1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell OcteonTx2 RVU Admin Function driver
3  *
4  * Copyright (C) 2018 Marvell International Ltd.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 #include <linux/types.h>
12 #include <linux/module.h>
13 #include <linux/pci.h>
14 
15 #include "rvu.h"
16 #include "cgx.h"
17 
18 struct cgx_evq_entry {
19 	struct list_head evq_node;
20 	struct cgx_link_event link_event;
21 };
22 
23 #define M(_name, _id, _fn_name, _req_type, _rsp_type)			\
24 static struct _req_type __maybe_unused					\
25 *otx2_mbox_alloc_msg_ ## _fn_name(struct rvu *rvu, int devid)		\
26 {									\
27 	struct _req_type *req;						\
28 									\
29 	req = (struct _req_type *)otx2_mbox_alloc_msg_rsp(		\
30 		&rvu->afpf_wq_info.mbox_up, devid, sizeof(struct _req_type), \
31 		sizeof(struct _rsp_type));				\
32 	if (!req)							\
33 		return NULL;						\
34 	req->hdr.sig = OTX2_MBOX_REQ_SIG;				\
35 	req->hdr.id = _id;						\
36 	return req;							\
37 }
38 
39 MBOX_UP_CGX_MESSAGES
40 #undef M
41 
42 /* Returns bitmap of mapped PFs */
43 static inline u16 cgxlmac_to_pfmap(struct rvu *rvu, u8 cgx_id, u8 lmac_id)
44 {
45 	return rvu->cgxlmac2pf_map[CGX_OFFSET(cgx_id) + lmac_id];
46 }
47 
48 static inline u8 cgxlmac_id_to_bmap(u8 cgx_id, u8 lmac_id)
49 {
50 	return ((cgx_id & 0xF) << 4) | (lmac_id & 0xF);
51 }
52 
53 void *rvu_cgx_pdata(u8 cgx_id, struct rvu *rvu)
54 {
55 	if (cgx_id >= rvu->cgx_cnt_max)
56 		return NULL;
57 
58 	return rvu->cgx_idmap[cgx_id];
59 }
60 
61 static int rvu_map_cgx_lmac_pf(struct rvu *rvu)
62 {
63 	struct npc_pkind *pkind = &rvu->hw->pkind;
64 	int cgx_cnt_max = rvu->cgx_cnt_max;
65 	int cgx, lmac_cnt, lmac;
66 	int pf = PF_CGXMAP_BASE;
67 	int size, free_pkind;
68 
69 	if (!cgx_cnt_max)
70 		return 0;
71 
72 	if (cgx_cnt_max > 0xF || MAX_LMAC_PER_CGX > 0xF)
73 		return -EINVAL;
74 
75 	/* Alloc map table
76 	 * An additional entry is required since PF id starts from 1 and
77 	 * hence entry at offset 0 is invalid.
78 	 */
79 	size = (cgx_cnt_max * MAX_LMAC_PER_CGX + 1) * sizeof(u8);
80 	rvu->pf2cgxlmac_map = devm_kmalloc(rvu->dev, size, GFP_KERNEL);
81 	if (!rvu->pf2cgxlmac_map)
82 		return -ENOMEM;
83 
84 	/* Initialize all entries with an invalid cgx and lmac id */
85 	memset(rvu->pf2cgxlmac_map, 0xFF, size);
86 
87 	/* Reverse map table */
88 	rvu->cgxlmac2pf_map = devm_kzalloc(rvu->dev,
89 				  cgx_cnt_max * MAX_LMAC_PER_CGX * sizeof(u16),
90 				  GFP_KERNEL);
91 	if (!rvu->cgxlmac2pf_map)
92 		return -ENOMEM;
93 
94 	rvu->cgx_mapped_pfs = 0;
95 	for (cgx = 0; cgx < cgx_cnt_max; cgx++) {
96 		if (!rvu_cgx_pdata(cgx, rvu))
97 			continue;
98 		lmac_cnt = cgx_get_lmac_cnt(rvu_cgx_pdata(cgx, rvu));
99 		for (lmac = 0; lmac < lmac_cnt; lmac++, pf++) {
100 			rvu->pf2cgxlmac_map[pf] = cgxlmac_id_to_bmap(cgx, lmac);
101 			rvu->cgxlmac2pf_map[CGX_OFFSET(cgx) + lmac] = 1 << pf;
102 			free_pkind = rvu_alloc_rsrc(&pkind->rsrc);
103 			pkind->pfchan_map[free_pkind] = ((pf) & 0x3F) << 16;
104 			rvu->cgx_mapped_pfs++;
105 		}
106 	}
107 	return 0;
108 }
109 
110 static int rvu_cgx_send_link_info(int cgx_id, int lmac_id, struct rvu *rvu)
111 {
112 	struct cgx_evq_entry *qentry;
113 	unsigned long flags;
114 	int err;
115 
116 	qentry = kmalloc(sizeof(*qentry), GFP_KERNEL);
117 	if (!qentry)
118 		return -ENOMEM;
119 
120 	/* Lock the event queue before we read the local link status */
121 	spin_lock_irqsave(&rvu->cgx_evq_lock, flags);
122 	err = cgx_get_link_info(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
123 				&qentry->link_event.link_uinfo);
124 	qentry->link_event.cgx_id = cgx_id;
125 	qentry->link_event.lmac_id = lmac_id;
126 	if (err)
127 		goto skip_add;
128 	list_add_tail(&qentry->evq_node, &rvu->cgx_evq_head);
129 skip_add:
130 	spin_unlock_irqrestore(&rvu->cgx_evq_lock, flags);
131 
132 	/* start worker to process the events */
133 	queue_work(rvu->cgx_evh_wq, &rvu->cgx_evh_work);
134 
135 	return 0;
136 }
137 
138 /* This is called from interrupt context and is expected to be atomic */
139 static int cgx_lmac_postevent(struct cgx_link_event *event, void *data)
140 {
141 	struct cgx_evq_entry *qentry;
142 	struct rvu *rvu = data;
143 
144 	/* post event to the event queue */
145 	qentry = kmalloc(sizeof(*qentry), GFP_ATOMIC);
146 	if (!qentry)
147 		return -ENOMEM;
148 	qentry->link_event = *event;
149 	spin_lock(&rvu->cgx_evq_lock);
150 	list_add_tail(&qentry->evq_node, &rvu->cgx_evq_head);
151 	spin_unlock(&rvu->cgx_evq_lock);
152 
153 	/* start worker to process the events */
154 	queue_work(rvu->cgx_evh_wq, &rvu->cgx_evh_work);
155 
156 	return 0;
157 }
158 
159 static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu)
160 {
161 	struct cgx_link_user_info *linfo;
162 	struct cgx_link_info_msg *msg;
163 	unsigned long pfmap;
164 	int err, pfid;
165 
166 	linfo = &event->link_uinfo;
167 	pfmap = cgxlmac_to_pfmap(rvu, event->cgx_id, event->lmac_id);
168 
169 	do {
170 		pfid = find_first_bit(&pfmap, 16);
171 		clear_bit(pfid, &pfmap);
172 
173 		/* check if notification is enabled */
174 		if (!test_bit(pfid, &rvu->pf_notify_bmap)) {
175 			dev_info(rvu->dev, "cgx %d: lmac %d Link status %s\n",
176 				 event->cgx_id, event->lmac_id,
177 				 linfo->link_up ? "UP" : "DOWN");
178 			continue;
179 		}
180 
181 		/* Send mbox message to PF */
182 		msg = otx2_mbox_alloc_msg_cgx_link_event(rvu, pfid);
183 		if (!msg)
184 			continue;
185 		msg->link_info = *linfo;
186 		otx2_mbox_msg_send(&rvu->afpf_wq_info.mbox_up, pfid);
187 		err = otx2_mbox_wait_for_rsp(&rvu->afpf_wq_info.mbox_up, pfid);
188 		if (err)
189 			dev_warn(rvu->dev, "notification to pf %d failed\n",
190 				 pfid);
191 	} while (pfmap);
192 }
193 
194 static void cgx_evhandler_task(struct work_struct *work)
195 {
196 	struct rvu *rvu = container_of(work, struct rvu, cgx_evh_work);
197 	struct cgx_evq_entry *qentry;
198 	struct cgx_link_event *event;
199 	unsigned long flags;
200 
201 	do {
202 		/* Dequeue an event */
203 		spin_lock_irqsave(&rvu->cgx_evq_lock, flags);
204 		qentry = list_first_entry_or_null(&rvu->cgx_evq_head,
205 						  struct cgx_evq_entry,
206 						  evq_node);
207 		if (qentry)
208 			list_del(&qentry->evq_node);
209 		spin_unlock_irqrestore(&rvu->cgx_evq_lock, flags);
210 		if (!qentry)
211 			break; /* nothing more to process */
212 
213 		event = &qentry->link_event;
214 
215 		/* process event */
216 		cgx_notify_pfs(event, rvu);
217 		kfree(qentry);
218 	} while (1);
219 }
220 
221 static int cgx_lmac_event_handler_init(struct rvu *rvu)
222 {
223 	struct cgx_event_cb cb;
224 	int cgx, lmac, err;
225 	void *cgxd;
226 
227 	spin_lock_init(&rvu->cgx_evq_lock);
228 	INIT_LIST_HEAD(&rvu->cgx_evq_head);
229 	INIT_WORK(&rvu->cgx_evh_work, cgx_evhandler_task);
230 	rvu->cgx_evh_wq = alloc_workqueue("rvu_evh_wq", 0, 0);
231 	if (!rvu->cgx_evh_wq) {
232 		dev_err(rvu->dev, "alloc workqueue failed");
233 		return -ENOMEM;
234 	}
235 
236 	cb.notify_link_chg = cgx_lmac_postevent; /* link change call back */
237 	cb.data = rvu;
238 
239 	for (cgx = 0; cgx <= rvu->cgx_cnt_max; cgx++) {
240 		cgxd = rvu_cgx_pdata(cgx, rvu);
241 		if (!cgxd)
242 			continue;
243 		for (lmac = 0; lmac < cgx_get_lmac_cnt(cgxd); lmac++) {
244 			err = cgx_lmac_evh_register(&cb, cgxd, lmac);
245 			if (err)
246 				dev_err(rvu->dev,
247 					"%d:%d handler register failed\n",
248 					cgx, lmac);
249 		}
250 	}
251 
252 	return 0;
253 }
254 
255 static void rvu_cgx_wq_destroy(struct rvu *rvu)
256 {
257 	if (rvu->cgx_evh_wq) {
258 		flush_workqueue(rvu->cgx_evh_wq);
259 		destroy_workqueue(rvu->cgx_evh_wq);
260 		rvu->cgx_evh_wq = NULL;
261 	}
262 }
263 
264 int rvu_cgx_init(struct rvu *rvu)
265 {
266 	int cgx, err;
267 	void *cgxd;
268 
269 	/* CGX port id starts from 0 and are not necessarily contiguous
270 	 * Hence we allocate resources based on the maximum port id value.
271 	 */
272 	rvu->cgx_cnt_max = cgx_get_cgxcnt_max();
273 	if (!rvu->cgx_cnt_max) {
274 		dev_info(rvu->dev, "No CGX devices found!\n");
275 		return -ENODEV;
276 	}
277 
278 	rvu->cgx_idmap = devm_kzalloc(rvu->dev, rvu->cgx_cnt_max *
279 				      sizeof(void *), GFP_KERNEL);
280 	if (!rvu->cgx_idmap)
281 		return -ENOMEM;
282 
283 	/* Initialize the cgxdata table */
284 	for (cgx = 0; cgx < rvu->cgx_cnt_max; cgx++)
285 		rvu->cgx_idmap[cgx] = cgx_get_pdata(cgx);
286 
287 	/* Map CGX LMAC interfaces to RVU PFs */
288 	err = rvu_map_cgx_lmac_pf(rvu);
289 	if (err)
290 		return err;
291 
292 	/* Register for CGX events */
293 	err = cgx_lmac_event_handler_init(rvu);
294 	if (err)
295 		return err;
296 
297 	/* Ensure event handler registration is completed, before
298 	 * we turn on the links
299 	 */
300 	mb();
301 
302 	/* Do link up for all CGX ports */
303 	for (cgx = 0; cgx <= rvu->cgx_cnt_max; cgx++) {
304 		cgxd = rvu_cgx_pdata(cgx, rvu);
305 		if (!cgxd)
306 			continue;
307 		err = cgx_lmac_linkup_start(cgxd);
308 		if (err)
309 			dev_err(rvu->dev,
310 				"Link up process failed to start on cgx %d\n",
311 				cgx);
312 	}
313 
314 	return 0;
315 }
316 
317 int rvu_cgx_exit(struct rvu *rvu)
318 {
319 	int cgx, lmac;
320 	void *cgxd;
321 
322 	for (cgx = 0; cgx <= rvu->cgx_cnt_max; cgx++) {
323 		cgxd = rvu_cgx_pdata(cgx, rvu);
324 		if (!cgxd)
325 			continue;
326 		for (lmac = 0; lmac < cgx_get_lmac_cnt(cgxd); lmac++)
327 			cgx_lmac_evh_unregister(cgxd, lmac);
328 	}
329 
330 	/* Ensure event handler unregister is completed */
331 	mb();
332 
333 	rvu_cgx_wq_destroy(rvu);
334 	return 0;
335 }
336 
337 int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start)
338 {
339 	int pf = rvu_get_pf(pcifunc);
340 	u8 cgx_id, lmac_id;
341 
342 	/* This msg is expected only from PFs that are mapped to CGX LMACs,
343 	 * if received from other PF/VF simply ACK, nothing to do.
344 	 */
345 	if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
346 		return -ENODEV;
347 
348 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
349 
350 	cgx_lmac_rx_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, start);
351 
352 	return 0;
353 }
354 
355 int rvu_mbox_handler_cgx_start_rxtx(struct rvu *rvu, struct msg_req *req,
356 				    struct msg_rsp *rsp)
357 {
358 	rvu_cgx_config_rxtx(rvu, req->hdr.pcifunc, true);
359 	return 0;
360 }
361 
362 int rvu_mbox_handler_cgx_stop_rxtx(struct rvu *rvu, struct msg_req *req,
363 				   struct msg_rsp *rsp)
364 {
365 	rvu_cgx_config_rxtx(rvu, req->hdr.pcifunc, false);
366 	return 0;
367 }
368 
369 int rvu_mbox_handler_cgx_stats(struct rvu *rvu, struct msg_req *req,
370 			       struct cgx_stats_rsp *rsp)
371 {
372 	int pf = rvu_get_pf(req->hdr.pcifunc);
373 	int stat = 0, err = 0;
374 	u64 tx_stat, rx_stat;
375 	u8 cgx_idx, lmac;
376 	void *cgxd;
377 
378 	if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
379 	    !is_pf_cgxmapped(rvu, pf))
380 		return -ENODEV;
381 
382 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac);
383 	cgxd = rvu_cgx_pdata(cgx_idx, rvu);
384 
385 	/* Rx stats */
386 	while (stat < CGX_RX_STATS_COUNT) {
387 		err = cgx_get_rx_stats(cgxd, lmac, stat, &rx_stat);
388 		if (err)
389 			return err;
390 		rsp->rx_stats[stat] = rx_stat;
391 		stat++;
392 	}
393 
394 	/* Tx stats */
395 	stat = 0;
396 	while (stat < CGX_TX_STATS_COUNT) {
397 		err = cgx_get_tx_stats(cgxd, lmac, stat, &tx_stat);
398 		if (err)
399 			return err;
400 		rsp->tx_stats[stat] = tx_stat;
401 		stat++;
402 	}
403 	return 0;
404 }
405 
406 int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu,
407 				      struct cgx_mac_addr_set_or_get *req,
408 				      struct cgx_mac_addr_set_or_get *rsp)
409 {
410 	int pf = rvu_get_pf(req->hdr.pcifunc);
411 	u8 cgx_id, lmac_id;
412 
413 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
414 
415 	cgx_lmac_addr_set(cgx_id, lmac_id, req->mac_addr);
416 
417 	return 0;
418 }
419 
420 int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu,
421 				      struct cgx_mac_addr_set_or_get *req,
422 				      struct cgx_mac_addr_set_or_get *rsp)
423 {
424 	int pf = rvu_get_pf(req->hdr.pcifunc);
425 	u8 cgx_id, lmac_id;
426 	int rc = 0, i;
427 	u64 cfg;
428 
429 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
430 
431 	rsp->hdr.rc = rc;
432 	cfg = cgx_lmac_addr_get(cgx_id, lmac_id);
433 	/* copy 48 bit mac address to req->mac_addr */
434 	for (i = 0; i < ETH_ALEN; i++)
435 		rsp->mac_addr[i] = cfg >> (ETH_ALEN - 1 - i) * 8;
436 	return 0;
437 }
438 
439 int rvu_mbox_handler_cgx_promisc_enable(struct rvu *rvu, struct msg_req *req,
440 					struct msg_rsp *rsp)
441 {
442 	u16 pcifunc = req->hdr.pcifunc;
443 	int pf = rvu_get_pf(pcifunc);
444 	u8 cgx_id, lmac_id;
445 
446 	/* This msg is expected only from PFs that are mapped to CGX LMACs,
447 	 * if received from other PF/VF simply ACK, nothing to do.
448 	 */
449 	if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
450 	    !is_pf_cgxmapped(rvu, pf))
451 		return -ENODEV;
452 
453 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
454 
455 	cgx_lmac_promisc_config(cgx_id, lmac_id, true);
456 	return 0;
457 }
458 
459 int rvu_mbox_handler_cgx_promisc_disable(struct rvu *rvu, struct msg_req *req,
460 					 struct msg_rsp *rsp)
461 {
462 	u16 pcifunc = req->hdr.pcifunc;
463 	int pf = rvu_get_pf(pcifunc);
464 	u8 cgx_id, lmac_id;
465 
466 	/* This msg is expected only from PFs that are mapped to CGX LMACs,
467 	 * if received from other PF/VF simply ACK, nothing to do.
468 	 */
469 	if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) ||
470 	    !is_pf_cgxmapped(rvu, pf))
471 		return -ENODEV;
472 
473 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
474 
475 	cgx_lmac_promisc_config(cgx_id, lmac_id, false);
476 	return 0;
477 }
478 
479 static int rvu_cgx_config_linkevents(struct rvu *rvu, u16 pcifunc, bool en)
480 {
481 	int pf = rvu_get_pf(pcifunc);
482 	u8 cgx_id, lmac_id;
483 
484 	/* This msg is expected only from PFs that are mapped to CGX LMACs,
485 	 * if received from other PF/VF simply ACK, nothing to do.
486 	 */
487 	if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
488 		return -ENODEV;
489 
490 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
491 
492 	if (en) {
493 		set_bit(pf, &rvu->pf_notify_bmap);
494 		/* Send the current link status to PF */
495 		rvu_cgx_send_link_info(cgx_id, lmac_id, rvu);
496 	} else {
497 		clear_bit(pf, &rvu->pf_notify_bmap);
498 	}
499 
500 	return 0;
501 }
502 
503 int rvu_mbox_handler_cgx_start_linkevents(struct rvu *rvu, struct msg_req *req,
504 					  struct msg_rsp *rsp)
505 {
506 	rvu_cgx_config_linkevents(rvu, req->hdr.pcifunc, true);
507 	return 0;
508 }
509 
510 int rvu_mbox_handler_cgx_stop_linkevents(struct rvu *rvu, struct msg_req *req,
511 					 struct msg_rsp *rsp)
512 {
513 	rvu_cgx_config_linkevents(rvu, req->hdr.pcifunc, false);
514 	return 0;
515 }
516 
517 int rvu_mbox_handler_cgx_get_linkinfo(struct rvu *rvu, struct msg_req *req,
518 				      struct cgx_link_info_msg *rsp)
519 {
520 	u8 cgx_id, lmac_id;
521 	int pf, err;
522 
523 	pf = rvu_get_pf(req->hdr.pcifunc);
524 
525 	if (!is_pf_cgxmapped(rvu, pf))
526 		return -ENODEV;
527 
528 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
529 
530 	err = cgx_get_link_info(rvu_cgx_pdata(cgx_id, rvu), lmac_id,
531 				&rsp->link_info);
532 	return err;
533 }
534 
535 static int rvu_cgx_config_intlbk(struct rvu *rvu, u16 pcifunc, bool en)
536 {
537 	int pf = rvu_get_pf(pcifunc);
538 	u8 cgx_id, lmac_id;
539 
540 	/* This msg is expected only from PFs that are mapped to CGX LMACs,
541 	 * if received from other PF/VF simply ACK, nothing to do.
542 	 */
543 	if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf))
544 		return -ENODEV;
545 
546 	rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id);
547 
548 	return cgx_lmac_internal_loopback(rvu_cgx_pdata(cgx_id, rvu),
549 					  lmac_id, en);
550 }
551 
552 int rvu_mbox_handler_cgx_intlbk_enable(struct rvu *rvu, struct msg_req *req,
553 				       struct msg_rsp *rsp)
554 {
555 	rvu_cgx_config_intlbk(rvu, req->hdr.pcifunc, true);
556 	return 0;
557 }
558 
559 int rvu_mbox_handler_cgx_intlbk_disable(struct rvu *rvu, struct msg_req *req,
560 					struct msg_rsp *rsp)
561 {
562 	rvu_cgx_config_intlbk(rvu, req->hdr.pcifunc, false);
563 	return 0;
564 }
565