nicvf_main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018 Marvell International Ltd.
  4. */
  5. #include <dm.h>
  6. #include <malloc.h>
  7. #include <misc.h>
  8. #include <net.h>
  9. #include <pci.h>
  10. #include <pci_ids.h>
  11. #include <phy.h>
  12. #include <asm/io.h>
  13. #include <linux/delay.h>
  14. #include "nic_reg.h"
  15. #include "nic.h"
  16. #include "nicvf_queues.h"
  17. /* Register read/write APIs */
  18. void nicvf_reg_write(struct nicvf *nic, u64 offset, u64 val)
  19. {
  20. writeq(val, nic->reg_base + offset);
  21. }
  22. u64 nicvf_reg_read(struct nicvf *nic, u64 offset)
  23. {
  24. return readq(nic->reg_base + offset);
  25. }
  26. void nicvf_queue_reg_write(struct nicvf *nic, u64 offset,
  27. u64 qidx, u64 val)
  28. {
  29. void *addr = nic->reg_base + offset;
  30. writeq(val, (void *)(addr + (qidx << NIC_Q_NUM_SHIFT)));
  31. }
  32. u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx)
  33. {
  34. void *addr = nic->reg_base + offset;
  35. return readq((void *)(addr + (qidx << NIC_Q_NUM_SHIFT)));
  36. }
  37. static void nicvf_handle_mbx_intr(struct nicvf *nic);
  38. /* VF -> PF mailbox communication */
  39. static void nicvf_write_to_mbx(struct nicvf *nic, union nic_mbx *mbx)
  40. {
  41. u64 *msg = (u64 *)mbx;
  42. nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 0, msg[0]);
  43. nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 8, msg[1]);
  44. }
  45. int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx)
  46. {
  47. int timeout = NIC_PF_VF_MBX_TIMEOUT;
  48. int sleep = 10;
  49. nic->pf_acked = false;
  50. nic->pf_nacked = false;
  51. nicvf_write_to_mbx(nic, mbx);
  52. nic_handle_mbx_intr(nic->nicpf, nic->vf_id);
  53. /* Wait for previous message to be acked, timeout 2sec */
  54. while (!nic->pf_acked) {
  55. if (nic->pf_nacked)
  56. return -1;
  57. mdelay(sleep);
  58. nicvf_handle_mbx_intr(nic);
  59. if (nic->pf_acked)
  60. break;
  61. timeout -= sleep;
  62. if (!timeout) {
  63. printf("PF didn't ack to mbox msg %d from VF%d\n",
  64. (mbx->msg.msg & 0xFF), nic->vf_id);
  65. return -1;
  66. }
  67. }
  68. return 0;
  69. }
  70. /* Checks if VF is able to comminicate with PF
  71. * and also gets the VNIC number this VF is associated to.
  72. */
  73. static int nicvf_check_pf_ready(struct nicvf *nic)
  74. {
  75. union nic_mbx mbx = {};
  76. mbx.msg.msg = NIC_MBOX_MSG_READY;
  77. if (nicvf_send_msg_to_pf(nic, &mbx)) {
  78. printf("PF didn't respond to READY msg\n");
  79. return 0;
  80. }
  81. return 1;
  82. }
  83. static void nicvf_handle_mbx_intr(struct nicvf *nic)
  84. {
  85. union nic_mbx mbx = {};
  86. struct eth_pdata *pdata = dev_get_plat(nic->dev);
  87. u64 *mbx_data;
  88. u64 mbx_addr;
  89. int i;
  90. mbx_addr = NIC_VF_PF_MAILBOX_0_1;
  91. mbx_data = (u64 *)&mbx;
  92. for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) {
  93. *mbx_data = nicvf_reg_read(nic, mbx_addr);
  94. mbx_data++;
  95. mbx_addr += sizeof(u64);
  96. }
  97. debug("Mbox message: msg: 0x%x\n", mbx.msg.msg);
  98. switch (mbx.msg.msg) {
  99. case NIC_MBOX_MSG_READY:
  100. nic->pf_acked = true;
  101. nic->vf_id = mbx.nic_cfg.vf_id & 0x7F;
  102. nic->tns_mode = mbx.nic_cfg.tns_mode & 0x7F;
  103. nic->node = mbx.nic_cfg.node_id;
  104. if (!nic->set_mac_pending)
  105. memcpy(pdata->enetaddr,
  106. mbx.nic_cfg.mac_addr, 6);
  107. nic->loopback_supported = mbx.nic_cfg.loopback_supported;
  108. nic->link_up = false;
  109. nic->duplex = 0;
  110. nic->speed = 0;
  111. break;
  112. case NIC_MBOX_MSG_ACK:
  113. nic->pf_acked = true;
  114. break;
  115. case NIC_MBOX_MSG_NACK:
  116. nic->pf_nacked = true;
  117. break;
  118. case NIC_MBOX_MSG_BGX_LINK_CHANGE:
  119. nic->pf_acked = true;
  120. nic->link_up = mbx.link_status.link_up;
  121. nic->duplex = mbx.link_status.duplex;
  122. nic->speed = mbx.link_status.speed;
  123. if (nic->link_up) {
  124. printf("%s: Link is Up %d Mbps %s\n",
  125. nic->dev->name, nic->speed,
  126. nic->duplex == 1 ?
  127. "Full duplex" : "Half duplex");
  128. } else {
  129. printf("%s: Link is Down\n", nic->dev->name);
  130. }
  131. break;
  132. default:
  133. printf("Invalid message from PF, msg 0x%x\n", mbx.msg.msg);
  134. break;
  135. }
  136. nicvf_clear_intr(nic, NICVF_INTR_MBOX, 0);
  137. }
  138. static int nicvf_hw_set_mac_addr(struct nicvf *nic, struct udevice *dev)
  139. {
  140. union nic_mbx mbx = {};
  141. struct eth_pdata *pdata = dev_get_plat(dev);
  142. mbx.mac.msg = NIC_MBOX_MSG_SET_MAC;
  143. mbx.mac.vf_id = nic->vf_id;
  144. memcpy(mbx.mac.mac_addr, pdata->enetaddr, 6);
  145. return nicvf_send_msg_to_pf(nic, &mbx);
  146. }
  147. static void nicvf_config_cpi(struct nicvf *nic)
  148. {
  149. union nic_mbx mbx = {};
  150. mbx.cpi_cfg.msg = NIC_MBOX_MSG_CPI_CFG;
  151. mbx.cpi_cfg.vf_id = nic->vf_id;
  152. mbx.cpi_cfg.cpi_alg = nic->cpi_alg;
  153. mbx.cpi_cfg.rq_cnt = nic->qs->rq_cnt;
  154. nicvf_send_msg_to_pf(nic, &mbx);
  155. }
  156. static int nicvf_init_resources(struct nicvf *nic)
  157. {
  158. int err;
  159. nic->num_qs = 1;
  160. /* Enable Qset */
  161. nicvf_qset_config(nic, true);
  162. /* Initialize queues and HW for data transfer */
  163. err = nicvf_config_data_transfer(nic, true);
  164. if (err) {
  165. printf("Failed to alloc/config VF's QSet resources\n");
  166. return err;
  167. }
  168. return 0;
  169. }
  170. static void nicvf_snd_pkt_handler(struct nicvf *nic,
  171. struct cmp_queue *cq,
  172. void *cq_desc, int cqe_type)
  173. {
  174. struct cqe_send_t *cqe_tx;
  175. struct snd_queue *sq;
  176. struct sq_hdr_subdesc *hdr;
  177. cqe_tx = (struct cqe_send_t *)cq_desc;
  178. sq = &nic->qs->sq[cqe_tx->sq_idx];
  179. hdr = (struct sq_hdr_subdesc *)GET_SQ_DESC(sq, cqe_tx->sqe_ptr);
  180. if (hdr->subdesc_type != SQ_DESC_TYPE_HEADER)
  181. return;
  182. nicvf_check_cqe_tx_errs(nic, cq, cq_desc);
  183. nicvf_put_sq_desc(sq, hdr->subdesc_cnt + 1);
  184. }
  185. static int nicvf_rcv_pkt_handler(struct nicvf *nic,
  186. struct cmp_queue *cq, void *cq_desc,
  187. void **ppkt, int cqe_type)
  188. {
  189. void *pkt;
  190. size_t pkt_len;
  191. struct cqe_rx_t *cqe_rx = (struct cqe_rx_t *)cq_desc;
  192. int err = 0;
  193. /* Check for errors */
  194. err = nicvf_check_cqe_rx_errs(nic, cq, cq_desc);
  195. if (err && !cqe_rx->rb_cnt)
  196. return -1;
  197. pkt = nicvf_get_rcv_pkt(nic, cq_desc, &pkt_len);
  198. if (!pkt) {
  199. debug("Packet not received\n");
  200. return -1;
  201. }
  202. if (pkt)
  203. *ppkt = pkt;
  204. return pkt_len;
  205. }
  206. int nicvf_cq_handler(struct nicvf *nic, void **ppkt, int *pkt_len)
  207. {
  208. int cq_qnum = 0;
  209. int processed_sq_cqe = 0;
  210. int processed_rq_cqe = 0;
  211. int processed_cqe = 0;
  212. unsigned long cqe_count, cqe_head;
  213. struct queue_set *qs = nic->qs;
  214. struct cmp_queue *cq = &qs->cq[cq_qnum];
  215. struct cqe_rx_t *cq_desc;
  216. /* Get num of valid CQ entries expect next one to be SQ completion */
  217. cqe_count = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS, cq_qnum);
  218. cqe_count &= 0xFFFF;
  219. if (!cqe_count)
  220. return 0;
  221. /* Get head of the valid CQ entries */
  222. cqe_head = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_HEAD, cq_qnum);
  223. cqe_head >>= 9;
  224. cqe_head &= 0xFFFF;
  225. if (cqe_count) {
  226. /* Get the CQ descriptor */
  227. cq_desc = (struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head);
  228. cqe_head++;
  229. cqe_head &= (cq->dmem.q_len - 1);
  230. /* Initiate prefetch for next descriptor */
  231. prefetch((struct cqe_rx_t *)GET_CQ_DESC(cq, cqe_head));
  232. switch (cq_desc->cqe_type) {
  233. case CQE_TYPE_RX:
  234. debug("%s: Got Rx CQE\n", nic->dev->name);
  235. *pkt_len = nicvf_rcv_pkt_handler(nic, cq, cq_desc,
  236. ppkt, CQE_TYPE_RX);
  237. processed_rq_cqe++;
  238. break;
  239. case CQE_TYPE_SEND:
  240. debug("%s: Got Tx CQE\n", nic->dev->name);
  241. nicvf_snd_pkt_handler(nic, cq, cq_desc, CQE_TYPE_SEND);
  242. processed_sq_cqe++;
  243. break;
  244. default:
  245. debug("%s: Got CQ type %u\n", nic->dev->name,
  246. cq_desc->cqe_type);
  247. break;
  248. }
  249. processed_cqe++;
  250. }
  251. /* Dequeue CQE */
  252. nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_DOOR,
  253. cq_qnum, processed_cqe);
  254. asm volatile ("dsb sy");
  255. return (processed_sq_cqe | processed_rq_cqe);
  256. }
  257. /* Qset error interrupt handler
  258. *
  259. * As of now only CQ errors are handled
  260. */
  261. void nicvf_handle_qs_err(struct nicvf *nic)
  262. {
  263. struct queue_set *qs = nic->qs;
  264. int qidx;
  265. u64 status;
  266. /* Check if it is CQ err */
  267. for (qidx = 0; qidx < qs->cq_cnt; qidx++) {
  268. status = nicvf_queue_reg_read(nic, NIC_QSET_CQ_0_7_STATUS,
  269. qidx);
  270. if (!(status & CQ_ERR_MASK))
  271. continue;
  272. /* Process already queued CQEs and reconfig CQ */
  273. nicvf_sq_disable(nic, qidx);
  274. nicvf_cmp_queue_config(nic, qs, qidx, true);
  275. nicvf_sq_free_used_descs(nic->dev, &qs->sq[qidx], qidx);
  276. nicvf_sq_enable(nic, &qs->sq[qidx], qidx);
  277. }
  278. }
  279. static int nicvf_free_pkt(struct udevice *dev, uchar *pkt, int pkt_len)
  280. {
  281. struct nicvf *nic = dev_get_priv(dev);
  282. if (pkt && pkt_len)
  283. free(pkt);
  284. nicvf_refill_rbdr(nic);
  285. return 0;
  286. }
  287. static int nicvf_xmit(struct udevice *dev, void *pkt, int pkt_len)
  288. {
  289. struct nicvf *nic = dev_get_priv(dev);
  290. int ret = 0;
  291. int rcv_len = 0;
  292. unsigned int timeout = 5000;
  293. void *rpkt = NULL;
  294. if (!nicvf_sq_append_pkt(nic, pkt, pkt_len)) {
  295. printf("VF%d: TX ring full\n", nic->vf_id);
  296. return -1;
  297. }
  298. /* check and update CQ for pkt sent */
  299. while (!ret && timeout--) {
  300. ret = nicvf_cq_handler(nic, &rpkt, &rcv_len);
  301. if (!ret) {
  302. debug("%s: %d, Not sent\n", __func__, __LINE__);
  303. udelay(10);
  304. }
  305. }
  306. return 0;
  307. }
  308. static int nicvf_recv(struct udevice *dev, int flags, uchar **packetp)
  309. {
  310. struct nicvf *nic = dev_get_priv(dev);
  311. void *pkt;
  312. int pkt_len = 0;
  313. #ifdef DEBUG
  314. u8 *dpkt;
  315. int i, j;
  316. #endif
  317. nicvf_cq_handler(nic, &pkt, &pkt_len);
  318. if (pkt_len) {
  319. #ifdef DEBUG
  320. dpkt = pkt;
  321. printf("RX packet contents:\n");
  322. for (i = 0; i < 8; i++) {
  323. puts("\t");
  324. for (j = 0; j < 10; j++)
  325. printf("%02x ", dpkt[i * 10 + j]);
  326. puts("\n");
  327. }
  328. #endif
  329. *packetp = pkt;
  330. }
  331. return pkt_len;
  332. }
  333. void nicvf_stop(struct udevice *dev)
  334. {
  335. struct nicvf *nic = dev_get_priv(dev);
  336. if (!nic->open)
  337. return;
  338. /* Free resources */
  339. nicvf_config_data_transfer(nic, false);
  340. /* Disable HW Qset */
  341. nicvf_qset_config(nic, false);
  342. nic->open = false;
  343. }
  344. int nicvf_open(struct udevice *dev)
  345. {
  346. int err;
  347. struct nicvf *nic = dev_get_priv(dev);
  348. nicvf_hw_set_mac_addr(nic, dev);
  349. /* Configure CPI alorithm */
  350. nic->cpi_alg = CPI_ALG_NONE;
  351. nicvf_config_cpi(nic);
  352. /* Initialize the queues */
  353. err = nicvf_init_resources(nic);
  354. if (err)
  355. return -1;
  356. if (!nicvf_check_pf_ready(nic))
  357. return -1;
  358. nic->open = true;
  359. /* Make sure queue initialization is written */
  360. asm volatile("dsb sy");
  361. return 0;
  362. }
  363. int nicvf_write_hwaddr(struct udevice *dev)
  364. {
  365. unsigned char ethaddr[ARP_HLEN];
  366. struct eth_pdata *pdata = dev_get_plat(dev);
  367. struct nicvf *nic = dev_get_priv(dev);
  368. /* If lower level firmware fails to set proper MAC
  369. * u-boot framework updates MAC to random address.
  370. * Use this hook to update mac address in environment.
  371. */
  372. if (!eth_env_get_enetaddr_by_index("eth", dev_seq(dev), ethaddr)) {
  373. eth_env_set_enetaddr_by_index("eth", dev_seq(dev),
  374. pdata->enetaddr);
  375. debug("%s: pMAC %pM\n", __func__, pdata->enetaddr);
  376. }
  377. eth_env_get_enetaddr_by_index("eth", dev_seq(dev), ethaddr);
  378. if (memcmp(ethaddr, pdata->enetaddr, ARP_HLEN)) {
  379. debug("%s: pMAC %pM\n", __func__, pdata->enetaddr);
  380. nicvf_hw_set_mac_addr(nic, dev);
  381. }
  382. return 0;
  383. }
  384. static void nicvf_probe_mdio_devices(void)
  385. {
  386. struct udevice *pdev;
  387. int err;
  388. static int probed;
  389. if (probed)
  390. return;
  391. err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
  392. PCI_DEVICE_ID_CAVIUM_SMI, 0,
  393. &pdev);
  394. if (err)
  395. debug("%s couldn't find SMI device\n", __func__);
  396. probed = 1;
  397. }
  398. int nicvf_initialize(struct udevice *dev)
  399. {
  400. struct nicvf *nicvf = dev_get_priv(dev);
  401. struct eth_pdata *pdata = dev_get_plat(dev);
  402. int ret = 0, bgx, lmac;
  403. char name[16];
  404. unsigned char ethaddr[ARP_HLEN];
  405. struct udevice *pfdev;
  406. struct nicpf *pf;
  407. static int vfid;
  408. if (dm_pci_find_device(PCI_VENDOR_ID_CAVIUM,
  409. PCI_DEVICE_ID_CAVIUM_NIC, 0, &pfdev)) {
  410. printf("%s NIC PF device not found..VF probe failed\n",
  411. __func__);
  412. return -1;
  413. }
  414. pf = dev_get_priv(pfdev);
  415. nicvf->vf_id = vfid++;
  416. nicvf->dev = dev;
  417. nicvf->nicpf = pf;
  418. nicvf_probe_mdio_devices();
  419. /* Enable TSO support */
  420. nicvf->hw_tso = true;
  421. nicvf->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
  422. PCI_REGION_MEM);
  423. debug("nicvf->reg_base: %p\n", nicvf->reg_base);
  424. if (!nicvf->reg_base) {
  425. printf("Cannot map config register space, aborting\n");
  426. ret = -1;
  427. goto fail;
  428. }
  429. ret = nicvf_set_qset_resources(nicvf);
  430. if (ret)
  431. return -1;
  432. sprintf(name, "vnic%u", nicvf->vf_id);
  433. debug("%s name %s\n", __func__, name);
  434. device_set_name(dev, name);
  435. bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]);
  436. lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(pf->vf_lmac_map[nicvf->vf_id]);
  437. debug("%s VF %d BGX %d LMAC %d\n", __func__, nicvf->vf_id, bgx, lmac);
  438. debug("%s PF %p pfdev %p VF %p vfdev %p vf->pdata %p\n",
  439. __func__, nicvf->nicpf, nicvf->nicpf->udev, nicvf, nicvf->dev,
  440. pdata);
  441. fdt_board_get_ethaddr(bgx, lmac, ethaddr);
  442. debug("%s bgx %d lmac %d ethaddr %pM\n", __func__, bgx, lmac, ethaddr);
  443. if (is_valid_ethaddr(ethaddr)) {
  444. memcpy(pdata->enetaddr, ethaddr, ARP_HLEN);
  445. eth_env_set_enetaddr_by_index("eth", dev_seq(dev), ethaddr);
  446. }
  447. debug("%s enetaddr %pM ethaddr %pM\n", __func__,
  448. pdata->enetaddr, ethaddr);
  449. fail:
  450. return ret;
  451. }
  452. int octeontx_vnic_probe(struct udevice *dev)
  453. {
  454. return nicvf_initialize(dev);
  455. }
  456. static const struct eth_ops octeontx_vnic_ops = {
  457. .start = nicvf_open,
  458. .stop = nicvf_stop,
  459. .send = nicvf_xmit,
  460. .recv = nicvf_recv,
  461. .free_pkt = nicvf_free_pkt,
  462. .write_hwaddr = nicvf_write_hwaddr,
  463. };
  464. U_BOOT_DRIVER(octeontx_vnic) = {
  465. .name = "vnic",
  466. .id = UCLASS_ETH,
  467. .probe = octeontx_vnic_probe,
  468. .ops = &octeontx_vnic_ops,
  469. .priv_auto = sizeof(struct nicvf),
  470. .plat_auto = sizeof(struct eth_pdata),
  471. };
  472. static struct pci_device_id octeontx_vnic_supported[] = {
  473. { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF) },
  474. { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_NICVF_1) },
  475. {}
  476. };
  477. U_BOOT_PCI_DEVICE(octeontx_vnic, octeontx_vnic_supported);