summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/Kconfig4
-rw-r--r--drivers/pci/access.c239
-rw-r--r--drivers/pci/bus.c7
-rw-r--r--drivers/pci/host/pci-imx6.c137
-rw-r--r--drivers/pci/host/pci-layerscape.c1
-rw-r--r--drivers/pci/host/pcie-designware.c15
-rw-r--r--drivers/pci/host/pcie-rcar.c14
-rw-r--r--drivers/pci/iov.c4
-rw-r--r--drivers/pci/pci-label.c2
-rw-r--r--drivers/pci/pci-sysfs.c22
-rw-r--r--drivers/pci/pci.c40
-rw-r--r--drivers/pci/pci.h16
-rw-r--r--drivers/pci/pcie/Kconfig7
-rw-r--r--drivers/pci/pcie/pme.c11
-rw-r--r--drivers/pci/probe.c10
-rw-r--r--drivers/pci/quirks.c46
-rw-r--r--drivers/pci/setup-bus.c1
17 files changed, 343 insertions, 233 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 73de4ef..616165d 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -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"
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 8c05b5c..01b9d0a 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -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
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 89b3bef..f2187d4 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -291,7 +291,12 @@ void pci_bus_add_device(struct pci_dev *dev)
dev->match_driver = true;
retval = device_attach(&dev->dev);
- WARN_ON(retval < 0);
+ if (retval < 0) {
+ dev_warn(&dev->dev, "device attach failed (%d)\n", retval);
+ pci_proc_detach_device(dev);
+ pci_remove_sysfs_dev_files(dev);
+ return;
+ }
dev->is_added = 1;
}
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index fe60096..bd3f7d0 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -202,6 +202,23 @@ static int pcie_phy_write(void __iomem *dbi_base, int addr, int data)
return 0;
}
+static void imx6_pcie_reset_phy(struct pcie_port *pp)
+{
+ u32 tmp;
+
+ pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp);
+ tmp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
+ PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+ pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp);
+
+ usleep_range(2000, 3000);
+
+ pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp);
+ tmp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
+ PHY_RX_OVRD_IN_LO_RX_PLL_EN);
+ pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp);
+}
+
/* Added for PCI abort handling */
static int imx6q_pcie_abort_handler(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
@@ -332,16 +349,30 @@ static int imx6_pcie_wait_for_link(struct pcie_port *pp)
{
unsigned int retries;
+ /*
+ * Test if the PHY reports that the link is up and also that the LTSSM
+ * training finished. There are three possible states of the link when
+ * this code is called:
+ * 1) The link is DOWN (unlikely)
+ * The link didn't come up yet for some reason. This usually means
+ * we have a real problem somewhere, if it happens with a peripheral
+ * connected. This state calls for inspection of the DEBUG registers.
+ * 2) The link is UP, but still in LTSSM training
+ * Wait for the training to finish, which should take a very short
+ * time. If the training does not finish, we have a problem and we
+ * need to inspect the DEBUG registers. If the training does finish,
+ * the link is up and operating correctly.
+ * 3) The link is UP and no longer in LTSSM training
+ * The link is up and operating correctly.
+ */
for (retries = 0; retries < 200; retries++) {
- if (dw_pcie_link_up(pp))
+ u32 reg = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
+ if ((reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) &&
+ !(reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
return 0;
- usleep_range(100, 1000);
+ usleep_range(1000, 2000);
}
- dev_err(pp->dev, "phy link never came up\n");
- dev_dbg(pp->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
- readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
- readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
return -EINVAL;
}
@@ -390,8 +421,10 @@ static int imx6_pcie_establish_link(struct pcie_port *pp)
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
ret = imx6_pcie_wait_for_link(pp);
- if (ret)
- return ret;
+ if (ret) {
+ dev_info(pp->dev, "Link never came up\n");
+ goto err_reset_phy;
+ }
/* Allow Gen2 mode after the link is up. */
tmp = readl(pp->dbi_base + PCIE_RC_LCR);
@@ -410,19 +443,28 @@ static int imx6_pcie_establish_link(struct pcie_port *pp)
ret = imx6_pcie_wait_for_speed_change(pp);
if (ret) {
dev_err(pp->dev, "Failed to bring link up!\n");
- return ret;
+ goto err_reset_phy;
}
/* Make sure link training is finished as well! */
ret = imx6_pcie_wait_for_link(pp);
if (ret) {
dev_err(pp->dev, "Failed to bring link up!\n");
- return ret;
+ goto err_reset_phy;
}
tmp = readl(pp->dbi_base + PCIE_RC_LCSR);
dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf);
+
return 0;
+
+err_reset_phy:
+ dev_dbg(pp->dev, "PHY DEBUG_R0=0x%08x DEBUG_R1=0x%08x\n",
+ readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
+ readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
+ imx6_pcie_reset_phy(pp);
+
+ return ret;
}
static void imx6_pcie_host_init(struct pcie_port *pp)
@@ -441,81 +483,10 @@ static void imx6_pcie_host_init(struct pcie_port *pp)
dw_pcie_msi_init(pp);
}
-static void imx6_pcie_reset_phy(struct pcie_port *pp)
-{
- u32 tmp;
-
- pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp);
- tmp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
- PHY_RX_OVRD_IN_LO_RX_PLL_EN);
- pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp);
-
- usleep_range(2000, 3000);
-
- pcie_phy_read(pp->dbi_base, PHY_RX_OVRD_IN_LO, &tmp);
- tmp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN |
- PHY_RX_OVRD_IN_LO_RX_PLL_EN);
- pcie_phy_write(pp->dbi_base, PHY_RX_OVRD_IN_LO, tmp);
-}
-
static int imx6_pcie_link_up(struct pcie_port *pp)
{
- u32 rc, debug_r0, rx_valid;
- int count = 5;
-
- /*
- * Test if the PHY reports that the link is up and also that the LTSSM
- * training finished. There are three possible states of the link when
- * this code is called:
- * 1) The link is DOWN (unlikely)
- * The link didn't come up yet for some reason. This usually means
- * we have a real problem somewhere. Reset the PHY and exit. This
- * state calls for inspection of the DEBUG registers.
- * 2) The link is UP, but still in LTSSM training
- * Wait for the training to finish, which should take a very short
- * time. If the training does not finish, we have a problem and we
- * need to inspect the DEBUG registers. If the training does finish,
- * the link is up and operating correctly.
- * 3) The link is UP and no longer in LTSSM training
- * The link is up and operating correctly.
- */
- while (1) {
- rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1);
- if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP))
- break;
- if (!(rc & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING))
- return 1;
- if (!count--)
- break;
- dev_dbg(pp->dev, "Link is up, but still in training\n");
- /*
- * Wait a little bit, then re-check if the link finished
- * the training.
- */
- usleep_range(1000, 2000);
- }
- /*
- * From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
- * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
- * If (MAC/LTSSM.state == Recovery.RcvrLock)
- * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition
- * to gen2 is stuck
- */
- pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
- debug_r0 = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0);
-
- if (rx_valid & PCIE_PHY_RX_ASIC_OUT_VALID)
- return 0;
-
- if ((debug_r0 & 0x3f) != 0x0d)
- return 0;
-
- dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n");
- dev_dbg(pp->dev, "debug_r0=%08x debug_r1=%08x\n", debug_r0, rc);
-
- imx6_pcie_reset_phy(pp);
-
- return 0;
+ return readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) &
+ PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
}
static struct pcie_host_ops imx6_pcie_host_ops = {
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c
index 3923bed..c40d8b2 100644
--- a/drivers/pci/host/pci-layerscape.c
+++ b/drivers/pci/host/pci-layerscape.c
@@ -203,6 +203,7 @@ static const struct of_device_id ls_pcie_of_match[] = {
{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
{ .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
{ .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
+ { .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata },
{ },
};
MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 2171682..f85f10d 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -517,6 +517,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
if (pp->ops->host_init)
pp->ops->host_init(pp);
+ /*
+ * If the platform provides ->rd_other_conf, it means the platform
+ * uses its own address translation component rather than ATU, so
+ * we should not program the ATU here.
+ */
if (!pp->ops->rd_other_conf)
dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_MEM, pp->mem_base,
@@ -551,13 +556,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
#endif
- if (!pci_has_flag(PCI_PROBE_ONLY)) {
- pci_bus_size_bridges(bus);
- pci_bus_assign_resources(bus);
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child);
- }
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
pci_bus_add_devices(bus);
return 0;
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 4edb518..3509218 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -390,9 +390,7 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie)
rcar_pcie_setup(&res, pcie);
- /* Do not reassign resources if probe only */
- if (!pci_has_flag(PCI_PROBE_ONLY))
- pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
+ pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
if (IS_ENABLED(CONFIG_PCI_MSI))
bus = pci_scan_root_bus_msi(pcie->dev, pcie->root_bus_nr,
@@ -408,13 +406,11 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie)
pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
- if (!pci_has_flag(PCI_PROBE_ONLY)) {
- pci_bus_size_bridges(bus);
- pci_bus_assign_resources(bus);
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child);
- }
+ list_for_each_entry(child, &bus->children, node)
+ pcie_bus_configure_settings(child);
pci_bus_add_devices(bus);
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 31f31d4..fe4bd0a 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -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);
diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c
index 0ae74d9..5135737 100644
--- a/drivers/pci/pci-label.c
+++ b/drivers/pci/pci-label.c
@@ -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.
*/
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 95d9e7b..ed39c09 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -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;
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 602eb42..eaf4ffc 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -25,7 +25,6 @@
#include <linux/device.h>
#include <linux/pm_runtime.h>
#include <linux/pci_hotplug.h>
-#include <asm-generic/pci-bridge.h>
#include <asm/setup.h>
#include <linux/aer.h>
#include "pci.h"
@@ -3386,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
@@ -3414,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;
@@ -3429,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;
}
@@ -3459,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;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9a1660f..d0fb934 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -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
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index e294713..72db7f4 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -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.
diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c
index 63fc639..1ae4c73 100644
--- a/drivers/pci/pcie/pme.c
+++ b/drivers/pci/pcie/pme.c
@@ -396,7 +396,7 @@ static int pcie_pme_suspend(struct pcie_device *srv)
{
struct pcie_pme_service_data *data = get_service_data(srv);
struct pci_dev *port = srv->port;
- bool wakeup;
+ bool wakeup, wake_irq_enabled = false;
int ret;
if (device_may_wakeup(&port->dev)) {
@@ -409,11 +409,12 @@ static int pcie_pme_suspend(struct pcie_device *srv)
spin_lock_irq(&data->lock);
if (wakeup) {
ret = enable_irq_wake(srv->irq);
- data->suspend_level = PME_SUSPEND_WAKEUP;
+ if (ret == 0) {
+ data->suspend_level = PME_SUSPEND_WAKEUP;
+ wake_irq_enabled = true;
+ }
}
- if (!wakeup || ret) {
- struct pci_dev *port = srv->port;
-
+ if (!wake_irq_enabled) {
pcie_pme_interrupt_enable(port, false);
pcie_clear_root_pme_status(port);
data->suspend_level = PME_SUSPEND_NOIRQ;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6d7ab9b..3f1d009 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -15,7 +15,6 @@
#include <linux/pci-aspm.h>
#include <linux/aer.h>
#include <linux/acpi.h>
-#include <asm-generic/pci-bridge.h>
#include "pci.h"
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
@@ -1608,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);
@@ -1803,6 +1802,13 @@ static int only_one_child(struct pci_bus *bus)
return 0;
if (pci_pcie_type(parent) == PCI_EXP_TYPE_ROOT_PORT)
return 1;
+
+ /*
+ * PCIe downstream ports are bridges that normally lead to only a
+ * device 0, but if PCI_SCAN_ALL_PCIE_DEVS is set, scan all
+ * possible devices, not just device 0. See PCIe spec r3.0,
+ * sec 7.3.1.
+ */
if (parent->has_secondary_link &&
!pci_has_flag(PCI_SCAN_ALL_PCIE_DEVS))
return 1;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 0575a1e..8e67802 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -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);
}
@@ -2135,6 +2135,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
* observed when a vpd entry was created in sysfs
@@ -3832,6 +3861,19 @@ static int pci_quirk_amd_sb_acs(struct pci_dev *dev, u16 acs_flags)
#endif
}
+static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags)
+{
+ /*
+ * Cavium devices matching this quirk do not perform peer-to-peer
+ * with other functions, allowing masking out these bits as if they
+ * were unimplemented in the ACS capability.
+ */
+ acs_flags &= ~(PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR |
+ PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT);
+
+ return acs_flags ? 0 : 1;
+}
+
/*
* Many Intel PCH root ports do provide ACS-like features to disable peer
* transactions and validate bus numbers in requests, but do not provide an
@@ -3984,6 +4026,8 @@ static const struct pci_dev_acs_enabled {
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
{ 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */
{ 0x10df, 0x720, pci_quirk_mf_endpoint_acs }, /* Emulex Skyhawk-R */
+ /* Cavium ThunderX */
+ { PCI_VENDOR_ID_CAVIUM, PCI_ANY_ID, pci_quirk_cavium_acs },
{ 0 }
};
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 7796d0a..55641a3 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -25,7 +25,6 @@
#include <linux/ioport.h>
#include <linux/cache.h>
#include <linux/slab.h>
-#include <asm-generic/pci-bridge.h>
#include "pci.h"
unsigned int pci_flags;