caif-shm: Bugfixes for caif_shmcore.c
Various bugfixes for caif_shmcore.c: - fix deadlocks due to improper usage of spin-lock - add missing spin-lock init - don't call dev_kfree_skb() with irqs disabled, use dev_kfree_skb_irq() instead. - fix potential skb null pointer de-reference. Squashed original patches from: Rabin Vincent <rabin.vincent@stericsson.com> Durga Prasada Rao BATHINA <durgaprasadarao.b@stericcson.com> Arun Murthy <arun.murthy@stericsson.com> Bibek Basu <bibek.basu@stericsson.com> Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
005b0b076f
Коммит
095d2a71e5
|
@ -238,11 +238,11 @@ 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;
|
||||
spin_unlock_irqrestore(&pshm_drv->lock, flags);
|
||||
pshm_drv->cfdev.flowctrl
|
||||
(pshm_drv->pshm_dev->pshm_netdev,
|
||||
CAIF_FLOW_ON);
|
||||
|
||||
spin_unlock_irqrestore(&pshm_drv->lock, flags);
|
||||
|
||||
/* Schedule the work queue. if required */
|
||||
if (!work_pending(&pshm_drv->shm_tx_work))
|
||||
|
@ -285,6 +285,7 @@ static void shm_rx_work_func(struct work_struct *rx_work)
|
|||
list_entry(pshm_drv->rx_full_list.next, struct buf_list,
|
||||
list);
|
||||
list_del_init(&pbuf->list);
|
||||
spin_unlock_irqrestore(&pshm_drv->lock, flags);
|
||||
|
||||
/* Retrieve pointer to start of the packet descriptor area. */
|
||||
pck_desc = (struct shm_pck_desc *) pbuf->desc_vptr;
|
||||
|
@ -360,6 +361,7 @@ static void shm_rx_work_func(struct work_struct *rx_work)
|
|||
pck_desc++;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pshm_drv->lock, flags);
|
||||
list_add_tail(&pbuf->list, &pshm_drv->rx_pend_list);
|
||||
|
||||
spin_unlock_irqrestore(&pshm_drv->lock, flags);
|
||||
|
@ -412,7 +414,6 @@ static void shm_tx_work_func(struct work_struct *tx_work)
|
|||
|
||||
if (skb == NULL)
|
||||
goto send_msg;
|
||||
|
||||
/* Check the available no. of buffers in the empty list */
|
||||
list_for_each(pos, &pshm_drv->tx_empty_list)
|
||||
avail_emptybuff++;
|
||||
|
@ -421,9 +422,11 @@ 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);
|
||||
}
|
||||
/*
|
||||
* We simply return back to the caller if we do not have space
|
||||
|
@ -469,6 +472,8 @@ static void shm_tx_work_func(struct work_struct *tx_work)
|
|||
}
|
||||
|
||||
skb = skb_dequeue(&pshm_drv->sk_qhead);
|
||||
if (skb == NULL)
|
||||
break;
|
||||
/* Copy in CAIF frame. */
|
||||
skb_copy_bits(skb, 0, pbuf->desc_vptr +
|
||||
pbuf->frm_ofs + SHM_HDR_LEN +
|
||||
|
@ -477,7 +482,7 @@ static void shm_tx_work_func(struct work_struct *tx_work)
|
|||
pshm_drv->pshm_dev->pshm_netdev->stats.tx_packets++;
|
||||
pshm_drv->pshm_dev->pshm_netdev->stats.tx_bytes +=
|
||||
frmlen;
|
||||
dev_kfree_skb(skb);
|
||||
dev_kfree_skb_irq(skb);
|
||||
|
||||
/* Fill in the shared memory packet descriptor area. */
|
||||
pck_desc = (struct shm_pck_desc *) (pbuf->desc_vptr);
|
||||
|
@ -512,16 +517,11 @@ send_msg:
|
|||
static int shm_netdev_tx(struct sk_buff *skb, struct net_device *shm_netdev)
|
||||
{
|
||||
struct shmdrv_layer *pshm_drv;
|
||||
unsigned long flags = 0;
|
||||
|
||||
pshm_drv = netdev_priv(shm_netdev);
|
||||
|
||||
spin_lock_irqsave(&pshm_drv->lock, flags);
|
||||
|
||||
skb_queue_tail(&pshm_drv->sk_qhead, skb);
|
||||
|
||||
spin_unlock_irqrestore(&pshm_drv->lock, flags);
|
||||
|
||||
/* Schedule Tx work queue. for deferred processing of skbs*/
|
||||
if (!work_pending(&pshm_drv->shm_tx_work))
|
||||
queue_work(pshm_drv->pshm_tx_workqueue, &pshm_drv->shm_tx_work);
|
||||
|
@ -606,6 +606,7 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev)
|
|||
pshm_drv->shm_rx_addr = pshm_dev->shm_base_addr +
|
||||
(NR_TX_BUF * TX_BUF_SZ);
|
||||
|
||||
spin_lock_init(&pshm_drv->lock);
|
||||
INIT_LIST_HEAD(&pshm_drv->tx_empty_list);
|
||||
INIT_LIST_HEAD(&pshm_drv->tx_pend_list);
|
||||
INIT_LIST_HEAD(&pshm_drv->tx_full_list);
|
||||
|
@ -640,7 +641,7 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev)
|
|||
tx_buf->frm_ofs = SHM_CAIF_FRM_OFS;
|
||||
|
||||
if (pshm_dev->shm_loopback)
|
||||
tx_buf->desc_vptr = (char *)tx_buf->phy_addr;
|
||||
tx_buf->desc_vptr = (unsigned char *)tx_buf->phy_addr;
|
||||
else
|
||||
tx_buf->desc_vptr =
|
||||
ioremap(tx_buf->phy_addr, TX_BUF_SZ);
|
||||
|
@ -664,7 +665,7 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev)
|
|||
rx_buf->len = RX_BUF_SZ;
|
||||
|
||||
if (pshm_dev->shm_loopback)
|
||||
rx_buf->desc_vptr = (char *)rx_buf->phy_addr;
|
||||
rx_buf->desc_vptr = (unsigned char *)rx_buf->phy_addr;
|
||||
else
|
||||
rx_buf->desc_vptr =
|
||||
ioremap(rx_buf->phy_addr, RX_BUF_SZ);
|
||||
|
|
Загрузка…
Ссылка в новой задаче