Skip to contentSkip to conversation

PCI Allow OutOfRange PIRQ table address

PATCH In review [email protected] 2 participants 2 messages Mar 17, 2005 Documentation

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 PCI Allow OutOfRange PIRQ table address

Hi Greg, PCI folk,

I updated this to change pirq_table_addr to a long, and to add a warning msg if the PIRQ table wasn't found at the specified address, as per thread with Matthew Wilcox. Let me know if it's okay. Thanks.

In our hardware situation, the BIOS is unable to store or generate it's PIRQ table in the F0000h-100000h standard range. This patch adds a pci kernel parameter, pirqaddr to allow the bootloader (or BIOS based loader) to inform the kernel where the PIRQ table got stored. A beneficial side-effect is that, if one's BIOS uses a static address each time for it's PIRQ table, then pirqaddr can be used to avoid the $pirq search through that address block each time at boot for normal PIRQ BIOSes.

arch/i386/pci/common.c +4 -0
diff -uprN -X dontdiff linux-2.6.11.2-vanilla/arch/i386/pci/common.c linux-2.6.11.2/arch/i386/pci/common.c
@@ -25,6 +25,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS 
 
 int pci_routeirq;
 int pcibios_last_bus = -1;
+unsigned long pirq_table_addr = 0;
 struct pci_bus *pci_root_bus = NULL;
 struct pci_raw_ops *raw_pci_ops;
 
@@ -188,6 +189,9 @@ char * __devinit  pcibios_setup(char *st
 	} else if (!strcmp(str, "biosirq")) {
 		pci_probe |= PCI_BIOS_IRQ_SCAN;
 		return NULL;
+	} else if (!strncmp(str, "pirqaddr=", 9)) {
+		pirq_table_addr = simple_strtol(str+9, NULL, 0);
+		return NULL;
 	}
 #endif
 #ifdef CONFIG_PCI_DIRECT
arch/i386/pci/irq.c +38 -13

65 lines not on this page · raw message

arch/i386/pci/pci.h +1 -0
diff -uprN -X dontdiff linux-2.6.11.2-vanilla/arch/i386/pci/pci.h linux-2.6.11.2/arch/i386/pci/pci.h
@@ -27,6 +27,7 @@
 #define PCI_ASSIGN_ALL_BUSSES	0x4000
 
 extern unsigned int pci_probe;
+extern unsigned long pirq_table_addr;
 
 /* pci-i386.c */
 
Documentation/kernel-parameters.txt +4 -0
diff -uprN -X dontdiff linux-2.6.11.2-vanilla/Documentation/kernel-parameters.txt linux-2.6.11.2/Documentation/kernel-parameters.txt
@@ -967,6 +967,10 @@ running once the system is up.
 		irqmask=0xMMMM		[IA-32] Set a bit mask of IRQs allowed to be assigned
 					automatically to PCI devices. You can make the kernel
 					exclude IRQs of your ISA cards this way.
+		pirqaddr=0xAAAAA	[IA-32] Specify the physical address
+					of the PIRQ table (normally generated
+					by the BIOS) if it is outside the .  
+					F0000h-100000h range.
 		lastbus=N		[IA-32] Scan all buses till bus #N. Can be useful
 					if the kernel is unable to find your secondary buses
 					and you want to tell it explicitly which ones they are.
#1 lore raw
Quoted 20 lines · [email protected] wrote:

Hi Greg, PCI folk,

I updated this to change pirq_table_addr to a long, and to add a warning msg if the PIRQ table wasn't found at the specified address, as per thread with Matthew Wilcox. Let me know if it's okay. Thanks.

In our hardware situation, the BIOS is unable to store or generate it's PIRQ table in the F0000h-100000h standard range. This patch adds a pci kernel parameter, pirqaddr to allow the bootloader (or BIOS based loader) to inform the kernel where the PIRQ table got stored. A beneficial side-effect is that, if one's BIOS uses a static address each time for it's PIRQ table, then pirqaddr can be used to avoid the $pirq search through that address block each time at boot for normal PIRQ BIOSes.

diff -uprN -X dontdiff linux-2.6.11.2-vanilla/arch/i386/pci/common.c linux-2.6.11.2/arch/i386/pci/common.c

arch/i386/pci/common.c unsigned int pci_probe = PCI_PROBE_BIOS · line 28

Quoted 4 lines
arch/i386/pci/common.c +1 -0
@@ -25,6 +25,7 @@ unsigned int pci_probe = PCI_PROBE_BIOS 
 
 int pci_routeirq;
 int pcibios_last_bus = -1;
+unsigned long pirq_table_addr = 0;

Don't need to init above (or below) to 0.

arch/i386/pci/common.c char * __devinit pcibios_setup(char *st · line 193

Quoted 9 lines
arch/i386/pci/common.c +2 -0
 struct pci_bus *pci_root_bus = NULL;
 struct pci_raw_ops *raw_pci_ops;
 
@@ -188,6 +189,9 @@ char * __devinit  pcibios_setup(char *st
 	} else if (!strcmp(str, "biosirq")) {
 		pci_probe |= PCI_BIOS_IRQ_SCAN;
 		return NULL;
+	} else if (!strncmp(str, "pirqaddr=", 9)) {
+		pirq_table_addr = simple_strtol(str+9, NULL, 0);

Use simple_strtoul().

Quoted 8 lines
arch/i386/pci/common.c +1 -0
+		return NULL;
 	}
 #endif
 #ifdef CONFIG_PCI_DIRECT

diff -uprN -X dontdiff linux-2.6.11.2-vanilla/arch/i386/pci/irq.c linux-2.6.11.2/arch/i386/pci/irq.c

arch/i386/pci/irq.c struct irq_router_handler { · line 65

Quoted 8 lines
arch/i386/pci/irq.c +5 -0
@@ -58,6 +58,35 @@ struct irq_router_handler {
 int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
 
 /*
+ *  Check passed address for the PCI IRQ Routing Table signature 
+ *  and perform checksum verification.
+ */
+
+static inline struct irq_routing_table * __init pirq_check_routing_table(u8 *addr)

This doesn't need to be both inline and __init.

arch/i386/pci/irq.c struct irq_router_handler { · line 78

Quoted 13 lines
arch/i386/pci/irq.c +13 -0
+{
+	struct irq_routing_table *rt;
+	int i;
+	u8 sum;
+
+	rt = (struct irq_routing_table *) addr;
+	if (rt->signature != PIRQ_SIGNATURE ||
+	    rt->version != PIRQ_VERSION ||
+	    rt->size % 16 ||
+	    rt->size < sizeof(struct irq_routing_table))
+		return NULL;
+	sum = 0;
+	for(i=0; i<rt->size; i++)

Space after for: "for ("
Spaces around "<" would be nice for readability.

Quoted 16 lines
arch/i386/pci/irq.c +11 -0
+		sum += addr[i];
+	if (!sum) {
+		DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+		return rt;
+	}
+	return NULL;
+}
+
+
+
+/*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
  */
 
@@ -65,21 +94,17 @@ static struct irq_routing_table * __init
 {

arch/i386/pci/irq.c static struct irq_routing_table * __init · line 102

Quoted 10 lines
arch/i386/pci/irq.c +5 -2
 	u8 *addr;
 	struct irq_routing_table *rt;
-	int i;
-	u8 sum;
 
+	if (pirq_table_addr) {
+		rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr));
+		if (rt) {
+			return rt;
+		}

No braces when not needed for block of statements.

Quoted 34 lines
arch/i386/pci/irq.c +4 -11
+		printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); 
+	}
 	for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
-		rt = (struct irq_routing_table *) addr;
-		if (rt->signature != PIRQ_SIGNATURE ||
-		    rt->version != PIRQ_VERSION ||
-		    rt->size % 16 ||
-		    rt->size < sizeof(struct irq_routing_table))
-			continue;
-		sum = 0;
-		for(i=0; i<rt->size; i++)
-			sum += addr[i];
-		if (!sum) {
-			DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+		rt = pirq_check_routing_table(addr);
+		if (rt) {
 			return rt;
 		}
 	}

diff -uprN -X dontdiff linux-2.6.11.2-vanilla/arch/i386/pci/pci.h linux-2.6.11.2/arch/i386/pci/pci.h

arch/i386/pci/pci.h +1 -0
@@ -27,6 +27,7 @@
 #define PCI_ASSIGN_ALL_BUSSES	0x4000
 
 extern unsigned int pci_probe;
+extern unsigned long pirq_table_addr;
 
 /* pci-i386.c */
 

diff -uprN -X dontdiff linux-2.6.11.2-vanilla/Documentation/kernel-parameters.txt linux-2.6.11.2/Documentation/kernel-parameters.txt

Documentation/kernel-parameters.txt running once the system is up. · line 972

Quoted 6 lines
Documentation/kernel-parameters.txt +3 -0
@@ -967,6 +967,10 @@ running once the system is up.
 		irqmask=0xMMMM		[IA-32] Set a bit mask of IRQs allowed to be assigned
 					automatically to PCI devices. You can make the kernel
 					exclude IRQs of your ISA cards this way.
+		pirqaddr=0xAAAAA	[IA-32] Specify the physical address
+					of the PIRQ table (normally generated
+					by the BIOS) if it is outside the .  

What is the trailing " . " here? (above)

Quoted 5 lines
Documentation/kernel-parameters.txt +1 -1
+					F0000h-100000h range.
 		lastbus=N		[IA-32] Scan all buses till bus #N. Can be useful
 					if the kernel is unable to find your secondary buses
 					and you want to tell it explicitly which ones they are.
-
Signature · 1 line
~Randy