[PATCH 3/3] RTAS MSI

Jake Moilanen moilanen at austin.ibm.com
Fri Jun 9 02:13:13 EST 2006


Here's a version addressing Nathan's concerns.

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

Index: 2.6/drivers/pci/Makefile
===================================================================
--- 2.6.orig/drivers/pci/Makefile	2006-06-08 10:30:14.000000000 -0500
+++ 2.6/drivers/pci/Makefile	2006-06-08 10:30:21.000000000 -0500
@@ -26,7 +26,14 @@
 obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
-obj-$(CONFIG_PCI_MSI) += msi.o
+
+msiobj-$(CONFIG_X86) += msi.o msi-apic.o msi-intel.o
+msiobj-$(CONFIG_IA64) += msi.o msi-apic.o msi-intel.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi.o msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi.o msi-altix.o
+msiobj-$(CONFIG_PPC_PSERIES) += msi-rtas.o
+
+obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
 # ACPI Related PCI FW Functions
Index: 2.6/drivers/pci/msi-rtas.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ 2.6/drivers/pci/msi-rtas.c	2006-06-08 10:51:13.000000000 -0500
@@ -0,0 +1,150 @@
+/*
+ * Jake Moilanen <moilanen at austin.ibm.com>
+ * Copyright (C) 2006 IBM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+int rtas_enable_msi(struct pci_dev* pdev)
+{
+	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];
+	int dummy;
+	unsigned int virq;
+	unsigned int addr;
+	unsigned long buid = -1;
+	struct device_node * dn;
+
+	BUG_ON(!pdev);
+
+	dn = pci_device_to_OF_node(pdev);
+
+	if (!of_find_property(dn, "ibm,req#msi", &dummy))
+		return -ENOENT;
+
+	reg = (u32 *) get_property(dn, "reg", &reglen);
+	if (reg == NULL || reglen < 20)
+		return -ENXIO;
+
+	devfn = (reg[0] >> 8) & 0xff;
+	busno = (reg[0] >> 16) & 0xff;
+
+	buid = get_phb_buid(dn->parent);
+	addr = (busno << 16) | (devfn << 8);
+
+	do {
+		rc = rtas_call(rtas_token("ibm,change-msi"), 6, 3, ret, addr,
+			       buid >> 32, buid & 0xffffffff,
+			       0, 0, seq_num);
+
+		seq_num = ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc)
+	{
+		printk(KERN_WARNING "error[%d]: getting the number of "
+		       "MSI interrupts for %s\n", rc, dn->name);
+		return -EIO;
+	}
+
+	/* Return if there's no MSI interrupts */
+	if (!ret[0])
+		return -ENOENT;
+
+	dn->n_intrs = ret[0];
+
+	dn->intrs = kmalloc(dn->n_intrs * sizeof(*(dn->intrs)), GFP_KERNEL);
+	if (!dn->intrs) {
+		printk(KERN_WARNING "rtas_enable_msi: can't allocate space\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < dn->n_intrs; i++) {
+		do {
+			rc = rtas_call(query_token, 4, 3, ret, addr,
+				       buid >> 32, buid & 0xffffffff, i);
+		} while (rtas_busy_delay(rc));
+
+		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);
+		}
+	}
+
+	/* Just give the first vector out for now */
+	pdev->irq = dn->intrs[0].line;
+
+	return 0;
+}
+
+void rtas_disable_msi(struct pci_dev* pdev)
+{
+	int seq_num = 1;
+	struct device_node * dn;
+	int rc;
+	int devfn;
+	int busno;
+	u32 *reg;
+	int reglen;
+	int ret[3];
+	int dummy;
+	unsigned int addr;
+	unsigned long buid = -1;
+
+	BUG_ON(!pdev);
+
+	dn = pci_device_to_OF_node(pdev);
+
+	if (!of_find_property(dn, "ibm,req#msi", &dummy))
+		return;
+
+	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);
+
+	do {
+		rc = rtas_call(rtas_token("ibm,change-msi"), 6, 3, ret, addr,
+			       buid >> 32, buid & 0xffffffff,
+			       2, 0, seq_num);
+
+		seq_num = ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		printk(KERN_WARNING "error[%d]: setting the number of "
+		       "MSI interrupts for %s\n", rc, dn->name);
+		return;
+	}
+
+	dn->n_intrs = 0;
+
+	kfree(dn->intrs);
+}
Index: 2.6/drivers/pci/Kconfig
===================================================================
--- 2.6.orig/drivers/pci/Kconfig	2006-06-08 10:30:14.000000000 -0500
+++ 2.6/drivers/pci/Kconfig	2006-06-08 10:30:21.000000000 -0500
@@ -4,7 +4,7 @@
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
-	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC_PSERIES
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to
Index: 2.6/arch/powerpc/platforms/pseries/setup.c
===================================================================
--- 2.6.orig/arch/powerpc/platforms/pseries/setup.c	2006-06-08 10:30:14.000000000 -0500
+++ 2.6/arch/powerpc/platforms/pseries/setup.c	2006-06-08 10:30:21.000000000 -0500
@@ -205,6 +205,10 @@
 	} else {
 		ppc_md.init_IRQ       = xics_init_IRQ;
 		ppc_md.get_irq        = xics_get_irq;
+#ifdef CONFIG_PCI_MSI
+		ppc_md.enable_msi	= rtas_enable_msi;
+		ppc_md.disable_msi	= rtas_disable_msi;
+#endif
 	}
 
 #ifdef CONFIG_SMP
Index: 2.6/include/asm-powerpc/rtas.h
===================================================================
--- 2.6.orig/include/asm-powerpc/rtas.h	2006-06-08 10:30:21.000000000 -0500
+++ 2.6/include/asm-powerpc/rtas.h	2006-06-08 10:30:21.000000000 -0500
@@ -4,6 +4,7 @@
 
 #include <linux/spinlock.h>
 #include <asm/page.h>
+#include <linux/pci.h>
 
 /*
  * Definitions for talking to the RTAS on CHRP machines.
@@ -182,6 +183,9 @@
 
 extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
 
+extern int rtas_enable_msi(struct pci_dev* pdev);
+extern void rtas_disable_msi(struct pci_dev * pdev);
+
 /* Error types logged.  */
 #define ERR_FLAG_ALREADY_LOGGED	0x0
 #define ERR_FLAG_BOOT		0x1 	/* log was pulled from NVRAM on boot */



More information about the Linuxppc-dev mailing list