diff options
| author | Suresh B. Siddha <suresh.b.siddha@intel.com> | 2004-10-18 09:02:26 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-10-18 09:02:26 -0700 |
| commit | 41b12ce3c47df492fe4591e8099d304ace7c809d (patch) | |
| tree | 0d11afae5e3cced630038264fbe6c9cfce9fd05b | |
| parent | c2634010e63ddba0efee4546b3f10f4d19acace2 (diff) | |
[PATCH] Disable SW irqbalance/irqaffinity for E7520/E7320/E7525 v2
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 <suresh.b.siddha@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | arch/i386/kernel/io_apic.c | 4 | ||||
| -rw-r--r-- | drivers/pci/quirks.c | 48 | ||||
| -rw-r--r-- | include/asm-i386/irq.h | 4 | ||||
| -rw-r--r-- | include/linux/irq.h | 2 | ||||
| -rw-r--r-- | include/linux/pci_ids.h | 2 | ||||
| -rw-r--r-- | kernel/irq/proc.c | 3 | ||||
| -rw-r--r-- | kernel/irq/spurious.c | 2 |
7 files changed, 61 insertions, 4 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 9b65953b2e51..48fa9cc14f65 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -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 --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 164f738df6a7..faaf5d04c05b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -18,6 +18,7 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/irq.h> #undef DEBUG @@ -978,11 +979,58 @@ static void __init quirk_intel_ide_combined(struct pci_dev *pdev) 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 --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h index 3204b45544f3..05b9e61b0a72 100644 --- a/include/asm-i386/irq.h +++ b/include/asm-i386/irq.h @@ -34,4 +34,8 @@ extern void release_vm86_irqs(struct task_struct *); # define irq_ctx_init(cpu) do { } while (0) #endif +#ifdef CONFIG_IRQBALANCE +extern int irqbalance_disable(char *str); +#endif + #endif /* _ASM_IRQ_H */ diff --git a/include/linux/irq.h b/include/linux/irq.h index 012315f5665c..fa3677deff3c 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -76,6 +76,8 @@ extern int setup_irq(unsigned int irq, struct irqaction * new); #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 --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index eed506d0196d..271f3eb29a60 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -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 --git a/kernel/irq/proc.c b/kernel/irq/proc.c index e29a833e065f..2ddbe8404c9c 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -32,13 +32,14 @@ static int irq_affinity_read_proc(char *page, char **start, off_t off, 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 --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index 3081611f9a23..f6297c306905 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -85,7 +85,7 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) 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"); |
