diff options
author | Liu Ping Fan <kernelfans@gmail.com> | 2013-08-23 04:58:47 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-08-26 06:58:00 -0400 |
commit | 25aa2957973d361081ac6c8b6e5a0d9d7a83fef6 (patch) | |
tree | ad77338c9f70a2dd2f4c731e71e1a4cd12c29fee /arch | |
parent | 17405453f4ad0220721a29978692081be6392b8f (diff) |
x86/ioapic: Check attr against the previous setting when programmed more than once
When programming ioapic pinX more than once, current code
does not check whether the later attr (trigger & polarity) is the
same as the former or not.
This causes broken semantics which can be observed in a qemu q35
machine, where ioapic's ioredtbl[x] can never be set as low-active,
even if the hpet driver registered it.
And hpet driver may share a high-level active IRQ line with other
devices. So in qemu, when hpet-dev asserts low-level as kernel
expects, the kernel has no response.
With this patch, we can observe an ioredtbl[x] set as low-active
for hpet.
Fix it by reporting -EBUSY to the caller, when attr is different.
Signed-off-by: Liu Ping Fan <pingfank@linux.vnet.ibm.com>
Cc: Kevin Hao <haokexin@gmail.com>
Cc: Len Brown <len.brown@intel.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Link: http://lkml.kernel.org/r/1377248327-19633-1-git-send-email-pingfank@linux.vnet.ibm.com
[ Made small readability edits to both the changelog and the code. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/acpi/boot.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 9 |
2 files changed, 10 insertions, 4 deletions
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 872a2d255e41..81aa73b8ecf5 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -1120,6 +1120,7 @@ int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) | |||
1120 | int ioapic; | 1120 | int ioapic; |
1121 | int ioapic_pin; | 1121 | int ioapic_pin; |
1122 | struct io_apic_irq_attr irq_attr; | 1122 | struct io_apic_irq_attr irq_attr; |
1123 | int ret; | ||
1123 | 1124 | ||
1124 | if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) | 1125 | if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) |
1125 | return gsi; | 1126 | return gsi; |
@@ -1149,7 +1150,9 @@ int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) | |||
1149 | set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin, | 1150 | set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin, |
1150 | trigger == ACPI_EDGE_SENSITIVE ? 0 : 1, | 1151 | trigger == ACPI_EDGE_SENSITIVE ? 0 : 1, |
1151 | polarity == ACPI_ACTIVE_HIGH ? 0 : 1); | 1152 | polarity == ACPI_ACTIVE_HIGH ? 0 : 1); |
1152 | io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr); | 1153 | ret = io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr); |
1154 | if (ret < 0) | ||
1155 | gsi = INT_MIN; | ||
1153 | 1156 | ||
1154 | return gsi; | 1157 | return gsi; |
1155 | } | 1158 | } |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 260abc2f9eeb..e63a5bd2a78f 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -3380,12 +3380,15 @@ int io_apic_setup_irq_pin_once(unsigned int irq, int node, | |||
3380 | { | 3380 | { |
3381 | unsigned int ioapic_idx = attr->ioapic, pin = attr->ioapic_pin; | 3381 | unsigned int ioapic_idx = attr->ioapic, pin = attr->ioapic_pin; |
3382 | int ret; | 3382 | int ret; |
3383 | struct IO_APIC_route_entry orig_entry; | ||
3383 | 3384 | ||
3384 | /* Avoid redundant programming */ | 3385 | /* Avoid redundant programming */ |
3385 | if (test_bit(pin, ioapics[ioapic_idx].pin_programmed)) { | 3386 | if (test_bit(pin, ioapics[ioapic_idx].pin_programmed)) { |
3386 | pr_debug("Pin %d-%d already programmed\n", | 3387 | pr_debug("Pin %d-%d already programmed\n", mpc_ioapic_id(ioapic_idx), pin); |
3387 | mpc_ioapic_id(ioapic_idx), pin); | 3388 | orig_entry = ioapic_read_entry(attr->ioapic, pin); |
3388 | return 0; | 3389 | if (attr->trigger == orig_entry.trigger && attr->polarity == orig_entry.polarity) |
3390 | return 0; | ||
3391 | return -EBUSY; | ||
3389 | } | 3392 | } |
3390 | ret = io_apic_setup_irq_pin(irq, node, attr); | 3393 | ret = io_apic_setup_irq_pin(irq, node, attr); |
3391 | if (!ret) | 3394 | if (!ret) |