mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 23:27:06 +00:00
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>
This commit is contained in:
parent
17405453f4
commit
25aa295797
2 changed files with 10 additions and 4 deletions
|
@ -1120,6 +1120,7 @@ int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
|
||||||
int ioapic;
|
int ioapic;
|
||||||
int ioapic_pin;
|
int ioapic_pin;
|
||||||
struct io_apic_irq_attr irq_attr;
|
struct io_apic_irq_attr irq_attr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
|
if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
|
||||||
return gsi;
|
return gsi;
|
||||||
|
@ -1149,7 +1150,9 @@ int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
|
||||||
set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin,
|
set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin,
|
||||||
trigger == ACPI_EDGE_SENSITIVE ? 0 : 1,
|
trigger == ACPI_EDGE_SENSITIVE ? 0 : 1,
|
||||||
polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
|
polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
|
||||||
io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr);
|
ret = io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr);
|
||||||
|
if (ret < 0)
|
||||||
|
gsi = INT_MIN;
|
||||||
|
|
||||||
return gsi;
|
return gsi;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3380,12 +3380,15 @@ int io_apic_setup_irq_pin_once(unsigned int irq, int node,
|
||||||
{
|
{
|
||||||
unsigned int ioapic_idx = attr->ioapic, pin = attr->ioapic_pin;
|
unsigned int ioapic_idx = attr->ioapic, pin = attr->ioapic_pin;
|
||||||
int ret;
|
int ret;
|
||||||
|
struct IO_APIC_route_entry orig_entry;
|
||||||
|
|
||||||
/* Avoid redundant programming */
|
/* Avoid redundant programming */
|
||||||
if (test_bit(pin, ioapics[ioapic_idx].pin_programmed)) {
|
if (test_bit(pin, ioapics[ioapic_idx].pin_programmed)) {
|
||||||
pr_debug("Pin %d-%d already programmed\n",
|
pr_debug("Pin %d-%d already programmed\n", mpc_ioapic_id(ioapic_idx), pin);
|
||||||
mpc_ioapic_id(ioapic_idx), pin);
|
orig_entry = ioapic_read_entry(attr->ioapic, pin);
|
||||||
return 0;
|
if (attr->trigger == orig_entry.trigger && attr->polarity == orig_entry.polarity)
|
||||||
|
return 0;
|
||||||
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
ret = io_apic_setup_irq_pin(irq, node, attr);
|
ret = io_apic_setup_irq_pin(irq, node, attr);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
|
Loading…
Reference in a new issue