1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018 Marvell International Ltd. 4 */ 5 6#include <dm.h> 7#include <malloc.h> 8#include <misc.h> 9#include <net.h> 10#include <pci.h> 11#include <pci_ids.h> 12#include <phy.h> 13#include <asm/io.h> 14#include <linux/delay.h> 15 16#include "nic_reg.h" 17#include "nic.h" 18#include "nicvf_queues.h" 19 20/* Register read/write APIs */ 21void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val) 22{ 23 writeq(val, nic->reg_base + offset); 24} 25 26u64 nicvf_reg_read(struct nicvf *nic, u64 offset) 27{ 28 return readq(nic->reg_base + offset); 29} 30 31void nicvf_queue_reg_write(struct nicvf *nic, u64 offset, 32 u64 qidx, u64 val) 33{ 34 void *addr = nic->reg_base + offset; 35 36 writeq(val, (void *)(addr + (qidx << NIC_Q_NUM_SHIFT))); 37} 38 39u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx) 40{ 41 void *addr = nic->reg_base + offset; 42 43 return readq((void *)(addr + (qidx << NIC_Q_NUM_SHIFT))); 44} 45 46static void nicvf_handle_mbx_intr(struct nicvf *nic); 47 48/* VF -> PF mailbox communication */ 49static void nicvf_write_to_mbx(struct nicvf *nic, union nic_mbx *mbx) 50{ 51 u64 *msg = (u64 *)mbx; 52 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]); 55} 56 57int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx) 58{ 59 int timeout = NIC_PF_VF_MBX_TIMEOUT; 60 int sleep = 10; 61 62 nic->pf_acked = false; 63 nic->pf_nacked = false; 64 65 nicvf_write_to_mbx(nic, mbx); 66 67 nic_handle_mbx_intr(nic->nicpf, nic->vf_id); 68 69 /* Wait for previous message to be acked, timeout 2sec */ 70 while (!nic->pf_acked) { 71 if (nic->pf_nacked) 72 return -1; 73 mdelay(sleep); 74 nicvf_handle_mbx_intr(nic); 75 76 if (nic->pf_acked) 77 break; 78 timeout -= sleep; 79 if (!timeout) { 80 printf("PF didn't ack to mbox msg %d from VF%d\n", 81 (mbx->msg.msg & 0xFF), nic->vf_id); 82 return -1; 83 } 84 } 85 86 return 0; 87} 88 89/* Checks if VF is able to comminicate with PF 90 * and also gets the VNIC number this VF is associated to. 91 */ 92static int nicvf_check_pf_ready(struct nicvf *nic) 93{ 94 union nic_mbx mbx = {}; 95 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"); 99 return 0; 100 } 101 102 return 1; 103} 104 105static void nicvf_handle_mbx_intr(struct nicvf *nic) 106{ 107 union nic_mbx mbx = {}; 108 struct eth_pdata *pdata = dev_get_plat(nic->dev); 109 u64 *mbx_data; 110 u64 mbx_addr; 111 int i; 112 113 mbx_addr = NIC_VF_PF_MAILBOX_0_1; 114 mbx_data = (u64 *)&mbx; 115 116 for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { 117 *mbx_data = nicvf_reg_read(nic, mbx_addr); 118 mbx_data++; 119 mbx_addr += sizeof(u64); 120 } 121 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; 134 nic->duplex = 0; 135 nic->speed = 0; 136 break; 137 case NIC_MBOX_MSG_ACK: 138 nic->pf_acked = true; 139 break; 140 case NIC_MBOX_MSG_NACK: 141 nic->pf_nacked = true; 142 break; 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; 148 if (nic->link_up) { 149 printf("%s: Link is Up %d Mbps %s\n", 150 nic->dev->name, nic->speed, 151 nic->duplex == 1 ? 152 "Full duplex" : "Half duplex"); 153 } else { 154 printf("%s: Link is Down\n", nic->dev->name); 155 } 156 break; 157 default: 158 printf("Invalid message from PF, msg 0x%x\n", mbx.msg.msg); 159 break; 160 } 161 162 nicvf_clear_intr(nic, NICVF_INTR_MBOX, 0); 163} 164 165static int nicvf_hw_set_mac_addr(struct nicvf *nic, struct udevice *dev) 166{ 167 union nic_mbx mbx = {}; 168 struct eth_pdata *pdata = dev_get_plat(dev); 169 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); 173 174 return nicvf_send_msg_to_pf(nic, &mbx); 175} 176 177static void nicvf_config_cpi(struct nicvf *nic) 178{ 179 union nic_mbx mbx = {}; 180 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; 185 186 nicvf_send_msg_to_pf(nic, &mbx); 187} 188 189static int nicvf_init_resources(struct nicvf *nic) 190{ 191 int err; 192 193 nic->num_qs = 1; 194 195 /* Enable Qset */ 196 nicvf_qset_config(nic, true); 197 198 /* Initialize queues and HW for data transfer */ 199 err = nicvf_config_data_transfer(nic, true); 200 201 if (err) { 202 printf("Failed to alloc/config VF's QSet resources\n"); 203 return err; 204 } 205 return 0; 206} 207 208static void nicvf_snd_pkt_handler(struct nicvf *nic, 209 struct cmp_queue *cq, 210 void *cq_desc, int cqe_type) 211{ 212 struct cqe_send_t *cqe_tx; 213 struct snd_queue *sq; 214 struct sq_hdr_subdesc *hdr; 215 216 cqe_tx = (struct cqe_send_t *)cq_desc; 217 sq = &nic->qs->sq[cqe_tx->sq_idx]; 218 219 hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, cqe_tx->sqe_ptr); 220 if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER) 221 return; 222 223 nicvf_check_cqe_tx_errs(nic, cq, cq_desc); 224 nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1); 225} 226 227static int nicvf_rcv_pkt_handler(struct nicvf *nic, 228 struct cmp_queue *cq, void *cq_desc, 229 void **ppkt, int cqe_type) 230{ 231 void *pkt; 232 233 size_t pkt_len; 234 struct cqe_rx_t *cqe_rx = (struct cqe_rx_t *)cq_desc; 235 int err = 0; 236 237 /* Check for errors */ 238 err = nicvf_check_cqe_rx_errs(nic, cq, cq_desc); 239 if (err && !cqe_rx->rb_cnt) 240 return -1; 241 242 pkt = nicvf_get_rcv_pkt(nic, cq_desc, &pkt_len); 243 if (!pkt) { 244 debug("Packet not received\n"); 245 return -1; 246 } 247 248 if (pkt) 249 *ppkt = pkt; 250 251 return pkt_len; 252} 253 254int nicvf_cq_handler(struct nicvf *nic, void **ppkt, int *pkt_len) 255{ 256 int cq_qnum = 0; 257 int processed_sq_cqe = 0; 258 int processed_rq_cqe = 0; 259 int processed_cqe = 0; 260 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; 265 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); 268 cqe_count &= 0xFFFF; 269 if (!cqe_count) 270 return 0; 271 272 /* Get head of the valid CQ entries */ 273 cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_qnum); 274 cqe_head >>= 9; 275 cqe_head &= 0xFFFF; 276 277 if (cqe_count) { 278 /* Get the CQ descriptor */ 279 cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head); 280 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)); 284 285 switch (cq_desc->cqe_type) { 286 case CQE_TYPE_RX: 287 debug("%s: Got Rx CQE\n", nic->dev->name); 288 *pkt_len = nicvf_rcv_pkt_handler(nic, cq, cq_desc, 289 ppkt, CQE_TYPE_RX); 290 processed_rq_cqe++; 291 break; 292 case CQE_TYPE_SEND: 293 debug("%s: Got Tx CQE\n", nic->dev->name); 294 nicvf_snd_pkt_handler(nic, cq, cq_desc, CQE_TYPE_SEND); 295 processed_sq_cqe++; 296 break; 297 default: 298 debug("%s: Got CQ type %u\n", nic->dev->name, 299 cq_desc->cqe_type); 300 break; 301 } 302 processed_cqe++; 303 } 304 305 /* Dequeue CQE */ 306 nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR, 307 cq_qnum, processed_cqe); 308 309 asm volatile ("dsb sy"); 310 311 return (processed_sq_cqe | processed_rq_cqe); 312} 313 314/* Qset error interrupt handler 315 * 316 * As of now only CQ errors are handled 317 */ 318void nicvf_handle_qs_err(struct nicvf *nic) 319{ 320 struct queue_set *qs = nic->qs; 321 int qidx; 322 u64 status; 323 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, 327 qidx); 328 if (!(status & CQ_ERR_MASK)) 329 continue; 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); 335 } 336} 337 338static int nicvf_free_pkt(struct udevice *dev, uchar *pkt, int pkt_len) 339{ 340 struct nicvf *nic = dev_get_priv(dev); 341 342 if (pkt && pkt_len) 343 free(pkt); 344 nicvf_refill_rbdr(nic); 345 return 0; 346} 347 348static int nicvf_xmit(struct udevice *dev, void *pkt, int pkt_len) 349{ 350 struct nicvf *nic = dev_get_priv(dev); 351 int ret = 0; 352 int rcv_len = 0; 353 unsigned int timeout = 5000; 354 void *rpkt = NULL; 355 356 if (!nicvf_sq_append_pkt(nic, pkt, pkt_len)) { 357 printf("VF%d: TX ring full\n", nic->vf_id); 358 return -1; 359 } 360 361 /* check and update CQ for pkt sent */ 362 while (!ret && timeout--) { 363 ret = nicvf_cq_handler(nic, &rpkt, &rcv_len); 364 if (!ret) { 365 debug("%s: %d, Not sent\n", __func__, __LINE__); 366 udelay(10); 367 } 368 } 369 370 return 0; 371} 372 373static int nicvf_recv(struct udevice *dev, int flags, uchar **packetp) 374{ 375 struct nicvf *nic = dev_get_priv(dev); 376 void *pkt; 377 int pkt_len = 0; 378#ifdef DEBUG 379 u8 *dpkt; 380 int i, j; 381#endif 382 383 nicvf_cq_handler(nic, &pkt, &pkt_len); 384 385 if (pkt_len) { 386#ifdef DEBUG 387 dpkt = pkt; 388 printf("RX packet contents:\n"); 389 for (i = 0; i < 8; i++) { 390 puts("\t"); 391 for (j = 0; j < 10; j++) 392 printf("%02x ", dpkt[i * 10 + j]); 393 puts("\n"); 394 } 395#endif 396 *packetp = pkt; 397 } 398 399 return pkt_len; 400} 401 402void nicvf_stop(struct udevice *dev) 403{ 404 struct nicvf *nic = dev_get_priv(dev); 405 406 if (!nic->open) 407 return; 408 409 /* Free resources */ 410 nicvf_config_data_transfer(nic, false); 411 412 /* Disable HW Qset */ 413 nicvf_qset_config(nic, false); 414 415 nic->open = false; 416} 417 418int nicvf_open(struct udevice *dev) 419{ 420 int err; 421 struct nicvf *nic = dev_get_priv(dev); 422 423 nicvf_hw_set_mac_addr(nic, dev); 424 425 /* Configure CPI alorithm */ 426 nic->cpi_alg = CPI_ALG_NONE; 427 nicvf_config_cpi(nic); 428 429 /* Initialize the queues */ 430 err = nicvf_init_resources(nic); 431 if (err) 432 return -1; 433 434 if (!nicvf_check_pf_ready(nic)) 435 return -1; 436 437 nic->open = true; 438 439 /* Make sure queue initialization is written */ 440 asm volatile("dsb sy"); 441 442 return 0; 443} 444 445int nicvf_write_hwaddr(struct udevice *dev) 446{ 447 unsigned char ethaddr[ARP_HLEN]; 448 struct eth_pdata *pdata = dev_get_plat(dev); 449 struct nicvf *nic = dev_get_priv(dev); 450 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. 454 */ 455 if (!eth_env_get_enetaddr_by_index("eth", dev_seq(dev), ethaddr)) { 456 eth_env_set_enetaddr_by_index("eth", dev_seq(dev), 457 pdata->enetaddr); 458 debug("%s: pMAC %pM\n", __func__, pdata->enetaddr); 459 } 460 eth_env_get_enetaddr_by_index("eth", dev_seq(dev), ethaddr); 461 if (memcmp(ethaddr, pdata->enetaddr, ARP_HLEN)) { 462 debug("%s: pMAC %pM\n", __func__, pdata->enetaddr); 463 nicvf_hw_set_mac_addr(nic, dev); 464 } 465 return 0; 466} 467 468static void nicvf_probe_mdio_devices(void) 469{ 470 struct udevice *pdev; 471 int err; 472 static int probed; 473 474 if (probed) 475 return; 476 477 err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM, 478 PCI_DEVICE_ID_CAVIUM_SMI, 0, 479 &pdev); 480 if (err) 481 debug("%s couldn't find SMI device\n", __func__); 482 probed = 1; 483} 484 485int nicvf_initialize(struct udevice *dev) 486{ 487 struct nicvf *nicvf = dev_get_priv(dev); 488 struct eth_pdata *pdata = dev_get_plat(dev); 489 int ret = 0, bgx, lmac; 490 char name[16]; 491 unsigned char ethaddr[ARP_HLEN]; 492 struct udevice *pfdev; 493 struct nicpf *pf; 494 static int vfid; 495 496 if (dm_pci_find_device(PCI_VENDOR_ID_CAVIUM, 497 PCI_DEVICE_ID_CAVIUM_NIC, 0, &pfdev)) { 498 printf("%s NIC PF device not found..VF probe failed\n", 499 __func__); 500 return -1; 501 } 502 pf = dev_get_priv(pfdev); 503 nicvf->vf_id = vfid++; 504 nicvf->dev = dev; 505 nicvf->nicpf = pf; 506 507 nicvf_probe_mdio_devices(); 508 509 /* Enable TSO support */ 510 nicvf->hw_tso = true; 511 512 nicvf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 513 PCI_REGION_MEM); 514 515 debug("nicvf->reg_base: %p\n", nicvf->reg_base); 516 517 if (!nicvf->reg_base) { 518 printf("Cannot map config register space, aborting\n"); 519 ret = -1; 520 goto fail; 521 } 522 523 ret = nicvf_set_qset_resources(nicvf); 524 if (ret) 525 return -1; 526 527 sprintf(name, "vnic%u", nicvf->vf_id); 528 debug("%s name %s\n", __func__, name); 529 device_set_name(dev, name); 530 531 bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]); 532 lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]); 533 debug("%s VF %d BGX %d LMAC %d\n", __func__, nicvf->vf_id, bgx, lmac); 534 debug("%s PF %p pfdev %p VF %p vfdev %p vf->pdata %p\n", 535 __func__, nicvf->nicpf, nicvf->nicpf->udev, nicvf, nicvf->dev, 536 pdata); 537 538 fdt_board_get_ethaddr(bgx, lmac, ethaddr); 539 540 debug("%s bgx %d lmac %d ethaddr %pM\n", __func__, bgx, lmac, ethaddr); 541 542 if (is_valid_ethaddr(ethaddr)) { 543 memcpy(pdata->enetaddr, ethaddr, ARP_HLEN); 544 eth_env_set_enetaddr_by_index("eth", dev_seq(dev), ethaddr); 545 } 546 debug("%s enetaddr %pM ethaddr %pM\n", __func__, 547 pdata->enetaddr, ethaddr); 548 549fail: 550 return ret; 551} 552 553int octeontx_vnic_probe(struct udevice *dev) 554{ 555 return nicvf_initialize(dev); 556} 557 558static const struct eth_ops octeontx_vnic_ops = { 559 .start = nicvf_open, 560 .stop = nicvf_stop, 561 .send = nicvf_xmit, 562 .recv = nicvf_recv, 563 .free_pkt = nicvf_free_pkt, 564 .write_hwaddr = nicvf_write_hwaddr, 565}; 566 567U_BOOT_DRIVER(octeontx_vnic) = { 568 .name = "vnic", 569 .id = UCLASS_ETH, 570 .probe = octeontx_vnic_probe, 571 .ops = &octeontx_vnic_ops, 572 .priv_auto = sizeof(struct nicvf), 573 .plat_auto = sizeof(struct eth_pdata), 574}; 575 576static struct pci_device_id octeontx_vnic_supported[] = { 577 { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF) }, 578 { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF_1) }, 579 {} 580}; 581 582U_BOOT_PCI_DEVICE(octeontx_vnic, octeontx_vnic_supported); 583