From 2b4aed1d1f119634d80d8c701873c2be01480aa9 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 19 Jun 2015 16:20:58 -0500 Subject: PCI: Shift PCI_CLASS_NOT_DEFINED consistently with other classes The PCI class in dev->class is a three-byte value comprising a base class, sub-class, and interface type. PCI_CLASS_NOT_DEFINED includes the base class and sub-class, but not the interface type, so it should be shifted to make space for the interface. It happens that PCI_CLASS_NOT_DEFINED is zero, so it doesn't matter in the end, but we should still use it consistently with other class definitions. Treat PCI_CLASS_NOT_DEFINED as a base class/sub-class value that should appear in bits 8-23 of dev->class. Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..71bd520e8ff7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1268,7 +1268,7 @@ int pci_setup_device(struct pci_dev *dev) bad: dev_err(&dev->dev, "ignoring class %#08x (doesn't match header type %02x)\n", dev->class, dev->hdr_type); - dev->class = PCI_CLASS_NOT_DEFINED; + dev->class = PCI_CLASS_NOT_DEFINED << 8; } /* We found a fine healthy device, go go go... */ -- cgit v1.2.3 From dff22d2054b5dbb1889f20c03959dd0c494fab8c Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Thu, 9 Jul 2015 11:59:16 +0100 Subject: PCI: Call pci_read_bridge_bases() from core instead of arch code When we scan a PCI bus, we read PCI-PCI bridge window registers with pci_read_bridge_bases() so we can validate the resource hierarchy. Most architectures call pci_read_bridge_bases() from pcibios_fixup_bus(), but PCI-PCI bridges are not arch-specific, so this doesn't need to be in arch-specific code. Call pci_read_bridge_bases() directly from the PCI core instead of from arch code. For alpha and mips, we now call pci_read_bridge_bases() always; previously we only called it if PCI_PROBE_ONLY was set. [bhelgaas: changelog] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas CC: Ralf Baechle CC: James E.J. Bottomley CC: Michael Ellerman CC: Bjorn Helgaas CC: Richard Henderson CC: Benjamin Herrenschmidt CC: David Howells CC: Russell King CC: Tony Luck CC: David S. Miller CC: Ingo Molnar CC: Guenter Roeck CC: Michal Simek CC: Chris Zankel --- arch/alpha/kernel/pci.c | 7 +------ arch/frv/mb93090-mb00/pci-vdk.c | 2 -- arch/ia64/pci/pci.c | 5 ++--- arch/microblaze/pci/pci-common.c | 9 +-------- arch/mips/pci/pci.c | 6 ------ arch/mn10300/unit-asb2305/pci.c | 1 - arch/powerpc/kernel/pci-common.c | 8 +------- arch/x86/pci/common.c | 1 - arch/xtensa/kernel/pci.c | 4 ---- drivers/parisc/dino.c | 3 --- drivers/parisc/lba_pci.c | 1 - drivers/pci/probe.c | 6 ++++++ 12 files changed, 11 insertions(+), 42 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c index 82f738e5d54c..cded02c890aa 100644 --- a/arch/alpha/kernel/pci.c +++ b/arch/alpha/kernel/pci.c @@ -242,12 +242,7 @@ pci_restore_srm_config(void) void pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_dev *dev = bus->self; - - if (pci_has_flag(PCI_PROBE_ONLY) && dev && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - pci_read_bridge_bases(bus); - } + struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { pdev_save_srm_config(dev); diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c index f211839e2cae..f9c86c475bbd 100644 --- a/arch/frv/mb93090-mb00/pci-vdk.c +++ b/arch/frv/mb93090-mb00/pci-vdk.c @@ -294,8 +294,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) printk("### PCIBIOS_FIXUP_BUS(%d)\n",bus->number); #endif - pci_read_bridge_bases(bus); - if (bus->number == 0) { struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 7cc3be9fa7c6..d89b6013c941 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -533,10 +533,9 @@ void pcibios_fixup_bus(struct pci_bus *b) { struct pci_dev *dev; - if (b->self) { - pci_read_bridge_bases(b); + if (b->self) pcibios_fixup_bridge_resources(b->self); - } + list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); platform_pci_fixup_bus(b); diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c index ae838ed5fcf2..6b8b75266801 100644 --- a/arch/microblaze/pci/pci-common.c +++ b/arch/microblaze/pci/pci-common.c @@ -863,14 +863,7 @@ void pcibios_setup_bus_devices(struct pci_bus *bus) void pcibios_fixup_bus(struct pci_bus *bus) { - /* When called from the generic PCI probe, read PCI<->PCI bridge - * bases. This is -not- called when generating the PCI tree from - * the OF device-tree. - */ - if (bus->self != NULL) - pci_read_bridge_bases(bus); - - /* Now fixup the bus bus */ + /* Fixup the bus */ pcibios_setup_bus_self(bus); /* Now fixup devices on that bus */ diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c index b8a0bf5766f2..c6996cf67a5c 100644 --- a/arch/mips/pci/pci.c +++ b/arch/mips/pci/pci.c @@ -311,12 +311,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) void pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_dev *dev = bus->self; - - if (pci_has_flag(PCI_PROBE_ONLY) && dev && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - pci_read_bridge_bases(bus); - } } EXPORT_SYMBOL(PCIBIOS_MIN_IO); diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c index 3dfe2d31c67b..deaa893efba5 100644 --- a/arch/mn10300/unit-asb2305/pci.c +++ b/arch/mn10300/unit-asb2305/pci.c @@ -324,7 +324,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) struct pci_dev *dev; if (bus->self) { - pci_read_bridge_bases(bus); pcibios_fixup_bridge_resources(bus->self); } diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index b9de34d44fcb..02c1d5dcee4d 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1044,13 +1044,7 @@ void pcibios_set_master(struct pci_dev *dev) void pcibios_fixup_bus(struct pci_bus *bus) { - /* When called from the generic PCI probe, read PCI<->PCI bridge - * bases. This is -not- called when generating the PCI tree from - * the OF device-tree. - */ - pci_read_bridge_bases(bus); - - /* Now fixup the bus bus */ + /* Fixup the bus */ pcibios_setup_bus_self(bus); /* Now fixup devices on that bus */ diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 8fd6f44aee83..3bff24438b00 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -166,7 +166,6 @@ void pcibios_fixup_bus(struct pci_bus *b) { struct pci_dev *dev; - pci_read_bridge_bases(b); list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); } diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index b848cc3dc913..d27b4dcf221f 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -210,10 +210,6 @@ subsys_initcall(pcibios_init); void pcibios_fixup_bus(struct pci_bus *bus) { - if (bus->parent) { - /* This is a subordinate bridge */ - pci_read_bridge_bases(bus); - } } void pcibios_set_master(struct pci_dev *dev) diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index a0580afe1713..baec33c4e698 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -560,9 +560,6 @@ dino_fixup_bus(struct pci_bus *bus) } else if (bus->parent) { int i; - pci_read_bridge_bases(bus); - - for(i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { if((bus->self->resource[i].flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index dceb9ddfd99a..901e1a3fa4e2 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -693,7 +693,6 @@ lba_fixup_bus(struct pci_bus *bus) if (bus->parent) { int i; /* PCI-PCI Bridge */ - pci_read_bridge_bases(bus); for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) pci_claim_bridge_resource(bus->self, i); } else { diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..b996aefc1092 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -826,6 +826,9 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) child->bridge_ctl = bctl; } + /* Read and initialize bridge resources */ + pci_read_bridge_bases(child); + cmax = pci_scan_child_bus(child); if (cmax > subordinate) dev_warn(&dev->dev, "bridge has subordinate %02x but max busn %02x\n", @@ -886,6 +889,9 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) if (!is_cardbus) { child->bridge_ctl = bctl; + + /* Read and initialize bridge resources */ + pci_read_bridge_bases(child); max = pci_scan_child_bus(child); } else { /* -- cgit v1.2.3 From 017ffe64e8b8c8db0f50433a71da41c6a4e12710 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Fri, 17 Jul 2015 17:16:32 +0800 Subject: PCI: Hold pci_slot_mutex while searching bus->slots list Previously, pci_setup_device() and similar functions searched the pci_bus->slots list without any locking. It was possible for another thread to update the list while we searched it. Add pci_dev_assign_slot() to search the list while holding pci_slot_mutex. [bhelgaas: changelog, fold in CONFIG_SYSFS fix] Tested-by: Guenter Roeck Signed-off-by: Yijing Wang Signed-off-by: Bjorn Helgaas --- arch/powerpc/kernel/pci_of_scan.c | 6 +----- arch/sparc/kernel/pci.c | 6 +----- drivers/pci/probe.c | 6 +----- drivers/pci/slot.c | 11 +++++++++++ include/linux/pci.h | 5 +++++ 5 files changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c index 42e02a2d570b..5e2debfc6ce5 100644 --- a/arch/powerpc/kernel/pci_of_scan.c +++ b/arch/powerpc/kernel/pci_of_scan.c @@ -126,7 +126,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, { struct pci_dev *dev; const char *type; - struct pci_slot *slot; dev = pci_alloc_dev(bus); if (!dev) @@ -145,10 +144,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, dev->needs_freset = 0; /* pcie fundamental reset required */ set_pcie_port_type(dev); - list_for_each_entry(slot, &dev->bus->slots, list) - if (PCI_SLOT(dev->devfn) == slot->number) - dev->slot = slot; - + pci_dev_assign_slot(dev); dev->vendor = get_int_prop(node, "vendor-id", 0xffff); dev->device = get_int_prop(node, "device-id", 0xffff); dev->subsystem_vendor = get_int_prop(node, "subsystem-vendor-id", 0); diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index c928bc64b4ba..3a0e1a986bfe 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -249,7 +249,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, struct pci_bus *bus, int devfn) { struct dev_archdata *sd; - struct pci_slot *slot; struct platform_device *op; struct pci_dev *dev; const char *type; @@ -290,10 +289,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, dev->multifunction = 0; /* maybe a lie? */ set_pcie_port_type(dev); - list_for_each_entry(slot, &dev->bus->slots, list) - if (PCI_SLOT(dev->devfn) == slot->number) - dev->slot = slot; - + pci_dev_assign_slot(dev); dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff); dev->device = of_getintprop_default(node, "device-id", 0xffff); dev->subsystem_vendor = diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..2a9ce16cb374 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1133,7 +1133,6 @@ int pci_setup_device(struct pci_dev *dev) { u32 class; u8 hdr_type; - struct pci_slot *slot; int pos = 0; struct pci_bus_region region; struct resource *res; @@ -1149,10 +1148,7 @@ int pci_setup_device(struct pci_dev *dev) dev->error_state = pci_channel_io_normal; set_pcie_port_type(dev); - list_for_each_entry(slot, &dev->bus->slots, list) - if (PCI_SLOT(dev->devfn) == slot->number) - dev->slot = slot; - + pci_dev_assign_slot(dev); /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) set this higher, assuming the system even supports it. */ dev->dma_mask = 0xffffffff; diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 4bd3fce93fa4..429d34c348b9 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -194,6 +194,17 @@ static int rename_slot(struct pci_slot *slot, const char *name) return result; } +void pci_dev_assign_slot(struct pci_dev *dev) +{ + struct pci_slot *slot; + + mutex_lock(&pci_slot_mutex); + list_for_each_entry(slot, &dev->bus->slots, list) + if (PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + mutex_unlock(&pci_slot_mutex); +} + static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) { struct pci_slot *slot; diff --git a/include/linux/pci.h b/include/linux/pci.h index aaee493174e2..b3ba7fef2916 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -798,6 +798,11 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, const char *name, struct hotplug_slot *hotplug); void pci_destroy_slot(struct pci_slot *slot); +#ifdef CONFIG_SYSFS +void pci_dev_assign_slot(struct pci_dev *dev); +#else +static inline void pci_dev_assign_slot(struct pci_dev *dev) { } +#endif int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn); void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); -- cgit v1.2.3 From edc90fee916b4f0d14af9c6b5c08666747488ef8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 17 Jul 2015 15:05:46 -0500 Subject: PCI: Allocate ATS struct during enumeration Previously, we allocated pci_ats structures when an IOMMU driver called pci_enable_ats(). An SR-IOV VF shares the STU setting with its PF, so when enabling ATS on the VF, we allocated a pci_ats struct for the PF if it didn't already have one. We held the sriov->lock to serialize threads concurrently enabling ATS on several VFS so only one would allocate the PF pci_ats. Gregor reported a deadlock here: pci_enable_sriov sriov_enable virtfn_add mutex_lock(dev->sriov->lock) # acquire sriov->lock pci_device_add device_add BUS_NOTIFY_ADD_DEVICE notifier chain iommu_bus_notifier amd_iommu_add_device # iommu_ops.add_device init_iommu_group iommu_group_get_for_dev iommu_group_add_device __iommu_attach_device amd_iommu_attach_device # iommu_ops.attach_device attach_device pci_enable_ats mutex_lock(dev->sriov->lock) # deadlock There's no reason to delay allocating the pci_ats struct, and if we allocate it for each device at enumeration-time, there's no need for locking in pci_enable_ats(). Allocate pci_ats struct during enumeration, when we initialize other capabilities. Note that this implementation requires ATS to be enabled on the PF first, before on any of the VFs because the PF controls the STU for all the VFs. Link: http://permalink.gmane.org/gmane.linux.kernel.iommu/9433 Reported-by: Gregor Dick Signed-off-by: Bjorn Helgaas Reviewed-by: Joerg Roedel --- drivers/pci/ats.c | 98 +++++++++++++++++++++---------------------------- drivers/pci/probe.c | 3 ++ drivers/pci/remove.c | 1 + include/linux/pci-ats.h | 2 +- include/linux/pci.h | 9 +++++ 5 files changed, 56 insertions(+), 57 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index a8099d4d0c9d..2026f5388796 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -17,7 +17,7 @@ #include "pci.h" -static int ats_alloc_one(struct pci_dev *dev, int ps) +static void ats_alloc_one(struct pci_dev *dev) { int pos; u16 cap; @@ -25,20 +25,19 @@ static int ats_alloc_one(struct pci_dev *dev, int ps) pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); if (!pos) - return -ENODEV; + return; ats = kzalloc(sizeof(*ats), GFP_KERNEL); - if (!ats) - return -ENOMEM; + if (!ats) { + dev_warn(&dev->dev, "can't allocate space for ATS state\n"); + return; + } ats->pos = pos; - ats->stu = ps; pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : PCI_ATS_MAX_QDEP; dev->ats = ats; - - return 0; } static void ats_free_one(struct pci_dev *dev) @@ -47,6 +46,16 @@ static void ats_free_one(struct pci_dev *dev) dev->ats = NULL; } +void pci_ats_init(struct pci_dev *dev) +{ + ats_alloc_one(dev); +} + +void pci_ats_free(struct pci_dev *dev) +{ + ats_free_one(dev); +} + /** * pci_enable_ats - enable the ATS capability * @dev: the PCI device @@ -56,43 +65,35 @@ static void ats_free_one(struct pci_dev *dev) */ int pci_enable_ats(struct pci_dev *dev, int ps) { - int rc; u16 ctrl; BUG_ON(dev->ats && dev->ats->is_enabled); + if (!dev->ats) + return -EINVAL; + if (ps < PCI_ATS_MIN_STU) return -EINVAL; - if (dev->is_physfn || dev->is_virtfn) { - struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; + /* + * Note that enabling ATS on a VF fails unless it's already enabled + * with the same STU on the PF. + */ + ctrl = PCI_ATS_CTRL_ENABLE; + if (dev->is_virtfn) { + struct pci_dev *pdev = dev->physfn; - mutex_lock(&pdev->sriov->lock); - if (pdev->ats) - rc = pdev->ats->stu == ps ? 0 : -EINVAL; - else - rc = ats_alloc_one(pdev, ps); + if (pdev->ats->stu != ps) + return -EINVAL; - if (!rc) - pdev->ats->ref_cnt++; - mutex_unlock(&pdev->sriov->lock); - if (rc) - return rc; - } - - if (!dev->is_physfn) { - rc = ats_alloc_one(dev, ps); - if (rc) - return rc; + atomic_inc(&pdev->ats->ref_cnt); /* count enabled VFs */ + } else { + dev->ats->stu = ps; + ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU); } - - ctrl = PCI_ATS_CTRL_ENABLE; - if (!dev->is_virtfn) - ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU); pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); dev->ats->is_enabled = 1; - return 0; } EXPORT_SYMBOL_GPL(pci_enable_ats); @@ -107,24 +108,20 @@ void pci_disable_ats(struct pci_dev *dev) BUG_ON(!dev->ats || !dev->ats->is_enabled); + if (atomic_read(&dev->ats->ref_cnt)) + return; /* VFs still enabled */ + + if (dev->is_virtfn) { + struct pci_dev *pdev = dev->physfn; + + atomic_dec(&pdev->ats->ref_cnt); + } + pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl); ctrl &= ~PCI_ATS_CTRL_ENABLE; pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); dev->ats->is_enabled = 0; - - if (dev->is_physfn || dev->is_virtfn) { - struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; - - mutex_lock(&pdev->sriov->lock); - pdev->ats->ref_cnt--; - if (!pdev->ats->ref_cnt) - ats_free_one(pdev); - mutex_unlock(&pdev->sriov->lock); - } - - if (!dev->is_physfn) - ats_free_one(dev); } EXPORT_SYMBOL_GPL(pci_disable_ats); @@ -140,7 +137,6 @@ void pci_restore_ats_state(struct pci_dev *dev) ctrl = PCI_ATS_CTRL_ENABLE; if (!dev->is_virtfn) ctrl |= PCI_ATS_CTRL_STU(dev->ats->stu - PCI_ATS_MIN_STU); - pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); } EXPORT_SYMBOL_GPL(pci_restore_ats_state); @@ -159,23 +155,13 @@ EXPORT_SYMBOL_GPL(pci_restore_ats_state); */ int pci_ats_queue_depth(struct pci_dev *dev) { - int pos; - u16 cap; - if (dev->is_virtfn) return 0; if (dev->ats) return dev->ats->qdep; - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); - if (!pos) - return -ENODEV; - - pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); - - return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : - PCI_ATS_MAX_QDEP; + return -ENODEV; } EXPORT_SYMBOL_GPL(pci_ats_queue_depth); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..c206398ca67e 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1540,6 +1540,9 @@ static void pci_init_capabilities(struct pci_dev *dev) /* Single Root I/O Virtualization */ pci_iov_init(dev); + /* Address Translation Services */ + pci_ats_init(dev); + /* Enable ACS P2P upstream forwarding */ pci_enable_acs(dev); } diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 8a280e9c2ad1..27617b862ca8 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -26,6 +26,7 @@ static void pci_stop_dev(struct pci_dev *dev) dev->is_added = 0; } + pci_ats_free(dev); if (dev->bus->self) pcie_aspm_exit_link_state(dev); } diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h index 72031785fe1d..e2dcc2ff3d0e 100644 --- a/include/linux/pci-ats.h +++ b/include/linux/pci-ats.h @@ -8,7 +8,7 @@ struct pci_ats { int pos; /* capability position */ int stu; /* Smallest Translation Unit */ int qdep; /* Invalidate Queue Depth */ - int ref_cnt; /* Physical Function reference count */ + atomic_t ref_cnt; /* number of VFs with ATS enabled */ unsigned int is_enabled:1; /* Enable bit is set */ }; diff --git a/include/linux/pci.h b/include/linux/pci.h index 8a0321a8fb59..1817819ba57b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1294,6 +1294,15 @@ int ht_create_irq(struct pci_dev *dev, int idx); void ht_destroy_irq(unsigned int irq); #endif /* CONFIG_HT_IRQ */ +#ifdef CONFIG_PCI_ATS +/* Address Translation Service */ +void pci_ats_init(struct pci_dev *dev); +void pci_ats_free(struct pci_dev *dev); +#else +static inline void pci_ats_init(struct pci_dev *dev) { } +static inline void pci_ats_free(struct pci_dev *dev) { } +#endif + void pci_cfg_access_lock(struct pci_dev *dev); bool pci_cfg_access_trylock(struct pci_dev *dev); void pci_cfg_access_unlock(struct pci_dev *dev); -- cgit v1.2.3 From d2a7926d42b3b46e45b4e44dc3302b2701ec0856 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 3 Aug 2015 21:27:10 -0500 Subject: PCI: Add pci_scan_root_bus_msi() Add a pci_scan_root_bus_msi() interface so an arch can specify the MSI controller up front. This removes the need for a pcibios callback to set the MSI controller later. This is not exported because I'd like to replace the variety of "scan root bus" interfaces with a single, more extensible interface that can handle the MSI controller, domain, pci_ops, resources, etc. I hope this interface is temporary. [bhelgaas: changelog, split into separate patch] Suggested-by: Russell King Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Jingoo Han --- drivers/pci/probe.c | 14 ++++++++++++-- include/linux/pci.h | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636681b6..9ff4df0db0c3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2096,8 +2096,9 @@ void pci_bus_release_busn_res(struct pci_bus *b) res, ret ? "can not be" : "is"); } -struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, struct list_head *resources) +struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, + struct list_head *resources, struct msi_controller *msi) { struct resource_entry *window; bool found = false; @@ -2114,6 +2115,8 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, if (!b) return NULL; + b->msi = msi; + if (!found) { dev_info(&b->dev, "No busn resource found for root bus, will use [bus %02x-ff]\n", @@ -2128,6 +2131,13 @@ struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, return b; } + +struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, struct list_head *resources) +{ + return pci_scan_root_bus_msi(parent, bus, ops, sysdata, resources, + NULL); +} EXPORT_SYMBOL(pci_scan_root_bus); struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, diff --git a/include/linux/pci.h b/include/linux/pci.h index 8a0321a8fb59..4d4f9d29fcc9 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -787,6 +787,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax); int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax); void pci_bus_release_busn_res(struct pci_bus *b); +struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, + struct list_head *resources, + struct msi_controller *msi); struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources); -- cgit v1.2.3 From 9dae3a97297f71e884ed8e7664955bcacb86f010 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 20 Aug 2015 16:08:27 -0500 Subject: PCI: Move MPS configuration check to pci_configure_device() Previously we checked for invalid MPS settings, i.e., a device with MPS different than its upstream bridge, in pcie_bus_detect_mps(). We only did this if the arch or hotplug driver called pcie_bus_configure_settings(), and then only if PCIe bus tuning was disabled (PCIE_BUS_TUNE_OFF). Move the MPS checking code to pci_configure_device(), so we do it in the pci_device_add() path for every device. Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9ff4df0db0c3..eb32395d5897 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1275,6 +1275,27 @@ int pci_setup_device(struct pci_dev *dev) return 0; } +static void pci_configure_mps(struct pci_dev *dev) +{ + struct pci_dev *bridge = pci_upstream_bridge(dev); + int mps, p_mps; + + if (!pci_is_pcie(dev) || !bridge || !pci_is_pcie(bridge)) + return; + + mps = pcie_get_mps(dev); + p_mps = pcie_get_mps(bridge); + + if (mps == p_mps) + return; + + if (pcie_bus_config == PCIE_BUS_TUNE_OFF) { + dev_warn(&dev->dev, "Max Payload Size %d, but upstream %s set to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n", + mps, pci_name(bridge), p_mps); + return; + } +} + static struct hpp_type0 pci_default_type0 = { .revision = 1, .cache_line_size = 8, @@ -1396,6 +1417,8 @@ static void pci_configure_device(struct pci_dev *dev) struct hotplug_params hpp; int ret; + pci_configure_mps(dev); + memset(&hpp, 0, sizeof(hpp)); ret = pci_get_hp_params(dev, &hpp); if (ret) @@ -1791,22 +1814,6 @@ static void pcie_write_mrrs(struct pci_dev *dev) dev_err(&dev->dev, "MRRS was unable to be configured with a safe value. If problems are experienced, try running with pci=pcie_bus_safe\n"); } -static void pcie_bus_detect_mps(struct pci_dev *dev) -{ - struct pci_dev *bridge = dev->bus->self; - int mps, p_mps; - - if (!bridge) - return; - - mps = pcie_get_mps(dev); - p_mps = pcie_get_mps(bridge); - - if (mps != p_mps) - dev_warn(&dev->dev, "Max Payload Size %d, but upstream %s set to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n", - mps, pci_name(bridge), p_mps); -} - static int pcie_bus_configure_set(struct pci_dev *dev, void *data) { int mps, orig_mps; @@ -1814,10 +1821,8 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) if (!pci_is_pcie(dev)) return 0; - if (pcie_bus_config == PCIE_BUS_TUNE_OFF) { - pcie_bus_detect_mps(dev); + if (pcie_bus_config == PCIE_BUS_TUNE_OFF) return 0; - } mps = 128 << *(u8 *)data; orig_mps = pcie_get_mps(dev); -- cgit v1.2.3 From 27d868b5e6cfaee4fec66b388e4085ff94050fa7 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 24 Aug 2015 08:48:16 -0500 Subject: PCI: Set MPS to match upstream bridge Firmware typically configures the PCIe fabric with a consistent Max Payload Size setting based on the devices present at boot. A hot-added device typically has the power-on default MPS setting (128 bytes), which may not match the fabric. The previous Linux default, in the absence of any "pci=pcie_bus_*" options, was PCIE_BUS_TUNE_OFF, in which we never touch MPS, even for hot-added devices. Add a new default setting, PCIE_BUS_DEFAULT, in which we make sure every device's MPS setting matches the upstream bridge. This makes it more likely that a hot-added device will work in a system with optimized MPS configuration. Note that if we hot-add a device that only supports 128-byte MPS, it still likely won't work because we don't reconfigure the rest of the fabric. Booting with "pci=pcie_bus_peer2peer" is a workaround for this because it sets MPS to 128 for everything. [bhelgaas: changelog, new default, rework for pci_configure_device() path] Tested-by: Keith Busch Tested-by: Jordan Hargrave Signed-off-by: Keith Busch Signed-off-by: Bjorn Helgaas Acked-by: Yinghai Lu --- drivers/pci/pci.c | 2 +- drivers/pci/probe.c | 22 ++++++++++++++++++++-- drivers/pci/quirks.c | 3 ++- include/linux/pci.h | 9 +++++---- 4 files changed, 28 insertions(+), 8 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 0008c950452c..b96b4ccc2819 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -81,7 +81,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; -enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF; +enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_DEFAULT; /* * The default CLS is used if arch didn't set CLS explicitly and not diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index eb32395d5897..eebabe3a814e 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1278,7 +1278,7 @@ int pci_setup_device(struct pci_dev *dev) static void pci_configure_mps(struct pci_dev *dev) { struct pci_dev *bridge = pci_upstream_bridge(dev); - int mps, p_mps; + int mps, p_mps, rc; if (!pci_is_pcie(dev) || !bridge || !pci_is_pcie(bridge)) return; @@ -1294,6 +1294,23 @@ static void pci_configure_mps(struct pci_dev *dev) mps, pci_name(bridge), p_mps); return; } + + /* + * Fancier MPS configuration is done later by + * pcie_bus_configure_settings() + */ + if (pcie_bus_config != PCIE_BUS_DEFAULT) + return; + + rc = pcie_set_mps(dev, p_mps); + if (rc) { + dev_warn(&dev->dev, "can't set Max Payload Size to %d; if necessary, use \"pci=pcie_bus_safe\" and report a bug\n", + p_mps); + return; + } + + dev_info(&dev->dev, "Max Payload Size set to %d (was %d, max %d)\n", + p_mps, mps, 128 << dev->pcie_mpss); } static struct hpp_type0 pci_default_type0 = { @@ -1821,7 +1838,8 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) if (!pci_is_pcie(dev)) return 0; - if (pcie_bus_config == PCIE_BUS_TUNE_OFF) + if (pcie_bus_config == PCIE_BUS_TUNE_OFF || + pcie_bus_config == PCIE_BUS_DEFAULT) return 0; mps = 128 << *(u8 *)data; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e9fd0e90fa3b..55f2c208bd0e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2862,7 +2862,8 @@ static void quirk_intel_mc_errata(struct pci_dev *dev) int err; u16 rcc; - if (pcie_bus_config == PCIE_BUS_TUNE_OFF) + if (pcie_bus_config == PCIE_BUS_TUNE_OFF || + pcie_bus_config == PCIE_BUS_DEFAULT) return; /* Intel errata specifies bits to change but does not say what they are. diff --git a/include/linux/pci.h b/include/linux/pci.h index 4d4f9d29fcc9..0007942923a7 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -738,10 +738,11 @@ struct pci_driver { void pcie_bus_configure_settings(struct pci_bus *bus); enum pcie_bus_config_types { - PCIE_BUS_TUNE_OFF, - PCIE_BUS_SAFE, - PCIE_BUS_PERFORMANCE, - PCIE_BUS_PEER2PEER, + PCIE_BUS_TUNE_OFF, /* don't touch MPS at all */ + PCIE_BUS_DEFAULT, /* ensure MPS matches upstream bridge */ + PCIE_BUS_SAFE, /* use largest MPS boot-time devices support */ + PCIE_BUS_PERFORMANCE, /* use MPS and MRRS for best performance */ + PCIE_BUS_PEER2PEER, /* set MPS = 128 for all devices */ }; extern enum pcie_bus_config_types pcie_bus_config; -- cgit v1.2.3