diff options
author | Liu Gang <Gang.Liu@freescale.com> | 2011-11-12 20:02:29 +0800 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2011-11-24 02:01:34 -0600 |
commit | abc3aeae3aaa5c319d02f12649e17ea5929999aa (patch) | |
tree | 1eb64b3c01ce6ae488c9f5f0460b602d654b5a2a /arch/powerpc/sysdev/fsl_rmu.c | |
parent | 6ec4bedbf153a8ef71aeba99a40efef556b57798 (diff) |
fsl-rio: Add two ports and rapidio message units support
Usually, freescale rapidio endpoint can support one or two 1x or 4X
LP-Serial link interfaces, and rapidio message transactions can be
implemented by two message units. This adds the support of two
rapidio ports and initializes message unit 0 and message unit 1. And
these ports and message units can work simultaneously.
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jin Qing <b24347@freescale.com>
Signed-off-by: Liu Gang <Gang.Liu@freescale.com>
Acked-by: Alexandre Bounine <alexandre.bounine@idt.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/sysdev/fsl_rmu.c')
-rw-r--r-- | arch/powerpc/sysdev/fsl_rmu.c | 502 |
1 files changed, 221 insertions, 281 deletions
diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c index 0a3e6cff1837..02445a51949d 100644 --- a/arch/powerpc/sysdev/fsl_rmu.c +++ b/arch/powerpc/sysdev/fsl_rmu.c @@ -36,8 +36,8 @@ (((struct rio_priv *)(mport->priv))->rmm_handle) /* RapidIO definition irq, which read from OF-tree */ -#define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq) -#define IRQ_RIO_BELL(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->bellirq) +#define IRQ_RIO_PW(m) (((struct fsl_rio_pw *)(m))->pwirq) +#define IRQ_RIO_BELL(m) (((struct fsl_rio_dbell *)(m))->bellirq) #define IRQ_RIO_TX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->txirq) #define IRQ_RIO_RX(m) (((struct fsl_rmu *)(GET_RMM_HANDLE(m)))->rxirq) @@ -73,13 +73,10 @@ #define LTLEECSR_ENABLE_ALL 0xFFC000FC #define RIO_LTLEECSR 0x060c -#define RIO_IM0SR 0x13064 -#define RIO_IM1SR 0x13164 -#define RIO_OM0SR 0x13004 -#define RIO_OM1SR 0x13104 - -#define RIO_P_MSG_REGS_OFFSET 0x11000 -#define RIO_S_MSG_REGS_OFFSET 0x13000 +#define RIO_IM0SR 0x64 +#define RIO_IM1SR 0x164 +#define RIO_OM0SR 0x4 +#define RIO_OM1SR 0x104 #define RIO_DBELL_WIN_SIZE 0x1000 @@ -113,75 +110,60 @@ #define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) struct rio_msg_regs { - u32 omr; /* 0xD_3000 - Outbound message 0 mode register */ - u32 osr; /* 0xD_3004 - Outbound message 0 status register */ + u32 omr; + u32 osr; u32 pad1; - u32 odqdpar; /* 0xD_300C - Outbound message 0 descriptor queue - dequeue pointer address register */ + u32 odqdpar; u32 pad2; - u32 osar; /* 0xD_3014 - Outbound message 0 source address - register */ - u32 odpr; /* 0xD_3018 - Outbound message 0 destination port - register */ - u32 odatr; /* 0xD_301C - Outbound message 0 destination attributes - Register*/ - u32 odcr; /* 0xD_3020 - Outbound message 0 double-word count - register */ + u32 osar; + u32 odpr; + u32 odatr; + u32 odcr; u32 pad3; - u32 odqepar; /* 0xD_3028 - Outbound message 0 descriptor queue - enqueue pointer address register */ + u32 odqepar; u32 pad4[13]; - u32 imr; /* 0xD_3060 - Inbound message 0 mode register */ - u32 isr; /* 0xD_3064 - Inbound message 0 status register */ + u32 imr; + u32 isr; u32 pad5; - u32 ifqdpar; /* 0xD_306C - Inbound message 0 frame queue dequeue - pointer address register*/ + u32 ifqdpar; u32 pad6; - u32 ifqepar; /* 0xD_3074 - Inbound message 0 frame queue enqueue - pointer address register */ - u32 pad7[226]; - u32 odmr; /* 0xD_3400 - Outbound doorbell mode register */ - u32 odsr; /* 0xD_3404 - Outbound doorbell status register */ - u32 res0[4]; - u32 oddpr; /* 0xD_3418 - Outbound doorbell destination port - register */ - u32 oddatr; /* 0xD_341c - Outbound doorbell destination attributes - register */ - u32 res1[3]; - u32 odretcr; /* 0xD_342C - Outbound doorbell retry error threshold - configuration register */ - u32 res2[12]; - u32 dmr; /* 0xD_3460 - Inbound doorbell mode register */ - u32 dsr; /* 0xD_3464 - Inbound doorbell status register */ - u32 pad8; - u32 dqdpar; /* 0xD_346C - Inbound doorbell queue dequeue Pointer - address register */ - u32 pad9; - u32 dqepar; /* 0xD_3474 - Inbound doorbell Queue enqueue pointer - address register */ - u32 pad10[26]; - u32 pwmr; /* 0xD_34E0 - Inbound port-write mode register */ - u32 pwsr; /* 0xD_34E4 - Inbound port-write status register */ - u32 epwqbar; /* 0xD_34E8 - Extended Port-Write Queue Base Address - register */ - u32 pwqbar; /* 0xD_34EC - Inbound port-write queue base address - register */ + u32 ifqepar; +}; + +struct rio_dbell_regs { + u32 odmr; + u32 odsr; + u32 pad1[4]; + u32 oddpr; + u32 oddatr; + u32 pad2[3]; + u32 odretcr; + u32 pad3[12]; + u32 dmr; + u32 dsr; + u32 pad4; + u32 dqdpar; + u32 pad5; + u32 dqepar; +}; + +struct rio_pw_regs { + u32 pwmr; + u32 pwsr; + u32 epwqbar; + u32 pwqbar; }; + struct rio_tx_desc { - u32 res1; + u32 pad1; u32 saddr; u32 dport; u32 dattr; - u32 res2; - u32 res3; + u32 pad2; + u32 pad3; u32 dwcnt; - u32 res4; -}; - -struct rio_dbell_ring { - void *virt; - dma_addr_t phys; + u32 pad4; }; struct rio_msg_tx_ring { @@ -204,13 +186,9 @@ struct rio_msg_rx_ring { }; struct fsl_rmu { - struct rio_atmu_regs __iomem *dbell_atmu_regs; - void __iomem *dbell_win; struct rio_msg_regs __iomem *msg_regs; - struct rio_dbell_ring dbell_ring; struct rio_msg_tx_ring msg_tx_ring; struct rio_msg_rx_ring msg_rx_ring; - int bellirq; int txirq; int rxirq; }; @@ -247,9 +225,11 @@ fsl_rio_tx_handler(int irq, void *dev_instance) if (osr & RIO_MSG_OSR_EOMI) { u32 dqp = in_be32(&rmu->msg_regs->odqdpar); int slot = (dqp - rmu->msg_tx_ring.phys) >> 5; - port->outb_msg[0].mcback(port, rmu->msg_tx_ring.dev_id, -1, - slot); - + if (port->outb_msg[0].mcback != NULL) { + port->outb_msg[0].mcback(port, rmu->msg_tx_ring.dev_id, + -1, + slot); + } /* Ack the end-of-message interrupt */ out_be32(&rmu->msg_regs->osr, RIO_MSG_OSR_EOMI); } @@ -284,12 +264,14 @@ fsl_rio_rx_handler(int irq, void *dev_instance) /* XXX Need to check/dispatch until queue empty */ if (isr & RIO_MSG_ISR_DIQI) { /* - * We implement *only* mailbox 0, but can receive messages - * for any mailbox/letter to that mailbox destination. So, - * make the callback with an unknown/invalid mailbox number - * argument. - */ - port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id, -1, -1); + * Can receive messages for any mailbox/letter to that + * mailbox destination. So, make the callback with an + * unknown/invalid mailbox number argument. + */ + if (port->inb_msg[0].mcback != NULL) + port->inb_msg[0].mcback(port, rmu->msg_rx_ring.dev_id, + -1, + -1); /* Ack the queueing interrupt */ out_be32(&rmu->msg_regs->isr, RIO_MSG_ISR_DIQI); @@ -311,27 +293,27 @@ static irqreturn_t fsl_rio_dbell_handler(int irq, void *dev_instance) { int dsr; - struct rio_mport *port = (struct rio_mport *)dev_instance; - struct fsl_rmu *rmu = GET_RMM_HANDLE(port); + struct fsl_rio_dbell *fsl_dbell = (struct fsl_rio_dbell *)dev_instance; + int i; - dsr = in_be32(&rmu->msg_regs->dsr); + dsr = in_be32(&fsl_dbell->dbell_regs->dsr); if (dsr & DOORBELL_DSR_TE) { pr_info("RIO: doorbell reception error\n"); - out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_TE); + out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_TE); goto out; } if (dsr & DOORBELL_DSR_QFI) { pr_info("RIO: doorbell queue full\n"); - out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_QFI); + out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_QFI); } /* XXX Need to check/dispatch until queue empty */ if (dsr & DOORBELL_DSR_DIQI) { u32 dmsg = - (u32) rmu->dbell_ring.virt + - (in_be32(&rmu->msg_regs->dqdpar) & 0xfff); + (u32) fsl_dbell->dbell_ring.virt + + (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); struct rio_dbell *dbell; int found = 0; @@ -340,48 +322,58 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) " sid %2.2x tid %2.2x info %4.4x\n", DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); - list_for_each_entry(dbell, &port->dbells, node) { - if ((dbell->res->start <= DBELL_INF(dmsg)) && - (dbell->res->end >= DBELL_INF(dmsg))) { - found = 1; - break; + 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)) + && (dbell->res->end + >= DBELL_INF(dmsg))) { + 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)); + break; + } } } - if (found) { - dbell->dinb(port, dbell->dev_id, - DBELL_SID(dmsg), - DBELL_TID(dmsg), DBELL_INF(dmsg)); - } else { + + if (!found) { pr_debug ("RIO: spurious doorbell," " sid %2.2x tid %2.2x info %4.4x\n", DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); } - setbits32(&rmu->msg_regs->dmr, DOORBELL_DMR_DI); - out_be32(&rmu->msg_regs->dsr, DOORBELL_DSR_DIQI); + setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI); + out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI); } out: return IRQ_HANDLED; } -void msg_unit_error_handler(struct rio_mport *port) +void msg_unit_error_handler(void) { - struct fsl_rmu *rmu = GET_RMM_HANDLE(port); /*XXX: Error recovery is not implemented, we just clear errors */ out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); - out_be32((u32 *)(rio_regs_win + RIO_IM0SR), IMSR_CLEAR); - out_be32((u32 *)(rio_regs_win + RIO_IM1SR), IMSR_CLEAR); - out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR); - out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR); + out_be32((u32 *)(rmu_regs_win + RIO_IM0SR), IMSR_CLEAR); + out_be32((u32 *)(rmu_regs_win + RIO_IM1SR), IMSR_CLEAR); + out_be32((u32 *)(rmu_regs_win + RIO_OM0SR), OMSR_CLEAR); + out_be32((u32 *)(rmu_regs_win + RIO_OM1SR), OMSR_CLEAR); - out_be32(&rmu->msg_regs->odsr, ODSR_CLEAR); - out_be32(&rmu->msg_regs->dsr, IDSR_CLEAR); + out_be32(&dbell->dbell_regs->odsr, ODSR_CLEAR); + out_be32(&dbell->dbell_regs->dsr, IDSR_CLEAR); - out_be32(&rmu->msg_regs->pwsr, IPWSR_CLEAR); + out_be32(&pw->pw_regs->pwsr, IPWSR_CLEAR); } /** @@ -396,18 +388,15 @@ static irqreturn_t fsl_rio_port_write_handler(int irq, void *dev_instance) { u32 ipwmr, ipwsr; - struct rio_mport *port = (struct rio_mport *)dev_instance; - struct rio_priv *priv = port->priv; - struct fsl_rmu *rmu; + struct fsl_rio_pw *pw = (struct fsl_rio_pw *)dev_instance; u32 epwisr, tmp; - rmu = GET_RMM_HANDLE(port); - epwisr = in_be32(priv->regs_win + RIO_EPWISR); + epwisr = in_be32(rio_regs_win + RIO_EPWISR); if (!(epwisr & RIO_EPWISR_PW)) goto pw_done; - ipwmr = in_be32(&rmu->msg_regs->pwmr); - ipwsr = in_be32(&rmu->msg_regs->pwsr); + ipwmr = in_be32(&pw->pw_regs->pwmr); + ipwsr = in_be32(&pw->pw_regs->pwsr); #ifdef DEBUG_PW pr_debug("PW Int->IPWMR: 0x%08x IPWSR: 0x%08x (", ipwmr, ipwsr); @@ -428,60 +417,60 @@ fsl_rio_port_write_handler(int irq, void *dev_instance) /* Save PW message (if there is room in FIFO), * otherwise discard it. */ - if (kfifo_avail(&priv->pw_fifo) >= RIO_PW_MSG_SIZE) { - priv->port_write_msg.msg_count++; - kfifo_in(&priv->pw_fifo, priv->port_write_msg.virt, + if (kfifo_avail(&pw->pw_fifo) >= RIO_PW_MSG_SIZE) { + pw->port_write_msg.msg_count++; + kfifo_in(&pw->pw_fifo, pw->port_write_msg.virt, RIO_PW_MSG_SIZE); } else { - priv->port_write_msg.discard_count++; + pw->port_write_msg.discard_count++; pr_debug("RIO: ISR Discarded Port-Write Msg(s) (%d)\n", - priv->port_write_msg.discard_count); + pw->port_write_msg.discard_count); } /* Clear interrupt and issue Clear Queue command. This allows * another port-write to be received. */ - out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_QFI); - out_be32(&rmu->msg_regs->pwmr, ipwmr | RIO_IPWMR_CQ); + out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_QFI); + out_be32(&pw->pw_regs->pwmr, ipwmr | RIO_IPWMR_CQ); - schedule_work(&priv->pw_work); + schedule_work(&pw->pw_work); } if ((ipwmr & RIO_IPWMR_EIE) && (ipwsr & RIO_IPWSR_TE)) { - priv->port_write_msg.err_count++; + pw->port_write_msg.err_count++; pr_debug("RIO: Port-Write Transaction Err (%d)\n", - priv->port_write_msg.err_count); + pw->port_write_msg.err_count); /* Clear Transaction Error: port-write controller should be * disabled when clearing this error */ - out_be32(&rmu->msg_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE); - out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_TE); - out_be32(&rmu->msg_regs->pwmr, ipwmr); + out_be32(&pw->pw_regs->pwmr, ipwmr & ~RIO_IPWMR_PWE); + out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_TE); + out_be32(&pw->pw_regs->pwmr, ipwmr); } if (ipwsr & RIO_IPWSR_PWD) { - priv->port_write_msg.discard_count++; + pw->port_write_msg.discard_count++; pr_debug("RIO: Port Discarded Port-Write Msg(s) (%d)\n", - priv->port_write_msg.discard_count); - out_be32(&rmu->msg_regs->pwsr, RIO_IPWSR_PWD); + pw->port_write_msg.discard_count); + out_be32(&pw->pw_regs->pwsr, RIO_IPWSR_PWD); } pw_done: if (epwisr & RIO_EPWISR_PINT1) { - tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); + tmp = in_be32(rio_regs_win + RIO_LTLEDCSR); pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); - fsl_rio_port_error_handler(port, 0); + fsl_rio_port_error_handler(0); } if (epwisr & RIO_EPWISR_PINT2) { - tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); + tmp = in_be32(rio_regs_win + RIO_LTLEDCSR); pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); - fsl_rio_port_error_handler(port, 1); + fsl_rio_port_error_handler(1); } if (epwisr & RIO_EPWISR_MU) { - tmp = in_be32(priv->regs_win + RIO_LTLEDCSR); + tmp = in_be32(rio_regs_win + RIO_LTLEDCSR); pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp); - msg_unit_error_handler(port); + msg_unit_error_handler(); } return IRQ_HANDLED; @@ -489,18 +478,15 @@ pw_done: static void fsl_pw_dpc(struct work_struct *work) { - struct rio_priv *priv = container_of(work, struct rio_priv, pw_work); - unsigned long flags; + struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work); u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)]; /* * Process port-write messages */ - spin_lock_irqsave(&priv->pw_fifo_lock, flags); - while (kfifo_out(&priv->pw_fifo, (unsigned char *)msg_buffer, - RIO_PW_MSG_SIZE)) { + while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)msg_buffer, + RIO_PW_MSG_SIZE, &pw->pw_fifo_lock)) { /* Process one message */ - spin_unlock_irqrestore(&priv->pw_fifo_lock, flags); #ifdef DEBUG_PW { u32 i; @@ -517,31 +503,26 @@ static void fsl_pw_dpc(struct work_struct *work) #endif /* Pass the port-write message to RIO core for processing */ rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer); - spin_lock_irqsave(&priv->pw_fifo_lock, flags); } - spin_unlock_irqrestore(&priv->pw_fifo_lock, flags); } /** * fsl_rio_pw_enable - enable/disable port-write interface init * @mport: Master port implementing the port write unit - * @enable: 1=enable; 0=disable port-write message handling + * @enable: 1=enable; 0=disable port-write message handling */ int fsl_rio_pw_enable(struct rio_mport *mport, int enable) { - struct fsl_rmu *rmu; u32 rval; - rmu = GET_RMM_HANDLE(mport); - - rval = in_be32(&rmu->msg_regs->pwmr); + rval = in_be32(&pw->pw_regs->pwmr); if (enable) rval |= RIO_IPWMR_PWE; else rval &= ~RIO_IPWMR_PWE; - out_be32(&rmu->msg_regs->pwmr, rval); + out_be32(&pw->pw_regs->pwmr, rval); return 0; } @@ -555,51 +536,47 @@ int fsl_rio_pw_enable(struct rio_mport *mport, int enable) * or %-ENOMEM on failure. */ -int fsl_rio_port_write_init(struct rio_mport *mport) +int fsl_rio_port_write_init(struct fsl_rio_pw *pw) { - struct rio_priv *priv = mport->priv; - struct fsl_rmu *rmu; int rc = 0; - rmu = GET_RMM_HANDLE(mport); - /* Following configurations require a disabled port write controller */ - out_be32(&rmu->msg_regs->pwmr, - in_be32(&rmu->msg_regs->pwmr) & ~RIO_IPWMR_PWE); + out_be32(&pw->pw_regs->pwmr, + in_be32(&pw->pw_regs->pwmr) & ~RIO_IPWMR_PWE); /* Initialize port write */ - priv->port_write_msg.virt = dma_alloc_coherent(priv->dev, + pw->port_write_msg.virt = dma_alloc_coherent(pw->dev, RIO_PW_MSG_SIZE, - &priv->port_write_msg.phys, GFP_KERNEL); - if (!priv->port_write_msg.virt) { + &pw->port_write_msg.phys, GFP_KERNEL); + if (!pw->port_write_msg.virt) { pr_err("RIO: unable allocate port write queue\n"); return -ENOMEM; } - priv->port_write_msg.err_count = 0; - priv->port_write_msg.discard_count = 0; + pw->port_write_msg.err_count = 0; + pw->port_write_msg.discard_count = 0; /* Point dequeue/enqueue pointers at first entry */ - out_be32(&rmu->msg_regs->epwqbar, 0); - out_be32(&rmu->msg_regs->pwqbar, (u32) priv->port_write_msg.phys); + out_be32(&pw->pw_regs->epwqbar, 0); + out_be32(&pw->pw_regs->pwqbar, (u32) pw->port_write_msg.phys); pr_debug("EIPWQBAR: 0x%08x IPWQBAR: 0x%08x\n", - in_be32(&rmu->msg_regs->epwqbar), - in_be32(&rmu->msg_regs->pwqbar)); + in_be32(&pw->pw_regs->epwqbar), + in_be32(&pw->pw_regs->pwqbar)); /* Clear interrupt status IPWSR */ - out_be32(&rmu->msg_regs->pwsr, + out_be32(&pw->pw_regs->pwsr, (RIO_IPWSR_TE | RIO_IPWSR_QFI | RIO_IPWSR_PWD)); /* Configure port write contoller for snooping enable all reporting, clear queue full */ - out_be32(&rmu->msg_regs->pwmr, + out_be32(&pw->pw_regs->pwmr, RIO_IPWMR_SEN | RIO_IPWMR_QFIE | RIO_IPWMR_EIE | RIO_IPWMR_CQ); /* Hook up port-write handler */ - rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, - IRQF_SHARED, "port-write", (void *)mport); + rc = request_irq(IRQ_RIO_PW(pw), fsl_rio_port_write_handler, + IRQF_SHARED, "port-write", (void *)pw); if (rc < 0) { pr_err("MPC85xx RIO: unable to request inbound doorbell irq"); goto err_out; @@ -607,26 +584,26 @@ int fsl_rio_port_write_init(struct rio_mport *mport) /* Enable Error Interrupt */ out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL); - INIT_WORK(&priv->pw_work, fsl_pw_dpc); - spin_lock_init(&priv->pw_fifo_lock); - if (kfifo_alloc(&priv->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) { + INIT_WORK(&pw->pw_work, fsl_pw_dpc); + spin_lock_init(&pw->pw_fifo_lock); + if (kfifo_alloc(&pw->pw_fifo, RIO_PW_MSG_SIZE * 32, GFP_KERNEL)) { pr_err("FIFO allocation failed\n"); rc = -ENOMEM; goto err_out_irq; } pr_debug("IPWMR: 0x%08x IPWSR: 0x%08x\n", - in_be32(&rmu->msg_regs->pwmr), - in_be32(&rmu->msg_regs->pwsr)); + in_be32(&pw->pw_regs->pwmr), + in_be32(&pw->pw_regs->pwsr)); return rc; err_out_irq: - free_irq(IRQ_RIO_PW(mport), (void *)mport); + free_irq(IRQ_RIO_PW(pw), (void *)pw); err_out: - dma_free_coherent(priv->dev, RIO_PW_MSG_SIZE, - priv->port_write_msg.virt, - priv->port_write_msg.phys); + dma_free_coherent(pw->dev, RIO_PW_MSG_SIZE, + pw->port_write_msg.virt, + pw->port_write_msg.phys); return rc; } @@ -640,29 +617,20 @@ err_out: * Sends a MPC85xx doorbell message. Returns %0 on success or * %-EINVAL on failure. */ -static int fsl_rio_doorbell_send(struct rio_mport *mport, +int fsl_rio_doorbell_send(struct rio_mport *mport, int index, u16 destid, u16 data) { - struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); - pr_debug("fsl_doorbell_send: index %d destid %4.4x data %4.4x\n", index, destid, data); - switch (mport->phy_type) { - case RIO_PHY_PARALLEL: - out_be32(&rmu->dbell_atmu_regs->rowtar, destid << 22); - out_be16(rmu->dbell_win, data); - break; - case RIO_PHY_SERIAL: - /* In the serial version silicons, such as MPC8548, MPC8641, - * below operations is must be. - */ - out_be32(&rmu->msg_regs->odmr, 0x00000000); - out_be32(&rmu->msg_regs->odretcr, 0x00000004); - out_be32(&rmu->msg_regs->oddpr, destid << 16); - out_be32(&rmu->msg_regs->oddatr, data); - out_be32(&rmu->msg_regs->odmr, 0x00000001); - break; - } + + /* In the serial version silicons, such as MPC8548, MPC8641, + * below operations is must be. + */ + out_be32(&dbell->dbell_regs->odmr, 0x00000000); + out_be32(&dbell->dbell_regs->odretcr, 0x00000004); + out_be32(&dbell->dbell_regs->oddpr, destid << 16); + out_be32(&dbell->dbell_regs->oddatr, (index << 20) | data); + out_be32(&dbell->dbell_regs->odmr, 0x00000001); return 0; } @@ -678,7 +646,7 @@ static int fsl_rio_doorbell_send(struct rio_mport *mport, * Adds the @buffer message to the MPC85xx outbound message queue. Returns * %0 on success or %-EINVAL on failure. */ -static int +int fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, void *buffer, size_t len) { @@ -690,7 +658,6 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, 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); - if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { ret = -EINVAL; goto out; @@ -703,22 +670,11 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, memset(rmu->msg_tx_ring.virt_buffer[rmu->msg_tx_ring.tx_slot] + len, 0, RIO_MAX_MSG_SIZE - len); - switch (mport->phy_type) { - case RIO_PHY_PARALLEL: - /* Set mbox field for message */ - desc->dport = mbox & 0x3; - - /* Enable EOMI interrupt, set priority, and set destid */ - desc->dattr = 0x28000000 | (rdev->destid << 2); - break; - case RIO_PHY_SERIAL: - /* Set mbox field for message, and set destid */ - desc->dport = (rdev->destid << 16) | (mbox & 0x3); - - /* Enable EOMI interrupt and priority */ - desc->dattr = 0x28000000; - break; - } + /* Set mbox field for message, and set destid */ + desc->dport = (rdev->destid << 16) | (mbox & 0x3); + + /* Enable EOMI interrupt and priority */ + desc->dattr = 0x28000000 | ((mport->index) << 20); /* Set transfer size aligned to next power of 2 (in double words) */ desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len); @@ -750,7 +706,7 @@ out: * and enables the outbound message unit. Returns %0 on success and * %-EINVAL or %-ENOMEM on failure. */ -static int +int fsl_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) { int i, j, rc = 0; @@ -855,7 +811,7 @@ out_dma: * Disables the outbound message unit, free all buffers, and * frees the outbound message interrupt. */ -static void fsl_close_outb_mbox(struct rio_mport *mport, int mbox) +void fsl_close_outb_mbox(struct rio_mport *mport, int mbox) { struct rio_priv *priv = mport->priv; struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); @@ -883,7 +839,7 @@ static void fsl_close_outb_mbox(struct rio_mport *mport, int mbox) * and enables the inbound message unit. Returns %0 on success * and %-EINVAL or %-ENOMEM on failure. */ -static int +int fsl_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) { int i, rc = 0; @@ -956,7 +912,7 @@ out: * Disables the inbound message unit, free all buffers, and * frees the inbound message interrupt. */ -static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox) +void fsl_close_inb_mbox(struct rio_mport *mport, int mbox) { struct rio_priv *priv = mport->priv; struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); @@ -966,7 +922,7 @@ static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox) /* Free ring */ dma_free_coherent(priv->dev, rmu->msg_rx_ring.size * RIO_MAX_MSG_SIZE, - rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys); + rmu->msg_rx_ring.virt, rmu->msg_rx_ring.phys); /* Free interrupt */ free_irq(IRQ_RIO_RX(mport), (void *)mport); @@ -981,7 +937,7 @@ static void fsl_close_inb_mbox(struct rio_mport *mport, int mbox) * Adds the @buf buffer to the MPC85xx inbound message queue. Returns * %0 on success or %-EINVAL on failure. */ -static int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) +int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) { int rc = 0; struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); @@ -1013,7 +969,7 @@ out: * Gets the next available inbound message from the inbound message queue. * A pointer to the message is returned on success or NULL on failure. */ -static void *fsl_get_inb_message(struct rio_mport *mport, int mbox) +void *fsl_get_inb_message(struct rio_mport *mport, int mbox) { struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); u32 phys_buf, virt_buf; @@ -1058,53 +1014,39 @@ out2: * ring. Called from fsl_rio_setup(). Returns %0 on success * or %-ENOMEM on failure. */ -static int fsl_rio_doorbell_init(struct rio_mport *mport) +int fsl_rio_doorbell_init(struct fsl_rio_dbell *dbell) { - struct rio_priv *priv = mport->priv; - struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); int rc = 0; - /* Map outbound doorbell window immediately after maintenance window */ - rmu->dbell_win = ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE, - RIO_DBELL_WIN_SIZE); - if (!rmu->dbell_win) { - printk(KERN_ERR - "RIO: unable to map outbound doorbell window\n"); - rc = -ENOMEM; - goto out; - } - /* Initialize inbound doorbells */ - rmu->dbell_ring.virt = dma_alloc_coherent(priv->dev, 512 * - DOORBELL_MESSAGE_SIZE, &rmu->dbell_ring.phys, GFP_KERNEL); - if (!rmu->dbell_ring.virt) { + dbell->dbell_ring.virt = dma_alloc_coherent(dbell->dev, 512 * + DOORBELL_MESSAGE_SIZE, &dbell->dbell_ring.phys, GFP_KERNEL); + if (!dbell->dbell_ring.virt) { printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n"); rc = -ENOMEM; - iounmap(rmu->dbell_win); goto out; } /* Point dequeue/enqueue pointers at first entry in ring */ - out_be32(&rmu->msg_regs->dqdpar, (u32) rmu->dbell_ring.phys); - out_be32(&rmu->msg_regs->dqepar, (u32) rmu->dbell_ring.phys); + out_be32(&dbell->dbell_regs->dqdpar, (u32) dbell->dbell_ring.phys); + out_be32(&dbell->dbell_regs->dqepar, (u32) dbell->dbell_ring.phys); /* Clear interrupt status */ - out_be32(&rmu->msg_regs->dsr, 0x00000091); + out_be32(&dbell->dbell_regs->dsr, 0x00000091); /* Hook up doorbell handler */ - rc = request_irq(IRQ_RIO_BELL(mport), fsl_rio_dbell_handler, 0, - "dbell_rx", (void *)mport); + rc = request_irq(IRQ_RIO_BELL(dbell), fsl_rio_dbell_handler, 0, + "dbell_rx", (void *)dbell); if (rc < 0) { - iounmap(rmu->dbell_win); - dma_free_coherent(priv->dev, 512 * DOORBELL_MESSAGE_SIZE, - rmu->dbell_ring.virt, rmu->dbell_ring.phys); + dma_free_coherent(dbell->dev, 512 * DOORBELL_MESSAGE_SIZE, + dbell->dbell_ring.virt, dbell->dbell_ring.phys); printk(KERN_ERR "MPC85xx RIO: unable to request inbound doorbell irq"); goto out; } /* Configure doorbells for snooping, 512 entries, and enable */ - out_be32(&rmu->msg_regs->dmr, 0x00108161); + out_be32(&dbell->dbell_regs->dmr, 0x00108161); out: return rc; @@ -1114,50 +1056,48 @@ int fsl_rio_setup_rmu(struct rio_mport *mport, struct device_node *node) { struct rio_priv *priv; struct fsl_rmu *rmu; - struct rio_ops *ops; + u64 msg_start; + const u32 *msg_addr; + int mlen; + int aw; - if (!mport || !mport->priv || !node) - return -1; + if (!mport || !mport->priv) + return -EINVAL; + + priv = mport->priv; + + if (!node) { + dev_warn(priv->dev, "Can't get %s property 'fsl,rmu'\n", + priv->dev->of_node->full_name); + return -EINVAL; + } rmu = kzalloc(sizeof(struct fsl_rmu), GFP_KERNEL); if (!rmu) return -ENOMEM; - priv = mport->priv; + aw = of_n_addr_cells(node); + msg_addr = of_get_property(node, "reg", &mlen); + if (!msg_addr) { + pr_err("%s: unable to find 'reg' property of message-unit\n", + node->full_name); + return -ENOMEM; + } + msg_start = of_read_number(msg_addr, aw); + + rmu->msg_regs = (struct rio_msg_regs *) + (rmu_regs_win + (u32)msg_start); + + rmu->txirq = irq_of_parse_and_map(node, 0); + rmu->rxirq = irq_of_parse_and_map(node, 1); + printk(KERN_INFO "%s: txirq: %d, rxirq %d\n", + node->full_name, rmu->txirq, rmu->rxirq); + priv->rmm_handle = rmu; - rmu->dbell_atmu_regs = priv->atmu_regs + 2; - rmu->msg_regs = (struct rio_msg_regs *)(priv->regs_win + - ((mport->phy_type == RIO_PHY_SERIAL) ? - RIO_S_MSG_REGS_OFFSET : RIO_P_MSG_REGS_OFFSET)); - - rmu->bellirq = irq_of_parse_and_map(node, 2); - rmu->txirq = irq_of_parse_and_map(node, 3); - rmu->rxirq = irq_of_parse_and_map(node, 4); - dev_info(priv->dev, "bellirq: %d, txirq: %d, rxirq %d\n", - rmu->bellirq, rmu->txirq, rmu->rxirq); - - ops = mport->ops; - - ops->dsend = fsl_rio_doorbell_send; - ops->open_outb_mbox = fsl_open_outb_mbox; - ops->open_inb_mbox = fsl_open_inb_mbox; - ops->close_outb_mbox = fsl_close_outb_mbox; - ops->close_inb_mbox = fsl_close_inb_mbox; - ops->add_outb_message = fsl_add_outb_message; - ops->add_inb_buffer = fsl_add_inb_buffer; - ops->get_inb_message = fsl_get_inb_message; rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 0); rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0); - /* Configure outbound doorbell window */ - out_be32(&rmu->dbell_atmu_regs->rowbar, - (mport->iores.start + RIO_MAINT_WIN_SIZE) >> 12); - /* 4k window size */ - out_be32(&rmu->dbell_atmu_regs->rowar, 0x8004200b); - - fsl_rio_doorbell_init(mport); - return 0; } |