Use SCLPC bit definitions from mpc52xx.h for better readability. Rewrite IRQ handlers, make them work for DMA. Fix module unload error.
Signed-off-by: Roman Fietze <roman.fie...@telemotive.de> --- arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c | 306 ++++++++++++------------- 1 files changed, 149 insertions(+), 157 deletions(-) diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c index 2763d5e..2fd1f3f 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c @@ -46,6 +46,34 @@ struct mpc52xx_lpbfifo { /* The MPC5200 has only one fifo, so only need one instance structure */ static struct mpc52xx_lpbfifo lpbfifo; + +/** + * mpc52xx_lpbfifo_is_write - return true if it's a WRITE request + */ +static inline int mpc52xx_lpbfifo_is_write(int flags) +{ + return flags & MPC52XX_LPBFIFO_FLAG_WRITE; +} + + +/** + * mpc52xx_lpbfifo_is_dma - return true if it's a DMA request + */ +static inline int mpc52xx_lpbfifo_is_dma(int flags) +{ + return !(flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); +} + + +/** + * mpc52xx_lpbfifo_is_poll_dma - return true if it's a polled DMA request + */ +static inline int mpc52xx_lpbfifo_is_poll_dma(int flags) +{ + return flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; +} + + /** * mpc52xx_lpbfifo_kick - Trigger the next block of data to be transfered */ @@ -57,16 +85,23 @@ static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) u32 *data; int i; int bit_fields; - int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); - int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; - int poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; + int rflags = req->flags; /* Set and clear the reset bits; is good practice in User Manual */ - out_be32(&lpbfifo.regs->enable, 0x01010000); + out_be32(&lpbfifo.regs->enable, MPC52xx_SCLPC_ENABLE_RC | MPC52xx_SCLPC_ENABLE_RF); + + /* Set width, chip select and READ mode */ + out_be32(&lpbfifo.regs->start_address, req->offset + req->pos); + + /* Set CS and BPT */ + bit_fields = MPC52xx_SCLPC_CONTROL_CS(req->cs) | 0x8; + if (!(mpc52xx_lpbfifo_is_write(rflags))) { + bit_fields |= MPC52xx_SCLPC_CONTROL_RWB_RECEIVE; /* read mode */ + bit_fields |= MPC52xx_SCLPC_CONTROL_FLUSH; + } + out_be32(&lpbfifo.regs->control, bit_fields); - /* set master enable bit */ - out_be32(&lpbfifo.regs->enable, 0x00000001); - if (!dma) { + if (!mpc52xx_lpbfifo_is_dma(rflags)) { /* While the FIFO can be setup for transfer sizes as large as * 16M-1, the FIFO itself is only 512 bytes deep and it does * not generate interrupts for FIFO full events (only transfer @@ -80,7 +115,7 @@ static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) transfer_size = 512; /* Load the FIFO with data */ - if (write) { + if (mpc52xx_lpbfifo_is_write(rflags)) { reg = &lpbfifo.regs->fifo_data; data = req->data + req->pos; for (i = 0; i < transfer_size; i += 4) @@ -88,7 +123,9 @@ static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) } /* Unmask both error and completion irqs */ - out_be32(&lpbfifo.regs->enable, 0x00000301); + out_be32(&lpbfifo.regs->enable, (MPC52xx_SCLPC_ENABLE_AIE | + MPC52xx_SCLPC_ENABLE_NIE | + MPC52xx_SCLPC_ENABLE_ME)); } else { /* Choose the correct direction * @@ -97,16 +134,16 @@ static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) * there is a performance impacit. However, if it is wrong there * is a risk of DMA not transferring the last chunk of data */ - if (write) { - out_be32(&lpbfifo.regs->fifo_alarm, 0x1e4); - out_8(&lpbfifo.regs->fifo_control, 7); + if (mpc52xx_lpbfifo_is_write(rflags)) { + out_be32(&lpbfifo.regs->fifo_alarm, MPC52xx_SCLPC_FIFO_SIZE - 28); + out_be32(&lpbfifo.regs->fifo_control, MPC52xx_SLPC_FIFO_CONTROL_GR(7)); lpbfifo.bcom_cur_task = lpbfifo.bcom_tx_task; } else { - out_be32(&lpbfifo.regs->fifo_alarm, 0x1ff); - out_8(&lpbfifo.regs->fifo_control, 0); + out_be32(&lpbfifo.regs->fifo_alarm, MPC52xx_SCLPC_FIFO_SIZE - 1); + out_be32(&lpbfifo.regs->fifo_control, MPC52xx_SLPC_FIFO_CONTROL_GR(0)); lpbfifo.bcom_cur_task = lpbfifo.bcom_rx_task; - if (poll_dma) { + if (mpc52xx_lpbfifo_is_poll_dma(rflags)) { if (lpbfifo.dma_irqs_enabled) { disable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); lpbfifo.dma_irqs_enabled = 0; @@ -119,63 +156,34 @@ static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) } } + /* error irq & master enabled bit */ + out_be32(&lpbfifo.regs->enable, MPC52xx_SCLPC_ENABLE_AIE | MPC52xx_SCLPC_ENABLE_NIE | MPC52xx_SCLPC_ENABLE_ME); + bd = bcom_prepare_next_buffer(lpbfifo.bcom_cur_task); bd->status = transfer_size; - if (!write) { - /* - * In the DMA read case, the DMA doesn't complete, - * possibly due to incorrect watermarks in the ALARM - * and CONTROL regs. For now instead of trying to - * determine the right watermarks that will make this - * work, just increase the number of bytes the FIFO is - * expecting. - * - * When submitting another operation, the FIFO will get - * reset, so the condition of the FIFO waiting for a - * non-existent 4 bytes will get cleared. - */ - transfer_size += 4; /* BLECH! */ - } bd->data[0] = req->data_phys + req->pos; bcom_submit_next_buffer(lpbfifo.bcom_cur_task, NULL); - - /* error irq & master enabled bit */ - bit_fields = 0x00000201; - - /* Unmask irqs */ - if (write && (!poll_dma)) - bit_fields |= 0x00000100; /* completion irq too */ - out_be32(&lpbfifo.regs->enable, bit_fields); } - /* Set transfer size, width, chip select and READ mode */ - out_be32(&lpbfifo.regs->start_address, - req->offset + req->pos); - out_be32(&lpbfifo.regs->packet_size.packet_size, transfer_size); - - bit_fields = req->cs << 24 | 0x000008; - if (!write) - bit_fields |= 0x010000; /* read mode */ - out_be32(&lpbfifo.regs->control, bit_fields); - - /* Kick it off */ - out_8(&lpbfifo.regs->packet_size.restart, 0x01); - if (dma) + /* Set packet size and kick it off */ + out_be32(&lpbfifo.regs->packet_size.packet_size, MPC52xx_SCLPC_PACKET_SIZE_RESTART | transfer_size); + if (mpc52xx_lpbfifo_is_dma(rflags)) bcom_enable(lpbfifo.bcom_cur_task); } /** - * mpc52xx_lpbfifo_irq - IRQ handler for LPB FIFO + * mpc52xx_lpbfifo_sclpc_irq - IRQ handler for LPB FIFO * - * On transmit, the dma completion irq triggers before the fifo completion - * triggers. Handle the dma completion here instead of the LPB FIFO Bestcomm - * task completion irq becuase everyting is not really done until the LPB FIFO - * completion irq triggers. + * On transmit, the dma completion irq triggers before the fifo + * completion triggers. Handle the dma completion here instead of the + * LPB FIFO Bestcomm task completion irq because everything is not + * really done until the LPB FIFO completion irq triggers. * * In other words: * For DMA, on receive, the "Fat Lady" is the bestcom completion irq. on - * transmit, the fifo completion irq is the "Fat Lady". The opera (or in this - * case the DMA/FIFO operation) is not finished until the "Fat Lady" sings. + * transmit, the fifo completion irq is the "Fat Lady". The opera (or in + * this case the DMA/FIFO operation) is not finished until the "Fat + * Lady" sings. * * Reasons for entering this routine: * 1) PIO mode rx and tx completion irq @@ -205,17 +213,17 @@ static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) * extra fiddling is done to make sure all paths lead to the same * outbound code. */ -static irqreturn_t mpc52xx_lpbfifo_irq(int irq, void *dev_id) +static irqreturn_t mpc52xx_lpbfifo_sclpc_irq(int irq, void *dev_id) { struct mpc52xx_lpbfifo_request *req; - u32 status = in_8(&lpbfifo.regs->bytes_done_status.status); + u32 status_count = in_be32(&lpbfifo.regs->bytes_done_status.bytes_done); void __iomem *reg; u32 *data; - int count, i; + size_t i; int do_callback = 0; u32 ts; unsigned long flags; - int dma, write, poll_dma; + int rflags; spin_lock_irqsave(&lpbfifo.lock, flags); ts = get_tbl(); @@ -223,87 +231,79 @@ static irqreturn_t mpc52xx_lpbfifo_irq(int irq, void *dev_id) req = lpbfifo.req; if (!req) { spin_unlock_irqrestore(&lpbfifo.lock, flags); - pr_err("bogus LPBFIFO IRQ\n"); + pr_err("bogus SCLPC IRQ\n"); return IRQ_HANDLED; } - dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); - write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; - poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; + rflags = req->flags; - if (dma && !write) { - spin_unlock_irqrestore(&lpbfifo.lock, flags); - pr_err("bogus LPBFIFO IRQ (dma and not writting)\n"); - return IRQ_HANDLED; - } - - if ((status & 0x01) == 0) { + /* check normal termination bit */ + if (!(status_count & MPC52xx_SCLPC_STATUS_NT)) goto out; - } /* check abort bit */ - if (status & 0x10) { - out_be32(&lpbfifo.regs->enable, 0x01010000); + if (status_count & MPC52xx_SCLPC_STATUS_AT) { + out_be32(&lpbfifo.regs->enable, MPC52xx_SCLPC_ENABLE_RC | MPC52xx_SCLPC_ENABLE_RF); do_callback = 1; goto out; } - /* Read result from hardware */ - count = in_be32(&lpbfifo.regs->bytes_done_status.bytes_done); - count &= 0x00ffffff; + if (!mpc52xx_lpbfifo_is_dma(rflags)) { - if (!dma && !write) { - /* copy the data out of the FIFO */ - reg = &lpbfifo.regs->fifo_data; - data = req->data + req->pos; - for (i = 0; i < count; i += 4) - *data++ = in_be32(reg); - } + /* bytes done */ + status_count &= MPC52xx_SCLPC_STATUS_BYTES_DONE_MASK; - /* Update transfer position and count */ - req->pos += count; + if (!mpc52xx_lpbfifo_is_write(rflags)) { + /* copy the data out of the FIFO */ + reg = &lpbfifo.regs->fifo_data; + data = req->data + req->pos; + for (i = 0; i < status_count; i += sizeof(u32)) + *data++ = in_be32(reg); + } - /* Decide what to do next */ - if (req->size - req->pos) - mpc52xx_lpbfifo_kick(req); /* more work to do */ - else + /* Update transfer position and count */ + req->pos += status_count; + + /* Decide what to do next */ + if (req->size - req->pos) + mpc52xx_lpbfifo_kick(req); /* more work to do */ + else + do_callback = 1; + } + else { do_callback = 1; + } out: /* Clear the IRQ */ - out_8(&lpbfifo.regs->bytes_done_status.status, 0x01); + out_8(&lpbfifo.regs->bytes_done_status.status, BIT(0)); - if (dma && (status & 0x11)) { - /* - * Count the DMA as complete only when the FIFO completion - * status or abort bits are set. - * - * (status & 0x01) should always be the case except sometimes - * when using polled DMA. - * - * (status & 0x10) {transfer aborted}: This case needs more - * testing. - */ - bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL); - } req->last_byte = ((u8 *)req->data)[req->size - 1]; + if (irq != 0) /* don't increment on polled case */ + req->irq_count++; + /* When the do_callback flag is set; it means the transfer is finished * so set the FIFO as idle */ - if (do_callback) + if (do_callback) { lpbfifo.req = NULL; + out_be32(&lpbfifo.regs->enable, MPC52xx_SCLPC_ENABLE_RC | MPC52xx_SCLPC_ENABLE_RF); - if (irq != 0) /* don't increment on polled case */ - req->irq_count++; + req->irq_ticks += get_tbl() - ts; + spin_unlock_irqrestore(&lpbfifo.lock, flags); - req->irq_ticks += get_tbl() - ts; - spin_unlock_irqrestore(&lpbfifo.lock, flags); + /* Spinlock is released; it is now safe to call the callback */ + if (req->callback) + req->callback(req); - /* Spinlock is released; it is now safe to call the callback */ - if (do_callback && req->callback) - req->callback(req); + return IRQ_HANDLED; + } + else { + req->irq_ticks += get_tbl() - ts; + spin_unlock_irqrestore(&lpbfifo.lock, flags); - return IRQ_HANDLED; + return IRQ_HANDLED; + } } /** @@ -313,48 +313,30 @@ out: */ static irqreturn_t mpc52xx_lpbfifo_bcom_irq(int irq, void *dev_id) { - struct mpc52xx_lpbfifo_request *req; + struct mpc52xx_lpbfifo *lpbfifo = dev_id; unsigned long flags; - u32 status; - u32 ts; - - spin_lock_irqsave(&lpbfifo.lock, flags); - ts = get_tbl(); - - req = lpbfifo.req; - if (!req || (req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA)) { - spin_unlock_irqrestore(&lpbfifo.lock, flags); - return IRQ_HANDLED; - } - if (irq != 0) /* don't increment on polled case */ - req->irq_count++; + spin_lock_irqsave(&lpbfifo->lock, flags); + // ts = get_tbl(); - if (!bcom_buffer_done(lpbfifo.bcom_cur_task)) { - spin_unlock_irqrestore(&lpbfifo.lock, flags); + if (!bcom_buffer_done(lpbfifo->bcom_cur_task)) { - req->buffer_not_done_cnt++; - if ((req->buffer_not_done_cnt % 1000) == 0) - pr_err("transfer stalled\n"); + if (bcom_queue_empty(lpbfifo->bcom_cur_task)) { + spin_unlock_irqrestore(&lpbfifo->lock, flags); + dev_err(lpbfifo->dev, "DMA queue empty\n"); + } + else { + spin_unlock_irqrestore(&lpbfifo->lock, flags); + dev_err(lpbfifo->dev, "DMA buffer not done\n"); + } return IRQ_HANDLED; } - bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL); - - req->last_byte = ((u8 *)req->data)[req->size - 1]; - - req->pos = status & 0x00ffffff; - - /* Mark the FIFO as idle */ - lpbfifo.req = NULL; + bcom_retrieve_buffer(lpbfifo->bcom_cur_task, NULL, NULL); + // req->irq_ticks += get_tbl() - ts; - /* Release the lock before calling out to the callback. */ - req->irq_ticks += get_tbl() - ts; - spin_unlock_irqrestore(&lpbfifo.lock, flags); - - if (req->callback) - req->callback(req); + spin_unlock_irqrestore(&lpbfifo->lock, flags); return IRQ_HANDLED; } @@ -365,14 +347,12 @@ static irqreturn_t mpc52xx_lpbfifo_bcom_irq(int irq, void *dev_id) void mpc52xx_lpbfifo_poll(void) { struct mpc52xx_lpbfifo_request *req = lpbfifo.req; - int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); - int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; /* * For more information, see comments on the "Fat Lady" */ - if (dma && write) - mpc52xx_lpbfifo_irq(0, NULL); + if (mpc52xx_lpbfifo_is_dma(req->flags) && (req->flags & MPC52XX_LPBFIFO_FLAG_WRITE)) + mpc52xx_lpbfifo_sclpc_irq(0, NULL); else mpc52xx_lpbfifo_bcom_irq(0, NULL); } @@ -406,6 +386,7 @@ int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req) mpc52xx_lpbfifo_kick(req); spin_unlock_irqrestore(&lpbfifo.lock, flags); + return 0; } EXPORT_SYMBOL(mpc52xx_lpbfifo_submit); @@ -419,7 +400,7 @@ void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req) /* Put it into reset and clear the state */ bcom_gen_bd_rx_reset(lpbfifo.bcom_rx_task); bcom_gen_bd_tx_reset(lpbfifo.bcom_tx_task); - out_be32(&lpbfifo.regs->enable, 0x01010000); + out_be32(&lpbfifo.regs->enable, MPC52xx_SCLPC_ENABLE_RC | MPC52xx_SCLPC_ENABLE_RF); lpbfifo.req = NULL; } spin_unlock_irqrestore(&lpbfifo.lock, flags); @@ -449,16 +430,16 @@ mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match) spin_lock_init(&lpbfifo.lock); /* Put FIFO into reset */ - out_be32(&lpbfifo.regs->enable, 0x01010000); + out_be32(&lpbfifo.regs->enable, MPC52xx_SCLPC_ENABLE_RC | MPC52xx_SCLPC_ENABLE_RF); /* register the interrupt handler */ - rc = request_irq(lpbfifo.irq, mpc52xx_lpbfifo_irq, 0, + rc = request_irq(lpbfifo.irq, mpc52xx_lpbfifo_sclpc_irq, 0, "mpc52xx-lpbfifo", &lpbfifo); if (rc) goto err_irq; /* Request the Bestcomm receive (fifo --> memory) task and IRQ */ - lpbfifo.bcom_rx_task = bcom_gen_bd_rx_init(2, + lpbfifo.bcom_rx_task = bcom_gen_bd_rx_init(16, res.start + offsetof(struct mpc52xx_sclpc, fifo_data), BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC, 16*1024*1024); @@ -472,16 +453,27 @@ mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match) goto err_bcom_rx_irq; /* Request the Bestcomm transmit (memory --> fifo) task and IRQ */ - lpbfifo.bcom_tx_task = bcom_gen_bd_tx_init(2, + lpbfifo.bcom_tx_task = bcom_gen_bd_tx_init(16, res.start + offsetof(struct mpc52xx_sclpc, fifo_data), BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC); if (!lpbfifo.bcom_tx_task) goto err_bcom_tx; + rc = request_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), + mpc52xx_lpbfifo_bcom_irq, 0, + "mpc52xx-lpbfifo-rx", &lpbfifo); + if (rc) + goto err_bcom_tx_irq; + + lpbfifo.dma_irqs_enabled = 1; + lpbfifo.dev = &op->dev; + return 0; +err_bcom_tx_irq: + free_irq(bcom_get_task_irq(lpbfifo.bcom_tx_task), &lpbfifo); err_bcom_tx: free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); err_bcom_rx_irq: -- 1.6.5.5 -- Roman Fietze Telemotive AG Büro Mühlhausen Breitwiesen 73347 Mühlhausen Tel.: +49(0)7335/18493-45 http://www.telemotive.de _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev