1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Marvell International Ltd.
14 #include <linux/delay.h>
18 #include "nicvf_queues.h"
20 /* Register read/write APIs */
21 void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val)
23 writeq(val, nic->reg_base + offset);
26 u64 nicvf_reg_read(struct nicvf *nic, u64 offset)
28 return readq(nic->reg_base + offset);
31 void nicvf_queue_reg_write(struct nicvf *nic, u64 offset,
34 void *addr = nic->reg_base + offset;
36 writeq(val, (void *)(addr + (qidx << NIC_Q_NUM_SHIFT)));
39 u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx)
41 void *addr = nic->reg_base + offset;
43 return readq((void *)(addr + (qidx << NIC_Q_NUM_SHIFT)));
46 static void nicvf_handle_mbx_intr(struct nicvf *nic);
48 /* VF -> PF mailbox communication */
49 static void nicvf_write_to_mbx(struct nicvf *nic, union nic_mbx *mbx)
51 u64 *msg = (u64 *)mbx;
53 nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 0, msg[0]);
54 nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 8, msg[1]);
57 int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx)
59 int timeout = NIC_PF_VF_MBX_TIMEOUT;
62 nic->pf_acked = false;
63 nic->pf_nacked = false;
65 nicvf_write_to_mbx(nic, mbx);
67 nic_handle_mbx_intr(nic->nicpf, nic->vf_id);
69 /* Wait for previous message to be acked, timeout 2sec */
70 while (!nic->pf_acked) {
74 nicvf_handle_mbx_intr(nic);
80 printf("PF didn't ack to mbox msg %d from VF%d\n",
81 (mbx->msg.msg & 0xFF), nic->vf_id);
89 /* Checks if VF is able to comminicate with PF
90 * and also gets the VNIC number this VF is associated to.
92 static int nicvf_check_pf_ready(struct nicvf *nic)
94 union nic_mbx mbx = {};
96 mbx.msg.msg = NIC_MBOX_MSG_READY;
97 if (nicvf_send_msg_to_pf(nic, &mbx)) {
98 printf("PF didn't respond to READY msg\n");
105 static void nicvf_handle_mbx_intr(struct nicvf *nic)
107 union nic_mbx mbx = {};
108 struct eth_pdata *pdata = dev_get_platdata(nic->dev);
113 mbx_addr = NIC_VF_PF_MAILBOX_0_1;
114 mbx_data = (u64 *)&mbx;
116 for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
117 *mbx_data = nicvf_reg_read(nic, mbx_addr);
119 mbx_addr += sizeof(u64);
122 debug("Mbox message: msg: 0x%x\n", mbx.msg.msg);
123 switch (mbx.msg.msg) {
124 case NIC_MBOX_MSG_READY:
125 nic->pf_acked = true;
126 nic->vf_id = mbx.nic_cfg.vf_id & 0x7F;
127 nic->tns_mode = mbx.nic_cfg.tns_mode & 0x7F;
128 nic->node = mbx.nic_cfg.node_id;
129 if (!nic->set_mac_pending)
130 memcpy(pdata->enetaddr,
131 mbx.nic_cfg.mac_addr, 6);
132 nic->loopback_supported = mbx.nic_cfg.loopback_supported;
133 nic->link_up = false;
137 case NIC_MBOX_MSG_ACK:
138 nic->pf_acked = true;
140 case NIC_MBOX_MSG_NACK:
141 nic->pf_nacked = true;
143 case NIC_MBOX_MSG_BGX_LINK_CHANGE:
144 nic->pf_acked = true;
145 nic->link_up = mbx.link_status.link_up;
146 nic->duplex = mbx.link_status.duplex;
147 nic->speed = mbx.link_status.speed;
149 printf("%s: Link is Up %d Mbps %s\n",
150 nic->dev->name, nic->speed,
152 "Full duplex" : "Half duplex");
154 printf("%s: Link is Down\n", nic->dev->name);
158 printf("Invalid message from PF, msg 0x%x\n", mbx.msg.msg);
162 nicvf_clear_intr(nic, NICVF_INTR_MBOX, 0);
165 static int nicvf_hw_set_mac_addr(struct nicvf *nic, struct udevice *dev)
167 union nic_mbx mbx = {};
168 struct eth_pdata *pdata = dev_get_platdata(dev);
170 mbx.mac.msg = NIC_MBOX_MSG_SET_MAC;
171 mbx.mac.vf_id = nic->vf_id;
172 memcpy(mbx.mac.mac_addr, pdata->enetaddr, 6);
174 return nicvf_send_msg_to_pf(nic, &mbx);
177 static void nicvf_config_cpi(struct nicvf *nic)
179 union nic_mbx mbx = {};
181 mbx.cpi_cfg.msg = NIC_MBOX_MSG_CPI_CFG;
182 mbx.cpi_cfg.vf_id = nic->vf_id;
183 mbx.cpi_cfg.cpi_alg = nic->cpi_alg;
184 mbx.cpi_cfg.rq_cnt = nic->qs->rq_cnt;
186 nicvf_send_msg_to_pf(nic, &mbx);
189 static int nicvf_init_resources(struct nicvf *nic)
196 nicvf_qset_config(nic, true);
198 /* Initialize queues and HW for data transfer */
199 err = nicvf_config_data_transfer(nic, true);
202 printf("Failed to alloc/config VF's QSet resources\n");
208 static void nicvf_snd_pkt_handler(struct nicvf *nic,
209 struct cmp_queue *cq,
210 void *cq_desc, int cqe_type)
212 struct cqe_send_t *cqe_tx;
213 struct snd_queue *sq;
214 struct sq_hdr_subdesc *hdr;
216 cqe_tx = (struct cqe_send_t *)cq_desc;
217 sq = &nic->qs->sq[cqe_tx->sq_idx];
219 hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, cqe_tx->sqe_ptr);
220 if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER)
223 nicvf_check_cqe_tx_errs(nic, cq, cq_desc);
224 nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
227 static int nicvf_rcv_pkt_handler(struct nicvf *nic,
228 struct cmp_queue *cq, void *cq_desc,
229 void **ppkt, int cqe_type)
234 struct cqe_rx_t *cqe_rx = (struct cqe_rx_t *)cq_desc;
237 /* Check for errors */
238 err = nicvf_check_cqe_rx_errs(nic, cq, cq_desc);
239 if (err && !cqe_rx->rb_cnt)
242 pkt = nicvf_get_rcv_pkt(nic, cq_desc, &pkt_len);
244 debug("Packet not received\n");
254 int nicvf_cq_handler(struct nicvf *nic, void **ppkt, int *pkt_len)
257 int processed_sq_cqe = 0;
258 int processed_rq_cqe = 0;
259 int processed_cqe = 0;
261 unsigned long cqe_count, cqe_head;
262 struct queue_set *qs = nic->qs;
263 struct cmp_queue *cq = &qs->cq[cq_qnum];
264 struct cqe_rx_t *cq_desc;
266 /* Get num of valid CQ entries expect next one to be SQ completion */
267 cqe_count = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, cq_qnum);
272 /* Get head of the valid CQ entries */
273 cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_qnum);
278 /* Get the CQ descriptor */
279 cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head);
281 cqe_head &= (cq->dmem.q_len - 1);
282 /* Initiate prefetch for next descriptor */
283 prefetch((struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head));
285 switch (cq_desc->cqe_type) {
287 debug("%s: Got Rx CQE\n", nic->dev->name);
288 *pkt_len = nicvf_rcv_pkt_handler(nic, cq, cq_desc,
293 debug("%s: Got Tx CQE\n", nic->dev->name);
294 nicvf_snd_pkt_handler(nic, cq, cq_desc, CQE_TYPE_SEND);
298 debug("%s: Got CQ type %u\n", nic->dev->name,
306 nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR,
307 cq_qnum, processed_cqe);
309 asm volatile ("dsb sy");
311 return (processed_sq_cqe | processed_rq_cqe);
314 /* Qset error interrupt handler
316 * As of now only CQ errors are handled
318 void nicvf_handle_qs_err(struct nicvf *nic)
320 struct queue_set *qs = nic->qs;
324 /* Check if it is CQ err */
325 for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
326 status = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS,
328 if (!(status & CQ_ERR_MASK))
330 /* Process already queued CQEs and reconfig CQ */
331 nicvf_sq_disable(nic, qidx);
332 nicvf_cmp_queue_config(nic, qs, qidx, true);
333 nicvf_sq_free_used_descs(nic->dev, &qs->sq[qidx], qidx);
334 nicvf_sq_enable(nic, &qs->sq[qidx], qidx);
338 static int nicvf_free_pkt(struct udevice *dev, uchar *pkt, int pkt_len)
340 struct nicvf *nic = dev_get_priv(dev);
344 nicvf_refill_rbdr(nic);
348 static int nicvf_xmit(struct udevice *dev, void *pkt, int pkt_len)
350 struct nicvf *nic = dev_get_priv(dev);
353 unsigned int timeout = 5000;
356 if (!nicvf_sq_append_pkt(nic, pkt, pkt_len)) {
357 printf("VF%d: TX ring full\n", nic->vf_id);
361 /* check and update CQ for pkt sent */
362 while (!ret && timeout--) {
363 ret = nicvf_cq_handler(nic, &rpkt, &rcv_len);
365 debug("%s: %d, Not sent\n", __func__, __LINE__);
373 static int nicvf_recv(struct udevice *dev, int flags, uchar **packetp)
375 struct nicvf *nic = dev_get_priv(dev);
383 nicvf_cq_handler(nic, &pkt, &pkt_len);
388 printf("RX packet contents:\n");
389 for (i = 0; i < 8; i++) {
391 for (j = 0; j < 10; j++)
392 printf("%02x ", dpkt[i * 10 + j]);
402 void nicvf_stop(struct udevice *dev)
404 struct nicvf *nic = dev_get_priv(dev);
410 nicvf_config_data_transfer(nic, false);
412 /* Disable HW Qset */
413 nicvf_qset_config(nic, false);
418 int nicvf_open(struct udevice *dev)
421 struct nicvf *nic = dev_get_priv(dev);
423 nicvf_hw_set_mac_addr(nic, dev);
425 /* Configure CPI alorithm */
426 nic->cpi_alg = CPI_ALG_NONE;
427 nicvf_config_cpi(nic);
429 /* Initialize the queues */
430 err = nicvf_init_resources(nic);
434 if (!nicvf_check_pf_ready(nic))
439 /* Make sure queue initialization is written */
440 asm volatile("dsb sy");
445 int nicvf_write_hwaddr(struct udevice *dev)
447 unsigned char ethaddr[ARP_HLEN];
448 struct eth_pdata *pdata = dev_get_platdata(dev);
449 struct nicvf *nic = dev_get_priv(dev);
451 /* If lower level firmware fails to set proper MAC
452 * u-boot framework updates MAC to random address.
453 * Use this hook to update mac address in environment.
455 if (!eth_env_get_enetaddr_by_index("eth", dev->seq, ethaddr)) {
456 eth_env_set_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
457 debug("%s: pMAC %pM\n", __func__, pdata->enetaddr);
459 eth_env_get_enetaddr_by_index("eth", dev->seq, ethaddr);
460 if (memcmp(ethaddr, pdata->enetaddr, ARP_HLEN)) {
461 debug("%s: pMAC %pM\n", __func__, pdata->enetaddr);
462 nicvf_hw_set_mac_addr(nic, dev);
467 static void nicvf_probe_mdio_devices(void)
469 struct udevice *pdev;
476 err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
477 PCI_DEVICE_ID_CAVIUM_SMI, 0,
480 debug("%s couldn't find SMI device\n", __func__);
484 int nicvf_initialize(struct udevice *dev)
486 struct nicvf *nicvf = dev_get_priv(dev);
487 struct eth_pdata *pdata = dev_get_platdata(dev);
488 int ret = 0, bgx, lmac;
490 unsigned char ethaddr[ARP_HLEN];
491 struct udevice *pfdev;
495 if (dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
496 PCI_DEVICE_ID_CAVIUM_NIC, 0, &pfdev)) {
497 printf("%s NIC PF device not found..VF probe failed\n",
501 pf = dev_get_priv(pfdev);
502 nicvf->vf_id = vfid++;
506 nicvf_probe_mdio_devices();
508 /* Enable TSO support */
509 nicvf->hw_tso = true;
511 nicvf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
514 debug("nicvf->reg_base: %p\n", nicvf->reg_base);
516 if (!nicvf->reg_base) {
517 printf("Cannot map config register space, aborting\n");
522 ret = nicvf_set_qset_resources(nicvf);
526 sprintf(name, "vnic%u", nicvf->vf_id);
527 debug("%s name %s\n", __func__, name);
528 device_set_name(dev, name);
530 bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]);
531 lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]);
532 debug("%s VF %d BGX %d LMAC %d\n", __func__, nicvf->vf_id, bgx, lmac);
533 debug("%s PF %p pfdev %p VF %p vfdev %p vf->pdata %p\n",
534 __func__, nicvf->nicpf, nicvf->nicpf->udev, nicvf, nicvf->dev,
537 fdt_board_get_ethaddr(bgx, lmac, ethaddr);
539 debug("%s bgx %d lmac %d ethaddr %pM\n", __func__, bgx, lmac, ethaddr);
541 if (is_valid_ethaddr(ethaddr)) {
542 memcpy(pdata->enetaddr, ethaddr, ARP_HLEN);
543 eth_env_set_enetaddr_by_index("eth", dev->seq, ethaddr);
545 debug("%s enetaddr %pM ethaddr %pM\n", __func__,
546 pdata->enetaddr, ethaddr);
552 int octeontx_vnic_probe(struct udevice *dev)
554 return nicvf_initialize(dev);
557 static const struct eth_ops octeontx_vnic_ops = {
562 .free_pkt = nicvf_free_pkt,
563 .write_hwaddr = nicvf_write_hwaddr,
566 U_BOOT_DRIVER(octeontx_vnic) = {
569 .probe = octeontx_vnic_probe,
570 .ops = &octeontx_vnic_ops,
571 .priv_auto = sizeof(struct nicvf),
572 .platdata_auto = sizeof(struct eth_pdata),
575 static struct pci_device_id octeontx_vnic_supported[] = {
576 { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF) },
577 { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF_1) },
581 U_BOOT_PCI_DEVICE(octeontx_vnic, octeontx_vnic_supported);