linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] msi abstractions and support for altix
@ 2006-01-19 19:46 Mark Maule
  2006-01-19 19:46 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
                   ` (2 more replies)
  0 siblings, 3 replies; 38+ messages in thread
From: Mark Maule @ 2006-01-19 19:46 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: Tony Luck, gregkh, Mark Maule

Resend #5:  bug fixes

Patch set to abstract portions of the MSI core so that it can be used on
architectures which don't use standard interrupt controllers.

Changes from Resend #4

+ Fix an x86_64 build problem
+ Fix an ia64 CONFIG_IA64_GENERIC build problem
+ Fix a bug in the new ia64 reserve_irq_vector()
+ Restore dev->irq if msi_ops->setup fails
+ Redo msi-altix.patch so it applies on 2.6.16-rc1

Changes from Resend #3 

+ Move external declarations of msi_apic_ops out of routines, and up earlier
  in the respective .h files.
+ Add comments to the msi_ops structure declaration

Changes from Resend #2

+ Cleanup the ia64 platform_msi_init macro so it works on non-altix ia64

Changes from initial version

+ Change uintXX_t to uXX
+ Change _callouts to _ops
+ Renamed the _generic routines to _apic and moved them to a new file
  msi-apic.c
+ Have each msi_arch_init() routine call msi_register() with the desired
  msi ops for that platform.
+ Moved msi_address, msi_data, and related defs out of msi.h and into
  msi-apic.c, replaced by shifts/masks.
+ Rolled msi-arch-init.patch and msi-callouts.patch into a single msi-ops.patch

Mark

1/3 msi-ops.patch
	Add an msi_arch_init() hook which can be used to perform platform
	specific setup prior to msi use.

	Define a set of msi ops to implement the platform-specific tasks:

	    setup - set up plumbing to get a vector directed at a default
		cpu, and return the corresponding MSI bus address and data.
	    teardown - inverse of msi_setup
	    target - retarget a vector to a given cpu

	Define the routine msi_register() called from msi_arch_init()
	to set the desired ops.

	Move a bunch of apic-specific code out of the msi core .h/.c and
	into a new msi-apic.c file.

2/3 ia64-per-platform-device-vector.patch
	For the ia64 arch, allow per-platform definitions of
	IA64_FIRST_DEVICE_VECTOR and IA64_LAST_DEVICE_VECTOR.
	
3/3 msi-altix.patch 
	Altix specific callouts to implement MSI.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/3] msi vector targeting abstractions
  2006-01-19 19:46 [PATCH 0/3] msi abstractions and support for altix Mark Maule
@ 2006-01-19 19:46 ` Mark Maule
  2006-01-20  2:15   ` Greg KH
  2006-01-19 19:46 ` [PATCH 2/3] per-platform IA64_{FIRST,LAST}_DEVICE_VECTOR definitions Mark Maule
  2006-01-19 19:47 ` [PATCH 3/3] altix: msi support Mark Maule
  2 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2006-01-19 19:46 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: Tony Luck, gregkh, Mark Maule

Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: linux-maule/drivers/pci/msi.c
===================================================================
--- linux-maule.orig/drivers/pci/msi.c	2006-01-17 11:09:15.000000000 -0600
+++ linux-maule/drivers/pci/msi.c	2006-01-19 12:40:27.938752136 -0600
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
    		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -249,30 +264,6 @@
 	.set_affinity	= set_msi_irq_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -367,6 +358,20 @@
 		return status;
 	}
 
+	if ((status = msi_arch_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -510,9 +515,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -539,23 +546,27 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		dev->irq = entry->msi_attrib.default_vector;
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -590,13 +601,15 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_hi;
+	u32 address_lo;
+	u32 data;
 	int vector, pos, i, j, nr_entries, temp = 0;
 	u32 phys_addr, table_offset;
  	u16 control;
 	u8 bir;
 	void __iomem *base;
+	int status;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	/* Request & Map MSI-X table region */
@@ -643,18 +656,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -789,6 +804,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: linux-maule/include/asm-i386/msi.h
===================================================================
--- linux-maule.orig/include/asm-i386/msi.h	2006-01-17 11:09:18.000000000 -0600
+++ linux-maule/include/asm-i386/msi.h	2006-01-19 09:46:52.315749136 -0600
@@ -12,4 +12,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-maule/include/asm-x86_64/msi.h
===================================================================
--- linux-maule.orig/include/asm-x86_64/msi.h	2006-01-17 11:09:18.000000000 -0600
+++ linux-maule/include/asm-x86_64/msi.h	2006-01-19 09:46:52.315749136 -0600
@@ -13,4 +13,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-maule/include/asm-ia64/machvec.h
===================================================================
--- linux-maule.orig/include/asm-ia64/machvec.h	2006-01-17 11:09:18.000000000 -0600
+++ linux-maule/include/asm-ia64/machvec.h	2006-01-19 09:46:52.315749136 -0600
@@ -74,6 +74,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -146,6 +147,7 @@
 #  define platform_readw_relaxed        ia64_mv.readw_relaxed
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
+#  define platform_msi_init	ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -194,6 +196,7 @@
 	ia64_mv_readw_relaxed_t *readw_relaxed;
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -238,6 +241,7 @@
 	platform_readw_relaxed,			\
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -386,5 +390,13 @@
 #ifndef platform_readq_relaxed
 # define platform_readq_relaxed	__ia64_readq_relaxed
 #endif
+#ifndef platform_msi_init
+#ifdef CONFIG_PCI_MSI
+#include <asm/msi.h>		/* pull in ia64_msi_init() */
+# define platform_msi_init	ia64_msi_init
+#else
+# define platform_msi_init	NULL
+#endif /* CONFIG_PCI_MSI */
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: linux-maule/include/asm-ia64/machvec_sn2.h
===================================================================
--- linux-maule.orig/include/asm-ia64/machvec_sn2.h	2006-01-17 11:09:18.000000000 -0600
+++ linux-maule/include/asm-ia64/machvec_sn2.h	2006-01-19 09:46:52.315749136 -0600
@@ -71,6 +71,7 @@
 extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
+extern ia64_mv_msi_init_t		sn_msi_init;
 
 /*
  * This stuff has dual use!
@@ -120,6 +121,11 @@
 #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
+#ifdef CONFIG_PCI_MSI
+#define platform_msi_init		sn_msi_init
+#else
+#define platform_msi_init		NULL
+#endif
 
 #include <asm/sn/io.h>
 
Index: linux-maule/include/asm-ia64/msi.h
===================================================================
--- linux-maule.orig/include/asm-ia64/msi.h	2006-01-17 11:09:18.000000000 -0600
+++ linux-maule/include/asm-ia64/msi.h	2006-01-19 09:46:52.315749136 -0600
@@ -14,4 +14,19 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+extern struct msi_ops msi_apic_ops;
+
+/* Ugly defs to avoid having to include pci.h in machvec.h */
+struct msi_ops;
+extern int msi_register(struct msi_ops *);
+
+/* default ia64 msi init routine */
+static inline int ia64_msi_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
+#define msi_arch_init		platform_msi_init	/* in asm/machvec.h */
+
 #endif /* ASM_MSI_H */
Index: linux-maule/arch/ia64/sn/pci/Makefile
===================================================================
--- linux-maule.orig/arch/ia64/sn/pci/Makefile	2006-01-17 11:09:12.000000000 -0600
+++ linux-maule/arch/ia64/sn/pci/Makefile	2006-01-19 09:46:52.315749136 -0600
@@ -3,8 +3,9 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (C) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
 #
 # Makefile for the sn pci general routines.
 
 obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
+obj-$(CONFIG_PCI_MSI) += msi.o
Index: linux-maule/arch/ia64/sn/pci/msi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-maule/arch/ia64/sn/pci/msi.c	2006-01-19 12:39:27.915552602 -0600
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}
Index: linux-maule/drivers/pci/Makefile
===================================================================
--- linux-maule.orig/drivers/pci/Makefile	2006-01-17 11:09:15.000000000 -0600
+++ linux-maule/drivers/pci/Makefile	2006-01-19 09:46:52.319749598 -0600
@@ -26,7 +26,7 @@
 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
+obj-$(CONFIG_PCI_MSI) += msi.o msi-apic.o
 
 #
 # ACPI Related PCI FW Functions
Index: linux-maule/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-maule/drivers/pci/msi-apic.c	2006-01-19 09:46:52.319749598 -0600
@@ -0,0 +1,100 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic ops used on most IA archs/platforms.  Set with msi_register()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+	.target = msi_target_apic,
+};
Index: linux-maule/drivers/pci/msi.h
===================================================================
--- linux-maule.orig/drivers/pci/msi.h	2006-01-17 11:09:15.000000000 -0600
+++ linux-maule/drivers/pci/msi.h	2006-01-19 09:46:52.319749598 -0600
@@ -69,67 +69,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -138,7 +77,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: linux-maule/include/linux/pci.h
===================================================================
--- linux-maule.orig/include/linux/pci.h	2006-01-17 11:09:18.000000000 -0600
+++ linux-maule/include/linux/pci.h	2006-01-19 09:46:52.319749598 -0600
@@ -547,6 +547,66 @@
 	u16	entry;	/* driver uses to specify entry, OS writes */
 };
 
+/*
+ * MSI operation vector.  Used by the msi core code (drivers/pci/msi.c)
+ * to abstract platform-specific tasks relating to MSI address generation
+ * and resource management.
+ */
+struct msi_ops {
+	/**
+	 * setup - generate an MSI bus address and data for a given vector
+	 * @pdev: PCI device context (in)
+	 * @vector: vector allocated by the msi core (in)
+	 * @addr_hi: upper 32 bits of PCI bus MSI address (out)
+	 * @addr_lo: lower 32 bits of PCI bus MSI address (out)
+	 * @data: MSI data payload (out)
+	 *
+	 * Description: The setup op is used to generate a PCI bus addres and
+	 * data which the msi core will program into the card MSI capability
+	 * registers.  The setup routine is responsible for picking an initial
+	 * cpu to target the MSI at.  The setup routine is responsible for
+	 * examining pdev to determine the MSI capabilities of the card and
+	 * generating a suitable address/data.  The setup routine is
+	 * responsible for allocating and tracking any system resources it
+	 * needs to route the MSI to the cpu it picks, and for associating
+	 * those resources with the passed in vector.
+	 *
+	 * Returns 0 if the MSI address/data was successfully setup.
+	 **/
+
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+
+	/**
+	 * teardown - release resources allocated by setup
+	 * @vector: vector context for resources (in)
+	 *
+	 * Description:  The teardown op is used to release any resources
+	 * that were allocated in the setup routine associated with the passed
+	 * in vector.
+	 **/
+
+	void	(*teardown) (unsigned int vector);
+
+	/**
+	 * target - retarget an MSI at a different cpu
+	 * @vector: vector context for resources (in)
+	 * @cpu:  new cpu to direct vector at (in)
+	 * @addr_hi: new value of PCI bus upper 32 bits (in/out)
+	 * @addr_lo: new value of PCI bus lower 32 bits (in/out)
+	 *
+	 * Description:  The target op is used to redirect an MSI vector
+	 * at a different cpu.  addr_hi/addr_lo coming in are the existing
+	 * values that the MSI core has programmed into the card.  The
+	 * target code is responsible for freeing any resources (if any)
+	 * associated with the old address, and generating a new PCI bus
+	 * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
+	 **/
+
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+};
+
 #ifndef CONFIG_PCI_MSI
 static inline void pci_scan_msi_device(struct pci_dev *dev) {}
 static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
@@ -555,6 +615,7 @@
 	struct msix_entry *entries, int nvec) {return -1;}
 static inline void pci_disable_msix(struct pci_dev *dev) {}
 static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+static inline int msi_register(struct msi_ops *ops) {return -1;}
 #else
 extern void pci_scan_msi_device(struct pci_dev *dev);
 extern int pci_enable_msi(struct pci_dev *dev);
@@ -563,6 +624,7 @@
 	struct msix_entry *entries, int nvec);
 extern void pci_disable_msix(struct pci_dev *dev);
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+extern int msi_register(struct msi_ops *ops);
 #endif
 
 extern void pci_block_user_cfg_access(struct pci_dev *dev);

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 2/3] per-platform IA64_{FIRST,LAST}_DEVICE_VECTOR definitions
  2006-01-19 19:46 [PATCH 0/3] msi abstractions and support for altix Mark Maule
  2006-01-19 19:46 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
@ 2006-01-19 19:46 ` Mark Maule
  2006-01-19 19:47 ` [PATCH 3/3] altix: msi support Mark Maule
  2 siblings, 0 replies; 38+ messages in thread
From: Mark Maule @ 2006-01-19 19:46 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: Tony Luck, gregkh, Mark Maule

Abstract IA64_FIRST_DEVICE_VECTOR/IA64_LAST_DEVICE_VECTOR since SN platforms
use a subset of the IA64 range.  Implement this by making the above macros
global variables which the platform can override in it setup code.

Also add a reserve_irq_vector() routine used by SN to mark a vector's as
in-use when that weren't allocated through assign_irq_vector().

Signed-off-by: Mark Maule <maule@sgi.com>

Index: linux-maule/arch/ia64/kernel/irq_ia64.c
===================================================================
--- linux-maule.orig/arch/ia64/kernel/irq_ia64.c	2006-01-17 11:09:12.000000000 -0600
+++ linux-maule/arch/ia64/kernel/irq_ia64.c	2006-01-19 10:35:05.494256362 -0600
@@ -46,6 +46,10 @@
 
 #define IRQ_DEBUG	0
 
+/* These can be overridden in platform_irq_init */
+int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
+int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
+
 /* default base addr of IPI table */
 void __iomem *ipi_base_addr = ((void __iomem *)
 			       (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
@@ -60,7 +64,7 @@
 };
 EXPORT_SYMBOL(isa_irq_to_vector_map);
 
-static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
+static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
 
 int
 assign_irq_vector (int irq)
@@ -89,6 +93,19 @@
 		printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
 }
 
+int
+reserve_irq_vector (int vector)
+{
+	int pos;
+
+	if (vector < IA64_FIRST_DEVICE_VECTOR ||
+	    vector > IA64_LAST_DEVICE_VECTOR)
+		return -EINVAL;
+
+	pos = vector - IA64_FIRST_DEVICE_VECTOR;
+	return test_and_set_bit(pos, ia64_vector_mask);
+}
+
 #ifdef CONFIG_SMP
 #	define IS_RESCHEDULE(vec)	(vec == IA64_IPI_RESCHEDULE)
 #else
Index: linux-maule/arch/ia64/sn/kernel/irq.c
===================================================================
--- linux-maule.orig/arch/ia64/sn/kernel/irq.c	2006-01-17 11:09:12.000000000 -0600
+++ linux-maule/arch/ia64/sn/kernel/irq.c	2006-01-19 10:34:44.803879833 -0600
@@ -203,6 +203,9 @@
 	int i;
 	irq_desc_t *base_desc = irq_desc;
 
+	ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR;
+	ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR;
+
 	for (i = 0; i < NR_IRQS; i++) {
 		if (base_desc[i].handler == &no_irq_type) {
 			base_desc[i].handler = &irq_type_sn;
@@ -287,6 +290,7 @@
 	/* link it into the sn_irq[irq] list */
 	spin_lock(&sn_irq_info_lock);
 	list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
+	reserve_irq_vector(sn_irq_info->irq_irq);
 	spin_unlock(&sn_irq_info_lock);
 
 	(void)register_intr_pda(sn_irq_info);
@@ -310,8 +314,11 @@
 	spin_lock(&sn_irq_info_lock);
 	list_del_rcu(&sn_irq_info->list);
 	spin_unlock(&sn_irq_info_lock);
+	if (list_empty(sn_irq_lh[sn_irq_info->irq_irq]))
+		free_irq_vector(sn_irq_info->irq_irq);
 	call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
 	pci_dev_put(pci_dev);
+
 }
 
 static inline void
Index: linux-maule/include/asm-ia64/hw_irq.h
===================================================================
--- linux-maule.orig/include/asm-ia64/hw_irq.h	2006-01-17 11:09:18.000000000 -0600
+++ linux-maule/include/asm-ia64/hw_irq.h	2006-01-19 09:47:23.915399191 -0600
@@ -47,9 +47,19 @@
 #define IA64_CMC_VECTOR			0x1f	/* corrected machine-check interrupt vector */
 /*
  * Vectors 0x20-0x2f are reserved for legacy ISA IRQs.
+ * Use vectors 0x30-0xe7 as the default device vector range for ia64.
+ * Platforms may choose to reduce this range in platform_irq_setup, but the
+ * platform range must fall within
+ *	[IA64_DEF_FIRST_DEVICE_VECTOR..IA64_DEF_LAST_DEVICE_VECTOR]
  */
-#define IA64_FIRST_DEVICE_VECTOR	0x30
-#define IA64_LAST_DEVICE_VECTOR		0xe7
+extern int ia64_first_device_vector;
+extern int ia64_last_device_vector;
+
+#define IA64_DEF_FIRST_DEVICE_VECTOR	0x30
+#define IA64_DEF_LAST_DEVICE_VECTOR	0xe7
+#define IA64_FIRST_DEVICE_VECTOR	ia64_first_device_vector
+#define IA64_LAST_DEVICE_VECTOR		ia64_last_device_vector
+#define IA64_MAX_DEVICE_VECTORS		(IA64_DEF_LAST_DEVICE_VECTOR - IA64_DEF_FIRST_DEVICE_VECTOR + 1)
 #define IA64_NUM_DEVICE_VECTORS		(IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1)
 
 #define IA64_MCA_RENDEZ_VECTOR		0xe8	/* MCA rendez interrupt */
@@ -83,6 +93,7 @@
 
 extern int assign_irq_vector (int irq);	/* allocate a free vector */
 extern void free_irq_vector (int vector);
+extern int reserve_irq_vector (int vector);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
 
Index: linux-maule/drivers/pci/msi.c
===================================================================
--- linux-maule.orig/drivers/pci/msi.c	2006-01-19 09:46:52.315749136 -0600
+++ linux-maule/drivers/pci/msi.c	2006-01-19 09:47:23.915399191 -0600
@@ -35,7 +35,7 @@
 
 #ifndef CONFIG_X86_IO_APIC
 int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
-u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
+u8 irq_vector[NR_IRQ_VECTORS];
 #endif
 
 static struct msi_ops *msi_ops;
@@ -377,6 +377,11 @@
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
 		return status;
 	}
+
+#ifndef CONFIG_X86_IO_APIC
+	irq_vector[0] = FIRST_DEVICE_VECTOR;
+#endif
+
 	last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
 	if (last_alloc_vector < 0) {
 		pci_msi_enable = 0;

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 3/3] altix:  msi support
  2006-01-19 19:46 [PATCH 0/3] msi abstractions and support for altix Mark Maule
  2006-01-19 19:46 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
  2006-01-19 19:46 ` [PATCH 2/3] per-platform IA64_{FIRST,LAST}_DEVICE_VECTOR definitions Mark Maule
@ 2006-01-19 19:47 ` Mark Maule
  2006-02-04  4:14   ` Altix SN2 2.6.16-rc1-mm5 build breakage (was: msi support) Paul Jackson
  2 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2006-01-19 19:47 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: Tony Luck, gregkh, Mark Maule

MSI callouts for altix.  Involves a fair amount of code reorg in sn irq.c
code as well as adding some extensions to the altix PCI provider abstaction.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: msi/arch/ia64/sn/pci/msi.c
===================================================================
--- msi.orig/arch/ia64/sn/pci/msi.c	2006-01-18 14:00:52.097507212 -0600
+++ msi/arch/ia64/sn/pci/msi.c	2006-01-18 14:01:06.964228604 -0600
@@ -6,13 +6,205 @@
  * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
-#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/cpumask.h>
+
+#include <asm/msi.h>
+
+#include <asm/sn/addrs.h>
+#include <asm/sn/intr.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/nodepda.h>
+
+struct sn_msi_info {
+	u64 pci_addr;
+	struct sn_irq_info *sn_irq_info;
+};
+
+static struct sn_msi_info *sn_msi_info;
+
+static void
+sn_msi_teardown(unsigned int vector)
+{
+	nasid_t nasid;
+	int widget;
+	struct pci_dev *pdev;
+	struct pcidev_info *sn_pdev;
+	struct sn_irq_info *sn_irq_info;
+	struct pcibus_bussoft *bussoft;
+	struct sn_pcibus_provider *provider;
+
+	sn_irq_info = sn_msi_info[vector].sn_irq_info;
+	if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
+		return;
+
+	sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+	pdev = sn_pdev->pdi_linux_pcidev;
+	provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+	(*provider->dma_unmap)(pdev,
+			       sn_msi_info[vector].pci_addr,
+			       PCI_DMA_FROMDEVICE);
+	sn_msi_info[vector].pci_addr = 0;
+
+	bussoft = SN_PCIDEV_BUSSOFT(pdev);
+	nasid = NASID_GET(bussoft->bs_base);
+	widget = (nasid & 1) ?
+			TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
+			SWIN_WIDGETNUM(bussoft->bs_base);
+
+	sn_intr_free(nasid, widget, sn_irq_info);
+	sn_msi_info[vector].sn_irq_info = NULL;
+
+	return;
+}
 
 int
-sn_msi_init(void)
+sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
+	     u32 *addr_hi, u32 *addr_lo, u32 *data)
 {
+	int widget;
+	int status;
+	nasid_t nasid;
+	u64 bus_addr;
+	struct sn_irq_info *sn_irq_info;
+	struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
+	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+	if (bussoft == NULL)
+		return -EINVAL;
+
+	if (provider == NULL || provider->dma_map_consistent == NULL)
+		return -EINVAL;
+
+	/*
+	 * Set up the vector plumbing.  Let the prom (via sn_intr_alloc)
+	 * decide which cpu to direct this msi at by default.
+	 */
+
+	nasid = NASID_GET(bussoft->bs_base);
+	widget = (nasid & 1) ?
+			TIO_SWIN_WIDGETNUM(bussoft->bs_base) :
+			SWIN_WIDGETNUM(bussoft->bs_base);
+
+	sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+	if (! sn_irq_info)
+		return -ENOMEM;
+
+	status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1);
+	if (status) {
+		kfree(sn_irq_info);
+		return -ENOMEM;
+	}
+
+	sn_irq_info->irq_int_bit = -1;		/* mark this as an MSI irq */
+	sn_irq_fixup(pdev, sn_irq_info);
+
+	/* Prom probably should fill these in, but doesn't ... */
+	sn_irq_info->irq_bridge_type = bussoft->bs_asic_type;
+	sn_irq_info->irq_bridge = (void *)bussoft->bs_base;
+
 	/*
-	 * return error until MSI is supported on altix platforms
+	 * Map the xio address into bus space
 	 */
-	return -EINVAL;
+	bus_addr = (*provider->dma_map_consistent)(pdev,
+					sn_irq_info->irq_xtalkaddr,
+					sizeof(sn_irq_info->irq_xtalkaddr),
+					SN_DMA_MSI|SN_DMA_ADDR_XIO);
+	if (! bus_addr) {
+		sn_intr_free(nasid, widget, sn_irq_info);
+		kfree(sn_irq_info);
+		return -ENOMEM;
+	}
+
+	sn_msi_info[vector].sn_irq_info = sn_irq_info;
+	sn_msi_info[vector].pci_addr = bus_addr;
+
+	*addr_hi = (u32)(bus_addr >> 32);
+	*addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+
+	/*
+	 * In the SN platform, bit 16 is a "send vector" bit which
+	 * must be present in order to move the vector through the system.
+	 */
+	*data = 0x100 + (unsigned int)vector;
+
+#ifdef CONFIG_SMP
+	set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0);
+#endif
+
+	return 0;
+}
+
+static void
+sn_msi_target(unsigned int vector, unsigned int cpu,
+	      u32 *addr_hi, u32 *addr_lo)
+{
+	int slice;
+	nasid_t nasid;
+	u64 bus_addr;
+	struct pci_dev *pdev;
+	struct pcidev_info *sn_pdev;
+	struct sn_irq_info *sn_irq_info;
+	struct sn_irq_info *new_irq_info;
+	struct sn_pcibus_provider *provider;
+
+	sn_irq_info = sn_msi_info[vector].sn_irq_info;
+	if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
+		return;
+
+	/*
+	 * Release XIO resources for the old MSI PCI address
+	 */
+
+        sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
+	pdev = sn_pdev->pdi_linux_pcidev;
+	provider = SN_PCIDEV_BUSPROVIDER(pdev);
+
+	bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo);
+	(*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
+	sn_msi_info[vector].pci_addr = 0;
+
+	nasid = cpuid_to_nasid(cpu);
+	slice = cpuid_to_slice(cpu);
+
+	new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
+	sn_msi_info[vector].sn_irq_info = new_irq_info;
+	if (new_irq_info == NULL)
+		return;
+
+	/*
+	 * Map the xio address into bus space
+	 */
+
+	bus_addr = (*provider->dma_map_consistent)(pdev,
+					new_irq_info->irq_xtalkaddr,
+					sizeof(new_irq_info->irq_xtalkaddr),
+					SN_DMA_MSI|SN_DMA_ADDR_XIO);
+
+	sn_msi_info[vector].pci_addr = bus_addr;
+	*addr_hi = (u32)(bus_addr >> 32);
+	*addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+}
+
+struct msi_ops sn_msi_ops = {
+	.setup = sn_msi_setup,
+	.teardown = sn_msi_teardown,
+#ifdef CONFIG_SMP
+	.target = sn_msi_target,
+#endif
+};
+
+int
+sn_msi_init(void)
+{
+	sn_msi_info =
+		kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL);
+	if (! sn_msi_info)
+		return -ENOMEM;
+
+	msi_register(&sn_msi_ops);
+	return 0;
 }
Index: msi/arch/ia64/sn/kernel/io_init.c
===================================================================
--- msi.orig/arch/ia64/sn/kernel/io_init.c	2006-01-18 14:00:52.099460147 -0600
+++ msi/arch/ia64/sn/kernel/io_init.c	2006-01-18 14:01:06.969110943 -0600
@@ -51,7 +51,7 @@
  */
 
 static dma_addr_t
-sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size)
+sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type)
 {
 	return 0;
 }
Index: msi/arch/ia64/sn/kernel/irq.c
===================================================================
--- msi.orig/arch/ia64/sn/kernel/irq.c	2006-01-18 14:01:05.024963679 -0600
+++ msi/arch/ia64/sn/kernel/irq.c	2006-01-18 14:01:06.971063878 -0600
@@ -25,11 +25,11 @@
 
 int sn_force_interrupt_flag = 1;
 extern int sn_ioif_inited;
-static struct list_head **sn_irq_lh;
+struct list_head **sn_irq_lh;
 static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
 
-static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
-				     u64 sn_irq_info,
+u64 sn_intr_alloc(nasid_t local_nasid, int local_widget,
+				     struct sn_irq_info *sn_irq_info,
 				     int req_irq, nasid_t req_nasid,
 				     int req_slice)
 {
@@ -39,12 +39,13 @@
 
 	SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT,
 			(u64) SAL_INTR_ALLOC, (u64) local_nasid,
-			(u64) local_widget, (u64) sn_irq_info, (u64) req_irq,
+			(u64) local_widget, __pa(sn_irq_info), (u64) req_irq,
 			(u64) req_nasid, (u64) req_slice);
+
 	return ret_stuff.status;
 }
 
-static inline void sn_intr_free(nasid_t local_nasid, int local_widget,
+void sn_intr_free(nasid_t local_nasid, int local_widget,
 				struct sn_irq_info *sn_irq_info)
 {
 	struct ia64_sal_retval ret_stuff;
@@ -113,73 +114,91 @@
 
 static void sn_irq_info_free(struct rcu_head *head);
 
-static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
+struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info,
+				       nasid_t nasid, int slice)
 {
-	struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
-	int cpuid, cpuphys;
+	int vector;
+	int cpuphys;
+	int64_t bridge;
+	int local_widget, status;
+	nasid_t local_nasid;
+	struct sn_irq_info *new_irq_info;
+	struct sn_pcibus_provider *pci_provider;
 
-	cpuid = first_cpu(mask);
-	cpuphys = cpu_physical_id(cpuid);
+	new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
+	if (new_irq_info == NULL)
+		return NULL;
 
-	list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
-				 sn_irq_lh[irq], list) {
-		u64 bridge;
-		int local_widget, status;
-		nasid_t local_nasid;
-		struct sn_irq_info *new_irq_info;
-		struct sn_pcibus_provider *pci_provider;
-
-		new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
-		if (new_irq_info == NULL)
-			break;
-		memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
-
-		bridge = (u64) new_irq_info->irq_bridge;
-		if (!bridge) {
-			kfree(new_irq_info);
-			break; /* irq is not a device interrupt */
-		}
+	memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
 
-		local_nasid = NASID_GET(bridge);
+	bridge = (u64) new_irq_info->irq_bridge;
+	if (!bridge) {
+		kfree(new_irq_info);
+		return NULL; /* irq is not a device interrupt */
+	}
 
-		if (local_nasid & 1)
-			local_widget = TIO_SWIN_WIDGETNUM(bridge);
-		else
-			local_widget = SWIN_WIDGETNUM(bridge);
-
-		/* Free the old PROM new_irq_info structure */
-		sn_intr_free(local_nasid, local_widget, new_irq_info);
-		/* Update kernels new_irq_info with new target info */
-		unregister_intr_pda(new_irq_info);
-
-		/* allocate a new PROM new_irq_info struct */
-		status = sn_intr_alloc(local_nasid, local_widget,
-				       __pa(new_irq_info), irq,
-				       cpuid_to_nasid(cpuid),
-				       cpuid_to_slice(cpuid));
-
-		/* SAL call failed */
-		if (status) {
-			kfree(new_irq_info);
-			break;
-		}
+	local_nasid = NASID_GET(bridge);
 
-		new_irq_info->irq_cpuid = cpuid;
-		register_intr_pda(new_irq_info);
+	if (local_nasid & 1)
+		local_widget = TIO_SWIN_WIDGETNUM(bridge);
+	else
+		local_widget = SWIN_WIDGETNUM(bridge);
 
-		pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
-		if (pci_provider && pci_provider->target_interrupt)
-			(pci_provider->target_interrupt)(new_irq_info);
-
-		spin_lock(&sn_irq_info_lock);
-		list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
-		spin_unlock(&sn_irq_info_lock);
-		call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+	vector = sn_irq_info->irq_irq;
+	/* Free the old PROM new_irq_info structure */
+	sn_intr_free(local_nasid, local_widget, new_irq_info);
+	/* Update kernels new_irq_info with new target info */
+	unregister_intr_pda(new_irq_info);
+
+	/* allocate a new PROM new_irq_info struct */
+	status = sn_intr_alloc(local_nasid, local_widget,
+			       new_irq_info, vector,
+			       nasid, slice);
+
+	/* SAL call failed */
+	if (status) {
+		kfree(new_irq_info);
+		return NULL;
+	}
+
+	cpuphys = nasid_slice_to_cpuid(nasid, slice);
+	new_irq_info->irq_cpuid = cpuphys;
+	register_intr_pda(new_irq_info);
+
+	pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type];
+
+	/*
+	 * If this represents a line interrupt, target it.  If it's
+	 * an msi (irq_int_bit < 0), it's already targeted.
+	 */
+	if (new_irq_info->irq_int_bit >= 0 &&
+	    pci_provider && pci_provider->target_interrupt)
+		(pci_provider->target_interrupt)(new_irq_info);
+
+	spin_lock(&sn_irq_info_lock);
+	list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
+	spin_unlock(&sn_irq_info_lock);
+	call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
 
 #ifdef CONFIG_SMP
-		set_irq_affinity_info((irq & 0xff), cpuphys, 0);
+	set_irq_affinity_info((vector & 0xff), cpuphys, 0);
 #endif
-	}
+
+	return new_irq_info;
+}
+
+static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
+{
+	struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
+	nasid_t nasid;
+	int slice;
+
+	nasid = cpuid_to_nasid(first_cpu(mask));
+	slice = cpuid_to_slice(first_cpu(mask));
+
+	list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
+				 sn_irq_lh[irq], list)
+		(void)sn_retarget_vector(sn_irq_info, nasid, slice);
 }
 
 struct hw_interrupt_type irq_type_sn = {
@@ -441,5 +460,4 @@
 
 		INIT_LIST_HEAD(sn_irq_lh[i]);
 	}
-
 }
Index: msi/arch/ia64/sn/pci/pci_dma.c
===================================================================
--- msi.orig/arch/ia64/sn/pci/pci_dma.c	2006-01-18 14:00:52.097507212 -0600
+++ msi/arch/ia64/sn/pci/pci_dma.c	2006-01-18 14:01:06.971063878 -0600
@@ -11,7 +11,7 @@
 
 #include <linux/module.h>
 #include <asm/dma.h>
-#include <asm/sn/pcibr_provider.h>
+#include <asm/sn/intr.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
 #include <asm/sn/sn_sal.h>
@@ -113,7 +113,8 @@
 	 * resources.
 	 */
 
-	*dma_handle = provider->dma_map_consistent(pdev, phys_addr, size);
+	*dma_handle = provider->dma_map_consistent(pdev, phys_addr, size,
+						   SN_DMA_ADDR_PHYS);
 	if (!*dma_handle) {
 		printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
 		free_pages((unsigned long)cpuaddr, get_order(size));
@@ -176,7 +177,7 @@
 	BUG_ON(dev->bus != &pci_bus_type);
 
 	phys_addr = __pa(cpu_addr);
-	dma_addr = provider->dma_map(pdev, phys_addr, size);
+	dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS);
 	if (!dma_addr) {
 		printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
 		return 0;
@@ -260,7 +261,8 @@
 	for (i = 0; i < nhwentries; i++, sg++) {
 		phys_addr = SG_ENT_PHYS_ADDRESS(sg);
 		sg->dma_address = provider->dma_map(pdev,
-						    phys_addr, sg->length);
+						    phys_addr, sg->length,
+						    SN_DMA_ADDR_PHYS);
 
 		if (!sg->dma_address) {
 			printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__);
Index: msi/arch/ia64/sn/pci/pcibr/pcibr_dma.c
===================================================================
--- msi.orig/arch/ia64/sn/pci/pcibr/pcibr_dma.c	2006-01-18 14:00:52.098483680 -0600
+++ msi/arch/ia64/sn/pci/pcibr/pcibr_dma.c	2006-01-18 14:01:06.974969749 -0600
@@ -41,7 +41,7 @@
 
 static dma_addr_t
 pcibr_dmamap_ate32(struct pcidev_info *info,
-		   u64 paddr, size_t req_size, u64 flags)
+		   u64 paddr, size_t req_size, u64 flags, int dma_flags)
 {
 
 	struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
@@ -81,9 +81,12 @@
 	if (IS_PCIX(pcibus_info))
 		ate_flags &= ~(PCI32_ATE_PREF);
 
-	xio_addr =
-	    IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
-	    PHYS_TO_TIODMA(paddr);
+	if (SN_DMA_ADDRTYPE(dma_flags == SN_DMA_ADDR_PHYS))
+		xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+	    					      PHYS_TO_TIODMA(paddr);
+	else
+		xio_addr = paddr;
+
 	offset = IOPGOFF(xio_addr);
 	ate = ate_flags | (xio_addr - offset);
 
@@ -91,6 +94,13 @@
 	if (IS_PIC_SOFT(pcibus_info)) {
 		ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT);
 	}
+
+	/*
+	 * If we're mapping for MSI, set the MSI bit in the ATE
+	 */
+	if (dma_flags & SN_DMA_MSI)
+		ate |= PCI32_ATE_MSI;
+
 	ate_write(pcibus_info, ate_index, ate_count, ate);
 
 	/*
@@ -105,20 +115,27 @@
 	if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR)
 		ATE_SWAP_ON(pci_addr);
 
+
 	return pci_addr;
 }
 
 static dma_addr_t
 pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr,
-			u64 dma_attributes)
+			u64 dma_attributes, int dma_flags)
 {
 	struct pcibus_info *pcibus_info = (struct pcibus_info *)
 	    ((info->pdi_host_pcidev_info)->pdi_pcibus_info);
 	u64 pci_addr;
 
 	/* Translate to Crosstalk View of Physical Address */
-	pci_addr = (IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
-		    PHYS_TO_TIODMA(paddr)) | dma_attributes;
+	if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
+		pci_addr = IS_PIC_SOFT(pcibus_info) ?
+				PHYS_TO_DMA(paddr) :
+		    		PHYS_TO_TIODMA(paddr) | dma_attributes;
+	else
+		pci_addr = IS_PIC_SOFT(pcibus_info) ?
+				paddr :
+				paddr | dma_attributes;
 
 	/* Handle Bus mode */
 	if (IS_PCIX(pcibus_info))
@@ -130,7 +147,9 @@
 		    ((u64) pcibus_info->
 		     pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT);
 	} else
-		pci_addr |= TIOCP_PCI64_CMDTYPE_MEM;
+		pci_addr |= (dma_flags & SN_DMA_MSI) ?
+				TIOCP_PCI64_CMDTYPE_MSI :
+				TIOCP_PCI64_CMDTYPE_MEM;
 
 	/* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */
 	if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn))
@@ -142,7 +161,7 @@
 
 static dma_addr_t
 pcibr_dmatrans_direct32(struct pcidev_info * info,
-			u64 paddr, size_t req_size, u64 flags)
+			u64 paddr, size_t req_size, u64 flags, int dma_flags)
 {
 
 	struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info;
@@ -158,8 +177,14 @@
 		return 0;
 	}
 
-	xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
-	    PHYS_TO_TIODMA(paddr);
+	if (dma_flags & SN_DMA_MSI)
+		return 0;
+
+	if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
+		xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) :
+	    					      PHYS_TO_TIODMA(paddr);
+	else
+		xio_addr = paddr;
 
 	xio_base = pcibus_info->pbi_dir_xbase;
 	offset = xio_addr - xio_base;
@@ -333,7 +358,7 @@
  */
 
 dma_addr_t
-pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size)
+pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size, int dma_flags)
 {
 	dma_addr_t dma_handle;
 	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
@@ -350,11 +375,11 @@
 		 */
 
 		dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
-						     PCI64_ATTR_PREF);
+						     PCI64_ATTR_PREF, dma_flags);
 	} else {
 		/* Handle 32-63 bit cards via direct mapping */
 		dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr,
-						     size, 0);
+						     size, 0, dma_flags);
 		if (!dma_handle) {
 			/*
 			 * It is a 32 bit card and we cannot do direct mapping,
@@ -362,7 +387,8 @@
 			 */
 
 			dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr,
-							size, PCI32_ATE_PREF);
+							size, PCI32_ATE_PREF,
+							dma_flags);
 		}
 	}
 
@@ -371,18 +397,18 @@
 
 dma_addr_t
 pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr,
-			 size_t size)
+			 size_t size, int dma_flags)
 {
 	dma_addr_t dma_handle;
 	struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev);
 
 	if (hwdev->dev.coherent_dma_mask == ~0UL) {
 		dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr,
-					    PCI64_ATTR_BAR);
+					    PCI64_ATTR_BAR, dma_flags);
 	} else {
 		dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info,
 						    phys_addr, size,
-						    PCI32_ATE_BAR);
+						    PCI32_ATE_BAR, dma_flags);
 	}
 
 	return dma_handle;
Index: msi/arch/ia64/sn/pci/tioca_provider.c
===================================================================
--- msi.orig/arch/ia64/sn/pci/tioca_provider.c	2006-01-18 14:00:52.098483680 -0600
+++ msi/arch/ia64/sn/pci/tioca_provider.c	2006-01-18 14:01:06.975946217 -0600
@@ -515,11 +515,17 @@
  * use the GART mapped mode.
  */
 static u64
-tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count)
+tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags)
 {
 	u64 mapaddr;
 
 	/*
+	 * Not supported for now ...
+	 */
+	if (dma_flags & SN_DMA_MSI)
+		return 0;
+
+	/*
 	 * If card is 64 or 48 bit addresable, use a direct mapping.  32
 	 * bit direct is so restrictive w.r.t. where the memory resides that
 	 * we don't use it even though CA has some support.
Index: msi/arch/ia64/sn/pci/tioce_provider.c
===================================================================
--- msi.orig/arch/ia64/sn/pci/tioce_provider.c	2006-01-18 14:00:52.099460147 -0600
+++ msi/arch/ia64/sn/pci/tioce_provider.c	2006-01-18 14:01:06.976922685 -0600
@@ -52,7 +52,8 @@
 	(ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1)
 
 #define ATE_VALID(ate)	((ate) & (1UL << 63))
-#define ATE_MAKE(addr, ps) (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63))
+#define ATE_MAKE(addr, ps, msi) \
+	(((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63) | ((msi)?(1UL << 62):0))
 
 /*
  * Flavors of ate-based mapping supported by tioce_alloc_map()
@@ -78,15 +79,17 @@
  *
  * 63    - must be 1 to indicate d64 mode to CE hardware
  * 62    - barrier bit ... controlled with tioce_dma_barrier()
- * 61    - 0 since this is not an MSI transaction
+ * 61    - msi bit ... specified through dma_flags
  * 60:54 - reserved, MBZ
  */
 static u64
-tioce_dma_d64(unsigned long ct_addr)
+tioce_dma_d64(unsigned long ct_addr, int dma_flags)
 {
 	u64 bus_addr;
 
 	bus_addr = ct_addr | (1UL << 63);
+	if (dma_flags & SN_DMA_MSI)
+		bus_addr |= (1UL << 61);
 
 	return bus_addr;
 }
@@ -143,7 +146,7 @@
  */
 static u64
 tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
-		u64 ct_addr, int len)
+		u64 ct_addr, int len, int dma_flags)
 {
 	int i;
 	int j;
@@ -152,6 +155,7 @@
 	int entries;
 	int nates;
 	int pagesize;
+	int msi_capable, msi_wanted;
 	u64 *ate_shadow;
 	u64 *ate_reg;
 	u64 addr;
@@ -173,6 +177,7 @@
 		ate_reg = ce_mmr->ce_ure_ate3240;
 		pagesize = ce_kern->ce_ate3240_pagesize;
 		bus_base = TIOCE_M32_MIN;
+		msi_capable = 1;
 		break;
 	case TIOCE_ATE_M40:
 		first = 0;
@@ -181,6 +186,7 @@
 		ate_reg = ce_mmr->ce_ure_ate40;
 		pagesize = MB(64);
 		bus_base = TIOCE_M40_MIN;
+		msi_capable = 0;
 		break;
 	case TIOCE_ATE_M40S:
 		/*
@@ -193,11 +199,16 @@
 		ate_reg = ce_mmr->ce_ure_ate3240;
 		pagesize = GB(16);
 		bus_base = TIOCE_M40S_MIN;
+		msi_capable = 0;
 		break;
 	default:
 		return 0;
 	}
 
+	msi_wanted = dma_flags & SN_DMA_MSI;
+	if (msi_wanted && !msi_capable)
+		return 0;
+
 	nates = ATE_NPAGES(ct_addr, len, pagesize);
 	if (nates > entries)
 		return 0;
@@ -226,7 +237,7 @@
 	for (j = 0; j < nates; j++) {
 		u64 ate;
 
-		ate = ATE_MAKE(addr, pagesize);
+		ate = ATE_MAKE(addr, pagesize, msi_wanted);
 		ate_shadow[i + j] = ate;
 		writeq(ate, &ate_reg[i + j]);
 		addr += pagesize;
@@ -253,7 +264,7 @@
  * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info.
  */
 static u64
-tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr)
+tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr, int dma_flags)
 {
 	int dma_ok;
 	int port;
@@ -263,6 +274,9 @@
 	u64 ct_lower;
 	dma_addr_t bus_addr;
 
+	if (dma_flags & SN_DMA_MSI)
+		return 0;
+
 	ct_upper = ct_addr & ~0x3fffffffUL;
 	ct_lower = ct_addr & 0x3fffffffUL;
 
@@ -387,7 +401,7 @@
  */
 static u64
 tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count,
-		 int barrier)
+		 int barrier, int dma_flags)
 {
 	unsigned long flags;
 	u64 ct_addr;
@@ -403,15 +417,18 @@
 	if (dma_mask < 0x7fffffffUL)
 		return 0;
 
-	ct_addr = PHYS_TO_TIODMA(paddr);
+	if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS)
+		ct_addr = PHYS_TO_TIODMA(paddr);
+	else
+		ct_addr = paddr;
 
 	/*
 	 * If the device can generate 64 bit addresses, create a D64 map.
-	 * Since this should never fail, bypass the rest of the checks.
 	 */
 	if (dma_mask == ~0UL) {
-		mapaddr = tioce_dma_d64(ct_addr);
-		goto dma_map_done;
+		mapaddr = tioce_dma_d64(ct_addr, dma_flags);
+		if (mapaddr)
+			goto dma_map_done;
 	}
 
 	pcidev_to_tioce(pdev, NULL, &ce_kern, &port);
@@ -454,18 +471,22 @@
 
 		if (byte_count > MB(64)) {
 			mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
-						  port, ct_addr, byte_count);
+						  port, ct_addr, byte_count,
+						  dma_flags);
 			if (!mapaddr)
 				mapaddr =
 				    tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
-						    ct_addr, byte_count);
+						    ct_addr, byte_count,
+						    dma_flags);
 		} else {
 			mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1,
-						  ct_addr, byte_count);
+						  ct_addr, byte_count,
+						  dma_flags);
 			if (!mapaddr)
 				mapaddr =
 				    tioce_alloc_map(ce_kern, TIOCE_ATE_M40S,
-						    port, ct_addr, byte_count);
+						    port, ct_addr, byte_count,
+						    dma_flags);
 		}
 	}
 
@@ -473,7 +494,7 @@
 	 * 32-bit direct is the next mode to try
 	 */
 	if (!mapaddr && dma_mask >= 0xffffffffUL)
-		mapaddr = tioce_dma_d32(pdev, ct_addr);
+		mapaddr = tioce_dma_d32(pdev, ct_addr, dma_flags);
 
 	/*
 	 * Last resort, try 32-bit ATE-based map.
@@ -481,12 +502,12 @@
 	if (!mapaddr)
 		mapaddr =
 		    tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr,
-				    byte_count);
+				    byte_count, dma_flags);
 
 	spin_unlock_irqrestore(&ce_kern->ce_lock, flags);
 
 dma_map_done:
-	if (mapaddr & barrier)
+	if (mapaddr && barrier)
 		mapaddr = tioce_dma_barrier(mapaddr, 1);
 
 	return mapaddr;
@@ -502,9 +523,9 @@
  * in the address.
  */
 static u64
-tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count)
+tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags)
 {
-	return tioce_do_dma_map(pdev, paddr, byte_count, 0);
+	return tioce_do_dma_map(pdev, paddr, byte_count, 0, dma_flags);
 }
 
 /**
@@ -516,9 +537,9 @@
  * Simply call tioce_do_dma_map() to create a map with the barrier bit set
  * in the address.
  */ static u64
-tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count)
+tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags)
 {
-	return tioce_do_dma_map(pdev, paddr, byte_count, 1);
+	return tioce_do_dma_map(pdev, paddr, byte_count, 1, dma_flags);
 }
 
 /**
Index: msi/include/asm-ia64/sn/intr.h
===================================================================
--- msi.orig/include/asm-ia64/sn/intr.h	2006-01-18 14:00:52.100436615 -0600
+++ msi/include/asm-ia64/sn/intr.h	2006-01-18 14:01:06.982781491 -0600
@@ -3,13 +3,14 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_IA64_SN_INTR_H
 #define _ASM_IA64_SN_INTR_H
 
 #include <linux/rcupdate.h>
+#include <asm/sn/types.h>
 
 #define SGI_UART_VECTOR		(0xe9)
 
@@ -40,6 +41,7 @@
 	int		irq_cpuid;	/* kernel logical cpuid	     */
 	int		irq_irq;	/* the IRQ number */
 	int		irq_int_bit;	/* Bridge interrupt pin */
+					/* <0 means MSI */
 	u64	irq_xtalkaddr;	/* xtalkaddr IRQ is sent to  */
 	int		irq_bridge_type;/* pciio asic type (pciio.h) */
 	void	       *irq_bridge;	/* bridge generating irq     */
@@ -53,6 +55,12 @@
 };
 
 extern void sn_send_IPI_phys(int, long, int, int);
+extern u64 sn_intr_alloc(nasid_t, int,
+			      struct sn_irq_info *,
+			      int, nasid_t, int);
+extern void sn_intr_free(nasid_t, int, struct sn_irq_info *);
+extern struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *, nasid_t, int);
+extern struct list_head **sn_irq_lh;
 
 #define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector)
 
Index: msi/include/asm-ia64/sn/pcibr_provider.h
===================================================================
--- msi.orig/include/asm-ia64/sn/pcibr_provider.h	2006-01-18 14:00:52.100436615 -0600
+++ msi/include/asm-ia64/sn/pcibr_provider.h	2006-01-18 14:01:06.984734427 -0600
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992-1997,2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992-1997,2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
 #define _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
@@ -55,6 +55,7 @@
 #define PCI32_ATE_V                     (0x1 << 0)
 #define PCI32_ATE_CO                    (0x1 << 1)
 #define PCI32_ATE_PREC                  (0x1 << 2)
+#define PCI32_ATE_MSI                   (0x1 << 2)
 #define PCI32_ATE_PREF                  (0x1 << 3)
 #define PCI32_ATE_BAR                   (0x1 << 4)
 #define PCI32_ATE_ADDR_SHFT             12
@@ -129,8 +130,8 @@
 
 extern int  pcibr_init_provider(void);
 extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *);
-extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t);
-extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t);
+extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t, int type);
+extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t, int type);
 extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int);
 
 /*
Index: msi/include/asm-ia64/sn/pcibus_provider_defs.h
===================================================================
--- msi.orig/include/asm-ia64/sn/pcibus_provider_defs.h	2006-01-18 14:00:52.101413083 -0600
+++ msi/include/asm-ia64/sn/pcibus_provider_defs.h	2006-01-18 14:01:06.986687362 -0600
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
 #define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H
@@ -45,13 +45,24 @@
  */
 
 struct sn_pcibus_provider {
-	dma_addr_t	(*dma_map)(struct pci_dev *, unsigned long, size_t);
-	dma_addr_t	(*dma_map_consistent)(struct pci_dev *, unsigned long, size_t);
+	dma_addr_t	(*dma_map)(struct pci_dev *, unsigned long, size_t, int flags);
+	dma_addr_t	(*dma_map_consistent)(struct pci_dev *, unsigned long, size_t, int flags);
 	void		(*dma_unmap)(struct pci_dev *, dma_addr_t, int);
 	void *		(*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *);
  	void		(*force_interrupt)(struct sn_irq_info *);
  	void		(*target_interrupt)(struct sn_irq_info *);
 };
 
+/*
+ * Flags used by the map interfaces
+ * bits 3:0 specifies format of passed in address
+ * bit  4   specifies that address is to be used for MSI
+ */
+
+#define SN_DMA_ADDRTYPE(x)	((x) & 0xf)
+#define     SN_DMA_ADDR_PHYS	1	/* address is an xio address. */
+#define     SN_DMA_ADDR_XIO	2	/* address is phys memory */
+#define SN_DMA_MSI		0x10	/* Bus address is to be used for MSI */
+
 extern struct sn_pcibus_provider *sn_pci_provider[];
 #endif				/* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */
Index: msi/include/asm-ia64/sn/tiocp.h
===================================================================
--- msi.orig/include/asm-ia64/sn/tiocp.h	2006-01-18 14:00:52.101413083 -0600
+++ msi/include/asm-ia64/sn/tiocp.h	2006-01-18 14:01:06.988640298 -0600
@@ -3,13 +3,14 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003-2004 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2003-2005 Silicon Graphics, Inc. All rights reserved.
  */
 #ifndef _ASM_IA64_SN_PCI_TIOCP_H
 #define _ASM_IA64_SN_PCI_TIOCP_H
 
 #define TIOCP_HOST_INTR_ADDR            0x003FFFFFFFFFFFFFUL
 #define TIOCP_PCI64_CMDTYPE_MEM         (0x1ull << 60)
+#define TIOCP_PCI64_CMDTYPE_MSI         (0x3ull << 60)
 
 
 /*****************************************************************************

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-19 19:46 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
@ 2006-01-20  2:15   ` Greg KH
  0 siblings, 0 replies; 38+ messages in thread
From: Greg KH @ 2006-01-20  2:15 UTC (permalink / raw)
  To: Mark Maule
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

On Thu, Jan 19, 2006 at 01:46:52PM -0600, Mark Maule wrote:
> Abstract portions of the MSI core for platforms that do not use standard
> APIC interrupt controllers.  This is implemented through a new arch-specific
> msi setup routine, and a set of msi ops which can be set on a per platform
> basis.
> 
> Signed-off-by: Mark Maule <maule@sgi.com>

Note that I changed this patch a bunch, rearanging where things went
(should not have touched include/linux/pci.h for this change) and
everything builds properly still on i386.  You should check that they
build on ia64 now too.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Altix SN2 2.6.16-rc1-mm5 build breakage (was:  msi support)
  2006-01-19 19:47 ` [PATCH 3/3] altix: msi support Mark Maule
@ 2006-02-04  4:14   ` Paul Jackson
  2006-02-04  4:25     ` Andrew Morton
  0 siblings, 1 reply; 38+ messages in thread
From: Paul Jackson @ 2006-02-04  4:14 UTC (permalink / raw)
  To: Mark Maule, Andrew Morton
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, tony.luck,
	gregkh, maule

Andrew,

The following patch seems to be breaking my ia64 sn2_defconfig
build of 2.6.16-rc1-mm5:

    gregkh-pci-altix-msi-support-git-ia64-fix.patch

I'm guessing you should remove it for now.


Details:
========

When I try to build an ia64 sn2_defconfig 2.6.16-rc1-mm5, the
build fails:

    arch/ia64/sn/pci/tioce_provider.c:699:49: macro "ATE_MAKE" passed 3 arguments, but takes just 2
    arch/ia64/sn/pci/tioce_provider.c: In function `tioce_reserve_m32':
    arch/ia64/sn/pci/tioce_provider.c:699: error: `ATE_MAKE' undeclared (first use in this function)

If I remove the patch:

    gregkh-pci-altix-msi-support-git-ia64-fix.patch

then it compiles fine.

It seems that someone added a patchset to change the ATE_MAKE()
macro from 2 to 3 args, then someone added this above fix patch
for a missed change, then someone reverted it all back to 2 args,
but leaving this fix patch.

I guess it means Andrew should remove the above patch.

But I really do not know what is going on here.

-- 
                  I won't rest till it's the best ...
                  Programmer, Linux Scalability
                  Paul Jackson <pj@sgi.com> 1.925.600.0401

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Altix SN2 2.6.16-rc1-mm5 build breakage (was:  msi support)
  2006-02-04  4:14   ` Altix SN2 2.6.16-rc1-mm5 build breakage (was: msi support) Paul Jackson
@ 2006-02-04  4:25     ` Andrew Morton
  2006-02-04  4:27       ` Andrew Morton
  0 siblings, 1 reply; 38+ messages in thread
From: Andrew Morton @ 2006-02-04  4:25 UTC (permalink / raw)
  To: Paul Jackson
  Cc: maule, linuxppc64-dev, linux-pci, linux-ia64, linux-kernel,
	tony.luck, gregkh

Paul Jackson <pj@sgi.com> wrote:
>
> The following patch seems to be breaking my ia64 sn2_defconfig
>  build of 2.6.16-rc1-mm5:
> 
>      gregkh-pci-altix-msi-support-git-ia64-fix.patch
> 
>  I'm guessing you should remove it for now.
> 
> 
>  Details:
>  ========
> 
>  When I try to build an ia64 sn2_defconfig 2.6.16-rc1-mm5, the
>  build fails:
> 
>      arch/ia64/sn/pci/tioce_provider.c:699:49: macro "ATE_MAKE" passed 3 arguments, but takes just 2
>      arch/ia64/sn/pci/tioce_provider.c: In function `tioce_reserve_m32':
>      arch/ia64/sn/pci/tioce_provider.c:699: error: `ATE_MAKE' undeclared (first use in this function)
> 
>  If I remove the patch:
> 
>      gregkh-pci-altix-msi-support-git-ia64-fix.patch
> 
>  then it compiles fine.

OK.  I autodrop several of Greg's MSI patches because a) they had bugs
which broke stuff a while ago and b) they don't apply and I'm lazy.  So it
looks like you've found a fix for a patch which isn't actually in -mm any
more.  I sent that fix to Greg the other day.

>  It seems that someone added a patchset to change the ATE_MAKE()
>  macro from 2 to 3 args, then someone added this above fix patch
>  for a missed change, then someone reverted it all back to 2 args,
>  but leaving this fix patch.
> 
>  I guess it means Andrew should remove the above patch.

I'll do that, thanks.


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Altix SN2 2.6.16-rc1-mm5 build breakage (was:  msi support)
  2006-02-04  4:25     ` Andrew Morton
@ 2006-02-04  4:27       ` Andrew Morton
  2006-02-04  4:42         ` Mark Maule
  2006-02-23  0:50         ` Paul Jackson
  0 siblings, 2 replies; 38+ messages in thread
From: Andrew Morton @ 2006-02-04  4:27 UTC (permalink / raw)
  To: pj, maule, linuxppc64-dev, linux-pci, linux-ia64, linux-kernel,
	tony.luck, gregkh

Andrew Morton <akpm@osdl.org> wrote:
>
> So it
>  looks like you've found a fix for a patch which isn't actually in -mm any
>  more.  I sent that fix to Greg the other day.

Actually, gregkh-pci-altix-msi-support-git-ia64-fix.patch fix`es
git-ia64.patch when gregkh-pci-altix-msi-support.patch is also applied, so
it's not presently useful to either Greg or Tony.  I'll take care of it,
somehow..


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Altix SN2 2.6.16-rc1-mm5 build breakage (was:  msi support)
  2006-02-04  4:27       ` Andrew Morton
@ 2006-02-04  4:42         ` Mark Maule
  2006-02-04  5:08           ` Andrew Morton
  2006-02-23  0:50         ` Paul Jackson
  1 sibling, 1 reply; 38+ messages in thread
From: Mark Maule @ 2006-02-04  4:42 UTC (permalink / raw)
  To: Andrew Morton
  Cc: pj, linuxppc64-dev, linux-pci, linux-ia64, linux-kernel,
	tony.luck, gregkh

On Fri, Feb 03, 2006 at 08:27:42PM -0800, Andrew Morton wrote:
> Andrew Morton <akpm@osdl.org> wrote:
> >
> > So it
> >  looks like you've found a fix for a patch which isn't actually in -mm any
> >  more.  I sent that fix to Greg the other day.
> 
> Actually, gregkh-pci-altix-msi-support-git-ia64-fix.patch fix`es
> git-ia64.patch when gregkh-pci-altix-msi-support.patch is also applied, so
> it's not presently useful to either Greg or Tony.  I'll take care of it,
> somehow..
> 

I think what happened here is that I submitted a patchset for msi
abstractions (and others posted a couple of subsequent bugfix incrementals),
but these were not taken into the 2.6.16 base 'cause of their invasiveness.
These patches touched the tioce_provider.c file.

Then I submitted another patch which touched the tioce_provider.c file, and
it looks like I probably based this file on the previous msi versions which
were being held back, so in order for everything to build, you need all of
the msi patches applied first.

What's the preferred way to handle this ... fix the current ia64 build and
then resubmit the msi patches relative to that base?

Mark

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Altix SN2 2.6.16-rc1-mm5 build breakage (was:  msi support)
  2006-02-04  4:42         ` Mark Maule
@ 2006-02-04  5:08           ` Andrew Morton
  0 siblings, 0 replies; 38+ messages in thread
From: Andrew Morton @ 2006-02-04  5:08 UTC (permalink / raw)
  To: Mark Maule
  Cc: pj, linuxppc64-dev, linux-pci, linux-ia64, linux-kernel,
	tony.luck, gregkh

Mark Maule <maule@sgi.com> wrote:
>
> On Fri, Feb 03, 2006 at 08:27:42PM -0800, Andrew Morton wrote:
> > Andrew Morton <akpm@osdl.org> wrote:
> > >
> > > So it
> > >  looks like you've found a fix for a patch which isn't actually in -mm any
> > >  more.  I sent that fix to Greg the other day.
> > 
> > Actually, gregkh-pci-altix-msi-support-git-ia64-fix.patch fix`es
> > git-ia64.patch when gregkh-pci-altix-msi-support.patch is also applied, so
> > it's not presently useful to either Greg or Tony.  I'll take care of it,
> > somehow..
> > 
> 
> I think what happened here is that I submitted a patchset for msi
> abstractions (and others posted a couple of subsequent bugfix incrementals),
> but these were not taken into the 2.6.16 base 'cause of their invasiveness.
> These patches touched the tioce_provider.c file.
> 
> Then I submitted another patch which touched the tioce_provider.c file, and
> it looks like I probably based this file on the previous msi versions which
> were being held back, so in order for everything to build, you need all of
> the msi patches applied first.
> 
> What's the preferred way to handle this ... fix the current ia64 build and
> then resubmit the msi patches relative to that base?
> 

umm, tricky.  This situation doesn't arise very often.

What you could do is to prepare the patches against Tony's latest tree. 
Then I can put them in -mm and Greg can drop them.  Once Tony merges up
with Linus I transfer the patches to Greg.

Or we put the patches into Tony's tree.

Either way - they'll be the same patches.  But it does mean that the
patches won't be merged into mainline until Tony merges up.  If that's a
problem then we'll need to think again.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Altix SN2 2.6.16-rc1-mm5 build breakage (was:  msi support)
  2006-02-04  4:27       ` Andrew Morton
  2006-02-04  4:42         ` Mark Maule
@ 2006-02-23  0:50         ` Paul Jackson
  2006-02-23  1:01           ` Andrew Morton
  1 sibling, 1 reply; 38+ messages in thread
From: Paul Jackson @ 2006-02-23  0:50 UTC (permalink / raw)
  To: Andrew Morton
  Cc: maule, linuxppc64-dev, linux-pci, linux-ia64, linux-kernel,
	tony.luck, gregkh

On Feb 3, Andrew wrote:
> Actually, gregkh-pci-altix-msi-support-git-ia64-fix.patch fix`es
> git-ia64.patch when gregkh-pci-altix-msi-support.patch

Is it time to reinsert that patch?

My ia64 sn build fails again, complaining:


===========================
  CC      arch/ia64/sn/pci/tioce_provider.o
arch/ia64/sn/pci/tioce_provider.c:720:46: macro "ATE_MAKE" requires 3 arguments, but only 2 given
===========================


Your broken-out/series file (2.6.16-rc4-mm1) has the lines:

    # Need this when gregkh-pci-altix-msi-support.patch comes back
    #gregkh-pci-altix-msi-support-git-ia64-fix.patch

I guess that is this patch below, which fixes my sn build just fine.
Holler if you need it as a proper patch.


--- 2.6.16-rc4-mm1.orig/arch/ia64/sn/pci/tioce_provider.c       2006-02-22 16:21:52.054985166 -0800
+++ 2.6.16-rc4-mm1/arch/ia64/sn/pci/tioce_provider.c    2006-02-22 16:31:21.594755653 -0800
@@ -717,7 +717,7 @@ tioce_reserve_m32(struct tioce_kernel *c
        while (ate_index <= last_ate) {
                u64 ate;

-               ate = ATE_MAKE(0xdeadbeef, ps);
+               ate = ATE_MAKE(0xdeadbeef, ps, 0);
                ce_kern->ce_ate3240_shadow[ate_index] = ate;
                tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_ate3240[ate_index],
                                 ate);


-- 
                  I won't rest till it's the best ...
                  Programmer, Linux Scalability
                  Paul Jackson <pj@sgi.com> 1.925.600.0401

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Altix SN2 2.6.16-rc1-mm5 build breakage (was:  msi support)
  2006-02-23  0:50         ` Paul Jackson
@ 2006-02-23  1:01           ` Andrew Morton
  0 siblings, 0 replies; 38+ messages in thread
From: Andrew Morton @ 2006-02-23  1:01 UTC (permalink / raw)
  To: Paul Jackson
  Cc: maule, linuxppc64-dev, linux-pci, linux-ia64, linux-kernel,
	tony.luck, gregkh

Paul Jackson <pj@sgi.com> wrote:
>
> Your broken-out/series file (2.6.16-rc4-mm1) has the lines:
> 
>     # Need this when gregkh-pci-altix-msi-support.patch comes back
>     #gregkh-pci-altix-msi-support-git-ia64-fix.patch

Bah.   I resurrected it, thanks.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/3] msi vector targeting abstractions
  2006-03-29  2:31 [PATCH 0/3] msi abstractions and support for altix Mark Maule
@ 2006-03-29  2:31 ` Mark Maule
  0 siblings, 0 replies; 38+ messages in thread
From: Mark Maule @ 2006-03-29  2:31 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: j-nomura, Tony Luck, gregkh, Mark Maule

Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: linux-2.6/drivers/pci/msi.c
===================================================================
--- linux-2.6.orig/drivers/pci/msi.c	2006-03-27 11:11:04.000000000 -0600
+++ linux-2.6/drivers/pci/msi.c	2006-03-27 13:32:56.192398615 -0600
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
 		if (!pos)
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -251,30 +266,6 @@
 	.set_affinity	= set_msi_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -369,13 +360,29 @@
 		return status;
 	}
 
+	status = msi_arch_init();
+	if (status < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
+	last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
 	status = msi_cache_init();
 	if (status < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
 		return status;
 	}
-	last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
+
 	if (last_alloc_vector < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
@@ -515,9 +522,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -546,23 +555,27 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		dev->irq = entry->msi_attrib.default_vector;
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -652,18 +665,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -809,6 +824,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: linux-2.6/include/asm-i386/msi.h
===================================================================
--- linux-2.6.orig/include/asm-i386/msi.h	2006-03-27 11:11:06.000000000 -0600
+++ linux-2.6/include/asm-i386/msi.h	2006-03-27 13:22:19.533603545 -0600
@@ -12,4 +12,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6/include/asm-x86_64/msi.h
===================================================================
--- linux-2.6.orig/include/asm-x86_64/msi.h	2006-03-27 11:11:07.000000000 -0600
+++ linux-2.6/include/asm-x86_64/msi.h	2006-03-27 13:22:19.536532943 -0600
@@ -13,4 +13,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6/include/asm-ia64/machvec.h
===================================================================
--- linux-2.6.orig/include/asm-ia64/machvec.h	2006-03-27 11:11:06.000000000 -0600
+++ linux-2.6/include/asm-ia64/machvec.h	2006-03-27 13:27:36.669263094 -0600
@@ -76,6 +76,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -154,6 +155,7 @@
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
 #  define platform_migrate		ia64_mv.migrate
+#  define platform_msi_init		ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -203,6 +205,7 @@
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
 	ia64_mv_migrate_t *migrate;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -248,6 +251,7 @@
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
 	platform_migrate,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -399,5 +403,8 @@
 #ifndef platform_migrate
 # define platform_migrate machvec_noop_task
 #endif
+#ifndef platform_msi_init
+# define platform_msi_init	((ia64_mv_msi_init_t*)NULL)
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: linux-2.6/include/asm-ia64/machvec_sn2.h
===================================================================
--- linux-2.6.orig/include/asm-ia64/machvec_sn2.h	2006-03-27 11:11:06.000000000 -0600
+++ linux-2.6/include/asm-ia64/machvec_sn2.h	2006-03-27 13:29:15.149771095 -0600
@@ -117,6 +117,11 @@
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
 #define platform_migrate		sn_migrate
+#ifdef CONFIG_PCI_MSI
+#define platform_msi_init		sn_msi_init
+#else
+#define platform_msi_init		((ia64_mv_msi_init_t*)NULL)
+#endif
 
 #include <asm/sn/io.h>
 
Index: linux-2.6/include/asm-ia64/msi.h
===================================================================
--- linux-2.6.orig/include/asm-ia64/msi.h	2006-03-27 11:11:06.000000000 -0600
+++ linux-2.6/include/asm-ia64/msi.h	2006-03-27 13:22:19.540438807 -0600
@@ -14,4 +14,16 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	if (platform_msi_init)
+		return platform_msi_init();
+
+	/* default ops for most ia64 platforms */
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6/drivers/pci/Makefile
===================================================================
--- linux-2.6.orig/drivers/pci/Makefile	2006-03-27 11:11:03.000000000 -0600
+++ linux-2.6/drivers/pci/Makefile	2006-03-27 13:22:19.540438807 -0600
@@ -26,7 +26,11 @@
 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-y := msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
 # ACPI Related PCI FW Functions
Index: linux-2.6/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/drivers/pci/msi-apic.c	2006-03-27 13:22:19.541415273 -0600
@@ -0,0 +1,100 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic ops used on most IA archs/platforms.  Set with msi_register()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+	.target = msi_target_apic,
+};
Index: linux-2.6/drivers/pci/msi.h
===================================================================
--- linux-2.6.orig/drivers/pci/msi.h	2006-03-27 11:11:04.000000000 -0600
+++ linux-2.6/drivers/pci/msi.h	2006-03-27 13:22:19.542391739 -0600
@@ -6,6 +6,68 @@
 #ifndef MSI_H
 #define MSI_H
 
+/*
+ * MSI operation vector.  Used by the msi core code (drivers/pci/msi.c)
+ * to abstract platform-specific tasks relating to MSI address generation
+ * and resource management.
+ */
+struct msi_ops {
+	/**
+	 * setup - generate an MSI bus address and data for a given vector
+	 * @pdev: PCI device context (in)
+	 * @vector: vector allocated by the msi core (in)
+	 * @addr_hi: upper 32 bits of PCI bus MSI address (out)
+	 * @addr_lo: lower 32 bits of PCI bus MSI address (out)
+	 * @data: MSI data payload (out)
+	 *
+	 * Description: The setup op is used to generate a PCI bus addres and
+	 * data which the msi core will program into the card MSI capability
+	 * registers.  The setup routine is responsible for picking an initial
+	 * cpu to target the MSI at.  The setup routine is responsible for
+	 * examining pdev to determine the MSI capabilities of the card and
+	 * generating a suitable address/data.  The setup routine is
+	 * responsible for allocating and tracking any system resources it
+	 * needs to route the MSI to the cpu it picks, and for associating
+	 * those resources with the passed in vector.
+	 *
+	 * Returns 0 if the MSI address/data was successfully setup.
+	 **/
+
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+
+	/**
+	 * teardown - release resources allocated by setup
+	 * @vector: vector context for resources (in)
+	 *
+	 * Description:  The teardown op is used to release any resources
+	 * that were allocated in the setup routine associated with the passed
+	 * in vector.
+	 **/
+
+	void	(*teardown) (unsigned int vector);
+
+	/**
+	 * target - retarget an MSI at a different cpu
+	 * @vector: vector context for resources (in)
+	 * @cpu:  new cpu to direct vector at (in)
+	 * @addr_hi: new value of PCI bus upper 32 bits (in/out)
+	 * @addr_lo: new value of PCI bus lower 32 bits (in/out)
+	 *
+	 * Description:  The target op is used to redirect an MSI vector
+	 * at a different cpu.  addr_hi/addr_lo coming in are the existing
+	 * values that the MSI core has programmed into the card.  The
+	 * target code is responsible for freeing any resources (if any)
+	 * associated with the old address, and generating a new PCI bus
+	 * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
+	 **/
+
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+};
+
+extern int msi_register(struct msi_ops *ops);
+
 #include <asm/msi.h>
 
 /*
@@ -63,67 +125,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -132,7 +133,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: linux-2.6/drivers/pci/msi-altix.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/drivers/pci/msi-altix.c	2006-03-27 13:22:19.543368205 -0600
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-03-21 19:23         ` Jun'ichi Nomura
@ 2006-03-21 19:38           ` Mark Maule
  0 siblings, 0 replies; 38+ messages in thread
From: Mark Maule @ 2006-03-21 19:38 UTC (permalink / raw)
  To: Jun'ichi Nomura
  Cc: Andreas Schwab, Tony Luck, linux-ia64, gregkh, linux-kernel,
	linuxppc64-dev, linux-pci

On Tue, Mar 21, 2006 at 02:23:44PM -0500, Jun'ichi Nomura wrote:
> Hi,
> 
> Mark Maule wrote:
> >@@ -386,5 +390,8 @@
> > #ifndef platform_readq_relaxed
> > # define platform_readq_relaxed	__ia64_readq_relaxed
> > #endif
> >+#ifndef platform_msi_init
> >+# define platform_msi_init	((ia64_mv_msi_init_t*)NULL)
> >+#endif
> 
> You may also need to change the sn specific header below.
> 
> >@@ -115,6 +116,11 @@
> > #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
> > #define platform_dma_mapping_error		sn_dma_mapping_error
> > #define platform_dma_supported		sn_dma_supported
> >+#ifdef CONFIG_PCI_MSI
> >+#define platform_msi_init		sn_msi_init
> >+#else
> >+#define platform_msi_init		NULL
> >+#endif
> 
> Thanks,
> -- 
> Jun'ichi Nomura, NEC Solutions (America), Inc.

Right - patch attached:


Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: linux-2.6.16/drivers/pci/msi.c
===================================================================
--- linux-2.6.16.orig/drivers/pci/msi.c	2006-03-21 11:13:59.726139722 -0600
+++ linux-2.6.16/drivers/pci/msi.c	2006-03-21 11:14:06.210856320 -0600
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
    		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -251,30 +266,6 @@
 	.set_affinity	= set_msi_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -369,6 +360,20 @@
 		return status;
 	}
 
+	if ((status = msi_arch_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -514,9 +519,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -543,23 +550,27 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		dev->irq = entry->msi_attrib.default_vector;
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -594,13 +605,15 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_hi;
+	u32 address_lo;
+	u32 data;
 	int vector, pos, i, j, nr_entries, temp = 0;
 	u32 phys_addr, table_offset;
  	u16 control;
 	u8 bir;
 	void __iomem *base;
+	int status;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	/* Request & Map MSI-X table region */
@@ -647,18 +660,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -793,6 +808,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: linux-2.6.16/include/asm-i386/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-i386/msi.h	2006-03-21 11:13:59.727116189 -0600
+++ linux-2.6.16/include/asm-i386/msi.h	2006-03-21 11:14:06.213785721 -0600
@@ -12,4 +12,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/include/asm-x86_64/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-x86_64/msi.h	2006-03-21 11:13:59.728092656 -0600
+++ linux-2.6.16/include/asm-x86_64/msi.h	2006-03-21 11:14:06.214762188 -0600
@@ -13,4 +13,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/include/asm-ia64/machvec.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/machvec.h	2006-03-21 11:13:59.728092656 -0600
+++ linux-2.6.16/include/asm-ia64/machvec.h	2006-03-21 11:14:57.089663570 -0600
@@ -74,6 +74,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -146,6 +147,7 @@
 #  define platform_readw_relaxed        ia64_mv.readw_relaxed
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
+#  define platform_msi_init	ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -194,6 +196,7 @@
 	ia64_mv_readw_relaxed_t *readw_relaxed;
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -238,6 +241,7 @@
 	platform_readw_relaxed,			\
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -386,5 +390,8 @@
 #ifndef platform_readq_relaxed
 # define platform_readq_relaxed	__ia64_readq_relaxed
 #endif
+#ifndef platform_msi_init
+# define platform_msi_init	((ia64_mv_msi_init_t*)NULL)
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: linux-2.6.16/include/asm-ia64/machvec_sn2.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/machvec_sn2.h	2006-03-21 11:13:59.728092656 -0600
+++ linux-2.6.16/include/asm-ia64/machvec_sn2.h	2006-03-21 13:26:22.138073104 -0600
@@ -66,6 +66,7 @@
 extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
+extern ia64_mv_msi_init_t		sn_msi_init;
 
 /*
  * This stuff has dual use!
@@ -115,6 +116,11 @@
 #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
+#ifdef CONFIG_PCI_MSI
+#define platform_msi_init		sn_msi_init
+#else
+#define platform_msi_init		((ia64_mv_msi_init_t*)NULL)
+#endif
 
 #include <asm/sn/io.h>
 
Index: linux-2.6.16/include/asm-ia64/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/msi.h	2006-03-21 11:13:59.729069123 -0600
+++ linux-2.6.16/include/asm-ia64/msi.h	2006-03-21 11:14:06.217691588 -0600
@@ -14,4 +14,16 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	if (platform_msi_init)
+		return platform_msi_init();
+
+	/* default ops for most ia64 platforms */
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/drivers/pci/Makefile
===================================================================
--- linux-2.6.16.orig/drivers/pci/Makefile	2006-03-21 11:13:59.726139722 -0600
+++ linux-2.6.16/drivers/pci/Makefile	2006-03-21 11:14:06.217691588 -0600
@@ -26,7 +26,11 @@
 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-y := msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
 # ACPI Related PCI FW Functions
Index: linux-2.6.16/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/drivers/pci/msi-apic.c	2006-03-21 11:14:06.220620989 -0600
@@ -0,0 +1,100 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic ops used on most IA archs/platforms.  Set with msi_register()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+	.target = msi_target_apic,
+};
Index: linux-2.6.16/drivers/pci/msi.h
===================================================================
--- linux-2.6.16.orig/drivers/pci/msi.h	2006-03-21 11:13:59.727116189 -0600
+++ linux-2.6.16/drivers/pci/msi.h	2006-03-21 11:14:06.223550390 -0600
@@ -6,6 +6,68 @@
 #ifndef MSI_H
 #define MSI_H
 
+/*
+ * MSI operation vector.  Used by the msi core code (drivers/pci/msi.c)
+ * to abstract platform-specific tasks relating to MSI address generation
+ * and resource management.
+ */
+struct msi_ops {
+	/**
+	 * setup - generate an MSI bus address and data for a given vector
+	 * @pdev: PCI device context (in)
+	 * @vector: vector allocated by the msi core (in)
+	 * @addr_hi: upper 32 bits of PCI bus MSI address (out)
+	 * @addr_lo: lower 32 bits of PCI bus MSI address (out)
+	 * @data: MSI data payload (out)
+	 *
+	 * Description: The setup op is used to generate a PCI bus addres and
+	 * data which the msi core will program into the card MSI capability
+	 * registers.  The setup routine is responsible for picking an initial
+	 * cpu to target the MSI at.  The setup routine is responsible for
+	 * examining pdev to determine the MSI capabilities of the card and
+	 * generating a suitable address/data.  The setup routine is
+	 * responsible for allocating and tracking any system resources it
+	 * needs to route the MSI to the cpu it picks, and for associating
+	 * those resources with the passed in vector.
+	 *
+	 * Returns 0 if the MSI address/data was successfully setup.
+	 **/
+
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+
+	/**
+	 * teardown - release resources allocated by setup
+	 * @vector: vector context for resources (in)
+	 *
+	 * Description:  The teardown op is used to release any resources
+	 * that were allocated in the setup routine associated with the passed
+	 * in vector.
+	 **/
+
+	void	(*teardown) (unsigned int vector);
+
+	/**
+	 * target - retarget an MSI at a different cpu
+	 * @vector: vector context for resources (in)
+	 * @cpu:  new cpu to direct vector at (in)
+	 * @addr_hi: new value of PCI bus upper 32 bits (in/out)
+	 * @addr_lo: new value of PCI bus lower 32 bits (in/out)
+	 *
+	 * Description:  The target op is used to redirect an MSI vector
+	 * at a different cpu.  addr_hi/addr_lo coming in are the existing
+	 * values that the MSI core has programmed into the card.  The
+	 * target code is responsible for freeing any resources (if any)
+	 * associated with the old address, and generating a new PCI bus
+	 * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
+	 **/
+
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+};
+
+extern int msi_register(struct msi_ops *ops);
+
 #include <asm/msi.h>
 
 /*
@@ -63,67 +125,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -132,7 +133,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: linux-2.6.16/drivers/pci/msi-altix.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/drivers/pci/msi-altix.c	2006-03-21 11:14:06.229409191 -0600
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-03-21 19:14       ` Mark Maule
@ 2006-03-21 19:23         ` Jun'ichi Nomura
  2006-03-21 19:38           ` Mark Maule
  0 siblings, 1 reply; 38+ messages in thread
From: Jun'ichi Nomura @ 2006-03-21 19:23 UTC (permalink / raw)
  To: Mark Maule
  Cc: Andreas Schwab, Tony Luck, linux-ia64, gregkh, linux-kernel,
	linuxppc64-dev, linux-pci

Hi,

Mark Maule wrote:
> @@ -386,5 +390,8 @@
>  #ifndef platform_readq_relaxed
>  # define platform_readq_relaxed	__ia64_readq_relaxed
>  #endif
> +#ifndef platform_msi_init
> +# define platform_msi_init	((ia64_mv_msi_init_t*)NULL)
> +#endif

You may also need to change the sn specific header below.

> @@ -115,6 +116,11 @@
>  #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
>  #define platform_dma_mapping_error		sn_dma_mapping_error
>  #define platform_dma_supported		sn_dma_supported
> +#ifdef CONFIG_PCI_MSI
> +#define platform_msi_init		sn_msi_init
> +#else
> +#define platform_msi_init		NULL
> +#endif

Thanks,
-- 
Jun'ichi Nomura, NEC Solutions (America), Inc.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-03-21 16:38     ` Andreas Schwab
@ 2006-03-21 19:14       ` Mark Maule
  2006-03-21 19:23         ` Jun'ichi Nomura
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2006-03-21 19:14 UTC (permalink / raw)
  To: Andreas Schwab
  Cc: Jun'ichi Nomura, Tony Luck, linux-ia64, gregkh, linux-kernel,
	linuxppc64-dev, linux-pci

On Tue, Mar 21, 2006 at 05:38:08PM +0100, Andreas Schwab wrote:
> "Jun'ichi Nomura" <j-nomura@ce.jp.nec.com> writes:
> 
> > Hi Mark,
> >
> > Mark Maule wrote:
> >> Index: linux-2.6.16/include/asm-ia64/msi.h
> >> ===================================================================
> >> --- linux-2.6.16.orig/include/asm-ia64/msi.h	2006-03-19 23:53:29.000000000 -0600
> >> +++ linux-2.6.16/include/asm-ia64/msi.h	2006-03-20 14:50:53.331368084 -0600
> >> @@ -14,4 +14,16 @@
> >>  #define ack_APIC_irq		ia64_eoi
> >>  #define MSI_TARGET_CPU_SHIFT	4
> >>  
> >> +extern struct msi_ops msi_apic_ops;
> >> +
> >> +static inline int msi_arch_init(void)
> >> +{
> >> +	if (platform_msi_init)
> >> +		return platform_msi_init();
> >> +
> >> +	/* default ops for most ia64 platforms */
> >> +	msi_register(&msi_apic_ops);
> >> +	return 0;
> >> +}
> >> +
> >>  #endif /* ASM_MSI_H */
> >
> > It turned out that the above code breaks configs other
> > than CONFIG_IA64_SN and CONFIG_IA64_GENERIC.
> > e.g. CONFIG_IA64_DIG.
> >
> > In file included from /build/16.msi/drivers/pci/msi.h:71,
> >                  from /build/16.msi/drivers/pci/msi.c:24:
> > include2/asm/msi.h: In function `msi_arch_init':
> > include2/asm/msi.h:22: error: called object is not a function
> > make[3]: *** [drivers/pci/msi.o] Error 1
> >
> > Something like below might fix this problem:
> >   if (platform_msi_init) {
> >       ia64_mv_msi_init_t *fn = platform_msi_init;
> >       return (*fn)();
> >   }
> 
> platform_msi_init should have the right type in the first place,
> ie. defined to ((ia64_mv_msi_init_t*)NULL) instead of just NULL.
> 
> Andreas.

The following resend of 1/3 fixes this:


Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: linux-2.6.16/drivers/pci/msi.c
===================================================================
--- linux-2.6.16.orig/drivers/pci/msi.c	2006-03-21 11:13:59.726139722 -0600
+++ linux-2.6.16/drivers/pci/msi.c	2006-03-21 11:14:06.210856320 -0600
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
    		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -251,30 +266,6 @@
 	.set_affinity	= set_msi_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -369,6 +360,20 @@
 		return status;
 	}
 
+	if ((status = msi_arch_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -514,9 +519,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -543,23 +550,27 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		dev->irq = entry->msi_attrib.default_vector;
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -594,13 +605,15 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_hi;
+	u32 address_lo;
+	u32 data;
 	int vector, pos, i, j, nr_entries, temp = 0;
 	u32 phys_addr, table_offset;
  	u16 control;
 	u8 bir;
 	void __iomem *base;
+	int status;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	/* Request & Map MSI-X table region */
@@ -647,18 +660,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -793,6 +808,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: linux-2.6.16/include/asm-i386/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-i386/msi.h	2006-03-21 11:13:59.727116189 -0600
+++ linux-2.6.16/include/asm-i386/msi.h	2006-03-21 11:14:06.213785721 -0600
@@ -12,4 +12,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/include/asm-x86_64/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-x86_64/msi.h	2006-03-21 11:13:59.728092656 -0600
+++ linux-2.6.16/include/asm-x86_64/msi.h	2006-03-21 11:14:06.214762188 -0600
@@ -13,4 +13,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/include/asm-ia64/machvec.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/machvec.h	2006-03-21 11:13:59.728092656 -0600
+++ linux-2.6.16/include/asm-ia64/machvec.h	2006-03-21 11:14:57.089663570 -0600
@@ -74,6 +74,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -146,6 +147,7 @@
 #  define platform_readw_relaxed        ia64_mv.readw_relaxed
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
+#  define platform_msi_init	ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -194,6 +196,7 @@
 	ia64_mv_readw_relaxed_t *readw_relaxed;
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -238,6 +241,7 @@
 	platform_readw_relaxed,			\
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -386,5 +390,8 @@
 #ifndef platform_readq_relaxed
 # define platform_readq_relaxed	__ia64_readq_relaxed
 #endif
+#ifndef platform_msi_init
+# define platform_msi_init	((ia64_mv_msi_init_t*)NULL)
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: linux-2.6.16/include/asm-ia64/machvec_sn2.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/machvec_sn2.h	2006-03-21 11:13:59.728092656 -0600
+++ linux-2.6.16/include/asm-ia64/machvec_sn2.h	2006-03-21 11:14:06.216715122 -0600
@@ -66,6 +66,7 @@
 extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
+extern ia64_mv_msi_init_t		sn_msi_init;
 
 /*
  * This stuff has dual use!
@@ -115,6 +116,11 @@
 #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
+#ifdef CONFIG_PCI_MSI
+#define platform_msi_init		sn_msi_init
+#else
+#define platform_msi_init		NULL
+#endif
 
 #include <asm/sn/io.h>
 
Index: linux-2.6.16/include/asm-ia64/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/msi.h	2006-03-21 11:13:59.729069123 -0600
+++ linux-2.6.16/include/asm-ia64/msi.h	2006-03-21 11:14:06.217691588 -0600
@@ -14,4 +14,16 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	if (platform_msi_init)
+		return platform_msi_init();
+
+	/* default ops for most ia64 platforms */
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/drivers/pci/Makefile
===================================================================
--- linux-2.6.16.orig/drivers/pci/Makefile	2006-03-21 11:13:59.726139722 -0600
+++ linux-2.6.16/drivers/pci/Makefile	2006-03-21 11:14:06.217691588 -0600
@@ -26,7 +26,11 @@
 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-y := msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
 # ACPI Related PCI FW Functions
Index: linux-2.6.16/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/drivers/pci/msi-apic.c	2006-03-21 11:14:06.220620989 -0600
@@ -0,0 +1,100 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic ops used on most IA archs/platforms.  Set with msi_register()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+	.target = msi_target_apic,
+};
Index: linux-2.6.16/drivers/pci/msi.h
===================================================================
--- linux-2.6.16.orig/drivers/pci/msi.h	2006-03-21 11:13:59.727116189 -0600
+++ linux-2.6.16/drivers/pci/msi.h	2006-03-21 11:14:06.223550390 -0600
@@ -6,6 +6,68 @@
 #ifndef MSI_H
 #define MSI_H
 
+/*
+ * MSI operation vector.  Used by the msi core code (drivers/pci/msi.c)
+ * to abstract platform-specific tasks relating to MSI address generation
+ * and resource management.
+ */
+struct msi_ops {
+	/**
+	 * setup - generate an MSI bus address and data for a given vector
+	 * @pdev: PCI device context (in)
+	 * @vector: vector allocated by the msi core (in)
+	 * @addr_hi: upper 32 bits of PCI bus MSI address (out)
+	 * @addr_lo: lower 32 bits of PCI bus MSI address (out)
+	 * @data: MSI data payload (out)
+	 *
+	 * Description: The setup op is used to generate a PCI bus addres and
+	 * data which the msi core will program into the card MSI capability
+	 * registers.  The setup routine is responsible for picking an initial
+	 * cpu to target the MSI at.  The setup routine is responsible for
+	 * examining pdev to determine the MSI capabilities of the card and
+	 * generating a suitable address/data.  The setup routine is
+	 * responsible for allocating and tracking any system resources it
+	 * needs to route the MSI to the cpu it picks, and for associating
+	 * those resources with the passed in vector.
+	 *
+	 * Returns 0 if the MSI address/data was successfully setup.
+	 **/
+
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+
+	/**
+	 * teardown - release resources allocated by setup
+	 * @vector: vector context for resources (in)
+	 *
+	 * Description:  The teardown op is used to release any resources
+	 * that were allocated in the setup routine associated with the passed
+	 * in vector.
+	 **/
+
+	void	(*teardown) (unsigned int vector);
+
+	/**
+	 * target - retarget an MSI at a different cpu
+	 * @vector: vector context for resources (in)
+	 * @cpu:  new cpu to direct vector at (in)
+	 * @addr_hi: new value of PCI bus upper 32 bits (in/out)
+	 * @addr_lo: new value of PCI bus lower 32 bits (in/out)
+	 *
+	 * Description:  The target op is used to redirect an MSI vector
+	 * at a different cpu.  addr_hi/addr_lo coming in are the existing
+	 * values that the MSI core has programmed into the card.  The
+	 * target code is responsible for freeing any resources (if any)
+	 * associated with the old address, and generating a new PCI bus
+	 * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
+	 **/
+
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+};
+
+extern int msi_register(struct msi_ops *ops);
+
 #include <asm/msi.h>
 
 /*
@@ -63,67 +125,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -132,7 +133,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: linux-2.6.16/drivers/pci/msi-altix.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/drivers/pci/msi-altix.c	2006-03-21 11:14:06.229409191 -0600
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-03-21 16:29   ` Jun'ichi Nomura
@ 2006-03-21 16:38     ` Andreas Schwab
  2006-03-21 19:14       ` Mark Maule
  0 siblings, 1 reply; 38+ messages in thread
From: Andreas Schwab @ 2006-03-21 16:38 UTC (permalink / raw)
  To: Jun'ichi Nomura
  Cc: Mark Maule, Tony Luck, linux-ia64, gregkh, linux-kernel,
	linuxppc64-dev, linux-pci

"Jun'ichi Nomura" <j-nomura@ce.jp.nec.com> writes:

> Hi Mark,
>
> Mark Maule wrote:
>> Index: linux-2.6.16/include/asm-ia64/msi.h
>> ===================================================================
>> --- linux-2.6.16.orig/include/asm-ia64/msi.h	2006-03-19 23:53:29.000000000 -0600
>> +++ linux-2.6.16/include/asm-ia64/msi.h	2006-03-20 14:50:53.331368084 -0600
>> @@ -14,4 +14,16 @@
>>  #define ack_APIC_irq		ia64_eoi
>>  #define MSI_TARGET_CPU_SHIFT	4
>>  
>> +extern struct msi_ops msi_apic_ops;
>> +
>> +static inline int msi_arch_init(void)
>> +{
>> +	if (platform_msi_init)
>> +		return platform_msi_init();
>> +
>> +	/* default ops for most ia64 platforms */
>> +	msi_register(&msi_apic_ops);
>> +	return 0;
>> +}
>> +
>>  #endif /* ASM_MSI_H */
>
> It turned out that the above code breaks configs other
> than CONFIG_IA64_SN and CONFIG_IA64_GENERIC.
> e.g. CONFIG_IA64_DIG.
>
> In file included from /build/16.msi/drivers/pci/msi.h:71,
>                  from /build/16.msi/drivers/pci/msi.c:24:
> include2/asm/msi.h: In function `msi_arch_init':
> include2/asm/msi.h:22: error: called object is not a function
> make[3]: *** [drivers/pci/msi.o] Error 1
>
> Something like below might fix this problem:
>   if (platform_msi_init) {
>       ia64_mv_msi_init_t *fn = platform_msi_init;
>       return (*fn)();
>   }

platform_msi_init should have the right type in the first place,
ie. defined to ((ia64_mv_msi_init_t*)NULL) instead of just NULL.

Andreas.

-- 
Andreas Schwab, SuSE Labs, schwab@suse.de
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-03-21 14:34 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
@ 2006-03-21 16:29   ` Jun'ichi Nomura
  2006-03-21 16:38     ` Andreas Schwab
  0 siblings, 1 reply; 38+ messages in thread
From: Jun'ichi Nomura @ 2006-03-21 16:29 UTC (permalink / raw)
  To: Mark Maule
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

Hi Mark,

Mark Maule wrote:
> Index: linux-2.6.16/include/asm-ia64/msi.h
> ===================================================================
> --- linux-2.6.16.orig/include/asm-ia64/msi.h	2006-03-19 23:53:29.000000000 -0600
> +++ linux-2.6.16/include/asm-ia64/msi.h	2006-03-20 14:50:53.331368084 -0600
> @@ -14,4 +14,16 @@
>  #define ack_APIC_irq		ia64_eoi
>  #define MSI_TARGET_CPU_SHIFT	4
>  
> +extern struct msi_ops msi_apic_ops;
> +
> +static inline int msi_arch_init(void)
> +{
> +	if (platform_msi_init)
> +		return platform_msi_init();
> +
> +	/* default ops for most ia64 platforms */
> +	msi_register(&msi_apic_ops);
> +	return 0;
> +}
> +
>  #endif /* ASM_MSI_H */

It turned out that the above code breaks configs other
than CONFIG_IA64_SN and CONFIG_IA64_GENERIC.
e.g. CONFIG_IA64_DIG.

In file included from /build/16.msi/drivers/pci/msi.h:71,
                 from /build/16.msi/drivers/pci/msi.c:24:
include2/asm/msi.h: In function `msi_arch_init':
include2/asm/msi.h:22: error: called object is not a function
make[3]: *** [drivers/pci/msi.o] Error 1

Something like below might fix this problem:
  if (platform_msi_init) {
      ia64_mv_msi_init_t *fn = platform_msi_init;
      return (*fn)();
  }

Thanks,
-- 
Jun'ichi Nomura, NEC Solutions (America), Inc.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/3] msi vector targeting abstractions
  2006-03-21 14:34 [PATCH 0/3] msi abstractions and support for altix Mark Maule
@ 2006-03-21 14:34 ` Mark Maule
  2006-03-21 16:29   ` Jun'ichi Nomura
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2006-03-21 14:34 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: j-nomura, Tony Luck, gregkh, Mark Maule

Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: linux-2.6.16/drivers/pci/msi.c
===================================================================
--- linux-2.6.16.orig/drivers/pci/msi.c	2006-03-19 23:53:29.000000000 -0600
+++ linux-2.6.16/drivers/pci/msi.c	2006-03-21 07:17:39.987000963 -0600
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
    		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -251,30 +266,6 @@
 	.set_affinity	= set_msi_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -369,6 +360,20 @@
 		return status;
 	}
 
+	if ((status = msi_arch_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -514,9 +519,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -543,23 +550,27 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		dev->irq = entry->msi_attrib.default_vector;
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -594,13 +605,15 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_hi;
+	u32 address_lo;
+	u32 data;
 	int vector, pos, i, j, nr_entries, temp = 0;
 	u32 phys_addr, table_offset;
  	u16 control;
 	u8 bir;
 	void __iomem *base;
+	int status;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	/* Request & Map MSI-X table region */
@@ -647,18 +660,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -793,6 +808,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: linux-2.6.16/include/asm-i386/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-i386/msi.h	2006-03-19 23:53:29.000000000 -0600
+++ linux-2.6.16/include/asm-i386/msi.h	2006-03-20 14:45:09.540950385 -0600
@@ -12,4 +12,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/include/asm-x86_64/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-x86_64/msi.h	2006-03-19 23:53:29.000000000 -0600
+++ linux-2.6.16/include/asm-x86_64/msi.h	2006-03-20 14:45:09.542903318 -0600
@@ -13,4 +13,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/include/asm-ia64/machvec.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/machvec.h	2006-03-19 23:53:29.000000000 -0600
+++ linux-2.6.16/include/asm-ia64/machvec.h	2006-03-20 14:49:38.415888062 -0600
@@ -74,6 +74,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -146,6 +147,7 @@
 #  define platform_readw_relaxed        ia64_mv.readw_relaxed
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
+#  define platform_msi_init	ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -194,6 +196,7 @@
 	ia64_mv_readw_relaxed_t *readw_relaxed;
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -238,6 +241,7 @@
 	platform_readw_relaxed,			\
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -386,5 +390,8 @@
 #ifndef platform_readq_relaxed
 # define platform_readq_relaxed	__ia64_readq_relaxed
 #endif
+#ifndef platform_msi_init
+# define platform_msi_init	NULL
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: linux-2.6.16/include/asm-ia64/machvec_sn2.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/machvec_sn2.h	2006-03-19 23:53:29.000000000 -0600
+++ linux-2.6.16/include/asm-ia64/machvec_sn2.h	2006-03-20 14:45:09.548762117 -0600
@@ -66,6 +66,7 @@
 extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
+extern ia64_mv_msi_init_t		sn_msi_init;
 
 /*
  * This stuff has dual use!
@@ -115,6 +116,11 @@
 #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
+#ifdef CONFIG_PCI_MSI
+#define platform_msi_init		sn_msi_init
+#else
+#define platform_msi_init		NULL
+#endif
 
 #include <asm/sn/io.h>
 
Index: linux-2.6.16/include/asm-ia64/msi.h
===================================================================
--- linux-2.6.16.orig/include/asm-ia64/msi.h	2006-03-19 23:53:29.000000000 -0600
+++ linux-2.6.16/include/asm-ia64/msi.h	2006-03-20 14:50:53.331368084 -0600
@@ -14,4 +14,16 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	if (platform_msi_init)
+		return platform_msi_init();
+
+	/* default ops for most ia64 platforms */
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6.16/drivers/pci/Makefile
===================================================================
--- linux-2.6.16.orig/drivers/pci/Makefile	2006-03-19 23:53:29.000000000 -0600
+++ linux-2.6.16/drivers/pci/Makefile	2006-03-20 22:00:54.079057888 -0600
@@ -26,7 +26,11 @@
 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-y := msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #
 # ACPI Related PCI FW Functions
Index: linux-2.6.16/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/drivers/pci/msi-apic.c	2006-03-20 22:01:01.802923681 -0600
@@ -0,0 +1,100 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic ops used on most IA archs/platforms.  Set with msi_register()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+	.target = msi_target_apic,
+};
Index: linux-2.6.16/drivers/pci/msi.h
===================================================================
--- linux-2.6.16.orig/drivers/pci/msi.h	2006-03-19 23:53:29.000000000 -0600
+++ linux-2.6.16/drivers/pci/msi.h	2006-03-20 14:55:40.935888578 -0600
@@ -6,6 +6,68 @@
 #ifndef MSI_H
 #define MSI_H
 
+/*
+ * MSI operation vector.  Used by the msi core code (drivers/pci/msi.c)
+ * to abstract platform-specific tasks relating to MSI address generation
+ * and resource management.
+ */
+struct msi_ops {
+	/**
+	 * setup - generate an MSI bus address and data for a given vector
+	 * @pdev: PCI device context (in)
+	 * @vector: vector allocated by the msi core (in)
+	 * @addr_hi: upper 32 bits of PCI bus MSI address (out)
+	 * @addr_lo: lower 32 bits of PCI bus MSI address (out)
+	 * @data: MSI data payload (out)
+	 *
+	 * Description: The setup op is used to generate a PCI bus addres and
+	 * data which the msi core will program into the card MSI capability
+	 * registers.  The setup routine is responsible for picking an initial
+	 * cpu to target the MSI at.  The setup routine is responsible for
+	 * examining pdev to determine the MSI capabilities of the card and
+	 * generating a suitable address/data.  The setup routine is
+	 * responsible for allocating and tracking any system resources it
+	 * needs to route the MSI to the cpu it picks, and for associating
+	 * those resources with the passed in vector.
+	 *
+	 * Returns 0 if the MSI address/data was successfully setup.
+	 **/
+
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+
+	/**
+	 * teardown - release resources allocated by setup
+	 * @vector: vector context for resources (in)
+	 *
+	 * Description:  The teardown op is used to release any resources
+	 * that were allocated in the setup routine associated with the passed
+	 * in vector.
+	 **/
+
+	void	(*teardown) (unsigned int vector);
+
+	/**
+	 * target - retarget an MSI at a different cpu
+	 * @vector: vector context for resources (in)
+	 * @cpu:  new cpu to direct vector at (in)
+	 * @addr_hi: new value of PCI bus upper 32 bits (in/out)
+	 * @addr_lo: new value of PCI bus lower 32 bits (in/out)
+	 *
+	 * Description:  The target op is used to redirect an MSI vector
+	 * at a different cpu.  addr_hi/addr_lo coming in are the existing
+	 * values that the MSI core has programmed into the card.  The
+	 * target code is responsible for freeing any resources (if any)
+	 * associated with the old address, and generating a new PCI bus
+	 * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
+	 **/
+
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+};
+
+extern int msi_register(struct msi_ops *ops);
+
 #include <asm/msi.h>
 
 /*
@@ -63,67 +125,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -132,7 +133,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: linux-2.6.16/drivers/pci/msi-altix.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/drivers/pci/msi-altix.c	2006-03-21 07:17:34.077424014 -0600
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-12  5:47     ` Paul Mackerras
@ 2006-01-12  7:33       ` Grant Grundler
  0 siblings, 0 replies; 38+ messages in thread
From: Grant Grundler @ 2006-01-12  7:33 UTC (permalink / raw)
  To: Paul Mackerras
  Cc: Grant Grundler, Mark Maule, Tony Luck, linux-ia64, gregkh,
	linux-kernel, linuxppc64-dev, linux-pci

On Thu, Jan 12, 2006 at 04:47:27PM +1100, Paul Mackerras wrote:
> Grant Grundler writes:
> 
> > > +	if ((status = msi_arch_init()) < 0) {
> > 
> > Willy told me I should always complain about assignment in if() statements :)
> 
> We are getting incredibly politically correct these days, aren't we.

I'm not asking greg to reject the patch nor dictating Mark Mauler change it.
Since greg is willing to accept a patch to "fix" it, I'm willing to provide 
the patch in this case. I think that's fairly normal way to clean things up.

> I see nothing wrong with that if statement.  It's perfectly valid,
> idiomatic C.  You can ignore Willy if you like. :)

While it is valid C, "=" occasionally gets confused with "==".
And adding unnecessary parens to an if() statement increases the
risk someone will misread the line.  "someone" includes me. :)

> (I would look askance at something that did an assignment as one of
> the parameters of a procedure call in an if statement, though.)

*nod* 

thanks,
grant

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-12  5:02   ` Grant Grundler
  2006-01-12  5:36     ` Greg KH
@ 2006-01-12  5:47     ` Paul Mackerras
  2006-01-12  7:33       ` Grant Grundler
  1 sibling, 1 reply; 38+ messages in thread
From: Paul Mackerras @ 2006-01-12  5:47 UTC (permalink / raw)
  To: Grant Grundler
  Cc: Mark Maule, Tony Luck, linux-ia64, gregkh, linux-kernel,
	linuxppc64-dev, linux-pci

Grant Grundler writes:

> > +	if ((status = msi_arch_init()) < 0) {
> 
> Willy told me I should always complain about assignment in if() statements :)

We are getting incredibly politically correct these days, aren't we.

I see nothing wrong with that if statement.  It's perfectly valid,
idiomatic C.  You can ignore Willy if you like. :)

(I would look askance at something that did an assignment as one of
the parameters of a procedure call in an if statement, though.)

Paul.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-12  5:02   ` Grant Grundler
@ 2006-01-12  5:36     ` Greg KH
  2006-01-12  5:47     ` Paul Mackerras
  1 sibling, 0 replies; 38+ messages in thread
From: Greg KH @ 2006-01-12  5:36 UTC (permalink / raw)
  To: Grant Grundler
  Cc: Mark Maule, linuxppc64-dev, linux-pci, linux-ia64, linux-kernel,
	Tony Luck

On Wed, Jan 11, 2006 at 10:02:43PM -0700, Grant Grundler wrote:
> On Wed, Jan 11, 2006 at 09:52:56AM -0600, Mark Maule wrote:
> > Abstract portions of the MSI core for platforms that do not use standard
> > APIC interrupt controllers.  This is implemented through a new arch-specific
> > msi setup routine, and a set of msi ops which can be set on a per platform
> > basis.
> ...
> > Index: linux-maule/drivers/pci/msi.c
> ...
> > +	if ((status = msi_arch_init()) < 0) {
> 
> Willy told me I should always complain about assignment in if() statements :)
> 
> Greg, I volunteer to submit a patch to fix all occurances in pci/msi.c
> including the one above.  I can prepare that this weekend on my own time.
> Is that ok?

Yes, that would be wonderful to have.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-11 15:52 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
  2006-01-11 20:21   ` Greg KH
@ 2006-01-12  5:02   ` Grant Grundler
  2006-01-12  5:36     ` Greg KH
  2006-01-12  5:47     ` Paul Mackerras
  1 sibling, 2 replies; 38+ messages in thread
From: Grant Grundler @ 2006-01-12  5:02 UTC (permalink / raw)
  To: Mark Maule
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

On Wed, Jan 11, 2006 at 09:52:56AM -0600, Mark Maule wrote:
> Abstract portions of the MSI core for platforms that do not use standard
> APIC interrupt controllers.  This is implemented through a new arch-specific
> msi setup routine, and a set of msi ops which can be set on a per platform
> basis.
...
> Index: linux-maule/drivers/pci/msi.c
...
> +	if ((status = msi_arch_init()) < 0) {

Willy told me I should always complain about assignment in if() statements :)

Greg, I volunteer to submit a patch to fix all occurances in pci/msi.c
including the one above.  I can prepare that this weekend on my own time.
Is that ok?

grant

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/3] msi vector targeting abstractions
  2006-01-11 22:16 [PATCH 0/3] msi abstractions and support for altix Mark Maule
@ 2006-01-11 22:16 ` Mark Maule
  0 siblings, 0 replies; 38+ messages in thread
From: Mark Maule @ 2006-01-11 22:16 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: Tony Luck, gregkh, Mark Maule

Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: linux-2.6/drivers/pci/msi.c
===================================================================
--- linux-2.6.orig/drivers/pci/msi.c	2006-01-11 15:09:44.886491753 -0600
+++ linux-2.6/drivers/pci/msi.c	2006-01-11 16:06:16.096502865 -0600
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
    		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -249,30 +264,6 @@
 	.set_affinity	= set_msi_irq_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -367,6 +358,20 @@
 		return status;
 	}
 
+	if ((status = msi_arch_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -510,9 +515,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -539,23 +546,26 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -590,13 +600,15 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_hi;
+	u32 address_lo;
+	u32 data;
 	int vector, pos, i, j, nr_entries, temp = 0;
 	u32 phys_addr, table_offset;
  	u16 control;
 	u8 bir;
 	void __iomem *base;
+	int status;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	/* Request & Map MSI-X table region */
@@ -643,18 +655,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -789,6 +803,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: linux-2.6/include/asm-i386/msi.h
===================================================================
--- linux-2.6.orig/include/asm-i386/msi.h	2006-01-11 15:09:44.888444686 -0600
+++ linux-2.6/include/asm-i386/msi.h	2006-01-11 15:10:28.932942666 -0600
@@ -12,4 +12,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6/include/asm-x86_64/msi.h
===================================================================
--- linux-2.6.orig/include/asm-x86_64/msi.h	2006-01-11 15:09:44.888444686 -0600
+++ linux-2.6/include/asm-x86_64/msi.h	2006-01-11 15:10:35.927372212 -0600
@@ -13,4 +13,12 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+extern struct msi_ops msi_apic_ops;
+
+static inline int msi_arch_init(void)
+{
+	msi_register_apic(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-2.6/include/asm-ia64/machvec.h
===================================================================
--- linux-2.6.orig/include/asm-ia64/machvec.h	2006-01-11 15:09:44.888444686 -0600
+++ linux-2.6/include/asm-ia64/machvec.h	2006-01-11 15:09:58.266035744 -0600
@@ -74,6 +74,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -146,6 +147,7 @@
 #  define platform_readw_relaxed        ia64_mv.readw_relaxed
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
+#  define platform_msi_init	ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -194,6 +196,7 @@
 	ia64_mv_readw_relaxed_t *readw_relaxed;
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -238,6 +241,7 @@
 	platform_readw_relaxed,			\
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -386,5 +390,8 @@
 #ifndef platform_readq_relaxed
 # define platform_readq_relaxed	__ia64_readq_relaxed
 #endif
+#ifndef platform_msi_init
+# define platform_msi_init	ia64_msi_init
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: linux-2.6/include/asm-ia64/machvec_sn2.h
===================================================================
--- linux-2.6.orig/include/asm-ia64/machvec_sn2.h	2006-01-11 15:09:44.889421152 -0600
+++ linux-2.6/include/asm-ia64/machvec_sn2.h	2006-01-11 15:09:58.267012210 -0600
@@ -71,6 +71,7 @@
 extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
+extern ia64_mv_msi_init_t		sn_msi_init;
 
 /*
  * This stuff has dual use!
@@ -120,6 +121,7 @@
 #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
+#define platform_msi_init		sn_msi_init
 
 #include <asm/sn/io.h>
 
Index: linux-2.6/include/asm-ia64/msi.h
===================================================================
--- linux-2.6.orig/include/asm-ia64/msi.h	2006-01-11 15:09:44.889421152 -0600
+++ linux-2.6/include/asm-ia64/msi.h	2006-01-11 15:10:44.146290750 -0600
@@ -14,4 +14,15 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+extern struct msi_ops msi_apic_ops;
+
+/* default ia64 msi init routine */
+static inline int ia64_msi_init(void)
+{
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
+#define msi_arch_init		platform_msi_init
+
 #endif /* ASM_MSI_H */
Index: linux-2.6/arch/ia64/sn/pci/Makefile
===================================================================
--- linux-2.6.orig/arch/ia64/sn/pci/Makefile	2006-01-11 15:09:44.890397619 -0600
+++ linux-2.6/arch/ia64/sn/pci/Makefile	2006-01-11 15:09:58.270918076 -0600
@@ -3,8 +3,9 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (C) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
 #
 # Makefile for the sn pci general routines.
 
 obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
+obj-$(CONFIG_PCI_MSI) += msi.o
Index: linux-2.6/arch/ia64/sn/pci/msi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/arch/ia64/sn/pci/msi.c	2006-01-11 16:06:14.504862843 -0600
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}
Index: linux-2.6/drivers/pci/Makefile
===================================================================
--- linux-2.6.orig/drivers/pci/Makefile	2006-01-11 15:09:44.887468219 -0600
+++ linux-2.6/drivers/pci/Makefile	2006-01-11 15:09:58.271894543 -0600
@@ -26,7 +26,7 @@
 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
+obj-$(CONFIG_PCI_MSI) += msi.o msi-apic.o
 
 #
 # ACPI Related PCI FW Functions
Index: linux-2.6/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/drivers/pci/msi-apic.c	2006-01-11 16:07:17.131503734 -0600
@@ -0,0 +1,100 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic ops used on most IA archs/platforms.  Set with msi_register()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+	.target = msi_target_apic,
+};
Index: linux-2.6/drivers/pci/msi.h
===================================================================
--- linux-2.6.orig/drivers/pci/msi.h	2006-01-11 15:09:44.887468219 -0600
+++ linux-2.6/drivers/pci/msi.h	2006-01-11 15:09:58.275800409 -0600
@@ -69,67 +69,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -138,7 +77,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h	2006-01-11 15:09:44.889421152 -0600
+++ linux-2.6/include/linux/pci.h	2006-01-11 15:59:55.573460347 -0600
@@ -547,6 +547,66 @@
 	u16	entry;	/* driver uses to specify entry, OS writes */
 };
 
+/*
+ * MSI operation vector.  Used by the msi core code (drivers/pci/msi.c)
+ * to abstract platform-specific tasks relating to MSI address generation
+ * and resource management.
+ */
+struct msi_ops {
+	/**
+	 * setup - generate an MSI bus address and data for a given vector
+	 * @pdev: PCI device context (in)
+	 * @vector: vector allocated by the msi core (in)
+	 * @addr_hi: upper 32 bits of PCI bus MSI address (out)
+	 * @addr_lo: lower 32 bits of PCI bus MSI address (out)
+	 * @data: MSI data payload (out)
+	 *
+	 * Description: The setup op is used to generate a PCI bus addres and
+	 * data which the msi core will program into the card MSI capability
+	 * registers.  The setup routine is responsible for picking an initial
+	 * cpu to target the MSI at.  The setup routine is responsible for
+	 * examining pdev to determine the MSI capabilities of the card and
+	 * generating a suitable address/data.  The setup routine is
+	 * responsible for allocating and tracking any system resources it
+	 * needs to route the MSI to the cpu it picks, and for associating
+	 * those resources with the passed in vector.
+	 *
+	 * Returns 0 if the MSI address/data was successfully setup.
+	 **/
+
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+
+	/**
+	 * teardown - release resources allocated by setup
+	 * @vector: vector context for resources (in)
+	 *
+	 * Description:  The teardown op is used to release any resources
+	 * that were allocated in the setup routine associated with the passed
+	 * in vector.
+	 **/
+
+	void	(*teardown) (unsigned int vector);
+
+	/**
+	 * target - retarget an MSI at a different cpu
+	 * @vector: vector context for resources (in)
+	 * @cpu:  new cpu to direct vector at (in)
+	 * @addr_hi: new value of PCI bus upper 32 bits (in/out)
+	 * @addr_lo: new value of PCI bus lower 32 bits (in/out)
+	 *
+	 * Description:  The target op is used to redirect an MSI vector
+	 * at a different cpu.  addr_hi/addr_lo coming in are the existing
+	 * values that the MSI core has programmed into the card.  The
+	 * target code is responsible for freeing any resources (if any)
+	 * associated with the old address, and generating a new PCI bus
+	 * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
+	 **/
+
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+};
+
 #ifndef CONFIG_PCI_MSI
 static inline void pci_scan_msi_device(struct pci_dev *dev) {}
 static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
@@ -555,6 +615,7 @@
 	struct msix_entry *entries, int nvec) {return -1;}
 static inline void pci_disable_msix(struct pci_dev *dev) {}
 static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+static inline int msi_register(struct msi_ops *ops) {return -1;}
 #else
 extern void pci_scan_msi_device(struct pci_dev *dev);
 extern int pci_enable_msi(struct pci_dev *dev);
@@ -563,6 +624,7 @@
 	struct msix_entry *entries, int nvec);
 extern void pci_disable_msix(struct pci_dev *dev);
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+extern int msi_register(struct msi_ops *ops);
 #endif
 
 extern void pci_block_user_cfg_access(struct pci_dev *dev);

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-11 20:49     ` Mark Maule
@ 2006-01-11 20:57       ` Greg KH
  0 siblings, 0 replies; 38+ messages in thread
From: Greg KH @ 2006-01-11 20:57 UTC (permalink / raw)
  To: Mark Maule
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

On Wed, Jan 11, 2006 at 02:49:29PM -0600, Mark Maule wrote:
> > > +static inline int msi_arch_init(void)
> > > +{
> > > +	extern struct msi_ops msi_apic_ops;
> > > +	msi_register(&msi_apic_ops);
> > > +	return 0;
> > > +}
> > 
> > Don't have an extern in a function, it belongs in a .h file somewhere
> > that describes it and everyone can see it.  Otherwise this gets stale
> > and messy over time.
> 
> In this case, I have a public .h (asm-xxx/msi.h) which needs a data structure
> decleared down in a driver-private file (drivers/pci/msi-apic.c).  Do you have
> a suggestion for where I should put the msi_apic_ops declaration?  It should
> be somewhere such that future msi ops (e.g. sn_msi_ops from patch3) would
> be treated consistently.
> 
> linux/pci.h seems like one possiblity near where the ops struct is declared,
> but that doesn't really seem right, because we'ld want to treat sn_msi_ops
> (and future msi ops) the same way.
> 
> Maybe just move the extern out of the function and up further in the
> asm-xxx/msi.h file?

Sure, or in drivers/pci/pci.h, as that is private to the pci
implementation code, right?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-11 20:21   ` Greg KH
@ 2006-01-11 20:49     ` Mark Maule
  2006-01-11 20:57       ` Greg KH
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2006-01-11 20:49 UTC (permalink / raw)
  To: Greg KH
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

> > +static inline int msi_arch_init(void)
> > +{
> > +	extern struct msi_ops msi_apic_ops;
> > +	msi_register(&msi_apic_ops);
> > +	return 0;
> > +}
> 
> Don't have an extern in a function, it belongs in a .h file somewhere
> that describes it and everyone can see it.  Otherwise this gets stale
> and messy over time.

In this case, I have a public .h (asm-xxx/msi.h) which needs a data structure
decleared down in a driver-private file (drivers/pci/msi-apic.c).  Do you have
a suggestion for where I should put the msi_apic_ops declaration?  It should
be somewhere such that future msi ops (e.g. sn_msi_ops from patch3) would
be treated consistently.

linux/pci.h seems like one possiblity near where the ops struct is declared,
but that doesn't really seem right, because we'ld want to treat sn_msi_ops
(and future msi ops) the same way.

Maybe just move the extern out of the function and up further in the
asm-xxx/msi.h file?

> 
> > +/*
> > + * Generic callouts used on most archs/platforms.  Override with
> > + * msi_register_callouts()
> > + */
> 
> Care to use kerneldoc here and define exactly what is needed for these
> function pointers?  And you are still calling them "callouts" here :)
> 
> > +struct msi_ops msi_apic_ops = {
> > +	.setup = msi_setup_apic,
> > +	.teardown = msi_teardown_apic,
> > +#ifdef CONFIG_SMP
> > +	.target = msi_target_apic,
> > +#endif
> 
> Why the #ifdef?  Just drop it, it makes the code cleaner.
> 
> Care to redo this?

ok.  Will submit a new version once we have the placement of the msi_apic_ops
declaration sorted out.

Mark

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-11 15:52 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
@ 2006-01-11 20:21   ` Greg KH
  2006-01-11 20:49     ` Mark Maule
  2006-01-12  5:02   ` Grant Grundler
  1 sibling, 1 reply; 38+ messages in thread
From: Greg KH @ 2006-01-11 20:21 UTC (permalink / raw)
  To: Mark Maule
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

On Wed, Jan 11, 2006 at 09:52:56AM -0600, Mark Maule wrote:
> Abstract portions of the MSI core for platforms that do not use standard
> APIC interrupt controllers.  This is implemented through a new arch-specific
> msi setup routine, and a set of msi ops which can be set on a per platform
> basis.

Ah, much better, just a few more minor comments below:


> 
> Signed-off-by: Mark Maule <maule@sgi.com>
> 
> Index: linux-maule/drivers/pci/msi.c
> ===================================================================
> --- linux-maule.orig/drivers/pci/msi.c	2006-01-10 11:48:01.000000000 -0800
> +++ linux-maule/drivers/pci/msi.c	2006-01-10 13:40:45.000000000 -0800
> @@ -23,8 +23,6 @@
>  #include "pci.h"
>  #include "msi.h"
>  
> -#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
> -
>  static DEFINE_SPINLOCK(msi_lock);
>  static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
>  static kmem_cache_t* msi_cachep;
> @@ -40,6 +38,15 @@
>  u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
>  #endif
>  
> +static struct msi_ops *msi_ops;
> +
> +int
> +msi_register(struct msi_ops *ops)
> +{
> +	msi_ops = ops;
> +	return 0;
> +}
> +
>  static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
>  {
>  	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
> @@ -92,7 +99,7 @@
>  static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
>  {
>  	struct msi_desc *entry;
> -	struct msg_address address;
> +	u32 address_hi, address_lo;
>  	unsigned int irq = vector;
>  	unsigned int dest_cpu = first_cpu(cpu_mask);
>  
> @@ -108,28 +115,36 @@
>     		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
>  			return;
>  
> +		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
> +			&address_hi);
>  		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
> -			&address.lo_address.value);
> -		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
> -		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
> -									MSI_TARGET_CPU_SHIFT);
> -		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
> +			&address_lo);
> +
> +		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
> +
> +		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
> +			address_hi);
>  		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
> -			address.lo_address.value);
> +			address_lo);
>  		set_native_irq_info(irq, cpu_mask);
>  		break;
>  	}
>  	case PCI_CAP_ID_MSIX:
>  	{
> -		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
> -			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
> +		int offset_hi =
> +			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
> +				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
> +		int offset_lo =
> +			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
> +				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
> +
> +		address_hi = readl(entry->mask_base + offset_hi);
> +		address_lo = readl(entry->mask_base + offset_lo);
>  
> -		address.lo_address.value = readl(entry->mask_base + offset);
> -		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
> -		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
> -									MSI_TARGET_CPU_SHIFT);
> -		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
> -		writel(address.lo_address.value, entry->mask_base + offset);
> +		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
> +
> +		writel(address_hi, entry->mask_base + offset_hi);
> +		writel(address_lo, entry->mask_base + offset_lo);
>  		set_native_irq_info(irq, cpu_mask);
>  		break;
>  	}
> @@ -249,30 +264,6 @@
>  	.set_affinity	= set_msi_irq_affinity
>  };
>  
> -static void msi_data_init(struct msg_data *msi_data,
> -			  unsigned int vector)
> -{
> -	memset(msi_data, 0, sizeof(struct msg_data));
> -	msi_data->vector = (u8)vector;
> -	msi_data->delivery_mode = MSI_DELIVERY_MODE;
> -	msi_data->level = MSI_LEVEL_MODE;
> -	msi_data->trigger = MSI_TRIGGER_MODE;
> -}
> -
> -static void msi_address_init(struct msg_address *msi_address)
> -{
> -	unsigned int	dest_id;
> -	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
> -
> -	memset(msi_address, 0, sizeof(struct msg_address));
> -	msi_address->hi_address = (u32)0;
> -	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
> -	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
> -	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
> -	msi_address->lo_address.u.dest_id = dest_id;
> -	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
> -}
> -
>  static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
>  static int assign_msi_vector(void)
>  {
> @@ -367,6 +358,20 @@
>  		return status;
>  	}
>  
> +	if ((status = msi_arch_init()) < 0) {
> +		pci_msi_enable = 0;
> +		printk(KERN_WARNING
> +		       "PCI: MSI arch init failed.  MSI disabled.\n");
> +		return status;
> +	}
> +
> +	if (! msi_ops) {
> +		printk(KERN_WARNING
> +		       "PCI: MSI ops not registered. MSI disabled.\n");
> +		status = -EINVAL;
> +		return status;
> +	}
> +
>  	if ((status = msi_cache_init()) < 0) {
>  		pci_msi_enable = 0;
>  		printk(KERN_WARNING "PCI: MSI cache init failed\n");
> @@ -510,9 +515,11 @@
>   **/
>  static int msi_capability_init(struct pci_dev *dev)
>  {
> +	int status;
>  	struct msi_desc *entry;
> -	struct msg_address address;
> -	struct msg_data data;
> +	u32 address_lo;
> +	u32 address_hi;
> +	u32 data;
>  	int pos, vector;
>  	u16 control;
>  
> @@ -539,23 +546,26 @@
>  		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
>  				is_64bit_address(control));
>  	}
> +	/* Configure MSI capability structure */
> +	status = msi_ops->setup(dev, vector,
> +				&address_hi,
> +				&address_lo,
> +				&data);
> +	if (status < 0) {
> +		kmem_cache_free(msi_cachep, entry);
> +		return status;
> +	}
>  	/* Replace with MSI handler */
>  	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
> -	/* Configure MSI capability structure */
> -	msi_address_init(&address);
> -	msi_data_init(&data, vector);
> -	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
> -				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
> -	pci_write_config_dword(dev, msi_lower_address_reg(pos),
> -			address.lo_address.value);
> +
> +	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
>  	if (is_64bit_address(control)) {
>  		pci_write_config_dword(dev,
> -			msi_upper_address_reg(pos), address.hi_address);
> -		pci_write_config_word(dev,
> -			msi_data_reg(pos, 1), *((u32*)&data));
> +			msi_upper_address_reg(pos), address_hi);
> +		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
>  	} else
> -		pci_write_config_word(dev,
> -			msi_data_reg(pos, 0), *((u32*)&data));
> +		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
> +
>  	if (entry->msi_attrib.maskbit) {
>  		unsigned int maskbits, temp;
>  		/* All MSIs are unmasked by default, Mask them all */
> @@ -590,13 +600,15 @@
>  				struct msix_entry *entries, int nvec)
>  {
>  	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
> -	struct msg_address address;
> -	struct msg_data data;
> +	u32 address_hi;
> +	u32 address_lo;
> +	u32 data;
>  	int vector, pos, i, j, nr_entries, temp = 0;
>  	u32 phys_addr, table_offset;
>   	u16 control;
>  	u8 bir;
>  	void __iomem *base;
> +	int status;
>  
>     	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
>  	/* Request & Map MSI-X table region */
> @@ -643,18 +655,20 @@
>  		/* Replace with MSI-X handler */
>  		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
>  		/* Configure MSI-X capability structure */
> -		msi_address_init(&address);
> -		msi_data_init(&data, vector);
> -		entry->msi_attrib.current_cpu =
> -			((address.lo_address.u.dest_id >>
> -			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
> -		writel(address.lo_address.value,
> +		status = msi_ops->setup(dev, vector,
> +					&address_hi,
> +					&address_lo,
> +					&data);
> +		if (status < 0)
> +			break;
> +
> +		writel(address_lo,
>  			base + j * PCI_MSIX_ENTRY_SIZE +
>  			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
> -		writel(address.hi_address,
> +		writel(address_hi,
>  			base + j * PCI_MSIX_ENTRY_SIZE +
>  			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
> -		writel(*(u32*)&data,
> +		writel(data,
>  			base + j * PCI_MSIX_ENTRY_SIZE +
>  			PCI_MSIX_ENTRY_DATA_OFFSET);
>  		attach_msi_entry(entry, vector);
> @@ -789,6 +803,8 @@
>  	void __iomem *base;
>  	unsigned long flags;
>  
> +	msi_ops->teardown(vector);
> +
>  	spin_lock_irqsave(&msi_lock, flags);
>  	entry = msi_desc[vector];
>  	if (!entry || entry->dev != dev) {
> Index: linux-maule/include/asm-i386/msi.h
> ===================================================================
> --- linux-maule.orig/include/asm-i386/msi.h	2006-01-10 11:47:42.000000000 -0800
> +++ linux-maule/include/asm-i386/msi.h	2006-01-10 11:58:55.000000000 -0800
> @@ -12,4 +12,11 @@
>  #define LAST_DEVICE_VECTOR		232
>  #define MSI_TARGET_CPU_SHIFT	12
>  
> +static inline int msi_arch_init(void)
> +{
> +	extern struct msi_ops msi_apic_ops;
> +	msi_register(&msi_apic_ops);
> +	return 0;
> +}

Don't have an extern in a function, it belongs in a .h file somewhere
that describes it and everyone can see it.  Otherwise this gets stale
and messy over time.

> +/*
> + * Generic callouts used on most archs/platforms.  Override with
> + * msi_register_callouts()
> + */

Care to use kerneldoc here and define exactly what is needed for these
function pointers?  And you are still calling them "callouts" here :)

> +struct msi_ops msi_apic_ops = {
> +	.setup = msi_setup_apic,
> +	.teardown = msi_teardown_apic,
> +#ifdef CONFIG_SMP
> +	.target = msi_target_apic,
> +#endif

Why the #ifdef?  Just drop it, it makes the code cleaner.

Care to redo this?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/3] msi vector targeting abstractions
  2006-01-11 15:52 [PATCH 0/3] msi abstractions and support for altix Mark Maule
@ 2006-01-11 15:52 ` Mark Maule
  2006-01-11 20:21   ` Greg KH
  2006-01-12  5:02   ` Grant Grundler
  0 siblings, 2 replies; 38+ messages in thread
From: Mark Maule @ 2006-01-11 15:52 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: Tony Luck, gregkh, Mark Maule

Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: linux-maule/drivers/pci/msi.c
===================================================================
--- linux-maule.orig/drivers/pci/msi.c	2006-01-10 11:48:01.000000000 -0800
+++ linux-maule/drivers/pci/msi.c	2006-01-10 13:40:45.000000000 -0800
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
    		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -249,30 +264,6 @@
 	.set_affinity	= set_msi_irq_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -367,6 +358,20 @@
 		return status;
 	}
 
+	if ((status = msi_arch_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -510,9 +515,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -539,23 +546,26 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -590,13 +600,15 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_hi;
+	u32 address_lo;
+	u32 data;
 	int vector, pos, i, j, nr_entries, temp = 0;
 	u32 phys_addr, table_offset;
  	u16 control;
 	u8 bir;
 	void __iomem *base;
+	int status;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	/* Request & Map MSI-X table region */
@@ -643,18 +655,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -789,6 +803,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: linux-maule/include/asm-i386/msi.h
===================================================================
--- linux-maule.orig/include/asm-i386/msi.h	2006-01-10 11:47:42.000000000 -0800
+++ linux-maule/include/asm-i386/msi.h	2006-01-10 11:58:55.000000000 -0800
@@ -12,4 +12,11 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+static inline int msi_arch_init(void)
+{
+	extern struct msi_ops msi_apic_ops;
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-maule/include/asm-x86_64/msi.h
===================================================================
--- linux-maule.orig/include/asm-x86_64/msi.h	2006-01-10 11:47:43.000000000 -0800
+++ linux-maule/include/asm-x86_64/msi.h	2006-01-10 11:58:55.000000000 -0800
@@ -13,4 +13,11 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+static inline int msi_arch_init(void)
+{
+	extern struct msi_ops msi_apic_ops;
+	msi_register_apic(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: linux-maule/include/asm-ia64/machvec.h
===================================================================
--- linux-maule.orig/include/asm-ia64/machvec.h	2006-01-10 11:47:42.000000000 -0800
+++ linux-maule/include/asm-ia64/machvec.h	2006-01-10 12:59:09.000000000 -0800
@@ -74,6 +74,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -146,6 +147,7 @@
 #  define platform_readw_relaxed        ia64_mv.readw_relaxed
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
+#  define platform_msi_init	ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -194,6 +196,7 @@
 	ia64_mv_readw_relaxed_t *readw_relaxed;
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -238,6 +241,7 @@
 	platform_readw_relaxed,			\
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -386,5 +390,8 @@
 #ifndef platform_readq_relaxed
 # define platform_readq_relaxed	__ia64_readq_relaxed
 #endif
+#ifndef platform_msi_init
+# define platform_msi_init	ia64_msi_init
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: linux-maule/include/asm-ia64/machvec_sn2.h
===================================================================
--- linux-maule.orig/include/asm-ia64/machvec_sn2.h	2006-01-10 11:47:42.000000000 -0800
+++ linux-maule/include/asm-ia64/machvec_sn2.h	2006-01-10 11:58:56.000000000 -0800
@@ -71,6 +71,7 @@
 extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
+extern ia64_mv_msi_init_t		sn_msi_init;
 
 /*
  * This stuff has dual use!
@@ -120,6 +121,7 @@
 #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
+#define platform_msi_init		sn_msi_init
 
 #include <asm/sn/io.h>
 
Index: linux-maule/include/asm-ia64/msi.h
===================================================================
--- linux-maule.orig/include/asm-ia64/msi.h	2006-01-10 11:47:42.000000000 -0800
+++ linux-maule/include/asm-ia64/msi.h	2006-01-10 13:02:00.000000000 -0800
@@ -14,4 +14,14 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+/* default ia64 msi init routine */
+static inline int ia64_msi_init(void)
+{
+	extern struct msi_ops msi_apic_ops;
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
+#define msi_arch_init		platform_msi_init
+
 #endif /* ASM_MSI_H */
Index: linux-maule/arch/ia64/sn/pci/Makefile
===================================================================
--- linux-maule.orig/arch/ia64/sn/pci/Makefile	2006-01-10 11:47:31.000000000 -0800
+++ linux-maule/arch/ia64/sn/pci/Makefile	2006-01-10 11:58:56.000000000 -0800
@@ -3,8 +3,9 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (C) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
 #
 # Makefile for the sn pci general routines.
 
 obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
+obj-$(CONFIG_PCI_MSI) += msi.o
Index: linux-maule/arch/ia64/sn/pci/msi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-maule/arch/ia64/sn/pci/msi.c	2006-01-10 13:40:40.000000000 -0800
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}
Index: linux-maule/drivers/pci/Makefile
===================================================================
--- linux-maule.orig/drivers/pci/Makefile	2006-01-10 11:48:01.000000000 -0800
+++ linux-maule/drivers/pci/Makefile	2006-01-10 11:58:56.000000000 -0800
@@ -26,7 +26,7 @@
 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
+obj-$(CONFIG_PCI_MSI) += msi.o msi-apic.o
 
 #
 # ACPI Related PCI FW Functions
Index: linux-maule/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-maule/drivers/pci/msi-apic.c	2006-01-10 11:58:56.000000000 -0800
@@ -0,0 +1,102 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic callouts used on most archs/platforms.  Override with
+ * msi_register_callouts()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+#ifdef CONFIG_SMP
+	.target = msi_target_apic,
+#endif
+};
Index: linux-maule/drivers/pci/msi.h
===================================================================
--- linux-maule.orig/drivers/pci/msi.h	2006-01-10 11:48:01.000000000 -0800
+++ linux-maule/drivers/pci/msi.h	2006-01-10 11:58:56.000000000 -0800
@@ -69,67 +69,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -138,7 +77,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: linux-maule/include/linux/pci.h
===================================================================
--- linux-maule.orig/include/linux/pci.h	2006-01-10 11:47:46.000000000 -0800
+++ linux-maule/include/linux/pci.h	2006-01-10 11:58:56.000000000 -0800
@@ -478,6 +478,16 @@
 	u16	entry;	/* driver uses to specify entry, OS writes */
 };
 
+struct msi_ops {
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+	void	(*teardown) (unsigned int vector);
+#ifdef CONFIG_SMP
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+#endif
+};
+
 #ifndef CONFIG_PCI_MSI
 static inline void pci_scan_msi_device(struct pci_dev *dev) {}
 static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
@@ -486,6 +496,7 @@
 	struct msix_entry *entries, int nvec) {return -1;}
 static inline void pci_disable_msix(struct pci_dev *dev) {}
 static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+static inline int msi_register(struct msi_ops *ops) {return -1;}
 #else
 extern void pci_scan_msi_device(struct pci_dev *dev);
 extern int pci_enable_msi(struct pci_dev *dev);
@@ -494,6 +505,7 @@
 	struct msix_entry *entries, int nvec);
 extern void pci_disable_msix(struct pci_dev *dev);
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+extern int msi_register(struct msi_ops *ops);
 #endif
 
 extern void pci_block_user_cfg_access(struct pci_dev *dev);

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-04  0:27         ` Greg KH
@ 2006-01-04  3:52           ` Mark Maule
  0 siblings, 0 replies; 38+ messages in thread
From: Mark Maule @ 2006-01-04  3:52 UTC (permalink / raw)
  To: Greg KH
  Cc: Grant Grundler, linuxppc64-dev, linux-pci, linux-ia64,
	linux-kernel, Tony Luck

On Tue, Jan 03, 2006 at 04:27:38PM -0800, Greg KH wrote:
> On Tue, Jan 03, 2006 at 04:20:47PM -0800, Grant Grundler wrote:
> > On Tue, Jan 03, 2006 at 05:50:24PM -0600, Mark Maule wrote:
> > > > > +struct msi_ops msi_apic_ops = {
> > > > > +	.setup = msi_setup_apic,
> > > > > +	.teardown = msi_teardown_apic,
> > > > > +#ifdef CONFIG_SMP
> > > > > +	.target = msi_target_apic,
> > > > > +#endif
> > > > 
> > > > Mark,
> > > > msi_target_apic() initializes address_lo parameter.
> > > > Even on a UP machine, we need inialize this value.
> > > 
> > > Not sure what you mean here.  target is used to retarget an existing
> > > MSI vector to a different processor.
> > 
> > Right - I didn't realize the caller, set_msi_affinity(), was surrounded by
> > "#ifdef CONFIG_SMP".
> > 
> > But set_msi_affinity() appears to be dead code.
> > I couldn't find any calls to set_msi_affinity() in 2.6.14 or 2.6.15.
> > Greg, you want a patch to remove that?
> 
> Yes please, that would be great to have.
> 
> thanks,
> 
> greg k-h

Is that really dead code?  From msi.h:

#ifdef CONFIG_SMP
#define set_msi_irq_affinity    set_msi_affinity
#else
#define set_msi_irq_affinity    NULL
#endif

Mark

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-04  0:20       ` Grant Grundler
@ 2006-01-04  0:27         ` Greg KH
  2006-01-04  3:52           ` Mark Maule
  0 siblings, 1 reply; 38+ messages in thread
From: Greg KH @ 2006-01-04  0:27 UTC (permalink / raw)
  To: Grant Grundler
  Cc: Mark Maule, linuxppc64-dev, linux-pci, linux-ia64, linux-kernel,
	Tony Luck

On Tue, Jan 03, 2006 at 04:20:47PM -0800, Grant Grundler wrote:
> On Tue, Jan 03, 2006 at 05:50:24PM -0600, Mark Maule wrote:
> > > > +struct msi_ops msi_apic_ops = {
> > > > +	.setup = msi_setup_apic,
> > > > +	.teardown = msi_teardown_apic,
> > > > +#ifdef CONFIG_SMP
> > > > +	.target = msi_target_apic,
> > > > +#endif
> > > 
> > > Mark,
> > > msi_target_apic() initializes address_lo parameter.
> > > Even on a UP machine, we need inialize this value.
> > 
> > Not sure what you mean here.  target is used to retarget an existing
> > MSI vector to a different processor.
> 
> Right - I didn't realize the caller, set_msi_affinity(), was surrounded by
> "#ifdef CONFIG_SMP".
> 
> But set_msi_affinity() appears to be dead code.
> I couldn't find any calls to set_msi_affinity() in 2.6.14 or 2.6.15.
> Greg, you want a patch to remove that?

Yes please, that would be great to have.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-03 23:50     ` Mark Maule
@ 2006-01-04  0:20       ` Grant Grundler
  2006-01-04  0:27         ` Greg KH
  0 siblings, 1 reply; 38+ messages in thread
From: Grant Grundler @ 2006-01-04  0:20 UTC (permalink / raw)
  To: Mark Maule
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

On Tue, Jan 03, 2006 at 05:50:24PM -0600, Mark Maule wrote:
> > > +struct msi_ops msi_apic_ops = {
> > > +	.setup = msi_setup_apic,
> > > +	.teardown = msi_teardown_apic,
> > > +#ifdef CONFIG_SMP
> > > +	.target = msi_target_apic,
> > > +#endif
> > 
> > Mark,
> > msi_target_apic() initializes address_lo parameter.
> > Even on a UP machine, we need inialize this value.
> 
> Not sure what you mean here.  target is used to retarget an existing
> MSI vector to a different processor.

Right - I didn't realize the caller, set_msi_affinity(), was surrounded by
"#ifdef CONFIG_SMP".

But set_msi_affinity() appears to be dead code.
I couldn't find any calls to set_msi_affinity() in 2.6.14 or 2.6.15.
Greg, you want a patch to remove that?

thanks,
grant

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2006-01-03 22:39   ` Grant Grundler
@ 2006-01-03 23:50     ` Mark Maule
  2006-01-04  0:20       ` Grant Grundler
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2006-01-03 23:50 UTC (permalink / raw)
  To: Grant Grundler
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

On Tue, Jan 03, 2006 at 02:39:18PM -0800, Grant Grundler wrote:
> On Thu, Dec 22, 2005 at 02:15:49PM -0600, Mark Maule wrote:
> > Abstract portions of the MSI core for platforms that do not use standard
> > APIC interrupt controllers.  This is implemented through a new arch-specific
> > msi setup routine, and a set of msi ops which can be set on a per platform
> > basis.
> 
> ...
> > +
> > +		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
> > +
> > +		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
> > +			address_hi);
> >  		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
> > -			address.lo_address.value);
> > +			address_lo);
> >  		set_native_irq_info(irq, cpu_mask);
> >  		break;
> >  	}
> ...
> > --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> > +++ msi/drivers/pci/msi-apic.c	2005-12-22 11:09:37.022232088 -0600
> ...
> > +struct msi_ops msi_apic_ops = {
> > +	.setup = msi_setup_apic,
> > +	.teardown = msi_teardown_apic,
> > +#ifdef CONFIG_SMP
> > +	.target = msi_target_apic,
> > +#endif
> 
> Mark,
> msi_target_apic() initializes address_lo parameter.
> Even on a UP machine, we need inialize this value.

Not sure what you mean here.  target is used to retarget an existing MSI vector
to a different processor.  In the case of apic, this appears to be accomplished
by swizzling the cpu in the low 32 bits of the msi address.  Nothing needs to
change in the upper 32 bits.

> 
> If target is called unconditionally, wouldn't it be better
> for msi_target_apic() always be called?

target is called through the msi_ops->target vector.  SN does not use
msi_target_apic(), it uses sn_msi_target().  Other platforms can implement
target however they need to.

> 
> It would also be good for msi_target_apic to validate the 'dest_cpu' is online.
> Maybe a BUG_ON or something like that.

That wasn't a check in the original code flow ... the main protection appears
to be in the upper levels in irq_affinity_write_proc().

> 
> grant
> 
> ps. not done looking through this...and still curious to see where
>     other discussion about generic vector assignment leads.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2005-12-22 20:15 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
@ 2006-01-03 22:39   ` Grant Grundler
  2006-01-03 23:50     ` Mark Maule
  0 siblings, 1 reply; 38+ messages in thread
From: Grant Grundler @ 2006-01-03 22:39 UTC (permalink / raw)
  To: Mark Maule
  Cc: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel, Tony Luck, gregkh

On Thu, Dec 22, 2005 at 02:15:49PM -0600, Mark Maule wrote:
> Abstract portions of the MSI core for platforms that do not use standard
> APIC interrupt controllers.  This is implemented through a new arch-specific
> msi setup routine, and a set of msi ops which can be set on a per platform
> basis.

...
> +
> +		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
> +
> +		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
> +			address_hi);
>  		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
> -			address.lo_address.value);
> +			address_lo);
>  		set_native_irq_info(irq, cpu_mask);
>  		break;
>  	}
...
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ msi/drivers/pci/msi-apic.c	2005-12-22 11:09:37.022232088 -0600
...
> +struct msi_ops msi_apic_ops = {
> +	.setup = msi_setup_apic,
> +	.teardown = msi_teardown_apic,
> +#ifdef CONFIG_SMP
> +	.target = msi_target_apic,
> +#endif

Mark,
msi_target_apic() initializes address_lo parameter.
Even on a UP machine, we need inialize this value.

If target is called unconditionally, wouldn't it be better
for msi_target_apic() always be called?

It would also be good for msi_target_apic to validate the 'dest_cpu' is online.
Maybe a BUG_ON or something like that.

grant

ps. not done looking through this...and still curious to see where
    other discussion about generic vector assignment leads.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2005-12-22 20:09     ` Mark Maule
@ 2005-12-22 20:19       ` Greg KH
  0 siblings, 0 replies; 38+ messages in thread
From: Greg KH @ 2005-12-22 20:19 UTC (permalink / raw)
  To: Mark Maule; +Cc: linux-ia64, linux-kernel, Tony Luck

On Thu, Dec 22, 2005 at 02:09:16PM -0600, Mark Maule wrote:
> On Thu, Dec 22, 2005 at 11:58:14AM -0800, Greg KH wrote:
> > On Thu, Dec 22, 2005 at 11:15:13AM -0600, Mark Maule wrote:
> > > Abstract portions of the MSI core for platforms that do not use standard
> > > APIC interrupt controllers.  This is implemented through a new arch-specific
> > > msi setup routine, and a set of msi ops which can be set on a per platform
> > > basis.
> > > 
> > > Signed-off-by: Mark Maule <maule@sgi.com>
> > 
> > Hm, care to CC: the linux-pci and pci maintainer next time?  And you
> > also might want to run this by the original MSI authors...
> 
> I did run an early version of the patches across the original MSI authors, but
> much has changed since then.

Then why would you want to keep them out of the loop now, after much
change?  :)

> I didn't realize that there were lists other than linux-kernel and linux-ia64
> that needed to be cross posted, so my bad.  I'll resend with those additional
> lists.

Thanks, I appreciate it.

greg k-h

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/3] msi vector targeting abstractions
  2005-12-22 20:15 [PATCH 0/3] msi abstractions and support for altix Mark Maule
@ 2005-12-22 20:15 ` Mark Maule
  2006-01-03 22:39   ` Grant Grundler
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2005-12-22 20:15 UTC (permalink / raw)
  To: linuxppc64-dev, linux-pci, linux-ia64, linux-kernel
  Cc: Tony Luck, gregkh, Mark Maule

Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: msi/drivers/pci/msi.c
===================================================================
--- msi.orig/drivers/pci/msi.c	2005-12-13 12:22:42.784269607 -0600
+++ msi/drivers/pci/msi.c	2005-12-21 22:59:09.200800164 -0600
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
    		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -249,30 +264,6 @@
 	.set_affinity	= set_msi_irq_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -367,6 +358,20 @@
 		return status;
 	}
 
+	if ((status = msi_arch_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -510,9 +515,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -539,23 +546,26 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -590,13 +600,15 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_hi;
+	u32 address_lo;
+	u32 data;
 	int vector, pos, i, j, nr_entries, temp = 0;
 	u32 phys_addr, table_offset;
  	u16 control;
 	u8 bir;
 	void __iomem *base;
+	int status;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	/* Request & Map MSI-X table region */
@@ -643,18 +655,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -789,6 +803,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: msi/include/asm-i386/msi.h
===================================================================
--- msi.orig/include/asm-i386/msi.h	2005-12-13 12:22:42.785246074 -0600
+++ msi/include/asm-i386/msi.h	2005-12-21 23:18:10.602753071 -0600
@@ -12,4 +12,11 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+static inline int msi_arch_init(void)
+{
+	extern struct msi_ops msi_apic_ops;
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: msi/include/asm-x86_64/msi.h
===================================================================
--- msi.orig/include/asm-x86_64/msi.h	2005-12-13 12:22:42.786222541 -0600
+++ msi/include/asm-x86_64/msi.h	2005-12-21 23:18:20.733573956 -0600
@@ -13,4 +13,11 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+static inline int msi_arch_init(void)
+{
+	extern struct msi_ops msi_apic_ops;
+	msi_register_apic(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: msi/include/asm-ia64/machvec.h
===================================================================
--- msi.orig/include/asm-ia64/machvec.h	2005-12-13 12:22:42.786222541 -0600
+++ msi/include/asm-ia64/machvec.h	2005-12-21 23:18:32.231445414 -0600
@@ -74,6 +74,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -146,6 +147,7 @@
 #  define platform_readw_relaxed        ia64_mv.readw_relaxed
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
+#  define platform_msi_init	ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -194,6 +196,7 @@
 	ia64_mv_readw_relaxed_t *readw_relaxed;
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -238,6 +241,7 @@
 	platform_readw_relaxed,			\
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -386,5 +390,9 @@
 #ifndef platform_readq_relaxed
 # define platform_readq_relaxed	__ia64_readq_relaxed
 #endif
+#ifndef platform_msi_init
+# define platform_msi_init	{ extern struct msi_ops msi_apic_ops; \
+				  msi_register(&msi_apic_ops); return 0; }
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: msi/include/asm-ia64/machvec_sn2.h
===================================================================
--- msi.orig/include/asm-ia64/machvec_sn2.h	2005-12-13 12:22:42.787199008 -0600
+++ msi/include/asm-ia64/machvec_sn2.h	2005-12-13 16:09:49.257035213 -0600
@@ -71,6 +71,7 @@
 extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
+extern ia64_mv_msi_init_t		sn_msi_init;
 
 /*
  * This stuff has dual use!
@@ -120,6 +121,7 @@
 #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
+#define platform_msi_init		sn_msi_init
 
 #include <asm/sn/io.h>
 
Index: msi/include/asm-ia64/msi.h
===================================================================
--- msi.orig/include/asm-ia64/msi.h	2005-12-13 12:22:42.787199008 -0600
+++ msi/include/asm-ia64/msi.h	2005-12-13 16:09:49.268752815 -0600
@@ -14,4 +14,6 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+static inline int msi_arch_init(void)	{ return platform_msi_init(); }
+
 #endif /* ASM_MSI_H */
Index: msi/arch/ia64/sn/pci/Makefile
===================================================================
--- msi.orig/arch/ia64/sn/pci/Makefile	2005-12-13 12:22:42.788175474 -0600
+++ msi/arch/ia64/sn/pci/Makefile	2005-12-13 16:09:49.296093887 -0600
@@ -3,8 +3,9 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (C) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
 #
 # Makefile for the sn pci general routines.
 
 obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
+obj-$(CONFIG_PCI_MSI) += msi.o
Index: msi/arch/ia64/sn/pci/msi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ msi/arch/ia64/sn/pci/msi.c	2005-12-21 22:59:02.713172526 -0600
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}
Index: msi/drivers/pci/Makefile
===================================================================
--- msi.orig/drivers/pci/Makefile	2005-12-21 16:08:58.222841575 -0600
+++ msi/drivers/pci/Makefile	2005-12-21 16:10:32.848440390 -0600
@@ -23,7 +23,7 @@
 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
+obj-$(CONFIG_PCI_MSI) += msi.o msi-apic.o
 
 #
 # ACPI Related PCI FW Functions
Index: msi/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ msi/drivers/pci/msi-apic.c	2005-12-22 11:09:37.022232088 -0600
@@ -0,0 +1,102 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic callouts used on most archs/platforms.  Override with
+ * msi_register_callouts()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+#ifdef CONFIG_SMP
+	.target = msi_target_apic,
+#endif
+};
Index: msi/drivers/pci/msi.h
===================================================================
--- msi.orig/drivers/pci/msi.h	2005-12-21 16:08:58.222841575 -0600
+++ msi/drivers/pci/msi.h	2005-12-21 23:06:48.292305590 -0600
@@ -69,67 +69,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -138,7 +77,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: msi/include/linux/pci.h
===================================================================
--- msi.orig/include/linux/pci.h	2005-12-21 16:08:58.223818043 -0600
+++ msi/include/linux/pci.h	2005-12-21 16:10:32.847463922 -0600
@@ -478,6 +478,16 @@
 	u16	entry;	/* driver uses to specify entry, OS writes */
 };
 
+struct msi_ops {
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+	void	(*teardown) (unsigned int vector);
+#ifdef CONFIG_SMP
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+#endif
+};
+
 #ifndef CONFIG_PCI_MSI
 static inline void pci_scan_msi_device(struct pci_dev *dev) {}
 static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
@@ -486,6 +496,7 @@
 	struct msix_entry *entries, int nvec) {return -1;}
 static inline void pci_disable_msix(struct pci_dev *dev) {}
 static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+static inline int msi_register(struct msi_ops *ops) {return -1;}
 #else
 extern void pci_scan_msi_device(struct pci_dev *dev);
 extern int pci_enable_msi(struct pci_dev *dev);
@@ -494,6 +505,7 @@
 	struct msix_entry *entries, int nvec);
 extern void pci_disable_msix(struct pci_dev *dev);
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+extern int msi_register(struct msi_ops *ops);
 #endif
 
 extern void pci_block_user_cfg_access(struct pci_dev *dev);

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2005-12-22 19:58   ` Greg KH
@ 2005-12-22 20:09     ` Mark Maule
  2005-12-22 20:19       ` Greg KH
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2005-12-22 20:09 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-ia64, linux-kernel, Tony Luck

On Thu, Dec 22, 2005 at 11:58:14AM -0800, Greg KH wrote:
> On Thu, Dec 22, 2005 at 11:15:13AM -0600, Mark Maule wrote:
> > Abstract portions of the MSI core for platforms that do not use standard
> > APIC interrupt controllers.  This is implemented through a new arch-specific
> > msi setup routine, and a set of msi ops which can be set on a per platform
> > basis.
> > 
> > Signed-off-by: Mark Maule <maule@sgi.com>
> 
> Hm, care to CC: the linux-pci and pci maintainer next time?  And you
> also might want to run this by the original MSI authors...

I did run an early version of the patches across the original MSI authors, but
much has changed since then.

I didn't realize that there were lists other than linux-kernel and linux-ia64
that needed to be cross posted, so my bad.  I'll resend with those additional
lists.

Mark

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/3] msi vector targeting abstractions
  2005-12-22 17:15 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
@ 2005-12-22 19:58   ` Greg KH
  2005-12-22 20:09     ` Mark Maule
  0 siblings, 1 reply; 38+ messages in thread
From: Greg KH @ 2005-12-22 19:58 UTC (permalink / raw)
  To: Mark Maule; +Cc: linux-ia64, linux-kernel, Tony Luck

On Thu, Dec 22, 2005 at 11:15:13AM -0600, Mark Maule wrote:
> Abstract portions of the MSI core for platforms that do not use standard
> APIC interrupt controllers.  This is implemented through a new arch-specific
> msi setup routine, and a set of msi ops which can be set on a per platform
> basis.
> 
> Signed-off-by: Mark Maule <maule@sgi.com>

Hm, care to CC: the linux-pci and pci maintainer next time?  And you
also might want to run this by the original MSI authors...

And you might want to cc: the ppc64 developers, as they are looking into
how to add MSI support to their platform, and are doing much of this
same "make MSI be more arch neutral" work.  They need to agree with
these changes before I can accept them.

> --- msi.orig/drivers/pci/msi.c	2005-12-13 12:22:42.784269607 -0600
> +++ msi/drivers/pci/msi.c	2005-12-21 22:59:09.200800164 -0600
> @@ -23,8 +23,6 @@
>  #include "pci.h"
>  #include "msi.h"
>  
> -#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
> -
>  static DEFINE_SPINLOCK(msi_lock);
>  static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
>  static kmem_cache_t* msi_cachep;
> @@ -40,6 +38,15 @@
>  u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
>  #endif
>  
> +static struct msi_ops *msi_ops;
> +
> +int
> +msi_register(struct msi_ops *ops)

Please put the return type on the same line as the function, especially
as the rest of the pci code is this way...

> +{
> +	msi_ops = ops;
> +	return 0;

Why return anything as this will always succeed?  Just make it a void
function please.

> @@ -367,6 +358,20 @@
>  		return status;
>  	}
>  
> +	if ((status = msi_arch_init()) < 0) {
> +		pci_msi_enable = 0;
> +		printk(KERN_WARNING
> +		       "PCI: MSI arch init failed.  MSI disabled.\n");
> +		return status;
> +	}
> +
> +	if (! msi_ops) {

No extra space after "!" please.

> ===================================================================
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ msi/drivers/pci/msi-apic.c	2005-12-22 11:09:37.022232088 -0600
> @@ -0,0 +1,102 @@
> +/*
> + * MSI hooks for standard x86 apic
> + */

No copyright notice?  People to blame/authors names?

> +#include <linux/pci.h>
> +
> +#include "msi.h"
> +
> +/*
> + * Shifts for APIC-based data
> + */
> +
> +#define MSI_DATA_VECTOR_SHIFT		0
> +#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
> +
> +#define MSI_DATA_DELIVERY_SHIFT		8
> +#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
> +#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
> +
> +#define MSI_DATA_LEVEL_SHIFT		14
> +#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
> +#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
> +
> +#define MSI_DATA_TRIGGER_SHIFT		15
> +#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
> +#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
> +
> +/*
> + * Shift/mask fields for APIC-based bus address
> + */
> +
> +#define MSI_ADDR_HEADER			0xfee00000
> +
> +#define MSI_ADDR_DESTID_MASK		0xfff0000f
> +#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
> +
> +#define MSI_ADDR_DESTMODE_SHIFT		2
> +#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
> +#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
> +
> +#define MSI_ADDR_REDIRECTION_SHIFT	3
> +#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
> +#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
> +
> +
> +static void
> +msi_target_apic(unsigned int vector,
> +		unsigned int dest_cpu,
> +		u32 *address_hi,	/* in/out */
> +		u32 *address_lo)	/* in/out */

Please put this on one line, like mentioned above (within line limits).
If you want to comment the parameters, do it in the proper kerneldoc
way.

> +struct msi_ops msi_apic_ops = {
> +	.setup = msi_setup_apic,
> +	.teardown = msi_teardown_apic,
> +#ifdef CONFIG_SMP
> +	.target = msi_target_apic,
> +#endif

Why ifdef this for SMP?

>  struct msi_desc {
>  	struct {
>  		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
> @@ -138,7 +77,7 @@
>  		__u8	reserved: 1; 	/* reserved			  */
>  		__u8	entry_nr;    	/* specific enabled entry 	  */
>  		__u8	default_vector; /* default pre-assigned vector    */
> -		__u8	current_cpu; 	/* current destination cpu	  */
> +		__u8	unused; 	/* formerly unused destination cpu*/

Can't you just remove this?  Or where does this structure come from?

> +struct msi_ops {

pci_msi_ops?  As you have seen, there are other uses of "MSI" in the
kernel :)

> +	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
> +			     u32 *addr_hi, u32 *addr_lo, u32 *data);
> +	void	(*teardown) (unsigned int vector);
> +#ifdef CONFIG_SMP
> +	void	(*target)   (unsigned int vector, unsigned int cpu,
> +			     u32 *addr_hi, u32 *addr_lo);
> +#endif

Again, why the ifdef here?

> +};
> +
>  #ifndef CONFIG_PCI_MSI
>  static inline void pci_scan_msi_device(struct pci_dev *dev) {}
>  static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
> @@ -486,6 +496,7 @@
>  	struct msix_entry *entries, int nvec) {return -1;}
>  static inline void pci_disable_msix(struct pci_dev *dev) {}
>  static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
> +static inline int msi_register(struct msi_ops *ops) {return -1;}

pci_msi_register() please.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/3] msi vector targeting abstractions
  2005-12-22 17:15 [PATCH 0/3] msi abstractions and support for altix Mark Maule
@ 2005-12-22 17:15 ` Mark Maule
  2005-12-22 19:58   ` Greg KH
  0 siblings, 1 reply; 38+ messages in thread
From: Mark Maule @ 2005-12-22 17:15 UTC (permalink / raw)
  To: linux-ia64, linux-kernel; +Cc: Tony Luck, Mark Maule

Abstract portions of the MSI core for platforms that do not use standard
APIC interrupt controllers.  This is implemented through a new arch-specific
msi setup routine, and a set of msi ops which can be set on a per platform
basis.

Signed-off-by: Mark Maule <maule@sgi.com>

Index: msi/drivers/pci/msi.c
===================================================================
--- msi.orig/drivers/pci/msi.c	2005-12-13 12:22:42.784269607 -0600
+++ msi/drivers/pci/msi.c	2005-12-21 22:59:09.200800164 -0600
@@ -23,8 +23,6 @@
 #include "pci.h"
 #include "msi.h"
 
-#define MSI_TARGET_CPU		first_cpu(cpu_online_map)
-
 static DEFINE_SPINLOCK(msi_lock);
 static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static kmem_cache_t* msi_cachep;
@@ -40,6 +38,15 @@
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 #endif
 
+static struct msi_ops *msi_ops;
+
+int
+msi_register(struct msi_ops *ops)
+{
+	msi_ops = ops;
+	return 0;
+}
+
 static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
 {
 	memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
@@ -92,7 +99,7 @@
 static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
 {
 	struct msi_desc *entry;
-	struct msg_address address;
+	u32 address_hi, address_lo;
 	unsigned int irq = vector;
 	unsigned int dest_cpu = first_cpu(cpu_mask);
 
@@ -108,28 +115,36 @@
    		if (!(pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI)))
 			return;
 
+		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
+			&address_hi);
 		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address.lo_address.value);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
+			&address_lo);
+
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
+			address_hi);
 		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+			address_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		int offset_hi =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
+		int offset_lo =
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+
+		address_hi = readl(entry->mask_base + offset_hi);
+		address_lo = readl(entry->mask_base + offset_lo);
 
-		address.lo_address.value = readl(entry->mask_base + offset);
-		address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK;
-		address.lo_address.value |= (cpu_physical_id(dest_cpu) <<
-									MSI_TARGET_CPU_SHIFT);
-		entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu);
-		writel(address.lo_address.value, entry->mask_base + offset);
+		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+
+		writel(address_hi, entry->mask_base + offset_hi);
+		writel(address_lo, entry->mask_base + offset_lo);
 		set_native_irq_info(irq, cpu_mask);
 		break;
 	}
@@ -249,30 +264,6 @@
 	.set_affinity	= set_msi_irq_affinity
 };
 
-static void msi_data_init(struct msg_data *msi_data,
-			  unsigned int vector)
-{
-	memset(msi_data, 0, sizeof(struct msg_data));
-	msi_data->vector = (u8)vector;
-	msi_data->delivery_mode = MSI_DELIVERY_MODE;
-	msi_data->level = MSI_LEVEL_MODE;
-	msi_data->trigger = MSI_TRIGGER_MODE;
-}
-
-static void msi_address_init(struct msg_address *msi_address)
-{
-	unsigned int	dest_id;
-	unsigned long	dest_phys_id = cpu_physical_id(MSI_TARGET_CPU);
-
-	memset(msi_address, 0, sizeof(struct msg_address));
-	msi_address->hi_address = (u32)0;
-	dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT);
-	msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE;
-	msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE;
-	msi_address->lo_address.u.dest_id = dest_id;
-	msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT);
-}
-
 static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
 static int assign_msi_vector(void)
 {
@@ -367,6 +358,20 @@
 		return status;
 	}
 
+	if ((status = msi_arch_init()) < 0) {
+		pci_msi_enable = 0;
+		printk(KERN_WARNING
+		       "PCI: MSI arch init failed.  MSI disabled.\n");
+		return status;
+	}
+
+	if (! msi_ops) {
+		printk(KERN_WARNING
+		       "PCI: MSI ops not registered. MSI disabled.\n");
+		status = -EINVAL;
+		return status;
+	}
+
 	if ((status = msi_cache_init()) < 0) {
 		pci_msi_enable = 0;
 		printk(KERN_WARNING "PCI: MSI cache init failed\n");
@@ -510,9 +515,11 @@
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
+	int status;
 	struct msi_desc *entry;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_lo;
+	u32 address_hi;
+	u32 data;
 	int pos, vector;
 	u16 control;
 
@@ -539,23 +546,26 @@
 		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
 				is_64bit_address(control));
 	}
+	/* Configure MSI capability structure */
+	status = msi_ops->setup(dev, vector,
+				&address_hi,
+				&address_lo,
+				&data);
+	if (status < 0) {
+		kmem_cache_free(msi_cachep, entry);
+		return status;
+	}
 	/* Replace with MSI handler */
 	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
-	/* Configure MSI capability structure */
-	msi_address_init(&address);
-	msi_data_init(&data, vector);
-	entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >>
-				MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-	pci_write_config_dword(dev, msi_lower_address_reg(pos),
-			address.lo_address.value);
+
+	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
 	if (is_64bit_address(control)) {
 		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address.hi_address);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), *((u32*)&data));
+			msi_upper_address_reg(pos), address_hi);
+		pci_write_config_word(dev, msi_data_reg(pos, 1), data);
 	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), *((u32*)&data));
+		pci_write_config_word(dev, msi_data_reg(pos, 0), data);
+
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -590,13 +600,15 @@
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	struct msg_address address;
-	struct msg_data data;
+	u32 address_hi;
+	u32 address_lo;
+	u32 data;
 	int vector, pos, i, j, nr_entries, temp = 0;
 	u32 phys_addr, table_offset;
  	u16 control;
 	u8 bir;
 	void __iomem *base;
+	int status;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
 	/* Request & Map MSI-X table region */
@@ -643,18 +655,20 @@
 		/* Replace with MSI-X handler */
 		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		msi_address_init(&address);
-		msi_data_init(&data, vector);
-		entry->msi_attrib.current_cpu =
-			((address.lo_address.u.dest_id >>
-			MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK);
-		writel(address.lo_address.value,
+		status = msi_ops->setup(dev, vector,
+					&address_hi,
+					&address_lo,
+					&data);
+		if (status < 0)
+			break;
+
+		writel(address_lo,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address.hi_address,
+		writel(address_hi,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(*(u32*)&data,
+		writel(data,
 			base + j * PCI_MSIX_ENTRY_SIZE +
 			PCI_MSIX_ENTRY_DATA_OFFSET);
 		attach_msi_entry(entry, vector);
@@ -789,6 +803,8 @@
 	void __iomem *base;
 	unsigned long flags;
 
+	msi_ops->teardown(vector);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[vector];
 	if (!entry || entry->dev != dev) {
Index: msi/include/asm-i386/msi.h
===================================================================
--- msi.orig/include/asm-i386/msi.h	2005-12-13 12:22:42.785246074 -0600
+++ msi/include/asm-i386/msi.h	2005-12-21 23:18:10.602753071 -0600
@@ -12,4 +12,11 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+static inline int msi_arch_init(void)
+{
+	extern struct msi_ops msi_apic_ops;
+	msi_register(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: msi/include/asm-x86_64/msi.h
===================================================================
--- msi.orig/include/asm-x86_64/msi.h	2005-12-13 12:22:42.786222541 -0600
+++ msi/include/asm-x86_64/msi.h	2005-12-21 23:18:20.733573956 -0600
@@ -13,4 +13,11 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_TARGET_CPU_SHIFT	12
 
+static inline int msi_arch_init(void)
+{
+	extern struct msi_ops msi_apic_ops;
+	msi_register_apic(&msi_apic_ops);
+	return 0;
+}
+
 #endif /* ASM_MSI_H */
Index: msi/include/asm-ia64/machvec.h
===================================================================
--- msi.orig/include/asm-ia64/machvec.h	2005-12-13 12:22:42.786222541 -0600
+++ msi/include/asm-ia64/machvec.h	2005-12-21 23:18:32.231445414 -0600
@@ -74,6 +74,7 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
+typedef int ia64_mv_msi_init_t (void);
 
 static inline void
 machvec_noop (void)
@@ -146,6 +147,7 @@
 #  define platform_readw_relaxed        ia64_mv.readw_relaxed
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
+#  define platform_msi_init	ia64_mv.msi_init
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -194,6 +196,7 @@
 	ia64_mv_readw_relaxed_t *readw_relaxed;
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
+	ia64_mv_msi_init_t *msi_init;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -238,6 +241,7 @@
 	platform_readw_relaxed,			\
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
+	platform_msi_init,			\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -386,5 +390,9 @@
 #ifndef platform_readq_relaxed
 # define platform_readq_relaxed	__ia64_readq_relaxed
 #endif
+#ifndef platform_msi_init
+# define platform_msi_init	{ extern struct msi_ops msi_apic_ops; \
+				  msi_register(&msi_apic_ops); return 0; }
+#endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
Index: msi/include/asm-ia64/machvec_sn2.h
===================================================================
--- msi.orig/include/asm-ia64/machvec_sn2.h	2005-12-13 12:22:42.787199008 -0600
+++ msi/include/asm-ia64/machvec_sn2.h	2005-12-13 16:09:49.257035213 -0600
@@ -71,6 +71,7 @@
 extern ia64_mv_dma_sync_sg_for_device	sn_dma_sync_sg_for_device;
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
+extern ia64_mv_msi_init_t		sn_msi_init;
 
 /*
  * This stuff has dual use!
@@ -120,6 +121,7 @@
 #define platform_dma_sync_sg_for_device	sn_dma_sync_sg_for_device
 #define platform_dma_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
+#define platform_msi_init		sn_msi_init
 
 #include <asm/sn/io.h>
 
Index: msi/include/asm-ia64/msi.h
===================================================================
--- msi.orig/include/asm-ia64/msi.h	2005-12-13 12:22:42.787199008 -0600
+++ msi/include/asm-ia64/msi.h	2005-12-13 16:09:49.268752815 -0600
@@ -14,4 +14,6 @@
 #define ack_APIC_irq		ia64_eoi
 #define MSI_TARGET_CPU_SHIFT	4
 
+static inline int msi_arch_init(void)	{ return platform_msi_init(); }
+
 #endif /* ASM_MSI_H */
Index: msi/arch/ia64/sn/pci/Makefile
===================================================================
--- msi.orig/arch/ia64/sn/pci/Makefile	2005-12-13 12:22:42.788175474 -0600
+++ msi/arch/ia64/sn/pci/Makefile	2005-12-13 16:09:49.296093887 -0600
@@ -3,8 +3,9 @@
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
+# Copyright (C) 2000-2005 Silicon Graphics, Inc.  All Rights Reserved.
 #
 # Makefile for the sn pci general routines.
 
 obj-y := pci_dma.o tioca_provider.o tioce_provider.o pcibr/
+obj-$(CONFIG_PCI_MSI) += msi.o
Index: msi/arch/ia64/sn/pci/msi.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ msi/arch/ia64/sn/pci/msi.c	2005-12-21 22:59:02.713172526 -0600
@@ -0,0 +1,18 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+#include <asm/errno.h>
+
+int
+sn_msi_init(void)
+{
+	/*
+	 * return error until MSI is supported on altix platforms
+	 */
+	return -EINVAL;
+}
Index: msi/drivers/pci/Makefile
===================================================================
--- msi.orig/drivers/pci/Makefile	2005-12-21 16:08:58.222841575 -0600
+++ msi/drivers/pci/Makefile	2005-12-21 16:10:32.848440390 -0600
@@ -23,7 +23,7 @@
 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
+obj-$(CONFIG_PCI_MSI) += msi.o msi-apic.o
 
 #
 # ACPI Related PCI FW Functions
Index: msi/drivers/pci/msi-apic.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ msi/drivers/pci/msi-apic.c	2005-12-22 11:09:37.022232088 -0600
@@ -0,0 +1,102 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+
+#include "msi.h"
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+
+static void
+msi_target_apic(unsigned int vector,
+		unsigned int dest_cpu,
+		u32 *address_hi,	/* in/out */
+		u32 *address_lo)	/* in/out */
+{
+	u32 addr = *address_lo;
+
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
+
+	*address_lo = addr;
+}
+
+static int
+msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
+		unsigned int vector,
+		u32 *address_hi,
+		u32 *address_lo,
+		u32 *data)
+{
+	unsigned long	dest_phys_id;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+
+	*address_hi = 0;
+	*address_lo =	MSI_ADDR_HEADER |
+			MSI_ADDR_DESTMODE_PHYS |
+			MSI_ADDR_REDIRECTION_CPU |
+			MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	*data = MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	return 0;
+}
+
+static void
+msi_teardown_apic(unsigned int vector)
+{
+	return;		/* no-op */
+}
+
+/*
+ * Generic callouts used on most archs/platforms.  Override with
+ * msi_register_callouts()
+ */
+
+struct msi_ops msi_apic_ops = {
+	.setup = msi_setup_apic,
+	.teardown = msi_teardown_apic,
+#ifdef CONFIG_SMP
+	.target = msi_target_apic,
+#endif
+};
Index: msi/drivers/pci/msi.h
===================================================================
--- msi.orig/drivers/pci/msi.h	2005-12-21 16:08:58.222841575 -0600
+++ msi/drivers/pci/msi.h	2005-12-21 23:06:48.292305590 -0600
@@ -69,67 +69,6 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-/*
- * MSI Defined Data Structures
- */
-#define MSI_ADDRESS_HEADER		0xfee
-#define MSI_ADDRESS_HEADER_SHIFT	12
-#define MSI_ADDRESS_HEADER_MASK		0xfff000
-#define MSI_ADDRESS_DEST_ID_MASK	0xfff0000f
-#define MSI_TARGET_CPU_MASK		0xff
-#define MSI_DELIVERY_MODE		0
-#define MSI_LEVEL_MODE			1	/* Edge always assert */
-#define MSI_TRIGGER_MODE		0	/* MSI is edge sensitive */
-#define MSI_PHYSICAL_MODE		0
-#define MSI_LOGICAL_MODE		1
-#define MSI_REDIRECTION_HINT_MODE	0
-
-struct msg_data {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-	__u32	vector		:  8;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	reserved_1	:  3;
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	reserved_2	: 16;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-	__u32	reserved_2	: 16;
-	__u32	trigger		:  1;	/* 0: edge | 1: level */
-	__u32	level		:  1;	/* 0: deassert | 1: assert */
-	__u32	reserved_1	:  3;
-	__u32	delivery_mode	:  3;	/* 000b: FIXED | 001b: lowest prior */
-	__u32	vector		:  8;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-} __attribute__ ((packed));
-
-struct msg_address {
-	union {
-		struct {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-			__u32	reserved_1	:  2;
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	reserved_2	:  4;
- 			__u32	dest_id		: 24;	/* Destination ID */
-#elif defined(__BIG_ENDIAN_BITFIELD)
- 			__u32	dest_id		: 24;	/* Destination ID */
-			__u32	reserved_2	:  4;
-			__u32	redirection_hint:  1;  	/*0: dedicated CPU
-							  1: lowest priority */
-			__u32	dest_mode	:  1;	/*0:physic | 1:logic */
-			__u32	reserved_1	:  2;
-#else
-#error "Bitfield endianness not defined! Check your byteorder.h"
-#endif
-      		}u;
-       		__u32  value;
-	}lo_address;
-	__u32 	hi_address;
-} __attribute__ ((packed));
-
 struct msi_desc {
 	struct {
 		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
@@ -138,7 +77,7 @@
 		__u8	reserved: 1; 	/* reserved			  */
 		__u8	entry_nr;    	/* specific enabled entry 	  */
 		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	current_cpu; 	/* current destination cpu	  */
+		__u8	unused; 	/* formerly unused destination cpu*/
 	}msi_attrib;
 
 	struct {
Index: msi/include/linux/pci.h
===================================================================
--- msi.orig/include/linux/pci.h	2005-12-21 16:08:58.223818043 -0600
+++ msi/include/linux/pci.h	2005-12-21 16:10:32.847463922 -0600
@@ -478,6 +478,16 @@
 	u16	entry;	/* driver uses to specify entry, OS writes */
 };
 
+struct msi_ops {
+	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
+			     u32 *addr_hi, u32 *addr_lo, u32 *data);
+	void	(*teardown) (unsigned int vector);
+#ifdef CONFIG_SMP
+	void	(*target)   (unsigned int vector, unsigned int cpu,
+			     u32 *addr_hi, u32 *addr_lo);
+#endif
+};
+
 #ifndef CONFIG_PCI_MSI
 static inline void pci_scan_msi_device(struct pci_dev *dev) {}
 static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
@@ -486,6 +496,7 @@
 	struct msix_entry *entries, int nvec) {return -1;}
 static inline void pci_disable_msix(struct pci_dev *dev) {}
 static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
+static inline int msi_register(struct msi_ops *ops) {return -1;}
 #else
 extern void pci_scan_msi_device(struct pci_dev *dev);
 extern int pci_enable_msi(struct pci_dev *dev);
@@ -494,6 +505,7 @@
 	struct msix_entry *entries, int nvec);
 extern void pci_disable_msix(struct pci_dev *dev);
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
+extern int msi_register(struct msi_ops *ops);
 #endif
 
 extern void pci_block_user_cfg_access(struct pci_dev *dev);

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2006-03-29  2:31 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-19 19:46 [PATCH 0/3] msi abstractions and support for altix Mark Maule
2006-01-19 19:46 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
2006-01-20  2:15   ` Greg KH
2006-01-19 19:46 ` [PATCH 2/3] per-platform IA64_{FIRST,LAST}_DEVICE_VECTOR definitions Mark Maule
2006-01-19 19:47 ` [PATCH 3/3] altix: msi support Mark Maule
2006-02-04  4:14   ` Altix SN2 2.6.16-rc1-mm5 build breakage (was: msi support) Paul Jackson
2006-02-04  4:25     ` Andrew Morton
2006-02-04  4:27       ` Andrew Morton
2006-02-04  4:42         ` Mark Maule
2006-02-04  5:08           ` Andrew Morton
2006-02-23  0:50         ` Paul Jackson
2006-02-23  1:01           ` Andrew Morton
  -- strict thread matches above, loose matches on Subject: below --
2006-03-29  2:31 [PATCH 0/3] msi abstractions and support for altix Mark Maule
2006-03-29  2:31 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
2006-03-21 14:34 [PATCH 0/3] msi abstractions and support for altix Mark Maule
2006-03-21 14:34 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
2006-03-21 16:29   ` Jun'ichi Nomura
2006-03-21 16:38     ` Andreas Schwab
2006-03-21 19:14       ` Mark Maule
2006-03-21 19:23         ` Jun'ichi Nomura
2006-03-21 19:38           ` Mark Maule
2006-01-11 22:16 [PATCH 0/3] msi abstractions and support for altix Mark Maule
2006-01-11 22:16 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
2006-01-11 15:52 [PATCH 0/3] msi abstractions and support for altix Mark Maule
2006-01-11 15:52 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
2006-01-11 20:21   ` Greg KH
2006-01-11 20:49     ` Mark Maule
2006-01-11 20:57       ` Greg KH
2006-01-12  5:02   ` Grant Grundler
2006-01-12  5:36     ` Greg KH
2006-01-12  5:47     ` Paul Mackerras
2006-01-12  7:33       ` Grant Grundler
2005-12-22 20:15 [PATCH 0/3] msi abstractions and support for altix Mark Maule
2005-12-22 20:15 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
2006-01-03 22:39   ` Grant Grundler
2006-01-03 23:50     ` Mark Maule
2006-01-04  0:20       ` Grant Grundler
2006-01-04  0:27         ` Greg KH
2006-01-04  3:52           ` Mark Maule
2005-12-22 17:15 [PATCH 0/3] msi abstractions and support for altix Mark Maule
2005-12-22 17:15 ` [PATCH 1/3] msi vector targeting abstractions Mark Maule
2005-12-22 19:58   ` Greg KH
2005-12-22 20:09     ` Mark Maule
2005-12-22 20:19       ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).