LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] IBM GPIO driver for PowerPC 4xx is back from the dead
From: Jean-Baptiste Maneyrol @ 2006-09-29  7:46 UTC (permalink / raw)
  To: linuxppc-embedded

Here is a patch for linux 2.6.18 that makes come back the old ibm gpio
driver from 2.6.10.

It is mainly useful for compatibility with old linux 2.4 from Montavista
I think, because direct memory access seems the new way to go.

Signed-off-by: Jean-Baptiste Maneyrol
<jean-baptiste.maneyrol@teamlog.com>


Jean-Baptiste Maneyrol
Teamlog - France

^ permalink raw reply

* Re: [PATCH] powerpc: cell spu problem state mapping updates
From: Arnd Bergmann @ 2006-09-29  7:52 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev list, Paul Mackerras, cbe-oss-dev@ozlabs.org
In-Reply-To: <1159506605.15792.24.camel@localhost.localdomain>

On Friday 29 September 2006 07:10, Benjamin Herrenschmidt wrote:
> This patch adds a new "psmap" file to spufs that allows mmap of all of
> the problem state mapping of SPEs. It is compatible with 64k pages. In
> addition, it removes mmap ability of individual files when using 64k
> pages, with the exception of signal1 and signal2 which will both map the
> entire 64k page holding both registers. It also removes
> CONFIG_SPUFS_MMAP as there is no point in not building mmap support in
> spufs.
> 
> It goes along a separate patch to libspe implementing usage of that new
> file to access problem state registers.
> 
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

^ permalink raw reply

* Re: [PATCH] Cell interrupt rework (final)
From: Arnd Bergmann @ 2006-09-29  7:51 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linuxppc-dev list, Paul Mackerras, cbe-oss-dev@ozlabs.org
In-Reply-To: <1159506029.15792.18.camel@localhost.localdomain>

On Friday 29 September 2006 07:00, Benjamin Herrenschmidt wrote:
> This patch reworks the cell iic interrupt handling so that:
>=20
> =A0- Node ID is back in the interrupt number (only one IRQ host is created
> for all nodes). This allows interrupts from sources on another node to
> be routed non-locally. This will allow possibly one day to fix maxcpus=3D1
> or 2 and still get interrupts from devices on BE 1. (A bit more fixing
> is needed for that) and it will allow us to implement actual affinity
> control of external interrupts.
>=20
> =A0- Added handling of the IO exceptions interrupts (badly named, but I
> re-used the name initially used by STI). Those are the interrupts
> exposed by IIC_ISR and IIC_IRR, such as the IOC translation exception,
> performance monitor, etc... Those get their special numbers in the IRQ
> number space and are internally implemented as a cascade on unit 0xe,
> class 1 of each node.
>=20
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>

^ permalink raw reply

* RE: [PATCH 11/12] Add MPC8360EMDS default dts file
From: Li Yang-r58472 @ 2006-09-29  7:46 UTC (permalink / raw)
  To: Vitaly Bordug; +Cc: linuxppc-dev, paulus
In-Reply-To: <20060928173816.168d4cc2@vitb.ru.mvista.com>

> -----Original Message-----
> From: Vitaly Bordug [mailto:vbordug@ru.mvista.com]
> Sent: Thursday, September 28, 2006 9:38 PM
> To: Li Yang-r58472
> Cc: paulus@samba.org; galak@kernel.crashing.org;
linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH 11/12] Add MPC8360EMDS default dts file
>=20
> On Thu, 28 Sep 2006 16:19:30 +0800
> Li Yang <leoli@freescale.com> wrote:
>=20
> > +		muram@10000 {
> > +			device_type =3D "muram";
> > +			ranges =3D <0 00010000 0000c000>;
> > +
> > +			data-only@0{
> > +				reg =3D <0 c000>;
> > +			};
> > +		};
> > +
>=20
> Why not to have reg property, showing the allocation ranges? data-only
seems
> redundant as a node...

The reason why I added this node is to put the address under "muram"
bus.  If I put the reg in muram node, the address will be offset to QE
base.  But what the driver needs is the offset to MURAM base.  IMHO,
this approach is clearer logically.

- Leo

^ permalink raw reply

* [PATCH] powerpc: cell spu problem state mapping updates
From: Benjamin Herrenschmidt @ 2006-09-29  5:10 UTC (permalink / raw)
  To: cbe-oss-dev@ozlabs.org; +Cc: linuxppc-dev list, Paul Mackerras, Arnd Bergmann

This patch adds a new "psmap" file to spufs that allows mmap of all of
the problem state mapping of SPEs. It is compatible with 64k pages. In
addition, it removes mmap ability of individual files when using 64k
pages, with the exception of signal1 and signal2 which will both map the
entire 64k page holding both registers. It also removes
CONFIG_SPUFS_MMAP as there is no point in not building mmap support in
spufs.

It goes along a separate patch to libspe implementing usage of that new
file to access problem state registers.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

Arnd: Unless I screwed up, this should be the same as the previous one I
sent you, with the addition of the changelog you requested and the
removal of the typo on WARRANTY.

Paul: If Arnd agrees, add that to your merge queue.

Index: linux-cell/arch/powerpc/platforms/cell/spufs/file.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spufs/file.c	2006-09-29 15:04:30.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spufs/file.c	2006-09-29 15:04:46.000000000 +1000
@@ -36,6 +36,8 @@
 
 #include "spufs.h"
 
+#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
+
 
 static int
 spufs_mem_open(struct inode *inode, struct file *file)
@@ -88,7 +90,6 @@ spufs_mem_write(struct file *file, const
 	return ret;
 }
 
-#ifdef CONFIG_SPUFS_MMAP
 static struct page *
 spufs_mem_mmap_nopage(struct vm_area_struct *vma,
 		      unsigned long address, int *type)
@@ -133,22 +134,19 @@ spufs_mem_mmap(struct file *file, struct
 	vma->vm_ops = &spufs_mem_mmap_vmops;
 	return 0;
 }
-#endif
 
 static struct file_operations spufs_mem_fops = {
 	.open	 = spufs_mem_open,
 	.read    = spufs_mem_read,
 	.write   = spufs_mem_write,
 	.llseek  = generic_file_llseek,
-#ifdef CONFIG_SPUFS_MMAP
 	.mmap    = spufs_mem_mmap,
-#endif
 };
 
-#ifdef CONFIG_SPUFS_MMAP
 static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
 				    unsigned long address,
-				    int *type, unsigned long ps_offs)
+				    int *type, unsigned long ps_offs,
+				    unsigned long ps_size)
 {
 	struct page *page = NOPAGE_SIGBUS;
 	int fault_type = VM_FAULT_SIGBUS;
@@ -158,7 +156,7 @@ static struct page *spufs_ps_nopage(stru
 	int ret;
 
 	offset += vma->vm_pgoff << PAGE_SHIFT;
-	if (offset >= 0x4000)
+	if (offset >= ps_size)
 		goto out;
 
 	ret = spu_acquire_runnable(ctx);
@@ -179,10 +177,11 @@ static struct page *spufs_ps_nopage(stru
 	return page;
 }
 
+#if SPUFS_MMAP_4K
 static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
 					   unsigned long address, int *type)
 {
-	return spufs_ps_nopage(vma, address, type, 0x4000);
+	return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000);
 }
 
 static struct vm_operations_struct spufs_cntl_mmap_vmops = {
@@ -191,17 +190,12 @@ static struct vm_operations_struct spufs
 
 /*
  * mmap support for problem state control area [0x4000 - 0x4fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
  */
 static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	if (!capable(CAP_SYS_RAWIO))
-		return -EPERM;
-
 	vma->vm_flags |= VM_RESERVED;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -209,7 +203,9 @@ static int spufs_cntl_mmap(struct file *
 	vma->vm_ops = &spufs_cntl_mmap_vmops;
 	return 0;
 }
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_cntl_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
 
 static int spufs_cntl_open(struct inode *inode, struct file *file)
 {
@@ -242,9 +238,7 @@ static struct file_operations spufs_cntl
 	.open = spufs_cntl_open,
 	.read = spufs_cntl_read,
 	.write = spufs_cntl_write,
-#ifdef CONFIG_SPUFS_MMAP
 	.mmap = spufs_cntl_mmap,
-#endif
 };
 
 static int
@@ -657,11 +651,19 @@ static ssize_t spufs_signal1_write(struc
 	return 4;
 }
 
-#ifdef CONFIG_SPUFS_MMAP
 static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
 					      unsigned long address, int *type)
 {
-	return spufs_ps_nopage(vma, address, type, 0x14000);
+#if PAGE_SIZE == 0x1000
+	return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000);
+#elif PAGE_SIZE == 0x10000
+	/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
+	 * signal 1 and 2 area
+	 */
+	return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
+#else
+#error unsupported page size
+#endif
 }
 
 static struct vm_operations_struct spufs_signal1_mmap_vmops = {
@@ -680,15 +682,12 @@ static int spufs_signal1_mmap(struct fil
 	vma->vm_ops = &spufs_signal1_mmap_vmops;
 	return 0;
 }
-#endif
 
 static struct file_operations spufs_signal1_fops = {
 	.open = spufs_signal1_open,
 	.read = spufs_signal1_read,
 	.write = spufs_signal1_write,
-#ifdef CONFIG_SPUFS_MMAP
 	.mmap = spufs_signal1_mmap,
-#endif
 };
 
 static int spufs_signal2_open(struct inode *inode, struct file *file)
@@ -743,11 +742,20 @@ static ssize_t spufs_signal2_write(struc
 	return 4;
 }
 
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
 static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
 					      unsigned long address, int *type)
 {
-	return spufs_ps_nopage(vma, address, type, 0x1c000);
+#if PAGE_SIZE == 0x1000
+	return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000);
+#elif PAGE_SIZE == 0x10000
+	/* For 64k pages, both signal1 and signal2 can be used to mmap the whole
+	 * signal 1 and 2 area
+	 */
+	return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
+#else
+#error unsupported page size
+#endif
 }
 
 static struct vm_operations_struct spufs_signal2_mmap_vmops = {
@@ -767,15 +775,15 @@ static int spufs_signal2_mmap(struct fil
 	vma->vm_ops = &spufs_signal2_mmap_vmops;
 	return 0;
 }
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_signal2_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
 
 static struct file_operations spufs_signal2_fops = {
 	.open = spufs_signal2_open,
 	.read = spufs_signal2_read,
 	.write = spufs_signal2_write,
-#ifdef CONFIG_SPUFS_MMAP
 	.mmap = spufs_signal2_mmap,
-#endif
 };
 
 static void spufs_signal1_type_set(void *data, u64 val)
@@ -824,11 +832,11 @@ static u64 spufs_signal2_type_get(void *
 DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
 					spufs_signal2_type_set, "%llu");
 
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
 static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma,
 					   unsigned long address, int *type)
 {
-	return spufs_ps_nopage(vma, address, type, 0x0000);
+	return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000);
 }
 
 static struct vm_operations_struct spufs_mss_mmap_vmops = {
@@ -837,17 +845,12 @@ static struct vm_operations_struct spufs
 
 /*
  * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
  */
 static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	if (!capable(CAP_SYS_RAWIO))
-		return -EPERM;
-
 	vma->vm_flags |= VM_RESERVED;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -855,7 +858,9 @@ static int spufs_mss_mmap(struct file *f
 	vma->vm_ops = &spufs_mss_mmap_vmops;
 	return 0;
 }
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_mss_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
 
 static int spufs_mss_open(struct inode *inode, struct file *file)
 {
@@ -867,17 +872,54 @@ static int spufs_mss_open(struct inode *
 
 static struct file_operations spufs_mss_fops = {
 	.open	 = spufs_mss_open,
-#ifdef CONFIG_SPUFS_MMAP
 	.mmap	 = spufs_mss_mmap,
-#endif
+};
+
+static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma,
+					   unsigned long address, int *type)
+{
+	return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000);
+}
+
+static struct vm_operations_struct spufs_psmap_mmap_vmops = {
+	.nopage = spufs_psmap_mmap_nopage,
+};
+
+/*
+ * mmap support for full problem state area [0x00000 - 0x1ffff].
+ */
+static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	if (!(vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
+
+	vma->vm_ops = &spufs_psmap_mmap_vmops;
+	return 0;
+}
+
+static int spufs_psmap_open(struct inode *inode, struct file *file)
+{
+	struct spufs_inode_info *i = SPUFS_I(inode);
+
+	file->private_data = i->i_ctx;
+	return nonseekable_open(inode, file);
+}
+
+static struct file_operations spufs_psmap_fops = {
+	.open	 = spufs_psmap_open,
+	.mmap	 = spufs_psmap_mmap,
 };
 
 
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
 static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
 					   unsigned long address, int *type)
 {
-	return spufs_ps_nopage(vma, address, type, 0x3000);
+	return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000);
 }
 
 static struct vm_operations_struct spufs_mfc_mmap_vmops = {
@@ -886,17 +928,12 @@ static struct vm_operations_struct spufs
 
 /*
  * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
  */
 static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	if (!(vma->vm_flags & VM_SHARED))
 		return -EINVAL;
 
-	if (!capable(CAP_SYS_RAWIO))
-		return -EPERM;
-
 	vma->vm_flags |= VM_RESERVED;
 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
 				     | _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -904,7 +941,9 @@ static int spufs_mfc_mmap(struct file *f
 	vma->vm_ops = &spufs_mfc_mmap_vmops;
 	return 0;
 }
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_mfc_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
 
 static int spufs_mfc_open(struct inode *inode, struct file *file)
 {
@@ -1194,9 +1233,7 @@ static struct file_operations spufs_mfc_
 	.flush	 = spufs_mfc_flush,
 	.fsync	 = spufs_mfc_fsync,
 	.fasync	 = spufs_mfc_fasync,
-#ifdef CONFIG_SPUFS_MMAP
 	.mmap	 = spufs_mfc_mmap,
-#endif
 };
 
 static void spufs_npc_set(void *data, u64 val)
@@ -1368,5 +1405,6 @@ struct tree_descr spufs_dir_contents[] =
 	{ "event_mask", &spufs_event_mask_ops, 0666, },
 	{ "srr0", &spufs_srr0_ops, 0666, },
 	{ "phys-id", &spufs_id_ops, 0666, },
+	{ "psmap", &spufs_psmap_fops, 0666, },
 	{},
 };
Index: linux-cell/arch/powerpc/platforms/cell/Kconfig
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/Kconfig	2006-09-29 15:04:30.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/Kconfig	2006-09-29 15:04:46.000000000 +1000
@@ -16,11 +16,6 @@ config SPU_BASE
 	bool
 	default n
 
-config SPUFS_MMAP
-	bool
-	depends on SPU_FS && SPARSEMEM
-	default y
-
 config CBE_RAS
 	bool "RAS features for bare metal Cell BE"
 	default y

^ permalink raw reply

* [PATCH] Cell interrupt rework (final)
From: Benjamin Herrenschmidt @ 2006-09-29  5:00 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev list, Paul Mackerras, cbe-oss-dev@ozlabs.org

This patch reworks the cell iic interrupt handling so that:

 - Node ID is back in the interrupt number (only one IRQ host is created
for all nodes). This allows interrupts from sources on another node to
be routed non-locally. This will allow possibly one day to fix maxcpus=1
or 2 and still get interrupts from devices on BE 1. (A bit more fixing
is needed for that) and it will allow us to implement actual affinity
control of external interrupts.

 - Added handling of the IO exceptions interrupts (badly named, but I
re-used the name initially used by STI). Those are the interrupts
exposed by IIC_ISR and IIC_IRR, such as the IOC translation exception,
performance monitor, etc... Those get their special numbers in the IRQ
number space and are internally implemented as a cascade on unit 0xe,
class 1 of each node.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

Hi Arnd !

It occurred to me that the version of the Cell interrupt rework I sent
you was still not the latest one ! In fact, I wasn't using the latest
one myself, only Jeremy was :) I messed up with my patch handling
locally. The result is that the version you have is causing occasional
loss of interrupts, typically the case where IDE disappears after
loading the SPUs a bit.

This is the real latest version that works and that survives parallel
SPU torture and hard disk activity. The problem was that unexepcted
interrupts wouldn't be ack'ed (the priority register wouldn't be put
back to 0xff). The bug was in the original code but it would somewhat
recover after some fairly high latency by getting some even higher
priority interrupt since it's eoi would unconditionally set back the
priority to 0xff. The new code implements a nice prio stack however, and
thus ends up with the priority never going back down.

Paulus: please merge upstream too.

Index: linux-cell/arch/powerpc/platforms/cell/interrupt.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/interrupt.c	2006-09-08 17:17:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/interrupt.c	2006-09-29 14:36:23.000000000 +1000
@@ -21,6 +21,12 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * TODO:
+ * - Fix various assumptions related to HW CPU numbers vs. linux CPU numbers
+ *   vs node numbers in the setup code
+ * - Implement proper handling of maxcpus=1/2 (that is, routing of irqs from
+ *   a non-active node to the active node)
  */
 
 #include <linux/interrupt.h>
@@ -44,24 +50,25 @@ struct iic {
 	u8 target_id;
 	u8 eoi_stack[16];
 	int eoi_ptr;
-	struct irq_host *host;
+	struct device_node *node;
 };
 
 static DEFINE_PER_CPU(struct iic, iic);
 #define IIC_NODE_COUNT	2
-static struct irq_host *iic_hosts[IIC_NODE_COUNT];
+static struct irq_host *iic_host;
 
 /* Convert between "pending" bits and hw irq number */
 static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
 {
 	unsigned char unit = bits.source & 0xf;
+	unsigned char node = bits.source >> 4;
+	unsigned char class = bits.class & 3;
 
+	/* Decode IPIs */
 	if (bits.flags & CBE_IIC_IRQ_IPI)
-		return IIC_IRQ_IPI0 | (bits.prio >> 4);
-	else if (bits.class <= 3)
-		return (bits.class << 4) | unit;
+		return IIC_IRQ_TYPE_IPI | (bits.prio >> 4);
 	else
-		return IIC_IRQ_INVALID;
+		return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit;
 }
 
 static void iic_mask(unsigned int irq)
@@ -86,21 +93,70 @@ static struct irq_chip iic_chip = {
 	.eoi = iic_eoi,
 };
 
+
+static void iic_ioexc_eoi(unsigned int irq)
+{
+}
+
+static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc,
+			    struct pt_regs *regs)
+{
+	struct cbe_iic_regs *node_iic = desc->handler_data;
+	unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC;
+	unsigned long bits, ack;
+	int cascade;
+
+	for (;;) {
+		bits = in_be64(&node_iic->iic_is);
+		if (bits == 0)
+			break;
+		/* pre-ack edge interrupts */
+		ack = bits & IIC_ISR_EDGE_MASK;
+		if (ack)
+			out_be64(&node_iic->iic_is, ack);
+		/* handle them */
+		for (cascade = 63; cascade >= 0; cascade--)
+			if (bits & (0x8000000000000000UL >> cascade)) {
+				unsigned int cirq =
+					irq_linear_revmap(iic_host,
+							  base | cascade);
+				if (cirq != NO_IRQ)
+					generic_handle_irq(cirq, regs);
+			}
+		/* post-ack level interrupts */
+		ack = bits & ~IIC_ISR_EDGE_MASK;
+		if (ack)
+			out_be64(&node_iic->iic_is, ack);
+	}
+	desc->chip->eoi(irq);
+}
+
+
+static struct irq_chip iic_ioexc_chip = {
+	.typename = " CELL-IOEX",
+	.mask = iic_mask,
+	.unmask = iic_unmask,
+	.eoi = iic_ioexc_eoi,
+};
+
 /* Get an IRQ number from the pending state register of the IIC */
 static unsigned int iic_get_irq(struct pt_regs *regs)
 {
   	struct cbe_iic_pending_bits pending;
  	struct iic *iic;
+	unsigned int virq;
 
  	iic = &__get_cpu_var(iic);
  	*(unsigned long *) &pending =
  		in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
+	if (!(pending.flags & CBE_IIC_IRQ_VALID))
+		return NO_IRQ;
+	virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending));
+	if (virq == NO_IRQ)
+		return NO_IRQ;
  	iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
  	BUG_ON(iic->eoi_ptr > 15);
-	if (pending.flags & CBE_IIC_IRQ_VALID)
-		return irq_linear_revmap(iic->host,
- 					 iic_pending_to_hwnum(pending));
-	return NO_IRQ;
+	return virq;
 }
 
 #ifdef CONFIG_SMP
@@ -108,12 +164,7 @@ static unsigned int iic_get_irq(struct p
 /* Use the highest interrupt priorities for IPI */
 static inline int iic_ipi_to_irq(int ipi)
 {
-	return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi;
-}
-
-static inline int iic_irq_to_ipi(int irq)
-{
-	return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0);
+	return IIC_IRQ_TYPE_IPI + 0xf - ipi;
 }
 
 void iic_setup_cpu(void)
@@ -123,7 +174,7 @@ void iic_setup_cpu(void)
 
 void iic_cause_IPI(int cpu, int mesg)
 {
-	out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
+	out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4);
 }
 
 u8 iic_get_target_id(int cpu)
@@ -134,9 +185,7 @@ EXPORT_SYMBOL_GPL(iic_get_target_id);
 
 struct irq_host *iic_get_irq_host(int node)
 {
-	if (node < 0 || node >= IIC_NODE_COUNT)
-		return NULL;
-	return iic_hosts[node];
+	return iic_host;
 }
 EXPORT_SYMBOL_GPL(iic_get_irq_host);
 
@@ -149,34 +198,20 @@ static irqreturn_t iic_ipi_action(int ir
 
 	return IRQ_HANDLED;
 }
-
 static void iic_request_ipi(int ipi, const char *name)
 {
-	int node, virq;
+	int virq;
 
-	for (node = 0; node < IIC_NODE_COUNT; node++) {
-		char *rname;
-		if (iic_hosts[node] == NULL)
-			continue;
-		virq = irq_create_mapping(iic_hosts[node],
-					  iic_ipi_to_irq(ipi));
-		if (virq == NO_IRQ) {
-			printk(KERN_ERR
-			       "iic: failed to map IPI %s on node %d\n",
-			       name, node);
-			continue;
-		}
-		rname = kzalloc(strlen(name) + 16, GFP_KERNEL);
-		if (rname)
-			sprintf(rname, "%s node %d", name, node);
-		else
-			rname = (char *)name;
-		if (request_irq(virq, iic_ipi_action, IRQF_DISABLED,
-				rname, (void *)(long)ipi))
-			printk(KERN_ERR
-			       "iic: failed to request IPI %s on node %d\n",
-			       name, node);
+	virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi));
+	if (virq == NO_IRQ) {
+		printk(KERN_ERR
+		       "iic: failed to map IPI %s\n", name);
+		return;
 	}
+	if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name,
+			(void *)(long)ipi))
+		printk(KERN_ERR
+		       "iic: failed to request IPI %s\n", name);
 }
 
 void iic_request_IPIs(void)
@@ -193,16 +228,24 @@ void iic_request_IPIs(void)
 
 static int iic_host_match(struct irq_host *h, struct device_node *node)
 {
-	return h->host_data != NULL && node == h->host_data;
+	return device_is_compatible(node,
+				    "IBM,CBEA-Internal-Interrupt-Controller");
 }
 
 static int iic_host_map(struct irq_host *h, unsigned int virq,
 			irq_hw_number_t hw)
 {
-	if (hw < IIC_IRQ_IPI0)
-		set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
-	else
+	switch (hw & IIC_IRQ_TYPE_MASK) {
+	case IIC_IRQ_TYPE_IPI:
 		set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq);
+		break;
+	case IIC_IRQ_TYPE_IOEXC:
+		set_irq_chip_and_handler(virq, &iic_ioexc_chip,
+					 handle_fasteoi_irq);
+		break;
+	default:
+		set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
+	}
 	return 0;
 }
 
@@ -211,11 +254,39 @@ static int iic_host_xlate(struct irq_hos
 			   irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 
 {
-	/* Currently, we don't translate anything. That needs to be fixed as
-	 * we get better defined device-trees. iic interrupts have to be
-	 * explicitely mapped by whoever needs them
-	 */
-	return -ENODEV;
+	unsigned int node, ext, unit, class;
+	const u32 *val;
+
+	if (!device_is_compatible(ct,
+				     "IBM,CBEA-Internal-Interrupt-Controller"))
+		return -ENODEV;
+	if (intsize != 1)
+		return -ENODEV;
+	val = get_property(ct, "#interrupt-cells", NULL);
+	if (val == NULL || *val != 1)
+		return -ENODEV;
+
+	node = intspec[0] >> 24;
+	ext = (intspec[0] >> 16) & 0xff;
+	class = (intspec[0] >> 8) & 0xff;
+	unit = intspec[0] & 0xff;
+
+	/* Check if node is in supported range */
+	if (node > 1)
+		return -EINVAL;
+
+	/* Build up interrupt number, special case for IO exceptions */
+	*out_hwirq = (node << IIC_IRQ_NODE_SHIFT);
+	if (unit == IIC_UNIT_IIC && class == 1)
+		*out_hwirq |= IIC_IRQ_TYPE_IOEXC | ext;
+	else
+		*out_hwirq |= IIC_IRQ_TYPE_NORMAL |
+			(class << IIC_IRQ_CLASS_SHIFT) | unit;
+
+	/* Dummy flags, ignored by iic code */
+	*out_flags = IRQ_TYPE_EDGE_RISING;
+
+	return 0;
 }
 
 static struct irq_host_ops iic_host_ops = {
@@ -225,7 +296,7 @@ static struct irq_host_ops iic_host_ops 
 };
 
 static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr,
-				struct irq_host *host)
+				struct device_node *node)
 {
 	/* XXX FIXME: should locate the linux CPU number from the HW cpu
 	 * number properly. We are lucky for now
@@ -237,28 +308,27 @@ static void __init init_one_iic(unsigned
 
 	iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe);
 	iic->eoi_stack[0] = 0xff;
-	iic->host = host;
+	iic->node = of_node_get(node);
 	out_be64(&iic->regs->prio, 0);
 
-	printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n",
-	       hw_cpu, addr, iic->regs, iic->target_id);
+	printk(KERN_INFO "IIC for CPU %d target id 0x%x : %s\n",
+	       hw_cpu, iic->target_id, node->full_name);
 }
 
 static int __init setup_iic(void)
 {
 	struct device_node *dn;
 	struct resource r0, r1;
-	struct irq_host *host;
-	int found = 0;
- 	u32 *np;
+	unsigned int node, cascade, found = 0;
+	struct cbe_iic_regs *node_iic;
+ 	const u32 *np;
 
 	for (dn = NULL;
 	     (dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
 		if (!device_is_compatible(dn,
 				     "IBM,CBEA-Internal-Interrupt-Controller"))
 			continue;
- 		np = (u32 *)get_property(dn, "ibm,interrupt-server-ranges",
-					 NULL);
+ 		np = get_property(dn, "ibm,interrupt-server-ranges", NULL);
  		if (np == NULL) {
 			printk(KERN_WARNING "IIC: CPU association not found\n");
 			of_node_put(dn);
@@ -270,19 +340,33 @@ static int __init setup_iic(void)
 			of_node_put(dn);
 			return -ENODEV;
 		}
-		host = NULL;
-		if (found < IIC_NODE_COUNT) {
-			host = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
-					      IIC_SOURCE_COUNT,
-					      &iic_host_ops,
-					      IIC_IRQ_INVALID);
-			iic_hosts[found] = host;
-			BUG_ON(iic_hosts[found] == NULL);
-			iic_hosts[found]->host_data = of_node_get(dn);
-			found++;
-		}
-		init_one_iic(np[0], r0.start, host);
-		init_one_iic(np[1], r1.start, host);
+		found++;
+		init_one_iic(np[0], r0.start, dn);
+		init_one_iic(np[1], r1.start, dn);
+
+		/* Setup cascade for IO exceptions. XXX cleanup tricks to get
+		 * node vs CPU etc...
+		 * Note that we configure the IIC_IRR here with a hard coded
+		 * priority of 1. We might want to improve that later.
+		 */
+		node = np[0] >> 1;
+		node_iic = cbe_get_cpu_iic_regs(np[0]);
+		cascade = node << IIC_IRQ_NODE_SHIFT;
+		cascade |= 1 << IIC_IRQ_CLASS_SHIFT;
+		cascade |= IIC_UNIT_IIC;
+		cascade = irq_create_mapping(iic_host, cascade);
+		if (cascade == NO_IRQ)
+			continue;
+		set_irq_data(cascade, node_iic);
+		set_irq_chained_handler(cascade , iic_ioexc_cascade);
+		out_be64(&node_iic->iic_ir,
+			 (1 << 12)		/* priority */ |
+			 (node << 4)		/* dest node */ |
+			 IIC_UNIT_THREAD_0	/* route them to thread 0 */);
+		/* Flush pending (make sure it triggers if there is
+		 * anything pending
+		 */
+		out_be64(&node_iic->iic_is, 0xfffffffffffffffful);
 	}
 
 	if (found)
@@ -293,6 +377,12 @@ static int __init setup_iic(void)
 
 void __init iic_init_IRQ(void)
 {
+	/* Setup an irq host data structure */
+	iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
+				  &iic_host_ops, IIC_IRQ_INVALID);
+	BUG_ON(iic_host == NULL);
+	irq_set_default_host(iic_host);
+
 	/* Discover and initialize iics */
 	if (setup_iic() < 0)
 		panic("IIC: Failed to initialize !\n");
Index: linux-cell/arch/powerpc/platforms/cell/interrupt.h
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/interrupt.h	2006-09-08 17:17:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/interrupt.h	2006-09-22 12:56:14.000000000 +1000
@@ -2,48 +2,76 @@
 #define ASM_CELL_PIC_H
 #ifdef __KERNEL__
 /*
- * Mapping of IIC pending bits into per-node
- * interrupt numbers.
+ * Mapping of IIC pending bits into per-node interrupt numbers.
  *
- * IRQ     FF CC SS PP   FF CC SS PP	Description
+ * Interrupt numbers are in the range 0...0x1ff where the top bit
+ * (0x100) represent the source node. Only 2 nodes are supported with
+ * the current code though it's trivial to extend that if necessary using
+ * higher level bits
  *
- * 00-3f   80 02 +0 00 - 80 02 +0 3f	South Bridge
- * 00-3f   80 02 +b 00 - 80 02 +b 3f	South Bridge
- * 41-4a   80 00 +1 ** - 80 00 +a **	SPU Class 0
- * 51-5a   80 01 +1 ** - 80 01 +a **	SPU Class 1
- * 61-6a   80 02 +1 ** - 80 02 +a **	SPU Class 2
- * 70-7f   C0 ** ** 00 - C0 ** ** 0f	IPI
+ * The bottom 8 bits are split into 2 type bits and 6 data bits that
+ * depend on the type:
  *
- *    F flags
- *    C class
- *    S source
- *    P Priority
- *    + node number
- *    * don't care
+ * 00 (0x00 | data) : normal interrupt. data is (class << 4) | source
+ * 01 (0x40 | data) : IO exception. data is the exception number as
+ *                    defined by bit numbers in IIC_SR
+ * 10 (0x80 | data) : IPI. data is the IPI number (obtained from the priority)
+ *                    and node is always 0 (IPIs are per-cpu, their source is
+ *                    not relevant)
+ * 11 (0xc0 | data) : reserved
  *
- * A node consists of a Cell Broadband Engine and an optional
- * south bridge device providing a maximum of 64 IRQs.
- * The south bridge may be connected to either IOIF0
- * or IOIF1.
- * Each SPE is represented as three IRQ lines, one per
- * interrupt class.
- * 16 IRQ numbers are reserved for inter processor
- * interruptions, although these are only used in the
- * range of the first node.
+ * In addition, interrupt number 0x80000000 is defined as always invalid
+ * (that is the node field is expected to never extend to move than 23 bits)
  *
- * This scheme needs 128 IRQ numbers per BIF node ID,
- * which means that with the total of 512 lines
- * available, we can have a maximum of four nodes.
  */
 
 enum {
-	IIC_IRQ_INVALID		= 0xff,
-	IIC_IRQ_MAX		= 0x3f,
-	IIC_IRQ_EXT_IOIF0	= 0x20,
-	IIC_IRQ_EXT_IOIF1	= 0x2b,
-	IIC_IRQ_IPI0		= 0x40,
-	IIC_NUM_IPIS    	= 0x10, /* IRQs reserved for IPI */
-	IIC_SOURCE_COUNT	= 0x50,
+	IIC_IRQ_INVALID		= 0x80000000u,
+	IIC_IRQ_NODE_MASK	= 0x100,
+	IIC_IRQ_NODE_SHIFT	= 8,
+	IIC_IRQ_MAX		= 0x1ff,
+	IIC_IRQ_TYPE_MASK	= 0xc0,
+	IIC_IRQ_TYPE_NORMAL	= 0x00,
+	IIC_IRQ_TYPE_IOEXC	= 0x40,
+	IIC_IRQ_TYPE_IPI	= 0x80,
+	IIC_IRQ_CLASS_SHIFT	= 4,
+	IIC_IRQ_CLASS_0		= 0x00,
+	IIC_IRQ_CLASS_1		= 0x10,
+	IIC_IRQ_CLASS_2		= 0x20,
+	IIC_SOURCE_COUNT	= 0x200,
+
+	/* Here are defined the various source/dest units. Avoid using those
+	 * definitions if you can, they are mostly here for reference
+	 */
+	IIC_UNIT_SPU_0		= 0x4,
+	IIC_UNIT_SPU_1		= 0x7,
+	IIC_UNIT_SPU_2		= 0x3,
+	IIC_UNIT_SPU_3		= 0x8,
+	IIC_UNIT_SPU_4		= 0x2,
+	IIC_UNIT_SPU_5		= 0x9,
+	IIC_UNIT_SPU_6		= 0x1,
+	IIC_UNIT_SPU_7		= 0xa,
+	IIC_UNIT_IOC_0		= 0x0,
+	IIC_UNIT_IOC_1		= 0xb,
+	IIC_UNIT_THREAD_0	= 0xe, /* target only */
+	IIC_UNIT_THREAD_1	= 0xf, /* target only */
+	IIC_UNIT_IIC		= 0xe, /* source only (IO exceptions) */
+
+	/* Base numbers for the external interrupts */
+	IIC_IRQ_EXT_IOIF0	=
+		IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_0,
+	IIC_IRQ_EXT_IOIF1	=
+		IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_1,
+
+	/* Base numbers for the IIC_ISR interrupts */
+	IIC_IRQ_IOEX_TMI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 63,
+	IIC_IRQ_IOEX_PMI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 62,
+	IIC_IRQ_IOEX_ATI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 61,
+	IIC_IRQ_IOEX_MATBFI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 60,
+	IIC_IRQ_IOEX_ELDI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 59,
+
+	/* Which bits in IIC_ISR are edge sensitive */
+	IIC_ISR_EDGE_MASK	= 0x4ul,
 };
 
 extern void iic_init_IRQ(void);
@@ -52,7 +80,6 @@ extern void iic_request_IPIs(void);
 extern void iic_setup_cpu(void);
 
 extern u8 iic_get_target_id(int cpu);
-extern struct irq_host *iic_get_irq_host(int node);
 
 extern void spider_init_IRQ(void);
 
Index: linux-cell/arch/powerpc/platforms/cell/spider-pic.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spider-pic.c	2006-09-08 17:17:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spider-pic.c	2006-09-29 14:37:00.000000000 +1000
@@ -240,10 +240,9 @@ static void spider_irq_cascade(unsigned 
 static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
 {
 	unsigned int virq;
-	u32 *imap, *tmp;
+	const u32 *imap, *tmp;
 	int imaplen, intsize, unit;
 	struct device_node *iic;
-	struct irq_host *iic_host;
 
 #if 0 /* Enable that when we have a way to retreive the node as well */
 	/* First, we check wether we have a real "interrupts" in the device
@@ -258,25 +257,25 @@ static unsigned int __init spider_find_c
 #endif
 
 	/* Now do the horrible hacks */
-	tmp = (u32 *)get_property(pic->of_node, "#interrupt-cells", NULL);
+	tmp = get_property(pic->of_node, "#interrupt-cells", NULL);
 	if (tmp == NULL)
 		return NO_IRQ;
 	intsize = *tmp;
-	imap = (u32 *)get_property(pic->of_node, "interrupt-map", &imaplen);
+	imap = get_property(pic->of_node, "interrupt-map", &imaplen);
 	if (imap == NULL || imaplen < (intsize + 1))
 		return NO_IRQ;
 	iic = of_find_node_by_phandle(imap[intsize]);
 	if (iic == NULL)
 		return NO_IRQ;
 	imap += intsize + 1;
-	tmp = (u32 *)get_property(iic, "#interrupt-cells", NULL);
+	tmp = get_property(iic, "#interrupt-cells", NULL);
 	if (tmp == NULL)
 		return NO_IRQ;
 	intsize = *tmp;
 	/* Assume unit is last entry of interrupt specifier */
 	unit = imap[intsize - 1];
 	/* Ok, we have a unit, now let's try to get the node */
-	tmp = (u32 *)get_property(iic, "ibm,interrupt-server-ranges", NULL);
+	tmp = get_property(iic, "ibm,interrupt-server-ranges", NULL);
 	if (tmp == NULL) {
 		of_node_put(iic);
 		return NO_IRQ;
@@ -289,11 +288,11 @@ static unsigned int __init spider_find_c
 	 * the iic host from the iic OF node, but that way I'm still compatible
 	 * with really really old old firmwares for which we don't have a node
 	 */
-	iic_host = iic_get_irq_host(pic->node_id);
-	if (iic_host == NULL)
-		return NO_IRQ;
 	/* Manufacture an IIC interrupt number of class 2 */
-	virq = irq_create_mapping(iic_host, 0x20 | unit);
+	virq = irq_create_mapping(NULL,
+				  (pic->node_id << IIC_IRQ_NODE_SHIFT) |
+				  (2 << IIC_IRQ_CLASS_SHIFT) |
+				  unit);
 	if (virq == NO_IRQ)
 		printk(KERN_ERR "spider_pic: failed to map cascade !");
 	return virq;
Index: linux-cell/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- linux-cell.orig/arch/powerpc/platforms/cell/spu_base.c	2006-09-08 17:17:10.000000000 +1000
+++ linux-cell/arch/powerpc/platforms/cell/spu_base.c	2006-09-22 12:56:14.000000000 +1000
@@ -568,24 +568,23 @@ static void spu_unmap(struct spu *spu)
 /* This function shall be abstracted for HV platforms */
 static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
 {
-	struct irq_host *host;
 	unsigned int isrc;
 	u32 *tmp;
 
-	host = iic_get_irq_host(spu->node);
-	if (host == NULL)
-		return -ENODEV;
-
-	/* Get the interrupt source from the device-tree */
+	/* Get the interrupt source unit from the device-tree */
 	tmp = (u32 *)get_property(np, "isrc", NULL);
 	if (!tmp)
 		return -ENODEV;
-	spu->isrc = isrc = tmp[0];
+	isrc = tmp[0];
+
+	/* Add the node number */
+	isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
+	spu->isrc = isrc;
 
 	/* Now map interrupts of all 3 classes */
-	spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc);
-	spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc);
-	spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc);
+	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
+	spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
+	spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
 
 	/* Right now, we only fail if class 2 failed */
 	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;

^ permalink raw reply

* LSP for MPC8247
From: Akhilesh Soni @ 2006-09-29  4:56 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: linuxppc-embedded-request

[-- Attachment #1: Type: text/plain, Size: 297 bytes --]

Hi,

Is there any open soure LSP for freescale MPC8247 available. 

I've an LSP for MPC8245 and I need for MPC8247. How much effort would be required to change from 8245 to 8247. Is somebody already done this ?

Any pointer or suggestions would be highly appreciated.

Regards,
Akhilesh

[-- Attachment #2: Type: text/html, Size: 1015 bytes --]

^ permalink raw reply

* RE: About cache
From: Xu, Li (GE, Research) @ 2006-09-29  4:45 UTC (permalink / raw)
  To: enorm, linuxppc-embedded
In-Reply-To: <00a901c6e366$1d3e4f70$a309a8c0@enorm>

WW91IGhhdmUgdG8gZG8gc28uDQpUaGF0IHdpbGwgcHJldmVudCBDUFUgZnJvbSBmZXRjaGluZyBk
YXRhIG9yIGluc3RydWN0aW9ucyBmcm9tIGktY2FjaGUgYW5kIGQtY2FjaGUNCmF0IHRoZSBpbml0
aWFsaXphdGlvbiB0aW1lIHNpbmNlIHRoZSBjYWNoZSBpcyBub3QgaW5pdGlhbGl6ZWQgeWV0Lg0K
DQoJLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0gDQoJRnJvbTogbGludXhwcGMtZW1iZWRkZWQt
Ym91bmNlcytsaS54dT1nZS5jb21Ab3psYWJzLm9yZyBvbiBiZWhhbGYgb2YgZW5vcm0gDQoJU2Vu
dDogRnJpIDkvMjkvMjAwNiA5OjI1IEFNIA0KCVRvOiBsaW51eHBwYy1lbWJlZGRlZEBvemxhYnMu
b3JnIA0KCUNjOiANCglTdWJqZWN0OiBBYm91dCBjYWNoZQ0KCQ0KCQ0KDQoJSGksDQoJDQoJSSBm
b3VuZCBpbiBtcGM4NXh4IHN0YXJ0LnMsIGJlZm9yZSBkb2luZyBhbnkgaW5pdGlhbGl6YXRpb24g
aXQgZGlzYWJsZWQNCgkgaS1jYWNoZSAmIGQtY2FjaGUuIE11c3Qgd2UgZG8gc28/IElmIHdlIGRv
bid0IGRpc2FibGUgdGhlbSB3aGF0IHdpbGwgaXQNCgkgY2F1c2U/DQoJDQoJQmVzdCBSZWdhcmRz
DQoJRW5vcm0NCgkNCgkNCgkNCgkNCg0K

^ permalink raw reply

* scc ethernet driver error - bus contention?
From: Lichang Che @ 2006-09-29  3:07 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 620 bytes --]

Hello,

 

I'm using Linux 2.6.16 + uboot on MPC8250 - SMC2 for UART and SCC4 for 10M
Ethernet. The problem I got is as follows:

 

1. If the GBL bit is set (with address snooping), an underrun happens for
each frame transmission.

 

2. If the GBL bit is disabled, the underrun problem disappears but nearly
all frames are corrupted - the frame can be received (without CRC etc) by
another machine but the data is not correct.

 

3. If the frame to be sent is copied into the dual port ram first and the
transmission is triggered, the frame can be successfully received.

 

Can anyone give me some hint?

 

Cheers


[-- Attachment #2: Type: text/html, Size: 3521 bytes --]

^ permalink raw reply

* RE: [PATCH 0/12] Add support for QE and 8360EMDS board -v2
From: Li Yang-r58472 @ 2006-09-29  3:21 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, paulus
In-Reply-To: <98C2C73A-F57B-49A6-9727-D76A1AE9746C@kernel.crashing.org>

> -----Original Message-----
> From: Kumar Gala [mailto:galak@kernel.crashing.org]
> Sent: Friday, September 29, 2006 12:37 AM
> To: Li Yang-r58472
> Cc: linuxppc-dev@ozlabs.org; paulus@samba.org
> Subject: Re: [PATCH 0/12] Add support for QE and 8360EMDS board -v2
>=20
>=20
> On Sep 28, 2006, at 11:09 AM, Li Yang wrote:
>=20
> > On 9/28/06, Kumar Gala <galak@kernel.crashing.org> wrote:
> >>
> >> On Sep 28, 2006, at 3:18 AM, Li Yang wrote:
> >>
> >> > Paul,
> >> >
> >> > The series of patches add generic QE infrastructure called
> >> > qe_lib, and MPC8360EMDS board support.  Qe_lib is used by
> >> > QE device drivers such as ucc_geth driver.
> >> >
> >> > This version updates QE interrupt controller to use new irq
> >> > mapping mechanism, addresses all the comments received with
> >> > last submission and includes some style fixes.
> >> >
> >> > v2 change: Change to use device tree for BCSR and MURAM;
> >> > Remove I/O port interrupt handling code as it is not generic
> >> > enough.
> >>
> >> Before accepting any of this code, I'd like to see what the drivers
> >> look like that are using it.  Its hard to make significant
> >> comments w/
> >> o seeing what the consumers of all the 'lib' code look like.
> >
> > Current in-tree user of the lib is driver/net/ucc_geth.c.  There is
> > also QE ATM driver which is included in Alex's 8360sar project.  QE
> > USB host/client drivers are in Freescale LTIB BSP.
>=20
> is there a serial driver?

No.  It is not very necessary to have serial support for QE, as there is
separate DUART SoC.  We can use 8250 serial driver for that.

- Leo

^ permalink raw reply

* Trouble with 2.6 Kernel
From: Glenn.G.Hart @ 2006-09-29  2:35 UTC (permalink / raw)
  To: linuxppc-embedded

I am trying to get Linux PPC 2.6.17.1 up and running on a Xilinx Virtex-4
FX 12 FPGA.  Everything appears to proceed normally, but at the end of the
kernel initialization it gives me a scheduling while atomic error.  I have
found on the web others having this problem, but without a good solution.
Do I have something configured wrong or do I need a patch.  The output of
the kernel is shown below.

  Thanks,
  Glenn

loaded at:     00400000 004E113C
board data at: 004DF124 004DF13C
relocated to:  004050EC 00405104
zimage at:     00405801 004DEC72
avail ram:     004E2000 10000000

Linux/PPC load: console=ttyS0,9600 console=tty0 root=/dev/sda2
Uncompressing Linux...done.
Now booting the kernel
Linux version 2.6.17.1 (root@AFedora3) (gcc version 3.4.5) #18 PREEMPT Thu
Sep 28 02:29:45 EDT 2006
Xilinx Virtex-II Pro port
Port by MontaVista Software, Inc. (source@mvista.com)
Built 1 zonelists
Kernel command line: console=ttyS0,9600 console=tty0 root=/dev/sda2
Xilinx INTC #0 at 0x41200000 mapped to 0xFDFFE000
PID hash table entries: 2048 (order: 11, 8192 bytes)
Console: colour dummy device 80x25
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 257792k available (1528k kernel code, 400k data, 84k init, 0k
highmem)
Mount-cache hash table entries: 512
NET: Registered protocol family 16
NET: Registered protocol family 2
IP route cache hash table entries: 2048 (order: 1, 8192 bytes)
TCP established hash table entries: 8192 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 8192 bind 4096)
TCP reno registered
io scheduler noop registered (default)
Serial: 8250/16550 driver $Revision: 1.90 $ 1 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0x40401003 (irq = 1) is a 16450
RAMDISK driver initialized: 1 RAM disks of 4096K size 1024 blocksize
loop: loaded (max 8 devices)
nbd: registered device at major 43
eth0: using fifo mode.
eth0: Xilinx EMAC #0 at 0x80400000 mapped to 0xD1000000, irq=0
eth0: id 2.0a; block id 0, type 8
mice: PS/2 mouse device common for all mice
ip_conntrack version 2.4 (2048 buckets, 16384 max) - 188 bytes per
conntrack
BUG: scheduling while atomic: swapper/0xffffffff/1
Call Trace:
[C0451E50] [C0008F20] show_stack+0x58/0x180 (unreliable)
[C0451E80] [C017AAC0] schedule+0x48/0x6e4
[C0451EB0] [C017B340] wait_for_completion+0xbc/0x158
[C0451EF0] [C003400C] synchronize_rcu+0x38/0x48
[C0451F30] [C01140D4] synchronize_net+0x10/0x20
[C0451F40] [C0124760] nf_register_hook+0xac/0xc0
[C0451F50] [C0124860] nf_register_hooks+0x34/0x7c
[C0451F70] [C01DD3C0] ip_conntrack_standalone_init+0xb8/0x154
[C0451F90] [C0002470] init+0xa4/0x280
[C0451FF0] [C00051FC] kernel_thread+0x44/0x60

^ permalink raw reply

* About cache
From: enorm @ 2006-09-29  1:25 UTC (permalink / raw)
  To: linuxppc-embedded

Hi,

I found in mpc85xx start.s, before doing any initialization it disabled 
 i-cache & d-cache. Must we do so? If we don't disable them what will it 
 cause? 

Best Regards
Enorm

^ permalink raw reply

* [PATCH] Preliminary MPIC MSI backend
From: Michael Ellerman @ 2006-09-29  0:16 UTC (permalink / raw)
  To: linux-kernel; +Cc: linuxppc-dev, Eric W. Biederman
In-Reply-To: <1159486661.25820.1.camel@localhost.localdomain>

A pretty hackish MPIC backend, just enough to flesh out the design.
Based on code from Segher.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/kernel/Makefile   |    1 
 arch/powerpc/kernel/msi-mpic.c |   92 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+)

Index: to-merge/arch/powerpc/kernel/Makefile
===================================================================
--- to-merge.orig/arch/powerpc/kernel/Makefile
+++ to-merge/arch/powerpc/kernel/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32
 
 msiobj-y			:= msi.o
 msiobj-$(CONFIG_PPC_PSERIES)	+= msi-rtas.o
+msiobj-$(CONFIG_PPC_PMAC)	+= msi-mpic.o
 obj-$(CONFIG_PCI_MSI)		+= $(msiobj-y)
 
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
Index: to-merge/arch/powerpc/kernel/msi-mpic.c
===================================================================
--- /dev/null
+++ to-merge/arch/powerpc/kernel/msi-mpic.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006 Segher Boessenkool, IBM Corp.
+ * Copyright (C) 2006 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#define DEBUG 1
+
+#include <linux/irq.h>
+#include <asm/msi.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int msi_mpic_check(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	/* The irq allocator needs more work to support MSI-X/multi-MSI */
+	if (type == PCI_CAP_ID_MSIX || num != 1)
+		return 1;
+
+	return 0;
+}
+
+static void msi_mpic_free(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	int i;
+
+	for (i = 0; i < num; i++)
+		irq_dispose_mapping(entries[i].vector);
+}
+
+static int msi_mpic_alloc(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	irq_hw_number_t hwirq;
+	unsigned int virq;
+
+	/* We need a smarter allocator for MSI-X/multi-MSI */
+	hwirq = irq_map[pdev->irq].hwirq;
+	hwirq += 100;
+
+	virq = irq_create_mapping(NULL, hwirq);
+	if (virq == NO_IRQ) {
+		pr_debug("msi_mpic_alloc: Failed mapping hwirq %lu\n", hwirq);
+		return -1;
+	}
+
+	set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+	entries[0].vector = virq;
+
+	return 0;
+}
+
+static int msi_mpic_setup_msi_msg(struct pci_dev *pdev,
+		struct msix_entry *entry, struct msi_msg *msg, int type)
+{
+	msg->address_lo = 0xfee00000;	/* XXX What is this value? */
+	msg->address_hi = 0;
+	msg->data = pdev->irq | 0x8000;
+
+	return 0;
+}
+
+static struct ppc_msi_ops mpic_msi_ops = {
+	.check = msi_mpic_check,
+	.alloc = msi_mpic_alloc,
+	.free = msi_mpic_free,
+	.enable = msi_raw_enable,
+	.disable = msi_raw_disable,
+	.setup_msi_msg = msi_mpic_setup_msi_msg,
+};
+
+static struct ppc_msi_ops *mpic_get_msi_ops(struct pci_dev *pdev)
+{
+	return &mpic_msi_ops;
+}
+
+static int msi_mpic_init(void)
+{
+	/* XXX Do this in mpic_init ? */
+	pr_debug("mpic_msi_init: Registering MPIC MSI ops.\n");
+	ppc_md.get_msi_ops = mpic_get_msi_ops;
+
+	return 0;
+}
+__initcall(msi_mpic_init);

^ permalink raw reply

* Re: [RFC/PATCH 7/7] Preliminary MPIC MSI backend
From: Michael Ellerman @ 2006-09-28 23:37 UTC (permalink / raw)
  To: linux-kernel; +Cc: linuxppc-dev, Eric W. Biederman
In-Reply-To: <20060928215349.45C0667C47@ozlabs.org>

[-- Attachment #1: Type: text/plain, Size: 530 bytes --]

On Fri, 2006-09-29 at 07:53 +1000, Michael Ellerman wrote:
> A pretty hackish MPIC backend, just enough to flesh out the design.
> Based on code from Segher.
> 
> Signed-off-by: Michael Ellerman <michael@ellerman.id.au>

Missing a quilt ref, new one coming RSN.

cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]

^ permalink raw reply

* Support for Linux Trace Tool (ltt)
From: Bizhan Gholikhamseh (bgholikh) @ 2006-09-28 23:01 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 123 bytes --]

Hi All,
Is there any support for Linux ltt on Linux 2.6 (perfably 2.6.11) for
ppc architecture (MPC8541E)?
Thanks,
BG

[-- Attachment #2: Type: text/html, Size: 684 bytes --]

^ permalink raw reply

* mount-  crashes with sig-11 error - linux-2.6.16.2
From: agnel juni @ 2006-09-28 22:51 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <45179FF7.3000400@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 6722 bytes --]


Hi
 
 We are using linux-2.6.16.2. We are trying to mount the compact flash (64MB) with FAT16 filesystem, using system ACE driver.
 
 We are able to run filesystem check, partition the CF etc, but the issue is with mount.
 
 'Mount' shows inconsistent results, meaning mount crashes with sig-11 error. Sametime when it succeeds we are able to copy/read/ and remove files from the CF.
 
 Please find the screen-dump of the kernel oops below:
 
 Any help is greatly appreciated.
 
 /******************* screen-dump*******************/
 Oops: kernel access of bad area, sig: 11 [#1]
 NIP: C004AD4C LR: C004CF98 CTR: 0FF050A0
 REGS: dfd8ddf8 TRAP: 0300   Not tainted  (2.6.16.2)
 MSR: 00029000 <EE,ME>  CR: 84004024  XER: 20000000
 DAR: 00000008, DSISR: 00000000
 TASK = dfc93450[620] 'exe' THREAD: dfd8c000
 GPR00: C004CF98 DFD8DEA8 DFC93450 DFD610CC DFF7D000 00000000 00029000 DFD8C000
 GPR08: C024D1F4 00000004 00000007 DFF7D090 24004022 10062C0C 00000000 00000000
 GPR16: 00000000 7FE73BA0 10060000 10060000 1006F650 10060000 1006F520 00000000
 GPR24: 1005AC48 10036970 00000005 1003EE68 DFC93450 00000000 00000000 DFD610CC
 NIP [C004AD4C] remove_vma+0x24/0x9c
 LR [C004CF98] exit_mmap+0xb4/0xec
 Call Trace:
 [DFD8DEA8] [C004ADA0] remove_vma+0x78/0x9c (unreliable)
 [DFD8DEB8] [C004CF98] exit_mmap+0xb4/0xec
 [DFD8DED8] [C0016CEC] mmput+0x50/0xd4
 [DFD8DEE8] [C001B2D8] exit_mm+0x120/0x1a0
 [DFD8DF00] [C001B914] do_exit+0x11c/0x77c
 [DFD8DF38] [C001BFB0] do_group_exit+0x0/0x80
 [DFD8DF40] [C0001BC4] ret_from_syscall+0x0/0x3c
 Instruction dump:
 4d9e0020 80a40080 4bffff58 7c0802a6 9421fff0 bfc10008 7c7f1b78 90010014
 81230044 83c3000c 2f890000 419e0010 <80090004> 2f800000 409e0064 807f004c
 Fixing recursive fault but reboot is needed!
 Oops: kernel access of bad area, sig: 11 [#2]
 NIP: C00556B8 LR: C00557E4 CTR: 00000000
 REGS: dfdbfe08 TRAP: 0300   Not tainted  (2.6.16.2)
 MSR: 00021000 <ME>  CR: 22008028  XER: 00000000
 DAR: 00000000, DSISR: 00800000
 TASK = dff6c030[4] 'events/0' THREAD: dfdbe000
 GPR00: 00100100 DFDBFEB8 DFF6C030 C0258D20 DFF7D010 00000018 DFD61000 C0256E20
 GPR08: 00000000 00200200 DFD61EE4 C0256E28 C0220000 10062C0C 1FFB9700 00000000
 GPR16: 00000001 FFFFFFFF 00000000 007FFF00 1FFB3604 1FF63CE0 1FFCEF78 C01F0000
 GPR24: C0240000 00100100 C0240000 00000000 DFF7D010 00000018 00000002 C0258D20
 NIP [C00556B8] free_block+0xa8/0x148
 LR [C00557E4] drain_array_locked+0x8c/0xd8
 Call Trace:
 [DFDBFEB8] [C0055338] kmem_freepages+0x98/0xdc (unreliable)
 [DFDBFED8] [C00557E4] drain_array_locked+0x8c/0xd8
 [DFDBFEF0] [C0056F80] cache_reap+0x74/0x18c
 [DFDBFF28] [C002B578] run_workqueue+0x9c/0x110
 [DFDBFF48] [C002B6E4] worker_thread+0xf8/0x13c
 [DFDBFFC0] [C002F6F0] kthread+0xf4/0x130
 [DFDBFFF0] [C000413C] kernel_thread+0x44/0x60
 Instruction dump:
 7cfbfa14 3c000010 80e70014 3d2a4000 60000100 5529c9f4 7d295a14 80c9001c
 3d200020 61290200 81060004 81660000 <91680000> 910b0004 3966001c 90060000
 BUG: events/0/4, lock held at task exit time!
  [c01f5d60] {cache_chain_mutex}
 .. held by:          events/0:    4 [dff6c030, 110]
 ... acquired at:               cache_reap+0x1c/0x18c
 
 
 Thanks
 Junita
 
 
 
 
Ameet Patil <ammubhai@gmail.com> wrote: agnel juni wrote:
> Hi Ameet
>
> I have posted a few messages regarding Ssytem ACE driver for Linux-2.6.
>
> We are working on a AMCC 440SPe based custom board.
>
> We applied the patch from
> //http://www.cs.york.ac.uk/rtslab/demos/amos/xupv2pro/patches/linuxppc-2.6.17.1-sysace-1.2.patch
>  //and applied against 2.6.16-2 kernel.
>
> We are trying to make the driver work in interrupt mode.
>
> First, I would like to know if the driver tested in interrupt mode.
>
> We are able to mount the CF, but it is very inconsistent.
>
> Same is the case with fdisk command. When it fails,we get errors which you could see in the screen-dump below.//
> //
> Are we missing to apply the right patch? Please let us know your 
> inputs to go forward.
> Looking forwards for your reply.
>
> Thanks
> Junita
>
> /*************** Screen dump ********************/
> # fdisk /dev/xsysace
> 1. sector = 0 xsa_cur_req->sector=0
> System ACE: Error 0 when reading sector 2.
> 2. sector = 2 xsa_cur_req->sector=16
> end_request: I/O error, System ACE: Error 0 when reading sectoru dev 
> xsa, sector 16
> Buffer I/O error on device xsa, logical block 2
> 1. sector = 184 xsa_cur_req->sector=184
>  
> Command (m for help): p
>  
> Disk /dev/xsysace: 524 MB, 524869632 bytes
> 17 heads, 59 sectors/track, 1022 cylinders
> Units = cylinders of 1003 * 512 = 513536 bytes
>  
>        Device Boot      Start         End      Blocks   Id  System
> /dev/xsysace1               1        1022      512503+   6  FAT16
>  
> Command (m for help): q
> And for 'mount'
> #
> #
> # mount -t msdos /dev/xsysace /root/cf
> 1. sector = 0 xsa_cur_req->sector=0
> 1. sector = 503 xsa_cur_req->sector=503
> 1. sector = 504 xsa_cur_req->sector=504
> 1. sector = 506 xsa_cur_req->sector=506
> 1. sector = 508 xsa_cur_req->sector=508
> 1. sector = 510 xsa_cur_req->sector=510
> # cd /root/cf
> < Here Prints Some Symbols like + - etc, which i am
>   not able to capture/copy -------------ERROR
> b: No such file or directory--------------------------------ERROR
> pci.h
> #
> Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.n0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.0Minicom2.00.d#
> # cp pci.h /root/
> # cd ../
> # ls
> app     cf      hello1  pci.h
> #
> #/root
>  /dev/xsysace /root/cf
> FAT: bogus number of reserved sectors
> VFS: Can't find a valid FAT filesystem on dev xsa.
> mount: Mounting /dev/xsysace on /root/cf failed: Invalid argument
> #
>  
>
>
> //
>
>
>
> //
>
> ------------------------------------------------------------------------
> Find out what India is talking about on - Yahoo! Answers India 
> 
> Send FREE SMS to your friend's mobile from Yahoo! Messenger Version 8. 
> Get it NOW 
>  


Hi Agnel,
    The driver was last tested with 2.6.17 kernel and till date works 
fine in the interrupt mode. I have been using it since the last 4 months 
now. It should also work on 2.6.16-2 kernel I think, but I have not 
tested this. Have you made any changes to the driver? If so... please 
give the details so I can give you better feedback as to where things 
might have gone wrong. When time permits I shall try my patch on the 
2.6.16-2 kernel and let you know if it works for me.

Thanks,
-Ameet


 				
---------------------------------
 Find out what India is talking about on  - Yahoo! Answers India 
 Send FREE SMS to your friend's mobile from Yahoo! Messenger Version 8. Get it NOW

[-- Attachment #2: Type: text/html, Size: 8109 bytes --]

^ permalink raw reply

* [RFC/PATCH 7/7] Preliminary MPIC MSI backend
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>

A pretty hackish MPIC backend, just enough to flesh out the design.
Based on code from Segher.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/kernel/Makefile   |    1 
 arch/powerpc/kernel/msi-mpic.c |   90 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)

Index: to-merge/arch/powerpc/kernel/Makefile
===================================================================
--- to-merge.orig/arch/powerpc/kernel/Makefile
+++ to-merge/arch/powerpc/kernel/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32
 
 msiobj-y			:= msi.o
 msiobj-$(CONFIG_PPC_PSERIES)	+= msi-rtas.o
+msiobj-$(CONFIG_PPC_PMAC)	+= msi-mpic.o
 obj-$(CONFIG_PCI_MSI)		+= $(msiobj-y)
 
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
Index: to-merge/arch/powerpc/kernel/msi-mpic.c
===================================================================
--- /dev/null
+++ to-merge/arch/powerpc/kernel/msi-mpic.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2006 Segher Boessenkool, IBM Corp.
+ * Copyright (C) 2006 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#define DEBUG 1
+
+#include <linux/irq.h>
+#include <asm/msi.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int msi_mpic_check(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	/* The irq allocator needs more work to support MSI-X/multi-MSI */
+	if (type == PCI_CAP_ID_MSIX || num != 1)
+		return 1;
+
+	return 0;
+}
+
+static void msi_mpic_free(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	for (i = 0; i < num; i++)
+		irq_dispose_mapping(entries[i].vector);
+}
+
+static int msi_mpic_alloc(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	irq_hw_number_t hwirq;
+	unsigned int virq;
+
+	/* We need a smarter allocator for MSI-X/multi-MSI */
+	hwirq = irq_map[pdev->irq].hwirq;
+	hwirq += 100;
+
+	virq = irq_create_mapping(NULL, hwirq);
+	if (virq == NO_IRQ) {
+		pr_debug("msi_mpic_alloc: Failed mapping hwirq %d\n", hwirq);
+		return -1;
+	}
+
+	set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+	entries[i].vector = virq;
+
+	return 0;
+}
+
+static int msi_mpic_setup_msi_msg(struct pci_dev *pdev,
+		struct msix_entry *entry, struct msi_msg *msg, int type)
+{
+	msg->address_lo = 0xfee00000;	/* XXX What is this value? */
+	msg->address_hi = 0;
+	msg->data = pdev->irq | 0x8000;
+
+	return 0;
+}
+
+static struct ppc_msi_ops mpic_msi_ops = {
+	.check = msi_mpic_check,
+	.alloc = msi_mpic_alloc,
+	.free = msi_mpic_free
+	.enable = msi_raw_enable,
+	.disable = msi_raw_disable,
+	.setup_msi_msg = msi_mpic_setup_msi_msg,
+};
+
+static struct ppc_msi_ops *mpic_get_msi_ops(struct pci_dev *pdev)
+{
+	return &mpic_msi_ops;
+}
+
+static int msi_mpic_init(void)
+{
+	/* XXX Do this in mpic_init ? */
+	pr_debug("mpic_msi_init: Registering MPIC MSI ops.\n");
+	ppc_md.get_msi_ops = mpic_get_msi_ops;
+
+	return 0;
+}
+__initcall(msi_mpic_init);

^ permalink raw reply

* [RFC/PATCH 6/7] RTAS MSI implementation
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>

Powerpc MSI support via RTAS. Based on Jake's code.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/kernel/Makefile   |    1 
 arch/powerpc/kernel/msi-rtas.c |  246 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 247 insertions(+)

Index: to-merge/arch/powerpc/kernel/Makefile
===================================================================
--- to-merge.orig/arch/powerpc/kernel/Makefile
+++ to-merge/arch/powerpc/kernel/Makefile
@@ -69,6 +69,7 @@ pci32-$(CONFIG_PPC32)		:= pci_32.o
 obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32-y)
 
 msiobj-y			:= msi.o
+msiobj-$(CONFIG_PPC_PSERIES)	+= msi-rtas.o
 obj-$(CONFIG_PCI_MSI)		+= $(msiobj-y)
 
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
Index: to-merge/arch/powerpc/kernel/msi-rtas.c
===================================================================
--- /dev/null
+++ to-merge/arch/powerpc/kernel/msi-rtas.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2006 Jake Moilanen <moilanen@austin.ibm.com>, IBM Corp.
+ * Copyright (C) 2006 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#define DEBUG 1
+
+#include <linux/irq.h>
+#include <asm/msi.h>
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int query_token, change_token;
+
+#define RTAS_QUERY_MSI_FN	0
+#define RTAS_CHANGE_MSI_FN	1
+#define RTAS_RESET_MSI_FN	2
+
+
+/* RTAS Helpers */
+
+static int rtas_change_msi(struct pci_dn *pdn, u32 function, u32 num_irqs)
+{
+	u32 addr, seq_num, rtas_ret[2];
+	unsigned long buid;
+	int rc;
+
+	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+	buid = pdn->phb->buid;
+
+	seq_num = 1;
+	do {
+		rc = rtas_call(change_token, 6, 3, rtas_ret, addr,
+				BUID_HI(buid), BUID_LO(buid),
+				function, num_irqs, seq_num);
+
+		seq_num = rtas_ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		printk(KERN_WARNING "Error[%d]: getting the number of"
+			" MSI interrupts for %s\n", rc, pci_name(pdn->pcidev));
+		return rc;
+	}
+
+	return rtas_ret[0];
+}
+
+static int rtas_query_irq_number(struct pci_dn *pdn, int offset)
+{
+	u32 addr, rtas_ret[2];
+	unsigned long buid;
+	int rc;
+
+	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+	buid = pdn->phb->buid;
+
+	do {
+		rc = rtas_call(query_token, 4, 3, rtas_ret, addr,
+			       BUID_HI(buid), BUID_LO(buid), offset);
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		printk(KERN_WARNING "Error[%d]: Querying irq source number "
+				"for %s\n", rc, pci_name(pdn->pcidev));
+		return rc;
+	}
+
+	return rtas_ret[0];
+}
+
+/*
+ * The spec gives firmware the option to enable either MSI or MSI-X,
+ * this doesn't wash with the Linux API. For the time beinging, we
+ * kludge around that by checking ourselves the right type is enabled.
+ */
+static int check_msi_type(struct pci_dev *pdev, int type)
+{
+	int pos, msi_enabled, msix_enabled;
+	u16 reg;
+
+	pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
+	if (!pos)
+		return -1;
+
+	pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &reg);
+
+	msi_enabled = msix_enabled = 0;
+
+	if (reg & PCI_MSI_FLAGS_ENABLE)
+		msi_enabled = 1;
+
+	if (reg & PCI_MSIX_FLAGS_ENABLE)
+		msix_enabled = 1;
+
+	if (type == PCI_CAP_ID_MSI && (msix_enabled || !msi_enabled)) {
+		pr_debug("check_msi_type: Expected MSI but got %s.\n",
+			msix_enabled ? "MSI-X" : "none");
+		return -1;
+	}
+
+	if (type == PCI_CAP_ID_MSIX && (msi_enabled || !msix_enabled)) {
+		pr_debug("check_msi_type: Expected MSI-X but got %s.\n",
+			msi_enabled ? "MSI" : "none");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void msi_rtas_free(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	struct device_node *dn;
+	struct pci_dn *pdn;
+	int i;
+
+	dn = pci_device_to_OF_node(pdev);
+	if (!dn) {
+		pr_debug("msi_rtas_free: No OF device node for %s\n",
+				pci_name(pdev));
+		return;
+	}
+
+	pdn = PCI_DN(dn);
+	if (!pdn) {
+		pr_debug("msi_rtas_free: No PCI DN for %s\n",
+				pci_name(pdev));
+		return;
+	}
+
+	for (i = 0; i < num; i++) {
+		irq_dispose_mapping(entries[i].vector);
+	}
+
+	/* XXX can we do anything sane if this fails? */
+	rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, 0);
+}
+
+static int msi_rtas_check(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	struct device_node *dn;
+	int i;
+
+	dn = pci_device_to_OF_node(pdev);
+
+	if (!of_find_property(dn, "ibm,req#msi", NULL)) {
+		pr_debug("msi_rtas_check: No ibm,req#msi for %s\n",
+				pci_name(pdev));
+		return -1;
+	}
+
+	/*
+	 * Firmware gives us no control over which entries are allocated
+	 * for MSI-X, it seems to assume we want 0 - n. For now just insist
+	 * that the entries array entry members are 0 - n.
+	 */
+	for (i = 0; i < num; i++) {
+		if (entries[i].entry != i) {
+			pr_debug("msi_rtas_check: entries[i].entry != i\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int msi_rtas_alloc(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	struct pci_dn *pdn;
+	int hwirq, virq, i;
+
+	pdn = PCI_DN(pci_device_to_OF_node(pdev));
+
+	/*
+	 * In the case of an error it's not clear whether the device is left
+	 * with MSI enabled or not, I think we should explicitly disable.
+	 */
+	if (rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, num) != num)
+		goto out_free;
+
+	if (check_msi_type(pdev, type))
+		goto out_free;
+
+	for (i = 0; i < num; i++) {
+		hwirq = rtas_query_irq_number(pdn, i);
+		if (hwirq < 0)
+			goto out_free;
+
+		virq = irq_create_mapping(NULL, hwirq);
+
+		if (virq == NO_IRQ) {
+			pr_debug("msi_rtas_alloc: Failed mapping hwirq %d\n",
+				hwirq);
+			goto out_free;
+		}
+
+		entries[i].vector = virq;
+	}
+
+	return 0;
+
+ out_free:
+	msi_rtas_free(pdev, num, entries, type);
+	return -1;
+}
+
+static struct ppc_msi_ops rtas_msi_ops = {
+	.check = msi_rtas_check,
+	.alloc = msi_rtas_alloc,
+	.free  = msi_rtas_free
+};
+
+static struct ppc_msi_ops *rtas_get_msi_ops(struct pci_dev *pdev)
+{
+	return &rtas_msi_ops;
+}
+
+static int msi_rtas_init(void)
+{
+	query_token  = rtas_token("ibm,query-interrupt-source-number");
+	change_token = rtas_token("ibm,change-msi");
+
+	if ((query_token == RTAS_UNKNOWN_SERVICE) ||
+			(change_token == RTAS_UNKNOWN_SERVICE)) {
+		pr_debug("rtas_msi_init: Couldn't find RTAS tokens, no "
+				"MSI support available.\n");
+		return 0;
+	}
+
+	pr_debug("rtas_msi_init: Registering RTAS MSI ops.\n");
+
+	ppc_md.get_msi_ops = rtas_get_msi_ops;
+
+	return 0;
+}
+__initcall(msi_rtas_init);

^ permalink raw reply

* [RFC/PATCH 5/7] Enable MSI on Powerpc
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>

Allow PCI_MSI to build on Powerpc.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/kernel/Makefile |    4 ++++
 drivers/pci/Kconfig          |    2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

Index: to-merge/arch/powerpc/kernel/Makefile
===================================================================
--- to-merge.orig/arch/powerpc/kernel/Makefile
+++ to-merge/arch/powerpc/kernel/Makefile
@@ -67,6 +67,10 @@ pci64-$(CONFIG_PPC64)		+= pci_64.o pci_d
 				   pci_direct_iommu.o iomap.o
 pci32-$(CONFIG_PPC32)		:= pci_32.o
 obj-$(CONFIG_PCI)		+= $(pci64-y) $(pci32-y)
+
+msiobj-y			:= msi.o
+obj-$(CONFIG_PCI_MSI)		+= $(msiobj-y)
+
 kexec-$(CONFIG_PPC64)		:= machine_kexec_64.o
 kexec-$(CONFIG_PPC32)		:= machine_kexec_32.o
 obj-$(CONFIG_KEXEC)		+= machine_kexec.o crash.o $(kexec-y)
Index: to-merge/drivers/pci/Kconfig
===================================================================
--- to-merge.orig/drivers/pci/Kconfig
+++ to-merge/drivers/pci/Kconfig
@@ -4,7 +4,7 @@
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
-	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || PPC
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to

^ permalink raw reply

* [RFC/PATCH 4/7] Allow for non-Intel MSI implementations
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 drivers/pci/Makefile |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Index: to-merge/drivers/pci/Makefile
===================================================================
--- to-merge.orig/drivers/pci/Makefile
+++ to-merge/drivers/pci/Makefile
@@ -27,7 +27,8 @@ obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 
-msiobj-y := msi.o msi-apic.o
+msiobj-$(CONFIG_X86) := msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) := 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)

^ permalink raw reply

* [RFC/PATCH 3/7] Powerpc MSI ops layer
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>

Powerpc MSI ops layer.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/kernel/msi.c        |  347 +++++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/machdep.h    |    6 
 include/asm-powerpc/msi.h        |  175 +++++++++++++++++++
 include/asm-powerpc/pci-bridge.h |    4 
 4 files changed, 532 insertions(+)

Index: to-merge/arch/powerpc/kernel/msi.c
===================================================================
--- /dev/null
+++ to-merge/arch/powerpc/kernel/msi.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2006 (C), Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <asm/msi.h>
+#include <asm/machdep.h>
+
+static struct ppc_msi_ops *get_msi_ops(struct pci_dev *pdev)
+{
+	if (ppc_md.get_msi_ops)
+		return ppc_md.get_msi_ops(pdev);
+	return NULL;
+}
+
+/* Activated by pci=nomsi on the command line. */
+static int no_msi;
+
+void pci_no_msi(void)
+{
+	no_msi = 1;
+}
+
+
+/* msi_info helpers */
+
+static struct pci_dn *get_pdn(struct pci_dev *pdev)
+{
+	struct device_node *dn;
+	struct pci_dn *pdn;
+
+	dn = pci_device_to_OF_node(pdev);
+	if (!dn) {
+		pr_debug("get_pdn: no dn found for %s\n", pci_name(pdev));
+		return NULL;
+	}
+
+	pdn = PCI_DN(dn);
+	if (!pdn) {
+		pr_debug("get_pdn: no pci_dn found for %s\n", pci_name(pdev));
+		return NULL;
+	}
+
+	return pdn;
+}
+
+static int alloc_msi_info(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	struct msi_info *info;
+	unsigned int entries_size;
+	struct pci_dn *pdn;
+
+	entries_size = sizeof(struct msix_entry) * num;
+
+	info = kzalloc(sizeof(struct msi_info) + entries_size, GFP_KERNEL);
+	if (!info) {
+		pr_debug("alloc_msi_info: kzalloc failed for %s\n",
+				pci_name(pdev));
+		return -ENOMEM;
+	}
+
+	info->type = type;
+	info->num = num;
+	memcpy(info->entries, entries, entries_size);
+
+	pdn = get_pdn(pdev);
+	if (!pdn || pdn->msi_info)	/* don't leak info structs */
+		BUG();
+
+	pdn->msi_info = info;
+
+	return 0;
+}
+
+static struct msi_info *get_msi_info(struct pci_dev *pdev)
+{
+	struct pci_dn *pdn;
+
+	pdn = get_pdn(pdev);
+	if (!pdn)
+		return NULL;
+
+	return pdn->msi_info;
+}
+
+static void free_msi_info(struct pci_dev *pdev)
+{
+	struct pci_dn *pdn;
+
+	pdn = get_pdn(pdev);
+	if (!pdn) {
+		pr_debug("free_msi_info: No pdn for %s\n", pci_name(pdev));
+		return;
+	}
+
+	kfree(pdn->msi_info);
+	pdn->msi_info = NULL;
+}
+
+
+/* Generic helpers */
+
+static int generic_msi_enable(struct pci_dev *pdev, int nvec,
+				struct msix_entry *entries, int type)
+{
+	struct ppc_msi_ops *ops;
+	int i, rc;
+
+	if (no_msi || !pdev || !entries || !nvec || !get_pdn(pdev)
+			|| get_msi_info(pdev))
+		return -EINVAL;
+
+	ops = get_msi_ops(pdev);
+	if (!ops)
+		return -EINVAL;
+
+	for (i = 0; i < nvec; i++)
+		entries[i].vector = NO_IRQ;
+
+	rc = ops->check(pdev, nvec, entries, type);
+	if (rc) {
+		pr_debug("generic_msi_enable: check failed (%d) for %s\n",
+			rc, pci_name(pdev));
+		return rc;
+	}
+
+	rc = ops->alloc(pdev, nvec, entries, type);
+	if (rc) {
+		pr_debug("generic_msi_enable: alloc failed (%d) for %s\n",
+			rc, pci_name(pdev));
+		return rc;
+	}
+
+	if (ops->enable) {
+		rc = ops->enable(pdev, nvec, entries, type);
+		if (rc) {
+			pr_debug("generic_msi_enable: enable failed (%d) "
+				"for %s\n", rc, pci_name(pdev));
+			goto out_free;
+		}
+	}
+
+	rc = alloc_msi_info(pdev, nvec, entries, type);
+	if (rc)
+		goto out_free;
+
+	return 0;
+
+ out_free:
+	ops->free(pdev, nvec, entries, type);
+
+	return rc;
+}
+
+static int generic_msi_disable(struct pci_dev *pdev, int type)
+{
+	struct ppc_msi_ops *ops;
+	struct msi_info *info;
+
+	if (no_msi || !pdev || !get_pdn(pdev))
+		return -1;
+
+	info = get_msi_info(pdev);
+	if (!info) {
+		pr_debug("generic_msi_disable: No info for %s\n",
+			pci_name(pdev));
+		return -1;
+	}
+
+	ops = get_msi_ops(pdev);
+	if (!ops)
+		return -1;
+
+	if (ops->disable)
+		ops->disable(pdev, info->num, info->entries, type);
+
+	ops->free(pdev, info->num, info->entries, type);
+
+	return 0;
+}
+
+
+/* MSI */
+
+int pci_enable_msi(struct pci_dev *pdev)
+{
+	struct msix_entry entry;
+	int rc;
+
+	entry.entry = 0;
+
+	rc = generic_msi_enable(pdev, 1, &entry, PCI_CAP_ID_MSI);
+	if (rc)
+		return rc;
+
+	get_msi_info(pdev)->saved_irq = pdev->irq;
+	pdev->irq = entry.vector;
+	pdev->msi_enabled = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pci_enable_msi);
+
+void pci_disable_msi(struct pci_dev *pdev)
+{
+	if (generic_msi_disable(pdev, PCI_CAP_ID_MSI) != 0)
+		return;
+
+	pdev->irq = get_msi_info(pdev)->saved_irq;
+	free_msi_info(pdev);
+	pdev->msi_enabled = 0;
+}
+EXPORT_SYMBOL_GPL(pci_disable_msi);
+
+
+/* MSI-X */
+
+int pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nvec)
+{
+	int rc;
+
+	rc = generic_msi_enable(pdev, nvec, entries, PCI_CAP_ID_MSIX);
+	if (rc)
+		return rc;
+
+	pdev->msix_enabled = 1;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pci_enable_msix);
+
+void pci_disable_msix(struct pci_dev *pdev)
+{
+	if (generic_msi_disable(pdev, PCI_CAP_ID_MSIX) != 0)
+		return;
+
+	free_msi_info(pdev);
+	pdev->msix_enabled = 0;
+}
+EXPORT_SYMBOL_GPL(pci_disable_msix);
+
+
+/* Stubs for now */
+
+void disable_msi_mode(struct pci_dev *dev, int pos, int type)
+{
+	return;
+}
+
+void pci_scan_msi_device(struct pci_dev *dev)
+{
+	return;
+}
+
+void msi_remove_pci_irq_vectors(struct pci_dev* dev)
+{
+	return;
+}
+
+
+/* Bare metal enable/disable */
+
+int msi_raw_enable(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	struct ppc_msi_ops *ops;
+	struct msi_msg msg;
+	int pos;
+	u16 control;
+
+	pos = pci_find_capability(pdev, type);
+	if (!pos)
+		return -1;
+
+	ops = get_msi_ops(pdev);
+	BUG_ON(!ops);
+
+	pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &control);
+
+	switch (type) {
+	case PCI_CAP_ID_MSI:
+		BUG_ON(!ops->setup_msi_msg);
+
+		ops->setup_msi_msg(pdev, &entries[0], &msg, type);
+
+		pci_write_config_dword(pdev, pos + PCI_MSI_ADDRESS_LO,
+			msg.address_lo);
+
+		if (control & PCI_MSI_FLAGS_64BIT) {
+			pci_write_config_dword(pdev, pos + PCI_MSI_ADDRESS_HI,
+						msg.address_hi);
+			pci_write_config_dword(pdev, pos + PCI_MSI_DATA_64,
+						msg.data);
+		} else {
+			pci_write_config_dword(pdev, pos + PCI_MSI_DATA_32,
+						msg.data);
+		}
+
+		control |= PCI_MSI_FLAGS_ENABLE;
+		break;
+	case PCI_CAP_ID_MSIX:
+		/* XXX implement me */
+		BUG();
+		break;
+	default:
+		BUG();
+	}
+
+	pci_write_config_word(pdev, pos + PCI_MSI_FLAGS, control);
+
+	return 0;
+}
+
+void msi_raw_disable(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type)
+{
+	int pos;
+	u16 control;
+
+	pos = pci_find_capability(pdev, type);
+	BUG_ON(!pos);
+
+	pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &control);
+
+	switch (type) {
+	case PCI_CAP_ID_MSI:
+		control &= ~PCI_MSI_FLAGS_ENABLE;
+		break;
+	case PCI_CAP_ID_MSIX:
+		control &= ~PCI_MSIX_FLAGS_ENABLE;
+		break;
+	default:
+		BUG();
+	}
+
+	pci_write_config_word(pdev, pos + PCI_MSI_FLAGS, control);
+
+	return;
+}
Index: to-merge/include/asm-powerpc/machdep.h
===================================================================
--- to-merge.orig/include/asm-powerpc/machdep.h
+++ to-merge/include/asm-powerpc/machdep.h
@@ -29,6 +29,9 @@ struct file;
 #ifdef CONFIG_KEXEC
 struct kimage;
 #endif
+#ifdef CONFIG_PCI_MSI
+struct ppc_msi_ops;
+#endif
 
 #ifdef CONFIG_SMP
 struct smp_ops_t {
@@ -106,6 +109,9 @@ struct machdep_calls {
 	/* Called after scanning the bus, before allocating resources */
 	void		(*pcibios_fixup)(void);
 	int		(*pci_probe_mode)(struct pci_bus *);
+#ifdef CONFIG_PCI_MSI
+	struct ppc_msi_ops*	(*get_msi_ops)(struct pci_dev *pdev);
+#endif
 
 	void		(*restart)(char *cmd);
 	void		(*power_off)(void);
Index: to-merge/include/asm-powerpc/msi.h
===================================================================
--- /dev/null
+++ to-merge/include/asm-powerpc/msi.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2006 Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _ASM_POWERPC_MSI_H
+#define _ASM_POWERPC_MSI_H
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <linux/pci.h>
+
+struct msi_msg {
+	u32	address_lo;	/* low 32 bits of msi message address */
+	u32	address_hi;	/* high 32 bits of msi message address */
+	u32	data;		/* 32 bits of msi message data */
+};
+
+/*
+ * MSI and MSI-X although different in some details, are also similar in
+ * many respects, and ultimately achieve the same end. Given that, this code
+ * tries as far as possible to implement both MSI and MSI-X with a minimum
+ * of code duplication. We will use "MSI" to refer to both MSI and MSI-X,
+ * except where it is important to differentiate between the two.
+ *
+ * Enabling MSI for a device can be broken down into:
+ *  1) Checking the device can support the type/number of MSIs requested.
+ *  2) Allocating irqs for the MSIs and setting up the irq_descs.
+ *  3) Writing the appropriate configuration to the device and enabling MSIs.
+ *
+ * To implement that we have the following callbacks:
+ *  1) check(pdev, num, msix_entries, type)
+ *  2) alloc(pdev, num, msix_entries, type)
+ *  3) enable(pdev, num, msix_entries, type)
+ *	a) setup_msi_msg(pdev, msix_entry, msi_msg, type)
+ *
+ * We give platforms full control over the enable step. However many
+ * platforms will simply want to program the device using standard PCI
+ * accessors. These platforms can use a generic enable callback and define
+ * a setup_msi_msg() callback which simply fills in the "magic" address and
+ * data values. Other platforms may leave setup_msi_msg() empty.
+ *
+ * Disabling MSI requires:
+ *  1) Disabling MSI on the device.
+ *  2) Freeing the irqs and any associated accounting information.
+ *
+ * Which maps directly to the two callbacks:
+ *  1) disable(pdev, num, msix_entries, type)
+ *  2) free(pdev, num, msix_entries, type)
+ */
+
+struct ppc_msi_ops
+{
+	/* check - Check that the requested MSI allocation is OK.
+	 *
+	 * @pdev:	PCI device structure.
+	 * @num:	The number of MSIs being requested.
+	 * @entries:	An array of @num msix_entry structures.
+	 * @type:	The type, MSI or MSI-X.
+	 *
+	 * This routine is responsible for checking that the given PCI device
+	 * can be allocated the requested type and number of MSIs.
+	 *
+	 * It is up to this routine to determine if the requested number of
+	 * MSIs is valid for the device in question. If the number of MSIs,
+	 * or the particular MSI entries, can not be supported for any
+	 * reason this routine must return non-zero.
+	 *
+	 * If the check is succesful this routine must return 0.
+	 */
+	int (*check) (struct pci_dev *pdev, int num,
+				struct msix_entry *entries, int type);
+
+	/* alloc - Allocate MSIs for the given device.
+	 *
+	 * @pdev:	PCI device structure.
+	 * @num:	The number of MSIs being requested.
+	 * @entries:	An array of @num msix_entry structures.
+	 * @type:	The type, MSI or MSI-X.
+	 *
+	 * This routine is responsible for allocating the number of
+	 * MSIs to the given PCI device.
+	 *
+	 * Upon completion there must be @num MSIs assigned to this device,
+	 * the "vector" member of each struct msix_entry must be filled in
+	 * with the Linux irq number allocated to it. The corresponding
+	 * irq_descs must also be setup with an appropriate handler if
+	 * required.
+	 *
+	 * If the allocation completes succesfully this routine must return 0.
+	 */
+	int (*alloc) (struct pci_dev *pdev, int num,
+				struct msix_entry *entries, int type);
+
+	/* enable - Enable the MSIs on the given device.
+	 *
+	 * @pdev:	PCI device structure.
+	 * @num:	The number of MSIs being requested.
+	 * @entries:	An array of @num msix_entry structures.
+	 * @type:	The type, MSI or MSI-X.
+	 *
+	 * This routine enables the MSIs on the given PCI device.
+	 *
+	 * If the enable completes succesfully this routine must return 0.
+	 *
+	 * This callback is optional.
+	 */
+	int (*enable) (struct pci_dev *pdev, int num,
+				struct msix_entry *entries, int type);
+
+	/* setup_msi_msg - Setup an MSI message for the given device.
+	 *
+	 * @pdev:	PCI device structure.
+	 * @entry:	The MSI entry to create a msi_msg for.
+	 * @msg:	Written with the magic address and data.
+	 * @type:	The type, MSI or MSI-X.
+	 *
+	 * Returns the "magic address and data" used to trigger the msi.
+	 * If the setup is succesful this routine must return 0.
+	 *
+	 * This callback is optional.
+	 */
+	int (*setup_msi_msg) (struct pci_dev *pdev, struct msix_entry *entry,
+				struct msi_msg *msg, int type);
+
+	/* disable - disable the MSI for the given device.
+	 *
+	 * @pdev:	PCI device structure.
+	 * @num:	The number of MSIs to disable.
+	 * @entries:	An array of @num msix_entry structures.
+	 * @type:	The type, MSI or MSI-X.
+	 *
+         * This routine should perform the inverse of enable.
+	 */
+	void (*disable) (struct pci_dev *pdev, int num,
+				struct msix_entry *entries, int type);
+
+	/* free - free the MSIs assigned to the device.
+	 *
+	 * @pdev:	PCI device structure.
+	 * @num:	The number of MSIs.
+	 * @entries:	An array of @num msix_entry structures.
+	 * @type:	The type, MSI or MSI-X.
+	 *
+	 * Free all MSIs and associated resources for the device. If any
+	 * MSIs have been enabled they will have been disabled already by
+	 * the generic code.
+	 */
+	void (*free) (struct pci_dev *pdev, int num,
+				struct msix_entry *entries, int type);
+};
+
+
+/* Used by the MSI code to track MSI info for a pci_dev */
+struct msi_info {
+	int type;
+	unsigned int saved_irq;
+	unsigned int num;
+	struct msix_entry *entries;
+	void *priv;
+};
+
+extern int msi_raw_enable(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type);
+extern int msi_raw_disable(struct pci_dev *pdev, int num,
+			struct msix_entry *entries, int type);
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_MSI_H */
Index: to-merge/include/asm-powerpc/pci-bridge.h
===================================================================
--- to-merge.orig/include/asm-powerpc/pci-bridge.h
+++ to-merge/include/asm-powerpc/pci-bridge.h
@@ -9,6 +9,7 @@
 #include <linux/config.h>
 #include <linux/pci.h>
 #include <linux/list.h>
+#include <asm/msi.h>
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -81,6 +82,9 @@ struct pci_dn {
 	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 	struct	device_node *node;	/* back-pointer to the device_node */
 	u32	config_space[16];	/* saved PCI config space */
+#ifdef CONFIG_PCI_MSI
+	struct	msi_info *msi_info;
+#endif
 };
 
 /* Get the pointer to a device_node's pci_dn */

^ permalink raw reply

* [RFC/PATCH 2/7] Make some MSIX defines generic
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>

Make some MSIX defines generic

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 drivers/pci/msi.h        |    8 --------
 include/linux/pci_regs.h |    8 ++++++++
 2 files changed, 8 insertions(+), 8 deletions(-)

Index: to-merge/drivers/pci/msi.h
===================================================================
--- to-merge.orig/drivers/pci/msi.h
+++ to-merge/drivers/pci/msi.h
@@ -8,14 +8,6 @@
 
 #include <asm/msi.h>
 
-/*
- * MSI-X Address Register
- */
-#define PCI_MSIX_FLAGS_QSIZE		0x7FF
-#define PCI_MSIX_FLAGS_ENABLE		(1 << 15)
-#define PCI_MSIX_FLAGS_BIRMASK		(7 << 0)
-#define PCI_MSIX_FLAGS_BITMASK		(1 << 0)
-
 #define PCI_MSIX_ENTRY_SIZE			16
 #define  PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET	0
 #define  PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET	4
Index: to-merge/include/linux/pci_regs.h
===================================================================
--- to-merge.orig/include/linux/pci_regs.h
+++ to-merge/include/linux/pci_regs.h
@@ -287,6 +287,14 @@
 #define PCI_MSI_DATA_64		12	/* 16 bits of data for 64-bit devices */
 #define PCI_MSI_MASK_BIT	16	/* Mask bits register */
 
+/* MSI-X registers */
+#define PCI_MSIX_FLAGS		2	/* Various flags */
+#define  PCI_MSIX_FLAGS_ENABLE	0x8000	/* MSI-X feature enabled */
+#define  PCI_MSIX_FLAGS_FNMASK	0x4000	/* Mask entire function */
+#define  PCI_MSIX_FLAGS_QSIZE	0x07FF	/* Number of MSI-X available */
+#define  PCI_MSIX_FLAGS_BIRMASK	0x0007	/* BIR */
+#define  PCI_MSIX_FLAGS_BITMASK	0x0001	/* ??? */
+
 /* CompactPCI Hotswap Register */
 
 #define PCI_CHSWP_CSR		2	/* Control and Status Register */

^ permalink raw reply

* [RFC/PATCH 1/7] Rip out the existing powerpc msi stubs
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev
In-Reply-To: <1159480412.269240.988552559176.qpush@concordia>

Rip out the existing powerpc msi stubs.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/kernel/irq.c     |   28 ----------------------------
 include/asm-powerpc/machdep.h |    5 -----
 2 files changed, 33 deletions(-)

Index: to-merge/arch/powerpc/kernel/irq.c
===================================================================
--- to-merge.orig/arch/powerpc/kernel/irq.c
+++ to-merge/arch/powerpc/kernel/irq.c
@@ -820,34 +820,6 @@ arch_initcall(irq_late_init);
 
 #endif /* CONFIG_PPC_MERGE */
 
-#ifdef CONFIG_PCI_MSI
-int pci_enable_msi(struct pci_dev * pdev)
-{
-	if (ppc_md.enable_msi)
-		return ppc_md.enable_msi(pdev);
-	else
-		return -1;
-}
-EXPORT_SYMBOL(pci_enable_msi);
-
-void pci_disable_msi(struct pci_dev * pdev)
-{
-	if (ppc_md.disable_msi)
-		ppc_md.disable_msi(pdev);
-}
-EXPORT_SYMBOL(pci_disable_msi);
-
-void pci_scan_msi_device(struct pci_dev *dev) {}
-int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
-void pci_disable_msix(struct pci_dev *dev) {}
-void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
-void disable_msi_mode(struct pci_dev *dev, int pos, int type) {}
-void pci_no_msi(void) {}
-EXPORT_SYMBOL(pci_enable_msix);
-EXPORT_SYMBOL(pci_disable_msix);
-
-#endif
-
 #ifdef CONFIG_PPC64
 static int __init setup_noirqdistrib(char *str)
 {
Index: to-merge/include/asm-powerpc/machdep.h
===================================================================
--- to-merge.orig/include/asm-powerpc/machdep.h
+++ to-merge/include/asm-powerpc/machdep.h
@@ -239,11 +239,6 @@ struct machdep_calls {
 	 */
 	void (*machine_kexec)(struct kimage *image);
 #endif /* CONFIG_KEXEC */
-
-#ifdef CONFIG_PCI_MSI
-	int (*enable_msi)(struct pci_dev *pdev);
-	void (*disable_msi)(struct pci_dev *pdev);
-#endif /* CONFIG_PCI_MSI */
 };
 
 extern void power4_idle(void);

^ permalink raw reply

* [RFC/PATCH 0/7] Powerpc MSI stuff
From: Michael Ellerman @ 2006-09-28 21:53 UTC (permalink / raw)
  To: linux-kernel; +Cc: Eric W. Biederman, linuxppc-dev

Here's what we've got so far towards an MSI layer for Powerpc. Perhaps
it's interesting for other people too.

Neither of the backends have had any real testing, waiting on hardware, but
I think there's enough to make me think the design makes (some) sense.

cheers

^ permalink raw reply

* Re: [RFC][PATCH 2/2] add mpc83xx.h to powerpc include proper
From: Kumar Gala @ 2006-09-28 21:35 UTC (permalink / raw)
  To: Kim Phillips; +Cc: linuxppc-dev
In-Reply-To: <20060928160226.4dca5b8c.kim.phillips@freescale.com>


On Sep 28, 2006, at 4:02 PM, Kim Phillips wrote:

> add mpc83xx.h to powerpc include proper, rm defines in board header  
> files replaced by the dt.  This completes 83xx transition to  
> ARCH=powerpc.

Can we get ride of mpc83xx.h.  I don't believe its needed and if it  
is we need to work on removing it before I'm ok with this change.

- k


> Signed-off-by: Scott Wood <scottwood@freescale.com>
> Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
>
> ---
>  arch/powerpc/platforms/83xx/mpc834x_itx.h |    5 -----
>  arch/powerpc/platforms/83xx/mpc834x_sys.h |    7 +------
>  include/asm-powerpc/mpc83xx.h             |   30 ++++++++++++++++++ 
> +++++++++++
>  3 files changed, 31 insertions(+), 11 deletions(-)
>
> diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.h b/arch/ 
> powerpc/platforms/83xx/mpc834x_itx.h
> index 174ca4e..88932d2 100644
> --- a/arch/powerpc/platforms/83xx/mpc834x_itx.h
> +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.h
> @@ -15,9 +15,4 @@
>  #ifndef __MACH_MPC83XX_ITX_H__
>  #define __MACH_MPC83XX_ITX_H__
>
> -#define PIRQA	MPC83xx_IRQ_EXT4
> -#define PIRQB	MPC83xx_IRQ_EXT5
> -#define PIRQC	MPC83xx_IRQ_EXT6
> -#define PIRQD	MPC83xx_IRQ_EXT7
> -
>  #endif				/* __MACH_MPC83XX_ITX_H__ */
> diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/ 
> powerpc/platforms/83xx/mpc834x_sys.h
> index fedecb7..8ec5f2f 100644
> --- a/arch/powerpc/platforms/83xx/mpc834x_sys.h
> +++ b/arch/powerpc/platforms/83xx/mpc834x_sys.h
> @@ -1,5 +1,5 @@
>  /*
> - * arch/powerppc/platforms/83xx/mpc834x_sys.h
> + * arch/powerpc/platforms/83xx/mpc834x_sys.h
>   *
>   * MPC834X SYS common board definitions
>   *
> @@ -15,9 +15,4 @@
>  #ifndef __MACH_MPC83XX_SYS_H__
>  #define __MACH_MPC83XX_SYS_H__
>
> -#define PIRQA	MPC83xx_IRQ_EXT4
> -#define PIRQB	MPC83xx_IRQ_EXT5
> -#define PIRQC	MPC83xx_IRQ_EXT6
> -#define PIRQD	MPC83xx_IRQ_EXT7
> -
>  #endif				/* __MACH_MPC83XX_SYS_H__ */
> diff --git a/include/asm-powerpc/mpc83xx.h b/include/asm-powerpc/ 
> mpc83xx.h
> new file mode 100644
> index 0000000..5773cba
> --- /dev/null
> +++ b/include/asm-powerpc/mpc83xx.h
> @@ -0,0 +1,30 @@
> +/*
> + * include/asm-powerpc/mpc83xx.h
> + *
> + * MPC83xx definitions
> + *
> + * Maintainer: Kumar Gala <galak@kernel.crashing.org>
> + *
> + * Copyright 2005 Freescale Semiconductor, Inc
> + *
> + * This program is free software; you can redistribute  it and/or  
> modify it
> + * under  the terms of  the GNU General  Public License as  
> published by the
> + * Free Software Foundation;  either version 2 of the  License, or  
> (at your
> + * option) any later version.
> + */
> +
> +#ifdef __KERNEL__
> +#ifndef __ASM_MPC83xx_H__
> +#define __ASM_MPC83xx_H__
> +
> +#include <asm/mmu.h>
> +
> +#ifdef CONFIG_83xx
> +
> +#ifdef CONFIG_MPC834x_SYS
> +#include <platforms/83xx/mpc834x_sys.h>
> +#endif
> +
> +#endif /* CONFIG_83xx */
> +#endif /* __ASM_MPC83xx_H__ */
> +#endif /* __KERNEL__ */
> -- 
> 1.4.2.1

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox