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

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

caif-hsi: Add RX flip buffer



Implement RX flip buffer in the cfhsi_rx_done function,
piggy-backed frames is also supported.
This gives a significant performance gain for CAIF over HSI.

Signed-off-by: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 576f3cc7
Loading
Loading
Loading
Loading
+103 −42
Original line number Diff line number Diff line
@@ -426,6 +426,35 @@ static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
	return xfer_sz;
}

static int cfhsi_rx_desc_len(struct cfhsi_desc *desc)
{
	int xfer_sz = 0;
	int nfrms = 0;
	u16 *plen;

	if ((desc->header & ~CFHSI_PIGGY_DESC) ||
			(desc->offset > CFHSI_MAX_EMB_FRM_SZ)) {

		pr_err("Invalid descriptor. %x %x\n", desc->header,
				desc->offset);
		return -EPROTO;
	}

	/* Calculate transfer length. */
	plen = desc->cffrm_len;
	while (nfrms < CFHSI_MAX_PKTS && *plen) {
		xfer_sz += *plen;
		plen++;
		nfrms++;
	}

	if (xfer_sz % 4) {
		pr_err("Invalid payload len: %d, ignored.\n", xfer_sz);
		return -EPROTO;
	}
	return xfer_sz;
}

static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
{
	int rx_sz = 0;
@@ -517,8 +546,10 @@ static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
static void cfhsi_rx_done(struct cfhsi *cfhsi)
{
	int res;
	int desc_pld_len = 0;
	int desc_pld_len = 0, rx_len, rx_state;
	struct cfhsi_desc *desc = NULL;
	u8 *rx_ptr, *rx_buf;
	struct cfhsi_desc *piggy_desc = NULL;

	desc = (struct cfhsi_desc *)cfhsi->rx_buf;

@@ -534,65 +565,71 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
	spin_unlock_bh(&cfhsi->lock);

	if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) {
		desc_pld_len = cfhsi_rx_desc(desc, cfhsi);
		if (desc_pld_len == -ENOMEM)
			goto restart;
		if (desc_pld_len == -EPROTO)
			goto out_of_sync;
	} else {
		int pld_len;
		desc_pld_len = cfhsi_rx_desc_len(desc);

		if (!cfhsi->rx_state.piggy_desc) {
			pld_len = cfhsi_rx_pld(desc, cfhsi);
			if (pld_len == -ENOMEM)
				goto restart;
			if (pld_len == -EPROTO)
		if (desc_pld_len < 0)
			goto out_of_sync;
			cfhsi->rx_state.pld_len = pld_len;

		rx_buf = cfhsi->rx_buf;
		rx_len = desc_pld_len;
		if (desc_pld_len > 0 && (desc->header & CFHSI_PIGGY_DESC))
			rx_len += CFHSI_DESC_SZ;
		if (desc_pld_len == 0)
			rx_buf = cfhsi->rx_flip_buf;
	} else {
			pld_len = cfhsi->rx_state.pld_len;
		}
		rx_buf = cfhsi->rx_flip_buf;

		rx_len = CFHSI_DESC_SZ;
		if (cfhsi->rx_state.pld_len > 0 &&
				(desc->header & CFHSI_PIGGY_DESC)) {

		if ((pld_len > 0) && (desc->header & CFHSI_PIGGY_DESC)) {
			struct cfhsi_desc *piggy_desc;
			piggy_desc = (struct cfhsi_desc *)
				(desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ +
						pld_len);
						cfhsi->rx_state.pld_len);

			cfhsi->rx_state.piggy_desc = true;

			/* Extract piggy-backed descriptor. */
			desc_pld_len = cfhsi_rx_desc(piggy_desc, cfhsi);
			if (desc_pld_len == -ENOMEM)
				goto restart;
			/* Extract payload len from piggy-backed descriptor. */
			desc_pld_len = cfhsi_rx_desc_len(piggy_desc);
			if (desc_pld_len < 0)
				goto out_of_sync;

			if (desc_pld_len > 0)
				rx_len = desc_pld_len;

			if (desc_pld_len > 0 &&
					(piggy_desc->header & CFHSI_PIGGY_DESC))
				rx_len += CFHSI_DESC_SZ;

			/*
			 * Copy needed information from the piggy-backed
			 * descriptor to the descriptor in the start.
			 */
			memcpy((u8 *)desc, (u8 *)piggy_desc,
			memcpy(rx_buf, (u8 *)piggy_desc,
					CFHSI_DESC_SHORT_SZ);

			/* Mark no embedded frame here */
			piggy_desc->offset = 0;
			if (desc_pld_len == -EPROTO)
				goto out_of_sync;
		}
	}

	memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state));
	if (desc_pld_len) {
		cfhsi->rx_state.state = CFHSI_RX_STATE_PAYLOAD;
		cfhsi->rx_ptr = cfhsi->rx_buf + CFHSI_DESC_SZ;
		cfhsi->rx_len = desc_pld_len;
		rx_state = CFHSI_RX_STATE_PAYLOAD;
		rx_ptr = rx_buf + CFHSI_DESC_SZ;
	} else {
		cfhsi->rx_state.state = CFHSI_RX_STATE_DESC;
		cfhsi->rx_ptr = cfhsi->rx_buf;
		cfhsi->rx_len = CFHSI_DESC_SZ;
		rx_state = CFHSI_RX_STATE_DESC;
		rx_ptr = rx_buf;
		rx_len = CFHSI_DESC_SZ;
	}

	/* Initiate next read */
	if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) {
		/* Set up new transfer. */
		dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n",
				__func__);
		res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len,

		res = cfhsi->dev->cfhsi_rx(rx_ptr, rx_len,
				cfhsi->dev);
		if (WARN_ON(res < 0)) {
			dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n",
@@ -601,16 +638,32 @@ static void cfhsi_rx_done(struct cfhsi *cfhsi)
			cfhsi->ndev->stats.rx_dropped++;
		}
	}
	return;

restart:
	if (++cfhsi->rx_state.retries > CFHSI_MAX_RX_RETRIES) {
		dev_err(&cfhsi->ndev->dev, "%s: No memory available "
			"in %d iterations.\n",
			__func__, CFHSI_MAX_RX_RETRIES);
		BUG();
	if (cfhsi->rx_state.state == CFHSI_RX_STATE_DESC) {
		/* Extract payload from descriptor */
		if (cfhsi_rx_desc(desc, cfhsi) < 0)
			goto out_of_sync;
	} else {
		/* Extract payload */
		if (cfhsi_rx_pld(desc, cfhsi) < 0)
			goto out_of_sync;
		if (piggy_desc) {
			/* Extract any payload in piggyback descriptor. */
			if (cfhsi_rx_desc(piggy_desc, cfhsi) < 0)
				goto out_of_sync;
		}
	mod_timer(&cfhsi->rx_slowpath_timer, jiffies + 1);
	}

	/* Update state info */
	memset(&cfhsi->rx_state, 0, sizeof(cfhsi->rx_state));
	cfhsi->rx_state.state = rx_state;
	cfhsi->rx_ptr = rx_ptr;
	cfhsi->rx_len = rx_len;
	cfhsi->rx_state.pld_len = desc_pld_len;
	cfhsi->rx_state.piggy_desc = desc->header & CFHSI_PIGGY_DESC;

	if (rx_buf != cfhsi->rx_buf)
		swap(cfhsi->rx_buf, cfhsi->rx_flip_buf);
	return;

out_of_sync:
@@ -1040,6 +1093,12 @@ int cfhsi_probe(struct platform_device *pdev)
		goto err_alloc_rx;
	}

	cfhsi->rx_flip_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL);
	if (!cfhsi->rx_flip_buf) {
		res = -ENODEV;
		goto err_alloc_rx_flip;
	}

	/* Pre-calculate inactivity timeout. */
	if (inactivity_timeout != -1) {
		cfhsi->inactivity_timeout =
@@ -1138,6 +1197,8 @@ int cfhsi_probe(struct platform_device *pdev)
 err_activate:
	destroy_workqueue(cfhsi->wq);
 err_create_wq:
	kfree(cfhsi->rx_flip_buf);
 err_alloc_rx_flip:
	kfree(cfhsi->rx_buf);
 err_alloc_rx:
	kfree(cfhsi->tx_buf);
+1 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ struct cfhsi {
	u8 *rx_ptr;
	u8 *tx_buf;
	u8 *rx_buf;
	u8 *rx_flip_buf;
	spinlock_t lock;
	int flow_off_sent;
	u32 q_low_mark;