uboot/drivers/net/octeontx/nicvf_main.c
<<
>>
Prefs
   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,
 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