linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
@ 2009-12-24  7:28 tmarri
  2010-01-04  6:25 ` Benjamin Herrenschmidt
  0 siblings, 1 reply; 10+ messages in thread
From: tmarri @ 2009-12-24  7:28 UTC (permalink / raw)
  To: jwboyer, linuxppc-dev; +Cc: linuxppc-dev, writetomarri, tmarri

From: Tirumala Marri <tmarri@amcc.com>


Signed-off-by: Tirumala Marri <tmarri@amcc.com>
---
	When 460SX configured as root as a end point E1000(Intell Ethernet card)
	was plugged into the one of the PCI-E ports. I was able to run the traffic
	with MSI interrupts.
---
 arch/powerpc/boot/dts/redwood.dts          |   15 ++
 arch/powerpc/configs/44x/redwood_defconfig |    5 +-
 arch/powerpc/platforms/44x/Kconfig         |    1 +
 arch/powerpc/sysdev/Kconfig                |    7 +
 arch/powerpc/sysdev/Makefile               |    1 +
 arch/powerpc/sysdev/ppc4xx_msi.c           |  333 ++++++++++++++++++++++++++++
 arch/powerpc/sysdev/ppc4xx_msi.h           |   39 ++++
 7 files changed, 399 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
 create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.h

diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
index 81636c0..6c20faf 100644
--- a/arch/powerpc/boot/dts/redwood.dts
+++ b/arch/powerpc/boot/dts/redwood.dts
@@ -357,6 +357,21 @@
 				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */
 				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
 		};
+  		MSI: ppc4xx-msi@400300000 {
+  			compatible = "amcc,ppc4xx-460sx-msi", "ppc4xx-msi";
+  			reg = < 0x4 0x00300000 0x100
+  				0x4 0x00300000 0x100>;
+  			sdr-base = <0x3B0>;
+  			interrupts =<0 1 2 3>;
+  			interrupt-parent = <&MSI>;
+  			#interrupt-cells = <1>;
+  			#address-cells = <0>;
+  			#size-cells = <0>;
+  			interrupt-map = <0 &UIC0 0xC 1
+  				1 &UIC0 0x0D 1
+  				2 &UIC0 0x0E 1
+  				3 &UIC0 0x0F 1>;
+  		};
 
 	};
 
diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig
index ed31d4f..5d16c88 100644
--- a/arch/powerpc/configs/44x/redwood_defconfig
+++ b/arch/powerpc/configs/44x/redwood_defconfig
@@ -158,6 +158,7 @@ CONFIG_DEFAULT_AS=y
 CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_FREEZER is not set
 CONFIG_PPC4xx_PCI_EXPRESS=y
+CONFIG_PPC_MSI_BITMAP=y
 
 #
 # Platform support
@@ -264,7 +265,7 @@ CONFIG_PCIEPORTBUS=y
 CONFIG_PCIEAER=y
 # CONFIG_PCIEASPM is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
-# CONFIG_PCI_MSI is not set
+CONFIG_PCI_MSI=y
 # CONFIG_PCI_LEGACY is not set
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
@@ -1062,7 +1063,7 @@ CONFIG_PRINT_STACK_DEPTH=64
 # CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_CODE_PATCHING_SELFTEST is not set
 # CONFIG_FTR_FIXUP_SELFTEST is not set
-# CONFIG_MSI_BITMAP_SELFTEST is not set
+CONFIG_MSI_BITMAP_SELFTEST=y
 # CONFIG_XMON is not set
 # CONFIG_IRQSTACKS is not set
 # CONFIG_VIRQ_DEBUG is not set
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 7486bff..9c3b8ca 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -126,6 +126,7 @@ config REDWOOD
 	select 460SX
 	select PCI
 	select PPC4xx_PCI_EXPRESS
+	select PPC4xx_MSI
 	help
 	  This option enables support for the AMCC PPC460SX Redwood board.
 
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 3965828..c8f1486 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
 	depends on PCI && 4xx
 	default n
 
+config PPC4xx_MSI
+	bool
+	depends on PCI_MSI
+	depends on PCI && 4xx
+	default n
+
 config PPC_MSI_BITMAP
 	bool
 	depends on PCI_MSI
 	default y if MPIC
 	default y if FSL_PCI
+	default y if PPC4xx_MSI
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 5642924..4c67d2d 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_I8259)		+= i8259.o
 obj-$(CONFIG_IPIC)		+= ipic.o
 obj-$(CONFIG_4xx)		+= uic.o
 obj-$(CONFIG_4xx_SOC)		+= ppc4xx_soc.o
+obj-$(CONFIG_PPC4xx_MSI)		+= ppc4xx_msi.o
 obj-$(CONFIG_XILINX_VIRTEX)	+= xilinx_intc.o
 obj-$(CONFIG_XILINX_PCI)	+= xilinx_pci.o
 obj-$(CONFIG_OF_RTC)		+= of_rtc.o
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
new file mode 100644
index 0000000..44b8962
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2009 Applied Micro Circuits corporation.
+ *
+ * Author: Tirumala Marri <tmarri@amcc.com>
+ * 	   Feng Kan <fkan@amcc.com>
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+#include "ppc4xx_msi.h"
+
+static struct ppc4xx_msi *ppc4xx_msi;
+
+struct ppc4xx_msi_feature {
+	u32 ppc4xx_pic_ip;
+	u32 msiir_offset;
+};
+
+static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
+{
+	int rc;
+
+	rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+				msi_data->irqhost->of_node);
+	if (rc)
+		return rc;
+	rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
+	if (rc < 0) {
+		msi_bitmap_free(&msi_data->bitmap);
+		return rc;
+	}
+	return 0;
+}
+
+static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned int cascade_irq;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+	int msir_index = -1;
+
+	raw_spin_lock(&desc->lock);
+	if (desc->chip->mask_ack) {
+		desc->chip->mask_ack(irq);
+	} else {
+		desc->chip->mask(irq);
+		desc->chip->ack(irq);
+	}
+
+	if (unlikely(desc->status & IRQ_INPROGRESS))
+		goto unlock;
+
+	msir_index = (int)desc->handler_data;
+
+	if (msir_index >= NR_MSI_IRQS)
+		cascade_irq = NO_IRQ;
+
+	desc->status |= IRQ_INPROGRESS;
+
+	cascade_irq = irq_linear_revmap(msi_data->irqhost, msir_index);
+	if (cascade_irq != NO_IRQ)
+		generic_handle_irq(cascade_irq);
+	desc->status &= ~IRQ_INPROGRESS;
+
+	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+		desc->chip->unmask(irq);
+unlock:
+	raw_spin_unlock(&desc->lock);
+}
+
+static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
+					struct msi_msg *msg)
+{
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+
+	msg->address_lo = msi_data->msi_addr_lo;
+	msg->address_hi = msi_data->msi_addr_hi;
+	msg->data = hwirq;
+}
+
+int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	struct msi_desc *entry;
+	int rc, hwirq;
+	unsigned int virq;
+	struct msi_msg msg;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+		if (hwirq < 0) {
+			rc = hwirq;
+			dev_err(&dev->dev, "%s: fail allocating msi\
+					interrupt\n",	__func__);
+			goto out_free;
+		}
+
+		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
+		virq = irq_create_mapping(msi_data->irqhost, hwirq);
+		if (virq == NO_IRQ) {
+			dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
+			rc = -ENOSPC;
+			goto out_free;
+		}
+
+		set_irq_msi(virq, entry);
+		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
+		write_msi_msg(virq, &msg);
+	}
+
+	return 0;
+out_free:
+	return rc;
+}
+
+void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
+{
+	struct msi_desc *entry;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+	 dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		if (entry->irq == NO_IRQ)
+			continue;
+		set_irq_msi(entry->irq, NULL);
+		msi_bitmap_free_hwirqs(&msi_data->bitmap,
+				       virq_to_hw(entry->irq), 1);
+		irq_dispose_mapping(entry->irq);
+
+	}
+
+	return;
+}
+
+static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+	pr_debug(KERN_INFO"PCIE-MSI:%s called. vec %x type %d\n",
+					__func__, nvec, type);
+	return 0;
+}
+
+/*
+ * We do not need this actually. The MSIR register has been read once
+ * in the cascade interrupt. So, this MSI interrupt has been acked
+*/
+static void ppc4xx_msi_end_irq(unsigned int virq)
+{
+}
+
+static struct irq_chip ppc4xx_msi_chip = {
+	.mask           = mask_msi_irq,
+	.unmask         = unmask_msi_irq,
+	.ack            = ppc4xx_msi_end_irq,
+	.name       = " UIC",
+};
+
+static int ppc4xx_msi_host_map(struct irq_host *h, unsigned int virq,
+				irq_hw_number_t hw)
+{
+	struct irq_chip *chip = &ppc4xx_msi_chip;
+
+	irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_RISING;
+
+	set_irq_chip_and_handler(virq, chip, handle_edge_irq);
+
+	return 0;
+}
+
+static struct irq_host_ops ppc4xx_msi_host_ops = {
+	.map = ppc4xx_msi_host_map,
+};
+
+static int __devinit ppc4xx_msi_probe(struct of_device *dev,
+					const struct of_device_id *match)
+{
+	struct ppc4xx_msi *msi;
+	struct resource res, rmsi;
+	int i, count;
+	int rc;
+	int virt_msir;
+	const u32 *p;
+	const u32 *sdr_base;
+	u32 *msi_virt = NULL;
+	dma_addr_t msi_phys;
+
+
+	msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
+	if (!msi) {
+		dev_err(&dev->dev, "No memory for MSI structure\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+
+	msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
+				      NR_MSI_IRQS, &ppc4xx_msi_host_ops, 0);
+	if (msi->irqhost == NULL) {
+		dev_err(&dev->dev, "No memory for MSI irqhost\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+
+
+	/* Get MSI ranges */
+	rc = of_address_to_resource(dev->node, 0, &rmsi);
+	if (rc) {
+		dev_err(&dev->dev, "%s resource error!\n",
+				dev->node->full_name);
+		goto error_out;
+	}
+
+
+	/* Get the MSI reg base */
+	rc = of_address_to_resource(dev->node, 1, &res);
+	if (rc) {
+		dev_err(&dev->dev, "%s resource error!\n",
+				dev->node->full_name);
+		goto error_out;
+	}
+	/* Get the sdr-base */
+	sdr_base = (u32 *)of_get_property(dev->node, "sdr-base", NULL);
+	if (sdr_base == NULL) {
+		dev_err(&dev->dev, "%s resource error!\n",
+				dev->node->full_name);
+		goto error_out;
+	}
+	msi->sdr_base = *sdr_base;
+	mtdcri(SDR0, msi->sdr_base, res.start >> 32);
+	mtdcri(SDR0, msi->sdr_base + 1, res.start & 0xFFFFFFFF);
+	msi->msi_regs = ioremap(res.start, res.end - res.start + 1);
+	if (!msi->msi_regs) {
+		dev_err(&dev->dev, "ioremap problem failed\n");
+		goto error_out;
+	}
+	/* MSI region always mapped in 4GB region*/
+	msi->msi_addr_hi = 0x0;
+	msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys,
+			GFP_KERNEL);
+	if (msi_virt == NULL) {
+		dev_err(&dev->dev, "No memory for MSI mem space\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+	msi->msi_addr_lo = (u32)msi_phys;
+
+	/* Progam the Interrupt handler Termination addr registers */
+	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
+	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
+
+	/* Program MSI Expected data and Mask bits */
+	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
+	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);
+
+	msi->irqhost->host_data = msi;
+
+	if (ppc4xx_msi_init_allocator(msi)) {
+		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
+		goto error_out;
+	}
+
+	p = of_get_property(dev->node, "interrupts", &count);
+	if (!p) {
+		dev_err(&dev->dev, "no interrupts property found on %s\n",
+				dev->node->full_name);
+		rc = -ENODEV;
+		goto error_out;
+	}
+	if (count == 0) {
+		dev_err(&dev->dev, "Malformed interrupts property on %s\n",
+				dev->node->full_name);
+		rc = -EINVAL;
+		goto error_out;
+	}
+
+	for (i = 0; i < NR_MSI_IRQS; i++) {
+		virt_msir = irq_of_parse_and_map(dev->node, i);
+		if (virt_msir != NO_IRQ) {
+			set_irq_data(virt_msir, (void *)i);
+			set_irq_chained_handler(virt_msir, ppc4xx_msi_cascade);
+		}
+	}
+
+	ppc4xx_msi = msi;
+
+	WARN_ON(ppc_md.setup_msi_irqs);
+	ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
+	ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
+	ppc_md.msi_check_device = ppc4xx_msi_check_device;
+	return 0;
+error_out:
+	if (msi_virt)
+		dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
+	kfree(msi);
+	return rc;
+}
+
+static const struct ppc4xx_msi_feature ppc4xx_msi_feature = {
+	.ppc4xx_pic_ip = 0,
+	.msiir_offset = 0x140,
+};
+
+static const struct of_device_id ppc4xx_msi_ids[] = {
+	{
+		.compatible = "amcc,ppc4xx-msi",
+		.data = (void *)&ppc4xx_msi_feature,
+	},
+	{}
+};
+
+static struct of_platform_driver ppc4xx_msi_driver = {
+	.name = "ppc4xx-msi",
+	.match_table = ppc4xx_msi_ids,
+	.probe = ppc4xx_msi_probe,
+};
+
+static __init int ppc4xx_msi_init(void)
+{
+	return of_register_platform_driver(&ppc4xx_msi_driver);
+}
+
+subsys_initcall(ppc4xx_msi_init);
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.h b/arch/powerpc/sysdev/ppc4xx_msi.h
new file mode 100644
index 0000000..e4ae058
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_msi.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Applied Micro Circuits Corporation.
+ *
+ * Author: Tirumala Marri <tmarri@amcc.com>
+ * 		Feng Kan <fkan@amcc.com>
+ * 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.
+ */
+#ifndef __PPC4XX_MSI_H__
+#define __PPC4XX_MSI_H__
+
+#include <asm/msi_bitmap.h>
+
+#define PEIH_TERMADH    0x00
+#define PEIH_TERMADL    0x08
+#define PEIH_MSIED      0x10
+#define PEIH_MSIMK      0x18
+#define PEIH_MSIASS     0x20
+#define PEIH_FLUSH0     0x30
+#define PEIH_FLUSH1     0x38
+#define PEIH_CNTRST     0x48
+
+#define MSI_DATA_PATTERN   0x44440000
+
+struct ppc4xx_msi {
+	struct irq_host *irqhost;
+	unsigned long cascade_irq;
+	u32 msi_addr_lo;
+	u32 msi_addr_hi;
+	void __iomem *msi_regs;
+	u32 feature;
+	struct msi_bitmap bitmap;
+	u32 sdr_base;
+};
+
+#define NR_MSI_IRQS 4
+#endif /* __PPC4XX_MSI_H__ */
-- 
1.6.1.rc3

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

* Re: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
  2009-12-24  7:28 [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC tmarri
@ 2010-01-04  6:25 ` Benjamin Herrenschmidt
  2010-01-11  6:46   ` Tirumala Reddy Marri
  0 siblings, 1 reply; 10+ messages in thread
From: Benjamin Herrenschmidt @ 2010-01-04  6:25 UTC (permalink / raw)
  To: tmarri; +Cc: linuxppc-dev, writetomarri, linuxppc-dev

On Wed, 2009-12-23 at 23:28 -0800, tmarri@amcc.com wrote:
> From: Tirumala Marri <tmarri@amcc.com>
> 
> 
> Signed-off-by: Tirumala Marri <tmarri@amcc.com>
> ---
> 	When 460SX configured as root as a end point E1000(Intell Ethernet card)
> 	was plugged into the one of the PCI-E ports. I was able to run the traffic
> 	with MSI interrupts.

So before I even ack or nack that patch, I need to better understand how
your HW works. I've read the doc of the 460EX twice and still don't
quite get it :-)

So my understanding so far is that when reception of MSIs is enabled,
writes to some magic address in the first 1K of BAR0 are interpreted ad
MSIs. The MSI interrupt value (low 16 bits of the 32-bit store in little
endian) is thus interpreted as an interrupt number and send to the UIC.

Is that correct ?

Now, which UIC ? There are at least 3 in the 460EX for example :-)

Also, UICs have a limited amount of inputs and I don't see many
interrupt sources "reserved" for use as MSIs, can you enlighten me a bit
more on how you get to choose an interrupt source to use as MSI ?

Or is there some translation done ? IE. In the 460EX manual, there seem
to be specific interrupt numbers dedicated to PCI0 MSI 0, 1 2 and 3
spread between UIC0 and UIC1, and a block of 8 interrupts in UIC3
reserved for PCI-E MSIs. Is there a renumbering done in HW here ?

IE. Your table shows for 460EX for example that PCI-E MSI 2 is UIC3
input 26. Do I need thus to program the device to write a "2" in the MSI
message or "26" to hit that interrupt ?

IE. Are you running the input message through a binary decoder that then
spreads into various UIC input lines ?

Now some comments:

> diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
> index 81636c0..6c20faf 100644
> --- a/arch/powerpc/boot/dts/redwood.dts
> +++ b/arch/powerpc/boot/dts/redwood.dts
> @@ -357,6 +357,21 @@
>  				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */
>  				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
>  		};
> +  		MSI: ppc4xx-msi@400300000 {
> +  			compatible = "amcc,ppc4xx-460sx-msi", "ppc4xx-msi";
> +  			reg = < 0x4 0x00300000 0x100
> +  				0x4 0x00300000 0x100>;
> +  			sdr-base = <0x3B0>;
> +  			interrupts =<0 1 2 3>;
> +  			interrupt-parent = <&MSI>;
> +  			#interrupt-cells = <1>;
> +  			#address-cells = <0>;
> +  			#size-cells = <0>;
> +  			interrupt-map = <0 &UIC0 0xC 1
> +  				1 &UIC0 0x0D 1
> +  				2 &UIC0 0x0E 1
> +  				3 &UIC0 0x0F 1>;
> +  		};

Wow ! That's the mother of all device-tree hacks :-) So you are using
the "interrupts" property of the MSI node to represent the MSI
interrupts you hand out, and you make it its own interrupt-parent, using
an interrupt-map in itself to convert them into UIC interrupts :-)
Sneaky... Hell, it will work so why not ?

> +static struct ppc4xx_msi *ppc4xx_msi;
> +
> +struct ppc4xx_msi_feature {
> +	u32 ppc4xx_pic_ip;
> +	u32 msiir_offset;
> +};
> +
> +static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
> +{
> +	int rc;
> +
> +	rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
> +				msi_data->irqhost->of_node);
> +	if (rc)
> +		return rc;
> +	rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
> +	if (rc < 0) {
> +		msi_bitmap_free(&msi_data->bitmap);
> +		return rc;
> +	}
> +	return 0;
> +}

Ok so here I start having problems :-) First you allocate a bitmap for
the MSIs of a fixed number, despite the fact that there seem to be a
different number of MSIs supported depending on what part/bridge you are
using. Then, you try to call msi_bitmap_reserve_dt_hwirqs()... why
that ? This is meant to be used when you don't know what interrupt
numbers are reserved for use by MSIs in your system, it's a bit fishy to
be honest, we use it on powermac mostly :-)

> +static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc *desc)
> +{
> +	unsigned int cascade_irq;
> +	struct ppc4xx_msi *msi_data = ppc4xx_msi;
> +	int msir_index = -1;
> +
> +	raw_spin_lock(&desc->lock);
> +	if (desc->chip->mask_ack) {
> +		desc->chip->mask_ack(irq);
> +	} else {
> +		desc->chip->mask(irq);
> +		desc->chip->ack(irq);
> +	}
> +
> +	if (unlikely(desc->status & IRQ_INPROGRESS))
> +		goto unlock;
> +
> +	msir_index = (int)desc->handler_data;
> +
> +	if (msir_index >= NR_MSI_IRQS)
> +		cascade_irq = NO_IRQ;
> +
> +	desc->status |= IRQ_INPROGRESS;
> +
> +	cascade_irq = irq_linear_revmap(msi_data->irqhost, msir_index);
> +	if (cascade_irq != NO_IRQ)
> +		generic_handle_irq(cascade_irq);
> +	desc->status &= ~IRQ_INPROGRESS;
> +
> +	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
> +		desc->chip->unmask(irq);
> +unlock:
> +	raw_spin_unlock(&desc->lock);
> +}

Now, that's really a weird idea. Why are you making it a cascaded
interrupt controller ? That is just gratuitous overhead. You could have
the MSI handling directly hand out the appropriate UIC interrupts and
have them call directly into the driver. The above adds significant
overhead to MSI processing.

> +static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
> +					struct msi_msg *msg)
> +{
> +	struct ppc4xx_msi *msi_data = ppc4xx_msi;
> +
> +	msg->address_lo = msi_data->msi_addr_lo;
> +	msg->address_hi = msi_data->msi_addr_hi;
> +	msg->data = hwirq;
> +}
> +
> +int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> +	struct msi_desc *entry;
> +	int rc, hwirq;
> +	unsigned int virq;
> +	struct msi_msg msg;
> +	struct ppc4xx_msi *msi_data = ppc4xx_msi;
> +
> +
> +	list_for_each_entry(entry, &dev->msi_list, list) {
> +		hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
> +		if (hwirq < 0) {
> +			rc = hwirq;
> +			dev_err(&dev->dev, "%s: fail allocating msi\
> +					interrupt\n",	__func__);
> +			goto out_free;
> +		}
> +
> +		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
> +		virq = irq_create_mapping(msi_data->irqhost, hwirq);
> +		if (virq == NO_IRQ) {
> +			dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
> +			rc = -ENOSPC;
> +			goto out_free;
> +		}
> +
> +		set_irq_msi(virq, entry);
> +		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
> +		write_msi_msg(virq, &msg);
> +	}
> +
> +	return 0;
> +out_free:
> +	return rc;
> +}

Similar here. You create this whole layer of secondary interrupt host
while you could just hand out existing UIC interrupts no ?
 
 .../...

> +
> +static int __devinit ppc4xx_msi_probe(struct of_device *dev,
> +					const struct of_device_id *match)
> +{
> +	struct ppc4xx_msi *msi;
> +	struct resource res, rmsi;
> +	int i, count;
> +	int rc;
> +	int virt_msir;
> +	const u32 *p;
> +	const u32 *sdr_base;
> +	u32 *msi_virt = NULL;
> +	dma_addr_t msi_phys;
> +
> +
> +	msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
> +	if (!msi) {
> +		dev_err(&dev->dev, "No memory for MSI structure\n");
> +		rc = -ENOMEM;
> +		goto error_out;
> +	}
> +
> +	msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
> +				      NR_MSI_IRQS, &ppc4xx_msi_host_ops, 0);
> +	if (msi->irqhost == NULL) {
> +		dev_err(&dev->dev, "No memory for MSI irqhost\n");
> +		rc = -ENOMEM;
> +		goto error_out;
> +	}

Same comment, ie, why a separate irq host ?

> +
> +	/* Get MSI ranges */
> +	rc = of_address_to_resource(dev->node, 0, &rmsi);
> +	if (rc) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +
> +
> +	/* Get the MSI reg base */
> +	rc = of_address_to_resource(dev->node, 1, &res);
> +	if (rc) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +	/* Get the sdr-base */
> +	sdr_base = (u32 *)of_get_property(dev->node, "sdr-base", NULL);
> +	if (sdr_base == NULL) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +	msi->sdr_base = *sdr_base;
> +	mtdcri(SDR0, msi->sdr_base, res.start >> 32);
> +	mtdcri(SDR0, msi->sdr_base + 1, res.start & 0xFFFFFFFF);
> +	msi->msi_regs = ioremap(res.start, res.end - res.start + 1);
> +	if (!msi->msi_regs) {
> +		dev_err(&dev->dev, "ioremap problem failed\n");
> +		goto error_out;
> +	}
> +	/* MSI region always mapped in 4GB region*/
> +	msi->msi_addr_hi = 0x0;
> +	msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys,
> +			GFP_KERNEL);
> +	if (msi_virt == NULL) {
> +		dev_err(&dev->dev, "No memory for MSI mem space\n");
> +		rc = -ENOMEM;
> +		goto error_out;
> +	}
> +	msi->msi_addr_lo = (u32)msi_phys;

Now, what is the above for ? Are the MSI writes done by the device
actually hitting memory as well ? I would have expected them to be
filtered by the bridge on the way up, are they not ?

I suppose it gives you a cheap way to obtain a bit of unused address
space...

> +	/* Progam the Interrupt handler Termination addr registers */
> +	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
> +	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
> +
> +	/* Program MSI Expected data and Mask bits */
> +	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
> +	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);

Can you tell me a bit more about what the above is about ?

Also, it looks like your code would work for other SoCs like 460EX
etc... by just updating the .dts right ? Care to update a few more
boards so I can test on my canyonlands ? :-)

Cheers,
Ben.

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

* RE: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
  2010-01-04  6:25 ` Benjamin Herrenschmidt
@ 2010-01-11  6:46   ` Tirumala Reddy Marri
  0 siblings, 0 replies; 10+ messages in thread
From: Tirumala Reddy Marri @ 2010-01-11  6:46 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, writetomarri, linuxppc-dev

UGxlYXNlIHNlZSBteSBhbnN3ZXJzIGluIGxpbmUuDQoNCi0tLS0tT3JpZ2luYWwgTWVzc2FnZS0t
LS0tDQpGcm9tOiBCZW5qYW1pbiBIZXJyZW5zY2htaWR0IFttYWlsdG86YmVuaEBrZXJuZWwuY3Jh
c2hpbmcub3JnXSANClNlbnQ6IFN1bmRheSwgSmFudWFyeSAwMywgMjAxMCAxMDoyNSBQTQ0KVG86
IFRpcnVtYWxhIFJlZGR5IE1hcnJpDQpDYzogandib3llckBsaW51eC52bmV0LmlibS5jb207IGxp
bnV4cHBjLWRldkBsaXN0cy5vemxhYnMub3JnOyBsaW51eHBwYy1kZXZAb3psYWJzLm9yZzsgd3Jp
dGV0b21hcnJpQHlhaG9vLmNvbQ0KU3ViamVjdDogUmU6IFtQQVRDSCAyLzJdIEFkZGluZyBQQ0kt
RSBNU0kgc3VwcG9ydCBmb3IgUG93ZXJQQyA0NjBTWCBTT0MuDQoNCk9uIFdlZCwgMjAwOS0xMi0y
MyBhdCAyMzoyOCAtMDgwMCwgdG1hcnJpQGFtY2MuY29tIHdyb3RlOg0KPiBGcm9tOiBUaXJ1bWFs
YSBNYXJyaSA8dG1hcnJpQGFtY2MuY29tPg0KPiANCj4gDQo+IFNpZ25lZC1vZmYtYnk6IFRpcnVt
YWxhIE1hcnJpIDx0bWFycmlAYW1jYy5jb20+DQo+IC0tLQ0KPiAJV2hlbiA0NjBTWCBjb25maWd1
cmVkIGFzIHJvb3QgYXMgYSBlbmQgcG9pbnQgRTEwMDAoSW50ZWxsIEV0aGVybmV0IGNhcmQpDQo+
IAl3YXMgcGx1Z2dlZCBpbnRvIHRoZSBvbmUgb2YgdGhlIFBDSS1FIHBvcnRzLiBJIHdhcyBhYmxl
IHRvIHJ1biB0aGUgdHJhZmZpYw0KPiAJd2l0aCBNU0kgaW50ZXJydXB0cy4NCg0KPlNvIGJlZm9y
ZSBJIGV2ZW4gYWNrIG9yIG5hY2sgdGhhdCBwYXRjaCwgSSBuZWVkIHRvIGJldHRlciB1bmRlcnN0
YW5kIGhvdw0KPnlvdXIgSFcgd29ya3MuIEkndmUgcmVhZCB0aGUgZG9jIG9mIHRoZSA0NjBFWCB0
d2ljZSBhbmQgc3RpbGwgZG9uJ3QNCj5xdWl0ZSBnZXQgaXQgOi0pDQoNCj5TbyBteSB1bmRlcnN0
YW5kaW5nIHNvIGZhciBpcyB0aGF0IHdoZW4gcmVjZXB0aW9uIG9mIE1TSXMgaXMgZW5hYmxlZCwN
Cj53cml0ZXMgdG8gc29tZSBtYWdpYyBhZGRyZXNzIGluIHRoZSBmaXJzdCAxSyBvZiBCQVIwIGFy
ZSBpbnRlcnByZXRlZCBhZA0KPk1TSXMuIFRoZSBNU0kgaW50ZXJydXB0IHZhbHVlIChsb3cgMTYg
Yml0cyBvZiB0aGUgMzItYml0IHN0b3JlIGluIGxpdHRsZQ0KPmVuZGlhbikgaXMgdGh1cyBpbnRl
cnByZXRlZCBhcyBhbiBpbnRlcnJ1cHQgbnVtYmVyIGFuZCBzZW5kIHRvIHRoZSBVSUMuDQoNCj5J
cyB0aGF0IGNvcnJlY3QgPw0KDQpNYXJyaTogWW91IGFyZSBzb21ld2hhdCByaWdodC4gVGhlcmUg
YXJlIHR3byB3YXlzIHRvIGNhdXNlIHRoZSBpbnRlcnJ1cHRzLiANCkluIGZpcnN0IGNhc2UgTVNJ
IGlzIGdlbmVyYXRlZCB0byByb290IGNvbXBsZXggYnkgd3JpdGluZyB0byBhIEFkZHJlc3MgcmVn
aW9uIA0KZnJvbSBFbmRwb2ludCB3aGljaCBpcyBtYXBwZWQgdG8gcm9vdC1jb21wbGV4IHNpZGUg
TVNJIEFyZWEuIA0KCQkJCQkJCQlJbiBzZWNvbmQgY2FzZSByb290IGNvbXBsZXgNCndyaXRlcyB0
aGUgNjRiaXQgTVNJIGFkZHJlc3MgYW5kIGRhdGEgcGF0dGVybiBpbiB0aGUgRW5kcG9pbnQgY29u
ZmlndXJhdGlvbg0Kc3BhY2UuIFRoZW4gZW5kcG9pbnQgc2lkZSBjcHUgd2lsbCB3cml0ZSB0byBy
ZWdpc3RlciBpbiB0aGUgUENJLUUgaW50ZXJydXB0IA0KaGFuZGxlciByZWdpc3RlciBNU0lBU1Mo
TVNJIHNvZnR3YXJlIGFzc2VydCApLCB0aGlzIHdvdWxkIHRyaWdnZXIgYSBtZW1vcnkgDQp3cml0
ZSB0cmFuc2FjdGlvbiBvbiB0aGUgUENJLUUgYnVzIHdpdGggYWRkcmVzcyBmcm9tIHRoZSBjb25m
aWcgc3BhY2UgYW5kIGRhdGENCmZyb20gZGF0YSByZWdpc3Rlci4gQXMgc29vbiBhcyB0aGlzIHRy
YW5zIGFjdGlvbiBjb21lcyBvbiB0aGUgQlVTIFBDSS1FIGhhbmRsZXINCm9uIHJvb3QgY29tcGxl
eCBzbm9vcHMgZm9yIHRoaXMgYWRkcmVzcyBhbmQgY2hlY2tzIGFnYWluc3QgdGhlIGRhdGEgcmVj
ZWl2ZWQuDQpJZiBpdCBtYXRjaGVzIGl0IHdvdWxkIGNhdXNlIGFwcHJvcHJpYXRlIGludGVycnVw
dCBudW1iZXIgYmFzZWQgb24gdGhlIGRhdGEgDQpSZWNlaXZlZC4gRm9yIGV4YW1wbGUgZm9yIGlu
dGVycnVwdCAxICwgZGF0YSB3b3VsZCBiZSAweDQ0NDQwMDAwIGFuZCBpbnRlcnJ1cHQNCjIgZGF0
YSB3b3VsZCBiZSAweDQ0NDQwMDAxIC4NCg0KDQo+Tm93LCB3aGljaCBVSUMgPyBUaGVyZSBhcmUg
YXQgbGVhc3QgMyBpbiB0aGUgNDYwRVggZm9yIGV4YW1wbGUgOi0pDQpNYXJyaTogRWFjaCBvZiA0
IE1TSSBpcyBtYXBwZWQgdG8gVUlDMCAxMiwxMywxNCAmIDE1IGludGVycnVwdCBudW1iZXJzDQoN
Cj5BbHNvLCBVSUNzIGhhdmUgYSBsaW1pdGVkIGFtb3VudCBvZiBpbnB1dHMgYW5kIEkgZG9uJ3Qg
c2VlIG1hbnkNCj5pbnRlcnJ1cHQgc291cmNlcyAicmVzZXJ2ZWQiIGZvciB1c2UgYXMgTVNJcywg
Y2FuIHlvdSBlbmxpZ2h0ZW4gbWUgYSBiaXQNCj5tb3JlIG9uIGhvdyB5b3UgZ2V0IHRvIGNob29z
ZSBhbiBpbnRlcnJ1cHQgc291cmNlIHRvIHVzZSBhcyBNU0kgPw0KDQpNYXJyaTogVGhlcmUgYXJl
IDQgTUlTJ3Mgb3IgMTUgTVNJLVggaW50ZXJydXB0cyBjYW4gYmUgZW5hYmxlZC4gRWFjaCBNU0kg
aXMgaGFyZA0KV2lyZWQgdG8gVUlDMCAxMiB0byAxNS4gRm9yIE1TSS1YIFVJQy0zIDEyIHRvIDI3
Lg0KDQo+T3IgaXMgdGhlcmUgc29tZSB0cmFuc2xhdGlvbiBkb25lID8gSUUuIEluIHRoZSA0NjBF
WCBtYW51YWwsIHRoZXJlIHNlZW0NCj50byBiZSBzcGVjaWZpYyBpbnRlcnJ1cHQgbnVtYmVycyBk
ZWRpY2F0ZWQgdG8gUENJMCBNU0kgMCwgMSAyIGFuZCAzDQo+c3ByZWFkIGJldHdlZW4gVUlDMCBh
bmQgVUlDMSwgYW5kIGEgYmxvY2sgb2YgOCBpbnRlcnJ1cHRzIGluIFVJQzMNCj5yZXNlcnZlZCBm
b3IgUENJLUUgTVNJcy4gSXMgdGhlcmUgYSByZW51bWJlcmluZyBkb25lIGluIEhXIGhlcmUgPw0K
DQoNCg0KPklFLiBZb3VyIHRhYmxlIHNob3dzIGZvciA0NjBFWCBmb3IgZXhhbXBsZSB0aGF0IFBD
SS1FIE1TSSAyIGlzIFVJQzMNCj5pbnB1dCAyNi4gRG8gSSBuZWVkIHRodXMgdG8gcHJvZ3JhbSB0
aGUgZGV2aWNlIHRvIHdyaXRlIGEgIjIiIGluIHRoZSBNU0kNCm1lc3NhZ2Ugb3IgIjI2IiB0byBo
aXQgdGhhdCBpbnRlcnJ1cHQgPw0KDQo+SUUuIEFyZSB5b3UgcnVubmluZyB0aGUgaW5wdXQgbWVz
c2FnZSB0aHJvdWdoIGEgYmluYXJ5IGRlY29kZXIgdGhhdCB0aGVuDQo+c3ByZWFkcyBpbnRvIHZh
cmlvdXMgVUlDIGlucHV0IGxpbmVzID8NCg0KDQpNYXJyaTogWWVzIGVhY2ggTVNJIGlzIGhhcmQg
d2lyZWQgdG8gZGlmZmVyZW50IGludGVycnVwdCBudW1iZXIgaW4gVUlDIHJlZ2lzdGVycy4NCk1J
UyBpbnRlcnJ1cHQgbnVtYmVyIHRvIFVJQyBpcyBub3QgcHJvZ3JhbW1hYmxlIC4gSXQgaXMgZml4
ZWQuDQoNCg0KPk5vdyBzb21lIGNvbW1lbnRzOg0KDQoNCj4gZGlmZiAtLWdpdCBhL2FyY2gvcG93
ZXJwYy9ib290L2R0cy9yZWR3b29kLmR0cyBiL2FyY2gvcG93ZXJwYy9ib290L2R0cy9yZWR3b29k
LmR0cw0KPiBpbmRleCA4MTYzNmMwLi42YzIwZmFmIDEwMDY0NA0KPiAtLS0gYS9hcmNoL3Bvd2Vy
cGMvYm9vdC9kdHMvcmVkd29vZC5kdHMNCj4gKysrIGIvYXJjaC9wb3dlcnBjL2Jvb3QvZHRzL3Jl
ZHdvb2QuZHRzDQo+IEBAIC0zNTcsNiArMzU3LDIxIEBADQo+ICAJCQkJMHgwIDB4MCAweDAgMHgz
ICZVSUMzIDB4YSAweDQgLyogc3dpenpsZWQgaW50IEMgKi8NCj4gIAkJCQkweDAgMHgwIDB4MCAw
eDQgJlVJQzMgMHhiIDB4NCAvKiBzd2l6emxlZCBpbnQgRCAqLz47DQo+ICAJCX07DQo+ICsgIAkJ
TVNJOiBwcGM0eHgtbXNpQDQwMDMwMDAwMCB7DQo+ICsgIAkJCWNvbXBhdGlibGUgPSAiYW1jYyxw
cGM0eHgtNDYwc3gtbXNpIiwgInBwYzR4eC1tc2kiOw0KPiArICAJCQlyZWcgPSA8IDB4NCAweDAw
MzAwMDAwIDB4MTAwDQo+ICsgIAkJCQkweDQgMHgwMDMwMDAwMCAweDEwMD47DQo+ICsgIAkJCXNk
ci1iYXNlID0gPDB4M0IwPjsNCj4gKyAgCQkJaW50ZXJydXB0cyA9PDAgMSAyIDM+Ow0KPiArICAJ
CQlpbnRlcnJ1cHQtcGFyZW50ID0gPCZNU0k+Ow0KPiArICAJCQkjaW50ZXJydXB0LWNlbGxzID0g
PDE+Ow0KPiArICAJCQkjYWRkcmVzcy1jZWxscyA9IDwwPjsNCj4gKyAgCQkJI3NpemUtY2VsbHMg
PSA8MD47DQo+ICsgIAkJCWludGVycnVwdC1tYXAgPSA8MCAmVUlDMCAweEMgMQ0KPiArICAJCQkJ
MSAmVUlDMCAweDBEIDENCj4gKyAgCQkJCTIgJlVJQzAgMHgwRSAxDQo+ICsgIAkJCQkzICZVSUMw
IDB4MEYgMT47DQo+ICsgIAkJfTsNCg0KPldvdyAhIFRoYXQncyB0aGUgbW90aGVyIG9mIGFsbCBk
ZXZpY2UtdHJlZSBoYWNrcyA6LSkgU28geW91IGFyZSB1c2luZw0KPnRoZSAiaW50ZXJydXB0cyIg
cHJvcGVydHkgb2YgdGhlIE1TSSBub2RlIHRvIHJlcHJlc2VudCB0aGUgTVNJDQo+aW50ZXJydXB0
cyB5b3UgaGFuZCBvdXQsIGFuZCB5b3UgbWFrZSBpdCBpdHMgb3duIGludGVycnVwdC1wYXJlbnQs
IHVzaW5nDQo+YW4gaW50ZXJydXB0LW1hcCBpbiBpdHNlbGYgdG8gY29udmVydCB0aGVtIGludG8g
VUlDIGludGVycnVwdHMgOi0pDQo+U25lYWt5Li4uIEhlbGwsIGl0IHdpbGwgd29yayBzbyB3aHkg
bm90ID8NCg0KDQpNYXJyaTogQlRXIHRoZXJlIGFyZSBzb21lIG90aGVyIHByb2Nlc3NvcnMgdXNp
bmcgdGhlIHNpbWlsYXIgd2F5Lg0KDQoNCj4gK3N0YXRpYyBzdHJ1Y3QgcHBjNHh4X21zaSAqcHBj
NHh4X21zaTsNCj4gKw0KPiArc3RydWN0IHBwYzR4eF9tc2lfZmVhdHVyZSB7DQo+ICsJdTMyIHBw
YzR4eF9waWNfaXA7DQo+ICsJdTMyIG1zaWlyX29mZnNldDsNCj4gK307DQo+ICsNCj4gK3N0YXRp
YyBpbnQgcHBjNHh4X21zaV9pbml0X2FsbG9jYXRvcihzdHJ1Y3QgcHBjNHh4X21zaSAqbXNpX2Rh
dGEpDQo+ICt7DQo+ICsJaW50IHJjOw0KPiArDQo+ICsJcmMgPSBtc2lfYml0bWFwX2FsbG9jKCZt
c2lfZGF0YS0+Yml0bWFwLCBOUl9NU0lfSVJRUywNCj4gKwkJCQltc2lfZGF0YS0+aXJxaG9zdC0+
b2Zfbm9kZSk7DQo+ICsJaWYgKHJjKQ0KPiArCQlyZXR1cm4gcmM7DQo+ICsJcmMgPSBtc2lfYml0
bWFwX3Jlc2VydmVfZHRfaHdpcnFzKCZtc2lfZGF0YS0+Yml0bWFwKTsNCj4gKwlpZiAocmMgPCAw
KSB7DQo+ICsJCW1zaV9iaXRtYXBfZnJlZSgmbXNpX2RhdGEtPmJpdG1hcCk7DQo+ICsJCXJldHVy
biByYzsNCj4gKwl9DQo+ICsJcmV0dXJuIDA7DQo+ICt9DQoNCj5PayBzbyBoZXJlIEkgc3RhcnQg
aGF2aW5nIHByb2JsZW1zIDotKSBGaXJzdCB5b3UgYWxsb2NhdGUgYSBiaXRtYXAgZm9yDQo+dGhl
IE1TSXMgb2YgYSBmaXhlZCBudW1iZXIsIGRlc3BpdGUgdGhlIGZhY3QgdGhhdCB0aGVyZSBzZWVt
IHRvIGJlIGENCj5kaWZmZXJlbnQgbnVtYmVyIG9mIE1TSXMgc3VwcG9ydGVkIGRlcGVuZGluZyBv
biB3aGF0IHBhcnQvYnJpZGdlIHlvdSBhcmUNCj51c2luZy4gVGhlbiwgeW91IHRyeSB0byBjYWxs
IG1zaV9iaXRtYXBfcmVzZXJ2ZV9kdF9od2lycXMoKS4uLiB3aHkNCj50aGF0ID8gVGhpcyBpcyBt
ZWFudCB0byBiZSB1c2VkIHdoZW4geW91IGRvbid0IGtub3cgd2hhdCBpbnRlcnJ1cHQNCj5udW1i
ZXJzIGFyZSByZXNlcnZlZCBmb3IgdXNlIGJ5IE1TSXMgaW4geW91ciBzeXN0ZW0sIGl0J3MgYSBi
aXQgZmlzaHkgdG8NCj5iZSBob25lc3QsIHdlIHVzZSBpdCBvbiBwb3dlcm1hYyBtb3N0bHkgOi0p
DQoNCk1hcnJpOiBQcm9iYWJseSB5b3UgYXJlIHJpZ2h0LiBMZXQgbWUgdHJ5IHRha2UgdGhpcyBv
dXQuIA0KDQo+ICtzdGF0aWMgdm9pZCBwcGM0eHhfbXNpX2Nhc2NhZGUodW5zaWduZWQgaW50IGly
cSwgc3RydWN0IGlycV9kZXNjICpkZXNjKQ0KPiArew0KPiArCXVuc2lnbmVkIGludCBjYXNjYWRl
X2lycTsNCj4gKwlzdHJ1Y3QgcHBjNHh4X21zaSAqbXNpX2RhdGEgPSBwcGM0eHhfbXNpOw0KPiAr
CWludCBtc2lyX2luZGV4ID0gLTE7DQo+ICsNCj4gKwlyYXdfc3Bpbl9sb2NrKCZkZXNjLT5sb2Nr
KTsNCj4gKwlpZiAoZGVzYy0+Y2hpcC0+bWFza19hY2spIHsNCj4gKwkJZGVzYy0+Y2hpcC0+bWFz
a19hY2soaXJxKTsNCj4gKwl9IGVsc2Ugew0KPiArCQlkZXNjLT5jaGlwLT5tYXNrKGlycSk7DQo+
ICsJCWRlc2MtPmNoaXAtPmFjayhpcnEpOw0KPiArCX0NCj4gKw0KPiArCWlmICh1bmxpa2VseShk
ZXNjLT5zdGF0dXMgJiBJUlFfSU5QUk9HUkVTUykpDQo+ICsJCWdvdG8gdW5sb2NrOw0KPiArDQo+
ICsJbXNpcl9pbmRleCA9IChpbnQpZGVzYy0+aGFuZGxlcl9kYXRhOw0KPiArDQo+ICsJaWYgKG1z
aXJfaW5kZXggPj0gTlJfTVNJX0lSUVMpDQo+ICsJCWNhc2NhZGVfaXJxID0gTk9fSVJROw0KPiAr
DQo+ICsJZGVzYy0+c3RhdHVzIHw9IElSUV9JTlBST0dSRVNTOw0KPiArDQo+ICsJY2FzY2FkZV9p
cnEgPSBpcnFfbGluZWFyX3Jldm1hcChtc2lfZGF0YS0+aXJxaG9zdCwgbXNpcl9pbmRleCk7DQo+
ICsJaWYgKGNhc2NhZGVfaXJxICE9IE5PX0lSUSkNCj4gKwkJZ2VuZXJpY19oYW5kbGVfaXJxKGNh
c2NhZGVfaXJxKTsNCj4gKwlkZXNjLT5zdGF0dXMgJj0gfklSUV9JTlBST0dSRVNTOw0KPiArDQo+
ICsJaWYgKCEoZGVzYy0+c3RhdHVzICYgSVJRX0RJU0FCTEVEKSAmJiBkZXNjLT5jaGlwLT51bm1h
c2spDQo+ICsJCWRlc2MtPmNoaXAtPnVubWFzayhpcnEpOw0KPiArdW5sb2NrOg0KPiArCXJhd19z
cGluX3VubG9jaygmZGVzYy0+bG9jayk7DQo+ICt9DQoNCj5Ob3csIHRoYXQncyByZWFsbHkgYSB3
ZWlyZCBpZGVhLiBXaHkgYXJlIHlvdSBtYWtpbmcgaXQgYSBjYXNjYWRlZA0KPmludGVycnVwdCBj
b250cm9sbGVyID8gVGhhdCBpcyBqdXN0IGdyYXR1aXRvdXMgb3ZlcmhlYWQuIFlvdSBjb3VsZCBo
YXZlDQo+dGhlIE1TSSBoYW5kbGluZyBkaXJlY3RseSBoYW5kIG91dCB0aGUgYXBwcm9wcmlhdGUg
VUlDIGludGVycnVwdHMgYW5kDQo+aGF2ZSB0aGVtIGNhbGwgZGlyZWN0bHkgaW50byB0aGUgZHJp
dmVyLiBUaGUgYWJvdmUgYWRkcyBzaWduaWZpY2FudA0KPm92ZXJoZWFkIHRvIE1TSSBwcm9jZXNz
aW5nLg0KTWFycmk6IExldCBtZSB0aGluayBtb3JlIGFib3V0IHRoaXMuDQoNCj4gK3N0YXRpYyB2
b2lkIHBwYzR4eF9jb21wb3NlX21zaV9tc2coc3RydWN0IHBjaV9kZXYgKnBkZXYsIGludCBod2ly
cSwNCj4gKwkJCQkJc3RydWN0IG1zaV9tc2cgKm1zZykNCj4gK3sNCj4gKwlzdHJ1Y3QgcHBjNHh4
X21zaSAqbXNpX2RhdGEgPSBwcGM0eHhfbXNpOw0KPiArDQo+ICsJbXNnLT5hZGRyZXNzX2xvID0g
bXNpX2RhdGEtPm1zaV9hZGRyX2xvOw0KPiArCW1zZy0+YWRkcmVzc19oaSA9IG1zaV9kYXRhLT5t
c2lfYWRkcl9oaTsNCj4gKwltc2ctPmRhdGEgPSBod2lycTsNCj4gK30NCj4gKw0KPiAraW50IHBw
YzR4eF9zZXR1cF9tc2lfaXJxcyhzdHJ1Y3QgcGNpX2RldiAqZGV2LCBpbnQgbnZlYywgaW50IHR5
cGUpDQo+ICt7DQo+ICsJc3RydWN0IG1zaV9kZXNjICplbnRyeTsNCj4gKwlpbnQgcmMsIGh3aXJx
Ow0KPiArCXVuc2lnbmVkIGludCB2aXJxOw0KPiArCXN0cnVjdCBtc2lfbXNnIG1zZzsNCj4gKwlz
dHJ1Y3QgcHBjNHh4X21zaSAqbXNpX2RhdGEgPSBwcGM0eHhfbXNpOw0KPiArDQo+ICsNCj4gKwls
aXN0X2Zvcl9lYWNoX2VudHJ5KGVudHJ5LCAmZGV2LT5tc2lfbGlzdCwgbGlzdCkgew0KPiArCQlo
d2lycSA9IG1zaV9iaXRtYXBfYWxsb2NfaHdpcnFzKCZtc2lfZGF0YS0+Yml0bWFwLCAxKTsNCj4g
KwkJaWYgKGh3aXJxIDwgMCkgew0KPiArCQkJcmMgPSBod2lycTsNCj4gKwkJCWRldl9lcnIoJmRl
di0+ZGV2LCAiJXM6IGZhaWwgYWxsb2NhdGluZyBtc2lcDQo+ICsJCQkJCWludGVycnVwdFxuIiwJ
X19mdW5jX18pOw0KPiArCQkJZ290byBvdXRfZnJlZTsNCj4gKwkJfQ0KPiArDQo+ICsJCXByX2Rl
YnVnKEtFUk5fSU5GTyJtaXMgaXMgJXBcbiIsIG1zaV9kYXRhLT5pcnFob3N0KTsNCj4gKwkJdmly
cSA9IGlycV9jcmVhdGVfbWFwcGluZyhtc2lfZGF0YS0+aXJxaG9zdCwgaHdpcnEpOw0KPiArCQlp
ZiAodmlycSA9PSBOT19JUlEpIHsNCj4gKwkJCWRldl9lcnIoJmRldi0+ZGV2LCAiJXM6IGZhaWwg
bWFwcGluZyBpcnFcbiIsIF9fZnVuY19fKTsNCj4gKwkJCXJjID0gLUVOT1NQQzsNCj4gKwkJCWdv
dG8gb3V0X2ZyZWU7DQo+ICsJCX0NCj4gKw0KPiArCQlzZXRfaXJxX21zaSh2aXJxLCBlbnRyeSk7
DQo+ICsJCXBwYzR4eF9jb21wb3NlX21zaV9tc2coZGV2LCBod2lycSwgJm1zZyk7DQo+ICsJCXdy
aXRlX21zaV9tc2codmlycSwgJm1zZyk7DQo+ICsJfQ0KPiArDQo+ICsJcmV0dXJuIDA7DQo+ICtv
dXRfZnJlZToNCj4gKwlyZXR1cm4gcmM7DQo+ICt9DQoNCj5TaW1pbGFyIGhlcmUuIFlvdSBjcmVh
dGUgdGhpcyB3aG9sZSBsYXllciBvZiBzZWNvbmRhcnkgaW50ZXJydXB0IGhvc3QNCj53aGlsZSB5
b3UgY291bGQganVzdCBoYW5kIG91dCBleGlzdGluZyBVSUMgaW50ZXJydXB0cyBubyA/DQpNYXJy
aTogTGV0IG1lIHRoaW5rIG1vcmUgaGVyZSB0b28uDQogDQogLi4uLy4uLg0KDQo+ICsNCj4gK3N0
YXRpYyBpbnQgX19kZXZpbml0IHBwYzR4eF9tc2lfcHJvYmUoc3RydWN0IG9mX2RldmljZSAqZGV2
LA0KPiArCQkJCQljb25zdCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkICptYXRjaCkNCj4gK3sNCj4gKwlz
dHJ1Y3QgcHBjNHh4X21zaSAqbXNpOw0KPiArCXN0cnVjdCByZXNvdXJjZSByZXMsIHJtc2k7DQo+
ICsJaW50IGksIGNvdW50Ow0KPiArCWludCByYzsNCj4gKwlpbnQgdmlydF9tc2lyOw0KPiArCWNv
bnN0IHUzMiAqcDsNCj4gKwljb25zdCB1MzIgKnNkcl9iYXNlOw0KPiArCXUzMiAqbXNpX3ZpcnQg
PSBOVUxMOw0KPiArCWRtYV9hZGRyX3QgbXNpX3BoeXM7DQo+ICsNCj4gKw0KPiArCW1zaSA9IGt6
YWxsb2Moc2l6ZW9mKHN0cnVjdCBwcGM0eHhfbXNpKSwgR0ZQX0tFUk5FTCk7DQo+ICsJaWYgKCFt
c2kpIHsNCj4gKwkJZGV2X2VycigmZGV2LT5kZXYsICJObyBtZW1vcnkgZm9yIE1TSSBzdHJ1Y3R1
cmVcbiIpOw0KPiArCQlyYyA9IC1FTk9NRU07DQo+ICsJCWdvdG8gZXJyb3Jfb3V0Ow0KPiArCX0N
Cj4gKw0KPiArCW1zaS0+aXJxaG9zdCA9IGlycV9hbGxvY19ob3N0KGRldi0+bm9kZSwgSVJRX0hP
U1RfTUFQX0xJTkVBUiwNCj4gKwkJCQkgICAgICBOUl9NU0lfSVJRUywgJnBwYzR4eF9tc2lfaG9z
dF9vcHMsIDApOw0KPiArCWlmIChtc2ktPmlycWhvc3QgPT0gTlVMTCkgew0KPiArCQlkZXZfZXJy
KCZkZXYtPmRldiwgIk5vIG1lbW9yeSBmb3IgTVNJIGlycWhvc3RcbiIpOw0KPiArCQlyYyA9IC1F
Tk9NRU07DQo+ICsJCWdvdG8gZXJyb3Jfb3V0Ow0KPiArCX0NCg0KPlNhbWUgY29tbWVudCwgaWUs
IHdoeSBhIHNlcGFyYXRlIGlycSBob3N0ID8NCk1hcnJpOiBPayBJIHdpbGwgY2hlY2sgdGhpcyBv
bmUuDQo+ICsNCj4gKwkvKiBHZXQgTVNJIHJhbmdlcyAqLw0KPiArCXJjID0gb2ZfYWRkcmVzc190
b19yZXNvdXJjZShkZXYtPm5vZGUsIDAsICZybXNpKTsNCj4gKwlpZiAocmMpIHsNCj4gKwkJZGV2
X2VycigmZGV2LT5kZXYsICIlcyByZXNvdXJjZSBlcnJvciFcbiIsDQo+ICsJCQkJZGV2LT5ub2Rl
LT5mdWxsX25hbWUpOw0KPiArCQlnb3RvIGVycm9yX291dDsNCj4gKwl9DQo+ICsNCj4gKw0KPiAr
CS8qIEdldCB0aGUgTVNJIHJlZyBiYXNlICovDQo+ICsJcmMgPSBvZl9hZGRyZXNzX3RvX3Jlc291
cmNlKGRldi0+bm9kZSwgMSwgJnJlcyk7DQo+ICsJaWYgKHJjKSB7DQo+ICsJCWRldl9lcnIoJmRl
di0+ZGV2LCAiJXMgcmVzb3VyY2UgZXJyb3IhXG4iLA0KPiArCQkJCWRldi0+bm9kZS0+ZnVsbF9u
YW1lKTsNCj4gKwkJZ290byBlcnJvcl9vdXQ7DQo+ICsJfQ0KPiArCS8qIEdldCB0aGUgc2RyLWJh
c2UgKi8NCj4gKwlzZHJfYmFzZSA9ICh1MzIgKilvZl9nZXRfcHJvcGVydHkoZGV2LT5ub2RlLCAi
c2RyLWJhc2UiLCBOVUxMKTsNCj4gKwlpZiAoc2RyX2Jhc2UgPT0gTlVMTCkgew0KPiArCQlkZXZf
ZXJyKCZkZXYtPmRldiwgIiVzIHJlc291cmNlIGVycm9yIVxuIiwNCj4gKwkJCQlkZXYtPm5vZGUt
PmZ1bGxfbmFtZSk7DQo+ICsJCWdvdG8gZXJyb3Jfb3V0Ow0KPiArCX0NCj4gKwltc2ktPnNkcl9i
YXNlID0gKnNkcl9iYXNlOw0KPiArCW10ZGNyaShTRFIwLCBtc2ktPnNkcl9iYXNlLCByZXMuc3Rh
cnQgPj4gMzIpOw0KPiArCW10ZGNyaShTRFIwLCBtc2ktPnNkcl9iYXNlICsgMSwgcmVzLnN0YXJ0
ICYgMHhGRkZGRkZGRik7DQo+ICsJbXNpLT5tc2lfcmVncyA9IGlvcmVtYXAocmVzLnN0YXJ0LCBy
ZXMuZW5kIC0gcmVzLnN0YXJ0ICsgMSk7DQo+ICsJaWYgKCFtc2ktPm1zaV9yZWdzKSB7DQo+ICsJ
CWRldl9lcnIoJmRldi0+ZGV2LCAiaW9yZW1hcCBwcm9ibGVtIGZhaWxlZFxuIik7DQo+ICsJCWdv
dG8gZXJyb3Jfb3V0Ow0KPiArCX0NCj4gKwkvKiBNU0kgcmVnaW9uIGFsd2F5cyBtYXBwZWQgaW4g
NEdCIHJlZ2lvbiovDQo+ICsJbXNpLT5tc2lfYWRkcl9oaSA9IDB4MDsNCj4gKwltc2lfdmlydCA9
IGRtYV9hbGxvY19jb2hlcmVudCgmZGV2LT5kZXYsIDY0LCAmbXNpX3BoeXMsDQo+ICsJCQlHRlBf
S0VSTkVMKTsNCj4gKwlpZiAobXNpX3ZpcnQgPT0gTlVMTCkgew0KPiArCQlkZXZfZXJyKCZkZXYt
PmRldiwgIk5vIG1lbW9yeSBmb3IgTVNJIG1lbSBzcGFjZVxuIik7DQo+ICsJCXJjID0gLUVOT01F
TTsNCj4gKwkJZ290byBlcnJvcl9vdXQ7DQo+ICsJfQ0KPiArCW1zaS0+bXNpX2FkZHJfbG8gPSAo
dTMyKW1zaV9waHlzOw0KDQo+Tm93LCB3aGF0IGlzIHRoZSBhYm92ZSBmb3IgPyBBcmUgdGhlIE1T
SSB3cml0ZXMgZG9uZSBieSB0aGUgZGV2aWNlDQo+YWN0dWFsbHkgaGl0dGluZyBtZW1vcnkgYXMg
d2VsbCA/IEkgd291bGQgaGF2ZSBleHBlY3RlZCB0aGVtIHRvIGJlDQo+ZmlsdGVyZWQgYnkgdGhl
IGJyaWRnZSBvbiB0aGUgd2F5IHVwLCBhcmUgdGhleSBub3QgPw0KDQo+SSBzdXBwb3NlIGl0IGdp
dmVzIHlvdSBhIGNoZWFwIHdheSB0byBvYnRhaW4gYSBiaXQgb2YgdW51c2VkIGFkZHJlc3MNCj5z
cGFjZS4uLg0KTWFycmk6ICBQQ0ktRSBpbnRlcnJ1cHQgaGFuZGxlciBuZWVkcyBhbiBhZGRyZXNz
IHJlZ2lvbiB3aGVyZSBpdCBjYW4gc25vb3AgDQpUaGUgYWRkcmVzcyBhbmQgZGF0YSB0byBjYXVz
ZSBhcHByb3ByaWF0ZSBNU0kuDQoNCj4gKwkvKiBQcm9nYW0gdGhlIEludGVycnVwdCBoYW5kbGVy
IFRlcm1pbmF0aW9uIGFkZHIgcmVnaXN0ZXJzICovDQo+ICsJb3V0X2JlMzIobXNpLT5tc2lfcmVn
cyArIFBFSUhfVEVSTUFESCwgbXNpLT5tc2lfYWRkcl9oaSk7DQo+ICsJb3V0X2JlMzIobXNpLT5t
c2lfcmVncyArIFBFSUhfVEVSTUFETCwgbXNpLT5tc2lfYWRkcl9sbyk7DQo+ICsNCj4gKwkvKiBQ
cm9ncmFtIE1TSSBFeHBlY3RlZCBkYXRhIGFuZCBNYXNrIGJpdHMgKi8NCj4gKwlvdXRfYmUzMiht
c2ktPm1zaV9yZWdzICsgUEVJSF9NU0lFRCwgTVNJX0RBVEFfUEFUVEVSTik7DQo+ICsJb3V0X2Jl
MzIobXNpLT5tc2lfcmVncyArIFBFSUhfTVNJTUssIE1TSV9EQVRBX1BBVFRFUk4pOw0KDQo+Q2Fu
IHlvdSB0ZWxsIG1lIGEgYml0IG1vcmUgYWJvdXQgd2hhdCB0aGUgYWJvdmUgaXMgYWJvdXQgPw0K
TWFycmk6IEFzIEkgcHJldmlvdXNseSBzYWlkIFBDSS1FIGludGVycnVwdCBoYW5kbGVyIHNub29w
cyBzeXN0ZW0gYnVzDQpGb3IgY2VydGFpbiBhZGRyZXNzIGFuZCBkYXRhLCB0aGlzIGFkZHJlc3Mg
Y291bGQgYmUgY2FsbGluZyBpbiB0aGUgDQpERFIgbWVtb3J5IHJlZ2lvbiAuIFdoZXJlIEREUiBj
b250cm9sbGVyIGNhbiBxdWV1ZSBjb21tYW5kcyBhbmQgc29tZSB0aW1lcyANClRoaXMgbWlnaHQg
Y2F1c2UgZGVsYXkgaW4gQUNLLiBUaGlzIHdpbGwgdGVybWluYXRlIHRoZSB3cml0ZSB0cmFuc2Fj
dGlvbg0KQW5kIHNlbmRzIGltbWVkaWF0ZSBBQ0suDQoNCj5BbHNvLCBpdCBsb29rcyBsaWtlIHlv
dXIgY29kZSB3b3VsZCB3b3JrIGZvciBvdGhlciBTb0NzIGxpa2UgNDYwRVgNCj5ldGMuLi4gYnkg
anVzdCB1cGRhdGluZyB0aGUgLmR0cyByaWdodCA/IENhcmUgdG8gdXBkYXRlIGEgZmV3IG1vcmUN
Cj5ib2FyZHMgc28gSSBjYW4gdGVzdCBvbiBteSBjYW55b25sYW5kcyA/IDotKQ0KDQpJbiB0aGUg
bmV4dCBwYXRjaCBJIHdpbGwgdHJ5IGFkZCB0aGUgNDYwRXgoQ2FueW9ubGFuZHMgc3VwcG9ydCB0
b28pDQoNCg0KUmVnYXJkcywNCk1hcnJpDQo=

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

* RE: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
  2009-12-23 17:23   ` Tirumala Reddy Marri
@ 2009-12-23 17:30     ` Tirumala Reddy Marri
  0 siblings, 0 replies; 10+ messages in thread
From: Tirumala Reddy Marri @ 2009-12-23 17:30 UTC (permalink / raw)
  To: Tirumala Reddy Marri, Stefan Roese, linuxppc-dev
  Cc: linuxppc-dev, writetomarri

BTW once this patch gets in I will add the 405Ex,460Ex and 440Spe
support to the same.

-----Original Message-----
From: linuxppc-dev-bounces+tmarri=3Damcc.com@lists.ozlabs.org
[mailto:linuxppc-dev-bounces+tmarri=3Damcc.com@lists.ozlabs.org] On =
Behalf
Of Tirumala Reddy Marri
Sent: Wednesday, December 23, 2009 9:23 AM
To: Stefan Roese; linuxppc-dev@lists.ozlabs.org
Cc: linuxppc-dev@ozlabs.org; writetomarri@yahoo.com
Subject: RE: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.

Thanks for the suggestions. I will try remove the extra lines . Add
changes you suggested.
-Marri

-----Original Message-----
From: linuxppc-dev-bounces+tmarri=3Damcc.com@lists.ozlabs.org
[mailto:linuxppc-dev-bounces+tmarri=3Damcc.com@lists.ozlabs.org] On =
Behalf
Of Stefan Roese
Sent: Wednesday, December 23, 2009 12:19 AM
To: linuxppc-dev@lists.ozlabs.org
Cc: linuxppc-dev@ozlabs.org; writetomarri@yahoo.com; Tirumala Reddy
Marri
Subject: Re: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.

On Wednesday 23 December 2009 08:52:23 tmarri@amcc.com wrote:
> From: Tirumala Marri <tmarri@amcc.com>

Please find some mostly nitpicking comments below.

BTW: Did you already test this on other 4xx platforms, like 440SPe or
405EX?=20
What are your plans here?
=20
> Signed-off-by: Tirumala Marri <tmarri@amcc.com>
> ---
> Kernel version: 2.6.33-rc1
> Testing:
> 	When 460SX configured as root as a end point E1000(Intell
Ethernet card)
> 	was plugged into the one of the PCI-E ports. I was able to run
the traffic
> 	with MSI interrupts.
> ---
>  arch/powerpc/boot/dts/redwood.dts          |   15 ++
>  arch/powerpc/configs/44x/redwood_defconfig |    5 +-
>  arch/powerpc/platforms/44x/Kconfig         |    1 +
>  arch/powerpc/sysdev/Kconfig                |    7 +
>  arch/powerpc/sysdev/Makefile               |    1 +
>  arch/powerpc/sysdev/ppc4xx_msi.c           |  342
>  ++++++++++++++++++++++++++++ arch/powerpc/sysdev/ppc4xx_msi.h
|=20
>   39 ++++
>  7 files changed, 408 insertions(+), 2 deletions(-)
>  create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
>  create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.h
>=20
> diff --git a/arch/powerpc/boot/dts/redwood.dts
>  b/arch/powerpc/boot/dts/redwood.dts index 81636c0..412d5f9 100644
> --- a/arch/powerpc/boot/dts/redwood.dts
> +++ b/arch/powerpc/boot/dts/redwood.dts
> @@ -357,6 +357,21 @@
>  				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /*
swizzled int C */
>  				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /*
swizzled int D */>;
>  		};
> +  		MSI: ppc4xx-msi@400300000 {
> +  			compatible =3D "amcc,ppc4xx-msi", "ppc4xx-msi";

Better use something like this:

  			compatible =3D "amcc,ppc4xx-msi-ppc460sx",
"amcc,ppc4xx-msi";

This way you could check for 460SX specials in the driver if needed.

> +  			reg =3D < 0x4 0x00300000 0x100
> +  				0x4 0x00300000 0x100>;
> +  			sdr-base =3D <0x3B0>;
> +  			interrupts =3D<0 1 2 3>;
> +  			interrupt-parent =3D <&MSI>;
> +  			#interrupt-cells =3D <1>;
> +  			#address-cells =3D <0>;
> +  			#size-cells =3D <0>;
> +  			interrupt-map =3D <0 &UIC0 0xC 1
> +  				1 &UIC0 0x0D 1
> +  				2 &UIC0 0x0E 1
> +  				3 &UIC0 0x0F 1>;
> +  		};
>=20
>  	};
>=20
> diff --git a/arch/powerpc/configs/44x/redwood_defconfig
>  b/arch/powerpc/configs/44x/redwood_defconfig index ed31d4f..5d16c88
100644
> --- a/arch/powerpc/configs/44x/redwood_defconfig
> +++ b/arch/powerpc/configs/44x/redwood_defconfig
> @@ -158,6 +158,7 @@ CONFIG_DEFAULT_AS=3Dy
>  CONFIG_DEFAULT_IOSCHED=3D"anticipatory"
>  # CONFIG_FREEZER is not set
>  CONFIG_PPC4xx_PCI_EXPRESS=3Dy
> +CONFIG_PPC_MSI_BITMAP=3Dy
>=20
>  #
>  # Platform support
> @@ -264,7 +265,7 @@ CONFIG_PCIEPORTBUS=3Dy
>  CONFIG_PCIEAER=3Dy
>  # CONFIG_PCIEASPM is not set
>  CONFIG_ARCH_SUPPORTS_MSI=3Dy
> -# CONFIG_PCI_MSI is not set
> +CONFIG_PCI_MSI=3Dy
>  # CONFIG_PCI_LEGACY is not set
>  # CONFIG_PCI_DEBUG is not set
>  # CONFIG_PCI_STUB is not set
> @@ -1062,7 +1063,7 @@ CONFIG_PRINT_STACK_DEPTH=3D64
>  # CONFIG_DEBUG_PAGEALLOC is not set
>  # CONFIG_CODE_PATCHING_SELFTEST is not set
>  # CONFIG_FTR_FIXUP_SELFTEST is not set
> -# CONFIG_MSI_BITMAP_SELFTEST is not set
> +CONFIG_MSI_BITMAP_SELFTEST=3Dy
>  # CONFIG_XMON is not set
>  # CONFIG_IRQSTACKS is not set
>  # CONFIG_VIRQ_DEBUG is not set
> diff --git a/arch/powerpc/platforms/44x/Kconfig
>  b/arch/powerpc/platforms/44x/Kconfig index 7486bff..9c3b8ca 100644
> --- a/arch/powerpc/platforms/44x/Kconfig
> +++ b/arch/powerpc/platforms/44x/Kconfig
> @@ -126,6 +126,7 @@ config REDWOOD
>  	select 460SX
>  	select PCI
>  	select PPC4xx_PCI_EXPRESS
> +	select PPC4xx_MSI
>  	help
>  	  This option enables support for the AMCC PPC460SX Redwood
board.
>=20
> diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
> index 3965828..c8f1486 100644
> --- a/arch/powerpc/sysdev/Kconfig
> +++ b/arch/powerpc/sysdev/Kconfig
> @@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
>  	depends on PCI && 4xx
>  	default n
>=20
> +config PPC4xx_MSI
> +	bool
> +	depends on PCI_MSI
> +	depends on PCI && 4xx
> +	default n
> +
>  config PPC_MSI_BITMAP
>  	bool
>  	depends on PCI_MSI
>  	default y if MPIC
>  	default y if FSL_PCI
> +	default y if PPC4xx_MSI
> diff --git a/arch/powerpc/sysdev/Makefile
b/arch/powerpc/sysdev/Makefile
> index 5642924..4c67d2d 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_I8259)		+=3D i8259.o
>  obj-$(CONFIG_IPIC)		+=3D ipic.o
>  obj-$(CONFIG_4xx)		+=3D uic.o
>  obj-$(CONFIG_4xx_SOC)		+=3D ppc4xx_soc.o
> +obj-$(CONFIG_PPC4xx_MSI)		+=3D ppc4xx_msi.o
>  obj-$(CONFIG_XILINX_VIRTEX)	+=3D xilinx_intc.o
>  obj-$(CONFIG_XILINX_PCI)	+=3D xilinx_pci.o
>  obj-$(CONFIG_OF_RTC)		+=3D of_rtc.o
> diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c
>  b/arch/powerpc/sysdev/ppc4xx_msi.c new file mode 100644
> index 0000000..3c2ef32
> --- /dev/null
> +++ b/arch/powerpc/sysdev/ppc4xx_msi.c
> @@ -0,0 +1,342 @@
> +/*
> + * Copyright (C) 2009 Applied Micro Circuits corporation.
> + *
> + * Author: Feng Kan <fkan@amcc.com>
> + * 	   Tirumala Marri <tmarri@amcc.com>
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; version 2 of the
> + * License.
> + */
> +#include <linux/irq.h>
> +#include <linux/bootmem.h>
> +#include <linux/pci.h>
> +#include <linux/msi.h>
> +#include <linux/of_platform.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <asm/prom.h>
> +#include <asm/hw_irq.h>
> +#include <asm/ppc-pci.h>
> +#include <asm/dcr.h>
> +#include <asm/dcr-regs.h>
> +#include "ppc4xx_msi.h"
> +
> +

Nitpicking: Remove one empty line here.

> +static struct ppc4xx_msi *ppc4xx_msi;
> +
> +struct ppc4xx_msi_feature {
> +	u32 ppc4xx_pic_ip;
> +	u32 msiir_offset;
> +};
> +
> +static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
> +{
> +	int rc;
> +
> +	rc =3D msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
> +				msi_data->irqhost->of_node);
> +	if (rc)
> +		return rc;
> +	rc =3D msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
> +	if (rc < 0) {
> +		msi_bitmap_free(&msi_data->bitmap);
> +		return rc;
> +	}
> +	return 0;
> +}
> +
> +

Nitpicking: Remove one empty line here.

> +static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc
*desc)
> +{
> +	unsigned int cascade_irq;
> +	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
> +	int msir_index =3D -1;
> +
> +	raw_spin_lock(&desc->lock);
> +	if (desc->chip->mask_ack) {
> +		desc->chip->mask_ack(irq);
> +	} else {
> +		desc->chip->mask(irq);
> +		desc->chip->ack(irq);
> +	}
> +
> +	if (unlikely(desc->status & IRQ_INPROGRESS))
> +		goto unlock;
> +
> +	msir_index =3D (int)desc->handler_data;
> +
> +	if (msir_index >=3D NR_MSI_IRQS)
> +		cascade_irq =3D NO_IRQ;
> +
> +	desc->status |=3D IRQ_INPROGRESS;
> +
> +	cascade_irq =3D irq_linear_revmap(msi_data->irqhost, msir_index);
> +	if (cascade_irq !=3D NO_IRQ)
> +		generic_handle_irq(cascade_irq);
> +	desc->status &=3D ~IRQ_INPROGRESS;
> +
> +	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
> +		desc->chip->unmask(irq);
> +unlock:
> +	raw_spin_unlock(&desc->lock);
> +}

Nitpicking: Add one empty line here.

> +static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
> +					struct msi_msg *msg)
> +{
> +	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
> +
> +	msg->address_lo =3D msi_data->msi_addr_lo;
> +	msg->address_hi =3D msi_data->msi_addr_hi;
> +	msg->data =3D hwirq;
> +}
> +
> +

Nitpicking: Remove one empty line here.

> +int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> +	struct msi_desc *entry;
> +	int rc, hwirq;
> +	unsigned int virq;
> +	struct msi_msg msg;
> +	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
> +
> +
> +	list_for_each_entry(entry, &dev->msi_list, list) {
> +		hwirq =3D msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
> +		if (hwirq < 0) {
> +			rc =3D hwirq;
> +			dev_err(&dev->dev, "%s: fail allocating msi\
> +					interrupt\n",	__func__);
> +			goto out_free;
> +		}
> +
> +		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
> +		virq =3D irq_create_mapping(msi_data->irqhost, hwirq);
> +		if (virq =3D=3D NO_IRQ) {
> +			dev_err(&dev->dev, "%s: fail mapping irq\n",
__func__);
> +			rc =3D -ENOSPC;
> +			goto out_free;
> +		}
> +
> +		set_irq_msi(virq, entry);
> +		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
> +		write_msi_msg(virq, &msg);
> +	}
> +
> +	return 0;
> +out_free:
> +	return rc;
> +}
> +
> +void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
> +{
> +	struct msi_desc *entry;
> +	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
> +	 dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
> +
> +	list_for_each_entry(entry, &dev->msi_list, list) {
> +		if (entry->irq =3D=3D NO_IRQ)
> +			continue;
> +		set_irq_msi(entry->irq, NULL);
> +		msi_bitmap_free_hwirqs(&msi_data->bitmap,
> +				       virq_to_hw(entry->irq), 1);
> +		irq_dispose_mapping(entry->irq);
> +

Nitpicking: Remove one empty line here.

> +	}
> +
> +	return;
> +}
> +
> +static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec,
int
>  type) +{
> +	pr_debug(KERN_INFO"PCIE-MSI:%s called. vec %x type %d\n",
> +					__func__, nvec, type);
> +	return 0;
> +}
> +
> +/*
> + * We do not need this actually. The MSIR register has been read once
> + * in the cascade interrupt. So, this MSI interrupt has been acked
> +*/
> +static void ppc4xx_msi_end_irq(unsigned int virq)
> +{
> +}
> +
> +

Nitpicking: Remove one empty line here. I'll stop mentioning this here.
Please=20
check the whole file for this.

> +static struct irq_chip ppc4xx_msi_chip =3D {
> +	.mask           =3D mask_msi_irq,
> +	.unmask         =3D unmask_msi_irq,
> +	.ack            =3D ppc4xx_msi_end_irq,
> +	.name       =3D " UIC",
> +};
> +
> +static int ppc4xx_msi_host_map(struct irq_host *h, unsigned int virq,
> +				irq_hw_number_t hw)
> +{
> +	struct irq_chip *chip =3D &ppc4xx_msi_chip;
> +
> +	irq_to_desc(virq)->status |=3D IRQ_TYPE_EDGE_RISING;
> +
> +	set_irq_chip_and_handler(virq, chip, handle_edge_irq);
> +
> +	return 0;
> +}
> +
> +static struct irq_host_ops ppc4xx_msi_host_ops =3D {
> +	.map =3D ppc4xx_msi_host_map,
> +};
> +
> +
> +static int __devinit ppc4xx_msi_probe(struct of_device *dev,
> +					const struct of_device_id
*match)
> +{
> +	struct ppc4xx_msi *msi;
> +	struct resource res, rmsi;
> +	int i, count;
> +	int rc;
> +	int virt_msir;
> +	const u32 *p;
> +	const u32 *sdr_base;
> +	u32 *msi_virt =3D NULL;
> +	dma_addr_t msi_phys;
> +
> +
> +	msi =3D kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
> +	if (!msi) {
> +		dev_err(&dev->dev, "No memory for MSI structure\n");
> +		rc =3D -ENOMEM;
> +		goto error_out;
> +	}
> +
> +	msi->irqhost =3D irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
> +				      NR_MSI_IRQS, &ppc4xx_msi_host_ops,
0);
> +	if (msi->irqhost =3D=3D NULL) {
> +		dev_err(&dev->dev, "No memory for MSI irqhost\n");
> +		rc =3D -ENOMEM;
> +		goto error_out;
> +	}
> +
> +
> +	/* Get MSI ranges */
> +	rc =3D of_address_to_resource(dev->node, 0, &rmsi);
> +	if (rc) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +
> +
> +	/* Get the MSI reg base */
> +	rc =3D of_address_to_resource(dev->node, 1, &res);
> +	if (rc) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +	/* Get the sdr-base */
> +	sdr_base =3D (u32 *)of_get_property(dev->node, "sdr-base", NULL);
> +	if (sdr_base =3D=3D NULL) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +	msi->sdr_base =3D *sdr_base;
> +#if  defined(CONFIG_460SX)
> +	mtdcri(SDR0, msi->sdr_base, res.start >> 32);
> +	mtdcri(SDR0, msi->sdr_base + 1, res.start & 0xFFFFFFFF);
> +	msi->msi_regs =3D ioremap(res.start, res.end - res.start + 1);

	msi->msi_regs =3D ioremap(res.start, resource_size(&res));

> +#else
> +	dev_err(&dev->dev, " Invalid Device \n");
> +	goto error_out;
> +#endif

Please don't introduce such a compile-time selection here. You don't
even need=20
it, since the register bases are provided via the device-tree. So just
remove=20
the #if and it's #else part here.

> +	if (!msi->msi_regs) {
> +		dev_err(&dev->dev, "ioremap problem failed\n");
> +		goto error_out;
> +	}
> +	/* MSI region always mapped in 4GB region*/
> +	msi->msi_addr_hi =3D 0x0;
> +	msi_virt =3D dma_alloc_coherent(&dev->dev, 64, &msi_phys,
> +			GFP_KERNEL);
> +	if (msi_virt =3D=3D NULL) {
> +		dev_err(&dev->dev, "No memory for MSI mem space\n");
> +		rc =3D -ENOMEM;
> +		goto error_out;
> +	}
> +	msi->msi_addr_lo =3D (u32)msi_phys;
> +
> +	/* Progam the Interrupt handler Termination addr registers */
> +	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
> +	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
> +
> +	/* Program MSI Expected data and Mask bits */
> +	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
> +	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);
> +
> +	msi->irqhost->host_data =3D msi;
> +
> +	if (ppc4xx_msi_init_allocator(msi)) {
> +		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
> +		goto error_out;
> +	}
> +
> +	p =3D of_get_property(dev->node, "interrupts", &count);
> +	if (!p) {
> +		dev_err(&dev->dev, "no interrupts property found on
%s\n",
> +				dev->node->full_name);
> +		rc =3D -ENODEV;
> +		goto error_out;
> +	}
> +	if (count =3D=3D 0) {
> +		dev_err(&dev->dev, "Malformed interrupts property on
%s\n",
> +				dev->node->full_name);
> +		rc =3D -EINVAL;
> +		goto error_out;
> +	}
> +
> +	for (i =3D 0; i < NR_MSI_IRQS; i++) {
> +		virt_msir =3D irq_of_parse_and_map(dev->node, i);
> +		if (virt_msir !=3D NO_IRQ) {
> +			set_irq_data(virt_msir, (void *)i);
> +			set_irq_chained_handler(virt_msir,
ppc4xx_msi_cascade);
> +		}
> +	}
> +
> +	ppc4xx_msi =3D msi;
> +
> +	WARN_ON(ppc_md.setup_msi_irqs);
> +	ppc_md.setup_msi_irqs =3D ppc4xx_setup_msi_irqs;
> +	ppc_md.teardown_msi_irqs =3D ppc4xx_teardown_msi_irqs;
> +	ppc_md.msi_check_device =3D ppc4xx_msi_check_device;
> +	return 0;
> +error_out:
> +	if (msi_virt)
> +		dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
> +	kfree(msi);
> +	return rc;
> +}
> +
> +static const struct ppc4xx_msi_feature ppc4xx_msi_feature =3D {
> +	.ppc4xx_pic_ip =3D 0,
> +	.msiir_offset =3D 0x140,
> +};
> +
> +static const struct of_device_id ppc4xx_msi_ids[] =3D {
> +	{
> +		.compatible =3D "amcc,ppc4xx-msi",
> +		.data =3D (void *)&ppc4xx_msi_feature,
> +	},
> +	{}
> +};
> +
> +static struct of_platform_driver ppc4xx_msi_driver =3D {
> +	.name =3D "ppc4xx-msi",
> +	.match_table =3D ppc4xx_msi_ids,
> +	.probe =3D ppc4xx_msi_probe,
> +};
> +
> +static __init int ppc4xx_msi_init(void)
> +{
> +	return of_register_platform_driver(&ppc4xx_msi_driver);
> +}
> +
> +subsys_initcall(ppc4xx_msi_init);
> diff --git a/arch/powerpc/sysdev/ppc4xx_msi.h
>  b/arch/powerpc/sysdev/ppc4xx_msi.h new file mode 100644
> index 0000000..e4ae058
> --- /dev/null
> +++ b/arch/powerpc/sysdev/ppc4xx_msi.h
> @@ -0,0 +1,39 @@
> +/*
> + * Copyright (C) 2009 Applied Micro Circuits Corporation.
> + *
> + * Author: Tirumala Marri <tmarri@amcc.com>
> + * 		Feng Kan <fkan@amcc.com>
> + * 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.
> + */
> +#ifndef __PPC4XX_MSI_H__
> +#define __PPC4XX_MSI_H__
> +
> +#include <asm/msi_bitmap.h>
> +
> +#define PEIH_TERMADH    0x00
> +#define PEIH_TERMADL    0x08
> +#define PEIH_MSIED      0x10
> +#define PEIH_MSIMK      0x18
> +#define PEIH_MSIASS     0x20
> +#define PEIH_FLUSH0     0x30
> +#define PEIH_FLUSH1     0x38
> +#define PEIH_CNTRST     0x48
> +
> +#define MSI_DATA_PATTERN   0x44440000
> +
> +struct ppc4xx_msi {
> +	struct irq_host *irqhost;
> +	unsigned long cascade_irq;
> +	u32 msi_addr_lo;
> +	u32 msi_addr_hi;
> +	void __iomem *msi_regs;
> +	u32 feature;
> +	struct msi_bitmap bitmap;
> +	u32 sdr_base;
> +};
> +
> +#define NR_MSI_IRQS 4
> +#endif /* __PPC4XX_MSI_H__ */
>=20

Cheers,
Stefan

--
DENX Software Engineering GmbH,      MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich,  Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-0 Fax: (+49)-8142-66989-80 Email: office@denx.de
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

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

* RE: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
  2009-12-23  8:18 ` Stefan Roese
@ 2009-12-23 17:23   ` Tirumala Reddy Marri
  2009-12-23 17:30     ` Tirumala Reddy Marri
  0 siblings, 1 reply; 10+ messages in thread
From: Tirumala Reddy Marri @ 2009-12-23 17:23 UTC (permalink / raw)
  To: Stefan Roese, linuxppc-dev; +Cc: linuxppc-dev, writetomarri

Thanks for the suggestions. I will try remove the extra lines . Add
changes you suggested.
-Marri

-----Original Message-----
From: linuxppc-dev-bounces+tmarri=3Damcc.com@lists.ozlabs.org
[mailto:linuxppc-dev-bounces+tmarri=3Damcc.com@lists.ozlabs.org] On =
Behalf
Of Stefan Roese
Sent: Wednesday, December 23, 2009 12:19 AM
To: linuxppc-dev@lists.ozlabs.org
Cc: linuxppc-dev@ozlabs.org; writetomarri@yahoo.com; Tirumala Reddy
Marri
Subject: Re: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.

On Wednesday 23 December 2009 08:52:23 tmarri@amcc.com wrote:
> From: Tirumala Marri <tmarri@amcc.com>

Please find some mostly nitpicking comments below.

BTW: Did you already test this on other 4xx platforms, like 440SPe or
405EX?=20
What are your plans here?
=20
> Signed-off-by: Tirumala Marri <tmarri@amcc.com>
> ---
> Kernel version: 2.6.33-rc1
> Testing:
> 	When 460SX configured as root as a end point E1000(Intell
Ethernet card)
> 	was plugged into the one of the PCI-E ports. I was able to run
the traffic
> 	with MSI interrupts.
> ---
>  arch/powerpc/boot/dts/redwood.dts          |   15 ++
>  arch/powerpc/configs/44x/redwood_defconfig |    5 +-
>  arch/powerpc/platforms/44x/Kconfig         |    1 +
>  arch/powerpc/sysdev/Kconfig                |    7 +
>  arch/powerpc/sysdev/Makefile               |    1 +
>  arch/powerpc/sysdev/ppc4xx_msi.c           |  342
>  ++++++++++++++++++++++++++++ arch/powerpc/sysdev/ppc4xx_msi.h
|=20
>   39 ++++
>  7 files changed, 408 insertions(+), 2 deletions(-)
>  create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
>  create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.h
>=20
> diff --git a/arch/powerpc/boot/dts/redwood.dts
>  b/arch/powerpc/boot/dts/redwood.dts index 81636c0..412d5f9 100644
> --- a/arch/powerpc/boot/dts/redwood.dts
> +++ b/arch/powerpc/boot/dts/redwood.dts
> @@ -357,6 +357,21 @@
>  				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /*
swizzled int C */
>  				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /*
swizzled int D */>;
>  		};
> +  		MSI: ppc4xx-msi@400300000 {
> +  			compatible =3D "amcc,ppc4xx-msi", "ppc4xx-msi";

Better use something like this:

  			compatible =3D "amcc,ppc4xx-msi-ppc460sx",
"amcc,ppc4xx-msi";

This way you could check for 460SX specials in the driver if needed.

> +  			reg =3D < 0x4 0x00300000 0x100
> +  				0x4 0x00300000 0x100>;
> +  			sdr-base =3D <0x3B0>;
> +  			interrupts =3D<0 1 2 3>;
> +  			interrupt-parent =3D <&MSI>;
> +  			#interrupt-cells =3D <1>;
> +  			#address-cells =3D <0>;
> +  			#size-cells =3D <0>;
> +  			interrupt-map =3D <0 &UIC0 0xC 1
> +  				1 &UIC0 0x0D 1
> +  				2 &UIC0 0x0E 1
> +  				3 &UIC0 0x0F 1>;
> +  		};
>=20
>  	};
>=20
> diff --git a/arch/powerpc/configs/44x/redwood_defconfig
>  b/arch/powerpc/configs/44x/redwood_defconfig index ed31d4f..5d16c88
100644
> --- a/arch/powerpc/configs/44x/redwood_defconfig
> +++ b/arch/powerpc/configs/44x/redwood_defconfig
> @@ -158,6 +158,7 @@ CONFIG_DEFAULT_AS=3Dy
>  CONFIG_DEFAULT_IOSCHED=3D"anticipatory"
>  # CONFIG_FREEZER is not set
>  CONFIG_PPC4xx_PCI_EXPRESS=3Dy
> +CONFIG_PPC_MSI_BITMAP=3Dy
>=20
>  #
>  # Platform support
> @@ -264,7 +265,7 @@ CONFIG_PCIEPORTBUS=3Dy
>  CONFIG_PCIEAER=3Dy
>  # CONFIG_PCIEASPM is not set
>  CONFIG_ARCH_SUPPORTS_MSI=3Dy
> -# CONFIG_PCI_MSI is not set
> +CONFIG_PCI_MSI=3Dy
>  # CONFIG_PCI_LEGACY is not set
>  # CONFIG_PCI_DEBUG is not set
>  # CONFIG_PCI_STUB is not set
> @@ -1062,7 +1063,7 @@ CONFIG_PRINT_STACK_DEPTH=3D64
>  # CONFIG_DEBUG_PAGEALLOC is not set
>  # CONFIG_CODE_PATCHING_SELFTEST is not set
>  # CONFIG_FTR_FIXUP_SELFTEST is not set
> -# CONFIG_MSI_BITMAP_SELFTEST is not set
> +CONFIG_MSI_BITMAP_SELFTEST=3Dy
>  # CONFIG_XMON is not set
>  # CONFIG_IRQSTACKS is not set
>  # CONFIG_VIRQ_DEBUG is not set
> diff --git a/arch/powerpc/platforms/44x/Kconfig
>  b/arch/powerpc/platforms/44x/Kconfig index 7486bff..9c3b8ca 100644
> --- a/arch/powerpc/platforms/44x/Kconfig
> +++ b/arch/powerpc/platforms/44x/Kconfig
> @@ -126,6 +126,7 @@ config REDWOOD
>  	select 460SX
>  	select PCI
>  	select PPC4xx_PCI_EXPRESS
> +	select PPC4xx_MSI
>  	help
>  	  This option enables support for the AMCC PPC460SX Redwood
board.
>=20
> diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
> index 3965828..c8f1486 100644
> --- a/arch/powerpc/sysdev/Kconfig
> +++ b/arch/powerpc/sysdev/Kconfig
> @@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
>  	depends on PCI && 4xx
>  	default n
>=20
> +config PPC4xx_MSI
> +	bool
> +	depends on PCI_MSI
> +	depends on PCI && 4xx
> +	default n
> +
>  config PPC_MSI_BITMAP
>  	bool
>  	depends on PCI_MSI
>  	default y if MPIC
>  	default y if FSL_PCI
> +	default y if PPC4xx_MSI
> diff --git a/arch/powerpc/sysdev/Makefile
b/arch/powerpc/sysdev/Makefile
> index 5642924..4c67d2d 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_I8259)		+=3D i8259.o
>  obj-$(CONFIG_IPIC)		+=3D ipic.o
>  obj-$(CONFIG_4xx)		+=3D uic.o
>  obj-$(CONFIG_4xx_SOC)		+=3D ppc4xx_soc.o
> +obj-$(CONFIG_PPC4xx_MSI)		+=3D ppc4xx_msi.o
>  obj-$(CONFIG_XILINX_VIRTEX)	+=3D xilinx_intc.o
>  obj-$(CONFIG_XILINX_PCI)	+=3D xilinx_pci.o
>  obj-$(CONFIG_OF_RTC)		+=3D of_rtc.o
> diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c
>  b/arch/powerpc/sysdev/ppc4xx_msi.c new file mode 100644
> index 0000000..3c2ef32
> --- /dev/null
> +++ b/arch/powerpc/sysdev/ppc4xx_msi.c
> @@ -0,0 +1,342 @@
> +/*
> + * Copyright (C) 2009 Applied Micro Circuits corporation.
> + *
> + * Author: Feng Kan <fkan@amcc.com>
> + * 	   Tirumala Marri <tmarri@amcc.com>
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; version 2 of the
> + * License.
> + */
> +#include <linux/irq.h>
> +#include <linux/bootmem.h>
> +#include <linux/pci.h>
> +#include <linux/msi.h>
> +#include <linux/of_platform.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <asm/prom.h>
> +#include <asm/hw_irq.h>
> +#include <asm/ppc-pci.h>
> +#include <asm/dcr.h>
> +#include <asm/dcr-regs.h>
> +#include "ppc4xx_msi.h"
> +
> +

Nitpicking: Remove one empty line here.

> +static struct ppc4xx_msi *ppc4xx_msi;
> +
> +struct ppc4xx_msi_feature {
> +	u32 ppc4xx_pic_ip;
> +	u32 msiir_offset;
> +};
> +
> +static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
> +{
> +	int rc;
> +
> +	rc =3D msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
> +				msi_data->irqhost->of_node);
> +	if (rc)
> +		return rc;
> +	rc =3D msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
> +	if (rc < 0) {
> +		msi_bitmap_free(&msi_data->bitmap);
> +		return rc;
> +	}
> +	return 0;
> +}
> +
> +

Nitpicking: Remove one empty line here.

> +static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc
*desc)
> +{
> +	unsigned int cascade_irq;
> +	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
> +	int msir_index =3D -1;
> +
> +	raw_spin_lock(&desc->lock);
> +	if (desc->chip->mask_ack) {
> +		desc->chip->mask_ack(irq);
> +	} else {
> +		desc->chip->mask(irq);
> +		desc->chip->ack(irq);
> +	}
> +
> +	if (unlikely(desc->status & IRQ_INPROGRESS))
> +		goto unlock;
> +
> +	msir_index =3D (int)desc->handler_data;
> +
> +	if (msir_index >=3D NR_MSI_IRQS)
> +		cascade_irq =3D NO_IRQ;
> +
> +	desc->status |=3D IRQ_INPROGRESS;
> +
> +	cascade_irq =3D irq_linear_revmap(msi_data->irqhost, msir_index);
> +	if (cascade_irq !=3D NO_IRQ)
> +		generic_handle_irq(cascade_irq);
> +	desc->status &=3D ~IRQ_INPROGRESS;
> +
> +	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
> +		desc->chip->unmask(irq);
> +unlock:
> +	raw_spin_unlock(&desc->lock);
> +}

Nitpicking: Add one empty line here.

> +static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
> +					struct msi_msg *msg)
> +{
> +	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
> +
> +	msg->address_lo =3D msi_data->msi_addr_lo;
> +	msg->address_hi =3D msi_data->msi_addr_hi;
> +	msg->data =3D hwirq;
> +}
> +
> +

Nitpicking: Remove one empty line here.

> +int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> +	struct msi_desc *entry;
> +	int rc, hwirq;
> +	unsigned int virq;
> +	struct msi_msg msg;
> +	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
> +
> +
> +	list_for_each_entry(entry, &dev->msi_list, list) {
> +		hwirq =3D msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
> +		if (hwirq < 0) {
> +			rc =3D hwirq;
> +			dev_err(&dev->dev, "%s: fail allocating msi\
> +					interrupt\n",	__func__);
> +			goto out_free;
> +		}
> +
> +		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
> +		virq =3D irq_create_mapping(msi_data->irqhost, hwirq);
> +		if (virq =3D=3D NO_IRQ) {
> +			dev_err(&dev->dev, "%s: fail mapping irq\n",
__func__);
> +			rc =3D -ENOSPC;
> +			goto out_free;
> +		}
> +
> +		set_irq_msi(virq, entry);
> +		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
> +		write_msi_msg(virq, &msg);
> +	}
> +
> +	return 0;
> +out_free:
> +	return rc;
> +}
> +
> +void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
> +{
> +	struct msi_desc *entry;
> +	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
> +	 dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
> +
> +	list_for_each_entry(entry, &dev->msi_list, list) {
> +		if (entry->irq =3D=3D NO_IRQ)
> +			continue;
> +		set_irq_msi(entry->irq, NULL);
> +		msi_bitmap_free_hwirqs(&msi_data->bitmap,
> +				       virq_to_hw(entry->irq), 1);
> +		irq_dispose_mapping(entry->irq);
> +

Nitpicking: Remove one empty line here.

> +	}
> +
> +	return;
> +}
> +
> +static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec,
int
>  type) +{
> +	pr_debug(KERN_INFO"PCIE-MSI:%s called. vec %x type %d\n",
> +					__func__, nvec, type);
> +	return 0;
> +}
> +
> +/*
> + * We do not need this actually. The MSIR register has been read once
> + * in the cascade interrupt. So, this MSI interrupt has been acked
> +*/
> +static void ppc4xx_msi_end_irq(unsigned int virq)
> +{
> +}
> +
> +

Nitpicking: Remove one empty line here. I'll stop mentioning this here.
Please=20
check the whole file for this.

> +static struct irq_chip ppc4xx_msi_chip =3D {
> +	.mask           =3D mask_msi_irq,
> +	.unmask         =3D unmask_msi_irq,
> +	.ack            =3D ppc4xx_msi_end_irq,
> +	.name       =3D " UIC",
> +};
> +
> +static int ppc4xx_msi_host_map(struct irq_host *h, unsigned int virq,
> +				irq_hw_number_t hw)
> +{
> +	struct irq_chip *chip =3D &ppc4xx_msi_chip;
> +
> +	irq_to_desc(virq)->status |=3D IRQ_TYPE_EDGE_RISING;
> +
> +	set_irq_chip_and_handler(virq, chip, handle_edge_irq);
> +
> +	return 0;
> +}
> +
> +static struct irq_host_ops ppc4xx_msi_host_ops =3D {
> +	.map =3D ppc4xx_msi_host_map,
> +};
> +
> +
> +static int __devinit ppc4xx_msi_probe(struct of_device *dev,
> +					const struct of_device_id
*match)
> +{
> +	struct ppc4xx_msi *msi;
> +	struct resource res, rmsi;
> +	int i, count;
> +	int rc;
> +	int virt_msir;
> +	const u32 *p;
> +	const u32 *sdr_base;
> +	u32 *msi_virt =3D NULL;
> +	dma_addr_t msi_phys;
> +
> +
> +	msi =3D kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
> +	if (!msi) {
> +		dev_err(&dev->dev, "No memory for MSI structure\n");
> +		rc =3D -ENOMEM;
> +		goto error_out;
> +	}
> +
> +	msi->irqhost =3D irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
> +				      NR_MSI_IRQS, &ppc4xx_msi_host_ops,
0);
> +	if (msi->irqhost =3D=3D NULL) {
> +		dev_err(&dev->dev, "No memory for MSI irqhost\n");
> +		rc =3D -ENOMEM;
> +		goto error_out;
> +	}
> +
> +
> +	/* Get MSI ranges */
> +	rc =3D of_address_to_resource(dev->node, 0, &rmsi);
> +	if (rc) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +
> +
> +	/* Get the MSI reg base */
> +	rc =3D of_address_to_resource(dev->node, 1, &res);
> +	if (rc) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +	/* Get the sdr-base */
> +	sdr_base =3D (u32 *)of_get_property(dev->node, "sdr-base", NULL);
> +	if (sdr_base =3D=3D NULL) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +	msi->sdr_base =3D *sdr_base;
> +#if  defined(CONFIG_460SX)
> +	mtdcri(SDR0, msi->sdr_base, res.start >> 32);
> +	mtdcri(SDR0, msi->sdr_base + 1, res.start & 0xFFFFFFFF);
> +	msi->msi_regs =3D ioremap(res.start, res.end - res.start + 1);

	msi->msi_regs =3D ioremap(res.start, resource_size(&res));

> +#else
> +	dev_err(&dev->dev, " Invalid Device \n");
> +	goto error_out;
> +#endif

Please don't introduce such a compile-time selection here. You don't
even need=20
it, since the register bases are provided via the device-tree. So just
remove=20
the #if and it's #else part here.

> +	if (!msi->msi_regs) {
> +		dev_err(&dev->dev, "ioremap problem failed\n");
> +		goto error_out;
> +	}
> +	/* MSI region always mapped in 4GB region*/
> +	msi->msi_addr_hi =3D 0x0;
> +	msi_virt =3D dma_alloc_coherent(&dev->dev, 64, &msi_phys,
> +			GFP_KERNEL);
> +	if (msi_virt =3D=3D NULL) {
> +		dev_err(&dev->dev, "No memory for MSI mem space\n");
> +		rc =3D -ENOMEM;
> +		goto error_out;
> +	}
> +	msi->msi_addr_lo =3D (u32)msi_phys;
> +
> +	/* Progam the Interrupt handler Termination addr registers */
> +	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
> +	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
> +
> +	/* Program MSI Expected data and Mask bits */
> +	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
> +	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);
> +
> +	msi->irqhost->host_data =3D msi;
> +
> +	if (ppc4xx_msi_init_allocator(msi)) {
> +		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
> +		goto error_out;
> +	}
> +
> +	p =3D of_get_property(dev->node, "interrupts", &count);
> +	if (!p) {
> +		dev_err(&dev->dev, "no interrupts property found on
%s\n",
> +				dev->node->full_name);
> +		rc =3D -ENODEV;
> +		goto error_out;
> +	}
> +	if (count =3D=3D 0) {
> +		dev_err(&dev->dev, "Malformed interrupts property on
%s\n",
> +				dev->node->full_name);
> +		rc =3D -EINVAL;
> +		goto error_out;
> +	}
> +
> +	for (i =3D 0; i < NR_MSI_IRQS; i++) {
> +		virt_msir =3D irq_of_parse_and_map(dev->node, i);
> +		if (virt_msir !=3D NO_IRQ) {
> +			set_irq_data(virt_msir, (void *)i);
> +			set_irq_chained_handler(virt_msir,
ppc4xx_msi_cascade);
> +		}
> +	}
> +
> +	ppc4xx_msi =3D msi;
> +
> +	WARN_ON(ppc_md.setup_msi_irqs);
> +	ppc_md.setup_msi_irqs =3D ppc4xx_setup_msi_irqs;
> +	ppc_md.teardown_msi_irqs =3D ppc4xx_teardown_msi_irqs;
> +	ppc_md.msi_check_device =3D ppc4xx_msi_check_device;
> +	return 0;
> +error_out:
> +	if (msi_virt)
> +		dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
> +	kfree(msi);
> +	return rc;
> +}
> +
> +static const struct ppc4xx_msi_feature ppc4xx_msi_feature =3D {
> +	.ppc4xx_pic_ip =3D 0,
> +	.msiir_offset =3D 0x140,
> +};
> +
> +static const struct of_device_id ppc4xx_msi_ids[] =3D {
> +	{
> +		.compatible =3D "amcc,ppc4xx-msi",
> +		.data =3D (void *)&ppc4xx_msi_feature,
> +	},
> +	{}
> +};
> +
> +static struct of_platform_driver ppc4xx_msi_driver =3D {
> +	.name =3D "ppc4xx-msi",
> +	.match_table =3D ppc4xx_msi_ids,
> +	.probe =3D ppc4xx_msi_probe,
> +};
> +
> +static __init int ppc4xx_msi_init(void)
> +{
> +	return of_register_platform_driver(&ppc4xx_msi_driver);
> +}
> +
> +subsys_initcall(ppc4xx_msi_init);
> diff --git a/arch/powerpc/sysdev/ppc4xx_msi.h
>  b/arch/powerpc/sysdev/ppc4xx_msi.h new file mode 100644
> index 0000000..e4ae058
> --- /dev/null
> +++ b/arch/powerpc/sysdev/ppc4xx_msi.h
> @@ -0,0 +1,39 @@
> +/*
> + * Copyright (C) 2009 Applied Micro Circuits Corporation.
> + *
> + * Author: Tirumala Marri <tmarri@amcc.com>
> + * 		Feng Kan <fkan@amcc.com>
> + * 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.
> + */
> +#ifndef __PPC4XX_MSI_H__
> +#define __PPC4XX_MSI_H__
> +
> +#include <asm/msi_bitmap.h>
> +
> +#define PEIH_TERMADH    0x00
> +#define PEIH_TERMADL    0x08
> +#define PEIH_MSIED      0x10
> +#define PEIH_MSIMK      0x18
> +#define PEIH_MSIASS     0x20
> +#define PEIH_FLUSH0     0x30
> +#define PEIH_FLUSH1     0x38
> +#define PEIH_CNTRST     0x48
> +
> +#define MSI_DATA_PATTERN   0x44440000
> +
> +struct ppc4xx_msi {
> +	struct irq_host *irqhost;
> +	unsigned long cascade_irq;
> +	u32 msi_addr_lo;
> +	u32 msi_addr_hi;
> +	void __iomem *msi_regs;
> +	u32 feature;
> +	struct msi_bitmap bitmap;
> +	u32 sdr_base;
> +};
> +
> +#define NR_MSI_IRQS 4
> +#endif /* __PPC4XX_MSI_H__ */
>=20

Cheers,
Stefan

--
DENX Software Engineering GmbH,      MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich,  Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-0 Fax: (+49)-8142-66989-80 Email: office@denx.de
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

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

* Re: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
  2009-12-23  7:52 tmarri
@ 2009-12-23  8:18 ` Stefan Roese
  2009-12-23 17:23   ` Tirumala Reddy Marri
  0 siblings, 1 reply; 10+ messages in thread
From: Stefan Roese @ 2009-12-23  8:18 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linuxppc-dev, writetomarri, tmarri

On Wednesday 23 December 2009 08:52:23 tmarri@amcc.com wrote:
> From: Tirumala Marri <tmarri@amcc.com>

Please find some mostly nitpicking comments below.

BTW: Did you already test this on other 4xx platforms, like 440SPe or 405EX? 
What are your plans here?
 
> Signed-off-by: Tirumala Marri <tmarri@amcc.com>
> ---
> Kernel version: 2.6.33-rc1
> Testing:
> 	When 460SX configured as root as a end point E1000(Intell Ethernet card)
> 	was plugged into the one of the PCI-E ports. I was able to run the traffic
> 	with MSI interrupts.
> ---
>  arch/powerpc/boot/dts/redwood.dts          |   15 ++
>  arch/powerpc/configs/44x/redwood_defconfig |    5 +-
>  arch/powerpc/platforms/44x/Kconfig         |    1 +
>  arch/powerpc/sysdev/Kconfig                |    7 +
>  arch/powerpc/sysdev/Makefile               |    1 +
>  arch/powerpc/sysdev/ppc4xx_msi.c           |  342
>  ++++++++++++++++++++++++++++ arch/powerpc/sysdev/ppc4xx_msi.h           | 
>   39 ++++
>  7 files changed, 408 insertions(+), 2 deletions(-)
>  create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
>  create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.h
> 
> diff --git a/arch/powerpc/boot/dts/redwood.dts
>  b/arch/powerpc/boot/dts/redwood.dts index 81636c0..412d5f9 100644
> --- a/arch/powerpc/boot/dts/redwood.dts
> +++ b/arch/powerpc/boot/dts/redwood.dts
> @@ -357,6 +357,21 @@
>  				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */
>  				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
>  		};
> +  		MSI: ppc4xx-msi@400300000 {
> +  			compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";

Better use something like this:

  			compatible = "amcc,ppc4xx-msi-ppc460sx", "amcc,ppc4xx-msi";

This way you could check for 460SX specials in the driver if needed.

> +  			reg = < 0x4 0x00300000 0x100
> +  				0x4 0x00300000 0x100>;
> +  			sdr-base = <0x3B0>;
> +  			interrupts =<0 1 2 3>;
> +  			interrupt-parent = <&MSI>;
> +  			#interrupt-cells = <1>;
> +  			#address-cells = <0>;
> +  			#size-cells = <0>;
> +  			interrupt-map = <0 &UIC0 0xC 1
> +  				1 &UIC0 0x0D 1
> +  				2 &UIC0 0x0E 1
> +  				3 &UIC0 0x0F 1>;
> +  		};
> 
>  	};
> 
> diff --git a/arch/powerpc/configs/44x/redwood_defconfig
>  b/arch/powerpc/configs/44x/redwood_defconfig index ed31d4f..5d16c88 100644
> --- a/arch/powerpc/configs/44x/redwood_defconfig
> +++ b/arch/powerpc/configs/44x/redwood_defconfig
> @@ -158,6 +158,7 @@ CONFIG_DEFAULT_AS=y
>  CONFIG_DEFAULT_IOSCHED="anticipatory"
>  # CONFIG_FREEZER is not set
>  CONFIG_PPC4xx_PCI_EXPRESS=y
> +CONFIG_PPC_MSI_BITMAP=y
> 
>  #
>  # Platform support
> @@ -264,7 +265,7 @@ CONFIG_PCIEPORTBUS=y
>  CONFIG_PCIEAER=y
>  # CONFIG_PCIEASPM is not set
>  CONFIG_ARCH_SUPPORTS_MSI=y
> -# CONFIG_PCI_MSI is not set
> +CONFIG_PCI_MSI=y
>  # CONFIG_PCI_LEGACY is not set
>  # CONFIG_PCI_DEBUG is not set
>  # CONFIG_PCI_STUB is not set
> @@ -1062,7 +1063,7 @@ CONFIG_PRINT_STACK_DEPTH=64
>  # CONFIG_DEBUG_PAGEALLOC is not set
>  # CONFIG_CODE_PATCHING_SELFTEST is not set
>  # CONFIG_FTR_FIXUP_SELFTEST is not set
> -# CONFIG_MSI_BITMAP_SELFTEST is not set
> +CONFIG_MSI_BITMAP_SELFTEST=y
>  # CONFIG_XMON is not set
>  # CONFIG_IRQSTACKS is not set
>  # CONFIG_VIRQ_DEBUG is not set
> diff --git a/arch/powerpc/platforms/44x/Kconfig
>  b/arch/powerpc/platforms/44x/Kconfig index 7486bff..9c3b8ca 100644
> --- a/arch/powerpc/platforms/44x/Kconfig
> +++ b/arch/powerpc/platforms/44x/Kconfig
> @@ -126,6 +126,7 @@ config REDWOOD
>  	select 460SX
>  	select PCI
>  	select PPC4xx_PCI_EXPRESS
> +	select PPC4xx_MSI
>  	help
>  	  This option enables support for the AMCC PPC460SX Redwood board.
> 
> diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
> index 3965828..c8f1486 100644
> --- a/arch/powerpc/sysdev/Kconfig
> +++ b/arch/powerpc/sysdev/Kconfig
> @@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
>  	depends on PCI && 4xx
>  	default n
> 
> +config PPC4xx_MSI
> +	bool
> +	depends on PCI_MSI
> +	depends on PCI && 4xx
> +	default n
> +
>  config PPC_MSI_BITMAP
>  	bool
>  	depends on PCI_MSI
>  	default y if MPIC
>  	default y if FSL_PCI
> +	default y if PPC4xx_MSI
> diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
> index 5642924..4c67d2d 100644
> --- a/arch/powerpc/sysdev/Makefile
> +++ b/arch/powerpc/sysdev/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_I8259)		+= i8259.o
>  obj-$(CONFIG_IPIC)		+= ipic.o
>  obj-$(CONFIG_4xx)		+= uic.o
>  obj-$(CONFIG_4xx_SOC)		+= ppc4xx_soc.o
> +obj-$(CONFIG_PPC4xx_MSI)		+= ppc4xx_msi.o
>  obj-$(CONFIG_XILINX_VIRTEX)	+= xilinx_intc.o
>  obj-$(CONFIG_XILINX_PCI)	+= xilinx_pci.o
>  obj-$(CONFIG_OF_RTC)		+= of_rtc.o
> diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c
>  b/arch/powerpc/sysdev/ppc4xx_msi.c new file mode 100644
> index 0000000..3c2ef32
> --- /dev/null
> +++ b/arch/powerpc/sysdev/ppc4xx_msi.c
> @@ -0,0 +1,342 @@
> +/*
> + * Copyright (C) 2009 Applied Micro Circuits corporation.
> + *
> + * Author: Feng Kan <fkan@amcc.com>
> + * 	   Tirumala Marri <tmarri@amcc.com>
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; version 2 of the
> + * License.
> + */
> +#include <linux/irq.h>
> +#include <linux/bootmem.h>
> +#include <linux/pci.h>
> +#include <linux/msi.h>
> +#include <linux/of_platform.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <asm/prom.h>
> +#include <asm/hw_irq.h>
> +#include <asm/ppc-pci.h>
> +#include <asm/dcr.h>
> +#include <asm/dcr-regs.h>
> +#include "ppc4xx_msi.h"
> +
> +

Nitpicking: Remove one empty line here.

> +static struct ppc4xx_msi *ppc4xx_msi;
> +
> +struct ppc4xx_msi_feature {
> +	u32 ppc4xx_pic_ip;
> +	u32 msiir_offset;
> +};
> +
> +static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
> +{
> +	int rc;
> +
> +	rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
> +				msi_data->irqhost->of_node);
> +	if (rc)
> +		return rc;
> +	rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
> +	if (rc < 0) {
> +		msi_bitmap_free(&msi_data->bitmap);
> +		return rc;
> +	}
> +	return 0;
> +}
> +
> +

Nitpicking: Remove one empty line here.

> +static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc *desc)
> +{
> +	unsigned int cascade_irq;
> +	struct ppc4xx_msi *msi_data = ppc4xx_msi;
> +	int msir_index = -1;
> +
> +	raw_spin_lock(&desc->lock);
> +	if (desc->chip->mask_ack) {
> +		desc->chip->mask_ack(irq);
> +	} else {
> +		desc->chip->mask(irq);
> +		desc->chip->ack(irq);
> +	}
> +
> +	if (unlikely(desc->status & IRQ_INPROGRESS))
> +		goto unlock;
> +
> +	msir_index = (int)desc->handler_data;
> +
> +	if (msir_index >= NR_MSI_IRQS)
> +		cascade_irq = NO_IRQ;
> +
> +	desc->status |= IRQ_INPROGRESS;
> +
> +	cascade_irq = irq_linear_revmap(msi_data->irqhost, msir_index);
> +	if (cascade_irq != NO_IRQ)
> +		generic_handle_irq(cascade_irq);
> +	desc->status &= ~IRQ_INPROGRESS;
> +
> +	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
> +		desc->chip->unmask(irq);
> +unlock:
> +	raw_spin_unlock(&desc->lock);
> +}

Nitpicking: Add one empty line here.

> +static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
> +					struct msi_msg *msg)
> +{
> +	struct ppc4xx_msi *msi_data = ppc4xx_msi;
> +
> +	msg->address_lo = msi_data->msi_addr_lo;
> +	msg->address_hi = msi_data->msi_addr_hi;
> +	msg->data = hwirq;
> +}
> +
> +

Nitpicking: Remove one empty line here.

> +int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
> +{
> +	struct msi_desc *entry;
> +	int rc, hwirq;
> +	unsigned int virq;
> +	struct msi_msg msg;
> +	struct ppc4xx_msi *msi_data = ppc4xx_msi;
> +
> +
> +	list_for_each_entry(entry, &dev->msi_list, list) {
> +		hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
> +		if (hwirq < 0) {
> +			rc = hwirq;
> +			dev_err(&dev->dev, "%s: fail allocating msi\
> +					interrupt\n",	__func__);
> +			goto out_free;
> +		}
> +
> +		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
> +		virq = irq_create_mapping(msi_data->irqhost, hwirq);
> +		if (virq == NO_IRQ) {
> +			dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
> +			rc = -ENOSPC;
> +			goto out_free;
> +		}
> +
> +		set_irq_msi(virq, entry);
> +		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
> +		write_msi_msg(virq, &msg);
> +	}
> +
> +	return 0;
> +out_free:
> +	return rc;
> +}
> +
> +void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
> +{
> +	struct msi_desc *entry;
> +	struct ppc4xx_msi *msi_data = ppc4xx_msi;
> +	 dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
> +
> +	list_for_each_entry(entry, &dev->msi_list, list) {
> +		if (entry->irq == NO_IRQ)
> +			continue;
> +		set_irq_msi(entry->irq, NULL);
> +		msi_bitmap_free_hwirqs(&msi_data->bitmap,
> +				       virq_to_hw(entry->irq), 1);
> +		irq_dispose_mapping(entry->irq);
> +

Nitpicking: Remove one empty line here.

> +	}
> +
> +	return;
> +}
> +
> +static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int
>  type) +{
> +	pr_debug(KERN_INFO"PCIE-MSI:%s called. vec %x type %d\n",
> +					__func__, nvec, type);
> +	return 0;
> +}
> +
> +/*
> + * We do not need this actually. The MSIR register has been read once
> + * in the cascade interrupt. So, this MSI interrupt has been acked
> +*/
> +static void ppc4xx_msi_end_irq(unsigned int virq)
> +{
> +}
> +
> +

Nitpicking: Remove one empty line here. I'll stop mentioning this here. Please 
check the whole file for this.

> +static struct irq_chip ppc4xx_msi_chip = {
> +	.mask           = mask_msi_irq,
> +	.unmask         = unmask_msi_irq,
> +	.ack            = ppc4xx_msi_end_irq,
> +	.name       = " UIC",
> +};
> +
> +static int ppc4xx_msi_host_map(struct irq_host *h, unsigned int virq,
> +				irq_hw_number_t hw)
> +{
> +	struct irq_chip *chip = &ppc4xx_msi_chip;
> +
> +	irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_RISING;
> +
> +	set_irq_chip_and_handler(virq, chip, handle_edge_irq);
> +
> +	return 0;
> +}
> +
> +static struct irq_host_ops ppc4xx_msi_host_ops = {
> +	.map = ppc4xx_msi_host_map,
> +};
> +
> +
> +static int __devinit ppc4xx_msi_probe(struct of_device *dev,
> +					const struct of_device_id *match)
> +{
> +	struct ppc4xx_msi *msi;
> +	struct resource res, rmsi;
> +	int i, count;
> +	int rc;
> +	int virt_msir;
> +	const u32 *p;
> +	const u32 *sdr_base;
> +	u32 *msi_virt = NULL;
> +	dma_addr_t msi_phys;
> +
> +
> +	msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
> +	if (!msi) {
> +		dev_err(&dev->dev, "No memory for MSI structure\n");
> +		rc = -ENOMEM;
> +		goto error_out;
> +	}
> +
> +	msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
> +				      NR_MSI_IRQS, &ppc4xx_msi_host_ops, 0);
> +	if (msi->irqhost == NULL) {
> +		dev_err(&dev->dev, "No memory for MSI irqhost\n");
> +		rc = -ENOMEM;
> +		goto error_out;
> +	}
> +
> +
> +	/* Get MSI ranges */
> +	rc = of_address_to_resource(dev->node, 0, &rmsi);
> +	if (rc) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +
> +
> +	/* Get the MSI reg base */
> +	rc = of_address_to_resource(dev->node, 1, &res);
> +	if (rc) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +	/* Get the sdr-base */
> +	sdr_base = (u32 *)of_get_property(dev->node, "sdr-base", NULL);
> +	if (sdr_base == NULL) {
> +		dev_err(&dev->dev, "%s resource error!\n",
> +				dev->node->full_name);
> +		goto error_out;
> +	}
> +	msi->sdr_base = *sdr_base;
> +#if  defined(CONFIG_460SX)
> +	mtdcri(SDR0, msi->sdr_base, res.start >> 32);
> +	mtdcri(SDR0, msi->sdr_base + 1, res.start & 0xFFFFFFFF);
> +	msi->msi_regs = ioremap(res.start, res.end - res.start + 1);

	msi->msi_regs = ioremap(res.start, resource_size(&res));

> +#else
> +	dev_err(&dev->dev, " Invalid Device \n");
> +	goto error_out;
> +#endif

Please don't introduce such a compile-time selection here. You don't even need 
it, since the register bases are provided via the device-tree. So just remove 
the #if and it's #else part here.

> +	if (!msi->msi_regs) {
> +		dev_err(&dev->dev, "ioremap problem failed\n");
> +		goto error_out;
> +	}
> +	/* MSI region always mapped in 4GB region*/
> +	msi->msi_addr_hi = 0x0;
> +	msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys,
> +			GFP_KERNEL);
> +	if (msi_virt == NULL) {
> +		dev_err(&dev->dev, "No memory for MSI mem space\n");
> +		rc = -ENOMEM;
> +		goto error_out;
> +	}
> +	msi->msi_addr_lo = (u32)msi_phys;
> +
> +	/* Progam the Interrupt handler Termination addr registers */
> +	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
> +	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
> +
> +	/* Program MSI Expected data and Mask bits */
> +	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
> +	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);
> +
> +	msi->irqhost->host_data = msi;
> +
> +	if (ppc4xx_msi_init_allocator(msi)) {
> +		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
> +		goto error_out;
> +	}
> +
> +	p = of_get_property(dev->node, "interrupts", &count);
> +	if (!p) {
> +		dev_err(&dev->dev, "no interrupts property found on %s\n",
> +				dev->node->full_name);
> +		rc = -ENODEV;
> +		goto error_out;
> +	}
> +	if (count == 0) {
> +		dev_err(&dev->dev, "Malformed interrupts property on %s\n",
> +				dev->node->full_name);
> +		rc = -EINVAL;
> +		goto error_out;
> +	}
> +
> +	for (i = 0; i < NR_MSI_IRQS; i++) {
> +		virt_msir = irq_of_parse_and_map(dev->node, i);
> +		if (virt_msir != NO_IRQ) {
> +			set_irq_data(virt_msir, (void *)i);
> +			set_irq_chained_handler(virt_msir, ppc4xx_msi_cascade);
> +		}
> +	}
> +
> +	ppc4xx_msi = msi;
> +
> +	WARN_ON(ppc_md.setup_msi_irqs);
> +	ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
> +	ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
> +	ppc_md.msi_check_device = ppc4xx_msi_check_device;
> +	return 0;
> +error_out:
> +	if (msi_virt)
> +		dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
> +	kfree(msi);
> +	return rc;
> +}
> +
> +static const struct ppc4xx_msi_feature ppc4xx_msi_feature = {
> +	.ppc4xx_pic_ip = 0,
> +	.msiir_offset = 0x140,
> +};
> +
> +static const struct of_device_id ppc4xx_msi_ids[] = {
> +	{
> +		.compatible = "amcc,ppc4xx-msi",
> +		.data = (void *)&ppc4xx_msi_feature,
> +	},
> +	{}
> +};
> +
> +static struct of_platform_driver ppc4xx_msi_driver = {
> +	.name = "ppc4xx-msi",
> +	.match_table = ppc4xx_msi_ids,
> +	.probe = ppc4xx_msi_probe,
> +};
> +
> +static __init int ppc4xx_msi_init(void)
> +{
> +	return of_register_platform_driver(&ppc4xx_msi_driver);
> +}
> +
> +subsys_initcall(ppc4xx_msi_init);
> diff --git a/arch/powerpc/sysdev/ppc4xx_msi.h
>  b/arch/powerpc/sysdev/ppc4xx_msi.h new file mode 100644
> index 0000000..e4ae058
> --- /dev/null
> +++ b/arch/powerpc/sysdev/ppc4xx_msi.h
> @@ -0,0 +1,39 @@
> +/*
> + * Copyright (C) 2009 Applied Micro Circuits Corporation.
> + *
> + * Author: Tirumala Marri <tmarri@amcc.com>
> + * 		Feng Kan <fkan@amcc.com>
> + * 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.
> + */
> +#ifndef __PPC4XX_MSI_H__
> +#define __PPC4XX_MSI_H__
> +
> +#include <asm/msi_bitmap.h>
> +
> +#define PEIH_TERMADH    0x00
> +#define PEIH_TERMADL    0x08
> +#define PEIH_MSIED      0x10
> +#define PEIH_MSIMK      0x18
> +#define PEIH_MSIASS     0x20
> +#define PEIH_FLUSH0     0x30
> +#define PEIH_FLUSH1     0x38
> +#define PEIH_CNTRST     0x48
> +
> +#define MSI_DATA_PATTERN   0x44440000
> +
> +struct ppc4xx_msi {
> +	struct irq_host *irqhost;
> +	unsigned long cascade_irq;
> +	u32 msi_addr_lo;
> +	u32 msi_addr_hi;
> +	void __iomem *msi_regs;
> +	u32 feature;
> +	struct msi_bitmap bitmap;
> +	u32 sdr_base;
> +};
> +
> +#define NR_MSI_IRQS 4
> +#endif /* __PPC4XX_MSI_H__ */
> 

Cheers,
Stefan

--
DENX Software Engineering GmbH,      MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich,  Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-0 Fax: (+49)-8142-66989-80 Email: office@denx.de

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

* [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
@ 2009-12-23  7:52 tmarri
  2009-12-23  8:18 ` Stefan Roese
  0 siblings, 1 reply; 10+ messages in thread
From: tmarri @ 2009-12-23  7:52 UTC (permalink / raw)
  To: jwboyer, linuxppc-dev; +Cc: linuxppc-dev, writetomarri, tmarri

From: Tirumala Marri <tmarri@amcc.com>

Signed-off-by: Tirumala Marri <tmarri@amcc.com>
---
Kernel version: 2.6.33-rc1
Testing:
	When 460SX configured as root as a end point E1000(Intell Ethernet card)
	was plugged into the one of the PCI-E ports. I was able to run the traffic
	with MSI interrupts.
---
 arch/powerpc/boot/dts/redwood.dts          |   15 ++
 arch/powerpc/configs/44x/redwood_defconfig |    5 +-
 arch/powerpc/platforms/44x/Kconfig         |    1 +
 arch/powerpc/sysdev/Kconfig                |    7 +
 arch/powerpc/sysdev/Makefile               |    1 +
 arch/powerpc/sysdev/ppc4xx_msi.c           |  342 ++++++++++++++++++++++++++++
 arch/powerpc/sysdev/ppc4xx_msi.h           |   39 ++++
 7 files changed, 408 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
 create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.h

diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
index 81636c0..412d5f9 100644
--- a/arch/powerpc/boot/dts/redwood.dts
+++ b/arch/powerpc/boot/dts/redwood.dts
@@ -357,6 +357,21 @@
 				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */
 				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
 		};
+  		MSI: ppc4xx-msi@400300000 {
+  			compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+  			reg = < 0x4 0x00300000 0x100
+  				0x4 0x00300000 0x100>;
+  			sdr-base = <0x3B0>;
+  			interrupts =<0 1 2 3>;
+  			interrupt-parent = <&MSI>;
+  			#interrupt-cells = <1>;
+  			#address-cells = <0>;
+  			#size-cells = <0>;
+  			interrupt-map = <0 &UIC0 0xC 1
+  				1 &UIC0 0x0D 1
+  				2 &UIC0 0x0E 1
+  				3 &UIC0 0x0F 1>;
+  		};
 
 	};
 
diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig
index ed31d4f..5d16c88 100644
--- a/arch/powerpc/configs/44x/redwood_defconfig
+++ b/arch/powerpc/configs/44x/redwood_defconfig
@@ -158,6 +158,7 @@ CONFIG_DEFAULT_AS=y
 CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_FREEZER is not set
 CONFIG_PPC4xx_PCI_EXPRESS=y
+CONFIG_PPC_MSI_BITMAP=y
 
 #
 # Platform support
@@ -264,7 +265,7 @@ CONFIG_PCIEPORTBUS=y
 CONFIG_PCIEAER=y
 # CONFIG_PCIEASPM is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
-# CONFIG_PCI_MSI is not set
+CONFIG_PCI_MSI=y
 # CONFIG_PCI_LEGACY is not set
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
@@ -1062,7 +1063,7 @@ CONFIG_PRINT_STACK_DEPTH=64
 # CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_CODE_PATCHING_SELFTEST is not set
 # CONFIG_FTR_FIXUP_SELFTEST is not set
-# CONFIG_MSI_BITMAP_SELFTEST is not set
+CONFIG_MSI_BITMAP_SELFTEST=y
 # CONFIG_XMON is not set
 # CONFIG_IRQSTACKS is not set
 # CONFIG_VIRQ_DEBUG is not set
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 7486bff..9c3b8ca 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -126,6 +126,7 @@ config REDWOOD
 	select 460SX
 	select PCI
 	select PPC4xx_PCI_EXPRESS
+	select PPC4xx_MSI
 	help
 	  This option enables support for the AMCC PPC460SX Redwood board.
 
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 3965828..c8f1486 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
 	depends on PCI && 4xx
 	default n
 
+config PPC4xx_MSI
+	bool
+	depends on PCI_MSI
+	depends on PCI && 4xx
+	default n
+
 config PPC_MSI_BITMAP
 	bool
 	depends on PCI_MSI
 	default y if MPIC
 	default y if FSL_PCI
+	default y if PPC4xx_MSI
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 5642924..4c67d2d 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_I8259)		+= i8259.o
 obj-$(CONFIG_IPIC)		+= ipic.o
 obj-$(CONFIG_4xx)		+= uic.o
 obj-$(CONFIG_4xx_SOC)		+= ppc4xx_soc.o
+obj-$(CONFIG_PPC4xx_MSI)		+= ppc4xx_msi.o
 obj-$(CONFIG_XILINX_VIRTEX)	+= xilinx_intc.o
 obj-$(CONFIG_XILINX_PCI)	+= xilinx_pci.o
 obj-$(CONFIG_OF_RTC)		+= of_rtc.o
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
new file mode 100644
index 0000000..3c2ef32
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2009 Applied Micro Circuits corporation.
+ *
+ * Author: Feng Kan <fkan@amcc.com>
+ * 	   Tirumala Marri <tmarri@amcc.com>
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+#include "ppc4xx_msi.h"
+
+
+static struct ppc4xx_msi *ppc4xx_msi;
+
+struct ppc4xx_msi_feature {
+	u32 ppc4xx_pic_ip;
+	u32 msiir_offset;
+};
+
+static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
+{
+	int rc;
+
+	rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+				msi_data->irqhost->of_node);
+	if (rc)
+		return rc;
+	rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
+	if (rc < 0) {
+		msi_bitmap_free(&msi_data->bitmap);
+		return rc;
+	}
+	return 0;
+}
+
+
+static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned int cascade_irq;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+	int msir_index = -1;
+
+	raw_spin_lock(&desc->lock);
+	if (desc->chip->mask_ack) {
+		desc->chip->mask_ack(irq);
+	} else {
+		desc->chip->mask(irq);
+		desc->chip->ack(irq);
+	}
+
+	if (unlikely(desc->status & IRQ_INPROGRESS))
+		goto unlock;
+
+	msir_index = (int)desc->handler_data;
+
+	if (msir_index >= NR_MSI_IRQS)
+		cascade_irq = NO_IRQ;
+
+	desc->status |= IRQ_INPROGRESS;
+
+	cascade_irq = irq_linear_revmap(msi_data->irqhost, msir_index);
+	if (cascade_irq != NO_IRQ)
+		generic_handle_irq(cascade_irq);
+	desc->status &= ~IRQ_INPROGRESS;
+
+	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+		desc->chip->unmask(irq);
+unlock:
+	raw_spin_unlock(&desc->lock);
+}
+static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
+					struct msi_msg *msg)
+{
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+
+	msg->address_lo = msi_data->msi_addr_lo;
+	msg->address_hi = msi_data->msi_addr_hi;
+	msg->data = hwirq;
+}
+
+
+int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	struct msi_desc *entry;
+	int rc, hwirq;
+	unsigned int virq;
+	struct msi_msg msg;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+		if (hwirq < 0) {
+			rc = hwirq;
+			dev_err(&dev->dev, "%s: fail allocating msi\
+					interrupt\n",	__func__);
+			goto out_free;
+		}
+
+		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
+		virq = irq_create_mapping(msi_data->irqhost, hwirq);
+		if (virq == NO_IRQ) {
+			dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
+			rc = -ENOSPC;
+			goto out_free;
+		}
+
+		set_irq_msi(virq, entry);
+		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
+		write_msi_msg(virq, &msg);
+	}
+
+	return 0;
+out_free:
+	return rc;
+}
+
+void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
+{
+	struct msi_desc *entry;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+	 dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		if (entry->irq == NO_IRQ)
+			continue;
+		set_irq_msi(entry->irq, NULL);
+		msi_bitmap_free_hwirqs(&msi_data->bitmap,
+				       virq_to_hw(entry->irq), 1);
+		irq_dispose_mapping(entry->irq);
+
+	}
+
+	return;
+}
+
+static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+	pr_debug(KERN_INFO"PCIE-MSI:%s called. vec %x type %d\n",
+					__func__, nvec, type);
+	return 0;
+}
+
+/*
+ * We do not need this actually. The MSIR register has been read once
+ * in the cascade interrupt. So, this MSI interrupt has been acked
+*/
+static void ppc4xx_msi_end_irq(unsigned int virq)
+{
+}
+
+
+static struct irq_chip ppc4xx_msi_chip = {
+	.mask           = mask_msi_irq,
+	.unmask         = unmask_msi_irq,
+	.ack            = ppc4xx_msi_end_irq,
+	.name       = " UIC",
+};
+
+static int ppc4xx_msi_host_map(struct irq_host *h, unsigned int virq,
+				irq_hw_number_t hw)
+{
+	struct irq_chip *chip = &ppc4xx_msi_chip;
+
+	irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_RISING;
+
+	set_irq_chip_and_handler(virq, chip, handle_edge_irq);
+
+	return 0;
+}
+
+static struct irq_host_ops ppc4xx_msi_host_ops = {
+	.map = ppc4xx_msi_host_map,
+};
+
+
+static int __devinit ppc4xx_msi_probe(struct of_device *dev,
+					const struct of_device_id *match)
+{
+	struct ppc4xx_msi *msi;
+	struct resource res, rmsi;
+	int i, count;
+	int rc;
+	int virt_msir;
+	const u32 *p;
+	const u32 *sdr_base;
+	u32 *msi_virt = NULL;
+	dma_addr_t msi_phys;
+
+
+	msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
+	if (!msi) {
+		dev_err(&dev->dev, "No memory for MSI structure\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+
+	msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
+				      NR_MSI_IRQS, &ppc4xx_msi_host_ops, 0);
+	if (msi->irqhost == NULL) {
+		dev_err(&dev->dev, "No memory for MSI irqhost\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+
+
+	/* Get MSI ranges */
+	rc = of_address_to_resource(dev->node, 0, &rmsi);
+	if (rc) {
+		dev_err(&dev->dev, "%s resource error!\n",
+				dev->node->full_name);
+		goto error_out;
+	}
+
+
+	/* Get the MSI reg base */
+	rc = of_address_to_resource(dev->node, 1, &res);
+	if (rc) {
+		dev_err(&dev->dev, "%s resource error!\n",
+				dev->node->full_name);
+		goto error_out;
+	}
+	/* Get the sdr-base */
+	sdr_base = (u32 *)of_get_property(dev->node, "sdr-base", NULL);
+	if (sdr_base == NULL) {
+		dev_err(&dev->dev, "%s resource error!\n",
+				dev->node->full_name);
+		goto error_out;
+	}
+	msi->sdr_base = *sdr_base;
+#if  defined(CONFIG_460SX)
+	mtdcri(SDR0, msi->sdr_base, res.start >> 32);
+	mtdcri(SDR0, msi->sdr_base + 1, res.start & 0xFFFFFFFF);
+	msi->msi_regs = ioremap(res.start, res.end - res.start + 1);
+#else
+	dev_err(&dev->dev, " Invalid Device \n");
+	goto error_out;
+#endif
+	if (!msi->msi_regs) {
+		dev_err(&dev->dev, "ioremap problem failed\n");
+		goto error_out;
+	}
+	/* MSI region always mapped in 4GB region*/
+	msi->msi_addr_hi = 0x0;
+	msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys,
+			GFP_KERNEL);
+	if (msi_virt == NULL) {
+		dev_err(&dev->dev, "No memory for MSI mem space\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+	msi->msi_addr_lo = (u32)msi_phys;
+
+	/* Progam the Interrupt handler Termination addr registers */
+	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
+	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
+
+	/* Program MSI Expected data and Mask bits */
+	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
+	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);
+
+	msi->irqhost->host_data = msi;
+
+	if (ppc4xx_msi_init_allocator(msi)) {
+		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
+		goto error_out;
+	}
+
+	p = of_get_property(dev->node, "interrupts", &count);
+	if (!p) {
+		dev_err(&dev->dev, "no interrupts property found on %s\n",
+				dev->node->full_name);
+		rc = -ENODEV;
+		goto error_out;
+	}
+	if (count == 0) {
+		dev_err(&dev->dev, "Malformed interrupts property on %s\n",
+				dev->node->full_name);
+		rc = -EINVAL;
+		goto error_out;
+	}
+
+	for (i = 0; i < NR_MSI_IRQS; i++) {
+		virt_msir = irq_of_parse_and_map(dev->node, i);
+		if (virt_msir != NO_IRQ) {
+			set_irq_data(virt_msir, (void *)i);
+			set_irq_chained_handler(virt_msir, ppc4xx_msi_cascade);
+		}
+	}
+
+	ppc4xx_msi = msi;
+
+	WARN_ON(ppc_md.setup_msi_irqs);
+	ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
+	ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
+	ppc_md.msi_check_device = ppc4xx_msi_check_device;
+	return 0;
+error_out:
+	if (msi_virt)
+		dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
+	kfree(msi);
+	return rc;
+}
+
+static const struct ppc4xx_msi_feature ppc4xx_msi_feature = {
+	.ppc4xx_pic_ip = 0,
+	.msiir_offset = 0x140,
+};
+
+static const struct of_device_id ppc4xx_msi_ids[] = {
+	{
+		.compatible = "amcc,ppc4xx-msi",
+		.data = (void *)&ppc4xx_msi_feature,
+	},
+	{}
+};
+
+static struct of_platform_driver ppc4xx_msi_driver = {
+	.name = "ppc4xx-msi",
+	.match_table = ppc4xx_msi_ids,
+	.probe = ppc4xx_msi_probe,
+};
+
+static __init int ppc4xx_msi_init(void)
+{
+	return of_register_platform_driver(&ppc4xx_msi_driver);
+}
+
+subsys_initcall(ppc4xx_msi_init);
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.h b/arch/powerpc/sysdev/ppc4xx_msi.h
new file mode 100644
index 0000000..e4ae058
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_msi.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Applied Micro Circuits Corporation.
+ *
+ * Author: Tirumala Marri <tmarri@amcc.com>
+ * 		Feng Kan <fkan@amcc.com>
+ * 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.
+ */
+#ifndef __PPC4XX_MSI_H__
+#define __PPC4XX_MSI_H__
+
+#include <asm/msi_bitmap.h>
+
+#define PEIH_TERMADH    0x00
+#define PEIH_TERMADL    0x08
+#define PEIH_MSIED      0x10
+#define PEIH_MSIMK      0x18
+#define PEIH_MSIASS     0x20
+#define PEIH_FLUSH0     0x30
+#define PEIH_FLUSH1     0x38
+#define PEIH_CNTRST     0x48
+
+#define MSI_DATA_PATTERN   0x44440000
+
+struct ppc4xx_msi {
+	struct irq_host *irqhost;
+	unsigned long cascade_irq;
+	u32 msi_addr_lo;
+	u32 msi_addr_hi;
+	void __iomem *msi_regs;
+	u32 feature;
+	struct msi_bitmap bitmap;
+	u32 sdr_base;
+};
+
+#define NR_MSI_IRQS 4
+#endif /* __PPC4XX_MSI_H__ */
-- 
1.6.1.rc3

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

* RE: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
  2009-12-22 12:07 ` Josh Boyer
@ 2009-12-22 17:55   ` Tirumala Reddy Marri
  0 siblings, 0 replies; 10+ messages in thread
From: Tirumala Reddy Marri @ 2009-12-22 17:55 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, writetomarri

Josh,
 Thanks for the comments. I will fix them re-submit it.
Regards,
Marri

-----Original Message-----
From: Josh Boyer [mailto:jwboyer@gmail.com] On Behalf Of Josh Boyer
Sent: Tuesday, December 22, 2009 4:08 AM
To: Tirumala Reddy Marri
Cc: linuxppc-dev@lists.ozlabs.org; writetomarri@yahoo.com
Subject: Re: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.

On Tue, Dec 22, 2009 at 12:49:51AM -0800, tmarri@amcc.com wrote:
>From: Tirumala Marri <tmarri@amcc.com>
>
>
>Signed-off-by: Tirumala Marri <tmarri@amcc.com>
>---
>Kernel version: 2.6.33-rc1
>Testing:
>	When 460SX configured as root as a end point E1000(Intell
Ethernet card)=20
>	was plugged into the one of the PCI-E ports. I was able to run
the traffic
>	with MSI interrupts.=20
>---
> arch/powerpc/boot/dts/redwood.dts          |   15 ++
> arch/powerpc/configs/44x/redwood_defconfig |    5 +-
> arch/powerpc/platforms/44x/Kconfig         |    1 +
> arch/powerpc/sysdev/Kconfig                |    7 +
> arch/powerpc/sysdev/Makefile               |    1 +
> arch/powerpc/sysdev/ppc4xx_msi.c           |  335
++++++++++++++++++++++++++++
> arch/powerpc/sysdev/ppc4xx_msi.h           |   49 ++++
> 7 files changed, 411 insertions(+), 2 deletions(-)
> create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
> create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.h
>
>diff --git a/arch/powerpc/boot/dts/redwood.dts
b/arch/powerpc/boot/dts/redwood.dts
>index 81636c0..412d5f9 100644
>--- a/arch/powerpc/boot/dts/redwood.dts
>+++ b/arch/powerpc/boot/dts/redwood.dts
>@@ -357,6 +357,21 @@
> 				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /*
swizzled int C */
> 				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /*
swizzled int D */>;
> 		};
>+  		MSI: ppc4xx-msi@400300000 {
>+  			compatible =3D "amcc,ppc4xx-msi", "ppc4xx-msi";
>+  			reg =3D < 0x4 0x00300000 0x100
>+  				0x4 0x00300000 0x100>;
>+  			sdr-base =3D <0x3B0>;
>+  			interrupts =3D<0 1 2 3>;
>+  			interrupt-parent =3D <&MSI>;
>+  			#interrupt-cells =3D <1>;
>+  			#address-cells =3D <0>;
>+  			#size-cells =3D <0>;
>+  			interrupt-map =3D <0 &UIC0 0xC 1
>+  				1 &UIC0 0x0D 1
>+  				2 &UIC0 0x0E 1
>+  				3 &UIC0 0x0F 1>;
>+  		};
>=20
> 	};
>=20
>diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
>index 3965828..32f5a40 100644
>--- a/arch/powerpc/sysdev/Kconfig
>+++ b/arch/powerpc/sysdev/Kconfig
>@@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
> 	depends on PCI && 4xx
> 	default n
>=20
>+config 4xx_MSI

This should probably be named PPC4xx_MSI, similar to how
PPC4xx_PCI_EXPRESS is named.

>+	bool
>+	depends on PCI_MSI
>+	depends on PCI && 4xx
>+	default n
>+
> config PPC_MSI_BITMAP
> 	bool
> 	depends on PCI_MSI
> 	default y if MPIC
> 	default y if FSL_PCI
>+	default y if 4xx_MSI

>diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c
b/arch/powerpc/sysdev/ppc4xx_msi.c
>new file mode 100644
>index 0000000..752da4b
>--- /dev/null
>+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
>@@ -0,0 +1,335 @@
>+/*
>+ * Copyright (C) 2009 Applied Micro Circuits corporation,
>+ * All rights reserved.

Please don't add the 'All rights reserved.' to new files.  It is
inaccurate and confusing given that it's a GPLv2 file.

>+ *
>+ * Author: Feng Kan <fkan@amcc.com>
>+ * 	   Tirumala Marri <tmarri@amcc.com>
>+ * This program is free software; you can redistribute it and/or
>+ * modify it under the terms of the GNU General Public License
>+ * as published by the Free Software Foundation; version 2 of the
>+ * License.
>+ */
>+#include <linux/irq.h>
>+#include <linux/bootmem.h>
>+#include <linux/pci.h>
>+#include <linux/msi.h>
>+#include <linux/of_platform.h>
>+#include <linux/interrupt.h>
>+#include <linux/device.h>
>+#include <asm/prom.h>
>+#include <asm/hw_irq.h>
>+#include <asm/ppc-pci.h>
>+#include <asm/dcr.h>
>+#include <asm/dcr-regs.h>
>+#include "ppc4xx_msi.h"
>+
>+
>+static struct ppc4xx_msi *ppc4xx_msi;
>+
>+struct ppc4xx_msi_feature {
>+	u32 ppc4xx_pic_ip;
>+	u32 msiir_offset;
>+};
>+
>+static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
>+{
>+	int rc;
>+
>+	rc =3D msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
>+				msi_data->irqhost->of_node);
>+	if (rc)
>+		return rc;
>+	rc =3D msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
>+	if (rc < 0) {
>+		msi_bitmap_free(&msi_data->bitmap);
>+		return rc;
>+	}
>+	return 0;
>+}
>+
>+
>+static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc
*desc)
>+{
>+	unsigned int cascade_irq;
>+	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
>+	int msir_index =3D -1;
>+
>+	raw_spin_lock(&desc->lock);
>+	if (desc->chip->mask_ack) {
>+		desc->chip->mask_ack(irq);
>+	} else {
>+		desc->chip->mask(irq);
>+		desc->chip->ack(irq);
>+	}
>+
>+	if (unlikely(desc->status & IRQ_INPROGRESS))
>+		goto unlock;
>+
>+	msir_index =3D (int)desc->handler_data;
>+
>+	if (msir_index >=3D NR_MSI_IRQS)
>+		cascade_irq =3D NO_IRQ;
>+
>+	desc->status |=3D IRQ_INPROGRESS;
>+
>+	cascade_irq =3D irq_linear_revmap(msi_data->irqhost, msir_index);
>+	if (cascade_irq !=3D NO_IRQ)
>+		generic_handle_irq(cascade_irq);
>+	desc->status &=3D ~IRQ_INPROGRESS;
>+
>+	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
>+		desc->chip->unmask(irq);
>+unlock:
>+	raw_spin_unlock(&desc->lock);
>+}
>+static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
>+					struct msi_msg *msg)
>+{
>+	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
>+
>+	msg->address_lo =3D msi_data->msi_addr_lo;
>+	msg->address_hi =3D msi_data->msi_addr_hi;
>+	msg->data =3D hwirq;
>+}
>+
>+
>+int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
>+{
>+	struct msi_desc *entry;
>+	int rc, hwirq;
>+	unsigned int virq;
>+	struct msi_msg msg;
>+	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
>+
>+
>+	list_for_each_entry(entry, &dev->msi_list, list) {
>+		hwirq =3D msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
>+		if (hwirq < 0) {
>+			rc =3D hwirq;
>+			dev_err(&dev->dev, "%s: fail allocating msi\
>+					interrupt\n",	__func__);
>+			goto out_free;
>+		}
>+
>+		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
>+		virq =3D irq_create_mapping(msi_data->irqhost, hwirq);
>+		if (virq =3D=3D NO_IRQ) {
>+			dev_err(&dev->dev, "%s: fail mapping irq\n",
__func__);
>+			rc =3D -ENOSPC;
>+			goto out_free;
>+		}
>+
>+		set_irq_msi(virq, entry);
>+		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
>+		write_msi_msg(virq, &msg);
>+	}
>+
>+	return 0;
>+out_free:
>+	return rc;
>+}
>+
>+void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
>+{
>+	struct msi_desc *entry;
>+	struct ppc4xx_msi *msi_data =3D ppc4xx_msi;
>+	 dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
>+
>+	list_for_each_entry(entry, &dev->msi_list, list) {
>+		if (entry->irq =3D=3D NO_IRQ)
>+			continue;
>+		set_irq_msi(entry->irq, NULL);
>+		msi_bitmap_free_hwirqs(&msi_data->bitmap,
>+				       virq_to_hw(entry->irq), 1);
>+		irq_dispose_mapping(entry->irq);
>+
>+	}
>+
>+	return;
>+}
>+
>+static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int
type)
>+{
>+	pr_debug(KERN_INFO"PCIE-MSI:%s called. vec %x type %d\n",
>+					__func__, nvec, type);
>+	return 0;
>+}
>+
>+/*
>+ * We do not need this actually. The MSIR register has been read once
>+ * in the cascade interrupt. So, this MSI interrupt has been acked
>+*/
>+static void ppc4xx_msi_end_irq(unsigned int virq)
>+{
>+}
>+
>+
>+static struct irq_chip ppc4xx_msi_chip =3D {
>+	.mask           =3D mask_msi_irq,
>+	.unmask         =3D unmask_msi_irq,
>+	.ack            =3D ppc4xx_msi_end_irq,
>+	.name       =3D " UIC",
>+};
>+
>+static int ppc4xx_msi_host_map(struct irq_host *h, unsigned int virq,
>+				irq_hw_number_t hw)
>+{
>+	struct irq_chip *chip =3D &ppc4xx_msi_chip;
>+
>+	irq_to_desc(virq)->status |=3D IRQ_TYPE_EDGE_RISING;
>+
>+	set_irq_chip_and_handler(virq, chip, handle_edge_irq);
>+
>+	return 0;
>+}
>+
>+static struct irq_host_ops ppc4xx_msi_host_ops =3D {
>+	.map =3D ppc4xx_msi_host_map,
>+};
>+
>+
>+static int __devinit ppc4xx_msi_probe(struct of_device *dev,
>+					const struct of_device_id
*match)
>+{
>+	struct ppc4xx_msi *msi;
>+	struct resource res, rmsi;
>+	int i, count;
>+	int rc;
>+	int virt_msir;
>+	const u32 *p;
>+	u32 *msi_virt =3D NULL;
>+	dma_addr_t msi_phys;
>+
>+
>+	msi =3D kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
>+	if (!msi) {
>+		dev_err(&dev->dev, "No memory for MSI structure\n");
>+		rc =3D -ENOMEM;
>+		goto error_out;
>+	}
>+
>+	msi->irqhost =3D irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
>+				      NR_MSI_IRQS, &ppc4xx_msi_host_ops,
0);
>+	if (msi->irqhost =3D=3D NULL) {
>+		dev_err(&dev->dev, "No memory for MSI irqhost\n");
>+		rc =3D -ENOMEM;
>+		goto error_out;
>+	}
>+
>+
>+	/* Get MSI ranges */
>+	rc =3D of_address_to_resource(dev->node, 0, &rmsi);
>+	if (rc) {
>+		dev_err(&dev->dev, "%s resource error!\n",
>+				dev->node->full_name);
>+		goto error_out;
>+	}
>+
>+
>+	/* Get the MSI reg base */
>+	rc =3D of_address_to_resource(dev->node, 1, &res);
>+	if (rc) {
>+		dev_err(&dev->dev, "%s resource error!\n",
>+				dev->node->full_name);
>+		goto error_out;
>+	}
>+#if  defined(CONFIG_460SX)
>+	mtdcri(SDR0, SDR0_PCIEH_H, PCIE_MSI_REG_BASE_H);
>+	mtdcri(SDR0, SDR0_PCIEH_L, PCIE_MSI_REG_BASE_L);
>+	msi->msi_regs =3D ioremap(((u64)PCIE_MSI_REG_BASE_H << 32) |
res.start,
>+			res.end - res.start + 1);

You defined sdr-base in the device tree.  Please use it instead of the
hard
coding.

>+#else
>+	dev_err(&dev->dev, " Invalid Device \n");
>+	goto error_out;
>+#endif
>+	if (!msi->msi_regs) {
>+		dev_err(&dev->dev, "ioremap problem failed\n");
>+		goto error_out;
>+	}
>+	/* MSI region always mapped in 4GB region*/
>+	msi->msi_addr_hi =3D 0x0;
>+	msi_virt =3D dma_alloc_coherent(&dev->dev, 64, &msi_phys,
>+			GFP_KERNEL);
>+	if (msi_virt =3D=3D NULL) {
>+		dev_err(&dev->dev, "No memory for MSI mem space\n");
>+		rc =3D -ENOMEM;
>+		goto error_out;
>+	}
>+	msi->msi_addr_lo =3D (u32)msi_phys;
>+
>+	/* Progam the Interrupt handler Termination addr registers */
>+	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
>+	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
>+
>+	/* Program MSI Expected data and Mask bits */
>+	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
>+	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);
>+
>+	msi->irqhost->host_data =3D msi;
>+
>+	if (ppc4xx_msi_init_allocator(msi)) {
>+		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
>+		goto error_out;
>+	}
>+
>+	p =3D of_get_property(dev->node, "interrupts", &count);
>+	if (!p) {
>+		dev_err(&dev->dev, "no interrupts property found on
%s\n",
>+				dev->node->full_name);
>+		rc =3D -ENODEV;
>+		goto error_out;
>+	}
>+	if (count =3D=3D 0) {
>+		dev_err(&dev->dev, "Malformed interrupts property on
%s\n",
>+				dev->node->full_name);
>+		rc =3D -EINVAL;
>+		goto error_out;
>+	}
>+
>+	for (i =3D 0; i < NR_MSI_IRQS; i++) {
>+		virt_msir =3D irq_of_parse_and_map(dev->node, i);
>+		if (virt_msir !=3D NO_IRQ) {
>+			set_irq_data(virt_msir, (void *)i);
>+			set_irq_chained_handler(virt_msir,
ppc4xx_msi_cascade);
>+		}
>+	}
>+
>+	ppc4xx_msi =3D msi;
>+
>+	WARN_ON(ppc_md.setup_msi_irqs);
>+	ppc_md.setup_msi_irqs =3D ppc4xx_setup_msi_irqs;
>+	ppc_md.teardown_msi_irqs =3D ppc4xx_teardown_msi_irqs;
>+	ppc_md.msi_check_device =3D ppc4xx_msi_check_device;
>+	return 0;
>+error_out:
>+	if (msi_virt)
>+		dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
>+	kfree(msi);
>+	return rc;
>+}
>+
>+static const struct ppc4xx_msi_feature ppc4xx_msi_feature =3D {
>+	.ppc4xx_pic_ip =3D 0,
>+	.msiir_offset =3D 0x140,
>+};
>+
>+static const struct of_device_id ppc4xx_msi_ids[] =3D {
>+	{
>+		.compatible =3D "amcc,ppc4xx-msi",
>+		.data =3D (void *)&ppc4xx_msi_feature,
>+	},
>+	{}
>+};
>+
>+static struct of_platform_driver ppc4xx_msi_driver =3D {
>+	.name =3D "ppc4xx-msi",
>+	.match_table =3D ppc4xx_msi_ids,
>+	.probe =3D ppc4xx_msi_probe,
>+};
>+
>+static __init int ppc4xx_msi_init(void)
>+{
>+	return of_register_platform_driver(&ppc4xx_msi_driver);
>+}
>+
>+subsys_initcall(ppc4xx_msi_init);
>diff --git a/arch/powerpc/sysdev/ppc4xx_msi.h
b/arch/powerpc/sysdev/ppc4xx_msi.h
>new file mode 100644
>index 0000000..7b8ac5c
>--- /dev/null
>+++ b/arch/powerpc/sysdev/ppc4xx_msi.h
>@@ -0,0 +1,49 @@
>+/*
>+ * Copyright (C) 2009 Applied Micro Circuits Corporation,
>+ * All rights reserved.

Same comment as above.

>+ *
>+ * Author: T	irumala Marri <tmarri@amcc.com>
>+ * 		Feng Kan <fkan@amcc.com>
>+ * 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.
>+ */
>+#ifndef __PPC4XX_MSI_H__
>+#define __PPC4XX_MSI_H__
>+
>+#include <asm/msi_bitmap.h>
>+
>+#define PEIH_TERMADH    0x00
>+#define PEIH_TERMADL    0x08
>+#define PEIH_MSIED      0x10
>+#define PEIH_MSIMK      0x18
>+#define PEIH_MSIASS     0x20
>+#define PEIH_FLUSH0     0x30
>+#define PEIH_FLUSH1     0x38
>+#define PEIH_CNTRST     0x48
>+
>+#define MSI_DATA_PATTERN   0x44440000
>+
>+#if defined(CONFIG_405Ex)
>+#define SDR0_PCIEH	0x4B1
>+#define PCIE_MSI_REG_BASE	0xef620000
>+#elif defined(CONFIG_440SPe) || defined(CONFIG_460SX)
>+#define SDR0_PCIEH_H	0x3B0
>+#define SDR0_PCIEH_L	0x3B1
>+#define PCIE_MSI_REG_BASE_L 0x00300000
>+#define PCIE_MSI_REG_BASE_H 0x00000004
>+#endif

sdr-base covers quite a bit of this.

>+
>+struct ppc4xx_msi {
>+	struct irq_host *irqhost;
>+	unsigned long cascade_irq;
>+	u32 msi_addr_lo;
>+	u32 msi_addr_hi;
>+	void __iomem *msi_regs;
>+	u32 feature;
>+	struct msi_bitmap bitmap;
>+};

Perhaps add an sdr_base member to this struct, similar to
how the pci port structure looks.

josh

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

* Re: [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
  2009-12-22  8:49 tmarri
@ 2009-12-22 12:07 ` Josh Boyer
  2009-12-22 17:55   ` Tirumala Reddy Marri
  0 siblings, 1 reply; 10+ messages in thread
From: Josh Boyer @ 2009-12-22 12:07 UTC (permalink / raw)
  To: tmarri; +Cc: linuxppc-dev, writetomarri

On Tue, Dec 22, 2009 at 12:49:51AM -0800, tmarri@amcc.com wrote:
>From: Tirumala Marri <tmarri@amcc.com>
>
>
>Signed-off-by: Tirumala Marri <tmarri@amcc.com>
>---
>Kernel version: 2.6.33-rc1
>Testing:
>	When 460SX configured as root as a end point E1000(Intell Ethernet card) 
>	was plugged into the one of the PCI-E ports. I was able to run the traffic
>	with MSI interrupts. 
>---
> arch/powerpc/boot/dts/redwood.dts          |   15 ++
> arch/powerpc/configs/44x/redwood_defconfig |    5 +-
> arch/powerpc/platforms/44x/Kconfig         |    1 +
> arch/powerpc/sysdev/Kconfig                |    7 +
> arch/powerpc/sysdev/Makefile               |    1 +
> arch/powerpc/sysdev/ppc4xx_msi.c           |  335 ++++++++++++++++++++++++++++
> arch/powerpc/sysdev/ppc4xx_msi.h           |   49 ++++
> 7 files changed, 411 insertions(+), 2 deletions(-)
> create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
> create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.h
>
>diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
>index 81636c0..412d5f9 100644
>--- a/arch/powerpc/boot/dts/redwood.dts
>+++ b/arch/powerpc/boot/dts/redwood.dts
>@@ -357,6 +357,21 @@
> 				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */
> 				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
> 		};
>+  		MSI: ppc4xx-msi@400300000 {
>+  			compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
>+  			reg = < 0x4 0x00300000 0x100
>+  				0x4 0x00300000 0x100>;
>+  			sdr-base = <0x3B0>;
>+  			interrupts =<0 1 2 3>;
>+  			interrupt-parent = <&MSI>;
>+  			#interrupt-cells = <1>;
>+  			#address-cells = <0>;
>+  			#size-cells = <0>;
>+  			interrupt-map = <0 &UIC0 0xC 1
>+  				1 &UIC0 0x0D 1
>+  				2 &UIC0 0x0E 1
>+  				3 &UIC0 0x0F 1>;
>+  		};
> 
> 	};
> 
>diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
>index 3965828..32f5a40 100644
>--- a/arch/powerpc/sysdev/Kconfig
>+++ b/arch/powerpc/sysdev/Kconfig
>@@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
> 	depends on PCI && 4xx
> 	default n
> 
>+config 4xx_MSI

This should probably be named PPC4xx_MSI, similar to how
PPC4xx_PCI_EXPRESS is named.

>+	bool
>+	depends on PCI_MSI
>+	depends on PCI && 4xx
>+	default n
>+
> config PPC_MSI_BITMAP
> 	bool
> 	depends on PCI_MSI
> 	default y if MPIC
> 	default y if FSL_PCI
>+	default y if 4xx_MSI

>diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
>new file mode 100644
>index 0000000..752da4b
>--- /dev/null
>+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
>@@ -0,0 +1,335 @@
>+/*
>+ * Copyright (C) 2009 Applied Micro Circuits corporation,
>+ * All rights reserved.

Please don't add the 'All rights reserved.' to new files.  It is
inaccurate and confusing given that it's a GPLv2 file.

>+ *
>+ * Author: Feng Kan <fkan@amcc.com>
>+ * 	   Tirumala Marri <tmarri@amcc.com>
>+ * This program is free software; you can redistribute it and/or
>+ * modify it under the terms of the GNU General Public License
>+ * as published by the Free Software Foundation; version 2 of the
>+ * License.
>+ */
>+#include <linux/irq.h>
>+#include <linux/bootmem.h>
>+#include <linux/pci.h>
>+#include <linux/msi.h>
>+#include <linux/of_platform.h>
>+#include <linux/interrupt.h>
>+#include <linux/device.h>
>+#include <asm/prom.h>
>+#include <asm/hw_irq.h>
>+#include <asm/ppc-pci.h>
>+#include <asm/dcr.h>
>+#include <asm/dcr-regs.h>
>+#include "ppc4xx_msi.h"
>+
>+
>+static struct ppc4xx_msi *ppc4xx_msi;
>+
>+struct ppc4xx_msi_feature {
>+	u32 ppc4xx_pic_ip;
>+	u32 msiir_offset;
>+};
>+
>+static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
>+{
>+	int rc;
>+
>+	rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
>+				msi_data->irqhost->of_node);
>+	if (rc)
>+		return rc;
>+	rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
>+	if (rc < 0) {
>+		msi_bitmap_free(&msi_data->bitmap);
>+		return rc;
>+	}
>+	return 0;
>+}
>+
>+
>+static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc *desc)
>+{
>+	unsigned int cascade_irq;
>+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
>+	int msir_index = -1;
>+
>+	raw_spin_lock(&desc->lock);
>+	if (desc->chip->mask_ack) {
>+		desc->chip->mask_ack(irq);
>+	} else {
>+		desc->chip->mask(irq);
>+		desc->chip->ack(irq);
>+	}
>+
>+	if (unlikely(desc->status & IRQ_INPROGRESS))
>+		goto unlock;
>+
>+	msir_index = (int)desc->handler_data;
>+
>+	if (msir_index >= NR_MSI_IRQS)
>+		cascade_irq = NO_IRQ;
>+
>+	desc->status |= IRQ_INPROGRESS;
>+
>+	cascade_irq = irq_linear_revmap(msi_data->irqhost, msir_index);
>+	if (cascade_irq != NO_IRQ)
>+		generic_handle_irq(cascade_irq);
>+	desc->status &= ~IRQ_INPROGRESS;
>+
>+	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
>+		desc->chip->unmask(irq);
>+unlock:
>+	raw_spin_unlock(&desc->lock);
>+}
>+static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
>+					struct msi_msg *msg)
>+{
>+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
>+
>+	msg->address_lo = msi_data->msi_addr_lo;
>+	msg->address_hi = msi_data->msi_addr_hi;
>+	msg->data = hwirq;
>+}
>+
>+
>+int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
>+{
>+	struct msi_desc *entry;
>+	int rc, hwirq;
>+	unsigned int virq;
>+	struct msi_msg msg;
>+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
>+
>+
>+	list_for_each_entry(entry, &dev->msi_list, list) {
>+		hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
>+		if (hwirq < 0) {
>+			rc = hwirq;
>+			dev_err(&dev->dev, "%s: fail allocating msi\
>+					interrupt\n",	__func__);
>+			goto out_free;
>+		}
>+
>+		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
>+		virq = irq_create_mapping(msi_data->irqhost, hwirq);
>+		if (virq == NO_IRQ) {
>+			dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
>+			rc = -ENOSPC;
>+			goto out_free;
>+		}
>+
>+		set_irq_msi(virq, entry);
>+		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
>+		write_msi_msg(virq, &msg);
>+	}
>+
>+	return 0;
>+out_free:
>+	return rc;
>+}
>+
>+void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
>+{
>+	struct msi_desc *entry;
>+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
>+	 dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
>+
>+	list_for_each_entry(entry, &dev->msi_list, list) {
>+		if (entry->irq == NO_IRQ)
>+			continue;
>+		set_irq_msi(entry->irq, NULL);
>+		msi_bitmap_free_hwirqs(&msi_data->bitmap,
>+				       virq_to_hw(entry->irq), 1);
>+		irq_dispose_mapping(entry->irq);
>+
>+	}
>+
>+	return;
>+}
>+
>+static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
>+{
>+	pr_debug(KERN_INFO"PCIE-MSI:%s called. vec %x type %d\n",
>+					__func__, nvec, type);
>+	return 0;
>+}
>+
>+/*
>+ * We do not need this actually. The MSIR register has been read once
>+ * in the cascade interrupt. So, this MSI interrupt has been acked
>+*/
>+static void ppc4xx_msi_end_irq(unsigned int virq)
>+{
>+}
>+
>+
>+static struct irq_chip ppc4xx_msi_chip = {
>+	.mask           = mask_msi_irq,
>+	.unmask         = unmask_msi_irq,
>+	.ack            = ppc4xx_msi_end_irq,
>+	.name       = " UIC",
>+};
>+
>+static int ppc4xx_msi_host_map(struct irq_host *h, unsigned int virq,
>+				irq_hw_number_t hw)
>+{
>+	struct irq_chip *chip = &ppc4xx_msi_chip;
>+
>+	irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_RISING;
>+
>+	set_irq_chip_and_handler(virq, chip, handle_edge_irq);
>+
>+	return 0;
>+}
>+
>+static struct irq_host_ops ppc4xx_msi_host_ops = {
>+	.map = ppc4xx_msi_host_map,
>+};
>+
>+
>+static int __devinit ppc4xx_msi_probe(struct of_device *dev,
>+					const struct of_device_id *match)
>+{
>+	struct ppc4xx_msi *msi;
>+	struct resource res, rmsi;
>+	int i, count;
>+	int rc;
>+	int virt_msir;
>+	const u32 *p;
>+	u32 *msi_virt = NULL;
>+	dma_addr_t msi_phys;
>+
>+
>+	msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
>+	if (!msi) {
>+		dev_err(&dev->dev, "No memory for MSI structure\n");
>+		rc = -ENOMEM;
>+		goto error_out;
>+	}
>+
>+	msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
>+				      NR_MSI_IRQS, &ppc4xx_msi_host_ops, 0);
>+	if (msi->irqhost == NULL) {
>+		dev_err(&dev->dev, "No memory for MSI irqhost\n");
>+		rc = -ENOMEM;
>+		goto error_out;
>+	}
>+
>+
>+	/* Get MSI ranges */
>+	rc = of_address_to_resource(dev->node, 0, &rmsi);
>+	if (rc) {
>+		dev_err(&dev->dev, "%s resource error!\n",
>+				dev->node->full_name);
>+		goto error_out;
>+	}
>+
>+
>+	/* Get the MSI reg base */
>+	rc = of_address_to_resource(dev->node, 1, &res);
>+	if (rc) {
>+		dev_err(&dev->dev, "%s resource error!\n",
>+				dev->node->full_name);
>+		goto error_out;
>+	}
>+#if  defined(CONFIG_460SX)
>+	mtdcri(SDR0, SDR0_PCIEH_H, PCIE_MSI_REG_BASE_H);
>+	mtdcri(SDR0, SDR0_PCIEH_L, PCIE_MSI_REG_BASE_L);
>+	msi->msi_regs = ioremap(((u64)PCIE_MSI_REG_BASE_H << 32) | res.start,
>+			res.end - res.start + 1);

You defined sdr-base in the device tree.  Please use it instead of the hard
coding.

>+#else
>+	dev_err(&dev->dev, " Invalid Device \n");
>+	goto error_out;
>+#endif
>+	if (!msi->msi_regs) {
>+		dev_err(&dev->dev, "ioremap problem failed\n");
>+		goto error_out;
>+	}
>+	/* MSI region always mapped in 4GB region*/
>+	msi->msi_addr_hi = 0x0;
>+	msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys,
>+			GFP_KERNEL);
>+	if (msi_virt == NULL) {
>+		dev_err(&dev->dev, "No memory for MSI mem space\n");
>+		rc = -ENOMEM;
>+		goto error_out;
>+	}
>+	msi->msi_addr_lo = (u32)msi_phys;
>+
>+	/* Progam the Interrupt handler Termination addr registers */
>+	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
>+	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
>+
>+	/* Program MSI Expected data and Mask bits */
>+	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
>+	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);
>+
>+	msi->irqhost->host_data = msi;
>+
>+	if (ppc4xx_msi_init_allocator(msi)) {
>+		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
>+		goto error_out;
>+	}
>+
>+	p = of_get_property(dev->node, "interrupts", &count);
>+	if (!p) {
>+		dev_err(&dev->dev, "no interrupts property found on %s\n",
>+				dev->node->full_name);
>+		rc = -ENODEV;
>+		goto error_out;
>+	}
>+	if (count == 0) {
>+		dev_err(&dev->dev, "Malformed interrupts property on %s\n",
>+				dev->node->full_name);
>+		rc = -EINVAL;
>+		goto error_out;
>+	}
>+
>+	for (i = 0; i < NR_MSI_IRQS; i++) {
>+		virt_msir = irq_of_parse_and_map(dev->node, i);
>+		if (virt_msir != NO_IRQ) {
>+			set_irq_data(virt_msir, (void *)i);
>+			set_irq_chained_handler(virt_msir, ppc4xx_msi_cascade);
>+		}
>+	}
>+
>+	ppc4xx_msi = msi;
>+
>+	WARN_ON(ppc_md.setup_msi_irqs);
>+	ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
>+	ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
>+	ppc_md.msi_check_device = ppc4xx_msi_check_device;
>+	return 0;
>+error_out:
>+	if (msi_virt)
>+		dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
>+	kfree(msi);
>+	return rc;
>+}
>+
>+static const struct ppc4xx_msi_feature ppc4xx_msi_feature = {
>+	.ppc4xx_pic_ip = 0,
>+	.msiir_offset = 0x140,
>+};
>+
>+static const struct of_device_id ppc4xx_msi_ids[] = {
>+	{
>+		.compatible = "amcc,ppc4xx-msi",
>+		.data = (void *)&ppc4xx_msi_feature,
>+	},
>+	{}
>+};
>+
>+static struct of_platform_driver ppc4xx_msi_driver = {
>+	.name = "ppc4xx-msi",
>+	.match_table = ppc4xx_msi_ids,
>+	.probe = ppc4xx_msi_probe,
>+};
>+
>+static __init int ppc4xx_msi_init(void)
>+{
>+	return of_register_platform_driver(&ppc4xx_msi_driver);
>+}
>+
>+subsys_initcall(ppc4xx_msi_init);
>diff --git a/arch/powerpc/sysdev/ppc4xx_msi.h b/arch/powerpc/sysdev/ppc4xx_msi.h
>new file mode 100644
>index 0000000..7b8ac5c
>--- /dev/null
>+++ b/arch/powerpc/sysdev/ppc4xx_msi.h
>@@ -0,0 +1,49 @@
>+/*
>+ * Copyright (C) 2009 Applied Micro Circuits Corporation,
>+ * All rights reserved.

Same comment as above.

>+ *
>+ * Author: T	irumala Marri <tmarri@amcc.com>
>+ * 		Feng Kan <fkan@amcc.com>
>+ * 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.
>+ */
>+#ifndef __PPC4XX_MSI_H__
>+#define __PPC4XX_MSI_H__
>+
>+#include <asm/msi_bitmap.h>
>+
>+#define PEIH_TERMADH    0x00
>+#define PEIH_TERMADL    0x08
>+#define PEIH_MSIED      0x10
>+#define PEIH_MSIMK      0x18
>+#define PEIH_MSIASS     0x20
>+#define PEIH_FLUSH0     0x30
>+#define PEIH_FLUSH1     0x38
>+#define PEIH_CNTRST     0x48
>+
>+#define MSI_DATA_PATTERN   0x44440000
>+
>+#if defined(CONFIG_405Ex)
>+#define SDR0_PCIEH	0x4B1
>+#define PCIE_MSI_REG_BASE	0xef620000
>+#elif defined(CONFIG_440SPe) || defined(CONFIG_460SX)
>+#define SDR0_PCIEH_H	0x3B0
>+#define SDR0_PCIEH_L	0x3B1
>+#define PCIE_MSI_REG_BASE_L 0x00300000
>+#define PCIE_MSI_REG_BASE_H 0x00000004
>+#endif

sdr-base covers quite a bit of this.

>+
>+struct ppc4xx_msi {
>+	struct irq_host *irqhost;
>+	unsigned long cascade_irq;
>+	u32 msi_addr_lo;
>+	u32 msi_addr_hi;
>+	void __iomem *msi_regs;
>+	u32 feature;
>+	struct msi_bitmap bitmap;
>+};

Perhaps add an sdr_base member to this struct, similar to
how the pci port structure looks.

josh

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

* [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC.
@ 2009-12-22  8:49 tmarri
  2009-12-22 12:07 ` Josh Boyer
  0 siblings, 1 reply; 10+ messages in thread
From: tmarri @ 2009-12-22  8:49 UTC (permalink / raw)
  To: jwboyer, linuxppc-dev; +Cc: linuxppc-dev, writetomarri, tmarri

From: Tirumala Marri <tmarri@amcc.com>


Signed-off-by: Tirumala Marri <tmarri@amcc.com>
---
Kernel version: 2.6.33-rc1
Testing:
	When 460SX configured as root as a end point E1000(Intell Ethernet card) 
	was plugged into the one of the PCI-E ports. I was able to run the traffic
	with MSI interrupts. 
---
 arch/powerpc/boot/dts/redwood.dts          |   15 ++
 arch/powerpc/configs/44x/redwood_defconfig |    5 +-
 arch/powerpc/platforms/44x/Kconfig         |    1 +
 arch/powerpc/sysdev/Kconfig                |    7 +
 arch/powerpc/sysdev/Makefile               |    1 +
 arch/powerpc/sysdev/ppc4xx_msi.c           |  335 ++++++++++++++++++++++++++++
 arch/powerpc/sysdev/ppc4xx_msi.h           |   49 ++++
 7 files changed, 411 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.c
 create mode 100644 arch/powerpc/sysdev/ppc4xx_msi.h

diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
index 81636c0..412d5f9 100644
--- a/arch/powerpc/boot/dts/redwood.dts
+++ b/arch/powerpc/boot/dts/redwood.dts
@@ -357,6 +357,21 @@
 				0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */
 				0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
 		};
+  		MSI: ppc4xx-msi@400300000 {
+  			compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+  			reg = < 0x4 0x00300000 0x100
+  				0x4 0x00300000 0x100>;
+  			sdr-base = <0x3B0>;
+  			interrupts =<0 1 2 3>;
+  			interrupt-parent = <&MSI>;
+  			#interrupt-cells = <1>;
+  			#address-cells = <0>;
+  			#size-cells = <0>;
+  			interrupt-map = <0 &UIC0 0xC 1
+  				1 &UIC0 0x0D 1
+  				2 &UIC0 0x0E 1
+  				3 &UIC0 0x0F 1>;
+  		};
 
 	};
 
diff --git a/arch/powerpc/configs/44x/redwood_defconfig b/arch/powerpc/configs/44x/redwood_defconfig
index ed31d4f..5d16c88 100644
--- a/arch/powerpc/configs/44x/redwood_defconfig
+++ b/arch/powerpc/configs/44x/redwood_defconfig
@@ -158,6 +158,7 @@ CONFIG_DEFAULT_AS=y
 CONFIG_DEFAULT_IOSCHED="anticipatory"
 # CONFIG_FREEZER is not set
 CONFIG_PPC4xx_PCI_EXPRESS=y
+CONFIG_PPC_MSI_BITMAP=y
 
 #
 # Platform support
@@ -264,7 +265,7 @@ CONFIG_PCIEPORTBUS=y
 CONFIG_PCIEAER=y
 # CONFIG_PCIEASPM is not set
 CONFIG_ARCH_SUPPORTS_MSI=y
-# CONFIG_PCI_MSI is not set
+CONFIG_PCI_MSI=y
 # CONFIG_PCI_LEGACY is not set
 # CONFIG_PCI_DEBUG is not set
 # CONFIG_PCI_STUB is not set
@@ -1062,7 +1063,7 @@ CONFIG_PRINT_STACK_DEPTH=64
 # CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_CODE_PATCHING_SELFTEST is not set
 # CONFIG_FTR_FIXUP_SELFTEST is not set
-# CONFIG_MSI_BITMAP_SELFTEST is not set
+CONFIG_MSI_BITMAP_SELFTEST=y
 # CONFIG_XMON is not set
 # CONFIG_IRQSTACKS is not set
 # CONFIG_VIRQ_DEBUG is not set
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 7486bff..85b9c33 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -126,6 +126,7 @@ config REDWOOD
 	select 460SX
 	select PCI
 	select PPC4xx_PCI_EXPRESS
+	select 4xx_MSI
 	help
 	  This option enables support for the AMCC PPC460SX Redwood board.
 
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 3965828..32f5a40 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -7,8 +7,15 @@ config PPC4xx_PCI_EXPRESS
 	depends on PCI && 4xx
 	default n
 
+config 4xx_MSI
+	bool
+	depends on PCI_MSI
+	depends on PCI && 4xx
+	default n
+
 config PPC_MSI_BITMAP
 	bool
 	depends on PCI_MSI
 	default y if MPIC
 	default y if FSL_PCI
+	default y if 4xx_MSI
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 5642924..d60c33b 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_I8259)		+= i8259.o
 obj-$(CONFIG_IPIC)		+= ipic.o
 obj-$(CONFIG_4xx)		+= uic.o
 obj-$(CONFIG_4xx_SOC)		+= ppc4xx_soc.o
+obj-$(CONFIG_4xx_MSI)		+= ppc4xx_msi.o
 obj-$(CONFIG_XILINX_VIRTEX)	+= xilinx_intc.o
 obj-$(CONFIG_XILINX_PCI)	+= xilinx_pci.o
 obj-$(CONFIG_OF_RTC)		+= of_rtc.o
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
new file mode 100644
index 0000000..752da4b
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2009 Applied Micro Circuits corporation,
+ * All rights reserved.
+ *
+ * Author: Feng Kan <fkan@amcc.com>
+ * 	   Tirumala Marri <tmarri@amcc.com>
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+#include <asm/dcr.h>
+#include <asm/dcr-regs.h>
+#include "ppc4xx_msi.h"
+
+
+static struct ppc4xx_msi *ppc4xx_msi;
+
+struct ppc4xx_msi_feature {
+	u32 ppc4xx_pic_ip;
+	u32 msiir_offset;
+};
+
+static int ppc4xx_msi_init_allocator(struct ppc4xx_msi *msi_data)
+{
+	int rc;
+
+	rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+				msi_data->irqhost->of_node);
+	if (rc)
+		return rc;
+	rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
+	if (rc < 0) {
+		msi_bitmap_free(&msi_data->bitmap);
+		return rc;
+	}
+	return 0;
+}
+
+
+static void ppc4xx_msi_cascade(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned int cascade_irq;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+	int msir_index = -1;
+
+	raw_spin_lock(&desc->lock);
+	if (desc->chip->mask_ack) {
+		desc->chip->mask_ack(irq);
+	} else {
+		desc->chip->mask(irq);
+		desc->chip->ack(irq);
+	}
+
+	if (unlikely(desc->status & IRQ_INPROGRESS))
+		goto unlock;
+
+	msir_index = (int)desc->handler_data;
+
+	if (msir_index >= NR_MSI_IRQS)
+		cascade_irq = NO_IRQ;
+
+	desc->status |= IRQ_INPROGRESS;
+
+	cascade_irq = irq_linear_revmap(msi_data->irqhost, msir_index);
+	if (cascade_irq != NO_IRQ)
+		generic_handle_irq(cascade_irq);
+	desc->status &= ~IRQ_INPROGRESS;
+
+	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+		desc->chip->unmask(irq);
+unlock:
+	raw_spin_unlock(&desc->lock);
+}
+static void ppc4xx_compose_msi_msg(struct pci_dev *pdev, int hwirq,
+					struct msi_msg *msg)
+{
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+
+	msg->address_lo = msi_data->msi_addr_lo;
+	msg->address_hi = msi_data->msi_addr_hi;
+	msg->data = hwirq;
+}
+
+
+int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+	struct msi_desc *entry;
+	int rc, hwirq;
+	unsigned int virq;
+	struct msi_msg msg;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+		if (hwirq < 0) {
+			rc = hwirq;
+			dev_err(&dev->dev, "%s: fail allocating msi\
+					interrupt\n",	__func__);
+			goto out_free;
+		}
+
+		pr_debug(KERN_INFO"mis is %p\n", msi_data->irqhost);
+		virq = irq_create_mapping(msi_data->irqhost, hwirq);
+		if (virq == NO_IRQ) {
+			dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
+			rc = -ENOSPC;
+			goto out_free;
+		}
+
+		set_irq_msi(virq, entry);
+		ppc4xx_compose_msi_msg(dev, hwirq, &msg);
+		write_msi_msg(virq, &msg);
+	}
+
+	return 0;
+out_free:
+	return rc;
+}
+
+void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
+{
+	struct msi_desc *entry;
+	struct ppc4xx_msi *msi_data = ppc4xx_msi;
+	 dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
+
+	list_for_each_entry(entry, &dev->msi_list, list) {
+		if (entry->irq == NO_IRQ)
+			continue;
+		set_irq_msi(entry->irq, NULL);
+		msi_bitmap_free_hwirqs(&msi_data->bitmap,
+				       virq_to_hw(entry->irq), 1);
+		irq_dispose_mapping(entry->irq);
+
+	}
+
+	return;
+}
+
+static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+	pr_debug(KERN_INFO"PCIE-MSI:%s called. vec %x type %d\n",
+					__func__, nvec, type);
+	return 0;
+}
+
+/*
+ * We do not need this actually. The MSIR register has been read once
+ * in the cascade interrupt. So, this MSI interrupt has been acked
+*/
+static void ppc4xx_msi_end_irq(unsigned int virq)
+{
+}
+
+
+static struct irq_chip ppc4xx_msi_chip = {
+	.mask           = mask_msi_irq,
+	.unmask         = unmask_msi_irq,
+	.ack            = ppc4xx_msi_end_irq,
+	.name       = " UIC",
+};
+
+static int ppc4xx_msi_host_map(struct irq_host *h, unsigned int virq,
+				irq_hw_number_t hw)
+{
+	struct irq_chip *chip = &ppc4xx_msi_chip;
+
+	irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_RISING;
+
+	set_irq_chip_and_handler(virq, chip, handle_edge_irq);
+
+	return 0;
+}
+
+static struct irq_host_ops ppc4xx_msi_host_ops = {
+	.map = ppc4xx_msi_host_map,
+};
+
+
+static int __devinit ppc4xx_msi_probe(struct of_device *dev,
+					const struct of_device_id *match)
+{
+	struct ppc4xx_msi *msi;
+	struct resource res, rmsi;
+	int i, count;
+	int rc;
+	int virt_msir;
+	const u32 *p;
+	u32 *msi_virt = NULL;
+	dma_addr_t msi_phys;
+
+
+	msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
+	if (!msi) {
+		dev_err(&dev->dev, "No memory for MSI structure\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+
+	msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
+				      NR_MSI_IRQS, &ppc4xx_msi_host_ops, 0);
+	if (msi->irqhost == NULL) {
+		dev_err(&dev->dev, "No memory for MSI irqhost\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+
+
+	/* Get MSI ranges */
+	rc = of_address_to_resource(dev->node, 0, &rmsi);
+	if (rc) {
+		dev_err(&dev->dev, "%s resource error!\n",
+				dev->node->full_name);
+		goto error_out;
+	}
+
+
+	/* Get the MSI reg base */
+	rc = of_address_to_resource(dev->node, 1, &res);
+	if (rc) {
+		dev_err(&dev->dev, "%s resource error!\n",
+				dev->node->full_name);
+		goto error_out;
+	}
+#if  defined(CONFIG_460SX)
+	mtdcri(SDR0, SDR0_PCIEH_H, PCIE_MSI_REG_BASE_H);
+	mtdcri(SDR0, SDR0_PCIEH_L, PCIE_MSI_REG_BASE_L);
+	msi->msi_regs = ioremap(((u64)PCIE_MSI_REG_BASE_H << 32) | res.start,
+			res.end - res.start + 1);
+#else
+	dev_err(&dev->dev, " Invalid Device \n");
+	goto error_out;
+#endif
+	if (!msi->msi_regs) {
+		dev_err(&dev->dev, "ioremap problem failed\n");
+		goto error_out;
+	}
+	/* MSI region always mapped in 4GB region*/
+	msi->msi_addr_hi = 0x0;
+	msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys,
+			GFP_KERNEL);
+	if (msi_virt == NULL) {
+		dev_err(&dev->dev, "No memory for MSI mem space\n");
+		rc = -ENOMEM;
+		goto error_out;
+	}
+	msi->msi_addr_lo = (u32)msi_phys;
+
+	/* Progam the Interrupt handler Termination addr registers */
+	out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
+	out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
+
+	/* Program MSI Expected data and Mask bits */
+	out_be32(msi->msi_regs + PEIH_MSIED, MSI_DATA_PATTERN);
+	out_be32(msi->msi_regs + PEIH_MSIMK, MSI_DATA_PATTERN);
+
+	msi->irqhost->host_data = msi;
+
+	if (ppc4xx_msi_init_allocator(msi)) {
+		dev_err(&dev->dev, "Error allocating MSI bitmap\n");
+		goto error_out;
+	}
+
+	p = of_get_property(dev->node, "interrupts", &count);
+	if (!p) {
+		dev_err(&dev->dev, "no interrupts property found on %s\n",
+				dev->node->full_name);
+		rc = -ENODEV;
+		goto error_out;
+	}
+	if (count == 0) {
+		dev_err(&dev->dev, "Malformed interrupts property on %s\n",
+				dev->node->full_name);
+		rc = -EINVAL;
+		goto error_out;
+	}
+
+	for (i = 0; i < NR_MSI_IRQS; i++) {
+		virt_msir = irq_of_parse_and_map(dev->node, i);
+		if (virt_msir != NO_IRQ) {
+			set_irq_data(virt_msir, (void *)i);
+			set_irq_chained_handler(virt_msir, ppc4xx_msi_cascade);
+		}
+	}
+
+	ppc4xx_msi = msi;
+
+	WARN_ON(ppc_md.setup_msi_irqs);
+	ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
+	ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
+	ppc_md.msi_check_device = ppc4xx_msi_check_device;
+	return 0;
+error_out:
+	if (msi_virt)
+		dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
+	kfree(msi);
+	return rc;
+}
+
+static const struct ppc4xx_msi_feature ppc4xx_msi_feature = {
+	.ppc4xx_pic_ip = 0,
+	.msiir_offset = 0x140,
+};
+
+static const struct of_device_id ppc4xx_msi_ids[] = {
+	{
+		.compatible = "amcc,ppc4xx-msi",
+		.data = (void *)&ppc4xx_msi_feature,
+	},
+	{}
+};
+
+static struct of_platform_driver ppc4xx_msi_driver = {
+	.name = "ppc4xx-msi",
+	.match_table = ppc4xx_msi_ids,
+	.probe = ppc4xx_msi_probe,
+};
+
+static __init int ppc4xx_msi_init(void)
+{
+	return of_register_platform_driver(&ppc4xx_msi_driver);
+}
+
+subsys_initcall(ppc4xx_msi_init);
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.h b/arch/powerpc/sysdev/ppc4xx_msi.h
new file mode 100644
index 0000000..7b8ac5c
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_msi.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 Applied Micro Circuits Corporation,
+ * All rights reserved.
+ *
+ * Author: T	irumala Marri <tmarri@amcc.com>
+ * 		Feng Kan <fkan@amcc.com>
+ * 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.
+ */
+#ifndef __PPC4XX_MSI_H__
+#define __PPC4XX_MSI_H__
+
+#include <asm/msi_bitmap.h>
+
+#define PEIH_TERMADH    0x00
+#define PEIH_TERMADL    0x08
+#define PEIH_MSIED      0x10
+#define PEIH_MSIMK      0x18
+#define PEIH_MSIASS     0x20
+#define PEIH_FLUSH0     0x30
+#define PEIH_FLUSH1     0x38
+#define PEIH_CNTRST     0x48
+
+#define MSI_DATA_PATTERN   0x44440000
+
+#if defined(CONFIG_405Ex)
+#define SDR0_PCIEH	0x4B1
+#define PCIE_MSI_REG_BASE	0xef620000
+#elif defined(CONFIG_440SPe) || defined(CONFIG_460SX)
+#define SDR0_PCIEH_H	0x3B0
+#define SDR0_PCIEH_L	0x3B1
+#define PCIE_MSI_REG_BASE_L 0x00300000
+#define PCIE_MSI_REG_BASE_H 0x00000004
+#endif
+
+struct ppc4xx_msi {
+	struct irq_host *irqhost;
+	unsigned long cascade_irq;
+	u32 msi_addr_lo;
+	u32 msi_addr_hi;
+	void __iomem *msi_regs;
+	u32 feature;
+	struct msi_bitmap bitmap;
+};
+
+#define NR_MSI_IRQS 4
+#endif /* __PPC4XX_MSI_H__ */
-- 
1.6.1.rc3

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

end of thread, other threads:[~2010-01-11  6:47 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-24  7:28 [PATCH 2/2] Adding PCI-E MSI support for PowerPC 460SX SOC tmarri
2010-01-04  6:25 ` Benjamin Herrenschmidt
2010-01-11  6:46   ` Tirumala Reddy Marri
  -- strict thread matches above, loose matches on Subject: below --
2009-12-23  7:52 tmarri
2009-12-23  8:18 ` Stefan Roese
2009-12-23 17:23   ` Tirumala Reddy Marri
2009-12-23 17:30     ` Tirumala Reddy Marri
2009-12-22  8:49 tmarri
2009-12-22 12:07 ` Josh Boyer
2009-12-22 17:55   ` Tirumala Reddy Marri

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