@ -36,6 +36,7 @@
# include <linux/mutex.h>
# include <linux/slab.h>
# include <linux/acpi.h>
# include <linux/irq.h>
# include "internal.h"
@ -440,7 +441,6 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
# 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)
@ -457,9 +457,9 @@ static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
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 */
0 , /* IRQ9 PCI, often acpi */
0 , /* IRQ10 PCI */
0 , /* IRQ11 PCI */
PIRQ_PENALTY_ISA_USED , /* IRQ12 mouse */
PIRQ_PENALTY_ISA_USED , /* IRQ13 fpe, sometimes */
PIRQ_PENALTY_ISA_USED , /* IRQ14 ide0 */
@ -467,6 +467,60 @@ static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
/* >IRQ15 */
} ;
static int acpi_irq_pci_sharing_penalty ( int irq )
{
struct acpi_pci_link * link ;
int penalty = 0 ;
list_for_each_entry ( link , & acpi_link_list , list ) {
/*
* If a link is active , penalize its IRQ heavily
* so we try to choose a different IRQ .
*/
if ( link - > irq . active & & link - > irq . active = = irq )
penalty + = PIRQ_PENALTY_PCI_USING ;
else {
int i ;
/*
* If a link is inactive , penalize the IRQs it
* might use , but not as severely .
*/
for ( i = 0 ; i < link - > irq . possible_count ; i + + )
if ( link - > irq . possible [ i ] = = irq )
penalty + = PIRQ_PENALTY_PCI_POSSIBLE /
link - > irq . possible_count ;
}
}
return penalty ;
}
static int acpi_irq_get_penalty ( int irq )
{
int penalty = 0 ;
if ( irq < ACPI_MAX_ISA_IRQ )
penalty + = acpi_irq_penalty [ irq ] ;
/*
* Penalize IRQ used by ACPI SCI . If ACPI SCI pin attributes conflict
* with PCI IRQ attributes , mark ACPI SCI as ISA_ALWAYS so it won ' t be
* use for PCI IRQs .
*/
if ( irq = = acpi_gbl_FADT . sci_interrupt ) {
u32 type = irq_get_trigger_type ( irq ) & IRQ_TYPE_SENSE_MASK ;
if ( type ! = IRQ_TYPE_LEVEL_LOW )
penalty + = PIRQ_PENALTY_ISA_ALWAYS ;
else
penalty + = PIRQ_PENALTY_PCI_USING ;
}
penalty + = acpi_irq_pci_sharing_penalty ( irq ) ;
return penalty ;
}
int __init acpi_irq_penalty_init ( void )
{
struct acpi_pci_link * link ;
@ -547,12 +601,12 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
* the use of IRQs 9 , 10 , 11 , and > 15.
*/
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_get_penalty ( irq ) >
acpi_irq_get_penalty ( link - > irq . possible [ i ] ) )
irq = link - > irq . possible [ i ] ;
}
}
if ( acpi_irq_penalty [ irq ] > = PIRQ_PENALTY_ISA_ALWAYS ) {
if ( acpi_irq_get_penalty ( irq ) > = PIRQ_PENALTY_ISA_ALWAYS ) {
printk ( KERN_ERR PREFIX " No IRQ available for %s [%s]. "
" Try pci=noacpi or acpi=off \n " ,
acpi_device_name ( link - > device ) ,
@ -568,7 +622,6 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
acpi_device_bid ( link - > device ) ) ;
return - ENODEV ;
} else {
acpi_irq_penalty [ link - > irq . active ] + = PIRQ_PENALTY_PCI_USING ;
printk ( KERN_WARNING PREFIX " %s [%s] enabled at IRQ %d \n " ,
acpi_device_name ( link - > device ) ,
acpi_device_bid ( link - > device ) , link - > irq . active ) ;
@ -800,9 +853,10 @@ static int __init acpi_irq_penalty_update(char *str, int used)
continue ;
if ( used )
acpi_irq_penalty [ irq ] + = PIRQ_PENALTY_ISA_USED ;
acpi_irq_penalty [ irq ] = acpi_irq_get_penalty ( irq ) +
PIRQ_PENALTY_ISA_USED ;
else
acpi_irq_penalty [ irq ] = PIRQ_PENALTY_PCI_AVAILABLE ;
acpi_irq_penalty [ irq ] = 0 ;
if ( retval ! = 2 ) /* no next number */
break ;
@ -819,34 +873,19 @@ static int __init acpi_irq_penalty_update(char *str, int used)
*/
void acpi_penalize_isa_irq ( int irq , int active )
{
if ( irq > = 0 & & irq < ARRAY_SIZE ( acpi_irq_penalty ) ) {
if ( active )
acpi_irq_penalty [ irq ] + = PIRQ_PENALTY_ISA_USED ;
else
acpi_irq_penalty [ irq ] + = PIRQ_PENALTY_PCI_USING ;
}
if ( irq > = 0 & & irq < ARRAY_SIZE ( acpi_irq_penalty ) )
acpi_irq_penalty [ irq ] = acpi_irq_get_penalty ( irq ) +
active ? PIRQ_PENALTY_ISA_USED : PIRQ_PENALTY_PCI_USING ;
}
bool acpi_isa_irq_available ( int irq )
{
return irq > = 0 & & ( irq > = ARRAY_SIZE ( acpi_irq_penalty ) | |
acpi_irq_penalty [ irq ] < PIRQ_PENALTY_ISA_ALWAYS ) ;
acpi_irq_get_penalty ( irq ) < PIRQ_PENALTY_ISA_ALWAYS ) ;
}
/*
* Penalize IRQ used by ACPI SCI . If ACPI SCI pin attributes conflict with
* PCI IRQ attributes , mark ACPI SCI as ISA_ALWAYS so it won ' t be use for
* PCI IRQs .
*/
void acpi_penalize_sci_irq ( int irq , int trigger , int polarity )
{
if ( irq > = 0 & & irq < ARRAY_SIZE ( acpi_irq_penalty ) ) {
if ( trigger ! = ACPI_MADT_TRIGGER_LEVEL | |
polarity ! = ACPI_MADT_POLARITY_ACTIVE_LOW )
acpi_irq_penalty [ irq ] + = PIRQ_PENALTY_ISA_ALWAYS ;
else
acpi_irq_penalty [ irq ] + = PIRQ_PENALTY_PCI_USING ;
}
}
/*