1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Marvell CN10K MCS driver |
3 | * |
4 | * Copyright (C) 2022 Marvell. |
5 | */ |
6 | |
7 | #include <linux/types.h> |
8 | #include <linux/device.h> |
9 | #include <linux/module.h> |
10 | #include <linux/pci.h> |
11 | |
12 | #include "mcs.h" |
13 | #include "rvu.h" |
14 | #include "mcs_reg.h" |
15 | #include "lmac_common.h" |
16 | |
17 | #define M(_name, _id, _fn_name, _req_type, _rsp_type) \ |
18 | static struct _req_type __maybe_unused \ |
19 | *otx2_mbox_alloc_msg_ ## _fn_name(struct rvu *rvu, int devid) \ |
20 | { \ |
21 | struct _req_type *req; \ |
22 | \ |
23 | req = (struct _req_type *)otx2_mbox_alloc_msg_rsp( \ |
24 | &rvu->afpf_wq_info.mbox_up, devid, sizeof(struct _req_type), \ |
25 | sizeof(struct _rsp_type)); \ |
26 | if (!req) \ |
27 | return NULL; \ |
28 | req->hdr.sig = OTX2_MBOX_REQ_SIG; \ |
29 | req->hdr.id = _id; \ |
30 | return req; \ |
31 | } |
32 | |
33 | MBOX_UP_MCS_MESSAGES |
34 | #undef M |
35 | |
36 | void rvu_mcs_ptp_cfg(struct rvu *rvu, u8 rpm_id, u8 lmac_id, bool ena) |
37 | { |
38 | struct mcs *mcs; |
39 | u64 cfg; |
40 | u8 port; |
41 | |
42 | if (!rvu->mcs_blk_cnt) |
43 | return; |
44 | |
45 | /* When ptp is enabled, RPM appends 8B header for all |
46 | * RX packets. MCS PEX need to configure to skip 8B |
47 | * during packet parsing. |
48 | */ |
49 | |
50 | /* CNF10K-B */ |
51 | if (rvu->mcs_blk_cnt > 1) { |
52 | mcs = mcs_get_pdata(mcs_id: rpm_id); |
53 | cfg = mcs_reg_read(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION); |
54 | if (ena) |
55 | cfg |= BIT_ULL(lmac_id); |
56 | else |
57 | cfg &= ~BIT_ULL(lmac_id); |
58 | mcs_reg_write(mcs, MCSX_PEX_RX_SLAVE_PEX_CONFIGURATION, val: cfg); |
59 | return; |
60 | } |
61 | /* CN10KB */ |
62 | mcs = mcs_get_pdata(mcs_id: 0); |
63 | port = (rpm_id * rvu->hw->lmac_per_cgx) + lmac_id; |
64 | cfg = mcs_reg_read(mcs, MCSX_PEX_RX_SLAVE_PORT_CFGX(port)); |
65 | if (ena) |
66 | cfg |= BIT_ULL(0); |
67 | else |
68 | cfg &= ~BIT_ULL(0); |
69 | mcs_reg_write(mcs, MCSX_PEX_RX_SLAVE_PORT_CFGX(port), val: cfg); |
70 | } |
71 | |
72 | int rvu_mbox_handler_mcs_set_lmac_mode(struct rvu *rvu, |
73 | struct mcs_set_lmac_mode *req, |
74 | struct msg_rsp *rsp) |
75 | { |
76 | struct mcs *mcs; |
77 | |
78 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
79 | return MCS_AF_ERR_INVALID_MCSID; |
80 | |
81 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
82 | |
83 | if (BIT_ULL(req->lmac_id) & mcs->hw->lmac_bmap) |
84 | mcs_set_lmac_mode(mcs, lmac_id: req->lmac_id, mode: req->mode); |
85 | |
86 | return 0; |
87 | } |
88 | |
89 | int mcs_add_intr_wq_entry(struct mcs *mcs, struct mcs_intr_event *event) |
90 | { |
91 | struct mcs_intrq_entry *qentry; |
92 | u16 pcifunc = event->pcifunc; |
93 | struct rvu *rvu = mcs->rvu; |
94 | struct mcs_pfvf *pfvf; |
95 | |
96 | /* Check if it is PF or VF */ |
97 | if (pcifunc & RVU_PFVF_FUNC_MASK) |
98 | pfvf = &mcs->vf[rvu_get_hwvf(rvu, pcifunc)]; |
99 | else |
100 | pfvf = &mcs->pf[rvu_get_pf(pcifunc)]; |
101 | |
102 | event->intr_mask &= pfvf->intr_mask; |
103 | |
104 | /* Check PF/VF interrupt notification is enabled */ |
105 | if (!(pfvf->intr_mask && event->intr_mask)) |
106 | return 0; |
107 | |
108 | qentry = kmalloc(size: sizeof(*qentry), GFP_ATOMIC); |
109 | if (!qentry) |
110 | return -ENOMEM; |
111 | |
112 | qentry->intr_event = *event; |
113 | spin_lock(lock: &rvu->mcs_intrq_lock); |
114 | list_add_tail(new: &qentry->node, head: &rvu->mcs_intrq_head); |
115 | spin_unlock(lock: &rvu->mcs_intrq_lock); |
116 | queue_work(wq: rvu->mcs_intr_wq, work: &rvu->mcs_intr_work); |
117 | |
118 | return 0; |
119 | } |
120 | |
121 | static int mcs_notify_pfvf(struct mcs_intr_event *event, struct rvu *rvu) |
122 | { |
123 | struct mcs_intr_info *req; |
124 | int pf; |
125 | |
126 | pf = rvu_get_pf(pcifunc: event->pcifunc); |
127 | |
128 | mutex_lock(&rvu->mbox_lock); |
129 | |
130 | req = otx2_mbox_alloc_msg_mcs_intr_notify(rvu, devid: pf); |
131 | if (!req) { |
132 | mutex_unlock(lock: &rvu->mbox_lock); |
133 | return -ENOMEM; |
134 | } |
135 | |
136 | req->mcs_id = event->mcs_id; |
137 | req->intr_mask = event->intr_mask; |
138 | req->sa_id = event->sa_id; |
139 | req->hdr.pcifunc = event->pcifunc; |
140 | req->lmac_id = event->lmac_id; |
141 | |
142 | otx2_mbox_wait_for_zero(mbox: &rvu->afpf_wq_info.mbox_up, devid: pf); |
143 | |
144 | otx2_mbox_msg_send_up(mbox: &rvu->afpf_wq_info.mbox_up, devid: pf); |
145 | |
146 | mutex_unlock(lock: &rvu->mbox_lock); |
147 | |
148 | return 0; |
149 | } |
150 | |
151 | static void mcs_intr_handler_task(struct work_struct *work) |
152 | { |
153 | struct rvu *rvu = container_of(work, struct rvu, mcs_intr_work); |
154 | struct mcs_intrq_entry *qentry; |
155 | struct mcs_intr_event *event; |
156 | unsigned long flags; |
157 | |
158 | do { |
159 | spin_lock_irqsave(&rvu->mcs_intrq_lock, flags); |
160 | qentry = list_first_entry_or_null(&rvu->mcs_intrq_head, |
161 | struct mcs_intrq_entry, |
162 | node); |
163 | if (qentry) |
164 | list_del(entry: &qentry->node); |
165 | |
166 | spin_unlock_irqrestore(lock: &rvu->mcs_intrq_lock, flags); |
167 | if (!qentry) |
168 | break; /* nothing more to process */ |
169 | |
170 | event = &qentry->intr_event; |
171 | |
172 | mcs_notify_pfvf(event, rvu); |
173 | kfree(objp: qentry); |
174 | } while (1); |
175 | } |
176 | |
177 | int rvu_mbox_handler_mcs_intr_cfg(struct rvu *rvu, |
178 | struct mcs_intr_cfg *req, |
179 | struct msg_rsp *rsp) |
180 | { |
181 | u16 pcifunc = req->hdr.pcifunc; |
182 | struct mcs_pfvf *pfvf; |
183 | struct mcs *mcs; |
184 | |
185 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
186 | return MCS_AF_ERR_INVALID_MCSID; |
187 | |
188 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
189 | |
190 | /* Check if it is PF or VF */ |
191 | if (pcifunc & RVU_PFVF_FUNC_MASK) |
192 | pfvf = &mcs->vf[rvu_get_hwvf(rvu, pcifunc)]; |
193 | else |
194 | pfvf = &mcs->pf[rvu_get_pf(pcifunc)]; |
195 | |
196 | mcs->pf_map[0] = pcifunc; |
197 | pfvf->intr_mask = req->intr_mask; |
198 | |
199 | return 0; |
200 | } |
201 | |
202 | int rvu_mbox_handler_mcs_get_hw_info(struct rvu *rvu, |
203 | struct msg_req *req, |
204 | struct mcs_hw_info *rsp) |
205 | { |
206 | struct mcs *mcs; |
207 | |
208 | if (!rvu->mcs_blk_cnt) |
209 | return MCS_AF_ERR_NOT_MAPPED; |
210 | |
211 | /* MCS resources are same across all blocks */ |
212 | mcs = mcs_get_pdata(mcs_id: 0); |
213 | rsp->num_mcs_blks = rvu->mcs_blk_cnt; |
214 | rsp->tcam_entries = mcs->hw->tcam_entries; |
215 | rsp->secy_entries = mcs->hw->secy_entries; |
216 | rsp->sc_entries = mcs->hw->sc_entries; |
217 | rsp->sa_entries = mcs->hw->sa_entries; |
218 | return 0; |
219 | } |
220 | |
221 | int rvu_mbox_handler_mcs_port_reset(struct rvu *rvu, struct mcs_port_reset_req *req, |
222 | struct msg_rsp *rsp) |
223 | { |
224 | struct mcs *mcs; |
225 | |
226 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
227 | return MCS_AF_ERR_INVALID_MCSID; |
228 | |
229 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
230 | |
231 | mcs_reset_port(mcs, port_id: req->port_id, reset: req->reset); |
232 | |
233 | return 0; |
234 | } |
235 | |
236 | int rvu_mbox_handler_mcs_clear_stats(struct rvu *rvu, |
237 | struct mcs_clear_stats *req, |
238 | struct msg_rsp *rsp) |
239 | { |
240 | u16 pcifunc = req->hdr.pcifunc; |
241 | struct mcs *mcs; |
242 | |
243 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
244 | return MCS_AF_ERR_INVALID_MCSID; |
245 | |
246 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
247 | |
248 | mutex_lock(&mcs->stats_lock); |
249 | if (req->all) |
250 | mcs_clear_all_stats(mcs, pcifunc, dir: req->dir); |
251 | else |
252 | mcs_clear_stats(mcs, type: req->type, id: req->id, dir: req->dir); |
253 | |
254 | mutex_unlock(lock: &mcs->stats_lock); |
255 | return 0; |
256 | } |
257 | |
258 | int rvu_mbox_handler_mcs_get_flowid_stats(struct rvu *rvu, |
259 | struct mcs_stats_req *req, |
260 | struct mcs_flowid_stats *rsp) |
261 | { |
262 | struct mcs *mcs; |
263 | |
264 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
265 | return MCS_AF_ERR_INVALID_MCSID; |
266 | |
267 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
268 | |
269 | /* In CNF10K-B, before reading the statistics, |
270 | * MCSX_MIL_GLOBAL.FORCE_CLK_EN_IP needs to be set |
271 | * to get accurate statistics |
272 | */ |
273 | if (mcs->hw->mcs_blks > 1) |
274 | mcs_set_force_clk_en(mcs, set: true); |
275 | |
276 | mutex_lock(&mcs->stats_lock); |
277 | mcs_get_flowid_stats(mcs, stats: rsp, id: req->id, dir: req->dir); |
278 | mutex_unlock(lock: &mcs->stats_lock); |
279 | |
280 | /* Clear MCSX_MIL_GLOBAL.FORCE_CLK_EN_IP after reading |
281 | * the statistics |
282 | */ |
283 | if (mcs->hw->mcs_blks > 1) |
284 | mcs_set_force_clk_en(mcs, set: false); |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | int rvu_mbox_handler_mcs_get_secy_stats(struct rvu *rvu, |
290 | struct mcs_stats_req *req, |
291 | struct mcs_secy_stats *rsp) |
292 | { struct mcs *mcs; |
293 | |
294 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
295 | return MCS_AF_ERR_INVALID_MCSID; |
296 | |
297 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
298 | |
299 | if (mcs->hw->mcs_blks > 1) |
300 | mcs_set_force_clk_en(mcs, set: true); |
301 | |
302 | mutex_lock(&mcs->stats_lock); |
303 | |
304 | if (req->dir == MCS_RX) |
305 | mcs_get_rx_secy_stats(mcs, stats: rsp, id: req->id); |
306 | else |
307 | mcs_get_tx_secy_stats(mcs, stats: rsp, id: req->id); |
308 | |
309 | mutex_unlock(lock: &mcs->stats_lock); |
310 | |
311 | if (mcs->hw->mcs_blks > 1) |
312 | mcs_set_force_clk_en(mcs, set: false); |
313 | |
314 | return 0; |
315 | } |
316 | |
317 | int rvu_mbox_handler_mcs_get_sc_stats(struct rvu *rvu, |
318 | struct mcs_stats_req *req, |
319 | struct mcs_sc_stats *rsp) |
320 | { |
321 | struct mcs *mcs; |
322 | |
323 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
324 | return MCS_AF_ERR_INVALID_MCSID; |
325 | |
326 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
327 | |
328 | if (mcs->hw->mcs_blks > 1) |
329 | mcs_set_force_clk_en(mcs, set: true); |
330 | |
331 | mutex_lock(&mcs->stats_lock); |
332 | mcs_get_sc_stats(mcs, stats: rsp, id: req->id, dir: req->dir); |
333 | mutex_unlock(lock: &mcs->stats_lock); |
334 | |
335 | if (mcs->hw->mcs_blks > 1) |
336 | mcs_set_force_clk_en(mcs, set: false); |
337 | |
338 | return 0; |
339 | } |
340 | |
341 | int rvu_mbox_handler_mcs_get_sa_stats(struct rvu *rvu, |
342 | struct mcs_stats_req *req, |
343 | struct mcs_sa_stats *rsp) |
344 | { |
345 | struct mcs *mcs; |
346 | |
347 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
348 | return MCS_AF_ERR_INVALID_MCSID; |
349 | |
350 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
351 | |
352 | if (mcs->hw->mcs_blks > 1) |
353 | mcs_set_force_clk_en(mcs, set: true); |
354 | |
355 | mutex_lock(&mcs->stats_lock); |
356 | mcs_get_sa_stats(mcs, stats: rsp, id: req->id, dir: req->dir); |
357 | mutex_unlock(lock: &mcs->stats_lock); |
358 | |
359 | if (mcs->hw->mcs_blks > 1) |
360 | mcs_set_force_clk_en(mcs, set: false); |
361 | |
362 | return 0; |
363 | } |
364 | |
365 | int rvu_mbox_handler_mcs_get_port_stats(struct rvu *rvu, |
366 | struct mcs_stats_req *req, |
367 | struct mcs_port_stats *rsp) |
368 | { |
369 | struct mcs *mcs; |
370 | |
371 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
372 | return MCS_AF_ERR_INVALID_MCSID; |
373 | |
374 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
375 | |
376 | if (mcs->hw->mcs_blks > 1) |
377 | mcs_set_force_clk_en(mcs, set: true); |
378 | |
379 | mutex_lock(&mcs->stats_lock); |
380 | mcs_get_port_stats(mcs, stats: rsp, id: req->id, dir: req->dir); |
381 | mutex_unlock(lock: &mcs->stats_lock); |
382 | |
383 | if (mcs->hw->mcs_blks > 1) |
384 | mcs_set_force_clk_en(mcs, set: false); |
385 | |
386 | return 0; |
387 | } |
388 | |
389 | int rvu_mbox_handler_mcs_set_active_lmac(struct rvu *rvu, |
390 | struct mcs_set_active_lmac *req, |
391 | struct msg_rsp *rsp) |
392 | { |
393 | struct mcs *mcs; |
394 | |
395 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
396 | return MCS_AF_ERR_INVALID_MCSID; |
397 | |
398 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
399 | if (!mcs) |
400 | return MCS_AF_ERR_NOT_MAPPED; |
401 | |
402 | mcs->hw->lmac_bmap = req->lmac_bmap; |
403 | mcs_set_lmac_channels(mcs_id: req->mcs_id, base: req->chan_base); |
404 | return 0; |
405 | } |
406 | |
407 | int rvu_mbox_handler_mcs_port_cfg_set(struct rvu *rvu, struct mcs_port_cfg_set_req *req, |
408 | struct msg_rsp *rsp) |
409 | { |
410 | struct mcs *mcs; |
411 | |
412 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
413 | return MCS_AF_ERR_INVALID_MCSID; |
414 | |
415 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
416 | |
417 | if (mcs->hw->lmac_cnt <= req->port_id || !(mcs->hw->lmac_bmap & BIT_ULL(req->port_id))) |
418 | return -EINVAL; |
419 | |
420 | mcs_set_port_cfg(mcs, req); |
421 | |
422 | return 0; |
423 | } |
424 | |
425 | int rvu_mbox_handler_mcs_port_cfg_get(struct rvu *rvu, struct mcs_port_cfg_get_req *req, |
426 | struct mcs_port_cfg_get_rsp *rsp) |
427 | { |
428 | struct mcs *mcs; |
429 | |
430 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
431 | return MCS_AF_ERR_INVALID_MCSID; |
432 | |
433 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
434 | |
435 | if (mcs->hw->lmac_cnt <= req->port_id || !(mcs->hw->lmac_bmap & BIT_ULL(req->port_id))) |
436 | return -EINVAL; |
437 | |
438 | mcs_get_port_cfg(mcs, req, rsp); |
439 | |
440 | return 0; |
441 | } |
442 | |
443 | int rvu_mbox_handler_mcs_custom_tag_cfg_get(struct rvu *rvu, struct mcs_custom_tag_cfg_get_req *req, |
444 | struct mcs_custom_tag_cfg_get_rsp *rsp) |
445 | { |
446 | struct mcs *mcs; |
447 | |
448 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
449 | return MCS_AF_ERR_INVALID_MCSID; |
450 | |
451 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
452 | |
453 | mcs_get_custom_tag_cfg(mcs, req, rsp); |
454 | |
455 | return 0; |
456 | } |
457 | |
458 | int rvu_mcs_flr_handler(struct rvu *rvu, u16 pcifunc) |
459 | { |
460 | struct mcs *mcs; |
461 | int mcs_id; |
462 | |
463 | /* CNF10K-B mcs0-6 are mapped to RPM2-8*/ |
464 | if (rvu->mcs_blk_cnt > 1) { |
465 | for (mcs_id = 0; mcs_id < rvu->mcs_blk_cnt; mcs_id++) { |
466 | mcs = mcs_get_pdata(mcs_id); |
467 | mcs_free_all_rsrc(mcs, dir: MCS_RX, pcifunc); |
468 | mcs_free_all_rsrc(mcs, dir: MCS_TX, pcifunc); |
469 | } |
470 | } else { |
471 | /* CN10K-B has only one mcs block */ |
472 | mcs = mcs_get_pdata(mcs_id: 0); |
473 | mcs_free_all_rsrc(mcs, dir: MCS_RX, pcifunc); |
474 | mcs_free_all_rsrc(mcs, dir: MCS_TX, pcifunc); |
475 | } |
476 | return 0; |
477 | } |
478 | |
479 | int rvu_mbox_handler_mcs_flowid_ena_entry(struct rvu *rvu, |
480 | struct mcs_flowid_ena_dis_entry *req, |
481 | struct msg_rsp *rsp) |
482 | { |
483 | struct mcs *mcs; |
484 | |
485 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
486 | return MCS_AF_ERR_INVALID_MCSID; |
487 | |
488 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
489 | mcs_ena_dis_flowid_entry(mcs, id: req->flow_id, dir: req->dir, ena: req->ena); |
490 | return 0; |
491 | } |
492 | |
493 | int rvu_mbox_handler_mcs_pn_table_write(struct rvu *rvu, |
494 | struct mcs_pn_table_write_req *req, |
495 | struct msg_rsp *rsp) |
496 | { |
497 | struct mcs *mcs; |
498 | |
499 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
500 | return MCS_AF_ERR_INVALID_MCSID; |
501 | |
502 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
503 | mcs_pn_table_write(mcs, pn_id: req->pn_id, next_pn: req->next_pn, dir: req->dir); |
504 | return 0; |
505 | } |
506 | |
507 | int rvu_mbox_handler_mcs_set_pn_threshold(struct rvu *rvu, |
508 | struct mcs_set_pn_threshold *req, |
509 | struct msg_rsp *rsp) |
510 | { |
511 | struct mcs *mcs; |
512 | |
513 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
514 | return MCS_AF_ERR_INVALID_MCSID; |
515 | |
516 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
517 | |
518 | mcs_pn_threshold_set(mcs, pn: req); |
519 | |
520 | return 0; |
521 | } |
522 | |
523 | int rvu_mbox_handler_mcs_rx_sc_sa_map_write(struct rvu *rvu, |
524 | struct mcs_rx_sc_sa_map *req, |
525 | struct msg_rsp *rsp) |
526 | { |
527 | struct mcs *mcs; |
528 | |
529 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
530 | return MCS_AF_ERR_INVALID_MCSID; |
531 | |
532 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
533 | mcs->mcs_ops->mcs_rx_sa_mem_map_write(mcs, req); |
534 | return 0; |
535 | } |
536 | |
537 | int rvu_mbox_handler_mcs_tx_sc_sa_map_write(struct rvu *rvu, |
538 | struct mcs_tx_sc_sa_map *req, |
539 | struct msg_rsp *rsp) |
540 | { |
541 | struct mcs *mcs; |
542 | |
543 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
544 | return MCS_AF_ERR_INVALID_MCSID; |
545 | |
546 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
547 | mcs->mcs_ops->mcs_tx_sa_mem_map_write(mcs, req); |
548 | mcs->tx_sa_active[req->sc_id] = req->tx_sa_active; |
549 | |
550 | return 0; |
551 | } |
552 | |
553 | int rvu_mbox_handler_mcs_sa_plcy_write(struct rvu *rvu, |
554 | struct mcs_sa_plcy_write_req *req, |
555 | struct msg_rsp *rsp) |
556 | { |
557 | struct mcs *mcs; |
558 | int i; |
559 | |
560 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
561 | return MCS_AF_ERR_INVALID_MCSID; |
562 | |
563 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
564 | |
565 | for (i = 0; i < req->sa_cnt; i++) |
566 | mcs_sa_plcy_write(mcs, plcy: &req->plcy[i][0], |
567 | sa: req->sa_index[i], dir: req->dir); |
568 | return 0; |
569 | } |
570 | |
571 | int rvu_mbox_handler_mcs_rx_sc_cam_write(struct rvu *rvu, |
572 | struct mcs_rx_sc_cam_write_req *req, |
573 | struct msg_rsp *rsp) |
574 | { |
575 | struct mcs *mcs; |
576 | |
577 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
578 | return MCS_AF_ERR_INVALID_MCSID; |
579 | |
580 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
581 | mcs_rx_sc_cam_write(mcs, sci: req->sci, secy: req->secy_id, sc_id: req->sc_id); |
582 | return 0; |
583 | } |
584 | |
585 | int rvu_mbox_handler_mcs_secy_plcy_write(struct rvu *rvu, |
586 | struct mcs_secy_plcy_write_req *req, |
587 | struct msg_rsp *rsp) |
588 | { struct mcs *mcs; |
589 | |
590 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
591 | return MCS_AF_ERR_INVALID_MCSID; |
592 | |
593 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
594 | |
595 | mcs_secy_plcy_write(mcs, plcy: req->plcy, |
596 | id: req->secy_id, dir: req->dir); |
597 | return 0; |
598 | } |
599 | |
600 | int rvu_mbox_handler_mcs_flowid_entry_write(struct rvu *rvu, |
601 | struct mcs_flowid_entry_write_req *req, |
602 | struct msg_rsp *rsp) |
603 | { |
604 | struct secy_mem_map map; |
605 | struct mcs *mcs; |
606 | |
607 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
608 | return MCS_AF_ERR_INVALID_MCSID; |
609 | |
610 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
611 | |
612 | /* TODO validate the flowid */ |
613 | mcs_flowid_entry_write(mcs, data: req->data, mask: req->mask, |
614 | id: req->flow_id, dir: req->dir); |
615 | map.secy = req->secy_id; |
616 | map.sc = req->sc_id; |
617 | map.ctrl_pkt = req->ctrl_pkt; |
618 | map.flow_id = req->flow_id; |
619 | map.sci = req->sci; |
620 | mcs->mcs_ops->mcs_flowid_secy_map(mcs, &map, req->dir); |
621 | if (req->ena) |
622 | mcs_ena_dis_flowid_entry(mcs, id: req->flow_id, |
623 | dir: req->dir, ena: true); |
624 | return 0; |
625 | } |
626 | |
627 | int rvu_mbox_handler_mcs_free_resources(struct rvu *rvu, |
628 | struct mcs_free_rsrc_req *req, |
629 | struct msg_rsp *rsp) |
630 | { |
631 | u16 pcifunc = req->hdr.pcifunc; |
632 | struct mcs_rsrc_map *map; |
633 | struct mcs *mcs; |
634 | int rc = 0; |
635 | |
636 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
637 | return MCS_AF_ERR_INVALID_MCSID; |
638 | |
639 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
640 | |
641 | if (req->dir == MCS_RX) |
642 | map = &mcs->rx; |
643 | else |
644 | map = &mcs->tx; |
645 | |
646 | mutex_lock(&rvu->rsrc_lock); |
647 | /* Free all the cam resources mapped to PF/VF */ |
648 | if (req->all) { |
649 | rc = mcs_free_all_rsrc(mcs, dir: req->dir, pcifunc); |
650 | goto exit; |
651 | } |
652 | |
653 | switch (req->rsrc_type) { |
654 | case MCS_RSRC_TYPE_FLOWID: |
655 | rc = mcs_free_rsrc(rsrc: &map->flow_ids, pf_map: map->flowid2pf_map, rsrc_id: req->rsrc_id, pcifunc); |
656 | mcs_ena_dis_flowid_entry(mcs, id: req->rsrc_id, dir: req->dir, ena: false); |
657 | break; |
658 | case MCS_RSRC_TYPE_SECY: |
659 | rc = mcs_free_rsrc(rsrc: &map->secy, pf_map: map->secy2pf_map, rsrc_id: req->rsrc_id, pcifunc); |
660 | mcs_clear_secy_plcy(mcs, secy_id: req->rsrc_id, dir: req->dir); |
661 | break; |
662 | case MCS_RSRC_TYPE_SC: |
663 | rc = mcs_free_rsrc(rsrc: &map->sc, pf_map: map->sc2pf_map, rsrc_id: req->rsrc_id, pcifunc); |
664 | /* Disable SC CAM only on RX side */ |
665 | if (req->dir == MCS_RX) |
666 | mcs_ena_dis_sc_cam_entry(mcs, id: req->rsrc_id, ena: false); |
667 | break; |
668 | case MCS_RSRC_TYPE_SA: |
669 | rc = mcs_free_rsrc(rsrc: &map->sa, pf_map: map->sa2pf_map, rsrc_id: req->rsrc_id, pcifunc); |
670 | break; |
671 | } |
672 | exit: |
673 | mutex_unlock(lock: &rvu->rsrc_lock); |
674 | return rc; |
675 | } |
676 | |
677 | int rvu_mbox_handler_mcs_alloc_resources(struct rvu *rvu, |
678 | struct mcs_alloc_rsrc_req *req, |
679 | struct mcs_alloc_rsrc_rsp *rsp) |
680 | { |
681 | u16 pcifunc = req->hdr.pcifunc; |
682 | struct mcs_rsrc_map *map; |
683 | struct mcs *mcs; |
684 | int rsrc_id, i; |
685 | |
686 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
687 | return MCS_AF_ERR_INVALID_MCSID; |
688 | |
689 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
690 | |
691 | if (req->dir == MCS_RX) |
692 | map = &mcs->rx; |
693 | else |
694 | map = &mcs->tx; |
695 | |
696 | mutex_lock(&rvu->rsrc_lock); |
697 | |
698 | if (req->all) { |
699 | rsrc_id = mcs_alloc_all_rsrc(mcs, flowid: &rsp->flow_ids[0], |
700 | secy_id: &rsp->secy_ids[0], |
701 | sc_id: &rsp->sc_ids[0], |
702 | sa1_id: &rsp->sa_ids[0], |
703 | sa2_id: &rsp->sa_ids[1], |
704 | pcifunc, dir: req->dir); |
705 | goto exit; |
706 | } |
707 | |
708 | switch (req->rsrc_type) { |
709 | case MCS_RSRC_TYPE_FLOWID: |
710 | for (i = 0; i < req->rsrc_cnt; i++) { |
711 | rsrc_id = mcs_alloc_rsrc(rsrc: &map->flow_ids, pf_map: map->flowid2pf_map, pcifunc); |
712 | if (rsrc_id < 0) |
713 | goto exit; |
714 | rsp->flow_ids[i] = rsrc_id; |
715 | rsp->rsrc_cnt++; |
716 | } |
717 | break; |
718 | case MCS_RSRC_TYPE_SECY: |
719 | for (i = 0; i < req->rsrc_cnt; i++) { |
720 | rsrc_id = mcs_alloc_rsrc(rsrc: &map->secy, pf_map: map->secy2pf_map, pcifunc); |
721 | if (rsrc_id < 0) |
722 | goto exit; |
723 | rsp->secy_ids[i] = rsrc_id; |
724 | rsp->rsrc_cnt++; |
725 | } |
726 | break; |
727 | case MCS_RSRC_TYPE_SC: |
728 | for (i = 0; i < req->rsrc_cnt; i++) { |
729 | rsrc_id = mcs_alloc_rsrc(rsrc: &map->sc, pf_map: map->sc2pf_map, pcifunc); |
730 | if (rsrc_id < 0) |
731 | goto exit; |
732 | rsp->sc_ids[i] = rsrc_id; |
733 | rsp->rsrc_cnt++; |
734 | } |
735 | break; |
736 | case MCS_RSRC_TYPE_SA: |
737 | for (i = 0; i < req->rsrc_cnt; i++) { |
738 | rsrc_id = mcs_alloc_rsrc(rsrc: &map->sa, pf_map: map->sa2pf_map, pcifunc); |
739 | if (rsrc_id < 0) |
740 | goto exit; |
741 | rsp->sa_ids[i] = rsrc_id; |
742 | rsp->rsrc_cnt++; |
743 | } |
744 | break; |
745 | } |
746 | |
747 | rsp->rsrc_type = req->rsrc_type; |
748 | rsp->dir = req->dir; |
749 | rsp->mcs_id = req->mcs_id; |
750 | rsp->all = req->all; |
751 | |
752 | exit: |
753 | if (rsrc_id < 0) |
754 | dev_err(rvu->dev, "Failed to allocate the mcs resources for PCIFUNC:%d\n" , pcifunc); |
755 | mutex_unlock(lock: &rvu->rsrc_lock); |
756 | return 0; |
757 | } |
758 | |
759 | int rvu_mbox_handler_mcs_alloc_ctrl_pkt_rule(struct rvu *rvu, |
760 | struct mcs_alloc_ctrl_pkt_rule_req *req, |
761 | struct mcs_alloc_ctrl_pkt_rule_rsp *rsp) |
762 | { |
763 | u16 pcifunc = req->hdr.pcifunc; |
764 | struct mcs_rsrc_map *map; |
765 | struct mcs *mcs; |
766 | int rsrc_id; |
767 | u16 offset; |
768 | |
769 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
770 | return MCS_AF_ERR_INVALID_MCSID; |
771 | |
772 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
773 | |
774 | map = (req->dir == MCS_RX) ? &mcs->rx : &mcs->tx; |
775 | |
776 | mutex_lock(&rvu->rsrc_lock); |
777 | |
778 | switch (req->rule_type) { |
779 | case MCS_CTRL_PKT_RULE_TYPE_ETH: |
780 | offset = MCS_CTRLPKT_ETYPE_RULE_OFFSET; |
781 | break; |
782 | case MCS_CTRL_PKT_RULE_TYPE_DA: |
783 | offset = MCS_CTRLPKT_DA_RULE_OFFSET; |
784 | break; |
785 | case MCS_CTRL_PKT_RULE_TYPE_RANGE: |
786 | offset = MCS_CTRLPKT_DA_RANGE_RULE_OFFSET; |
787 | break; |
788 | case MCS_CTRL_PKT_RULE_TYPE_COMBO: |
789 | offset = MCS_CTRLPKT_COMBO_RULE_OFFSET; |
790 | break; |
791 | case MCS_CTRL_PKT_RULE_TYPE_MAC: |
792 | offset = MCS_CTRLPKT_MAC_EN_RULE_OFFSET; |
793 | break; |
794 | } |
795 | |
796 | rsrc_id = mcs_alloc_ctrlpktrule(rsrc: &map->ctrlpktrule, pf_map: map->ctrlpktrule2pf_map, offset, |
797 | pcifunc); |
798 | if (rsrc_id < 0) |
799 | goto exit; |
800 | |
801 | rsp->rule_idx = rsrc_id; |
802 | rsp->rule_type = req->rule_type; |
803 | rsp->dir = req->dir; |
804 | rsp->mcs_id = req->mcs_id; |
805 | |
806 | mutex_unlock(lock: &rvu->rsrc_lock); |
807 | return 0; |
808 | exit: |
809 | if (rsrc_id < 0) |
810 | dev_err(rvu->dev, "Failed to allocate the mcs ctrl pkt rule for PCIFUNC:%d\n" , |
811 | pcifunc); |
812 | mutex_unlock(lock: &rvu->rsrc_lock); |
813 | return rsrc_id; |
814 | } |
815 | |
816 | int rvu_mbox_handler_mcs_free_ctrl_pkt_rule(struct rvu *rvu, |
817 | struct mcs_free_ctrl_pkt_rule_req *req, |
818 | struct msg_rsp *rsp) |
819 | { |
820 | struct mcs *mcs; |
821 | int rc; |
822 | |
823 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
824 | return MCS_AF_ERR_INVALID_MCSID; |
825 | |
826 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
827 | |
828 | mutex_lock(&rvu->rsrc_lock); |
829 | |
830 | rc = mcs_free_ctrlpktrule(mcs, req); |
831 | |
832 | mutex_unlock(lock: &rvu->rsrc_lock); |
833 | |
834 | return rc; |
835 | } |
836 | |
837 | int rvu_mbox_handler_mcs_ctrl_pkt_rule_write(struct rvu *rvu, |
838 | struct mcs_ctrl_pkt_rule_write_req *req, |
839 | struct msg_rsp *rsp) |
840 | { |
841 | struct mcs *mcs; |
842 | int rc; |
843 | |
844 | if (req->mcs_id >= rvu->mcs_blk_cnt) |
845 | return MCS_AF_ERR_INVALID_MCSID; |
846 | |
847 | mcs = mcs_get_pdata(mcs_id: req->mcs_id); |
848 | |
849 | rc = mcs_ctrlpktrule_write(mcs, req); |
850 | |
851 | return rc; |
852 | } |
853 | |
854 | static void rvu_mcs_set_lmac_bmap(struct rvu *rvu) |
855 | { |
856 | struct mcs *mcs = mcs_get_pdata(mcs_id: 0); |
857 | unsigned long lmac_bmap; |
858 | int cgx, lmac, port; |
859 | |
860 | for (port = 0; port < mcs->hw->lmac_cnt; port++) { |
861 | cgx = port / rvu->hw->lmac_per_cgx; |
862 | lmac = port % rvu->hw->lmac_per_cgx; |
863 | if (!is_lmac_valid(cgx: rvu_cgx_pdata(cgx_id: cgx, rvu), lmac_id: lmac)) |
864 | continue; |
865 | set_bit(nr: port, addr: &lmac_bmap); |
866 | } |
867 | mcs->hw->lmac_bmap = lmac_bmap; |
868 | } |
869 | |
870 | int rvu_mcs_init(struct rvu *rvu) |
871 | { |
872 | struct rvu_hwinfo *hw = rvu->hw; |
873 | int lmac, err = 0, mcs_id; |
874 | struct mcs *mcs; |
875 | |
876 | rvu->mcs_blk_cnt = mcs_get_blkcnt(); |
877 | |
878 | if (!rvu->mcs_blk_cnt) |
879 | return 0; |
880 | |
881 | /* Needed only for CN10K-B */ |
882 | if (rvu->mcs_blk_cnt == 1) { |
883 | err = mcs_set_lmac_channels(mcs_id: 0, base: hw->cgx_chan_base); |
884 | if (err) |
885 | return err; |
886 | /* Set active lmacs */ |
887 | rvu_mcs_set_lmac_bmap(rvu); |
888 | } |
889 | |
890 | /* Install default tcam bypass entry and set port to operational mode */ |
891 | for (mcs_id = 0; mcs_id < rvu->mcs_blk_cnt; mcs_id++) { |
892 | mcs = mcs_get_pdata(mcs_id); |
893 | mcs_install_flowid_bypass_entry(mcs); |
894 | for (lmac = 0; lmac < mcs->hw->lmac_cnt; lmac++) |
895 | mcs_set_lmac_mode(mcs, lmac_id: lmac, mode: 0); |
896 | |
897 | mcs->rvu = rvu; |
898 | |
899 | /* Allocated memory for PFVF data */ |
900 | mcs->pf = devm_kcalloc(dev: mcs->dev, n: hw->total_pfs, |
901 | size: sizeof(struct mcs_pfvf), GFP_KERNEL); |
902 | if (!mcs->pf) |
903 | return -ENOMEM; |
904 | |
905 | mcs->vf = devm_kcalloc(dev: mcs->dev, n: hw->total_vfs, |
906 | size: sizeof(struct mcs_pfvf), GFP_KERNEL); |
907 | if (!mcs->vf) |
908 | return -ENOMEM; |
909 | } |
910 | |
911 | /* Initialize the wq for handling mcs interrupts */ |
912 | INIT_LIST_HEAD(list: &rvu->mcs_intrq_head); |
913 | INIT_WORK(&rvu->mcs_intr_work, mcs_intr_handler_task); |
914 | rvu->mcs_intr_wq = alloc_workqueue(fmt: "mcs_intr_wq" , flags: 0, max_active: 0); |
915 | if (!rvu->mcs_intr_wq) { |
916 | dev_err(rvu->dev, "mcs alloc workqueue failed\n" ); |
917 | return -ENOMEM; |
918 | } |
919 | |
920 | return err; |
921 | } |
922 | |
923 | void rvu_mcs_exit(struct rvu *rvu) |
924 | { |
925 | if (!rvu->mcs_intr_wq) |
926 | return; |
927 | |
928 | flush_workqueue(rvu->mcs_intr_wq); |
929 | destroy_workqueue(wq: rvu->mcs_intr_wq); |
930 | rvu->mcs_intr_wq = NULL; |
931 | } |
932 | |