From b6c46dcf61173999d95597bea87628cc08b359fb Mon Sep 17 00:00:00 2001 From: Liu Gang Date: Tue, 6 Mar 2012 10:58:12 +0800 Subject: powerpc/srio: Fix the relocation errors when building with 64bit For the file "arch/powerpc/sysdev/fsl_rio.c", there will be some relocation errors while using the corenet64_smp_defconfig: WARNING: modpost: Found 6 section mismatch(es). To see full details build your kernel with: 'make CONFIG_DEBUG_SECTION_MISMATCH=y' GEN .version CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o LD init/built-in.o LD .tmp_vmlinux1 arch/powerpc/sysdev/built-in.o:(__ex_table+0x0): relocation truncated to fit: R_PPC64_ADDR16 against `.text'+3208 arch/powerpc/sysdev/built-in.o:(__ex_table+0x2): relocation truncated to fit: R_PPC64_ADDR16 against `.fixup' arch/powerpc/sysdev/built-in.o:(__ex_table+0x4): relocation truncated to fit: R_PPC64_ADDR16 against `.text'+3230 arch/powerpc/sysdev/built-in.o:(__ex_table+0x6): relocation truncated to fit: R_PPC64_ADDR16 against `.fixup'+c arch/powerpc/sysdev/built-in.o:(__ex_table+0x8): relocation truncated to fit: R_PPC64_ADDR16 against `.text'+3250 arch/powerpc/sysdev/built-in.o:(__ex_table+0xa): relocation truncated to fit: R_PPC64_ADDR16 against `.fixup'+18 Rewrote the corresponding code with the support of 64bit building. Signed-off-by: Liu Gang Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_rio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index a4c4f4a932d8..5b6f556094dd 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -66,8 +66,8 @@ " li %0,%3\n" \ " b 2b\n" \ ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ + PPC_LONG_ALIGN "\n" \ + PPC_LONG "1b,3b\n" \ ".text" \ : "=r" (err), "=r" (x) \ : "b" (addr), "i" (-EFAULT), "0" (err)) -- cgit v1.2.3 From 2a2383dab097823d68accce65da043402bdeb57b Mon Sep 17 00:00:00 2001 From: Liu Gang Date: Fri, 9 Mar 2012 16:10:38 +0800 Subject: powerpc/srio: Fix the compile errors when building with 64bit For the file "arch/powerpc/sysdev/fsl_rmu.c", there will be some compile errors while using the corenet64_smp_defconfig: .../fsl_rmu.c:315: error: cast from pointer to integer of different size .../fsl_rmu.c:320: error: cast to pointer from integer of different size .../fsl_rmu.c:320: error: cast to pointer from integer of different size .../fsl_rmu.c:320: error: cast to pointer from integer of different size .../fsl_rmu.c:330: error: cast to pointer from integer of different size .../fsl_rmu.c:332: error: cast to pointer from integer of different size .../fsl_rmu.c:339: error: cast to pointer from integer of different size .../fsl_rmu.c:340: error: cast to pointer from integer of different size .../fsl_rmu.c:341: error: cast to pointer from integer of different size .../fsl_rmu.c:348: error: cast to pointer from integer of different size .../fsl_rmu.c:348: error: cast to pointer from integer of different size .../fsl_rmu.c:348: error: cast to pointer from integer of different size .../fsl_rmu.c:659: error: cast from pointer to integer of different size .../fsl_rmu.c:659: error: format '%8.8x' expects type 'unsigned int', but argument 5 has type 'size_t' .../fsl_rmu.c:985: error: cast from pointer to integer of different size .../fsl_rmu.c:997: error: cast to pointer from integer of different size Rewrote the corresponding code with the support of 64bit building. Signed-off-by: Liu Gang Signed-off-by: Shaohui Xie Reported-by: Paul Gortmaker Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_rmu.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c index 15485789e9db..14bd5221f28a 100644 --- a/arch/powerpc/sysdev/fsl_rmu.c +++ b/arch/powerpc/sysdev/fsl_rmu.c @@ -100,14 +100,8 @@ #define DOORBELL_DSR_TE 0x00000080 #define DOORBELL_DSR_QFI 0x00000010 #define DOORBELL_DSR_DIQI 0x00000001 -#define DOORBELL_TID_OFFSET 0x02 -#define DOORBELL_SID_OFFSET 0x04 -#define DOORBELL_INFO_OFFSET 0x06 #define DOORBELL_MESSAGE_SIZE 0x08 -#define DBELL_SID(x) (*(u16 *)(x + DOORBELL_SID_OFFSET)) -#define DBELL_TID(x) (*(u16 *)(x + DOORBELL_TID_OFFSET)) -#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) struct rio_msg_regs { u32 omr; @@ -193,6 +187,13 @@ struct fsl_rmu { int rxirq; }; +struct rio_dbell_msg { + u16 pad1; + u16 tid; + u16 sid; + u16 info; +}; + /** * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler * @irq: Linux interrupt number @@ -311,8 +312,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) /* XXX Need to check/dispatch until queue empty */ if (dsr & DOORBELL_DSR_DIQI) { - u32 dmsg = - (u32) fsl_dbell->dbell_ring.virt + + struct rio_dbell_msg *dmsg = + fsl_dbell->dbell_ring.virt + (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); struct rio_dbell *dbell; int found = 0; @@ -320,25 +321,25 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) pr_debug ("RIO: processing doorbell," " sid %2.2x tid %2.2x info %4.4x\n", - DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); + dmsg->sid, dmsg->tid, dmsg->info); for (i = 0; i < MAX_PORT_NUM; i++) { if (fsl_dbell->mport[i]) { list_for_each_entry(dbell, &fsl_dbell->mport[i]->dbells, node) { if ((dbell->res->start - <= DBELL_INF(dmsg)) + <= dmsg->info) && (dbell->res->end - >= DBELL_INF(dmsg))) { + >= dmsg->info)) { found = 1; break; } } if (found && dbell->dinb) { dbell->dinb(fsl_dbell->mport[i], - dbell->dev_id, DBELL_SID(dmsg), - DBELL_TID(dmsg), - DBELL_INF(dmsg)); + dbell->dev_id, dmsg->sid, + dmsg->tid, + dmsg->info); break; } } @@ -348,8 +349,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) pr_debug ("RIO: spurious doorbell," " sid %2.2x tid %2.2x info %4.4x\n", - DBELL_SID(dmsg), DBELL_TID(dmsg), - DBELL_INF(dmsg)); + dmsg->sid, dmsg->tid, + dmsg->info); } setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI); out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI); @@ -657,7 +658,7 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, int ret = 0; pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \ - "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len); + "%p len %8.8zx\n", rdev->destid, mbox, buffer, len); if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { ret = -EINVAL; goto out; @@ -972,7 +973,8 @@ out: void *fsl_get_inb_message(struct rio_mport *mport, int mbox) { struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); - u32 phys_buf, virt_buf; + u32 phys_buf; + void *virt_buf; void *buf = NULL; int buf_idx; @@ -982,7 +984,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox) if (phys_buf == in_be32(&rmu->msg_regs->ifqepar)) goto out2; - virt_buf = (u32) rmu->msg_rx_ring.virt + (phys_buf + virt_buf = rmu->msg_rx_ring.virt + (phys_buf - rmu->msg_rx_ring.phys); buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; buf = rmu->msg_rx_ring.virt_buffer[buf_idx]; @@ -994,7 +996,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox) } /* Copy max message size, caller is expected to allocate that big */ - memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); + memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE); /* Clear the available buffer */ rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL; -- cgit v1.2.3 From b53804c70258000026d0b68b86aaecd571f2ba8b Mon Sep 17 00:00:00 2001 From: Liu Shuo Date: Thu, 8 Mar 2012 14:47:37 -0800 Subject: powerpc/fsl_msi: return proper error value when ioremap failed. Signed-off-by: Liu Shuo Acked-by: Timur Tabi Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_msi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index ecb5c1946d22..0bab15626ee2 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -410,6 +410,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) msi->msi_regs = ioremap(res.start, resource_size(&res)); if (!msi->msi_regs) { + err = -ENOMEM; dev_err(&dev->dev, "could not map node %s\n", dev->dev.of_node->full_name); goto error_out; -- cgit v1.2.3 From 44b24b74abc37e3c0f28c8288178056f10074863 Mon Sep 17 00:00:00 2001 From: Martyn Welch Date: Mon, 12 Mar 2012 17:12:59 +0000 Subject: powerpc: Move GE PIC drivers Move the GE PIC drivers to allow these to be used by non-86xx boards. Signed-off-by: Martyn Welch Signed-off-by: Kumar Gala --- arch/powerpc/platforms/86xx/Kconfig | 4 - arch/powerpc/platforms/86xx/Makefile | 1 - arch/powerpc/platforms/86xx/gef_pic.c | 252 ------------------------------- arch/powerpc/platforms/86xx/gef_pic.h | 11 -- arch/powerpc/platforms/86xx/gef_ppc9a.c | 2 +- arch/powerpc/platforms/86xx/gef_sbc310.c | 2 +- arch/powerpc/platforms/86xx/gef_sbc610.c | 2 +- arch/powerpc/sysdev/Kconfig | 4 + arch/powerpc/sysdev/Makefile | 2 + arch/powerpc/sysdev/ge/Makefile | 1 + arch/powerpc/sysdev/ge/ge_pic.c | 252 +++++++++++++++++++++++++++++++ arch/powerpc/sysdev/ge/ge_pic.h | 11 ++ 12 files changed, 273 insertions(+), 271 deletions(-) delete mode 100644 arch/powerpc/platforms/86xx/gef_pic.c delete mode 100644 arch/powerpc/platforms/86xx/gef_pic.h create mode 100644 arch/powerpc/sysdev/ge/Makefile create mode 100644 arch/powerpc/sysdev/ge/ge_pic.c create mode 100644 arch/powerpc/sysdev/ge/ge_pic.h (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index abe2c4fff811..7a6279e38213 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -64,10 +64,6 @@ config GEF_SBC610 help This option enables support for the GE SBC610. -config GE_FPGA - bool - default n - endif config MPC8641 diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 1ee6ca8e53f7..ede815d6489d 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o obj-$(CONFIG_SBC8641D) += sbc8641d.o obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o -obj-$(CONFIG_GE_FPGA) += gef_pic.o obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c deleted file mode 100644 index 94594e58594c..000000000000 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Interrupt handling for GE FPGA based PIC - * - * Author: Martyn Welch - * - * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "gef_pic.h" - -#define DEBUG -#undef DEBUG - -#ifdef DEBUG -#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0) -#else -#define DBG(fmt...) do { } while (0) -#endif - -#define GEF_PIC_NUM_IRQS 32 - -/* Interrupt Controller Interface Registers */ -#define GEF_PIC_INTR_STATUS 0x0000 - -#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu)) -#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0) -#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1) - -#define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu)) -#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0) -#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1) - - -static DEFINE_RAW_SPINLOCK(gef_pic_lock); - -static void __iomem *gef_pic_irq_reg_base; -static struct irq_host *gef_pic_irq_host; -static int gef_pic_cascade_irq; - -/* - * Interrupt Controller Handling - * - * The interrupt controller handles interrupts for most on board interrupts, - * apart from PCI interrupts. For example on SBC610: - * - * 17:31 RO Reserved - * 16 RO PCI Express Doorbell 3 Status - * 15 RO PCI Express Doorbell 2 Status - * 14 RO PCI Express Doorbell 1 Status - * 13 RO PCI Express Doorbell 0 Status - * 12 RO Real Time Clock Interrupt Status - * 11 RO Temperature Interrupt Status - * 10 RO Temperature Critical Interrupt Status - * 9 RO Ethernet PHY1 Interrupt Status - * 8 RO Ethernet PHY3 Interrupt Status - * 7 RO PEX8548 Interrupt Status - * 6 RO Reserved - * 5 RO Watchdog 0 Interrupt Status - * 4 RO Watchdog 1 Interrupt Status - * 3 RO AXIS Message FIFO A Interrupt Status - * 2 RO AXIS Message FIFO B Interrupt Status - * 1 RO AXIS Message FIFO C Interrupt Status - * 0 RO AXIS Message FIFO D Interrupt Status - * - * Interrupts can be forwarded to one of two output lines. Nothing - * clever is done, so if the masks are incorrectly set, a single input - * interrupt could generate interrupts on both output lines! - * - * The dual lines are there to allow the chained interrupts to be easily - * passed into two different cores. We currently do not use this functionality - * in this driver. - * - * Controller can also be configured to generate Machine checks (MCP), again on - * two lines, to be attached to two different cores. It is suggested that these - * should be masked out. - */ - -void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - unsigned int cascade_irq; - - /* - * See if we actually have an interrupt, call generic handling code if - * we do. - */ - cascade_irq = gef_pic_get_irq(); - - if (cascade_irq != NO_IRQ) - generic_handle_irq(cascade_irq); - - chip->irq_eoi(&desc->irq_data); -} - -static void gef_pic_mask(struct irq_data *d) -{ - unsigned long flags; - unsigned int hwirq = irqd_to_hwirq(d); - u32 mask; - - raw_spin_lock_irqsave(&gef_pic_lock, flags); - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); - mask &= ~(1 << hwirq); - out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); - raw_spin_unlock_irqrestore(&gef_pic_lock, flags); -} - -static void gef_pic_mask_ack(struct irq_data *d) -{ - /* Don't think we actually have to do anything to ack an interrupt, - * we just need to clear down the devices interrupt and it will go away - */ - gef_pic_mask(d); -} - -static void gef_pic_unmask(struct irq_data *d) -{ - unsigned long flags; - unsigned int hwirq = irqd_to_hwirq(d); - u32 mask; - - raw_spin_lock_irqsave(&gef_pic_lock, flags); - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); - mask |= (1 << hwirq); - out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); - raw_spin_unlock_irqrestore(&gef_pic_lock, flags); -} - -static struct irq_chip gef_pic_chip = { - .name = "gefp", - .irq_mask = gef_pic_mask, - .irq_mask_ack = gef_pic_mask_ack, - .irq_unmask = gef_pic_unmask, -}; - - -/* When an interrupt is being configured, this call allows some flexibilty - * in deciding which irq_chip structure is used - */ -static int gef_pic_host_map(struct irq_host *h, unsigned int virq, - irq_hw_number_t hwirq) -{ - /* All interrupts are LEVEL sensitive */ - irq_set_status_flags(virq, IRQ_LEVEL); - irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq); - - return 0; -} - -static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_flags) -{ - - *out_hwirq = intspec[0]; - if (intsize > 1) - *out_flags = intspec[1]; - else - *out_flags = IRQ_TYPE_LEVEL_HIGH; - - return 0; -} - -static struct irq_host_ops gef_pic_host_ops = { - .map = gef_pic_host_map, - .xlate = gef_pic_host_xlate, -}; - - -/* - * Initialisation of PIC, this should be called in BSP - */ -void __init gef_pic_init(struct device_node *np) -{ - unsigned long flags; - - /* Map the devices registers into memory */ - gef_pic_irq_reg_base = of_iomap(np, 0); - - raw_spin_lock_irqsave(&gef_pic_lock, flags); - - /* Initialise everything as masked. */ - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0); - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0); - - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0); - out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0); - - raw_spin_unlock_irqrestore(&gef_pic_lock, flags); - - /* Map controller */ - gef_pic_cascade_irq = irq_of_parse_and_map(np, 0); - if (gef_pic_cascade_irq == NO_IRQ) { - printk(KERN_ERR "SBC610: failed to map cascade interrupt"); - return; - } - - /* Setup an irq_host structure */ - gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, - GEF_PIC_NUM_IRQS, - &gef_pic_host_ops, NO_IRQ); - if (gef_pic_irq_host == NULL) - return; - - /* Chain with parent controller */ - irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade); -} - -/* - * This is called when we receive an interrupt with apparently comes from this - * chip - check, returning the highest interrupt generated or return NO_IRQ - */ -unsigned int gef_pic_get_irq(void) -{ - u32 cause, mask, active; - unsigned int virq = NO_IRQ; - int hwirq; - - cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS); - - mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); - - active = cause & mask; - - if (active) { - for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) { - if (active & (0x1 << hwirq)) - break; - } - virq = irq_linear_revmap(gef_pic_irq_host, - (irq_hw_number_t)hwirq); - } - - return virq; -} - diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/platforms/86xx/gef_pic.h deleted file mode 100644 index 6149916da3f4..000000000000 --- a/arch/powerpc/platforms/86xx/gef_pic.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __GEF_PIC_H__ -#define __GEF_PIC_H__ - -#include - -void gef_pic_cascade(unsigned int, struct irq_desc *); -unsigned int gef_pic_get_irq(void); -void gef_pic_init(struct device_node *); - -#endif /* __GEF_PIC_H__ */ - diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 60ce07e39100..ed58b6cfd60c 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -37,9 +37,9 @@ #include #include +#include #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index 3ecee25bf3ed..710db69bd523 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -37,9 +37,9 @@ #include #include +#include #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index 5090d608d9ee..4a13d2f4ac20 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -37,9 +37,9 @@ #include #include +#include #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 7b4df37ac381..a84fecf63c4d 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -29,3 +29,7 @@ config SCOM_DEBUGFS bool "Expose SCOM controllers via debugfs" depends on PPC_SCOM default n + +config GE_FPGA + bool + default n diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 5e37b4717864..f80ff9f5f441 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -65,3 +65,5 @@ obj-$(CONFIG_PPC_SCOM) += scom.o subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror obj-$(CONFIG_PPC_XICS) += xics/ + +obj-$(CONFIG_GE_FPGA) += ge/ diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile new file mode 100644 index 000000000000..8731ffcb79b9 --- /dev/null +++ b/arch/powerpc/sysdev/ge/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_GE_FPGA) += ge_pic.o diff --git a/arch/powerpc/sysdev/ge/ge_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c new file mode 100644 index 000000000000..002a56295e01 --- /dev/null +++ b/arch/powerpc/sysdev/ge/ge_pic.c @@ -0,0 +1,252 @@ +/* + * Interrupt handling for GE FPGA based PIC + * + * Author: Martyn Welch + * + * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ge_pic.h" + +#define DEBUG +#undef DEBUG + +#ifdef DEBUG +#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0) +#else +#define DBG(fmt...) do { } while (0) +#endif + +#define GEF_PIC_NUM_IRQS 32 + +/* Interrupt Controller Interface Registers */ +#define GEF_PIC_INTR_STATUS 0x0000 + +#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu)) +#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0) +#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1) + +#define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu)) +#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0) +#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1) + + +static DEFINE_RAW_SPINLOCK(gef_pic_lock); + +static void __iomem *gef_pic_irq_reg_base; +static struct irq_host *gef_pic_irq_host; +static int gef_pic_cascade_irq; + +/* + * Interrupt Controller Handling + * + * The interrupt controller handles interrupts for most on board interrupts, + * apart from PCI interrupts. For example on SBC610: + * + * 17:31 RO Reserved + * 16 RO PCI Express Doorbell 3 Status + * 15 RO PCI Express Doorbell 2 Status + * 14 RO PCI Express Doorbell 1 Status + * 13 RO PCI Express Doorbell 0 Status + * 12 RO Real Time Clock Interrupt Status + * 11 RO Temperature Interrupt Status + * 10 RO Temperature Critical Interrupt Status + * 9 RO Ethernet PHY1 Interrupt Status + * 8 RO Ethernet PHY3 Interrupt Status + * 7 RO PEX8548 Interrupt Status + * 6 RO Reserved + * 5 RO Watchdog 0 Interrupt Status + * 4 RO Watchdog 1 Interrupt Status + * 3 RO AXIS Message FIFO A Interrupt Status + * 2 RO AXIS Message FIFO B Interrupt Status + * 1 RO AXIS Message FIFO C Interrupt Status + * 0 RO AXIS Message FIFO D Interrupt Status + * + * Interrupts can be forwarded to one of two output lines. Nothing + * clever is done, so if the masks are incorrectly set, a single input + * interrupt could generate interrupts on both output lines! + * + * The dual lines are there to allow the chained interrupts to be easily + * passed into two different cores. We currently do not use this functionality + * in this driver. + * + * Controller can also be configured to generate Machine checks (MCP), again on + * two lines, to be attached to two different cores. It is suggested that these + * should be masked out. + */ + +void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int cascade_irq; + + /* + * See if we actually have an interrupt, call generic handling code if + * we do. + */ + cascade_irq = gef_pic_get_irq(); + + if (cascade_irq != NO_IRQ) + generic_handle_irq(cascade_irq); + + chip->irq_eoi(&desc->irq_data); +} + +static void gef_pic_mask(struct irq_data *d) +{ + unsigned long flags; + unsigned int hwirq = irqd_to_hwirq(d); + u32 mask; + + raw_spin_lock_irqsave(&gef_pic_lock, flags); + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); + mask &= ~(1 << hwirq); + out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); + raw_spin_unlock_irqrestore(&gef_pic_lock, flags); +} + +static void gef_pic_mask_ack(struct irq_data *d) +{ + /* Don't think we actually have to do anything to ack an interrupt, + * we just need to clear down the devices interrupt and it will go away + */ + gef_pic_mask(d); +} + +static void gef_pic_unmask(struct irq_data *d) +{ + unsigned long flags; + unsigned int hwirq = irqd_to_hwirq(d); + u32 mask; + + raw_spin_lock_irqsave(&gef_pic_lock, flags); + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); + mask |= (1 << hwirq); + out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); + raw_spin_unlock_irqrestore(&gef_pic_lock, flags); +} + +static struct irq_chip gef_pic_chip = { + .name = "gefp", + .irq_mask = gef_pic_mask, + .irq_mask_ack = gef_pic_mask_ack, + .irq_unmask = gef_pic_unmask, +}; + + +/* When an interrupt is being configured, this call allows some flexibilty + * in deciding which irq_chip structure is used + */ +static int gef_pic_host_map(struct irq_host *h, unsigned int virq, + irq_hw_number_t hwirq) +{ + /* All interrupts are LEVEL sensitive */ + irq_set_status_flags(virq, IRQ_LEVEL); + irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq); + + return 0; +} + +static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_flags) +{ + + *out_hwirq = intspec[0]; + if (intsize > 1) + *out_flags = intspec[1]; + else + *out_flags = IRQ_TYPE_LEVEL_HIGH; + + return 0; +} + +static struct irq_host_ops gef_pic_host_ops = { + .map = gef_pic_host_map, + .xlate = gef_pic_host_xlate, +}; + + +/* + * Initialisation of PIC, this should be called in BSP + */ +void __init gef_pic_init(struct device_node *np) +{ + unsigned long flags; + + /* Map the devices registers into memory */ + gef_pic_irq_reg_base = of_iomap(np, 0); + + raw_spin_lock_irqsave(&gef_pic_lock, flags); + + /* Initialise everything as masked. */ + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0); + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0); + + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0); + out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0); + + raw_spin_unlock_irqrestore(&gef_pic_lock, flags); + + /* Map controller */ + gef_pic_cascade_irq = irq_of_parse_and_map(np, 0); + if (gef_pic_cascade_irq == NO_IRQ) { + printk(KERN_ERR "SBC610: failed to map cascade interrupt"); + return; + } + + /* Setup an irq_host structure */ + gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, + GEF_PIC_NUM_IRQS, + &gef_pic_host_ops, NO_IRQ); + if (gef_pic_irq_host == NULL) + return; + + /* Chain with parent controller */ + irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade); +} + +/* + * This is called when we receive an interrupt with apparently comes from this + * chip - check, returning the highest interrupt generated or return NO_IRQ + */ +unsigned int gef_pic_get_irq(void) +{ + u32 cause, mask, active; + unsigned int virq = NO_IRQ; + int hwirq; + + cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS); + + mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); + + active = cause & mask; + + if (active) { + for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) { + if (active & (0x1 << hwirq)) + break; + } + virq = irq_linear_revmap(gef_pic_irq_host, + (irq_hw_number_t)hwirq); + } + + return virq; +} + diff --git a/arch/powerpc/sysdev/ge/ge_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h new file mode 100644 index 000000000000..6149916da3f4 --- /dev/null +++ b/arch/powerpc/sysdev/ge/ge_pic.h @@ -0,0 +1,11 @@ +#ifndef __GEF_PIC_H__ +#define __GEF_PIC_H__ + +#include + +void gef_pic_cascade(unsigned int, struct irq_desc *); +unsigned int gef_pic_get_irq(void); +void gef_pic_init(struct device_node *); + +#endif /* __GEF_PIC_H__ */ + -- cgit v1.2.3 From e4399461bdf4d230129c99f785ebe6814269427b Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 1 Feb 2012 19:05:15 +0200 Subject: powerpc/85xx: Fix compiler error with THIS_MODULE and related CC arch/powerpc/sysdev/fsl_85xx_l2ctlr.o arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:209:13: error: 'THIS_MODULE' undeclared here (not in a function) arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:229:20: error: expected declaration specifiers or '...' before string constant cc1: warnings being treated as errors arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:229:1: error: data definition has no type or storage class arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:229:1: error: type defaults to 'int' in declaration of 'MODULE_DESCRIPTION' arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:229:20: error: function declaration isn't a prototype arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:230:16: error: expected declaration specifiers or '...' before string constant arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:230:1: error: data definition has no type or storage class arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:230:1: error: type defaults to 'int' in declaration of 'MODULE_LICENSE' arch/powerpc/sysdev/fsl_85xx_l2ctlr.c:230:16: error: function declaration isn't a prototype make[1]: *** [arch/powerpc/sysdev/fsl_85xx_l2ctlr.o] Error 1 ... CC arch/powerpc/sysdev/fsl_85xx_cache_sram.o cc1: warnings being treated as errors arch/powerpc/sysdev/fsl_85xx_cache_sram.c:69:1: error: data definition has no type or storage class arch/powerpc/sysdev/fsl_85xx_cache_sram.c:69:1: error: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' arch/powerpc/sysdev/fsl_85xx_cache_sram.c:69:1: error: parameter names (without types) in function declaration arch/powerpc/sysdev/fsl_85xx_cache_sram.c:80:1: error: data definition has no type or storage class arch/powerpc/sysdev/fsl_85xx_cache_sram.c:80:1: error: type defaults to 'int' in declaration of 'EXPORT_SYMBOL' arch/powerpc/sysdev/fsl_85xx_cache_sram.c:80:1: error: parameter names (without types) in function declaration make[1]: *** [arch/powerpc/sysdev/fsl_85xx_cache_sram.o] Error 1 Signed-off-by: Claudiu Manoil Acked-by: Paul Gortmaker Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_85xx_cache_sram.c | 1 + arch/powerpc/sysdev/fsl_85xx_l2ctlr.c | 1 + 2 files changed, 2 insertions(+) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c index 116415899176..37a69097e022 100644 --- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c +++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c index 5f88797dce73..1957e532e18b 100644 --- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c +++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c @@ -21,6 +21,7 @@ */ #include +#include #include #include -- cgit v1.2.3 From 401a376e94021f2040e6cedd4cc858e0eeec5854 Mon Sep 17 00:00:00 2001 From: chenhui zhao Date: Wed, 22 Feb 2012 18:20:13 +0800 Subject: powerpc/85xx: l2sram - Add compatible entry for mpc8548 L2 controller Signed-off-by: Zhao Chenhui Signed-off-by: Li Yang Signed-off-by: Kumar Gala --- arch/powerpc/sysdev/fsl_85xx_l2ctlr.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c index 1957e532e18b..cedabd0f4bfe 100644 --- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c +++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c @@ -201,6 +201,9 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = { { .compatible = "fsl,p1022-l2-cache-controller", }, + { + .compatible = "fsl,mpc8548-l2-cache-controller", + }, {}, }; -- cgit v1.2.3 From 8626816e905e8e131663dfcae27d307df8c220d0 Mon Sep 17 00:00:00 2001 From: Jia Hongtao Date: Fri, 17 Feb 2012 10:49:03 +0800 Subject: powerpc: add support for MPIC message register API Some MPIC implementations contain one or more blocks of message registers that are used to send messages between cores via IPIs. A simple API has been added to access (get/put, read, write, etc ...) these message registers. The available message registers are initially discovered via nodes in the device tree. A separate commit contains a binding for the message register nodes. Signed-off-by: Meador Inge Signed-off-by: Jia Hongtao Signed-off-by: Li Yang Signed-off-by: Kumar Gala --- arch/powerpc/include/asm/mpic_msgr.h | 132 ++++++++++++++++ arch/powerpc/platforms/Kconfig | 8 + arch/powerpc/sysdev/Makefile | 2 + arch/powerpc/sysdev/mpic_msgr.c | 282 +++++++++++++++++++++++++++++++++++ 4 files changed, 424 insertions(+) create mode 100644 arch/powerpc/include/asm/mpic_msgr.h create mode 100644 arch/powerpc/sysdev/mpic_msgr.c (limited to 'arch/powerpc/sysdev') diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h new file mode 100644 index 000000000000..3ec37dc9003e --- /dev/null +++ b/arch/powerpc/include/asm/mpic_msgr.h @@ -0,0 +1,132 @@ +/* + * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 of the + * License. + * + */ + +#ifndef _ASM_MPIC_MSGR_H +#define _ASM_MPIC_MSGR_H + +#include +#include + +struct mpic_msgr { + u32 __iomem *base; + u32 __iomem *mer; + int irq; + unsigned char in_use; + raw_spinlock_t lock; + int num; +}; + +/* Get a message register + * + * @reg_num: the MPIC message register to get + * + * A pointer to the message register is returned. If + * the message register asked for is already in use, then + * EBUSY is returned. If the number given is not associated + * with an actual message register, then ENODEV is returned. + * Successfully getting the register marks it as in use. + */ +extern struct mpic_msgr *mpic_msgr_get(unsigned int reg_num); + +/* Relinquish a message register + * + * @msgr: the message register to return + * + * Disables the given message register and marks it as free. + * After this call has completed successully the message + * register is available to be acquired by a call to + * mpic_msgr_get. + */ +extern void mpic_msgr_put(struct mpic_msgr *msgr); + +/* Enable a message register + * + * @msgr: the message register to enable + * + * The given message register is enabled for sending + * messages. + */ +extern void mpic_msgr_enable(struct mpic_msgr *msgr); + +/* Disable a message register + * + * @msgr: the message register to disable + * + * The given message register is disabled for sending + * messages. + */ +extern void mpic_msgr_disable(struct mpic_msgr *msgr); + +/* Write a message to a message register + * + * @msgr: the message register to write to + * @message: the message to write + * + * The given 32-bit message is written to the given message + * register. Writing to an enabled message registers fires + * an interrupt. + */ +static inline void mpic_msgr_write(struct mpic_msgr *msgr, u32 message) +{ + out_be32(msgr->base, message); +} + +/* Read a message from a message register + * + * @msgr: the message register to read from + * + * Returns the 32-bit value currently in the given message register. + * Upon reading the register any interrupts for that register are + * cleared. + */ +static inline u32 mpic_msgr_read(struct mpic_msgr *msgr) +{ + return in_be32(msgr->base); +} + +/* Clear a message register + * + * @msgr: the message register to clear + * + * Clears any interrupts associated with the given message register. + */ +static inline void mpic_msgr_clear(struct mpic_msgr *msgr) +{ + (void) mpic_msgr_read(msgr); +} + +/* Set the destination CPU for the message register + * + * @msgr: the message register whose destination is to be set + * @cpu_num: the Linux CPU number to bind the message register to + * + * Note that the CPU number given is the CPU number used by the kernel + * and *not* the actual hardware CPU number. + */ +static inline void mpic_msgr_set_destination(struct mpic_msgr *msgr, + u32 cpu_num) +{ + out_be32(msgr->base, 1 << get_hard_smp_processor_id(cpu_num)); +} + +/* Get the IRQ number for the message register + * @msgr: the message register whose IRQ is to be returned + * + * Returns the IRQ number associated with the given message register. + * NO_IRQ is returned if this message register is not capable of + * receiving interrupts. What message register can and cannot receive + * interrupts is specified in the device tree for the system. + */ +static inline int mpic_msgr_get_irq(struct mpic_msgr *msgr) +{ + return msgr->irq; +} + +#endif diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 236ab67bc3a4..a35ca44ade66 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -86,6 +86,14 @@ config MPIC_WEIRD bool default n +config MPIC_MSGR + bool "MPIC message register support" + depends on MPIC + default n + help + Enables support for the MPIC message registers. These + registers are used for inter-processor communication. + config PPC_I8259 bool default n diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index f80ff9f5f441..1bd7ecb24620 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -4,6 +4,8 @@ ccflags-$(CONFIG_PPC64) := -mno-minimal-toc mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) +mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o +obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y) obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c new file mode 100644 index 000000000000..6e7fa386e76a --- /dev/null +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -0,0 +1,282 @@ +/* + * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. + * + * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and + * Mingkai Hu from Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 of the + * License. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MPIC_MSGR_REGISTERS_PER_BLOCK 4 +#define MPIC_MSGR_STRIDE 0x10 +#define MPIC_MSGR_MER_OFFSET 0x100 +#define MSGR_INUSE 0 +#define MSGR_FREE 1 + +static struct mpic_msgr **mpic_msgrs; +static unsigned int mpic_msgr_count; + +static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value) +{ + out_be32(msgr->mer, value); +} + +static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr) +{ + return in_be32(msgr->mer); +} + +static inline void _mpic_msgr_disable(struct mpic_msgr *msgr) +{ + u32 mer = _mpic_msgr_mer_read(msgr); + + _mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num)); +} + +struct mpic_msgr *mpic_msgr_get(unsigned int reg_num) +{ + unsigned long flags; + struct mpic_msgr *msgr; + + /* Assume busy until proven otherwise. */ + msgr = ERR_PTR(-EBUSY); + + if (reg_num >= mpic_msgr_count) + return ERR_PTR(-ENODEV); + + raw_spin_lock_irqsave(&msgr->lock, flags); + if (mpic_msgrs[reg_num]->in_use == MSGR_FREE) { + msgr = mpic_msgrs[reg_num]; + msgr->in_use = MSGR_INUSE; + } + raw_spin_unlock_irqrestore(&msgr->lock, flags); + + return msgr; +} +EXPORT_SYMBOL_GPL(mpic_msgr_get); + +void mpic_msgr_put(struct mpic_msgr *msgr) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&msgr->lock, flags); + msgr->in_use = MSGR_FREE; + _mpic_msgr_disable(msgr); + raw_spin_unlock_irqrestore(&msgr->lock, flags); +} +EXPORT_SYMBOL_GPL(mpic_msgr_put); + +void mpic_msgr_enable(struct mpic_msgr *msgr) +{ + unsigned long flags; + u32 mer; + + raw_spin_lock_irqsave(&msgr->lock, flags); + mer = _mpic_msgr_mer_read(msgr); + _mpic_msgr_mer_write(msgr, mer | (1 << msgr->num)); + raw_spin_unlock_irqrestore(&msgr->lock, flags); +} +EXPORT_SYMBOL_GPL(mpic_msgr_enable); + +void mpic_msgr_disable(struct mpic_msgr *msgr) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&msgr->lock, flags); + _mpic_msgr_disable(msgr); + raw_spin_unlock_irqrestore(&msgr->lock, flags); +} +EXPORT_SYMBOL_GPL(mpic_msgr_disable); + +/* The following three functions are used to compute the order and number of + * the message register blocks. They are clearly very inefficent. However, + * they are called *only* a few times during device initialization. + */ +static unsigned int mpic_msgr_number_of_blocks(void) +{ + unsigned int count; + struct device_node *aliases; + + count = 0; + aliases = of_find_node_by_name(NULL, "aliases"); + + if (aliases) { + char buf[32]; + + for (;;) { + snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count); + if (!of_find_property(aliases, buf, NULL)) + break; + + count += 1; + } + } + + return count; +} + +static unsigned int mpic_msgr_number_of_registers(void) +{ + return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK; +} + +static int mpic_msgr_block_number(struct device_node *node) +{ + struct device_node *aliases; + unsigned int index, number_of_blocks; + char buf[64]; + + number_of_blocks = mpic_msgr_number_of_blocks(); + aliases = of_find_node_by_name(NULL, "aliases"); + if (!aliases) + return -1; + + for (index = 0; index < number_of_blocks; ++index) { + struct property *prop; + + snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index); + prop = of_find_property(aliases, buf, NULL); + if (node == of_find_node_by_path(prop->value)) + break; + } + + return index == number_of_blocks ? -1 : index; +} + +/* The probe function for a single message register block. + */ +static __devinit int mpic_msgr_probe(struct platform_device *dev) +{ + void __iomem *msgr_block_addr; + int block_number; + struct resource rsrc; + unsigned int i; + unsigned int irq_index; + struct device_node *np = dev->dev.of_node; + unsigned int receive_mask; + const unsigned int *prop; + + if (!np) { + dev_err(&dev->dev, "Device OF-Node is NULL"); + return -EFAULT; + } + + /* Allocate the message register array upon the first device + * registered. + */ + if (!mpic_msgrs) { + mpic_msgr_count = mpic_msgr_number_of_registers(); + dev_info(&dev->dev, "Found %d message registers\n", + mpic_msgr_count); + + mpic_msgrs = kzalloc(sizeof(struct mpic_msgr) * mpic_msgr_count, + GFP_KERNEL); + if (!mpic_msgrs) { + dev_err(&dev->dev, + "No memory for message register blocks\n"); + return -ENOMEM; + } + } + dev_info(&dev->dev, "Of-device full name %s\n", np->full_name); + + /* IO map the message register block. */ + of_address_to_resource(np, 0, &rsrc); + msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start); + if (!msgr_block_addr) { + dev_err(&dev->dev, "Failed to iomap MPIC message registers"); + return -EFAULT; + } + + /* Ensure the block has a defined order. */ + block_number = mpic_msgr_block_number(np); + if (block_number < 0) { + dev_err(&dev->dev, + "Failed to find message register block alias\n"); + return -ENODEV; + } + dev_info(&dev->dev, "Setting up message register block %d\n", + block_number); + + /* Grab the receive mask which specifies what registers can receive + * interrupts. + */ + prop = of_get_property(np, "mpic-msgr-receive-mask", NULL); + receive_mask = (prop) ? *prop : 0xF; + + /* Build up the appropriate message register data structures. */ + for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) { + struct mpic_msgr *msgr; + unsigned int reg_number; + + msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL); + if (!msgr) { + dev_err(&dev->dev, "No memory for message register\n"); + return -ENOMEM; + } + + reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i; + msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE; + msgr->mer = msgr->base + MPIC_MSGR_MER_OFFSET; + msgr->in_use = MSGR_FREE; + msgr->num = i; + raw_spin_lock_init(&msgr->lock); + + if (receive_mask & (1 << i)) { + struct resource irq; + + if (of_irq_to_resource(np, irq_index, &irq) == NO_IRQ) { + dev_err(&dev->dev, + "Missing interrupt specifier"); + kfree(msgr); + return -EFAULT; + } + msgr->irq = irq.start; + irq_index += 1; + } else { + msgr->irq = NO_IRQ; + } + + mpic_msgrs[reg_number] = msgr; + mpic_msgr_disable(msgr); + dev_info(&dev->dev, "Register %d initialized: irq %d\n", + reg_number, msgr->irq); + + } + + return 0; +} + +static const struct of_device_id mpic_msgr_ids[] = { + { + .compatible = "fsl,mpic-v3.1-msgr", + .data = NULL, + }, + {} +}; + +static struct platform_driver mpic_msgr_driver = { + .driver = { + .name = "mpic-msgr", + .owner = THIS_MODULE, + .of_match_table = mpic_msgr_ids, + }, + .probe = mpic_msgr_probe, +}; + +static __init int mpic_msgr_init(void) +{ + return platform_driver_register(&mpic_msgr_driver); +} +subsys_initcall(mpic_msgr_init); -- cgit v1.2.3