From 7fd2405c0498ec7f9d6b6f319f016d8b3e4e2317 Mon Sep 17 00:00:00 2001 From: Erwan Bracq Date: Sat, 23 Apr 2011 12:32:31 +0200 Subject: CAIF: Minor alignment with internal CAIF git Some added blank line and BUGON for CAIF serial. Change-Id: If3452ed104b93203fc86fe6a95fd957946447876 Signed-off-by: Erwan Bracq Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/21527 Reviewed-by: QATEST Reviewed-by: Jonas ABERG --- drivers/net/caif/caif_serial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 8a3054b8481..957363ceae4 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -182,6 +182,7 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data, * This is not yet handled. */ + BUG_ON(ser->dev == NULL); /* * Workaround for garbage at start of transmission, -- cgit v1.2.3 From 9e2de8518e8762e40d91de5202ecb225be569a06 Mon Sep 17 00:00:00 2001 From: Arun Murthy Date: Tue, 13 Dec 2011 22:44:34 +0530 Subject: caif-shm: synchronize caif flow control In the shm tx work function caif flow control is turned ON and without acquiring the spin lock. In the rx callback cail flow control is turned off. The expected sequence would be on caif writing message to modem via shm, if shm finds that there is no empty space then, it is not sets caif flow control to OFF. On shm receiving messages from modem, it sets caif flow control to ON. Now this since this is in interrupt context, there are chances of this fucntion being preeempted by the caif OFF that is being set in the tx work function. Hence create a seperate workqueue and two work functions to turn caif flow control ON and OFF. With this implementation it is ensured that caif flow control is turned OFF first by tx work function and turned ON by the rx callback. ST-Ericsson Linux next: NA ST-Ericsson ID: 372652 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Ide75415233d7b4560faf25862876c15421df7c2c Signed-off-by: Arun Murthy Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/42438 Reviewed-by: QABUILD Reviewed-by: Hemant-vilas RAMDASI Reviewed-by: Sjur BRENDELAND --- drivers/net/caif/caif_shmcore.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c index 5b2041319a3..7bd35e0c18b 100644 --- a/drivers/net/caif/caif_shmcore.c +++ b/drivers/net/caif/caif_shmcore.c @@ -106,9 +106,12 @@ struct shmdrv_layer { struct workqueue_struct *pshm_tx_workqueue; struct workqueue_struct *pshm_rx_workqueue; + struct workqueue_struct *pshm_flow_ctrl_workqueue; struct work_struct shm_tx_work; struct work_struct shm_rx_work; + struct work_struct shm_flow_on_work; + struct work_struct shm_flow_off_work; struct sk_buff_head sk_qhead; struct shmdev_layer *pshm_dev; @@ -126,6 +129,24 @@ static int shm_netdev_close(struct net_device *shm_netdev) return 0; } +static void shm_flow_on_work_func(struct work_struct *work) +{ + struct shmdrv_layer *pshm_drv = container_of(work, struct shmdrv_layer, shm_flow_on_work); + + pshm_drv->cfdev.flowctrl + (pshm_drv->pshm_dev->pshm_netdev, + CAIF_FLOW_ON); +} + +static void shm_flow_off_work_func(struct work_struct *work) +{ + struct shmdrv_layer *pshm_drv = container_of(work, struct shmdrv_layer, shm_flow_off_work); + + pshm_drv->cfdev.flowctrl + (pshm_drv->pshm_dev->pshm_netdev, + CAIF_FLOW_OFF); +} + int caif_shmdrv_rx_cb(u32 mbx_msg, void *priv) { struct buf_list *pbuf; @@ -238,11 +259,9 @@ int caif_shmdrv_rx_cb(u32 mbx_msg, void *priv) if ((avail_emptybuff > HIGH_WATERMARK) && (!pshm_drv->tx_empty_available)) { pshm_drv->tx_empty_available = 1; + queue_work(pshm_drv->pshm_flow_ctrl_workqueue, + &pshm_drv->shm_flow_on_work); spin_unlock_irqrestore(&pshm_drv->lock, flags); - pshm_drv->cfdev.flowctrl - (pshm_drv->pshm_dev->pshm_netdev, - CAIF_FLOW_ON); - /* Schedule the work queue. if required */ if (!work_pending(&pshm_drv->shm_tx_work)) @@ -426,11 +445,8 @@ static void shm_tx_work_func(struct work_struct *tx_work) pshm_drv->tx_empty_available) { /* Update blocking condition. */ pshm_drv->tx_empty_available = 0; - spin_unlock_irqrestore(&pshm_drv->lock, flags); - pshm_drv->cfdev.flowctrl - (pshm_drv->pshm_dev->pshm_netdev, - CAIF_FLOW_OFF); - spin_lock_irqsave(&pshm_drv->lock, flags); + queue_work(pshm_drv->pshm_flow_ctrl_workqueue, + &pshm_drv->shm_flow_off_work); } /* * We simply return back to the caller if we do not have space @@ -621,11 +637,16 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev) INIT_WORK(&pshm_drv->shm_tx_work, shm_tx_work_func); INIT_WORK(&pshm_drv->shm_rx_work, shm_rx_work_func); + INIT_WORK(&pshm_drv->shm_flow_on_work, shm_flow_on_work_func); + INIT_WORK(&pshm_drv->shm_flow_off_work, shm_flow_off_work_func); pshm_drv->pshm_tx_workqueue = create_singlethread_workqueue("shm_tx_work"); pshm_drv->pshm_rx_workqueue = create_singlethread_workqueue("shm_rx_work"); + pshm_drv->pshm_flow_ctrl_workqueue = + create_singlethread_workqueue( + "shm_caif_flow_ctrl_work"); for (j = 0; j < NR_TX_BUF; j++) { struct buf_list *tx_buf = @@ -744,6 +765,7 @@ void caif_shmcore_remove(struct net_device *pshm_netdev) /* Destroy work queues. */ destroy_workqueue(pshm_drv->pshm_tx_workqueue); destroy_workqueue(pshm_drv->pshm_rx_workqueue); + destroy_workqueue(pshm_drv->pshm_flow_ctrl_workqueue); unregister_netdev(pshm_netdev); } -- cgit v1.2.3 From 2495f3141b952fe084675acc7c24d41dfcd2d184 Mon Sep 17 00:00:00 2001 From: Arun Murthy Date: Fri, 16 Dec 2011 11:30:35 +0530 Subject: caif-shmcore: increase the priority of flow control wq replace work queue with kthread workqueue for which the priority can be increased. Priority has to be increased, because ideally there the control information on flow ctrl i.e ON or OFF should reach caif with no delay. ST-Ericsson Linux next: NA ST-Ericsson ID: 372652 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I7a148b3277bcc885ade810df12b47c609a631e21 Signed-off-by: Arun Murthy Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/42835 Reviewed-by: Hemant-vilas RAMDASI Reviewed-by: QABUILD Reviewed-by: QATEST Reviewed-by: Sjur BRENDELAND Reviewed-by: Srinidhi KASAGAR --- drivers/net/caif/caif_shmcore.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c index 7bd35e0c18b..2cdae3fc158 100644 --- a/drivers/net/caif/caif_shmcore.c +++ b/drivers/net/caif/caif_shmcore.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -106,12 +107,14 @@ struct shmdrv_layer { struct workqueue_struct *pshm_tx_workqueue; struct workqueue_struct *pshm_rx_workqueue; - struct workqueue_struct *pshm_flow_ctrl_workqueue; + + struct kthread_worker pshm_flow_ctrl_kw; + struct task_struct *pshm_flow_ctrl_kw_task; struct work_struct shm_tx_work; struct work_struct shm_rx_work; - struct work_struct shm_flow_on_work; - struct work_struct shm_flow_off_work; + struct kthread_work shm_flow_on_work; + struct kthread_work shm_flow_off_work; struct sk_buff_head sk_qhead; struct shmdev_layer *pshm_dev; @@ -129,7 +132,7 @@ static int shm_netdev_close(struct net_device *shm_netdev) return 0; } -static void shm_flow_on_work_func(struct work_struct *work) +static void shm_flow_on_work_func(struct kthread_work *work) { struct shmdrv_layer *pshm_drv = container_of(work, struct shmdrv_layer, shm_flow_on_work); @@ -138,7 +141,7 @@ static void shm_flow_on_work_func(struct work_struct *work) CAIF_FLOW_ON); } -static void shm_flow_off_work_func(struct work_struct *work) +static void shm_flow_off_work_func(struct kthread_work *work) { struct shmdrv_layer *pshm_drv = container_of(work, struct shmdrv_layer, shm_flow_off_work); @@ -259,7 +262,7 @@ int caif_shmdrv_rx_cb(u32 mbx_msg, void *priv) if ((avail_emptybuff > HIGH_WATERMARK) && (!pshm_drv->tx_empty_available)) { pshm_drv->tx_empty_available = 1; - queue_work(pshm_drv->pshm_flow_ctrl_workqueue, + queue_kthread_work(&pshm_drv->pshm_flow_ctrl_kw, &pshm_drv->shm_flow_on_work); spin_unlock_irqrestore(&pshm_drv->lock, flags); @@ -445,7 +448,7 @@ static void shm_tx_work_func(struct work_struct *tx_work) pshm_drv->tx_empty_available) { /* Update blocking condition. */ pshm_drv->tx_empty_available = 0; - queue_work(pshm_drv->pshm_flow_ctrl_workqueue, + queue_kthread_work(&pshm_drv->pshm_flow_ctrl_kw, &pshm_drv->shm_flow_off_work); } /* @@ -578,6 +581,7 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev) { int result, j; struct shmdrv_layer *pshm_drv = NULL; + struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; pshm_dev->pshm_netdev = alloc_netdev(sizeof(struct shmdrv_layer), "cfshm%d", shm_netdev_setup); @@ -637,16 +641,20 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev) INIT_WORK(&pshm_drv->shm_tx_work, shm_tx_work_func); INIT_WORK(&pshm_drv->shm_rx_work, shm_rx_work_func); - INIT_WORK(&pshm_drv->shm_flow_on_work, shm_flow_on_work_func); - INIT_WORK(&pshm_drv->shm_flow_off_work, shm_flow_off_work_func); + + init_kthread_work(&pshm_drv->shm_flow_on_work, shm_flow_on_work_func); + init_kthread_work(&pshm_drv->shm_flow_off_work, shm_flow_off_work_func); pshm_drv->pshm_tx_workqueue = create_singlethread_workqueue("shm_tx_work"); pshm_drv->pshm_rx_workqueue = create_singlethread_workqueue("shm_rx_work"); - pshm_drv->pshm_flow_ctrl_workqueue = - create_singlethread_workqueue( - "shm_caif_flow_ctrl_work"); + + init_kthread_worker(&pshm_drv->pshm_flow_ctrl_kw); + pshm_drv->pshm_flow_ctrl_kw_task = kthread_run(kthread_worker_fn, + &pshm_drv->pshm_flow_ctrl_kw, "pshm_caif_flow_ctrl"); + /* must use the FIFO scheduler as it is realtime sensitive */ + sched_setscheduler(pshm_drv->pshm_flow_ctrl_kw_task, SCHED_FIFO, ¶m); for (j = 0; j < NR_TX_BUF; j++) { struct buf_list *tx_buf = @@ -765,7 +773,8 @@ void caif_shmcore_remove(struct net_device *pshm_netdev) /* Destroy work queues. */ destroy_workqueue(pshm_drv->pshm_tx_workqueue); destroy_workqueue(pshm_drv->pshm_rx_workqueue); - destroy_workqueue(pshm_drv->pshm_flow_ctrl_workqueue); + flush_kthread_worker(&pshm_drv->pshm_flow_ctrl_kw); + kthread_stop(pshm_drv->pshm_flow_ctrl_kw_task); unregister_netdev(pshm_netdev); } -- cgit v1.2.3 From 2226b173a9085faf3da513181c7e177cc7c66db1 Mon Sep 17 00:00:00 2001 From: Arun Murthy Date: Wed, 21 Dec 2011 11:43:06 +0530 Subject: caif-shmcore: in tx check for buffer full condition There are 6 buffers and each buffer can be filled with 10 messages. The size of each buffer is 8k. In shm tx work function, 10 messages are written to the buffer, if the buffer gets filled during writing these 10 messages stop writing to buffer and use the next buffer. ST-Ericsson Linux next: NA ST-Ericsson ID: 375088 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I146d41e4e415c8ff96c605b4c20546ff7501442a Signed-off-by: Arun Murthy Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/43350 Reviewed-by: Durga Prasada Rao BATHINA Reviewed-by: QABUILD Reviewed-by: Sjur BRENDELAND --- drivers/net/caif/caif_shmcore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c index 2cdae3fc158..fc55bf65f1c 100644 --- a/drivers/net/caif/caif_shmcore.c +++ b/drivers/net/caif/caif_shmcore.c @@ -522,7 +522,8 @@ static void shm_tx_work_func(struct work_struct *tx_work) pbuf->frames++; pbuf->frm_ofs += frmlen + (frmlen % 32); - } while (pbuf->frames < SHM_MAX_FRMS_PER_BUF); + } while (pbuf->frames < SHM_MAX_FRMS_PER_BUF && + pbuf->frm_ofs < pbuf->len); /* Assign buffer as full. */ list_add_tail(&pbuf->list, &pshm_drv->tx_full_list); -- cgit v1.2.3