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
16132d462a5SJulia 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 /**
340e71146ffSAleksandr Mishin * octep_oq_next_pkt() - Move to the next packet in Rx queue.
341e71146ffSAleksandr Mishin *
342e71146ffSAleksandr Mishin * @oq: Octeon Rx queue data structure.
343e71146ffSAleksandr Mishin * @buff_info: Current packet buffer info.
344e71146ffSAleksandr Mishin * @read_idx: Current packet index in the ring.
345e71146ffSAleksandr Mishin * @desc_used: Current packet descriptor number.
346e71146ffSAleksandr Mishin *
347e71146ffSAleksandr Mishin * Free the resources associated with a packet.
348e71146ffSAleksandr Mishin * Increment packet index in the ring and packet descriptor number.
349e71146ffSAleksandr Mishin */
octep_oq_next_pkt(struct octep_oq * oq,struct octep_rx_buffer * buff_info,u32 * read_idx,u32 * desc_used)350e71146ffSAleksandr Mishin static void octep_oq_next_pkt(struct octep_oq *oq,
351e71146ffSAleksandr Mishin struct octep_rx_buffer *buff_info,
352e71146ffSAleksandr Mishin u32 *read_idx, u32 *desc_used)
353e71146ffSAleksandr Mishin {
354e71146ffSAleksandr Mishin dma_unmap_page(oq->dev, oq->desc_ring[*read_idx].buffer_ptr,
355e71146ffSAleksandr Mishin PAGE_SIZE, DMA_FROM_DEVICE);
356e71146ffSAleksandr Mishin buff_info->page = NULL;
357e71146ffSAleksandr Mishin (*read_idx)++;
358e71146ffSAleksandr Mishin (*desc_used)++;
359e71146ffSAleksandr Mishin if (*read_idx == oq->max_count)
360e71146ffSAleksandr Mishin *read_idx = 0;
361e71146ffSAleksandr Mishin }
362e71146ffSAleksandr Mishin
363e71146ffSAleksandr Mishin /**
364*c2d2dc4fSAleksandr Mishin * octep_oq_drop_rx() - Free the resources associated with a packet.
365*c2d2dc4fSAleksandr Mishin *
366*c2d2dc4fSAleksandr Mishin * @oq: Octeon Rx queue data structure.
367*c2d2dc4fSAleksandr Mishin * @buff_info: Current packet buffer info.
368*c2d2dc4fSAleksandr Mishin * @read_idx: Current packet index in the ring.
369*c2d2dc4fSAleksandr Mishin * @desc_used: Current packet descriptor number.
370*c2d2dc4fSAleksandr Mishin *
371*c2d2dc4fSAleksandr Mishin */
octep_oq_drop_rx(struct octep_oq * oq,struct octep_rx_buffer * buff_info,u32 * read_idx,u32 * desc_used)372*c2d2dc4fSAleksandr Mishin static void octep_oq_drop_rx(struct octep_oq *oq,
373*c2d2dc4fSAleksandr Mishin struct octep_rx_buffer *buff_info,
374*c2d2dc4fSAleksandr Mishin u32 *read_idx, u32 *desc_used)
375*c2d2dc4fSAleksandr Mishin {
376*c2d2dc4fSAleksandr Mishin int data_len = buff_info->len - oq->max_single_buffer_size;
377*c2d2dc4fSAleksandr Mishin
378*c2d2dc4fSAleksandr Mishin while (data_len > 0) {
379*c2d2dc4fSAleksandr Mishin octep_oq_next_pkt(oq, buff_info, read_idx, desc_used);
380*c2d2dc4fSAleksandr Mishin data_len -= oq->buffer_size;
381*c2d2dc4fSAleksandr Mishin };
382*c2d2dc4fSAleksandr Mishin }
383*c2d2dc4fSAleksandr Mishin
384*c2d2dc4fSAleksandr Mishin /**
38537d79d05SVeerasenareddy Burru * __octep_oq_process_rx() - Process hardware Rx queue and push to stack.
38637d79d05SVeerasenareddy Burru *
38737d79d05SVeerasenareddy Burru * @oct: Octeon device private data structure.
38837d79d05SVeerasenareddy Burru * @oq: Octeon Rx queue data structure.
38937d79d05SVeerasenareddy Burru * @pkts_to_process: number of packets to be processed.
39037d79d05SVeerasenareddy Burru *
39137d79d05SVeerasenareddy Burru * Process the new packets in Rx queue.
39237d79d05SVeerasenareddy Burru * Packets larger than single Rx buffer arrive in consecutive descriptors.
39337d79d05SVeerasenareddy Burru * But, count returned by the API only accounts full packets, not fragments.
39437d79d05SVeerasenareddy Burru *
39537d79d05SVeerasenareddy Burru * Return: number of packets processed and pushed to stack.
39637d79d05SVeerasenareddy Burru */
__octep_oq_process_rx(struct octep_device * oct,struct octep_oq * oq,u16 pkts_to_process)39737d79d05SVeerasenareddy Burru static int __octep_oq_process_rx(struct octep_device *oct,
39837d79d05SVeerasenareddy Burru struct octep_oq *oq, u16 pkts_to_process)
39937d79d05SVeerasenareddy Burru {
40037d79d05SVeerasenareddy Burru struct octep_oq_resp_hw_ext *resp_hw_ext = NULL;
40137d79d05SVeerasenareddy Burru struct octep_rx_buffer *buff_info;
40237d79d05SVeerasenareddy Burru struct octep_oq_resp_hw *resp_hw;
40337d79d05SVeerasenareddy Burru u32 pkt, rx_bytes, desc_used;
40437d79d05SVeerasenareddy Burru struct sk_buff *skb;
40537d79d05SVeerasenareddy Burru u16 data_offset;
40637d79d05SVeerasenareddy Burru u32 read_idx;
40737d79d05SVeerasenareddy Burru
40837d79d05SVeerasenareddy Burru read_idx = oq->host_read_idx;
40937d79d05SVeerasenareddy Burru rx_bytes = 0;
41037d79d05SVeerasenareddy Burru desc_used = 0;
41137d79d05SVeerasenareddy Burru for (pkt = 0; pkt < pkts_to_process; pkt++) {
41237d79d05SVeerasenareddy Burru buff_info = (struct octep_rx_buffer *)&oq->buff_info[read_idx];
41337d79d05SVeerasenareddy Burru resp_hw = page_address(buff_info->page);
41437d79d05SVeerasenareddy Burru
41537d79d05SVeerasenareddy Burru /* Swap the length field that is in Big-Endian to CPU */
41637d79d05SVeerasenareddy Burru buff_info->len = be64_to_cpu(resp_hw->length);
41737d79d05SVeerasenareddy Burru if (oct->caps_enabled & OCTEP_CAP_RX_CHECKSUM) {
41837d79d05SVeerasenareddy Burru /* Extended response header is immediately after
41937d79d05SVeerasenareddy Burru * response header (resp_hw)
42037d79d05SVeerasenareddy Burru */
42137d79d05SVeerasenareddy Burru resp_hw_ext = (struct octep_oq_resp_hw_ext *)
42237d79d05SVeerasenareddy Burru (resp_hw + 1);
42337d79d05SVeerasenareddy Burru buff_info->len -= OCTEP_OQ_RESP_HW_EXT_SIZE;
42437d79d05SVeerasenareddy Burru /* Packet Data is immediately after
42537d79d05SVeerasenareddy Burru * extended response header.
42637d79d05SVeerasenareddy Burru */
42737d79d05SVeerasenareddy Burru data_offset = OCTEP_OQ_RESP_HW_SIZE +
42837d79d05SVeerasenareddy Burru OCTEP_OQ_RESP_HW_EXT_SIZE;
42937d79d05SVeerasenareddy Burru } else {
43037d79d05SVeerasenareddy Burru /* Data is immediately after
43137d79d05SVeerasenareddy Burru * Hardware Rx response header.
43237d79d05SVeerasenareddy Burru */
43337d79d05SVeerasenareddy Burru data_offset = OCTEP_OQ_RESP_HW_SIZE;
43437d79d05SVeerasenareddy Burru }
435e71146ffSAleksandr Mishin
436e71146ffSAleksandr Mishin octep_oq_next_pkt(oq, buff_info, &read_idx, &desc_used);
437e71146ffSAleksandr Mishin
438e71146ffSAleksandr Mishin skb = build_skb((void *)resp_hw, PAGE_SIZE);
439*c2d2dc4fSAleksandr Mishin if (!skb) {
440*c2d2dc4fSAleksandr Mishin octep_oq_drop_rx(oq, buff_info,
441*c2d2dc4fSAleksandr Mishin &read_idx, &desc_used);
442*c2d2dc4fSAleksandr Mishin oq->stats.alloc_failures++;
443*c2d2dc4fSAleksandr Mishin continue;
444*c2d2dc4fSAleksandr Mishin }
445e71146ffSAleksandr Mishin skb_reserve(skb, data_offset);
446e71146ffSAleksandr Mishin
44737d79d05SVeerasenareddy Burru rx_bytes += buff_info->len;
44837d79d05SVeerasenareddy Burru
44937d79d05SVeerasenareddy Burru if (buff_info->len <= oq->max_single_buffer_size) {
45037d79d05SVeerasenareddy Burru skb_put(skb, buff_info->len);
45137d79d05SVeerasenareddy Burru } else {
45237d79d05SVeerasenareddy Burru struct skb_shared_info *shinfo;
45337d79d05SVeerasenareddy Burru u16 data_len;
45437d79d05SVeerasenareddy Burru
45537d79d05SVeerasenareddy Burru /* Head fragment includes response header(s);
45637d79d05SVeerasenareddy Burru * subsequent fragments contains only data.
45737d79d05SVeerasenareddy Burru */
45837d79d05SVeerasenareddy Burru skb_put(skb, oq->max_single_buffer_size);
45937d79d05SVeerasenareddy Burru shinfo = skb_shinfo(skb);
46037d79d05SVeerasenareddy Burru data_len = buff_info->len - oq->max_single_buffer_size;
46137d79d05SVeerasenareddy Burru while (data_len) {
46237d79d05SVeerasenareddy Burru buff_info = (struct octep_rx_buffer *)
46337d79d05SVeerasenareddy Burru &oq->buff_info[read_idx];
46437d79d05SVeerasenareddy Burru if (data_len < oq->buffer_size) {
46537d79d05SVeerasenareddy Burru buff_info->len = data_len;
46637d79d05SVeerasenareddy Burru data_len = 0;
46737d79d05SVeerasenareddy Burru } else {
46837d79d05SVeerasenareddy Burru buff_info->len = oq->buffer_size;
46937d79d05SVeerasenareddy Burru data_len -= oq->buffer_size;
47037d79d05SVeerasenareddy Burru }
47137d79d05SVeerasenareddy Burru
47237d79d05SVeerasenareddy Burru skb_add_rx_frag(skb, shinfo->nr_frags,
47337d79d05SVeerasenareddy Burru buff_info->page, 0,
47437d79d05SVeerasenareddy Burru buff_info->len,
47537d79d05SVeerasenareddy Burru buff_info->len);
476e71146ffSAleksandr Mishin
477e71146ffSAleksandr Mishin octep_oq_next_pkt(oq, buff_info, &read_idx, &desc_used);
47837d79d05SVeerasenareddy Burru }
47937d79d05SVeerasenareddy Burru }
48037d79d05SVeerasenareddy Burru
48137d79d05SVeerasenareddy Burru skb->dev = oq->netdev;
48237d79d05SVeerasenareddy Burru skb->protocol = eth_type_trans(skb, skb->dev);
48337d79d05SVeerasenareddy Burru if (resp_hw_ext &&
48437d79d05SVeerasenareddy Burru resp_hw_ext->csum_verified == OCTEP_CSUM_VERIFIED)
48537d79d05SVeerasenareddy Burru skb->ip_summed = CHECKSUM_UNNECESSARY;
48637d79d05SVeerasenareddy Burru else
48737d79d05SVeerasenareddy Burru skb->ip_summed = CHECKSUM_NONE;
48837d79d05SVeerasenareddy Burru napi_gro_receive(oq->napi, skb);
48937d79d05SVeerasenareddy Burru }
49037d79d05SVeerasenareddy Burru
49137d79d05SVeerasenareddy Burru oq->host_read_idx = read_idx;
49237d79d05SVeerasenareddy Burru oq->refill_count += desc_used;
49337d79d05SVeerasenareddy Burru oq->stats.packets += pkt;
49437d79d05SVeerasenareddy Burru oq->stats.bytes += rx_bytes;
49537d79d05SVeerasenareddy Burru
49637d79d05SVeerasenareddy Burru return pkt;
49737d79d05SVeerasenareddy Burru }
49837d79d05SVeerasenareddy Burru
49937d79d05SVeerasenareddy Burru /**
50037d79d05SVeerasenareddy Burru * octep_oq_process_rx() - Process Rx queue.
50137d79d05SVeerasenareddy Burru *
50237d79d05SVeerasenareddy Burru * @oq: Octeon Rx queue data structure.
50337d79d05SVeerasenareddy Burru * @budget: max number of packets can be processed in one invocation.
50437d79d05SVeerasenareddy Burru *
50537d79d05SVeerasenareddy Burru * Check for newly received packets and process them.
50637d79d05SVeerasenareddy Burru * Keeps checking for new packets until budget is used or no new packets seen.
50737d79d05SVeerasenareddy Burru *
50837d79d05SVeerasenareddy Burru * Return: number of packets processed.
50937d79d05SVeerasenareddy Burru */
octep_oq_process_rx(struct octep_oq * oq,int budget)51037d79d05SVeerasenareddy Burru int octep_oq_process_rx(struct octep_oq *oq, int budget)
51137d79d05SVeerasenareddy Burru {
51237d79d05SVeerasenareddy Burru u32 pkts_available, pkts_processed, total_pkts_processed;
51337d79d05SVeerasenareddy Burru struct octep_device *oct = oq->octep_dev;
51437d79d05SVeerasenareddy Burru
51537d79d05SVeerasenareddy Burru pkts_available = 0;
51637d79d05SVeerasenareddy Burru pkts_processed = 0;
51737d79d05SVeerasenareddy Burru total_pkts_processed = 0;
51837d79d05SVeerasenareddy Burru while (total_pkts_processed < budget) {
51937d79d05SVeerasenareddy Burru /* update pending count only when current one exhausted */
52037d79d05SVeerasenareddy Burru if (oq->pkts_pending == 0)
52137d79d05SVeerasenareddy Burru octep_oq_check_hw_for_pkts(oct, oq);
52237d79d05SVeerasenareddy Burru pkts_available = min(budget - total_pkts_processed,
52337d79d05SVeerasenareddy Burru oq->pkts_pending);
52437d79d05SVeerasenareddy Burru if (!pkts_available)
52537d79d05SVeerasenareddy Burru break;
52637d79d05SVeerasenareddy Burru
52737d79d05SVeerasenareddy Burru pkts_processed = __octep_oq_process_rx(oct, oq,
52837d79d05SVeerasenareddy Burru pkts_available);
52937d79d05SVeerasenareddy Burru oq->pkts_pending -= pkts_processed;
53037d79d05SVeerasenareddy Burru total_pkts_processed += pkts_processed;
53137d79d05SVeerasenareddy Burru }
53237d79d05SVeerasenareddy Burru
53337d79d05SVeerasenareddy Burru if (oq->refill_count >= oq->refill_threshold) {
53437d79d05SVeerasenareddy Burru u32 desc_refilled = octep_oq_refill(oct, oq);
53537d79d05SVeerasenareddy Burru
53637d79d05SVeerasenareddy Burru /* flush pending writes before updating credits */
53737d79d05SVeerasenareddy Burru wmb();
53837d79d05SVeerasenareddy Burru writel(desc_refilled, oq->pkts_credit_reg);
53937d79d05SVeerasenareddy Burru }
54037d79d05SVeerasenareddy Burru
54137d79d05SVeerasenareddy Burru return total_pkts_processed;
54237d79d05SVeerasenareddy Burru }
543