diff options
-rw-r--r-- | arch/x86/kernel/io_apic_32.c | 21 | ||||
-rw-r--r-- | arch/x86/kernel/io_apic_64.c | 24 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 2 | ||||
-rw-r--r-- | drivers/acpi/ec.c | 8 | ||||
-rw-r--r-- | drivers/acpi/sbs.c | 25 | ||||
-rw-r--r-- | drivers/pnp/pnpacpi/rsparser.c | 24 | ||||
-rw-r--r-- | include/linux/acpi.h | 5 |
7 files changed, 90 insertions, 19 deletions
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index f35c6eb..6bb80ea 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c @@ -962,7 +962,7 @@ static int EISA_ELCR(unsigned int irq) #define default_MCA_trigger(idx) (1) #define default_MCA_polarity(idx) (0) -static int __init MPBIOS_polarity(int idx) +static int MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; int polarity; @@ -2830,6 +2830,25 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a return 0; } +int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) +{ + int i; + + if (skip_ioapic_setup) + return -1; + + for (i = 0; i < mp_irq_entries; i++) + if (mp_irqs[i].mpc_irqtype == mp_INT && + mp_irqs[i].mpc_srcbusirq == bus_irq) + break; + if (i >= mp_irq_entries) + return -1; + + *trigger = irq_trigger(i); + *polarity = irq_polarity(i); + return 0; +} + #endif /* CONFIG_ACPI */ static int __init parse_disable_timer_pin_1(char *arg) diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c index 953328b..435a8c9 100644 --- a/arch/x86/kernel/io_apic_64.c +++ b/arch/x86/kernel/io_apic_64.c @@ -546,7 +546,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) #define default_PCI_trigger(idx) (1) #define default_PCI_polarity(idx) (1) -static int __init MPBIOS_polarity(int idx) +static int MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; int polarity; @@ -2222,8 +2222,27 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p return 0; } -#endif /* CONFIG_ACPI */ +int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity) +{ + int i; + + if (skip_ioapic_setup) + return -1; + + for (i = 0; i < mp_irq_entries; i++) + if (mp_irqs[i].mpc_irqtype == mp_INT && + mp_irqs[i].mpc_srcbusirq == bus_irq) + break; + if (i >= mp_irq_entries) + return -1; + + *trigger = irq_trigger(i); + *polarity = irq_polarity(i); + return 0; +} + +#endif /* CONFIG_ACPI */ /* * This function currently is only a helper for the i386 smp boot process where @@ -2260,3 +2279,4 @@ void __init setup_ioapic_dest(void) } } #endif + diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 192c244..2e8e790 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -153,6 +153,8 @@ static int acpi_battery_get_property(struct power_supply *psy, val->intval = POWER_SUPPLY_STATUS_CHARGING; else if (battery->state == 0) val->intval = POWER_SUPPLY_STATUS_FULL; + else + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; break; case POWER_SUPPLY_PROP_PRESENT: val->intval = acpi_battery_present(battery); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 390f8f8..d6ddb54 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -890,12 +890,20 @@ int __init acpi_ec_ecdt_probe(void) boot_ec->gpe = ecdt_ptr->gpe; boot_ec->handle = ACPI_ROOT_OBJECT; } else { + /* This workaround is needed only on some broken machines, + * which require early EC, but fail to provide ECDT */ + acpi_handle x; printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, boot_ec, NULL); /* Check that acpi_get_devices actually find something */ if (ACPI_FAILURE(status) || !boot_ec->handle) goto error; + /* We really need to limit this workaround, the only ASUS, + * which needs it, has fake EC._INI method, so use it as flag. + */ + if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x))) + goto error; } ret = ec_install_handlers(boot_ec); diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 90fd09c..73c1ba3 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -113,6 +113,7 @@ struct acpi_battery { u16 spec; u8 id; u8 present:1; + u8 have_sysfs_alarm:1; }; #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); @@ -808,7 +809,13 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) } battery->bat.get_property = acpi_sbs_battery_get_property; result = power_supply_register(&sbs->device->dev, &battery->bat); - device_create_file(battery->bat.dev, &alarm_attr); + if (result) + goto end; + result = device_create_file(battery->bat.dev, &alarm_attr); + if (result) + goto end; + battery->have_sysfs_alarm = 1; + end: printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), battery->name, sbs->battery->present ? "present" : "absent"); @@ -817,14 +824,16 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) static void acpi_battery_remove(struct acpi_sbs *sbs, int id) { - if (sbs->battery[id].bat.dev) - device_remove_file(sbs->battery[id].bat.dev, &alarm_attr); - power_supply_unregister(&sbs->battery[id].bat); -#ifdef CONFIG_ACPI_PROCFS - if (sbs->battery[id].proc_entry) { - acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry), - acpi_battery_dir); + struct acpi_battery *battery = &sbs->battery[id]; + + if (battery->bat.dev) { + if (battery->have_sysfs_alarm) + device_remove_file(battery->bat.dev, &alarm_attr); + power_supply_unregister(&battery->bat); } +#ifdef CONFIG_ACPI_PROCFS + if (battery->proc_entry) + acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir); #endif } diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index cd0a204..11adab1 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -75,6 +75,7 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, { int i = 0; int irq; + int p, t; if (!valid_IRQ(gsi)) return; @@ -85,15 +86,22 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, if (i >= PNP_MAX_IRQ) return; -#ifdef CONFIG_X86 - if (gsi < 16 && (triggering != ACPI_EDGE_SENSITIVE || - polarity != ACPI_ACTIVE_HIGH)) { - pnp_warn("BIOS BUG: legacy PNP IRQ %d should be edge trigger, " - "active high", gsi); - triggering = ACPI_EDGE_SENSITIVE; - polarity = ACPI_ACTIVE_HIGH; + /* + * in IO-APIC mode, use overrided attribute. Two reasons: + * 1. BIOS bug in DSDT + * 2. BIOS uses IO-APIC mode Interrupt Source Override + */ + if (!acpi_get_override_irq(gsi, &t, &p)) { + t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; + p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; + + if (triggering != t || polarity != p) { + pnp_warn("IRQ %d override to %s, %s", + gsi, t ? "edge":"level", p ? "low":"high"); + triggering = t; + polarity = p; + } } -#endif res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag res->irq_resource[i].flags |= irq_flags(triggering, polarity); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 8ccedf7..e3c16c9 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -132,6 +132,11 @@ extern unsigned long acpi_realmode_flags; int acpi_register_gsi (u32 gsi, int triggering, int polarity); int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); +#ifdef CONFIG_X86_IO_APIC +extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity); +#else +#define acpi_get_override_irq(bus, trigger, polarity) (-1) +#endif /* * This function undoes the effect of one call to acpi_register_gsi(). * If this matches the last registration, any IRQ resources for gsi |