From: Suresh Siddha As part of the workaround for the "Interrupt message re-ordering across hub interface" errata (page #16 in http://developer.intel.com/design/chipsets/specupdt/30288402.pdf), BIOS may enable hardware IRQ balancing for E7520/E7320/E7525(revision ID 0x9 and below) based platforms. Add pci quirks to disable SW irqbalance/affinity on those platforms. Move balanced_irq_init() to late_initcall so that kirqd will be started after pci quirks. Signed-off-by: Suresh Siddha Signed-off-by: Andrew Morton --- 25-akpm/arch/i386/kernel/io_apic.c | 4 +-- 25-akpm/drivers/pci/quirks.c | 48 +++++++++++++++++++++++++++++++++++++ 25-akpm/include/asm-i386/irq.h | 4 +++ 25-akpm/include/linux/irq.h | 2 + 25-akpm/include/linux/pci_ids.h | 2 + 25-akpm/kernel/irq/proc.c | 3 +- 25-akpm/kernel/irq/spurious.c | 2 - 7 files changed, 61 insertions(+), 4 deletions(-) diff -puN arch/i386/kernel/io_apic.c~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 arch/i386/kernel/io_apic.c --- 25/arch/i386/kernel/io_apic.c~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 Fri Oct 8 13:34:32 2004 +++ 25-akpm/arch/i386/kernel/io_apic.c Fri Oct 8 13:34:32 2004 @@ -636,7 +636,7 @@ failed: return 0; } -static int __init irqbalance_disable(char *str) +int __init irqbalance_disable(char *str) { irqbalance_disabled = 1; return 0; @@ -653,7 +653,7 @@ static inline void move_irq(int irq) } } -__initcall(balanced_irq_init); +late_initcall(balanced_irq_init); #else /* !CONFIG_IRQBALANCE */ static inline void move_irq(int irq) { } diff -puN drivers/pci/quirks.c~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 drivers/pci/quirks.c --- 25/drivers/pci/quirks.c~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 Fri Oct 8 13:34:32 2004 +++ 25-akpm/drivers/pci/quirks.c Fri Oct 8 13:34:32 2004 @@ -18,6 +18,7 @@ #include #include #include +#include #undef DEBUG @@ -1210,11 +1211,58 @@ static void __init quirk_intel_ide_combi DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined ); #endif /* CONFIG_SCSI_SATA */ +#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) + +void __devinit quirk_intel_irqbalance(struct pci_dev *dev) +{ + u8 config, rev; + u32 word; + extern struct pci_raw_ops *raw_pci_ops; + + /* BIOS may enable hardware IRQ balancing for + * E7520/E7320/E7525(revision ID 0x9 and below) + * based platforms. + * Disable SW irqbalance/affinity on those platforms. + */ + pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev); + if (rev > 0x9) + return; + + printk(KERN_INFO "Intel E7520/7320/7525 detected."); + + /* enable access to config space*/ + pci_read_config_byte(dev, 0xf4, &config); + config |= 0x2; + pci_write_config_byte(dev, 0xf4, config); + + /* read xTPR register */ + raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word); + + if (!(word & (1 << 13))) { + printk(KERN_INFO "Disabling irq balancing and affinity\n"); +#ifdef CONFIG_IRQBALANCE + irqbalance_disable(""); +#endif + noirqdebug_setup(""); + no_irq_affinity = 1; + } + + config &= ~0x2; + /* disable access to config space*/ + pci_write_config_byte(dev, 0xf4, config); +} +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); +#endif + int pciehp_msi_quirk; static void __devinit quirk_pciehp_msi(struct pci_dev *pdev) { pciehp_msi_quirk = 1; +#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) + quirk_intel_irqbalance(pdev); +#endif } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi ); diff -puN include/asm-i386/irq.h~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 include/asm-i386/irq.h --- 25/include/asm-i386/irq.h~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 Fri Oct 8 13:34:32 2004 +++ 25-akpm/include/asm-i386/irq.h Fri Oct 8 13:34:32 2004 @@ -34,4 +34,8 @@ extern void release_vm86_irqs(struct tas # define irq_ctx_init(cpu) do { } while (0) #endif +#ifdef CONFIG_IRQBALANCE +extern int irqbalance_disable(char *str); +#endif + #endif /* _ASM_IRQ_H */ diff -puN include/linux/irq.h~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 include/linux/irq.h --- 25/include/linux/irq.h~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 Fri Oct 8 13:34:32 2004 +++ 25-akpm/include/linux/irq.h Fri Oct 8 13:34:32 2004 @@ -76,6 +76,8 @@ extern int setup_irq(unsigned int irq, s #ifdef CONFIG_GENERIC_HARDIRQS extern cpumask_t irq_affinity[NR_IRQS]; +extern int no_irq_affinity; +extern int noirqdebug_setup(char *str); extern asmlinkage int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action); diff -puN include/linux/pci_ids.h~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 include/linux/pci_ids.h --- 25/include/linux/pci_ids.h~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 Fri Oct 8 13:34:32 2004 +++ 25-akpm/include/linux/pci_ids.h Fri Oct 8 13:34:32 2004 @@ -2205,6 +2205,8 @@ #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_E7320_MCH 0x3592 +#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e #define PCI_DEVICE_ID_INTEL_80310 0x530d #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 diff -puN kernel/irq/proc.c~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 kernel/irq/proc.c --- 25/kernel/irq/proc.c~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 Fri Oct 8 13:34:32 2004 +++ 25-akpm/kernel/irq/proc.c Fri Oct 8 13:34:32 2004 @@ -32,13 +32,14 @@ static int irq_affinity_read_proc(char * return len; } +int no_irq_affinity; static int irq_affinity_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data) { unsigned int irq = (int)(long)data, full_count = count, err; cpumask_t new_value, tmp; - if (!irq_desc[irq].handler->set_affinity) + if (!irq_desc[irq].handler->set_affinity || no_irq_affinity) return -EIO; err = cpumask_parse(buffer, count, new_value); diff -puN kernel/irq/spurious.c~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 kernel/irq/spurious.c --- 25/kernel/irq/spurious.c~disable-sw-irqbalance-irqaffinity-for-e7520-e7320-e7525-2 Fri Oct 8 13:34:32 2004 +++ 25-akpm/kernel/irq/spurious.c Fri Oct 8 13:34:32 2004 @@ -85,7 +85,7 @@ void note_interrupt(unsigned int irq, ir int noirqdebug; -static int __init noirqdebug_setup(char *str) +int __init noirqdebug_setup(char *str) { noirqdebug = 1; printk(KERN_INFO "IRQ lockup detection disabled\n"); _