[PATCH 2/2] Base pSeries PCIe support

Jake Moilanen moilanen at austin.ibm.com
Sat Apr 1 09:13:30 EST 2006


This patch hooks our current interrupt subsystem and sets up a single
vector MSI as if it was a LSI.  Multiple MSI vectors is coming in the
future.

The NR_IRQS got bumped up to 1024, as vectors can go much higher.
Unfortunately, this number was arbitrarily picked as there is no claim
at what the max number really is by either the firmware team, or the
PAPR+.

Signed-off-by: Jake Moilanen <moilanen at austin.ibm.com>

---

Index: 2.6.16/arch/powerpc/kernel/prom.c
===================================================================
--- 2.6.16.orig/arch/powerpc/kernel/prom.c	2006-03-31 15:11:20.000000000 -0600
+++ 2.6.16/arch/powerpc/kernel/prom.c	2006-03-31 15:37:10.000000000 -0600
@@ -88,6 +88,8 @@
 struct device_node *dflt_interrupt_controller;
 int num_interrupt_controllers;
 
+void __init finish_msi_node(struct device_node *dn, unsigned long *mem_start, int measure_only);
+
 /*
  * Wrapper for allocating memory for various data that needs to be
  * attached to device nodes as they are processed at boot or when
@@ -120,6 +122,22 @@
 	return NULL;
 }
 
+int
+property_present(struct device_node *np, const char *name)
+{
+	struct property *pp;
+
+	read_lock(&devtree_lock);
+	for (pp = np->properties; pp != 0; pp = pp->next)
+		if (strcmp(pp->name, name) == 0) {
+			return 1;
+		}
+	read_unlock(&devtree_lock);
+
+	return 0;
+}
+
+
 /*
  * Find the interrupt parent of a node.
  */
@@ -341,6 +359,14 @@
 		return 0;
 	}
 
+#ifdef CONFIG_PPC_PSERIES
+	if(property_present(np, "ibm,req#msi")) {
+		printk(KERN_EMERG "Found MSI\n");
+		finish_msi_node(np, mem_start, measure_only);
+		return 0;
+	}
+#endif
+
 	ints = (unsigned int *) get_property(np, "interrupts", &intlen);
 	TRACE("ints=%p, intlen=%d\n", ints, intlen);
 	if (ints == NULL)
@@ -503,6 +529,80 @@
 	DBG(" <- finish_device_tree\n");
 }
 
+void __init finish_msi_node(struct device_node *dn, unsigned long *mem_start, int measure_only)
+{
+	static int seq_num = 1;
+	int i;
+	int rc;
+	int query_token = rtas_token("ibm,query-interrupt-source-number");
+	int devfn;
+	int busno;
+	u32 *reg;
+	int reglen;
+	int ret[3];
+	unsigned int virq;
+	unsigned int addr;
+	unsigned long buid = -1;
+	unsigned long wait_time;
+
+	reg = (u32 *) get_property(dn, "reg", &reglen);
+	if (reg == NULL || reglen < 20)
+		return;
+
+	devfn = (reg[0] >> 8) & 0xff;
+	busno = (reg[0] >> 16) & 0xff;
+
+	buid = get_phb_buid(dn->parent);
+	addr = (busno << 16) | (devfn << 8);
+
+	while (1) {
+		rc = rtas_call(rtas_token("ibm,change-msi"), 6, 3, ret, addr,
+			       buid >> 32, buid & 0xffffffff,
+			       1, 1, seq_num);
+
+		if (!rc)
+			break;
+		else if (rc == RTAS_BUSY)
+			udelay(1);
+		else if (rtas_is_extended_busy(rc)) {
+			wait_time = rtas_extended_busy_delay_time(rc);
+			udelay(wait_time * 1000);
+		} else {
+			printk(KERN_WARNING "error[%d]: getting the number of"
+			       "MSI interrupts for %s\n", rc, dn->name);
+			return;
+		}
+
+		seq_num = ret[1];
+	}
+
+	dn->n_intrs = ret[0];
+
+	dn->intrs = prom_alloc(dn->n_intrs * sizeof(*(dn->intrs)), mem_start);
+	if (!dn->intrs) {
+		printk(KERN_EMERG "finish_msi_node: can't allocate space\n");
+		return;
+	}
+
+	if (measure_only)
+		return;
+
+	for (i = 0; i < dn->n_intrs; i++) {
+		rc = rtas_call(query_token, 4, 3, ret, addr, buid >> 32, buid & 0xffffffff, i);
+
+		if (!rc) {
+			virq = virt_irq_create_mapping(ret[0]);
+
+			dn->intrs[i].line = irq_offset_up(virq);
+			dn->intrs[i].sense = ret[1];
+		} else {
+			printk(KERN_WARNING "error[%d]: query-interrupt-source-number for %s\n",
+			       rc, dn->name);
+		}
+	}
+
+}
+
 static inline char *find_flat_dt_string(u32 offset)
 {
 	return ((char *)initial_boot_params) +
Index: 2.6.16/include/asm-powerpc/irq.h
===================================================================
--- 2.6.16.orig/include/asm-powerpc/irq.h	2006-03-31 15:11:12.000000000 -0600
+++ 2.6.16/include/asm-powerpc/irq.h	2006-03-31 15:15:46.000000000 -0600
@@ -47,7 +47,7 @@
 /*
  * Maximum number of interrupt sources that we can handle.
  */
-#define NR_IRQS		512
+#define NR_IRQS		1024
 
 /* Interrupt numbers are virtual in case they are sparsely
  * distributed by the hardware.
Index: 2.6.16/include/asm-powerpc/pci-bridge.h
===================================================================
--- 2.6.16.orig/include/asm-powerpc/pci-bridge.h	2006-03-31 15:11:36.000000000 -0600
+++ 2.6.16/include/asm-powerpc/pci-bridge.h	2006-03-31 15:34:50.000000000 -0600
@@ -141,6 +141,7 @@
 void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus);
 
 extern int pcibios_remove_root_bus(struct pci_controller *phb);
+extern unsigned long __devinit get_phb_buid (struct device_node *phb);
 
 static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
 {




More information about the Linuxppc-dev mailing list