summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Lv <r65388@freescale.com>2013-04-12 15:44:46 +0800
committerTerry Lv <r65388@freescale.com>2013-04-15 17:29:07 +0800
commitf8f1b8124d552ec0320c4360b460ed2d74fab81d (patch)
tree626216bc729c8a26f3f2542eddb2d940525de485
parentb4570bd7fce38384f01eed2a0cd5ff1c28165ad8 (diff)
ENGR00258357-5: mlb: Use circle buf macros to replace old ringbuf mechanism
Use circle buf to replace old ringbuf mechanism. Change to use circle buffer in read, write, rx isr and tx isr functions. In first design of MLB, it's using it's own mechanism to manage ring buffer, like in mxc_mlb.c. And then, I saw that kernel already had a serials of circ buffer macros which can be used to manage ring buffers. This patch is to use circle buffer macros to manage mlb internal ring buffers. For detail of circle buffers, you can refer to linux-2.6-imx/Documentation/circular-buffers.txt. Signed-off-by: Terry Lv <r65388@freescale.com>
-rwxr-xr-xdrivers/mxc/mlb/mxc_mlb150.c571
-rw-r--r--include/linux/mxc_mlb.h7
2 files changed, 371 insertions, 207 deletions
diff --git a/drivers/mxc/mlb/mxc_mlb150.c b/drivers/mxc/mlb/mxc_mlb150.c
index 4fa3ff873e1f..a74a72bb029b 100755
--- a/drivers/mxc/mlb/mxc_mlb150.c
+++ b/drivers/mxc/mlb/mxc_mlb150.c
@@ -37,6 +37,7 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
+#include <linux/circ_buf.h>
#define DRIVER_NAME "mxc_mlb150"
@@ -157,24 +158,30 @@
#define CAT_MODE_INBOUND_DMA (0x1 << 8)
#define CAT_MODE_OUTBOUND_DMA (0x1 << 9)
-#define CH_SYNC_BUF_DEP (128 * 4 * 4)
-#define CH_CTRL_BUF_DEP (64)
-#define CH_ASYNC_BUF_DEP (2048)
-#define CH_ISOC_BLK_SIZE (196)
-#define CH_ISOC_BLK_NUM (3)
-#define CH_ISOC_BUF_DEP (CH_ISOC_BLK_SIZE * CH_ISOC_BLK_NUM)
+#define CH_SYNC_DEFAULT_QUAD (1)
+#define CH_SYNC_MAX_QUAD (15)
+#define CH_SYNC_CDT_BUF_DEP (CH_SYNC_DEFAULT_QUAD * 4 * 4)
+#define CH_SYNC_ADT_BUF_MULTI (4)
+#define CH_SYNC_ADT_BUF_DEP (CH_SYNC_CDT_BUF_DEP * CH_SYNC_ADT_BUF_MULTI)
+#define CH_SYNC_BUF_SZ (CH_SYNC_MAX_QUAD * 4 * 4 * CH_SYNC_ADT_BUF_MULTI)
+#define CH_CTRL_CDT_BUF_DEP (64)
+#define CH_CTRL_ADT_BUF_DEP (CH_CTRL_CDT_BUF_DEP)
+#define CH_CTRL_BUF_SZ (CH_CTRL_ADT_BUF_DEP)
+#define CH_ASYNC_CDT_BUF_DEP (2048)
+#define CH_ASYNC_ADT_BUF_DEP (CH_ASYNC_CDT_BUF_DEP)
+#define CH_ASYNC_BUF_SZ (CH_ASYNC_ADT_BUF_DEP)
+#define CH_ISOC_BLK_SIZE_188 (188)
+#define CH_ISOC_BLK_SIZE_196 (196)
+#define CH_ISOC_BLK_SIZE (CH_ISOC_BLK_SIZE_188)
+#define CH_ISOC_BLK_NUM (5)
+#define CH_ISOC_CDT_BUF_DEP (CH_ISOC_BLK_SIZE * CH_ISOC_BLK_NUM)
+#define CH_ISOC_ADT_BUF_DEP (CH_ISOC_CDT_BUF_DEP)
+#define CH_ISOC_BUF_SZ (1024)
#define CH_SYNC_DBR_BUF_OFFSET (0x0)
-#define CH_CTRL_DBR_BUF_OFFSET (CH_SYNC_DBR_BUF_OFFSET + 2 * CH_SYNC_BUF_DEP)
-#define CH_ASYNC_DBR_BUF_OFFSET (CH_CTRL_DBR_BUF_OFFSET + 2 * CH_CTRL_BUF_DEP)
-#define CH_ISOC_DBR_BUF_OFFSET (CH_ASYNC_DBR_BUF_OFFSET + 2 * CH_ASYNC_BUF_DEP)
-
-static u32 mlb150_ch_packet_buf_size[4] = {
- CH_SYNC_BUF_DEP,
- CH_CTRL_BUF_DEP,
- CH_ASYNC_BUF_DEP,
- CH_ISOC_BUF_DEP
-};
+#define CH_CTRL_DBR_BUF_OFFSET (CH_SYNC_DBR_BUF_OFFSET + 2 * (CH_SYNC_MAX_QUAD * 4 * 4))
+#define CH_ASYNC_DBR_BUF_OFFSET (CH_CTRL_DBR_BUF_OFFSET + 2 * CH_CTRL_CDT_BUF_DEP)
+#define CH_ISOC_DBR_BUF_OFFSET (CH_ASYNC_DBR_BUF_OFFSET + 2 * CH_ASYNC_CDT_BUF_DEP)
#define DBR_BUF_START 0x00000
@@ -1273,8 +1280,22 @@ static s32 mlb150_dev_reset_all_regs(void)
return 0;
}
-static inline s32 mlb150_dev_set_ch_amba_ahb(u32 ch, enum MLB_CTYPE ctype,
- u32 dne_sts, u32 buf_addr)
+static inline s32 mlb150_dev_pipo_start(struct mlb_ringbuf *rbuf,
+ u32 ahb_ch, u32 buf_addr)
+{
+ u32 ctr_val[4] = { 0 };
+
+ ctr_val[1] |= ADT_RDY1;
+ ctr_val[2] = buf_addr;
+
+ if (mlb150_dev_adt_write(ahb_ch, ctr_val))
+ return -ETIME;
+
+ return 0;
+}
+
+static inline s32 mlb150_dev_pipo_next(u32 ahb_ch, enum MLB_CTYPE ctype,
+ u32 dne_sts, u32 buf_addr)
{
u32 ctr_val[4] = { 0 };
@@ -1294,42 +1315,25 @@ static inline s32 mlb150_dev_set_ch_amba_ahb(u32 ch, enum MLB_CTYPE ctype,
ctr_val[2] = buf_addr;
}
-#ifdef DEBUG_ADT
- pr_debug("mxc_mlb150: Set ADT val of channel %d, ctype: %d: "
- "0x%08x 0x%08x 0x%08x 0x%08x\n",
- ch, ctype, ctr_val[3], ctr_val[2], ctr_val[1], ctr_val[0]);
-#endif
-
- if (unlikely(mlb150_dev_adt_write(ch, ctr_val)))
+ if (mlb150_dev_adt_write(ahb_ch, ctr_val))
return -ETIME;
-#ifdef DEBUG_ADT_N
- {
- u32 ctr_rd[4] = { 0 };
- if (likely(!mlb150_dev_adt_read(ch, ctr_rd))) {
- pr_debug("mxc_mlb150: ADT val of channel %d: "
- "0x%08x 0x%08x 0x%08x 0x%08x\n",
- ch, ctr_rd[3], ctr_rd[2],
- ctr_rd[1], ctr_rd[0]);
- if (ctr_rd[3] == ctr_val[3] &&
- ctr_rd[2] == ctr_val[2] &&
- ctr_rd[1] == ctr_val[1] &&
- ctr_rd[0] == ctr_val[0]) {
- pr_debug("mxc_mlb150: set adt succeed!\n");
- return 0;
- } else {
- pr_debug("mxc_mlb150: set adt failed!\n");
- return -EBADE;
- }
- } else {
- pr_debug("mxc_mlb150: Read ADT val of channel %d failed\n",
- ch);
- return -EBADE;
- }
- }
-#endif
+ return 0;
+}
- return 0;
+static inline s32 mlb150_dev_pipo_stop(struct mlb_ringbuf *rbuf, u32 ahb_ch)
+{
+ u32 ctr_val[4] = { 0 };
+ unsigned long flags;
+
+ write_lock_irqsave(&rbuf->rb_lock, flags);
+ rbuf->head = rbuf->tail = 0;
+ write_unlock_irqrestore(&rbuf->rb_lock, flags);
+
+ if (mlb150_dev_adt_write(ahb_ch, ctr_val))
+ return -ETIME;
+
+ return 0;
}
static s32 mlb150_dev_init_ch_amba_ahb(struct mlb_dev_info *pdevinfo,
@@ -1505,26 +1509,43 @@ static s32 mlb150_dev_unmute_syn_ch(u32 rx_ch, u32 rx_cl, u32 tx_ch, u32 tx_cl)
return 0;
}
-/*!
- * MLB receive start function
- *
- * load phy_head to next buf register to start next rx
- * here use single-packet buffer, set start=end
- */
-static inline void mlb_start_rx(u32 ch, s32 ctype, u32 dne_sts, u32 buf_addr)
+/* In case the user calls channel shutdown, but rx or tx is not completed yet */
+static s32 mlb150_trans_complete_check(struct mlb_dev_info *pdevinfo)
{
- /* Set ADT for RX */
- mlb150_dev_set_ch_amba_ahb(ch, ctype, dne_sts, buf_addr);
-}
+ struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+ struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+ s32 timeout = 1024;
-/*!
- * MLB transmit start function
- * make sure aquiring the rw buf_lock, when calling this
- */
-static inline void mlb_start_tx(u32 ch, s32 ctype, u32 dne_sts, u32 buf_addr)
-{
- /* Set ADT for TX */
- mlb150_dev_set_ch_amba_ahb(ch, ctype, dne_sts, buf_addr);
+ while (timeout--) {
+ read_lock(&tx_rbuf->rb_lock);
+ if (!CIRC_CNT(tx_rbuf->head, tx_rbuf->tail, TRANS_RING_NODES)) {
+ read_unlock(&tx_rbuf->rb_lock);
+ break;
+ } else
+ read_unlock(&tx_rbuf->rb_lock);
+ }
+
+ if (timeout <= 0) {
+ pr_debug("TX complete check timeout!\n");
+ return -ETIME;
+ }
+
+ timeout = 1024;
+ while (timeout--) {
+ read_lock(&rx_rbuf->rb_lock);
+ if (!CIRC_CNT(rx_rbuf->head, rx_rbuf->tail, TRANS_RING_NODES)) {
+ read_unlock(&rx_rbuf->rb_lock);
+ break;
+ } else
+ read_unlock(&rx_rbuf->rb_lock);
+ }
+
+ if (timeout <= 0) {
+ pr_debug("RX complete check timeout!\n");
+ return -ETIME;
+ }
+
+ return 0;
}
/*!
@@ -1596,123 +1617,134 @@ static void mlb_channel_enable(struct mlb_data *drvdata,
/*!
* MLB interrupt handler
*/
-static void mlb_tx_isr(int minor)
-{
- struct mlb_dev_info *pdevinfo = &mlb_devinfo[minor];
-
- pdevinfo->tx_busy = 0;
-
- wake_up_interruptible(&pdevinfo->wt_wq);
-}
-
-static void mlb_rx_isr(int minor)
+static void mlb_rx_isr(s32 ctype, u32 ahb_ch, struct mlb_dev_info *pdevinfo)
{
- struct mlb_dev_info *pdevinfo = &mlb_devinfo[minor];
- struct mlb_channel_info *pchinfo = &_get_rxchan(minor);
- struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_bufs;
- s32 wpos, rpos, adt_sts;
- u32 rx_ring_buf = 0;
- s32 ctype = pdevinfo->channel_type;
- u32 ch_addr = pchinfo->address;
+ struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+ s32 head, tail, adt_sts;
+ unsigned long flags;
+ u32 rx_buf_ptr;
#ifdef DEBUG_RX
pr_debug("mxc_mlb150: mlb_rx_isr\n");
#endif
- rpos = rx_rbuf->rpos;
- wpos = rx_rbuf->wpos;
+ write_lock_irqsave(&rx_rbuf->rb_lock, flags);
-#ifdef DEBUG_RX
- pr_debug("adt_buf_ptr: 0x%08x\n", (u32)adt_buf_ptr);
-#endif
+ head = (rx_rbuf->head + 1) & (TRANS_RING_NODES - 1);
+ tail = ACCESS_ONCE(rx_rbuf->tail);
- /*!
- * Copy packet from IRAM buf to ring buf.
- * if the wpos++ == rpos, drop this packet
- */
- if (((wpos + 1) % TRANS_RING_NODES) != rpos) {
- rx_ring_buf = rx_rbuf->phy_addrs[(wpos + 1) % TRANS_RING_NODES];
-#ifdef DEBUG_RX
- if (len > mlb150_ch_packet_buf_size[ctype])
- pr_debug("mxc_mlb150: packet overflow, "
- "packet type: %d\n", ctype);
-#endif
+ if (CIRC_SPACE(head, tail, TRANS_RING_NODES) >= 1) {
+ rx_buf_ptr = rx_rbuf->phy_addrs[head];
- /* update the ring wpos */
- rx_rbuf->wpos = (wpos + 1) % TRANS_RING_NODES;
+ /* commit the item before incrementing the head */
+ smp_wmb();
- /* wake up the reader */
- wake_up_interruptible(&pdevinfo->rd_wq);
+ rx_rbuf->head = head;
-#ifdef DEBUG_RX
- pr_debug("recv package, len:%d, rx_rdpos: %d, rx_wtpos: %d\n",
- len, rpos, pdevinfo->rx_bufs.wpos);
-#endif
- } else {
- rx_ring_buf = pdevinfo->rx_bufs.phy_addrs[TRANS_RING_NODES];
+ write_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
- pr_debug
- ("drop package, due to no space, (%d,%d)\n",
- rpos, pdevinfo->rx_bufs.wpos);
+ /* wake up the reader */
+ wake_up_interruptible(&pdevinfo->rx_wq);
+ } else {
+ rx_buf_ptr = rx_rbuf->phy_addrs[TRANS_RING_NODES];
+ write_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+ pr_debug("drop RX package, due to no space, (%d,%d)\n",
+ head, tail);
}
- adt_sts = mlb150_dev_get_adt_sts(ch_addr);
- mlb_start_rx(ch_addr, ctype, adt_sts, rx_ring_buf);
+ adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+ /* Set ADT for RX */
+ mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, rx_buf_ptr);
+}
+
+static void mlb_tx_isr(s32 ctype, u32 ahb_ch, struct mlb_dev_info *pdevinfo)
+{
+ struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+ s32 head, tail, adt_sts;
+ u32 tx_buf_ptr;
+ unsigned long flags;
+
+ write_lock_irqsave(&tx_rbuf->rb_lock, flags);
+
+ head = ACCESS_ONCE(tx_rbuf->head);
+ tail = (tx_rbuf->tail + 1) & (TRANS_RING_NODES - 1);
+ smp_mb();
+ tx_rbuf->tail = tail;
+
+ /* check the current tx buffer is available or not */
+ if (CIRC_CNT(head, tail, TRANS_RING_NODES) >= 1) {
+ /* read index before reading contents at that index */
+ smp_read_barrier_depends();
+
+ tx_buf_ptr = tx_rbuf->phy_addrs[tail];
+
+ write_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+
+ wake_up_interruptible(&pdevinfo->tx_wq);
+
+ adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+ /* Set ADT for TX */
+ mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, tx_buf_ptr);
+ } else
+ write_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
}
static irqreturn_t mlb_ahb_isr(int irq, void *dev_id)
{
- u32 rx_int_sts, tx_int_sts, acsr0,
- acsr1, rx_err, tx_err, hcer0, hcer1;
- struct mlb_dev_info *pdev = NULL;
- struct mlb_channel_info *ptxchinfo = NULL, *prxchinfo = NULL;
- int minor;
+ u32 acsr0, hcer0;
+ u32 ch_mask = (1 << SYNC_RX_CL) | (1 << CTRL_RX_CL)
+ | (1 << ASYNC_RX_CL) | (1 << ISOC_RX_CL)
+ | (1 << SYNC_TX_CL) | (1 << CTRL_TX_CL)
+ | (1 << ASYNC_TX_CL) | (1 << ISOC_TX_CL);
/* Step 5, Read the ACSRn registers to determine which channel or
* channels are causing the interrupt */
acsr0 = __raw_readl(mlb_base + REG_ACSR0);
- acsr1 = __raw_readl(mlb_base + REG_ACSR1);
hcer0 = __raw_readl(mlb_base + REG_HCER0);
- hcer1 = __raw_readl(mlb_base + REG_HCER1);
/* Step 6, If ACTL.SCE = 1, write the result of step 5 back to ACSR0
* and ACSR1 to clear the interrupt */
- if (ACTL_SCE & __raw_readl(mlb_base + REG_ACTL)) {
+ /* We'll not set ACTL_SCE */
+ /*
+ if (ACTL_SCE & __raw_readl(mlb_base + REG_ACTL))
__raw_writel(acsr0, mlb_base + REG_ACSR0);
- __raw_writel(acsr1, mlb_base + REG_ACSR1);
- }
+ */
- for (minor = 0; minor < MLB_MINOR_DEVICES; minor++) {
- pdev = &mlb_devinfo[minor];
- prxchinfo = &_get_rxchan(minor);
- ptxchinfo = &_get_txchan(minor);
-
- rx_int_sts = (prxchinfo->address < 31) ? acsr0 : acsr1;
- tx_int_sts = (ptxchinfo->address < 31) ? acsr0 : acsr1;
- rx_err = (prxchinfo->address < 31) ? hcer0 : hcer1;
- tx_err = (ptxchinfo->address < 31) ? hcer0 : hcer1;
-
- /* get tx channel interrupt status */
- if (tx_int_sts & (1 << (ptxchinfo->address % 32))) {
- if (!(tx_err & (1 << (ptxchinfo->address % 32))))
- mlb_tx_isr(minor);
- else {
- pr_debug("tx channel %d encountered an AHB error!\n",
- ptxchinfo->address);
- }
- }
+ if (ch_mask & hcer0)
+ pr_err("CH encounters an AHB error: 0x%x\n", hcer0);
- /* get rx channel interrupt status */
- if (rx_int_sts & (1 << (prxchinfo->address % 32))) {
- if (!(rx_err & (1 << (prxchinfo->address % 32))))
- mlb_rx_isr(minor);
- else {
- pr_debug("rx channel %d encountered an AHB error!\n",
- prxchinfo->address);
- }
- }
- }
+ if ((1 << SYNC_RX_CL) & acsr0)
+ mlb_rx_isr(MLB_CTYPE_SYNC, SYNC_RX_CL,
+ &mlb_devinfo[MLB_CTYPE_SYNC]);
+
+ if ((1 << CTRL_RX_CL) & acsr0)
+ mlb_rx_isr(MLB_CTYPE_CTRL, CTRL_RX_CL,
+ &mlb_devinfo[MLB_CTYPE_CTRL]);
+
+ if ((1 << ASYNC_RX_CL) & acsr0)
+ mlb_rx_isr(MLB_CTYPE_ASYNC, ASYNC_RX_CL,
+ &mlb_devinfo[MLB_CTYPE_ASYNC]);
+
+ if ((1 << ISOC_RX_CL) & acsr0)
+ mlb_rx_isr(MLB_CTYPE_ISOC, ISOC_RX_CL,
+ &mlb_devinfo[MLB_CTYPE_ISOC]);
+
+ if ((1 << SYNC_TX_CL) & acsr0)
+ mlb_tx_isr(MLB_CTYPE_SYNC, SYNC_TX_CL,
+ &mlb_devinfo[MLB_CTYPE_SYNC]);
+
+ if ((1 << CTRL_TX_CL) & acsr0)
+ mlb_tx_isr(MLB_CTYPE_CTRL, CTRL_TX_CL,
+ &mlb_devinfo[MLB_CTYPE_CTRL]);
+
+ if ((1 << ASYNC_TX_CL) & acsr0)
+ mlb_tx_isr(MLB_CTYPE_ASYNC, ASYNC_TX_CL,
+ &mlb_devinfo[MLB_CTYPE_ASYNC]);
+
+ if ((1 << ISOC_TX_CL) & acsr0)
+ mlb_tx_isr(MLB_CTYPE_ASYNC, ISOC_TX_CL,
+ &mlb_devinfo[MLB_CTYPE_ISOC]);
return IRQ_HANDLED;
}
@@ -1997,6 +2029,37 @@ static long mxc_mlb150_ioctl(struct file *filp,
}
} else
return -EAGAIN;
+ break;
+ case MLB_SET_ISOC_BLKSIZE_188:
+ pdevinfo->isoc_blksz = 188;
+ pdevinfo->cdt_buf_dep = pdevinfo->adt_buf_dep =
+ pdevinfo->isoc_blksz * CH_ISOC_BLK_NUM;
+ break;
+ case MLB_SET_ISOC_BLKSIZE_196:
+ pdevinfo->isoc_blksz = 196;
+ pdevinfo->cdt_buf_dep = pdevinfo->adt_buf_dep =
+ pdevinfo->isoc_blksz * CH_ISOC_BLK_NUM;
+ break;
+ case MLB_SET_SYNC_QUAD:
+ {
+ u32 quad;
+
+ if (copy_from_user(&quad, argp, sizeof(quad))) {
+ pr_err("mxc_mlb150: get quad number "
+ "from user failed\n");
+ return -EFAULT;
+ }
+ if (quad <= 0 || quad > 3) {
+ pr_err("mxc_mlb150: Invalid Quadlets!"
+ "Quadlets in Sync mode can "
+ "only be 1, 2, 3\n");
+ return -EINVAL;
+ }
+ pdevinfo->sync_quad = quad;
+ /* Each quadlets is 4 bytes */
+ pdevinfo->cdt_buf_dep = quad * 4 * 4;
+ pdevinfo->adt_buf_dep =
+ pdevinfo->cdt_buf_dep * CH_SYNC_ADT_BUF_MULTI;
}
break;
case MLB_SET_FPS:
@@ -2117,35 +2180,59 @@ static long mxc_mlb150_ioctl(struct file *filp,
static ssize_t mxc_mlb150_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
- int minor, ret;
- int size, rdpos;
- struct mlb_ringbuf *rx_rbuf = NULL;
- struct mlb_dev_info *pdevinfo = NULL;
-
-#ifdef DEBUG_RX
- pr_debug("mxc_mlb150: mxc_mlb150_read\n");
-#endif
-
- minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ int size;
+ struct mlb_data *drvdata = filp->private_data;
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+ struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+ int head, tail;
+ unsigned long flags;
- pdevinfo = &mlb_devinfo[minor];
+ read_lock_irqsave(&rx_rbuf->rb_lock, flags);
- rdpos = pdevinfo->rx_bufs.rpos;
- rx_rbuf = &pdevinfo->rx_bufs;
+ head = ACCESS_ONCE(rx_rbuf->head);
+ tail = rx_rbuf->tail;
/* check the current rx buffer is available or not */
- if (rdpos == rx_rbuf->wpos) {
+ if (0 == CIRC_CNT(head, tail, TRANS_RING_NODES)) {
+ read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
- /* if !O_NONBLOCK, we wait for recv packet */
- ret = wait_event_interruptible(pdevinfo->rd_wq,
- (rx_rbuf->wpos != rdpos));
- if (ret < 0)
- return ret;
+
+ do {
+ DEFINE_WAIT(__wait);
+
+ for (;;) {
+ prepare_to_wait(&pdevinfo->rx_wq,
+ &__wait, TASK_INTERRUPTIBLE);
+
+ read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+ if (CIRC_CNT(rx_rbuf->head, rx_rbuf->tail,
+ TRANS_RING_NODES) > 0) {
+ read_unlock_irqrestore(&rx_rbuf->rb_lock,
+ flags);
+ break;
+ }
+ read_unlock_irqrestore(&rx_rbuf->rb_lock,
+ flags);
+
+ if (!signal_pending(current)) {
+ schedule();
+ continue;
+ }
+ return -ERESTARTSYS;
+ }
+ finish_wait(&pdevinfo->rx_wq, &__wait);
+ } while (0);
+ read_lock_irqsave(&rx_rbuf->rb_lock, flags);
}
+ read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
+ /* read index before reading contents at that index */
+ smp_read_barrier_depends();
- size = mlb150_ch_packet_buf_size[minor];
- if (unlikely(size > count)) {
+ size = pdevinfo->adt_buf_dep;
+ if (size > count) {
/* the user buffer is too small */
pr_warning
("mxc_mlb150: received data size is bigger than "
@@ -2153,14 +2240,18 @@ static ssize_t mxc_mlb150_read(struct file *filp, char __user *buf,
return -EINVAL;
}
- /* copy rx buffer data to user buffer */
- if (likely(copy_to_user(buf, rx_rbuf->virt_bufs[rdpos], size))) {
+ /* extract one item from the buffer */
+ if (copy_to_user(buf, rx_rbuf->virt_bufs[tail], size)) {
pr_err("mxc_mlb150: copy from user failed\n");
return -EFAULT;
}
- /* update the read ptr */
- rx_rbuf->rpos = (rdpos + 1) % TRANS_RING_NODES;
+ /* finish reading descriptor before incrementing tail */
+ smp_mb();
+
+ write_lock_irqsave(&rx_rbuf->rb_lock, flags);
+ rx_rbuf->tail = (tail + 1) & (TRANS_RING_NODES - 1);
+ write_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
*f_pos = 0;
@@ -2176,16 +2267,20 @@ static ssize_t mxc_mlb150_read(struct file *filp, char __user *buf,
static ssize_t mxc_mlb150_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
- s32 minor = 0, ret = 0;
+ s32 ret = 0;
struct mlb_channel_info *pchinfo = NULL;
- struct mlb_dev_info *pdevinfo = NULL;
- u32 adt_sts = 0;
+ struct mlb_data *drvdata = filp->private_data;
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+ struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+ int head, tail;
+ unsigned long flags;
+ /*
minor = MINOR(filp->f_dentry->d_inode->i_rdev);
- pchinfo = &_get_txchan(minor);
- pdevinfo = &mlb_devinfo[minor];
+ */
+ pchinfo = &pdevinfo->channels[TX_CHANNEL];
- if (unlikely(count > pchinfo->buf_size)) {
+ if (count > pdevinfo->buf_size) {
/* too many data to write */
pr_warning("mxc_mlb150: overflow write data\n");
return -EFBIG;
@@ -2193,31 +2288,77 @@ static ssize_t mxc_mlb150_write(struct file *filp, const char __user *buf,
*f_pos = 0;
- /* check the current tx buffer is used or not */
- if (1 == pdevinfo->tx_busy) {
+ read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+
+ head = tx_rbuf->head;
+ tail = ACCESS_ONCE(tx_rbuf->tail);
+
+ if (0 == CIRC_SPACE(head, tail, TRANS_RING_NODES)) {
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
+ do {
+ DEFINE_WAIT(__wait);
+
+ for (;;) {
+ prepare_to_wait(&pdevinfo->tx_wq,
+ &__wait, TASK_INTERRUPTIBLE);
+
+ read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+ if (CIRC_SPACE(tx_rbuf->head, tx_rbuf->tail,
+ TRANS_RING_NODES) > 0) {
+ read_unlock_irqrestore(&tx_rbuf->rb_lock,
+ flags);
+ break;
+ }
+ read_unlock_irqrestore(&tx_rbuf->rb_lock,
+ flags);
- ret = wait_event_interruptible(pdevinfo->wt_wq,
- 0 == pdevinfo->tx_busy);
-
- if (ret < 0)
- goto out;
+ if (!signal_pending(current)) {
+ schedule();
+ continue;
+ }
+ return -ERESTARTSYS;
+ }
+ finish_wait(&pdevinfo->tx_wq, &__wait);
+ } while (0);
}
- if (copy_from_user((void *)pchinfo->buf_ptr, buf, count)) {
+ if (copy_from_user((void *)tx_rbuf->virt_bufs[head], buf, count)) {
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
pr_err("mxc_mlb: copy from user failed\n");
ret = -EFAULT;
goto out;
}
- adt_sts = mlb150_dev_get_adt_sts(pchinfo->address);
- pdevinfo->tx_busy = 1;
- mlb_start_tx(pchinfo->address, pdevinfo->channel_type,
- adt_sts, pchinfo->buf_phy_addr);
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+ write_lock_irqsave(&tx_rbuf->rb_lock, flags);
+ smp_wmb();
+ tx_rbuf->head = (head + 1) & (TRANS_RING_NODES - 1);
+ write_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
- ret = count;
+ read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+ if (0 == CIRC_CNT(head, tail, TRANS_RING_NODES)) {
+ u32 tx_buf_ptr, ahb_ch;
+ s32 adt_sts;
+ u32 ctype = pdevinfo->channel_type;
+
+ /* read index before reading contents at that index */
+ smp_read_barrier_depends();
+
+ tx_buf_ptr = tx_rbuf->phy_addrs[tail];
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+ ahb_ch = pdevinfo->channels[TX_CHANNEL].cl;
+ adt_sts = mlb150_dev_get_adt_sts(ahb_ch);
+
+ /* Set ADT for TX */
+ mlb150_dev_pipo_next(ahb_ch, ctype, adt_sts, tx_buf_ptr);
+ } else {
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+ }
+
+ ret = count;
out:
return ret;
}
@@ -2227,23 +2368,41 @@ static unsigned int mxc_mlb150_poll(struct file *filp,
{
int minor;
unsigned int ret = 0;
- struct mlb_dev_info *pdevinfo = NULL;
+ struct mlb_data *drvdata = filp->private_data;
+ struct mlb_dev_info *pdevinfo = drvdata->devinfo;
+ struct mlb_ringbuf *tx_rbuf = &pdevinfo->tx_rbuf;
+ struct mlb_ringbuf *rx_rbuf = &pdevinfo->rx_rbuf;
+ int head, tail;
+ unsigned long flags;
+
minor = MINOR(filp->f_dentry->d_inode->i_rdev);
- pdevinfo = &mlb_devinfo[minor];
+ poll_wait(filp, &pdevinfo->rx_wq, wait);
+ poll_wait(filp, &pdevinfo->tx_wq, wait);
- poll_wait(filp, &pdevinfo->rd_wq, wait);
- poll_wait(filp, &pdevinfo->wt_wq, wait);
+ read_lock_irqsave(&tx_rbuf->rb_lock, flags);
+
+ head = tx_rbuf->head;
+ tail = tx_rbuf->tail;
/* check the tx buffer is avaiable or not */
- if (0 == pdevinfo->tx_busy)
+ if (CIRC_SPACE(head, tail, TRANS_RING_NODES) >= 1)
ret |= POLLOUT | POLLWRNORM;
+ read_unlock_irqrestore(&tx_rbuf->rb_lock, flags);
+
+ read_lock_irqsave(&rx_rbuf->rb_lock, flags);
+
+ head = rx_rbuf->head;
+ tail = rx_rbuf->tail;
+
/* check the rx buffer filled or not */
- if (pdevinfo->rx_bufs.rpos != pdevinfo->rx_bufs.wpos)
+ if (CIRC_CNT(head, tail, TRANS_RING_NODES) >= 1)
ret |= POLLIN | POLLRDNORM;
+ read_unlock_irqrestore(&rx_rbuf->rb_lock, flags);
+
/* check the exception event */
if (pdevinfo->ex_event)
ret |= POLLIN | POLLRDNORM;
diff --git a/include/linux/mxc_mlb.h b/include/linux/mxc_mlb.h
index 7ac953c84dd3..3a63647b61b3 100644
--- a/include/linux/mxc_mlb.h
+++ b/include/linux/mxc_mlb.h
@@ -1,7 +1,7 @@
/*
* mxc_mlb.h
*
- * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -21,6 +21,7 @@
#define MLB_SET_FPS _IOW('S', 0x10, unsigned int)
#define MLB_GET_VER _IOR('S', 0x11, unsigned long)
#define MLB_SET_DEVADDR _IOR('S', 0x12, unsigned char)
+
/*!
* set channel address for each logical channel
* the MSB 16bits is for tx channel, the left LSB is for rx channel
@@ -30,6 +31,10 @@
#define MLB_CHAN_SHUTDOWN _IO('S', 0x15)
#define MLB_CHAN_GETEVENT _IOR('S', 0x16, unsigned long)
+#define MLB_SET_ISOC_BLKSIZE_188 _IO('S', 0x17)
+#define MLB_SET_ISOC_BLKSIZE_196 _IO('S', 0x18)
+#define MLB_SET_SYNC_QUAD _IOW('S', 0x19, unsigned int)
+
/*!
* MLB event define
*/