1862cd659SVeerasenareddy Burru // SPDX-License-Identifier: GPL-2.0
2862cd659SVeerasenareddy Burru /* Marvell Octeon EP (EndPoint) Ethernet Driver
3862cd659SVeerasenareddy Burru  *
4862cd659SVeerasenareddy Burru  * Copyright (C) 2020 Marvell.
5862cd659SVeerasenareddy Burru  *
6862cd659SVeerasenareddy Burru  */
7862cd659SVeerasenareddy Burru 
8862cd659SVeerasenareddy Burru #include <linux/pci.h>
9862cd659SVeerasenareddy Burru #include <linux/etherdevice.h>
10397dfb57SVeerasenareddy Burru #include <linux/vmalloc.h>
11862cd659SVeerasenareddy Burru 
12862cd659SVeerasenareddy Burru #include "octep_config.h"
13862cd659SVeerasenareddy Burru #include "octep_main.h"
14862cd659SVeerasenareddy Burru 
octep_oq_reset_indices(struct octep_oq * oq)15397dfb57SVeerasenareddy Burru static void octep_oq_reset_indices(struct octep_oq *oq)
16397dfb57SVeerasenareddy Burru {
17397dfb57SVeerasenareddy Burru 	oq->host_read_idx = 0;
18397dfb57SVeerasenareddy Burru 	oq->host_refill_idx = 0;
19397dfb57SVeerasenareddy Burru 	oq->refill_count = 0;
20397dfb57SVeerasenareddy Burru 	oq->last_pkt_count = 0;
21397dfb57SVeerasenareddy Burru 	oq->pkts_pending = 0;
22397dfb57SVeerasenareddy Burru }
23397dfb57SVeerasenareddy Burru 
24397dfb57SVeerasenareddy Burru /**
25397dfb57SVeerasenareddy Burru  * octep_oq_fill_ring_buffers() - fill initial receive buffers for Rx ring.
26397dfb57SVeerasenareddy Burru  *
27397dfb57SVeerasenareddy Burru  * @oq: Octeon Rx queue data structure.
28397dfb57SVeerasenareddy Burru  *
29397dfb57SVeerasenareddy Burru  * Return: 0, if successfully filled receive buffers for all descriptors.
30397dfb57SVeerasenareddy Burru  *         -1, if failed to allocate a buffer or failed to map for DMA.
31397dfb57SVeerasenareddy Burru  */
octep_oq_fill_ring_buffers(struct octep_oq * oq)32397dfb57SVeerasenareddy Burru static int octep_oq_fill_ring_buffers(struct octep_oq *oq)
33397dfb57SVeerasenareddy Burru {
34397dfb57SVeerasenareddy Burru 	struct octep_oq_desc_hw *desc_ring = oq->desc_ring;
35397dfb57SVeerasenareddy Burru 	struct page *page;
36397dfb57SVeerasenareddy Burru 	u32 i;
37397dfb57SVeerasenareddy Burru 
38397dfb57SVeerasenareddy Burru 	for (i = 0; i < oq->max_count; i++) {
39397dfb57SVeerasenareddy Burru 		page = dev_alloc_page();
40397dfb57SVeerasenareddy Burru 		if (unlikely(!page)) {
41397dfb57SVeerasenareddy Burru 			dev_err(oq->dev, "Rx buffer alloc failed\n");
42397dfb57SVeerasenareddy Burru 			goto rx_buf_alloc_err;
43397dfb57SVeerasenareddy Burru 		}
44397dfb57SVeerasenareddy Burru 		desc_ring[i].buffer_ptr = dma_map_page(oq->dev, page, 0,
45397dfb57SVeerasenareddy Burru 						       PAGE_SIZE,
46397dfb57SVeerasenareddy Burru 						       DMA_FROM_DEVICE);
47397dfb57SVeerasenareddy Burru 		if (dma_mapping_error(oq->dev, desc_ring[i].buffer_ptr)) {
48397dfb57SVeerasenareddy Burru 			dev_err(oq->dev,
49397dfb57SVeerasenareddy Burru 				"OQ-%d buffer alloc: DMA mapping error!\n",
50397dfb57SVeerasenareddy Burru 				oq->q_no);
51397dfb57SVeerasenareddy Burru 			put_page(page);
52397dfb57SVeerasenareddy Burru 			goto dma_map_err;
53397dfb57SVeerasenareddy Burru 		}
54397dfb57SVeerasenareddy Burru 		oq->buff_info[i].page = page;
55397dfb57SVeerasenareddy Burru 	}
56397dfb57SVeerasenareddy Burru 
57397dfb57SVeerasenareddy Burru 	return 0;
58397dfb57SVeerasenareddy Burru 
59397dfb57SVeerasenareddy Burru dma_map_err:
60397dfb57SVeerasenareddy Burru rx_buf_alloc_err:
61397dfb57SVeerasenareddy Burru 	while (i) {
62397dfb57SVeerasenareddy Burru 		i--;
63397dfb57SVeerasenareddy Burru 		dma_unmap_page(oq->dev, desc_ring[i].buffer_ptr, PAGE_SIZE, DMA_FROM_DEVICE);
64397dfb57SVeerasenareddy Burru 		put_page(oq->buff_info[i].page);
65397dfb57SVeerasenareddy Burru 		oq->buff_info[i].page = NULL;
66397dfb57SVeerasenareddy Burru 	}
67397dfb57SVeerasenareddy Burru 
68397dfb57SVeerasenareddy Burru 	return -1;
69397dfb57SVeerasenareddy Burru }
70397dfb57SVeerasenareddy Burru 
71397dfb57SVeerasenareddy Burru /**
7237d79d05SVeerasenareddy Burru  * octep_oq_refill() - refill buffers for used Rx ring descriptors.
7337d79d05SVeerasenareddy Burru  *
7437d79d05SVeerasenareddy Burru  * @oct: Octeon device private data structure.
7537d79d05SVeerasenareddy Burru  * @oq: Octeon Rx queue data structure.
7637d79d05SVeerasenareddy Burru  *
7737d79d05SVeerasenareddy Burru  * Return: number of descriptors successfully refilled with receive buffers.
7837d79d05SVeerasenareddy Burru  */
octep_oq_refill(struct octep_device * oct,struct octep_oq * oq)7937d79d05SVeerasenareddy Burru static int octep_oq_refill(struct octep_device *oct, struct octep_oq *oq)
8037d79d05SVeerasenareddy Burru {
8137d79d05SVeerasenareddy Burru 	struct octep_oq_desc_hw *desc_ring = oq->desc_ring;
8237d79d05SVeerasenareddy Burru 	struct page *page;
8337d79d05SVeerasenareddy Burru 	u32 refill_idx, i;
8437d79d05SVeerasenareddy Burru 
8537d79d05SVeerasenareddy Burru 	refill_idx = oq->host_refill_idx;
8637d79d05SVeerasenareddy Burru 	for (i = 0; i < oq->refill_count; i++) {
8737d79d05SVeerasenareddy Burru 		page = dev_alloc_page();
8837d79d05SVeerasenareddy Burru 		if (unlikely(!page)) {
8937d79d05SVeerasenareddy Burru 			dev_err(oq->dev, "refill: rx buffer alloc failed\n");
9037d79d05SVeerasenareddy Burru 			oq->stats.alloc_failures++;
9137d79d05SVeerasenareddy Burru 			break;
9237d79d05SVeerasenareddy Burru 		}
9337d79d05SVeerasenareddy Burru 
9437d79d05SVeerasenareddy Burru 		desc_ring[refill_idx].buffer_ptr = dma_map_page(oq->dev, page, 0,
9537d79d05SVeerasenareddy Burru 								PAGE_SIZE, DMA_FROM_DEVICE);
9637d79d05SVeerasenareddy Burru 		if (dma_mapping_error(oq->dev, desc_ring[refill_idx].buffer_ptr)) {
9737d79d05SVeerasenareddy Burru 			dev_err(oq->dev,
9837d79d05SVeerasenareddy Burru 				"OQ-%d buffer refill: DMA mapping error!\n",
9937d79d05SVeerasenareddy Burru 				oq->q_no);
10037d79d05SVeerasenareddy Burru 			put_page(page);
10137d79d05SVeerasenareddy Burru 			oq->stats.alloc_failures++;
10237d79d05SVeerasenareddy Burru 			break;
10337d79d05SVeerasenareddy Burru 		}
10437d79d05SVeerasenareddy Burru 		oq->buff_info[refill_idx].page = page;
10537d79d05SVeerasenareddy Burru 		refill_idx++;
10637d79d05SVeerasenareddy Burru 		if (refill_idx == oq->max_count)
10737d79d05SVeerasenareddy Burru 			refill_idx = 0;
10837d79d05SVeerasenareddy Burru 	}
10937d79d05SVeerasenareddy Burru 	oq->host_refill_idx = refill_idx;
11037d79d05SVeerasenareddy Burru 	oq->refill_count -= i;
11137d79d05SVeerasenareddy Burru 
11237d79d05SVeerasenareddy Burru 	return i;
11337d79d05SVeerasenareddy Burru }
11437d79d05SVeerasenareddy Burru 
11537d79d05SVeerasenareddy Burru /**
116397dfb57SVeerasenareddy Burru  * octep_setup_oq() - Setup a Rx queue.
117397dfb57SVeerasenareddy Burru  *
118397dfb57SVeerasenareddy Burru  * @oct: Octeon device private data structure.
119397dfb57SVeerasenareddy Burru  * @q_no: Rx queue number to be setup.
120397dfb57SVeerasenareddy Burru  *
121397dfb57SVeerasenareddy Burru  * Allocate resources for a Rx queue.
122397dfb57SVeerasenareddy Burru  */
octep_setup_oq(struct octep_device * oct,int q_no)123397dfb57SVeerasenareddy Burru static int octep_setup_oq(struct octep_device *oct, int q_no)
124397dfb57SVeerasenareddy Burru {
125397dfb57SVeerasenareddy Burru 	struct octep_oq *oq;
126397dfb57SVeerasenareddy Burru 	u32 desc_ring_size;
127397dfb57SVeerasenareddy Burru 
128397dfb57SVeerasenareddy Burru 	oq = vzalloc(sizeof(*oq));
129397dfb57SVeerasenareddy Burru 	if (!oq)
130397dfb57SVeerasenareddy Burru 		goto create_oq_fail;
131397dfb57SVeerasenareddy Burru 	oct->oq[q_no] = oq;
132397dfb57SVeerasenareddy Burru 
133397dfb57SVeerasenareddy Burru 	oq->octep_dev = oct;
134397dfb57SVeerasenareddy Burru 	oq->netdev = oct->netdev;
135397dfb57SVeerasenareddy Burru 	oq->dev = &oct->pdev->dev;
136397dfb57SVeerasenareddy Burru 	oq->q_no = q_no;
137397dfb57SVeerasenareddy Burru 	oq->max_count = CFG_GET_OQ_NUM_DESC(oct->conf);
138397dfb57SVeerasenareddy Burru 	oq->ring_size_mask = oq->max_count - 1;
139397dfb57SVeerasenareddy Burru 	oq->buffer_size = CFG_GET_OQ_BUF_SIZE(oct->conf);
140397dfb57SVeerasenareddy Burru 	oq->max_single_buffer_size = oq->buffer_size - OCTEP_OQ_RESP_HW_SIZE;
141397dfb57SVeerasenareddy Burru 
142397dfb57SVeerasenareddy Burru 	/* When the hardware/firmware supports additional capabilities,
143397dfb57SVeerasenareddy Burru 	 * additional header is filled-in by Octeon after length field in
144397dfb57SVeerasenareddy Burru 	 * Rx packets. this header contains additional packet information.
145397dfb57SVeerasenareddy Burru 	 */
146397dfb57SVeerasenareddy Burru 	if (oct->caps_enabled)
147397dfb57SVeerasenareddy Burru 		oq->max_single_buffer_size -= OCTEP_OQ_RESP_HW_EXT_SIZE;
148397dfb57SVeerasenareddy Burru 
149397dfb57SVeerasenareddy Burru 	oq->refill_threshold = CFG_GET_OQ_REFILL_THRESHOLD(oct->conf);
150397dfb57SVeerasenareddy Burru 
151397dfb57SVeerasenareddy Burru 	desc_ring_size = oq->max_count * OCTEP_OQ_DESC_SIZE;
152397dfb57SVeerasenareddy Burru 	oq->desc_ring = dma_alloc_coherent(oq->dev, desc_ring_size,
153397dfb57SVeerasenareddy Burru 					   &oq->desc_ring_dma, GFP_KERNEL);
154397dfb57SVeerasenareddy Burru 
155397dfb57SVeerasenareddy Burru 	if (unlikely(!oq->desc_ring)) {
156397dfb57SVeerasenareddy Burru 		dev_err(oq->dev,
157397dfb57SVeerasenareddy Burru 			"Failed to allocate DMA memory for OQ-%d !!\n", q_no);
158397dfb57SVeerasenareddy Burru 		goto desc_dma_alloc_err;
159397dfb57SVeerasenareddy Burru 	}
160397dfb57SVeerasenareddy Burru 
161*32d462a5SJulia Lawall 	oq->buff_info = vcalloc(oq->max_count, OCTEP_OQ_RECVBUF_SIZE);
162397dfb57SVeerasenareddy Burru 	if (unlikely(!oq->buff_info)) {
163397dfb57SVeerasenareddy Burru 		dev_err(&oct->pdev->dev,
164397dfb57SVeerasenareddy Burru 			"Failed to allocate buffer info for OQ-%d\n", q_no);
165397dfb57SVeerasenareddy Burru 		goto buf_list_err;
166397dfb57SVeerasenareddy Burru 	}
167397dfb57SVeerasenareddy Burru 
168397dfb57SVeerasenareddy Burru 	if (octep_oq_fill_ring_buffers(oq))
169397dfb57SVeerasenareddy Burru 		goto oq_fill_buff_err;
170397dfb57SVeerasenareddy Burru 
171397dfb57SVeerasenareddy Burru 	octep_oq_reset_indices(oq);
172397dfb57SVeerasenareddy Burru 	oct->hw_ops.setup_oq_regs(oct, q_no);
173397dfb57SVeerasenareddy Burru 	oct->num_oqs++;
174397dfb57SVeerasenareddy Burru 
175397dfb57SVeerasenareddy Burru 	return 0;
176397dfb57SVeerasenareddy Burru 
177397dfb57SVeerasenareddy Burru oq_fill_buff_err:
178397dfb57SVeerasenareddy Burru 	vfree(oq->buff_info);
179397dfb57SVeerasenareddy Burru 	oq->buff_info = NULL;
180397dfb57SVeerasenareddy Burru buf_list_err:
181397dfb57SVeerasenareddy Burru 	dma_free_coherent(oq->dev, desc_ring_size,
182397dfb57SVeerasenareddy Burru 			  oq->desc_ring, oq->desc_ring_dma);
183397dfb57SVeerasenareddy Burru 	oq->desc_ring = NULL;
184397dfb57SVeerasenareddy Burru desc_dma_alloc_err:
185397dfb57SVeerasenareddy Burru 	vfree(oq);
186397dfb57SVeerasenareddy Burru 	oct->oq[q_no] = NULL;
187397dfb57SVeerasenareddy Burru create_oq_fail:
188397dfb57SVeerasenareddy Burru 	return -1;
189397dfb57SVeerasenareddy Burru }
190397dfb57SVeerasenareddy Burru 
191397dfb57SVeerasenareddy Burru /**
192397dfb57SVeerasenareddy Burru  * octep_oq_free_ring_buffers() - Free ring buffers.
193397dfb57SVeerasenareddy Burru  *
194397dfb57SVeerasenareddy Burru  * @oq: Octeon Rx queue data structure.
195397dfb57SVeerasenareddy Burru  *
196397dfb57SVeerasenareddy Burru  * Free receive buffers in unused Rx queue descriptors.
197397dfb57SVeerasenareddy Burru  */
octep_oq_free_ring_buffers(struct octep_oq * oq)198397dfb57SVeerasenareddy Burru static void octep_oq_free_ring_buffers(struct octep_oq *oq)
199397dfb57SVeerasenareddy Burru {
200397dfb57SVeerasenareddy Burru 	struct octep_oq_desc_hw *desc_ring = oq->desc_ring;
201397dfb57SVeerasenareddy Burru 	int  i;
202397dfb57SVeerasenareddy Burru 
203397dfb57SVeerasenareddy Burru 	if (!oq->desc_ring || !oq->buff_info)
204397dfb57SVeerasenareddy Burru 		return;
205397dfb57SVeerasenareddy Burru 
206397dfb57SVeerasenareddy Burru 	for (i = 0; i < oq->max_count; i++)  {
207397dfb57SVeerasenareddy Burru 		if (oq->buff_info[i].page) {
208397dfb57SVeerasenareddy Burru 			dma_unmap_page(oq->dev, desc_ring[i].buffer_ptr,
209397dfb57SVeerasenareddy Burru 				       PAGE_SIZE, DMA_FROM_DEVICE);
210397dfb57SVeerasenareddy Burru 			put_page(oq->buff_info[i].page);
211397dfb57SVeerasenareddy Burru 			oq->buff_info[i].page = NULL;
212397dfb57SVeerasenareddy Burru 			desc_ring[i].buffer_ptr = 0;
213397dfb57SVeerasenareddy Burru 		}
214397dfb57SVeerasenareddy Burru 	}
215397dfb57SVeerasenareddy Burru 	octep_oq_reset_indices(oq);
216397dfb57SVeerasenareddy Burru }
217397dfb57SVeerasenareddy Burru 
218397dfb57SVeerasenareddy Burru /**
219397dfb57SVeerasenareddy Burru  * octep_free_oq() - Free Rx queue resources.
220397dfb57SVeerasenareddy Burru  *
221397dfb57SVeerasenareddy Burru  * @oq: Octeon Rx queue data structure.
222397dfb57SVeerasenareddy Burru  *
223397dfb57SVeerasenareddy Burru  * Free all resources of a Rx queue.
224397dfb57SVeerasenareddy Burru  */
octep_free_oq(struct octep_oq * oq)225397dfb57SVeerasenareddy Burru static int octep_free_oq(struct octep_oq *oq)
226397dfb57SVeerasenareddy Burru {
227397dfb57SVeerasenareddy Burru 	struct octep_device *oct = oq->octep_dev;
228397dfb57SVeerasenareddy Burru 	int q_no = oq->q_no;
229397dfb57SVeerasenareddy Burru 
230397dfb57SVeerasenareddy Burru 	octep_oq_free_ring_buffers(oq);
231397dfb57SVeerasenareddy Burru 
232397dfb57SVeerasenareddy Burru 	vfree(oq->buff_info);
233397dfb57SVeerasenareddy Burru 
234397dfb57SVeerasenareddy Burru 	if (oq->desc_ring)
235397dfb57SVeerasenareddy Burru 		dma_free_coherent(oq->dev,
236397dfb57SVeerasenareddy Burru 				  oq->max_count * OCTEP_OQ_DESC_SIZE,
237397dfb57SVeerasenareddy Burru 				  oq->desc_ring, oq->desc_ring_dma);
238397dfb57SVeerasenareddy Burru 
239397dfb57SVeerasenareddy Burru 	vfree(oq);
240397dfb57SVeerasenareddy Burru 	oct->oq[q_no] = NULL;
241397dfb57SVeerasenareddy Burru 	oct->num_oqs--;
242397dfb57SVeerasenareddy Burru 	return 0;
243397dfb57SVeerasenareddy Burru }
244397dfb57SVeerasenareddy Burru 
245862cd659SVeerasenareddy Burru /**
246862cd659SVeerasenareddy Burru  * octep_setup_oqs() - setup resources for all Rx queues.
247862cd659SVeerasenareddy Burru  *
248862cd659SVeerasenareddy Burru  * @oct: Octeon device private data structure.
249862cd659SVeerasenareddy Burru  */
octep_setup_oqs(struct octep_device * oct)250862cd659SVeerasenareddy Burru int octep_setup_oqs(struct octep_device *oct)
251862cd659SVeerasenareddy Burru {
252397dfb57SVeerasenareddy Burru 	int i, retval = 0;
253397dfb57SVeerasenareddy Burru 
254397dfb57SVeerasenareddy Burru 	oct->num_oqs = 0;
255397dfb57SVeerasenareddy Burru 	for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
256397dfb57SVeerasenareddy Burru 		retval = octep_setup_oq(oct, i);
257397dfb57SVeerasenareddy Burru 		if (retval) {
258397dfb57SVeerasenareddy Burru 			dev_err(&oct->pdev->dev,
259397dfb57SVeerasenareddy Burru 				"Failed to setup OQ(RxQ)-%d.\n", i);
260397dfb57SVeerasenareddy Burru 			goto oq_setup_err;
261397dfb57SVeerasenareddy Burru 		}
262397dfb57SVeerasenareddy Burru 		dev_dbg(&oct->pdev->dev, "Successfully setup OQ(RxQ)-%d.\n", i);
263397dfb57SVeerasenareddy Burru 	}
264397dfb57SVeerasenareddy Burru 
265397dfb57SVeerasenareddy Burru 	return 0;
266397dfb57SVeerasenareddy Burru 
267397dfb57SVeerasenareddy Burru oq_setup_err:
268397dfb57SVeerasenareddy Burru 	while (i) {
269397dfb57SVeerasenareddy Burru 		i--;
270397dfb57SVeerasenareddy Burru 		octep_free_oq(oct->oq[i]);
271397dfb57SVeerasenareddy Burru 	}
272862cd659SVeerasenareddy Burru 	return -1;
273862cd659SVeerasenareddy Burru }
274862cd659SVeerasenareddy Burru 
275862cd659SVeerasenareddy Burru /**
276862cd659SVeerasenareddy Burru  * octep_oq_dbell_init() - Initialize Rx queue doorbell.
277862cd659SVeerasenareddy Burru  *
278862cd659SVeerasenareddy Burru  * @oct: Octeon device private data structure.
279862cd659SVeerasenareddy Burru  *
280862cd659SVeerasenareddy Burru  * Write number of descriptors to Rx queue doorbell register.
281862cd659SVeerasenareddy Burru  */
octep_oq_dbell_init(struct octep_device * oct)282862cd659SVeerasenareddy Burru void octep_oq_dbell_init(struct octep_device *oct)
283862cd659SVeerasenareddy Burru {
284397dfb57SVeerasenareddy Burru 	int i;
285397dfb57SVeerasenareddy Burru 
286397dfb57SVeerasenareddy Burru 	for (i = 0; i < oct->num_oqs; i++)
287397dfb57SVeerasenareddy Burru 		writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg);
288862cd659SVeerasenareddy Burru }
289862cd659SVeerasenareddy Burru 
290862cd659SVeerasenareddy Burru /**
291862cd659SVeerasenareddy Burru  * octep_free_oqs() - Free resources of all Rx queues.
292862cd659SVeerasenareddy Burru  *
293862cd659SVeerasenareddy Burru  * @oct: Octeon device private data structure.
294862cd659SVeerasenareddy Burru  */
octep_free_oqs(struct octep_device * oct)295862cd659SVeerasenareddy Burru void octep_free_oqs(struct octep_device *oct)
296862cd659SVeerasenareddy Burru {
297397dfb57SVeerasenareddy Burru 	int i;
298397dfb57SVeerasenareddy Burru 
299397dfb57SVeerasenareddy Burru 	for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
300397dfb57SVeerasenareddy Burru 		if (!oct->oq[i])
301397dfb57SVeerasenareddy Burru 			continue;
302397dfb57SVeerasenareddy Burru 		octep_free_oq(oct->oq[i]);
303397dfb57SVeerasenareddy Burru 		dev_dbg(&oct->pdev->dev,
304397dfb57SVeerasenareddy Burru 			"Successfully freed OQ(RxQ)-%d.\n", i);
305397dfb57SVeerasenareddy Burru 	}
306862cd659SVeerasenareddy Burru }
30737d79d05SVeerasenareddy Burru 
30837d79d05SVeerasenareddy Burru /**
30937d79d05SVeerasenareddy Burru  * octep_oq_check_hw_for_pkts() - Check for new Rx packets.
31037d79d05SVeerasenareddy Burru  *
31137d79d05SVeerasenareddy Burru  * @oct: Octeon device private data structure.
31237d79d05SVeerasenareddy Burru  * @oq: Octeon Rx queue data structure.
31337d79d05SVeerasenareddy Burru  *
31437d79d05SVeerasenareddy Burru  * Return: packets received after previous check.
31537d79d05SVeerasenareddy Burru  */
octep_oq_check_hw_for_pkts(struct octep_device * oct,struct octep_oq * oq)31637d79d05SVeerasenareddy Burru static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
31737d79d05SVeerasenareddy Burru 				      struct octep_oq *oq)
31837d79d05SVeerasenareddy Burru {
31937d79d05SVeerasenareddy Burru 	u32 pkt_count, new_pkts;
32037d79d05SVeerasenareddy Burru 
32137d79d05SVeerasenareddy Burru 	pkt_count = readl(oq->pkts_sent_reg);
32237d79d05SVeerasenareddy Burru 	new_pkts = pkt_count - oq->last_pkt_count;
32337d79d05SVeerasenareddy Burru 
32437d79d05SVeerasenareddy Burru 	/* Clear the hardware packets counter register if the rx queue is
32537d79d05SVeerasenareddy Burru 	 * being processed continuously with-in a single interrupt and
32637d79d05SVeerasenareddy Burru 	 * reached half its max value.
32737d79d05SVeerasenareddy Burru 	 * this counter is not cleared every time read, to save write cycles.
32837d79d05SVeerasenareddy Burru 	 */
32937d79d05SVeerasenareddy Burru 	if (unlikely(pkt_count > 0xF0000000U)) {
33037d79d05SVeerasenareddy Burru 		writel(pkt_count, oq->pkts_sent_reg);
33137d79d05SVeerasenareddy Burru 		pkt_count = readl(oq->pkts_sent_reg);
33237d79d05SVeerasenareddy Burru 		new_pkts += pkt_count;
33337d79d05SVeerasenareddy Burru 	}
33437d79d05SVeerasenareddy Burru 	oq->last_pkt_count = pkt_count;
33537d79d05SVeerasenareddy Burru 	oq->pkts_pending += new_pkts;
33637d79d05SVeerasenareddy Burru 	return new_pkts;
33737d79d05SVeerasenareddy Burru }
33837d79d05SVeerasenareddy Burru 
33937d79d05SVeerasenareddy Burru /**
34037d79d05SVeerasenareddy Burru  * __octep_oq_process_rx() - Process hardware Rx queue and push to stack.
34137d79d05SVeerasenareddy Burru  *
34237d79d05SVeerasenareddy Burru  * @oct: Octeon device private data structure.
34337d79d05SVeerasenareddy Burru  * @oq: Octeon Rx queue data structure.
34437d79d05SVeerasenareddy Burru  * @pkts_to_process: number of packets to be processed.
34537d79d05SVeerasenareddy Burru  *
34637d79d05SVeerasenareddy Burru  * Process the new packets in Rx queue.
34737d79d05SVeerasenareddy Burru  * Packets larger than single Rx buffer arrive in consecutive descriptors.
34837d79d05SVeerasenareddy Burru  * But, count returned by the API only accounts full packets, not fragments.
34937d79d05SVeerasenareddy Burru  *
35037d79d05SVeerasenareddy Burru  * Return: number of packets processed and pushed to stack.
35137d79d05SVeerasenareddy Burru  */
__octep_oq_process_rx(struct octep_device * oct,struct octep_oq * oq,u16 pkts_to_process)35237d79d05SVeerasenareddy Burru static int __octep_oq_process_rx(struct octep_device *oct,
35337d79d05SVeerasenareddy Burru 				 struct octep_oq *oq, u16 pkts_to_process)
35437d79d05SVeerasenareddy Burru {
35537d79d05SVeerasenareddy Burru 	struct octep_oq_resp_hw_ext *resp_hw_ext = NULL;
35637d79d05SVeerasenareddy Burru 	struct octep_rx_buffer *buff_info;
35737d79d05SVeerasenareddy Burru 	struct octep_oq_resp_hw *resp_hw;
35837d79d05SVeerasenareddy Burru 	u32 pkt, rx_bytes, desc_used;
35937d79d05SVeerasenareddy Burru 	struct sk_buff *skb;
36037d79d05SVeerasenareddy Burru 	u16 data_offset;
36137d79d05SVeerasenareddy Burru 	u32 read_idx;
36237d79d05SVeerasenareddy Burru 
36337d79d05SVeerasenareddy Burru 	read_idx = oq->host_read_idx;
36437d79d05SVeerasenareddy Burru 	rx_bytes = 0;
36537d79d05SVeerasenareddy Burru 	desc_used = 0;
36637d79d05SVeerasenareddy Burru 	for (pkt = 0; pkt < pkts_to_process; pkt++) {
36737d79d05SVeerasenareddy Burru 		buff_info = (struct octep_rx_buffer *)&oq->buff_info[read_idx];
36837d79d05SVeerasenareddy Burru 		dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
36937d79d05SVeerasenareddy Burru 			       PAGE_SIZE, DMA_FROM_DEVICE);
37037d79d05SVeerasenareddy Burru 		resp_hw = page_address(buff_info->page);
37137d79d05SVeerasenareddy Burru 		buff_info->page = NULL;
37237d79d05SVeerasenareddy Burru 
37337d79d05SVeerasenareddy Burru 		/* Swap the length field that is in Big-Endian to CPU */
37437d79d05SVeerasenareddy Burru 		buff_info->len = be64_to_cpu(resp_hw->length);
37537d79d05SVeerasenareddy Burru 		if (oct->caps_enabled & OCTEP_CAP_RX_CHECKSUM) {
37637d79d05SVeerasenareddy Burru 			/* Extended response header is immediately after
37737d79d05SVeerasenareddy Burru 			 * response header (resp_hw)
37837d79d05SVeerasenareddy Burru 			 */
37937d79d05SVeerasenareddy Burru 			resp_hw_ext = (struct octep_oq_resp_hw_ext *)
38037d79d05SVeerasenareddy Burru 				      (resp_hw + 1);
38137d79d05SVeerasenareddy Burru 			buff_info->len -= OCTEP_OQ_RESP_HW_EXT_SIZE;
38237d79d05SVeerasenareddy Burru 			/* Packet Data is immediately after
38337d79d05SVeerasenareddy Burru 			 * extended response header.
38437d79d05SVeerasenareddy Burru 			 */
38537d79d05SVeerasenareddy Burru 			data_offset = OCTEP_OQ_RESP_HW_SIZE +
38637d79d05SVeerasenareddy Burru 				      OCTEP_OQ_RESP_HW_EXT_SIZE;
38737d79d05SVeerasenareddy Burru 		} else {
38837d79d05SVeerasenareddy Burru 			/* Data is immediately after
38937d79d05SVeerasenareddy Burru 			 * Hardware Rx response header.
39037d79d05SVeerasenareddy Burru 			 */
39137d79d05SVeerasenareddy Burru 			data_offset = OCTEP_OQ_RESP_HW_SIZE;
39237d79d05SVeerasenareddy Burru 		}
39337d79d05SVeerasenareddy Burru 		rx_bytes += buff_info->len;
39437d79d05SVeerasenareddy Burru 
39537d79d05SVeerasenareddy Burru 		if (buff_info->len <= oq->max_single_buffer_size) {
39637d79d05SVeerasenareddy Burru 			skb = build_skb((void *)resp_hw, PAGE_SIZE);
39737d79d05SVeerasenareddy Burru 			skb_reserve(skb, data_offset);
39837d79d05SVeerasenareddy Burru 			skb_put(skb, buff_info->len);
39937d79d05SVeerasenareddy Burru 			read_idx++;
40037d79d05SVeerasenareddy Burru 			desc_used++;
40137d79d05SVeerasenareddy Burru 			if (read_idx == oq->max_count)
40237d79d05SVeerasenareddy Burru 				read_idx = 0;
40337d79d05SVeerasenareddy Burru 		} else {
40437d79d05SVeerasenareddy Burru 			struct skb_shared_info *shinfo;
40537d79d05SVeerasenareddy Burru 			u16 data_len;
40637d79d05SVeerasenareddy Burru 
40737d79d05SVeerasenareddy Burru 			skb = build_skb((void *)resp_hw, PAGE_SIZE);
40837d79d05SVeerasenareddy Burru 			skb_reserve(skb, data_offset);
40937d79d05SVeerasenareddy Burru 			/* Head fragment includes response header(s);
41037d79d05SVeerasenareddy Burru 			 * subsequent fragments contains only data.
41137d79d05SVeerasenareddy Burru 			 */
41237d79d05SVeerasenareddy Burru 			skb_put(skb, oq->max_single_buffer_size);
41337d79d05SVeerasenareddy Burru 			read_idx++;
41437d79d05SVeerasenareddy Burru 			desc_used++;
41537d79d05SVeerasenareddy Burru 			if (read_idx == oq->max_count)
41637d79d05SVeerasenareddy Burru 				read_idx = 0;
41737d79d05SVeerasenareddy Burru 
41837d79d05SVeerasenareddy Burru 			shinfo = skb_shinfo(skb);
41937d79d05SVeerasenareddy Burru 			data_len = buff_info->len - oq->max_single_buffer_size;
42037d79d05SVeerasenareddy Burru 			while (data_len) {
42137d79d05SVeerasenareddy Burru 				dma_unmap_page(oq->dev, oq->desc_ring[read_idx].buffer_ptr,
42237d79d05SVeerasenareddy Burru 					       PAGE_SIZE, DMA_FROM_DEVICE);
42337d79d05SVeerasenareddy Burru 				buff_info = (struct octep_rx_buffer *)
42437d79d05SVeerasenareddy Burru 					    &oq->buff_info[read_idx];
42537d79d05SVeerasenareddy Burru 				if (data_len < oq->buffer_size) {
42637d79d05SVeerasenareddy Burru 					buff_info->len = data_len;
42737d79d05SVeerasenareddy Burru 					data_len = 0;
42837d79d05SVeerasenareddy Burru 				} else {
42937d79d05SVeerasenareddy Burru 					buff_info->len = oq->buffer_size;
43037d79d05SVeerasenareddy Burru 					data_len -= oq->buffer_size;
43137d79d05SVeerasenareddy Burru 				}
43237d79d05SVeerasenareddy Burru 
43337d79d05SVeerasenareddy Burru 				skb_add_rx_frag(skb, shinfo->nr_frags,
43437d79d05SVeerasenareddy Burru 						buff_info->page, 0,
43537d79d05SVeerasenareddy Burru 						buff_info->len,
43637d79d05SVeerasenareddy Burru 						buff_info->len);
43737d79d05SVeerasenareddy Burru 				buff_info->page = NULL;
43837d79d05SVeerasenareddy Burru 				read_idx++;
43937d79d05SVeerasenareddy Burru 				desc_used++;
44037d79d05SVeerasenareddy Burru 				if (read_idx == oq->max_count)
44137d79d05SVeerasenareddy Burru 					read_idx = 0;
44237d79d05SVeerasenareddy Burru 			}
44337d79d05SVeerasenareddy Burru 		}
44437d79d05SVeerasenareddy Burru 
44537d79d05SVeerasenareddy Burru 		skb->dev = oq->netdev;
44637d79d05SVeerasenareddy Burru 		skb->protocol =  eth_type_trans(skb, skb->dev);
44737d79d05SVeerasenareddy Burru 		if (resp_hw_ext &&
44837d79d05SVeerasenareddy Burru 		    resp_hw_ext->csum_verified == OCTEP_CSUM_VERIFIED)
44937d79d05SVeerasenareddy Burru 			skb->ip_summed = CHECKSUM_UNNECESSARY;
45037d79d05SVeerasenareddy Burru 		else
45137d79d05SVeerasenareddy Burru 			skb->ip_summed = CHECKSUM_NONE;
45237d79d05SVeerasenareddy Burru 		napi_gro_receive(oq->napi, skb);
45337d79d05SVeerasenareddy Burru 	}
45437d79d05SVeerasenareddy Burru 
45537d79d05SVeerasenareddy Burru 	oq->host_read_idx = read_idx;
45637d79d05SVeerasenareddy Burru 	oq->refill_count += desc_used;
45737d79d05SVeerasenareddy Burru 	oq->stats.packets += pkt;
45837d79d05SVeerasenareddy Burru 	oq->stats.bytes += rx_bytes;
45937d79d05SVeerasenareddy Burru 
46037d79d05SVeerasenareddy Burru 	return pkt;
46137d79d05SVeerasenareddy Burru }
46237d79d05SVeerasenareddy Burru 
46337d79d05SVeerasenareddy Burru /**
46437d79d05SVeerasenareddy Burru  * octep_oq_process_rx() - Process Rx queue.
46537d79d05SVeerasenareddy Burru  *
46637d79d05SVeerasenareddy Burru  * @oq: Octeon Rx queue data structure.
46737d79d05SVeerasenareddy Burru  * @budget: max number of packets can be processed in one invocation.
46837d79d05SVeerasenareddy Burru  *
46937d79d05SVeerasenareddy Burru  * Check for newly received packets and process them.
47037d79d05SVeerasenareddy Burru  * Keeps checking for new packets until budget is used or no new packets seen.
47137d79d05SVeerasenareddy Burru  *
47237d79d05SVeerasenareddy Burru  * Return: number of packets processed.
47337d79d05SVeerasenareddy Burru  */
octep_oq_process_rx(struct octep_oq * oq,int budget)47437d79d05SVeerasenareddy Burru int octep_oq_process_rx(struct octep_oq *oq, int budget)
47537d79d05SVeerasenareddy Burru {
47637d79d05SVeerasenareddy Burru 	u32 pkts_available, pkts_processed, total_pkts_processed;
47737d79d05SVeerasenareddy Burru 	struct octep_device *oct = oq->octep_dev;
47837d79d05SVeerasenareddy Burru 
47937d79d05SVeerasenareddy Burru 	pkts_available = 0;
48037d79d05SVeerasenareddy Burru 	pkts_processed = 0;
48137d79d05SVeerasenareddy Burru 	total_pkts_processed = 0;
48237d79d05SVeerasenareddy Burru 	while (total_pkts_processed < budget) {
48337d79d05SVeerasenareddy Burru 		 /* update pending count only when current one exhausted */
48437d79d05SVeerasenareddy Burru 		if (oq->pkts_pending == 0)
48537d79d05SVeerasenareddy Burru 			octep_oq_check_hw_for_pkts(oct, oq);
48637d79d05SVeerasenareddy Burru 		pkts_available = min(budget - total_pkts_processed,
48737d79d05SVeerasenareddy Burru 				     oq->pkts_pending);
48837d79d05SVeerasenareddy Burru 		if (!pkts_available)
48937d79d05SVeerasenareddy Burru 			break;
49037d79d05SVeerasenareddy Burru 
49137d79d05SVeerasenareddy Burru 		pkts_processed = __octep_oq_process_rx(oct, oq,
49237d79d05SVeerasenareddy Burru 						       pkts_available);
49337d79d05SVeerasenareddy Burru 		oq->pkts_pending -= pkts_processed;
49437d79d05SVeerasenareddy Burru 		total_pkts_processed += pkts_processed;
49537d79d05SVeerasenareddy Burru 	}
49637d79d05SVeerasenareddy Burru 
49737d79d05SVeerasenareddy Burru 	if (oq->refill_count >= oq->refill_threshold) {
49837d79d05SVeerasenareddy Burru 		u32 desc_refilled = octep_oq_refill(oct, oq);
49937d79d05SVeerasenareddy Burru 
50037d79d05SVeerasenareddy Burru 		/* flush pending writes before updating credits */
50137d79d05SVeerasenareddy Burru 		wmb();
50237d79d05SVeerasenareddy Burru 		writel(desc_refilled, oq->pkts_credit_reg);
50337d79d05SVeerasenareddy Burru 	}
50437d79d05SVeerasenareddy Burru 
50537d79d05SVeerasenareddy Burru 	return total_pkts_processed;
50637d79d05SVeerasenareddy Burru }
507