Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 095d2a71 authored by sjur.brandeland@stericsson.com's avatar sjur.brandeland@stericsson.com Committed by David S. Miller
Browse files

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: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 005b0b07
Loading
Loading
Loading
Loading
+11 −10
Original line number Diff line number Diff line
@@ -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);