Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 4006

kernel-2.6.18-194.11.1.el5.src.rpm

From: Kevin Monroe <kmonroe@redhat.com>
Date: Fri, 21 Aug 2009 18:30:26 -0400
Subject: [x86] pnpacpi: fix serial ports on IBM Point-of-Sale HW
Message-id: 20090821222658.21144.2154.sendpatchset@squad5-lp1.lab.bos.redhat.com
O-Subject: [PATCH RHEL5.5 BZ506799] Alter pnpacpi code to fix serial ports on IBM POS hardware
Bugzilla: 506799
RH-Acked-by: Matthew Garrett <mjg@redhat.com>

RHBZ#:
======
https://bugzilla.redhat.com/show_bug.cgi?id=506799

Description:
============
Reading/writing with a loopback serial device on IBM POS 4838-310 hardware does not work without the pnpacpi=off boot option. An upstream ACPI fix was made that addresses this issue. Description of upstream commit:

Use mp_irqs[] to get PNP device's interrupt polarity and trigger.
There are two reasons to do this:
1. BIOS bug for PNP interrupt
2. BIOS explictly does override
mp_irqs[] should cover all the cases.

RHEL Version Found:
===================
RHEL 5.4

kABI Status:
============
No symbols were harmed.

Brew:
=====
Built on all platforms.
http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1939926

Upstream Status:
================
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=61fd47e0c84764f49b4e52bfd8170fac52636f00

Test Status:
============
Testing was done by connecting a serial loopback device, reading from one tty (cat /dev/ttyS0) and writing to another (echo foo > /dev/ttyS1). Without this patch, the echo blocks for a while and then returns with no console output seen.

After this patch is applied, the test runs as expected ("foo" is output to the console).
===============================================================
Kevin Monroe 978-392-3183 ext 23183
IBM on-site partner

Proposed Patch:
===============

diff --git a/arch/i386/kernel/io_apic-xen.c b/arch/i386/kernel/io_apic-xen.c
index dc20fcc..c479de3 100644
--- a/arch/i386/kernel/io_apic-xen.c
+++ b/arch/i386/kernel/io_apic-xen.c
@@ -963,7 +963,7 @@ static int EISA_ELCR(unsigned int irq)
 #define default_NEC98_trigger(idx)     (0)
 #define default_NEC98_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;
@@ -2768,4 +2768,23 @@ 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 */
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 9a21455..84889d1 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -915,7 +915,7 @@ static int EISA_ELCR(unsigned int irq)
 #define default_NEC98_trigger(idx)     (0)
 #define default_NEC98_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;
@@ -2711,4 +2711,23 @@ 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 */
diff --git a/arch/x86_64/kernel/io_apic-xen.c b/arch/x86_64/kernel/io_apic-xen.c
index bc894fa..b47bcee 100644
--- a/arch/x86_64/kernel/io_apic-xen.c
+++ b/arch/x86_64/kernel/io_apic-xen.c
@@ -601,7 +601,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;
@@ -2229,6 +2229,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 */
 
 
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index e4ddc3c..3caf95d 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -553,7 +553,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;
@@ -2294,6 +2294,25 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
 	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 */
 
 
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index dc79b0a..720c13a 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -78,6 +78,7 @@ pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
 {
 	int i = 0;
 	int irq;
+	int p, t;
 
 	if (!valid_IRQ(gsi))
 		return;
@@ -88,6 +89,23 @@ pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
 	if (i >= PNP_MAX_IRQ)
 		return;
 
+	/*
+	 * 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;
+		}
+	}
+
 	res->irq_resource[i].flags = IORESOURCE_IRQ;  // Also clears _UNSET flag
 	irq = acpi_register_gsi(gsi, triggering, polarity);
 	if (irq < 0) {
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 41df59f..0f5676d 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -450,6 +450,11 @@ extern unsigned long acpi_video_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