Re: [PATCH] PCI fixes for 2.6.10-rc1

Greg KH
2004-11-12T23:31:53Z

ChangeSet 1.2026.66.15, 2004/11/05 15:06:04-08:00, dlsy@snoqualmie.dp.intel.com

[PATCH] PCI: ASPM patch for

This is the ASPM patch against 2.6.10-rc1-mm2.

As mentioned in my last email, this patch has a slight difference than
the one for 2.6.10-rc1, because the irqbalance quirk was moved from
drivers/pci/quirks.c in 2.6.10-rc1 to arch/i386/kernel/quirks.c in
2.6.10-rc1-mm2.

Signed-off-by: Dely Sy <dely.l.sy@intel.com>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>

arch/i386/kernel/quirks.c | 4 -
arch/i386/pci/fixup.c | 91 ++++++++++++++++++++++++++++++++++++++
drivers/pci/hotplug/pciehp_ctrl.c | 9 +++
drivers/pci/hotplug/pciehp_hpc.c | 6 +-
drivers/pci/hotplug/pciehp_pci.c | 8 +++
drivers/pci/hotplug/shpchp_hpc.c | 1
drivers/pci/pci.h | 2
drivers/pci/quirks.c | 18 ++++---
include/linux/pci_ids.h | 8 ++-
9 files changed, 133 insertions(+), 14 deletions(-)

diff -Nru a/arch/i386/kernel/quirks.c b/arch/i386/kernel/quirks.c
--- a/arch/i386/kernel/quirks.c 2004-11-12 15:13:05 -08:00
+++ b/arch/i386/kernel/quirks.c 2004-11-12 15:13:05 -08:00
@@ -6,7 +6,7 @@

#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP)

-void __init quirk_intel_irqbalance(struct pci_dev *dev)
+void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
{
u8 config, rev;
u32 word;
@@ -45,5 +45,5 @@
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_intel_irqbalance);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
#endif
diff -Nru a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
--- a/arch/i386/pci/fixup.c 2004-11-12 15:13:05 -08:00
+++ b/arch/i386/pci/fixup.c 2004-11-12 15:13:05 -08:00
@@ -255,3 +255,94 @@
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2);

+/* Max PCI Express root ports */
+#define MAX_PCIEROOT 6
+static int quirk_aspm_offset[MAX_PCIEROOT << 3];
+
+#define GET_INDEX(a, b) (((a - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + b)
+
+static int quirk_pcie_aspm_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
+{
+ return raw_pci_ops->read(0, bus->number, devfn, where, size, value);
+}
+
+/*
+ * Replace the original pci bus ops for write with a new one that will filter
+ * the request to insure ASPM cannot be enabled.
+ */
+static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
+{
+ u8 offset;
+
+ offset = quirk_aspm_offset[GET_INDEX(bus->self->device, devfn)];
+
+ if ((offset) && (where == offset))
+ value = value & 0xfffffffc;
+
+ return raw_pci_ops->write(0, bus->number, devfn, where, size, value);
+}
+
+struct pci_ops quirk_pcie_aspm_ops = {
+ .read = quirk_pcie_aspm_read,
+ .write = quirk_pcie_aspm_write,
+};
+
+/*
+ * Prevents PCI Express ASPM (Active State Power Management) being enabled.
+ *
+ * Save the register offset, where the ASPM control bits are located,
+ * for each PCI Express device that is in the device list of
+ * the root port in an array for fast indexing. Replace the bus ops
+ * with the modified one.
+ */
+void pcie_rootport_aspm_quirk(struct pci_dev *pdev)
+{
+ int cap_base, i;
+ struct pci_bus *pbus;
+ struct pci_dev *dev;
+
+ if ((pbus = pdev->subordinate) == NULL)
+ return;
+
+ /*
+ * Check if the DID of pdev matches one of the six root ports. This
+ * check is needed in the case this function is called directly by the
+ * hot-plug driver.
+ */
+ if ((pdev->device < PCI_DEVICE_ID_INTEL_MCH_PA) ||
+ (pdev->device > PCI_DEVICE_ID_INTEL_MCH_PC1))
+ return;
+
+ if (list_empty(&pbus->devices)) {
+ /*
+ * If no device is attached to the root port at power-up or
+ * after hot-remove, the pbus->devices is empty and this code
+ * will set the offsets to zero and the bus ops to parent's bus
+ * ops, which is unmodified.
+ */
+ for (i= GET_INDEX(pdev->device, 0); i <= GET_INDEX(pdev->device, 7); ++i)
+ quirk_aspm_offset[i] = 0;
+
+ pbus->ops = pbus->parent->ops;
+ } else {
+ /*
+ * If devices are attached to the root port at power-up or
+ * after hot-add, the code loops through the device list of
+ * each root port to save the register offsets and replace the
+ * bus ops.
+ */
+ list_for_each_entry(dev, &pbus->devices, bus_list) {
+ /* There are 0 to 8 devices attached to this bus */
+ cap_base = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)]= cap_base + 0x10;
+ }
+ pbus->ops = &quirk_pcie_aspm_ops;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA, pcie_rootport_aspm_quirk );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA1, pcie_rootport_aspm_quirk );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB, pcie_rootport_aspm_quirk );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_rootport_aspm_quirk );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk );
+
diff -Nru a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
--- a/drivers/pci/hotplug/pciehp_ctrl.c 2004-11-12 15:13:05 -08:00
+++ b/drivers/pci/hotplug/pciehp_ctrl.c 2004-11-12 15:13:05 -08:00
@@ -38,6 +38,7 @@
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <linux/pci.h>
+#include "../pci.h"
#include "pciehp.h"
#include "pciehprm.h"

@@ -1220,7 +1221,13 @@
pciehp_configure_device(ctrl, new_func);
}
} while (new_func);
-
+
+ /*
+ * Some PCI Express root ports require fixup after hot-plug operation.
+ */
+ if (pcie_mch_quirk)
+ pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
+
if (PWR_LED(ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
down(&ctrl->crit_sect);
diff -Nru a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
--- a/drivers/pci/hotplug/pciehp_hpc.c 2004-11-12 15:13:05 -08:00
+++ b/drivers/pci/hotplug/pciehp_hpc.c 2004-11-12 15:13:05 -08:00
@@ -741,6 +741,8 @@
if (php_ctlr->irq) {
free_irq(php_ctlr->irq, ctrl);
php_ctlr->irq = 0;
+ if (!pcie_mch_quirk)
+ pci_disable_msi(php_ctlr->pci_dev);
}
}
if (php_ctlr->pci_dev)
@@ -1402,8 +1404,8 @@
start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
} else {
/* Installs the interrupt handler */
- dbg("%s: pciehp_msi_quirk = %x\n", __FUNCTION__, pciehp_msi_quirk);
- if (!pciehp_msi_quirk) {
+ dbg("%s: pcie_mch_quirk = %x\n", __FUNCTION__, pcie_mch_quirk);
+ if (!pcie_mch_quirk) {
rc = pci_enable_msi(pdev);
if (rc) {
info("Can't get msi for the hotplug controller\n");
diff -Nru a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
--- a/drivers/pci/hotplug/pciehp_pci.c 2004-11-12 15:13:05 -08:00
+++ b/drivers/pci/hotplug/pciehp_pci.c 2004-11-12 15:13:05 -08:00
@@ -82,9 +82,11 @@
{
int rc = 0;
int j;
+ struct pci_bus *pbus;

dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus,
func->device, func->function);
+ pbus = func->pci_dev->bus;

for (j=0; j<8 ; j++) {
struct pci_dev* temp = pci_find_slot(func->bus,
@@ -93,6 +95,12 @@
pci_remove_bus_device(temp);
}
}
+ /*
+ * Some PCI Express root ports require fixup after hot-plug operation.
+ */
+ if (pcie_mch_quirk)
+ pci_fixup_device(pci_fixup_final, pbus->self);
+
return rc;
}

diff -Nru a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
--- a/drivers/pci/hotplug/shpchp_hpc.c 2004-11-12 15:13:05 -08:00
+++ b/drivers/pci/hotplug/shpchp_hpc.c 2004-11-12 15:13:05 -08:00
@@ -792,6 +792,7 @@
if (php_ctlr->irq) {
free_irq(php_ctlr->irq, ctrl);
php_ctlr->irq = 0;
+ pci_disable_msi(php_ctlr->pci_dev);
}
}
if (php_ctlr->pci_dev) {
diff -Nru a/drivers/pci/pci.h b/drivers/pci/pci.h
--- a/drivers/pci/pci.h 2004-11-12 15:13:05 -08:00
+++ b/drivers/pci/pci.h 2004-11-12 15:13:05 -08:00
@@ -61,7 +61,7 @@
/* Lock for read/write access to pci device and bus lists */
extern spinlock_t pci_bus_lock;

-extern int pciehp_msi_quirk;
+extern int pcie_mch_quirk;
extern struct device_attribute pci_dev_attrs[];

/**
diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c
--- a/drivers/pci/quirks.c 2004-11-12 15:13:05 -08:00
+++ b/drivers/pci/quirks.c 2004-11-12 15:13:05 -08:00
@@ -1135,7 +1135,7 @@
#endif

#ifdef CONFIG_SCSI_SATA
-static void __init quirk_intel_ide_combined(struct pci_dev *pdev)
+static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
{
u8 prog, comb, tmp;
int ich = 0;
@@ -1209,14 +1209,15 @@
#endif /* CONFIG_SCSI_SATA */

-int pciehp_msi_quirk;
+int pcie_mch_quirk;

-static void __devinit quirk_pciehp_msi(struct pci_dev *pdev)
+static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
{
- pciehp_msi_quirk = 1;
+ pcie_mch_quirk = 1;
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi );
-
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch );

static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
{
@@ -1265,4 +1266,7 @@
pci_do_fixups(dev, start, end);
}

-EXPORT_SYMBOL(pciehp_msi_quirk);
+EXPORT_SYMBOL(pcie_mch_quirk);
+#ifdef CONFIG_HOTPLUG
+EXPORT_SYMBOL(pci_fixup_device);
+#endif
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h 2004-11-12 15:13:05 -08:00
+++ b/include/linux/pci_ids.h 2004-11-12 15:13:05 -08:00
@@ -2206,8 +2206,14 @@
#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577
#define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580
#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582
-#define PCI_DEVICE_ID_INTEL_SMCH 0x3590
+#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590
#define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592
+#define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595
+#define PCI_DEVICE_ID_INTEL_MCH_PA1 0x3596
+#define PCI_DEVICE_ID_INTEL_MCH_PB 0x3597
+#define PCI_DEVICE_ID_INTEL_MCH_PB1 0x3598
+#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599
+#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a
#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e
#define PCI_DEVICE_ID_INTEL_80310 0x530d
#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000