mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 11:41:38 -04:00
Merge branches 'pci/aer', 'pci/enumeration', 'pci/kconfig', 'pci/misc', 'pci/virtualization' and 'pci/vpd' into next
* pci/aer:
PCI/AER: Log aer_inject error injections
PCI/AER: Log actual error causes in aer_inject
PCI/AER: Use dev_warn() in aer_inject
PCI/AER: Fix aer_inject error codes
* pci/enumeration:
PCI: Fix broken URL for Dell biosdevname
* pci/kconfig:
PCI: Cleanup pci/pcie/Kconfig whitespace
PCI: Include pci/hotplug Kconfig directly from pci/Kconfig
PCI: Include pci/pcie/Kconfig directly from pci/Kconfig
* pci/misc:
PCI: Add PCI_CLASS_SERIAL_USB_DEVICE definition
PCI: Add QEMU top-level IDs for (sub)vendor & device
unicore32: Remove unused HAVE_ARCH_PCI_SET_DMA_MASK definition
PCI: Consolidate PCI DMA constants and interfaces in linux/pci-dma-compat.h
PCI: Move pci_dma_* helpers to common code
frv/PCI: Remove stray pci_{alloc,free}_consistent() declaration
* pci/virtualization:
PCI: Wait for up to 1000ms after FLR reset
PCI: Support SR-IOV on any function type
* pci/vpd:
PCI: Prevent VPD access for buggy devices
PCI: Sleep rather than busy-wait for VPD access completion
PCI: Fold struct pci_vpd_pci22 into struct pci_vpd
PCI: Rename VPD symbols to remove unnecessary "pci22"
PCI: Remove struct pci_vpd_ops.release function pointer
PCI: Move pci_vpd_release() from header file to pci/access.c
PCI: Move pci_read_vpd() and pci_write_vpd() close to other VPD code
PCI: Determine actual VPD size on first access
PCI: Use bitfield instead of bool for struct pci_vpd_pci22.busy
PCI: Allow access to VPD attributes with size 0
PCI: Update VPD definitions
This commit is contained in:
commit
18e5e6913b
57 changed files with 343 additions and 268 deletions
|
|
@ -1,6 +1,9 @@
|
|||
#
|
||||
# PCI configuration
|
||||
#
|
||||
|
||||
source "drivers/pci/pcie/Kconfig"
|
||||
|
||||
config PCI_BUS_ADDR_T_64BIT
|
||||
def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT)
|
||||
depends on PCI
|
||||
|
|
@ -118,4 +121,5 @@ config PCI_LABEL
|
|||
def_bool y if (DMI || ACPI)
|
||||
select NLS
|
||||
|
||||
source "drivers/pci/hotplug/Kconfig"
|
||||
source "drivers/pci/host/Kconfig"
|
||||
|
|
|
|||
|
|
@ -174,38 +174,6 @@ struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops)
|
|||
}
|
||||
EXPORT_SYMBOL(pci_bus_set_ops);
|
||||
|
||||
/**
|
||||
* pci_read_vpd - Read one entry from Vital Product Data
|
||||
* @dev: pci device struct
|
||||
* @pos: offset in vpd space
|
||||
* @count: number of bytes to read
|
||||
* @buf: pointer to where to store result
|
||||
*
|
||||
*/
|
||||
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
|
||||
{
|
||||
if (!dev->vpd || !dev->vpd->ops)
|
||||
return -ENODEV;
|
||||
return dev->vpd->ops->read(dev, pos, count, buf);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_read_vpd);
|
||||
|
||||
/**
|
||||
* pci_write_vpd - Write entry to Vital Product Data
|
||||
* @dev: pci device struct
|
||||
* @pos: offset in vpd space
|
||||
* @count: number of bytes to write
|
||||
* @buf: buffer containing write data
|
||||
*
|
||||
*/
|
||||
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
|
||||
{
|
||||
if (!dev->vpd || !dev->vpd->ops)
|
||||
return -ENODEV;
|
||||
return dev->vpd->ops->write(dev, pos, count, buf);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_write_vpd);
|
||||
|
||||
/*
|
||||
* The following routines are to prevent the user from accessing PCI config
|
||||
* space when it's unsafe to do so. Some devices require this during BIST and
|
||||
|
|
@ -277,15 +245,91 @@ PCI_USER_WRITE_CONFIG(dword, u32)
|
|||
|
||||
/* VPD access through PCI 2.2+ VPD capability */
|
||||
|
||||
#define PCI_VPD_PCI22_SIZE (PCI_VPD_ADDR_MASK + 1)
|
||||
/**
|
||||
* pci_read_vpd - Read one entry from Vital Product Data
|
||||
* @dev: pci device struct
|
||||
* @pos: offset in vpd space
|
||||
* @count: number of bytes to read
|
||||
* @buf: pointer to where to store result
|
||||
*/
|
||||
ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
|
||||
{
|
||||
if (!dev->vpd || !dev->vpd->ops)
|
||||
return -ENODEV;
|
||||
return dev->vpd->ops->read(dev, pos, count, buf);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_read_vpd);
|
||||
|
||||
struct pci_vpd_pci22 {
|
||||
struct pci_vpd base;
|
||||
struct mutex lock;
|
||||
u16 flag;
|
||||
bool busy;
|
||||
u8 cap;
|
||||
};
|
||||
/**
|
||||
* pci_write_vpd - Write entry to Vital Product Data
|
||||
* @dev: pci device struct
|
||||
* @pos: offset in vpd space
|
||||
* @count: number of bytes to write
|
||||
* @buf: buffer containing write data
|
||||
*/
|
||||
ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
|
||||
{
|
||||
if (!dev->vpd || !dev->vpd->ops)
|
||||
return -ENODEV;
|
||||
return dev->vpd->ops->write(dev, pos, count, buf);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_write_vpd);
|
||||
|
||||
#define PCI_VPD_MAX_SIZE (PCI_VPD_ADDR_MASK + 1)
|
||||
|
||||
/**
|
||||
* pci_vpd_size - determine actual size of Vital Product Data
|
||||
* @dev: pci device struct
|
||||
* @old_size: current assumed size, also maximum allowed size
|
||||
*/
|
||||
static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
|
||||
{
|
||||
size_t off = 0;
|
||||
unsigned char header[1+2]; /* 1 byte tag, 2 bytes length */
|
||||
|
||||
while (off < old_size &&
|
||||
pci_read_vpd(dev, off, 1, header) == 1) {
|
||||
unsigned char tag;
|
||||
|
||||
if (header[0] & PCI_VPD_LRDT) {
|
||||
/* Large Resource Data Type Tag */
|
||||
tag = pci_vpd_lrdt_tag(header);
|
||||
/* Only read length from known tag items */
|
||||
if ((tag == PCI_VPD_LTIN_ID_STRING) ||
|
||||
(tag == PCI_VPD_LTIN_RO_DATA) ||
|
||||
(tag == PCI_VPD_LTIN_RW_DATA)) {
|
||||
if (pci_read_vpd(dev, off+1, 2,
|
||||
&header[1]) != 2) {
|
||||
dev_warn(&dev->dev,
|
||||
"invalid large VPD tag %02x size at offset %zu",
|
||||
tag, off + 1);
|
||||
return 0;
|
||||
}
|
||||
off += PCI_VPD_LRDT_TAG_SIZE +
|
||||
pci_vpd_lrdt_size(header);
|
||||
}
|
||||
} else {
|
||||
/* Short Resource Data Type Tag */
|
||||
off += PCI_VPD_SRDT_TAG_SIZE +
|
||||
pci_vpd_srdt_size(header);
|
||||
tag = pci_vpd_srdt_tag(header);
|
||||
}
|
||||
|
||||
if (tag == PCI_VPD_STIN_END) /* End tag descriptor */
|
||||
return off;
|
||||
|
||||
if ((tag != PCI_VPD_LTIN_ID_STRING) &&
|
||||
(tag != PCI_VPD_LTIN_RO_DATA) &&
|
||||
(tag != PCI_VPD_LTIN_RW_DATA)) {
|
||||
dev_warn(&dev->dev,
|
||||
"invalid %s VPD tag %02x at offset %zu",
|
||||
(header[0] & PCI_VPD_LRDT) ? "large" : "short",
|
||||
tag, off);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for last operation to complete.
|
||||
|
|
@ -295,55 +339,71 @@ struct pci_vpd_pci22 {
|
|||
*
|
||||
* Returns 0 on success, negative values indicate error.
|
||||
*/
|
||||
static int pci_vpd_pci22_wait(struct pci_dev *dev)
|
||||
static int pci_vpd_wait(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_vpd_pci22 *vpd =
|
||||
container_of(dev->vpd, struct pci_vpd_pci22, base);
|
||||
unsigned long timeout = jiffies + HZ/20 + 2;
|
||||
struct pci_vpd *vpd = dev->vpd;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(50);
|
||||
unsigned long max_sleep = 16;
|
||||
u16 status;
|
||||
int ret;
|
||||
|
||||
if (!vpd->busy)
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
while (time_before(jiffies, timeout)) {
|
||||
ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR,
|
||||
&status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if ((status & PCI_VPD_ADDR_F) == vpd->flag) {
|
||||
vpd->busy = false;
|
||||
vpd->busy = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_printk(KERN_DEBUG, &dev->dev, "vpd r/w failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (fatal_signal_pending(current))
|
||||
return -EINTR;
|
||||
if (!cond_resched())
|
||||
udelay(10);
|
||||
|
||||
usleep_range(10, max_sleep);
|
||||
if (max_sleep < 1024)
|
||||
max_sleep *= 2;
|
||||
}
|
||||
|
||||
dev_warn(&dev->dev, "VPD access failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count,
|
||||
void *arg)
|
||||
static ssize_t pci_vpd_read(struct pci_dev *dev, loff_t pos, size_t count,
|
||||
void *arg)
|
||||
{
|
||||
struct pci_vpd_pci22 *vpd =
|
||||
container_of(dev->vpd, struct pci_vpd_pci22, base);
|
||||
struct pci_vpd *vpd = dev->vpd;
|
||||
int ret;
|
||||
loff_t end = pos + count;
|
||||
u8 *buf = arg;
|
||||
|
||||
if (pos < 0 || pos > vpd->base.len || end > vpd->base.len)
|
||||
if (pos < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!vpd->valid) {
|
||||
vpd->valid = 1;
|
||||
vpd->len = pci_vpd_size(dev, vpd->len);
|
||||
}
|
||||
|
||||
if (vpd->len == 0)
|
||||
return -EIO;
|
||||
|
||||
if (pos > vpd->len)
|
||||
return 0;
|
||||
|
||||
if (end > vpd->len) {
|
||||
end = vpd->len;
|
||||
count = end - pos;
|
||||
}
|
||||
|
||||
if (mutex_lock_killable(&vpd->lock))
|
||||
return -EINTR;
|
||||
|
||||
ret = pci_vpd_pci22_wait(dev);
|
||||
ret = pci_vpd_wait(dev);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
|
@ -355,9 +415,9 @@ static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count,
|
|||
pos & ~3);
|
||||
if (ret < 0)
|
||||
break;
|
||||
vpd->busy = true;
|
||||
vpd->busy = 1;
|
||||
vpd->flag = PCI_VPD_ADDR_F;
|
||||
ret = pci_vpd_pci22_wait(dev);
|
||||
ret = pci_vpd_wait(dev);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
|
|
@ -380,22 +440,32 @@ out:
|
|||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count,
|
||||
const void *arg)
|
||||
static ssize_t pci_vpd_write(struct pci_dev *dev, loff_t pos, size_t count,
|
||||
const void *arg)
|
||||
{
|
||||
struct pci_vpd_pci22 *vpd =
|
||||
container_of(dev->vpd, struct pci_vpd_pci22, base);
|
||||
struct pci_vpd *vpd = dev->vpd;
|
||||
const u8 *buf = arg;
|
||||
loff_t end = pos + count;
|
||||
int ret = 0;
|
||||
|
||||
if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len)
|
||||
if (pos < 0 || (pos & 3) || (count & 3))
|
||||
return -EINVAL;
|
||||
|
||||
if (!vpd->valid) {
|
||||
vpd->valid = 1;
|
||||
vpd->len = pci_vpd_size(dev, vpd->len);
|
||||
}
|
||||
|
||||
if (vpd->len == 0)
|
||||
return -EIO;
|
||||
|
||||
if (end > vpd->len)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_killable(&vpd->lock))
|
||||
return -EINTR;
|
||||
|
||||
ret = pci_vpd_pci22_wait(dev);
|
||||
ret = pci_vpd_wait(dev);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
|
@ -415,9 +485,9 @@ static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count
|
|||
if (ret < 0)
|
||||
break;
|
||||
|
||||
vpd->busy = true;
|
||||
vpd->busy = 1;
|
||||
vpd->flag = 0;
|
||||
ret = pci_vpd_pci22_wait(dev);
|
||||
ret = pci_vpd_wait(dev);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
|
|
@ -428,15 +498,9 @@ out:
|
|||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static void pci_vpd_pci22_release(struct pci_dev *dev)
|
||||
{
|
||||
kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
|
||||
}
|
||||
|
||||
static const struct pci_vpd_ops pci_vpd_pci22_ops = {
|
||||
.read = pci_vpd_pci22_read,
|
||||
.write = pci_vpd_pci22_write,
|
||||
.release = pci_vpd_pci22_release,
|
||||
static const struct pci_vpd_ops pci_vpd_ops = {
|
||||
.read = pci_vpd_read,
|
||||
.write = pci_vpd_write,
|
||||
};
|
||||
|
||||
static ssize_t pci_vpd_f0_read(struct pci_dev *dev, loff_t pos, size_t count,
|
||||
|
|
@ -472,12 +536,11 @@ static ssize_t pci_vpd_f0_write(struct pci_dev *dev, loff_t pos, size_t count,
|
|||
static const struct pci_vpd_ops pci_vpd_f0_ops = {
|
||||
.read = pci_vpd_f0_read,
|
||||
.write = pci_vpd_f0_write,
|
||||
.release = pci_vpd_pci22_release,
|
||||
};
|
||||
|
||||
int pci_vpd_pci22_init(struct pci_dev *dev)
|
||||
int pci_vpd_init(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_vpd_pci22 *vpd;
|
||||
struct pci_vpd *vpd;
|
||||
u8 cap;
|
||||
|
||||
cap = pci_find_capability(dev, PCI_CAP_ID_VPD);
|
||||
|
|
@ -488,18 +551,24 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
|
|||
if (!vpd)
|
||||
return -ENOMEM;
|
||||
|
||||
vpd->base.len = PCI_VPD_PCI22_SIZE;
|
||||
vpd->len = PCI_VPD_MAX_SIZE;
|
||||
if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0)
|
||||
vpd->base.ops = &pci_vpd_f0_ops;
|
||||
vpd->ops = &pci_vpd_f0_ops;
|
||||
else
|
||||
vpd->base.ops = &pci_vpd_pci22_ops;
|
||||
vpd->ops = &pci_vpd_ops;
|
||||
mutex_init(&vpd->lock);
|
||||
vpd->cap = cap;
|
||||
vpd->busy = false;
|
||||
dev->vpd = &vpd->base;
|
||||
vpd->busy = 0;
|
||||
vpd->valid = 0;
|
||||
dev->vpd = vpd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pci_vpd_release(struct pci_dev *dev)
|
||||
{
|
||||
kfree(dev->vpd);
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_cfg_access_lock - Lock PCI config reads/writes
|
||||
* @dev: pci device struct
|
||||
|
|
|
|||
|
|
@ -387,10 +387,6 @@ static int sriov_init(struct pci_dev *dev, int pos)
|
|||
struct resource *res;
|
||||
struct pci_dev *pdev;
|
||||
|
||||
if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_END &&
|
||||
pci_pcie_type(dev) != PCI_EXP_TYPE_ENDPOINT)
|
||||
return -ENODEV;
|
||||
|
||||
pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
|
||||
if (ctrl & PCI_SRIOV_CTRL_VFE) {
|
||||
pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* the instance number and string from the type 41 record and exports
|
||||
* it to sysfs.
|
||||
*
|
||||
* Please see http://linux.dell.com/wiki/index.php/Oss/libnetdevname for more
|
||||
* Please see http://linux.dell.com/files/biosdevname/ for more
|
||||
* information.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -769,10 +769,12 @@ static ssize_t read_vpd_attr(struct file *filp, struct kobject *kobj,
|
|||
{
|
||||
struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
|
||||
|
||||
if (off > bin_attr->size)
|
||||
count = 0;
|
||||
else if (count > bin_attr->size - off)
|
||||
count = bin_attr->size - off;
|
||||
if (bin_attr->size > 0) {
|
||||
if (off > bin_attr->size)
|
||||
count = 0;
|
||||
else if (count > bin_attr->size - off)
|
||||
count = bin_attr->size - off;
|
||||
}
|
||||
|
||||
return pci_read_vpd(dev, off, count, buf);
|
||||
}
|
||||
|
|
@ -783,10 +785,12 @@ static ssize_t write_vpd_attr(struct file *filp, struct kobject *kobj,
|
|||
{
|
||||
struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
|
||||
|
||||
if (off > bin_attr->size)
|
||||
count = 0;
|
||||
else if (count > bin_attr->size - off)
|
||||
count = bin_attr->size - off;
|
||||
if (bin_attr->size > 0) {
|
||||
if (off > bin_attr->size)
|
||||
count = 0;
|
||||
else if (count > bin_attr->size - off)
|
||||
count = bin_attr->size - off;
|
||||
}
|
||||
|
||||
return pci_write_vpd(dev, off, count, buf);
|
||||
}
|
||||
|
|
@ -1319,7 +1323,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
|
|||
return -ENOMEM;
|
||||
|
||||
sysfs_bin_attr_init(attr);
|
||||
attr->size = dev->vpd->len;
|
||||
attr->size = 0;
|
||||
attr->attr.name = "vpd";
|
||||
attr->attr.mode = S_IRUSR | S_IWUSR;
|
||||
attr->read = read_vpd_attr;
|
||||
|
|
|
|||
|
|
@ -3385,18 +3385,6 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx);
|
||||
|
||||
int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
|
||||
{
|
||||
return dma_set_max_seg_size(&dev->dev, size);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_set_dma_max_seg_size);
|
||||
|
||||
int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
|
||||
{
|
||||
return dma_set_seg_boundary(&dev->dev, mask);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_set_dma_seg_boundary);
|
||||
|
||||
/**
|
||||
* pci_wait_for_pending_transaction - waits for pending transaction
|
||||
* @dev: the PCI device to operate on
|
||||
|
|
@ -3413,6 +3401,29 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev)
|
|||
}
|
||||
EXPORT_SYMBOL(pci_wait_for_pending_transaction);
|
||||
|
||||
/*
|
||||
* We should only need to wait 100ms after FLR, but some devices take longer.
|
||||
* Wait for up to 1000ms for config space to return something other than -1.
|
||||
* Intel IGD requires this when an LCD panel is attached. We read the 2nd
|
||||
* dword because VFs don't implement the 1st dword.
|
||||
*/
|
||||
static void pci_flr_wait(struct pci_dev *dev)
|
||||
{
|
||||
int i = 0;
|
||||
u32 id;
|
||||
|
||||
do {
|
||||
msleep(100);
|
||||
pci_read_config_dword(dev, PCI_COMMAND, &id);
|
||||
} while (i++ < 10 && id == ~0);
|
||||
|
||||
if (id == ~0)
|
||||
dev_warn(&dev->dev, "Failed to return from FLR\n");
|
||||
else if (i > 1)
|
||||
dev_info(&dev->dev, "Required additional %dms to return from FLR\n",
|
||||
(i - 1) * 100);
|
||||
}
|
||||
|
||||
static int pcie_flr(struct pci_dev *dev, int probe)
|
||||
{
|
||||
u32 cap;
|
||||
|
|
@ -3428,7 +3439,7 @@ static int pcie_flr(struct pci_dev *dev, int probe)
|
|||
dev_err(&dev->dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
|
||||
|
||||
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
|
||||
msleep(100);
|
||||
pci_flr_wait(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3458,7 +3469,7 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
|
|||
dev_err(&dev->dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
|
||||
|
||||
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
|
||||
msleep(100);
|
||||
pci_flr_wait(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -97,21 +97,21 @@ static inline bool pci_has_subordinate(struct pci_dev *pci_dev)
|
|||
struct pci_vpd_ops {
|
||||
ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
|
||||
ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
|
||||
void (*release)(struct pci_dev *dev);
|
||||
};
|
||||
|
||||
struct pci_vpd {
|
||||
unsigned int len;
|
||||
const struct pci_vpd_ops *ops;
|
||||
struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
|
||||
struct mutex lock;
|
||||
unsigned int len;
|
||||
u16 flag;
|
||||
u8 cap;
|
||||
u8 busy:1;
|
||||
u8 valid:1;
|
||||
};
|
||||
|
||||
int pci_vpd_pci22_init(struct pci_dev *dev);
|
||||
static inline void pci_vpd_release(struct pci_dev *dev)
|
||||
{
|
||||
if (dev->vpd)
|
||||
dev->vpd->ops->release(dev);
|
||||
}
|
||||
int pci_vpd_init(struct pci_dev *dev);
|
||||
void pci_vpd_release(struct pci_dev *dev);
|
||||
|
||||
/* PCI /proc functions */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ config PCIEASPM
|
|||
/sys/module/pcie_aspm/parameters/policy
|
||||
|
||||
When in doubt, say Y.
|
||||
|
||||
config PCIEASPM_DEBUG
|
||||
bool "Debug PCI Express ASPM"
|
||||
depends on PCIEASPM
|
||||
|
|
@ -58,20 +59,20 @@ choice
|
|||
depends on PCIEASPM
|
||||
|
||||
config PCIEASPM_DEFAULT
|
||||
bool "BIOS default"
|
||||
bool "BIOS default"
|
||||
depends on PCIEASPM
|
||||
help
|
||||
Use the BIOS defaults for PCI Express ASPM.
|
||||
|
||||
config PCIEASPM_POWERSAVE
|
||||
bool "Powersave"
|
||||
bool "Powersave"
|
||||
depends on PCIEASPM
|
||||
help
|
||||
Enable PCI Express ASPM L0s and L1 where possible, even if the
|
||||
BIOS did not.
|
||||
|
||||
config PCIEASPM_PERFORMANCE
|
||||
bool "Performance"
|
||||
bool "Performance"
|
||||
depends on PCIEASPM
|
||||
help
|
||||
Disable PCI Express ASPM L0s and L1, even if the BIOS enabled them.
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/device.h>
|
||||
#include "aerdrv.h"
|
||||
|
||||
/* Override the existing corrected and uncorrected error masks */
|
||||
|
|
@ -357,13 +358,15 @@ static int aer_inject(struct aer_error_inj *einj)
|
|||
return -ENODEV;
|
||||
rpdev = pcie_find_root_port(dev);
|
||||
if (!rpdev) {
|
||||
dev_err(&dev->dev, "aer_inject: Root port not found\n");
|
||||
ret = -ENODEV;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||
if (!pos_cap_err) {
|
||||
ret = -EPERM;
|
||||
dev_err(&dev->dev, "aer_inject: Device doesn't support AER\n");
|
||||
ret = -EPROTONOSUPPORT;
|
||||
goto out_put;
|
||||
}
|
||||
pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
|
||||
|
|
@ -373,7 +376,9 @@ static int aer_inject(struct aer_error_inj *einj)
|
|||
|
||||
rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
|
||||
if (!rp_pos_cap_err) {
|
||||
ret = -EPERM;
|
||||
dev_err(&rpdev->dev,
|
||||
"aer_inject: Root port doesn't support AER\n");
|
||||
ret = -EPROTONOSUPPORT;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
|
|
@ -420,14 +425,16 @@ static int aer_inject(struct aer_error_inj *einj)
|
|||
if (!aer_mask_override && einj->cor_status &&
|
||||
!(einj->cor_status & ~cor_mask)) {
|
||||
ret = -EINVAL;
|
||||
printk(KERN_WARNING "The correctable error(s) is masked by device\n");
|
||||
dev_warn(&dev->dev,
|
||||
"aer_inject: The correctable error(s) is masked by device\n");
|
||||
spin_unlock_irqrestore(&inject_lock, flags);
|
||||
goto out_put;
|
||||
}
|
||||
if (!aer_mask_override && einj->uncor_status &&
|
||||
!(einj->uncor_status & ~uncor_mask)) {
|
||||
ret = -EINVAL;
|
||||
printk(KERN_WARNING "The uncorrectable error(s) is masked by device\n");
|
||||
dev_warn(&dev->dev,
|
||||
"aer_inject: The uncorrectable error(s) is masked by device\n");
|
||||
spin_unlock_irqrestore(&inject_lock, flags);
|
||||
goto out_put;
|
||||
}
|
||||
|
|
@ -480,13 +487,19 @@ static int aer_inject(struct aer_error_inj *einj)
|
|||
|
||||
if (find_aer_device(rpdev, &edev)) {
|
||||
if (!get_service_data(edev)) {
|
||||
printk(KERN_WARNING "AER service is not initialized\n");
|
||||
ret = -EINVAL;
|
||||
dev_warn(&edev->device,
|
||||
"aer_inject: AER service is not initialized\n");
|
||||
ret = -EPROTONOSUPPORT;
|
||||
goto out_put;
|
||||
}
|
||||
dev_info(&edev->device,
|
||||
"aer_inject: Injecting errors %08x/%08x into device %s\n",
|
||||
einj->cor_status, einj->uncor_status, pci_name(dev));
|
||||
aer_irq(-1, edev);
|
||||
} else
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
dev_err(&rpdev->dev, "aer_inject: AER device not found\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
out_put:
|
||||
kfree(err_alloc);
|
||||
kfree(rperr_alloc);
|
||||
|
|
|
|||
|
|
@ -1607,7 +1607,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
|
|||
pci_pm_init(dev);
|
||||
|
||||
/* Vital Product Data */
|
||||
pci_vpd_pci22_init(dev);
|
||||
pci_vpd_init(dev);
|
||||
|
||||
/* Alternative Routing-ID Forwarding */
|
||||
pci_configure_ari(dev);
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ static void quirk_amd_nl_class(struct pci_dev *pdev)
|
|||
u32 class = pdev->class;
|
||||
|
||||
/* Use "USB Device (not host controller)" class */
|
||||
pdev->class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe;
|
||||
pdev->class = PCI_CLASS_SERIAL_USB_DEVICE;
|
||||
dev_info(&pdev->dev, "PCI class overridden (%#08x -> %#08x) so dwc3 driver can claim this instead of xhci\n",
|
||||
class, pdev->class);
|
||||
}
|
||||
|
|
@ -2134,6 +2134,35 @@ static void quirk_via_cx700_pci_parking_caching(struct pci_dev *dev)
|
|||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_caching);
|
||||
|
||||
/*
|
||||
* If a device follows the VPD format spec, the PCI core will not read or
|
||||
* write past the VPD End Tag. But some vendors do not follow the VPD
|
||||
* format spec, so we can't tell how much data is safe to access. Devices
|
||||
* may behave unpredictably if we access too much. Blacklist these devices
|
||||
* so we don't touch VPD at all.
|
||||
*/
|
||||
static void quirk_blacklist_vpd(struct pci_dev *dev)
|
||||
{
|
||||
if (dev->vpd) {
|
||||
dev->vpd->len = 0;
|
||||
dev_warn(&dev->dev, FW_BUG "VPD access disabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0060, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x007c, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0413, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0078, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0079, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0073, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x0071, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005b, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x002f, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005d, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LSI_LOGIC, 0x005f, quirk_blacklist_vpd);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, PCI_ANY_ID,
|
||||
quirk_blacklist_vpd);
|
||||
|
||||
/*
|
||||
* For Broadcom 5706, 5708, 5709 rev. A nics, any read beyond the
|
||||
* VPD end tag will hang the device. This problem was initially
|
||||
|
|
|
|||
Loading…
Reference in a new issue