aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLiu Ping Fan <kernelfans@gmail.com>2013-08-23 04:58:47 -0400
committerIngo Molnar <mingo@kernel.org>2013-08-26 06:58:00 -0400
commit25aa2957973d361081ac6c8b6e5a0d9d7a83fef6 (patch)
treead77338c9f70a2dd2f4c731e71e1a4cd12c29fee /arch
parent17405453f4ad0220721a29978692081be6392b8f (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.c5
-rw-r--r--arch/x86/kernel/apic/io_apic.c9
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)