Thanks for the suggestions. I will try remove the extra lines . Add changes you suggested. -Marri
-----Original Message----- From: linuxppc-dev-bounces+tmarri=amcc....@lists.ozlabs.org [mailto:linuxppc-dev-bounces+tmarri=amcc....@lists.ozlabs.org] On Behalf Of Stefan Roese Sent: Wednesday, December 23, 2009 12:19 AM To: linuxppc-dev@lists.ozlabs.org Cc: linuxppc-...@ozlabs.org; writetoma...@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 tma...@amcc.com wrote: > From: Tirumala Marri <tma...@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 <tma...@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-...@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 <f...@amcc.com> > + * Tirumala Marri <tma...@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 <tma...@amcc.com> > + * Feng Kan <f...@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: off...@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