Commit e1981aa9 authored by Len Brown's avatar Len Brown Committed by Len Brown

[ACPI] ACPI SCI shall be level/low unless explicit over-ride

http://bugzilla.kernel.org/show_bug.cgi?id=1622
add "acpi_sci=edge" and "acpi_sci=high" manual over-ride
parent c0354d57
No related merge requests found
......@@ -99,10 +99,8 @@ running once the system is up.
See also Documentation/pm.txt.
acpi_pic_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
Format: { level | edge }
level Force PIC-mode SCI to Level Trigger (default)
edge Force PIC-mode SCI to Edge Trigge
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
Format: { level | edge | high | low }
acpi_irq_balance [HW,ACPI] ACPI will balance active IRQs
default in APIC mode
......
......@@ -50,6 +50,9 @@ int acpi_lapic;
int acpi_ioapic;
int acpi_strict;
acpi_interrupt_flags acpi_sci_flags __initdata;
int acpi_sci_override_gsi __initdata;
#ifdef CONFIG_X86_LOCAL_APIC
static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
#endif
......@@ -244,6 +247,34 @@ acpi_parse_ioapic (
return 0;
}
/*
* Parse Interrupt Source Override for the ACPI SCI
*/
static void
acpi_parse_sci_int_src_ovr(u8 bus_irq, u16 polarity, u16 trigger, u32 global_irq)
{
if (trigger == 0) /* compatible SCI trigger is level */
trigger = 3;
if (polarity == 0) /* compatible SCI polarity is low */
polarity = 3;
/* Command-line over-ride via acpi_sci= */
if (acpi_sci_flags.trigger)
trigger = acpi_sci_flags.trigger;
if (acpi_sci_flags.polarity)
polarity = acpi_sci_flags.polarity;
mp_override_legacy_irq(bus_irq, polarity, trigger, global_irq);
/*
* stash over-ride to indicate we've been here
* and for later update of acpi_fadt
*/
acpi_sci_override_gsi = global_irq;
return;
}
static int __init
acpi_parse_int_src_ovr (
......@@ -257,6 +288,13 @@ acpi_parse_int_src_ovr (
acpi_table_print_madt_entry(header);
if (intsrc->bus_irq == acpi_fadt.sci_int) {
acpi_parse_sci_int_src_ovr(intsrc->bus_irq,
intsrc->flags.polarity, intsrc->flags.trigger,
intsrc->global_irq);
return 0;
}
mp_override_legacy_irq (
intsrc->bus_irq,
intsrc->flags.polarity,
......@@ -287,14 +325,14 @@ acpi_parse_nmi_src (
#endif /* CONFIG_X86_IO_APIC */
#ifdef CONFIG_ACPI_BUS
/*
* "acpi_pic_sci=level" (current default)
* programs the PIC-mode SCI to Level Trigger.
* (NO-OP if the BIOS set Level Trigger already)
* acpi_pic_sci_set_trigger()
*
* use ELCR to set PIC-mode trigger type for SCI
*
* If a PIC-mode SCI is not recognized or gives spurious IRQ7's
* it may require Edge Trigger -- use "acpi_pic_sci=edge"
* (NO-OP if the BIOS set Edge Trigger already)
* it may require Edge Trigger -- use "acpi_sci=edge"
*
* Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
* for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge.
......@@ -302,10 +340,8 @@ acpi_parse_nmi_src (
* ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0)
*/
static int __initdata acpi_pic_sci_trigger; /* 0: level, 1: edge */
void __init
acpi_pic_sci_set_trigger(unsigned int irq)
acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
{
unsigned char mask = 1 << (irq & 7);
unsigned int port = 0x4d0 + (irq >> 3);
......@@ -316,37 +352,21 @@ acpi_pic_sci_set_trigger(unsigned int irq)
if (!(val & mask)) {
printk(" Edge");
if (!acpi_pic_sci_trigger) {
if (trigger == 3) {
printk(" set to Level");
outb(val | mask, port);
}
} else {
printk(" Level");
if (acpi_pic_sci_trigger) {
if (trigger == 1) {
printk(" set to Edge");
outb(val | mask, port);
outb(val & ~mask, port);
}
}
printk(" Trigger.\n");
}
int __init
acpi_pic_sci_setup(char *str)
{
while (str && *str) {
if (strncmp(str, "level", 5) == 0)
acpi_pic_sci_trigger = 0; /* force level trigger */
if (strncmp(str, "edge", 4) == 0)
acpi_pic_sci_trigger = 1; /* force edge trigger */
str = strchr(str, ',');
if (str)
str += strspn(str, ", \t");
}
return 1;
}
__setup("acpi_pic_sci=", acpi_pic_sci_setup);
#endif /* CONFIG_ACPI_BUS */
......@@ -442,8 +462,6 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
#define acpi_parse_hpet NULL
#endif
/* detect the location of the ACPI PM Timer */
#ifdef CONFIG_X86_PM_TIMER
extern u32 pmtmr_ioport;
static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
......@@ -456,6 +474,13 @@ static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
return 0;
}
#ifdef CONFIG_ACPI_INTERPRETER
/* initialize sci_int early for INT_SRC_OVR MADT parsing */
acpi_fadt.sci_int = fadt->sci_int;
#endif
#ifdef CONFIG_X86_PM_TIMER
/* detect the location of the ACPI PM Timer */
if (fadt->revision >= FADT2_REVISION_ID) {
/* FADT rev. 2 */
if (fadt->xpm_tmr_blk.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO)
......@@ -468,11 +493,9 @@ static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
}
if (pmtmr_ioport)
printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport);
#endif
return 0;
}
#else
#define acpi_parse_fadt NULL
#endif
unsigned long __init
......@@ -592,6 +615,13 @@ acpi_parse_madt_ioapic_entries(void)
return count;
}
/*
* If BIOS did not supply an INT_SRC_OVR for the SCI
* pretend we got one so we can set the SCI flags.
*/
if (!acpi_sci_override_gsi)
acpi_parse_sci_int_src_ovr(acpi_fadt.sci_int, 0, 0, acpi_fadt.sci_int);
count = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS);
if (count < 0) {
printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
......@@ -696,12 +726,16 @@ acpi_boot_init (void)
return error;
}
/*
* set sci_int and PM timer address
*/
acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
/*
* Process the Multiple APIC Description Table (MADT), if present
*/
acpi_process_madt();
acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
......
......@@ -1036,69 +1036,6 @@ void __init mp_config_acpi_legacy_irqs (void)
extern FADT_DESCRIPTOR acpi_fadt;
void __init mp_config_ioapic_for_sci(u32 gsi)
{
int ioapic;
int ioapic_pin;
struct acpi_table_madt *madt;
struct acpi_table_int_src_ovr *entry = NULL;
acpi_interrupt_flags flags;
void *madt_end;
acpi_status status;
/*
* Ensure that if there is an interrupt source override entry
* for the ACPI SCI, we leave it as is. Unfortunately this involves
* walking the MADT again.
*/
status = acpi_get_firmware_table("APIC", 1, ACPI_LOGICAL_ADDRESSING,
(struct acpi_table_header **) &madt);
if (ACPI_SUCCESS(status)) {
madt_end = (void *) (unsigned long)madt + madt->header.length;
entry = (struct acpi_table_int_src_ovr *)
((unsigned long) madt + sizeof(struct acpi_table_madt));
while ((void *) entry < madt_end) {
if (entry->header.type == ACPI_MADT_INT_SRC_OVR &&
acpi_fadt.sci_int == entry->bus_irq)
goto found;
entry = (struct acpi_table_int_src_ovr *)
((unsigned long) entry + entry->header.length);
}
}
/*
* Although the ACPI spec says that the SCI should be level/low
* don't reprogram it unless there is an explicit MADT OVR entry
* instructing us to do so -- otherwise we break Tyan boards which
* have the SCI wired edge/high but no MADT OVR.
*/
return;
found:
/*
* See the note at the end of ACPI 2.0b section
* 5.2.10.8 for what this is about.
*/
flags = entry->flags;
acpi_fadt.sci_int = entry->global_irq;
gsi = entry->global_irq;
ioapic = mp_find_ioapic(gsi);
ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
/*
* MPS INTI flags:
* trigger: 0=default, 1=edge, 3=level
* polarity: 0=default, 1=high, 3=low
* Per ACPI spec, default for SCI means level/low.
*/
io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
(flags.trigger == 1 ? 0 : 1), (flags.polarity == 1 ? 0 : 1));
}
#ifdef CONFIG_ACPI_PCI
void __init mp_parse_prt (void)
......
......@@ -79,6 +79,7 @@ EXPORT_SYMBOL(acpi_disabled);
#ifdef CONFIG_ACPI_BOOT
int __initdata acpi_force = 0;
extern acpi_interrupt_flags acpi_sci_flags;
#endif
int MCA_bus;
......@@ -596,6 +597,18 @@ static void __init parse_cmdline_early (char ** cmdline_p)
acpi_noirq_set();
}
else if (!memcmp(from, "acpi_sci=edge", 13))
acpi_sci_flags.trigger = 1;
else if (!memcmp(from, "acpi_sci=level", 14))
acpi_sci_flags.trigger = 3;
else if (!memcmp(from, "acpi_sci=high", 13))
acpi_sci_flags.polarity = 1;
else if (!memcmp(from, "acpi_sci=low", 12))
acpi_sci_flags.polarity = 3;
#ifdef CONFIG_X86_LOCAL_APIC
/* disable IO-APIC */
else if (!memcmp(from, "noapic", 6))
......
......@@ -39,7 +39,11 @@
#define _COMPONENT ACPI_BUS_COMPONENT
ACPI_MODULE_NAME ("acpi_bus")
#ifdef CONFIG_X86_64
extern void __init acpi_pic_sci_set_trigger(unsigned int irq);
#elif defined(CONFIG_X86)
extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
#endif
FADT_DESCRIPTOR acpi_fadt;
struct acpi_device *acpi_root;
......@@ -609,13 +613,25 @@ acpi_bus_init (void)
printk(KERN_ERR PREFIX "Unable to get the FADT\n");
goto error1;
}
#ifdef CONFIG_X86
#ifdef CONFIG_X86_64
/* Ensure the SCI is set to level-triggered, active-low */
if (acpi_ioapic)
mp_config_ioapic_for_sci(acpi_fadt.sci_int);
else
acpi_pic_sci_set_trigger(acpi_fadt.sci_int);
#elif defined(CONFIG_X86)
if (!acpi_ioapic) {
extern acpi_interrupt_flags acpi_sci_flags;
/* Set PIC-mode SCI trigger type */
acpi_pic_sci_set_trigger(acpi_fadt.sci_int, acpi_sci_flags.trigger);
} else {
extern int acpi_sci_override_gsi;
/*
* now that acpi_fadt is initialized,
* update it with result from INT_SRC_OVR parsing
*/
acpi_fadt.sci_int = acpi_sci_override_gsi;
}
#endif
status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
......
......@@ -34,13 +34,6 @@ extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
extern void mp_config_acpi_legacy_irqs (void);
extern void mp_parse_prt (void);
#ifdef CONFIG_X86_IO_APIC
extern void mp_config_ioapic_for_sci(u32 gsi);
#else
static inline void mp_config_ioapic_for_sci(u32 gsi)
{ }
#endif
#endif /*CONFIG_ACPI_BOOT*/
#define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS)
......
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