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

Reply via email to