Commit | Line | Data |
---|---|---|
862cd659 VB |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Marvell Octeon EP (EndPoint) Ethernet Driver | |
3 | * | |
4 | * Copyright (C) 2020 Marvell. | |
5 | * | |
6 | */ | |
7 | ||
8 | #include <linux/pci.h> | |
9 | #include <linux/etherdevice.h> | |
397dfb57 | 10 | #include <linux/vmalloc.h> |
862cd659 VB |
11 | |
12 | #include "octep_config.h" | |
13 | #include "octep_main.h" | |
14 | ||
397dfb57 VB |
15 | /* Reset various index of Tx queue data structure. */ |
16 | static void octep_iq_reset_indices(struct octep_iq *iq) | |
17 | { | |
18 | iq->fill_cnt = 0; | |
19 | iq->host_write_index = 0; | |
20 | iq->octep_read_index = 0; | |
21 | iq->flush_index = 0; | |
22 | iq->pkts_processed = 0; | |
23 | iq->pkt_in_done = 0; | |
24 | atomic_set(&iq->instr_pending, 0); | |
25 | } | |
26 | ||
37d79d05 VB |
27 | /** |
28 | * octep_iq_process_completions() - Process Tx queue completions. | |
29 | * | |
30 | * @iq: Octeon Tx queue data structure. | |
31 | * @budget: max number of completions to be processed in one invocation. | |
32 | */ | |
33 | int octep_iq_process_completions(struct octep_iq *iq, u16 budget) | |
34 | { | |
35 | u32 compl_pkts, compl_bytes, compl_sg; | |
36 | struct octep_device *oct = iq->octep_dev; | |
37 | struct octep_tx_buffer *tx_buffer; | |
38 | struct skb_shared_info *shinfo; | |
39 | u32 fi = iq->flush_index; | |
40 | struct sk_buff *skb; | |
41 | u8 frags, i; | |
42 | ||
43 | compl_pkts = 0; | |
44 | compl_sg = 0; | |
45 | compl_bytes = 0; | |
46 | iq->octep_read_index = oct->hw_ops.update_iq_read_idx(iq); | |
47 | ||
48 | while (likely(budget && (fi != iq->octep_read_index))) { | |
49 | tx_buffer = iq->buff_info + fi; | |
50 | skb = tx_buffer->skb; | |
51 | ||
52 | fi++; | |
53 | if (unlikely(fi == iq->max_count)) | |
54 | fi = 0; | |
55 | compl_bytes += skb->len; | |
56 | compl_pkts++; | |
57 | budget--; | |
58 | ||
59 | if (!tx_buffer->gather) { | |
60 | dma_unmap_single(iq->dev, tx_buffer->dma, | |
61 | tx_buffer->skb->len, DMA_TO_DEVICE); | |
62 | dev_kfree_skb_any(skb); | |
63 | continue; | |
64 | } | |
65 | ||
66 | /* Scatter/Gather */ | |
67 | shinfo = skb_shinfo(skb); | |
68 | frags = shinfo->nr_frags; | |
69 | compl_sg++; | |
70 | ||
71 | dma_unmap_single(iq->dev, tx_buffer->sglist[0].dma_ptr[0], | |
350db8a5 | 72 | tx_buffer->sglist[0].len[3], DMA_TO_DEVICE); |
37d79d05 VB |
73 | |
74 | i = 1; /* entry 0 is main skb, unmapped above */ | |
75 | while (frags--) { | |
76 | dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3], | |
350db8a5 | 77 | tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE); |
37d79d05 VB |
78 | i++; |
79 | } | |
80 | ||
81 | dev_kfree_skb_any(skb); | |
82 | } | |
83 | ||
84 | iq->pkts_processed += compl_pkts; | |
85 | atomic_sub(compl_pkts, &iq->instr_pending); | |
86 | iq->stats.instr_completed += compl_pkts; | |
87 | iq->stats.bytes_sent += compl_bytes; | |
88 | iq->stats.sgentry_sent += compl_sg; | |
89 | iq->flush_index = fi; | |
90 | ||
91 | netdev_tx_completed_queue(iq->netdev_q, compl_pkts, compl_bytes); | |
92 | ||
93 | if (unlikely(__netif_subqueue_stopped(iq->netdev, iq->q_no)) && | |
94 | ((iq->max_count - atomic_read(&iq->instr_pending)) > | |
95 | OCTEP_WAKE_QUEUE_THRESHOLD)) | |
96 | netif_wake_subqueue(iq->netdev, iq->q_no); | |
97 | return !budget; | |
98 | } | |
99 | ||
397dfb57 VB |
100 | /** |
101 | * octep_iq_free_pending() - Free Tx buffers for pending completions. | |
102 | * | |
103 | * @iq: Octeon Tx queue data structure. | |
104 | */ | |
105 | static void octep_iq_free_pending(struct octep_iq *iq) | |
106 | { | |
107 | struct octep_tx_buffer *tx_buffer; | |
108 | struct skb_shared_info *shinfo; | |
109 | u32 fi = iq->flush_index; | |
110 | struct sk_buff *skb; | |
111 | u8 frags, i; | |
112 | ||
113 | while (fi != iq->host_write_index) { | |
114 | tx_buffer = iq->buff_info + fi; | |
115 | skb = tx_buffer->skb; | |
116 | ||
117 | fi++; | |
118 | if (unlikely(fi == iq->max_count)) | |
119 | fi = 0; | |
120 | ||
121 | if (!tx_buffer->gather) { | |
122 | dma_unmap_single(iq->dev, tx_buffer->dma, | |
123 | tx_buffer->skb->len, DMA_TO_DEVICE); | |
124 | dev_kfree_skb_any(skb); | |
125 | continue; | |
126 | } | |
127 | ||
128 | /* Scatter/Gather */ | |
129 | shinfo = skb_shinfo(skb); | |
130 | frags = shinfo->nr_frags; | |
131 | ||
132 | dma_unmap_single(iq->dev, | |
133 | tx_buffer->sglist[0].dma_ptr[0], | |
350db8a5 | 134 | tx_buffer->sglist[0].len[3], |
397dfb57 VB |
135 | DMA_TO_DEVICE); |
136 | ||
137 | i = 1; /* entry 0 is main skb, unmapped above */ | |
138 | while (frags--) { | |
139 | dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3], | |
350db8a5 | 140 | tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE); |
397dfb57 VB |
141 | i++; |
142 | } | |
143 | ||
144 | dev_kfree_skb_any(skb); | |
145 | } | |
146 | ||
147 | atomic_set(&iq->instr_pending, 0); | |
148 | iq->flush_index = fi; | |
149 | netdev_tx_reset_queue(netdev_get_tx_queue(iq->netdev, iq->q_no)); | |
150 | } | |
151 | ||
862cd659 VB |
152 | /** |
153 | * octep_clean_iqs() - Clean Tx queues to shutdown the device. | |
154 | * | |
155 | * @oct: Octeon device private data structure. | |
156 | * | |
157 | * Free the buffers in Tx queue descriptors pending completion and | |
158 | * reset queue indices | |
159 | */ | |
160 | void octep_clean_iqs(struct octep_device *oct) | |
161 | { | |
397dfb57 VB |
162 | int i; |
163 | ||
164 | for (i = 0; i < oct->num_iqs; i++) { | |
165 | octep_iq_free_pending(oct->iq[i]); | |
166 | octep_iq_reset_indices(oct->iq[i]); | |
167 | } | |
168 | } | |
169 | ||
170 | /** | |
171 | * octep_setup_iq() - Setup a Tx queue. | |
172 | * | |
173 | * @oct: Octeon device private data structure. | |
174 | * @q_no: Tx queue number to be setup. | |
175 | * | |
176 | * Allocate resources for a Tx queue. | |
177 | */ | |
178 | static int octep_setup_iq(struct octep_device *oct, int q_no) | |
179 | { | |
180 | u32 desc_ring_size, buff_info_size, sglist_size; | |
181 | struct octep_iq *iq; | |
182 | int i; | |
183 | ||
184 | iq = vzalloc(sizeof(*iq)); | |
185 | if (!iq) | |
186 | goto iq_alloc_err; | |
187 | oct->iq[q_no] = iq; | |
188 | ||
189 | iq->octep_dev = oct; | |
190 | iq->netdev = oct->netdev; | |
191 | iq->dev = &oct->pdev->dev; | |
192 | iq->q_no = q_no; | |
193 | iq->max_count = CFG_GET_IQ_NUM_DESC(oct->conf); | |
194 | iq->ring_size_mask = iq->max_count - 1; | |
195 | iq->fill_threshold = CFG_GET_IQ_DB_MIN(oct->conf); | |
196 | iq->netdev_q = netdev_get_tx_queue(iq->netdev, q_no); | |
197 | ||
198 | /* Allocate memory for hardware queue descriptors */ | |
199 | desc_ring_size = OCTEP_IQ_DESC_SIZE * CFG_GET_IQ_NUM_DESC(oct->conf); | |
200 | iq->desc_ring = dma_alloc_coherent(iq->dev, desc_ring_size, | |
201 | &iq->desc_ring_dma, GFP_KERNEL); | |
202 | if (unlikely(!iq->desc_ring)) { | |
203 | dev_err(iq->dev, | |
204 | "Failed to allocate DMA memory for IQ-%d\n", q_no); | |
205 | goto desc_dma_alloc_err; | |
206 | } | |
207 | ||
208 | /* Allocate memory for hardware SGLIST descriptors */ | |
209 | sglist_size = OCTEP_SGLIST_SIZE_PER_PKT * | |
210 | CFG_GET_IQ_NUM_DESC(oct->conf); | |
211 | iq->sglist = dma_alloc_coherent(iq->dev, sglist_size, | |
212 | &iq->sglist_dma, GFP_KERNEL); | |
213 | if (unlikely(!iq->sglist)) { | |
214 | dev_err(iq->dev, | |
215 | "Failed to allocate DMA memory for IQ-%d SGLIST\n", | |
216 | q_no); | |
217 | goto sglist_alloc_err; | |
218 | } | |
219 | ||
220 | /* allocate memory to manage Tx packets pending completion */ | |
221 | buff_info_size = OCTEP_IQ_TXBUFF_INFO_SIZE * iq->max_count; | |
222 | iq->buff_info = vzalloc(buff_info_size); | |
223 | if (!iq->buff_info) { | |
224 | dev_err(iq->dev, | |
225 | "Failed to allocate buff info for IQ-%d\n", q_no); | |
226 | goto buff_info_err; | |
227 | } | |
228 | ||
229 | /* Setup sglist addresses in tx_buffer entries */ | |
230 | for (i = 0; i < CFG_GET_IQ_NUM_DESC(oct->conf); i++) { | |
231 | struct octep_tx_buffer *tx_buffer; | |
232 | ||
233 | tx_buffer = &iq->buff_info[i]; | |
234 | tx_buffer->sglist = | |
235 | &iq->sglist[i * OCTEP_SGLIST_ENTRIES_PER_PKT]; | |
236 | tx_buffer->sglist_dma = | |
237 | iq->sglist_dma + (i * OCTEP_SGLIST_SIZE_PER_PKT); | |
238 | } | |
239 | ||
240 | octep_iq_reset_indices(iq); | |
241 | oct->hw_ops.setup_iq_regs(oct, q_no); | |
242 | ||
243 | oct->num_iqs++; | |
244 | return 0; | |
245 | ||
246 | buff_info_err: | |
247 | dma_free_coherent(iq->dev, sglist_size, iq->sglist, iq->sglist_dma); | |
248 | sglist_alloc_err: | |
249 | dma_free_coherent(iq->dev, desc_ring_size, | |
250 | iq->desc_ring, iq->desc_ring_dma); | |
251 | desc_dma_alloc_err: | |
252 | vfree(iq); | |
253 | oct->iq[q_no] = NULL; | |
254 | iq_alloc_err: | |
255 | return -1; | |
256 | } | |
257 | ||
258 | /** | |
259 | * octep_free_iq() - Free Tx queue resources. | |
260 | * | |
261 | * @iq: Octeon Tx queue data structure. | |
262 | * | |
263 | * Free all the resources allocated for a Tx queue. | |
264 | */ | |
265 | static void octep_free_iq(struct octep_iq *iq) | |
266 | { | |
267 | struct octep_device *oct = iq->octep_dev; | |
268 | u64 desc_ring_size, sglist_size; | |
269 | int q_no = iq->q_no; | |
270 | ||
271 | desc_ring_size = OCTEP_IQ_DESC_SIZE * CFG_GET_IQ_NUM_DESC(oct->conf); | |
272 | ||
1dee43c2 | 273 | vfree(iq->buff_info); |
397dfb57 VB |
274 | |
275 | if (iq->desc_ring) | |
276 | dma_free_coherent(iq->dev, desc_ring_size, | |
277 | iq->desc_ring, iq->desc_ring_dma); | |
278 | ||
279 | sglist_size = OCTEP_SGLIST_SIZE_PER_PKT * | |
280 | CFG_GET_IQ_NUM_DESC(oct->conf); | |
281 | if (iq->sglist) | |
282 | dma_free_coherent(iq->dev, sglist_size, | |
283 | iq->sglist, iq->sglist_dma); | |
284 | ||
285 | vfree(iq); | |
286 | oct->iq[q_no] = NULL; | |
287 | oct->num_iqs--; | |
862cd659 VB |
288 | } |
289 | ||
290 | /** | |
291 | * octep_setup_iqs() - setup resources for all Tx queues. | |
292 | * | |
293 | * @oct: Octeon device private data structure. | |
294 | */ | |
295 | int octep_setup_iqs(struct octep_device *oct) | |
296 | { | |
397dfb57 VB |
297 | int i; |
298 | ||
299 | oct->num_iqs = 0; | |
300 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { | |
301 | if (octep_setup_iq(oct, i)) { | |
302 | dev_err(&oct->pdev->dev, | |
303 | "Failed to setup IQ(TxQ)-%d.\n", i); | |
304 | goto iq_setup_err; | |
305 | } | |
306 | dev_dbg(&oct->pdev->dev, "Successfully setup IQ(TxQ)-%d.\n", i); | |
307 | } | |
308 | ||
309 | return 0; | |
310 | ||
311 | iq_setup_err: | |
312 | while (i) { | |
313 | i--; | |
314 | octep_free_iq(oct->iq[i]); | |
315 | } | |
862cd659 VB |
316 | return -1; |
317 | } | |
318 | ||
319 | /** | |
320 | * octep_free_iqs() - Free resources of all Tx queues. | |
321 | * | |
322 | * @oct: Octeon device private data structure. | |
323 | */ | |
324 | void octep_free_iqs(struct octep_device *oct) | |
325 | { | |
397dfb57 VB |
326 | int i; |
327 | ||
328 | for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) { | |
329 | octep_free_iq(oct->iq[i]); | |
330 | dev_dbg(&oct->pdev->dev, | |
331 | "Successfully destroyed IQ(TxQ)-%d.\n", i); | |
332 | } | |
333 | oct->num_iqs = 0; | |
862cd659 | 334 | } |