浏览代码

Merge branches 'pci/enumeration', 'pci/hotplug', 'pci/resource' and 'pci/virtualization' into next

* pci/enumeration:
  PCI: Generate uppercase hex for modalias var in uevent

* pci/hotplug:
  PCI: pciehp: Handle surprise add even if surprise removal isn't supported

* pci/resource:
  PCI: Fix infinite loop with ROM image of size 0

* pci/virtualization:
  PCI: Add Wellsburg (X99) to Intel PCH root port ACS quirk
  PCI: Add DMA alias quirk for Adaptec 3405
  PCI: Add ACS quirk for Emulex NICs
  PCI: Mark AMD/ATI VGA devices that don't reset on D3hot->D0 transition
  PCI: Add flag for devices that don't reset on D3hot->D0 transition
  PCI: Mark Atheros AR93xx to avoid bus reset
  PCI: Add flag for devices where we can't use bus reset
Bjorn Helgaas 10 年之前
父节点
当前提交
341f3a2bcf
共有 6 个文件被更改,包括 124 次插入11 次删除
  1. 0 2
      drivers/pci/hotplug/pciehp_ctrl.c
  2. 1 1
      drivers/pci/pci-driver.c
  3. 37 5
      drivers/pci/pci.c
  4. 78 0
      drivers/pci/quirks.c
  5. 4 3
      drivers/pci/rom.c
  6. 4 0
      include/linux/pci.h

+ 0 - 2
drivers/pci/hotplug/pciehp_ctrl.c

@@ -532,8 +532,6 @@ static void interrupt_event_handler(struct work_struct *work)
 		pciehp_green_led_off(p_slot);
 		pciehp_green_led_off(p_slot);
 		break;
 		break;
 	case INT_PRESENCE_ON:
 	case INT_PRESENCE_ON:
-		if (!HP_SUPR_RM(ctrl))
-			break;
 		ctrl_dbg(ctrl, "Surprise Insertion\n");
 		ctrl_dbg(ctrl, "Surprise Insertion\n");
 		handle_surprise_event(p_slot);
 		handle_surprise_event(p_slot);
 		break;
 		break;

+ 1 - 1
drivers/pci/pci-driver.c

@@ -1383,7 +1383,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
 	if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
 	if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
+	if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X",
 			   pdev->vendor, pdev->device,
 			   pdev->vendor, pdev->device,
 			   pdev->subsystem_vendor, pdev->subsystem_device,
 			   pdev->subsystem_vendor, pdev->subsystem_device,
 			   (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
 			   (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),

+ 37 - 5
drivers/pci/pci.c

@@ -3199,7 +3199,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
 {
 {
 	u16 csr;
 	u16 csr;
 
 
-	if (!dev->pm_cap)
+	if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET)
 		return -ENOTTY;
 		return -ENOTTY;
 
 
 	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
 	pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
@@ -3273,7 +3273,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
 {
 {
 	struct pci_dev *pdev;
 	struct pci_dev *pdev;
 
 
-	if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self)
+	if (pci_is_root_bus(dev->bus) || dev->subordinate ||
+	    !dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
 		return -ENOTTY;
 		return -ENOTTY;
 
 
 	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
 	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
@@ -3307,7 +3308,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
 {
 {
 	struct pci_dev *pdev;
 	struct pci_dev *pdev;
 
 
-	if (dev->subordinate || !dev->slot)
+	if (dev->subordinate || !dev->slot ||
+	    dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
 		return -ENOTTY;
 		return -ENOTTY;
 
 
 	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
 	list_for_each_entry(pdev, &dev->bus->devices, bus_list)
@@ -3559,6 +3561,20 @@ int pci_try_reset_function(struct pci_dev *dev)
 }
 }
 EXPORT_SYMBOL_GPL(pci_try_reset_function);
 EXPORT_SYMBOL_GPL(pci_try_reset_function);
 
 
+/* Do any devices on or below this bus prevent a bus reset? */
+static bool pci_bus_resetable(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
+		    (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
+			return false;
+	}
+
+	return true;
+}
+
 /* Lock devices from the top of the tree down */
 /* Lock devices from the top of the tree down */
 static void pci_bus_lock(struct pci_bus *bus)
 static void pci_bus_lock(struct pci_bus *bus)
 {
 {
@@ -3609,6 +3625,22 @@ unlock:
 	return 0;
 	return 0;
 }
 }
 
 
+/* Do any devices on or below this slot prevent a bus reset? */
+static bool pci_slot_resetable(struct pci_slot *slot)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+		if (!dev->slot || dev->slot != slot)
+			continue;
+		if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
+		    (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
+			return false;
+	}
+
+	return true;
+}
+
 /* Lock devices from the top of the tree down */
 /* Lock devices from the top of the tree down */
 static void pci_slot_lock(struct pci_slot *slot)
 static void pci_slot_lock(struct pci_slot *slot)
 {
 {
@@ -3730,7 +3762,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe)
 {
 {
 	int rc;
 	int rc;
 
 
-	if (!slot)
+	if (!slot || !pci_slot_resetable(slot))
 		return -ENOTTY;
 		return -ENOTTY;
 
 
 	if (!probe)
 	if (!probe)
@@ -3822,7 +3854,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot);
 
 
 static int pci_bus_reset(struct pci_bus *bus, int probe)
 static int pci_bus_reset(struct pci_bus *bus, int probe)
 {
 {
-	if (!bus->self)
+	if (!bus->self || !pci_bus_resetable(bus))
 		return -ENOTTY;
 		return -ENOTTY;
 
 
 	if (probe)
 	if (probe)

+ 78 - 0
drivers/pci/quirks.c

@@ -3028,6 +3028,41 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169,
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID,
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID,
 			 quirk_broken_intx_masking);
 			 quirk_broken_intx_masking);
 
 
+static void quirk_no_bus_reset(struct pci_dev *dev)
+{
+	dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
+}
+
+/*
+ * Atheros AR93xx chips do not behave after a bus reset.  The device will
+ * throw a Link Down error on AER-capable systems and regardless of AER,
+ * config space of the device is never accessible again and typically
+ * causes the system to hang or reset when access is attempted.
+ * http://www.spinics.net/lists/linux-pci/msg34797.html
+ */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
+
+static void quirk_no_pm_reset(struct pci_dev *dev)
+{
+	/*
+	 * We can't do a bus reset on root bus devices, but an ineffective
+	 * PM reset may be better than nothing.
+	 */
+	if (!pci_is_root_bus(dev->bus))
+		dev->dev_flags |= PCI_DEV_FLAGS_NO_PM_RESET;
+}
+
+/*
+ * Some AMD/ATI GPUS (HD8570 - Oland) report that a D3hot->D0 transition
+ * causes a reset (i.e., they advertise NoSoftRst-).  This transition seems
+ * to have no effect on the device: it retains the framebuffer contents and
+ * monitor sync.  Advertising this support makes other layers, like VFIO,
+ * assume pci_reset_function() is viable for this device.  Mark it as
+ * unavailable to skip it when testing reset methods.
+ */
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+			       PCI_CLASS_DISPLAY_VGA, 8, quirk_no_pm_reset);
+
 #ifdef CONFIG_ACPI
 #ifdef CONFIG_ACPI
 /*
 /*
  * Apple: Shutdown Cactus Ridge Thunderbolt controller.
  * Apple: Shutdown Cactus Ridge Thunderbolt controller.
@@ -3527,6 +3562,44 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON,
 			 PCI_DEVICE_ID_JMICRON_JMB388_ESD,
 			 PCI_DEVICE_ID_JMICRON_JMB388_ESD,
 			 quirk_dma_func1_alias);
 			 quirk_dma_func1_alias);
 
 
+/*
+ * Some devices DMA with the wrong devfn, not just the wrong function.
+ * quirk_fixed_dma_alias() uses this table to create fixed aliases, where
+ * the alias is "fixed" and independent of the device devfn.
+ *
+ * For example, the Adaptec 3405 is a PCIe card with an Intel 80333 I/O
+ * processor.  To software, this appears as a PCIe-to-PCI/X bridge with a
+ * single device on the secondary bus.  In reality, the single exposed
+ * device at 0e.0 is the Address Translation Unit (ATU) of the controller
+ * that provides a bridge to the internal bus of the I/O processor.  The
+ * controller supports private devices, which can be hidden from PCI config
+ * space.  In the case of the Adaptec 3405, a private device at 01.0
+ * appears to be the DMA engine, which therefore needs to become a DMA
+ * alias for the device.
+ */
+static const struct pci_device_id fixed_dma_alias_tbl[] = {
+	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285,
+			 PCI_VENDOR_ID_ADAPTEC2, 0x02bb), /* Adaptec 3405 */
+	  .driver_data = PCI_DEVFN(1, 0) },
+	{ 0 }
+};
+
+static void quirk_fixed_dma_alias(struct pci_dev *dev)
+{
+	const struct pci_device_id *id;
+
+	id = pci_match_id(fixed_dma_alias_tbl, dev);
+	if (id) {
+		dev->dma_alias_devfn = id->driver_data;
+		dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
+		dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n",
+			 PCI_SLOT(dev->dma_alias_devfn),
+			 PCI_FUNC(dev->dma_alias_devfn));
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias);
+
 /*
 /*
  * A few PCIe-to-PCI bridges fail to expose a PCIe capability, resulting in
  * A few PCIe-to-PCI bridges fail to expose a PCIe capability, resulting in
  * using the wrong DMA alias for the device.  Some of these devices can be
  * using the wrong DMA alias for the device.  Some of these devices can be
@@ -3630,6 +3703,9 @@ static const u16 pci_quirk_intel_pch_acs_ids[] = {
 	0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
 	0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
 	/* Patsburg (X79) PCH */
 	/* Patsburg (X79) PCH */
 	0x1d10, 0x1d12, 0x1d14, 0x1d16, 0x1d18, 0x1d1a, 0x1d1c, 0x1d1e,
 	0x1d10, 0x1d12, 0x1d14, 0x1d16, 0x1d18, 0x1d1a, 0x1d1c, 0x1d1e,
+	/* Wellsburg (X99) PCH */
+	0x8d10, 0x8d11, 0x8d12, 0x8d13, 0x8d14, 0x8d15, 0x8d16, 0x8d17,
+	0x8d18, 0x8d19, 0x8d1a, 0x8d1b, 0x8d1c, 0x8d1d, 0x8d1e,
 };
 };
 
 
 static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
 static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
@@ -3713,6 +3789,8 @@ static const struct pci_dev_acs_enabled {
 	{ PCI_VENDOR_ID_INTEL, 0x1551, pci_quirk_mf_endpoint_acs },
 	{ PCI_VENDOR_ID_INTEL, 0x1551, pci_quirk_mf_endpoint_acs },
 	{ PCI_VENDOR_ID_INTEL, 0x1558, pci_quirk_mf_endpoint_acs },
 	{ PCI_VENDOR_ID_INTEL, 0x1558, pci_quirk_mf_endpoint_acs },
 	{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
 	{ 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 */
 	{ 0 }
 	{ 0 }
 };
 };
 
 

+ 4 - 3
drivers/pci/rom.c

@@ -71,6 +71,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
 {
 {
 	void __iomem *image;
 	void __iomem *image;
 	int last_image;
 	int last_image;
+	unsigned length;
 
 
 	image = rom;
 	image = rom;
 	do {
 	do {
@@ -93,9 +94,9 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
 		if (readb(pds + 3) != 'R')
 		if (readb(pds + 3) != 'R')
 			break;
 			break;
 		last_image = readb(pds + 21) & 0x80;
 		last_image = readb(pds + 21) & 0x80;
-		/* this length is reliable */
-		image += readw(pds + 16) * 512;
-	} while (!last_image);
+		length = readw(pds + 16);
+		image += length * 512;
+	} while (length && !last_image);
 
 
 	/* never return a size larger than the PCI resource window */
 	/* never return a size larger than the PCI resource window */
 	/* there are known ROMs that get the size wrong */
 	/* there are known ROMs that get the size wrong */

+ 4 - 0
include/linux/pci.h

@@ -175,6 +175,10 @@ enum pci_dev_flags {
 	PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4),
 	PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4),
 	/* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */
 	/* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */
 	PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5),
 	PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5),
+	/* Do not use bus resets for device */
+	PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6),
+	/* Do not use PM reset even if device advertises NoSoftRst- */
+	PCI_DEV_FLAGS_NO_PM_RESET = (__force pci_dev_flags_t) (1 << 7),
 };
 };
 
 
 enum pci_irq_reroute_variant {
 enum pci_irq_reroute_variant {