Commit febc94c5 authored by Len Brown's avatar Len Brown

[ACPI] sync with 2.4.23

Re-enable IRQ balacning if IOAPIC mode
http://bugzilla.kernel.org/show_bug.cgi?id=1440

Also allow IRQ balancing in PIC mode if "acpi_irq_balance"
http://bugzilla.kernel.org/show_bug.cgi?id=1391
parent 46313e34
...@@ -96,6 +96,18 @@ running once the system is up. ...@@ -96,6 +96,18 @@ running once the system is up.
level Force PIC-mode SCI to Level Trigger (default) level Force PIC-mode SCI to Level Trigger (default)
edge Force PIC-mode SCI to Edge Trigge edge Force PIC-mode SCI to Edge Trigge
acpi_irq_balance [HW,ACPI] ACPI will balance active IRQs
default in APIC mode
acpi_irq_nobalance [HW,ACPI] ACPI will not move active IRQs (default)
default in PIC mode
acpi_irq_pci= [HW,ACPI] If irq_balance, Clear listed IRQs for use by PCI
Format: <irq>,<irq>...
acpi_irq_isa= [HW,ACPI] If irq_balance, Mark listed IRQs used by ISA
Format: <irq>,<irq>...
ad1816= [HW,OSS] ad1816= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma2> Format: <io>,<irq>,<dma>,<dma2>
See also Documentation/sound/oss/AD1816. See also Documentation/sound/oss/AD1816.
......
...@@ -541,6 +541,8 @@ acpi_boot_init (void) ...@@ -541,6 +541,8 @@ acpi_boot_init (void)
acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
acpi_irq_balance_set(NULL);
acpi_ioapic = 1; acpi_ioapic = 1;
#endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */ #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
......
...@@ -521,6 +521,8 @@ acpi_boot_init (void) ...@@ -521,6 +521,8 @@ acpi_boot_init (void)
acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
acpi_irq_balance_set(NULL);
acpi_ioapic = 1; acpi_ioapic = 1;
#endif /*CONFIG_X86_IO_APIC*/ #endif /*CONFIG_X86_IO_APIC*/
......
...@@ -99,7 +99,7 @@ acpi_pci_link_check_possible ( ...@@ -99,7 +99,7 @@ acpi_pci_link_check_possible (
void *context) void *context)
{ {
struct acpi_pci_link *link = (struct acpi_pci_link *) context; struct acpi_pci_link *link = (struct acpi_pci_link *) context;
int i = 0; u32 i = 0;
ACPI_FUNCTION_TRACE("acpi_pci_link_check_possible"); ACPI_FUNCTION_TRACE("acpi_pci_link_check_possible");
...@@ -294,7 +294,10 @@ acpi_pci_link_try_get_current ( ...@@ -294,7 +294,10 @@ acpi_pci_link_try_get_current (
if (!link->irq.active) { if (!link->irq.active) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No active IRQ resource found\n")); ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No active IRQ resource found\n"));
printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for device (%s [%s]).\n", irq, acpi_device_name(link->device), acpi_device_bid(link->device)); printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for"
"device (%s [%s]).\n", irq,
acpi_device_name(link->device),
acpi_device_bid(link->device));
link->irq.active = irq; link->irq.active = irq;
} }
...@@ -429,30 +432,67 @@ acpi_pci_link_set ( ...@@ -429,30 +432,67 @@ acpi_pci_link_set (
PCI Link IRQ Management PCI Link IRQ Management
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
#define ACPI_MAX_IRQS 256
#define ACPI_MAX_ISA_IRQ 16
/* /*
* IRQ penalties are used to promote PCI IRQ balancing. We set each ISA- * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt
* possible IRQ (0-15) with a default penalty relative to its feasibility * Link Devices to move the PIRQs around to minimize sharing.
* for PCI's use: *
* "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs
* that the BIOS has already set to active. This is necessary because
* ACPI has no automatic means of knowing what ISA IRQs are used. Note that
* if the BIOS doesn't set a Link Device active, ACPI needs to program it
* even if acpi_irq_nobalance is set.
*
* A tables of penalties avoids directing PCI interrupts to well known
* ISA IRQs. Boot params are available to over-ride the default table:
* *
* Never use: 0, 1, 2 (timer, keyboard, and cascade) * List interrupts that are free for PCI use.
* Avoid using: 13, 14, and 15 (FP error and IDE) * acpi_irq_pci=n[,m]
* Penalize: 3, 4, 6, 7, 12 (known ISA uses)
* *
* Thus we're left with IRQs 5, 9, 10, 11, and everything above 15 (IO[S]APIC) * List interrupts that should not be used for PCI:
* as 'best bets' for PCI use. * acpi_irq_isa=n[,m]
*
* Note that PCI IRQ routers have a list of possible IRQs,
* which may not include the IRQs this table says are available.
*
* Since this heuristic can't tell the difference between a link
* that no device will attach to, vs. a link which may be shared
* by multiple active devices -- it is not optimal.
*
* If interrupt performance is that important, get an IO-APIC system
* with a pin dedicated to each device. Or for that matter, an MSI
* enabled system.
*/ */
#define ACPI_MAX_IRQS 256
#define ACPI_MAX_ISA_IRQ 16
#define PIRQ_PENALTY_PCI_AVAILABLE (0)
#define PIRQ_PENALTY_PCI_POSSIBLE (16*16)
#define PIRQ_PENALTY_PCI_USING (16*16*16)
#define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16)
#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16)
#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16)
static int acpi_irq_penalty[ACPI_MAX_IRQS] = { static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
1000000, 1000000, 1000000, 10000, PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */
10000, 0, 10000, 10000, PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */
10000, 0, 0, 0, PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */
10000, 100000, 100000, 100000, PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ5 sometimes SoundBlaster */
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ8 rtc, sometimes */
PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */
PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */
PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */
PIRQ_PENALTY_ISA_TYPICAL, /* IRQ12 mouse */
PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */
PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */
PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */
/* >IRQ15 */
}; };
int int
acpi_pci_link_check (void) acpi_pci_link_check (void)
{ {
...@@ -473,20 +513,30 @@ acpi_pci_link_check (void) ...@@ -473,20 +513,30 @@ acpi_pci_link_check (void)
continue; continue;
} }
if (link->irq.active) /*
acpi_irq_penalty[link->irq.active] += 100; * reflect the possible and active irqs in the penalty table --
else if (link->irq.possible_count) { * useful for breaking ties.
int penalty = 100 / link->irq.possible_count; */
for (i=0; i<link->irq.possible_count; i++) { if (link->irq.possible_count) {
int penalty = PIRQ_PENALTY_PCI_POSSIBLE / link->irq.possible_count;
for (i = 0; i < link->irq.possible_count; i++) {
if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ) if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
acpi_irq_penalty[link->irq.possible[i]] += penalty; acpi_irq_penalty[link->irq.possible[i]] += penalty;
} }
} else if (link->irq.active) {
acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_POSSIBLE;
} }
} }
/* Add a penalty for the SCI */
acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
return_VALUE(0); return_VALUE(0);
} }
static int acpi_irq_balance; /* 0: static, 1: balance */
static int acpi_pci_link_allocate(struct acpi_pci_link* link) { static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
int irq; int irq;
int i; int i;
...@@ -500,12 +550,14 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) { ...@@ -500,12 +550,14 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
irq = link->irq.active; irq = link->irq.active;
} else { } else {
irq = link->irq.possible[0]; irq = link->irq.possible[0];
}
if (acpi_irq_balance || !link->irq.active) {
/* /*
* Select the best IRQ. This is done in reverse to promote * Select the best IRQ. This is done in reverse to promote
* the use of IRQs 9, 10, 11, and >15. * the use of IRQs 9, 10, 11, and >15.
*/ */
for (i=(link->irq.possible_count-1); i>0; i--) { for (i = (link->irq.possible_count - 1); i >= 0; i--) {
if (acpi_irq_penalty[irq] > acpi_irq_penalty[link->irq.possible[i]]) if (acpi_irq_penalty[irq] > acpi_irq_penalty[link->irq.possible[i]])
irq = link->irq.possible[i]; irq = link->irq.possible[i];
} }
...@@ -518,13 +570,14 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) { ...@@ -518,13 +570,14 @@ static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
acpi_device_bid(link->device)); acpi_device_bid(link->device));
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
} else { } else {
acpi_irq_penalty[link->irq.active] += 100; acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
printk(PREFIX "%s [%s] enabled at IRQ %d\n", printk(PREFIX "%s [%s] enabled at IRQ %d\n",
acpi_device_name(link->device), acpi_device_name(link->device),
acpi_device_bid(link->device), link->irq.active); acpi_device_bid(link->device), link->irq.active);
} }
link->irq.setonboot = 1; link->irq.setonboot = 1;
return_VALUE(0); return_VALUE(0);
} }
...@@ -607,9 +660,12 @@ acpi_pci_link_add ( ...@@ -607,9 +660,12 @@ acpi_pci_link_add (
if (result) if (result)
goto end; goto end;
/* query and set link->irq.active */
acpi_pci_link_get_current(link); acpi_pci_link_get_current(link);
printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), acpi_device_bid(device)); //#ifdef CONFIG_ACPI_DEBUG
printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
acpi_device_bid(device));
for (i = 0; i < link->irq.possible_count; i++) { for (i = 0; i < link->irq.possible_count; i++) {
if (link->irq.active == link->irq.possible[i]) { if (link->irq.active == link->irq.possible[i]) {
printk(" *%d", link->irq.possible[i]); printk(" *%d", link->irq.possible[i]);
...@@ -619,6 +675,7 @@ acpi_pci_link_add ( ...@@ -619,6 +675,7 @@ acpi_pci_link_add (
printk(" %d", link->irq.possible[i]); printk(" %d", link->irq.possible[i]);
} }
printk(")\n"); printk(")\n");
//#endif /* CONFIG_ACPI_DEBUG */
/* TBD: Acquire/release lock */ /* TBD: Acquire/release lock */
list_add_tail(&link->node, &acpi_link.entries); list_add_tail(&link->node, &acpi_link.entries);
...@@ -654,6 +711,77 @@ acpi_pci_link_remove ( ...@@ -654,6 +711,77 @@ acpi_pci_link_remove (
return_VALUE(0); return_VALUE(0);
} }
/*
* modify acpi_irq_penalty[] from cmdline
*/
static int __init acpi_irq_penalty_update(char *str, int used)
{
int i;
for (i = 0; i < 16; i++) {
int retval;
int irq;
retval = get_option(&str,&irq);
if (!retval)
break; /* no number found */
if (irq < 0)
continue;
if (irq >= ACPI_MAX_IRQS)
continue;
if (used)
acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
else
acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
if (retval != 2) /* no next number */
break;
}
return 1;
}
/*
* Over-ride default table to reserve additional IRQs for use by ISA
* e.g. acpi_irq_isa=5
* Useful for telling ACPI how not to interfere with your ISA sound card.
*/
static int __init acpi_irq_isa(char *str)
{
return(acpi_irq_penalty_update(str, 1));
}
__setup("acpi_irq_isa=", acpi_irq_isa);
/*
* Over-ride default table to free additional IRQs for use by PCI
* e.g. acpi_irq_pci=7,15
* Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing.
*/
static int __init acpi_irq_pci(char *str)
{
return(acpi_irq_penalty_update(str, 0));
}
__setup("acpi_irq_pci=", acpi_irq_pci);
static int __init acpi_irq_nobalance_set(char *str)
{
printk("ACPI STATIC SET\n");
acpi_irq_balance = 0;
return(1);
}
__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
int __init acpi_irq_balance_set(char *str)
{
printk("ACPI BALANCE SET\n");
acpi_irq_balance = 1;
return(1);
}
__setup("acpi_irq_balance", acpi_irq_balance_set);
static int __init acpi_pci_link_init (void) static int __init acpi_pci_link_init (void)
{ {
......
...@@ -139,6 +139,12 @@ static inline void disable_ioapic_setup(void) ...@@ -139,6 +139,12 @@ static inline void disable_ioapic_setup(void)
#endif #endif
#ifdef CONFIG_ACPI_PCI
extern int acpi_irq_balance_set(char *str);
#else
static inline int acpi_irq_balance_set(char *str) { return 0; }
#endif
#ifdef CONFIG_ACPI_SLEEP #ifdef CONFIG_ACPI_SLEEP
/* routines for saving/restoring kernel state */ /* routines for saving/restoring kernel state */
......
...@@ -124,6 +124,12 @@ extern int acpi_ioapic; ...@@ -124,6 +124,12 @@ extern int acpi_ioapic;
#endif /*CONFIG_ACPI_BOOT*/ #endif /*CONFIG_ACPI_BOOT*/
#ifdef CONFIG_ACPI_PCI
extern int acpi_irq_balance_set(char *str);
#else
static inline int acpi_irq_balance_set(char *str) { return 0; }
#endif
#ifdef CONFIG_ACPI_SLEEP #ifdef CONFIG_ACPI_SLEEP
/* routines for saving/restoring kernel state */ /* routines for saving/restoring kernel state */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment