static int rvu_map_cgx_lmac_pf(struct rvu *rvu) { struct npc_pkind *pkind = &rvu->hw->pkind; int cgx_cnt_max = rvu->cgx_cnt_max; int cgx, lmac_cnt, lmac; int pf = PF_CGXMAP_BASE; int size, free_pkind; if (!cgx_cnt_max) return 0; if (cgx_cnt_max > 0xF || MAX_LMAC_PER_CGX > 0xF) return -EINVAL; /* Alloc map table * An additional entry is required since PF id starts from 1 and * hence entry at offset 0 is invalid. */ size = (cgx_cnt_max * MAX_LMAC_PER_CGX + 1) * sizeof(u8); rvu->pf2cgxlmac_map = devm_kmalloc(rvu->dev, size, GFP_KERNEL); if (!rvu->pf2cgxlmac_map) return -ENOMEM; /* Initialize all entries with an invalid cgx and lmac id */ memset(rvu->pf2cgxlmac_map, 0xFF, size); /* Reverse map table */ rvu->cgxlmac2pf_map = devm_kzalloc(rvu->dev, cgx_cnt_max * MAX_LMAC_PER_CGX * sizeof(u16), GFP_KERNEL); if (!rvu->cgxlmac2pf_map) return -ENOMEM; rvu->cgx_mapped_pfs = 0; for (cgx = 0; cgx < cgx_cnt_max; cgx++) { if (!rvu_cgx_pdata(cgx, rvu)) continue; lmac_cnt = cgx_get_lmac_cnt(rvu_cgx_pdata(cgx, rvu)); for (lmac = 0; lmac < lmac_cnt; lmac++, pf++) { rvu->pf2cgxlmac_map[pf] = cgxlmac_id_to_bmap(cgx, lmac); rvu->cgxlmac2pf_map[CGX_OFFSET(cgx) + lmac] = 1 << pf; free_pkind = rvu_alloc_rsrc(&pkind->rsrc); pkind->pfchan_map[free_pkind] = ((pf) & 0x3F) << 16; rvu->cgx_mapped_pfs++; } } return 0; }
static void cgx_lmac_event_handler_init(struct rvu *rvu) { struct cgx_event_cb cb; int cgx, lmac, err; void *cgxd; spin_lock_init(&rvu->cgx_evq_lock); INIT_LIST_HEAD(&rvu->cgx_evq_head); INIT_WORK(&rvu->cgx_evh_work, cgx_evhandler_task); rvu->cgx_evh_wq = alloc_workqueue("rvu_evh_wq", 0, 0); if (!rvu->cgx_evh_wq) { dev_err(rvu->dev, "alloc workqueue failed"); return; } cb.notify_link_chg = cgx_lmac_postevent; /* link change call back */ cb.data = rvu; for (cgx = 0; cgx < rvu->cgx_cnt; cgx++) { cgxd = rvu_cgx_pdata(cgx, rvu); for (lmac = 0; lmac < cgx_get_lmac_cnt(cgxd); lmac++) { err = cgx_lmac_evh_register(&cb, cgxd, lmac); if (err) dev_err(rvu->dev, "%d:%d handler register failed\n", cgx, lmac); } } }
static int rvu_cgx_send_link_info(int cgx_id, int lmac_id, struct rvu *rvu) { struct cgx_evq_entry *qentry; unsigned long flags; int err; qentry = kmalloc(sizeof(*qentry), GFP_KERNEL); if (!qentry) return -ENOMEM; /* Lock the event queue before we read the local link status */ spin_lock_irqsave(&rvu->cgx_evq_lock, flags); err = cgx_get_link_info(rvu_cgx_pdata(cgx_id, rvu), lmac_id, &qentry->link_event.link_uinfo); qentry->link_event.cgx_id = cgx_id; qentry->link_event.lmac_id = lmac_id; if (err) goto skip_add; list_add_tail(&qentry->evq_node, &rvu->cgx_evq_head); skip_add: spin_unlock_irqrestore(&rvu->cgx_evq_lock, flags); /* start worker to process the events */ queue_work(rvu->cgx_evh_wq, &rvu->cgx_evh_work); return 0; }
int rvu_cgx_init(struct rvu *rvu) { int cgx, err; void *cgxd; /* CGX port id starts from 0 and are not necessarily contiguous * Hence we allocate resources based on the maximum port id value. */ rvu->cgx_cnt_max = cgx_get_cgxcnt_max(); if (!rvu->cgx_cnt_max) { dev_info(rvu->dev, "No CGX devices found!\n"); return -ENODEV; } rvu->cgx_idmap = devm_kzalloc(rvu->dev, rvu->cgx_cnt_max * sizeof(void *), GFP_KERNEL); if (!rvu->cgx_idmap) return -ENOMEM; /* Initialize the cgxdata table */ for (cgx = 0; cgx < rvu->cgx_cnt_max; cgx++) rvu->cgx_idmap[cgx] = cgx_get_pdata(cgx); /* Map CGX LMAC interfaces to RVU PFs */ err = rvu_map_cgx_lmac_pf(rvu); if (err) return err; /* Register for CGX events */ err = cgx_lmac_event_handler_init(rvu); if (err) return err; /* Ensure event handler registration is completed, before * we turn on the links */ mb(); /* Do link up for all CGX ports */ for (cgx = 0; cgx <= rvu->cgx_cnt_max; cgx++) { cgxd = rvu_cgx_pdata(cgx, rvu); if (!cgxd) continue; err = cgx_lmac_linkup_start(cgxd); if (err) dev_err(rvu->dev, "Link up process failed to start on cgx %d\n", cgx); } return 0; }
static int rvu_cgx_config_intlbk(struct rvu *rvu, u16 pcifunc, bool en) { int pf = rvu_get_pf(pcifunc); u8 cgx_id, lmac_id; /* This msg is expected only from PFs that are mapped to CGX LMACs, * if received from other PF/VF simply ACK, nothing to do. */ if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) return -ENODEV; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); return cgx_lmac_internal_loopback(rvu_cgx_pdata(cgx_id, rvu), lmac_id, en); }
int rvu_mbox_handler_CGX_GET_LINKINFO(struct rvu *rvu, struct msg_req *req, struct cgx_link_info_msg *rsp) { u8 cgx_id, lmac_id; int pf, err; pf = rvu_get_pf(req->hdr.pcifunc); if (!is_pf_cgxmapped(rvu, pf)) return -ENODEV; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); err = cgx_get_link_info(rvu_cgx_pdata(cgx_id, rvu), lmac_id, &rsp->link_info); return err; }
int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start) { int pf = rvu_get_pf(pcifunc); u8 cgx_id, lmac_id; /* This msg is expected only from PFs that are mapped to CGX LMACs, * if received from other PF/VF simply ACK, nothing to do. */ if ((pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) return -ENODEV; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); cgx_lmac_rx_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, start); return 0; }
int rvu_cgx_exit(struct rvu *rvu) { int cgx, lmac; void *cgxd; for (cgx = 0; cgx <= rvu->cgx_cnt_max; cgx++) { cgxd = rvu_cgx_pdata(cgx, rvu); if (!cgxd) continue; for (lmac = 0; lmac < cgx_get_lmac_cnt(cgxd); lmac++) cgx_lmac_evh_unregister(cgxd, lmac); } /* Ensure event handler unregister is completed */ mb(); rvu_cgx_wq_destroy(rvu); return 0; }
int rvu_mbox_handler_CGX_STATS(struct rvu *rvu, struct msg_req *req, struct cgx_stats_rsp *rsp) { int pf = rvu_get_pf(req->hdr.pcifunc); int stat = 0, err = 0; u64 tx_stat, rx_stat; u8 cgx_idx, lmac; void *cgxd; if ((req->hdr.pcifunc & RVU_PFVF_FUNC_MASK) || !is_pf_cgxmapped(rvu, pf)) return -ENODEV; rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac); cgxd = rvu_cgx_pdata(cgx_idx, rvu); /* Rx stats */ while (stat < CGX_RX_STATS_COUNT) { err = cgx_get_rx_stats(cgxd, lmac, stat, &rx_stat); if (err) return err; rsp->rx_stats[stat] = rx_stat; stat++; } /* Tx stats */ stat = 0; while (stat < CGX_TX_STATS_COUNT) { err = cgx_get_tx_stats(cgxd, lmac, stat, &tx_stat); if (err) return err; rsp->tx_stats[stat] = tx_stat; stat++; } return 0; }