12e99ea80SHyong Youb Kim /* SPDX-License-Identifier: BSD-3-Clause 22e99ea80SHyong Youb Kim * Copyright 2008-2017 Cisco Systems, Inc. All rights reserved. 372f3de30SBruce Richardson * Copyright 2007 Nuova Systems, Inc. All rights reserved. 472f3de30SBruce Richardson */ 572f3de30SBruce Richardson 672f3de30SBruce Richardson #include <rte_memzone.h> 772f3de30SBruce Richardson #include <rte_memcpy.h> 872f3de30SBruce Richardson #include <rte_string_fns.h> 9846ac76cSJohn Daley #include <rte_ether.h> 1072f3de30SBruce Richardson 1172f3de30SBruce Richardson #include "vnic_dev.h" 1272f3de30SBruce Richardson #include "vnic_resource.h" 1372f3de30SBruce Richardson #include "vnic_devcmd.h" 149bd04182SJohn Daley #include "vnic_nic.h" 1572f3de30SBruce Richardson #include "vnic_stats.h" 16ea7768b5SHyong Youb Kim #include "vnic_flowman.h" 1772f3de30SBruce Richardson 1872f3de30SBruce Richardson 1972f3de30SBruce Richardson enum vnic_proxy_type { 2072f3de30SBruce Richardson PROXY_NONE, 2172f3de30SBruce Richardson PROXY_BY_BDF, 2272f3de30SBruce Richardson PROXY_BY_INDEX, 2372f3de30SBruce Richardson }; 2472f3de30SBruce Richardson 2572f3de30SBruce Richardson struct vnic_res { 2672f3de30SBruce Richardson void __iomem *vaddr; 2772f3de30SBruce Richardson dma_addr_t bus_addr; 2872f3de30SBruce Richardson unsigned int count; 2972f3de30SBruce Richardson }; 3072f3de30SBruce Richardson 3172f3de30SBruce Richardson struct vnic_intr_coal_timer_info { 3204e8ec74SJohn Daley uint32_t mul; 3304e8ec74SJohn Daley uint32_t div; 3404e8ec74SJohn Daley uint32_t max_usec; 3572f3de30SBruce Richardson }; 3672f3de30SBruce Richardson 3772f3de30SBruce Richardson struct vnic_dev { 3872f3de30SBruce Richardson void *priv; 3972f3de30SBruce Richardson struct rte_pci_device *pdev; 4072f3de30SBruce Richardson struct vnic_res res[RES_TYPE_MAX]; 4172f3de30SBruce Richardson enum vnic_dev_intr_mode intr_mode; 4272f3de30SBruce Richardson struct vnic_devcmd __iomem *devcmd; 4372f3de30SBruce Richardson struct vnic_devcmd_notify *notify; 4472f3de30SBruce Richardson struct vnic_devcmd_notify notify_copy; 4572f3de30SBruce Richardson dma_addr_t notify_pa; 4604e8ec74SJohn Daley uint32_t notify_sz; 4772f3de30SBruce Richardson dma_addr_t linkstatus_pa; 4872f3de30SBruce Richardson struct vnic_stats *stats; 4972f3de30SBruce Richardson dma_addr_t stats_pa; 50*00ce4311SHyong Youb Kim struct vnic_sriov_stats *sriov_stats; 51*00ce4311SHyong Youb Kim dma_addr_t sriov_stats_pa; 5272f3de30SBruce Richardson struct vnic_devcmd_fw_info *fw_info; 5372f3de30SBruce Richardson dma_addr_t fw_info_pa; 54ea7768b5SHyong Youb Kim struct fm_info *flowman_info; 55ea7768b5SHyong Youb Kim dma_addr_t flowman_info_pa; 5672f3de30SBruce Richardson enum vnic_proxy_type proxy; 5704e8ec74SJohn Daley uint32_t proxy_index; 5804e8ec74SJohn Daley uint64_t args[VNIC_DEVCMD_NARGS]; 5972f3de30SBruce Richardson int in_reset; 6072f3de30SBruce Richardson struct vnic_intr_coal_timer_info intr_coal_timer_info; 6172f3de30SBruce Richardson void *(*alloc_consistent)(void *priv, size_t size, 6204e8ec74SJohn Daley dma_addr_t *dma_handle, uint8_t *name); 63da5f560bSNelson Escobar void (*free_consistent)(void *priv, 6472f3de30SBruce Richardson size_t size, void *vaddr, 6572f3de30SBruce Richardson dma_addr_t dma_handle); 660e7312b9SHyong Youb Kim /* 670e7312b9SHyong Youb Kim * Used to serialize devcmd access, currently from PF and its 680e7312b9SHyong Youb Kim * VF representors. When there are no representors, lock is 690e7312b9SHyong Youb Kim * not used. 700e7312b9SHyong Youb Kim */ 710e7312b9SHyong Youb Kim int locked; 720e7312b9SHyong Youb Kim void (*lock)(void *priv); 730e7312b9SHyong Youb Kim void (*unlock)(void *priv); 740e7312b9SHyong Youb Kim struct vnic_dev *pf_vdev; 750e7312b9SHyong Youb Kim int vf_id; 7672f3de30SBruce Richardson }; 7772f3de30SBruce Richardson 7872f3de30SBruce Richardson #define VNIC_MAX_RES_HDR_SIZE \ 7972f3de30SBruce Richardson (sizeof(struct vnic_resource_header) + \ 8072f3de30SBruce Richardson sizeof(struct vnic_resource) * RES_TYPE_MAX) 8172f3de30SBruce Richardson #define VNIC_RES_STRIDE 128 8272f3de30SBruce Richardson 8372f3de30SBruce Richardson void *vnic_dev_priv(struct vnic_dev *vdev) 8472f3de30SBruce Richardson { 8572f3de30SBruce Richardson return vdev->priv; 8672f3de30SBruce Richardson } 8772f3de30SBruce Richardson 8872f3de30SBruce Richardson void vnic_register_cbacks(struct vnic_dev *vdev, 8972f3de30SBruce Richardson void *(*alloc_consistent)(void *priv, size_t size, 9004e8ec74SJohn Daley dma_addr_t *dma_handle, uint8_t *name), 91da5f560bSNelson Escobar void (*free_consistent)(void *priv, 9272f3de30SBruce Richardson size_t size, void *vaddr, 9372f3de30SBruce Richardson dma_addr_t dma_handle)) 9472f3de30SBruce Richardson { 9572f3de30SBruce Richardson vdev->alloc_consistent = alloc_consistent; 9672f3de30SBruce Richardson vdev->free_consistent = free_consistent; 9772f3de30SBruce Richardson } 9872f3de30SBruce Richardson 990e7312b9SHyong Youb Kim void vnic_register_lock(struct vnic_dev *vdev, void (*lock)(void *priv), 1000e7312b9SHyong Youb Kim void (*unlock)(void *priv)) 1010e7312b9SHyong Youb Kim { 1020e7312b9SHyong Youb Kim vdev->lock = lock; 1030e7312b9SHyong Youb Kim vdev->unlock = unlock; 1040e7312b9SHyong Youb Kim vdev->locked = 0; 1050e7312b9SHyong Youb Kim } 1060e7312b9SHyong Youb Kim 10772f3de30SBruce Richardson static int vnic_dev_discover_res(struct vnic_dev *vdev, 10872f3de30SBruce Richardson struct vnic_dev_bar *bar, unsigned int num_bars) 10972f3de30SBruce Richardson { 11072f3de30SBruce Richardson struct vnic_resource_header __iomem *rh; 11172f3de30SBruce Richardson struct mgmt_barmap_hdr __iomem *mrh; 11272f3de30SBruce Richardson struct vnic_resource __iomem *r; 11304e8ec74SJohn Daley uint8_t type; 11472f3de30SBruce Richardson 11572f3de30SBruce Richardson if (num_bars == 0) 11672f3de30SBruce Richardson return -EINVAL; 11772f3de30SBruce Richardson 11872f3de30SBruce Richardson if (bar->len < VNIC_MAX_RES_HDR_SIZE) { 11972f3de30SBruce Richardson pr_err("vNIC BAR0 res hdr length error\n"); 12072f3de30SBruce Richardson return -EINVAL; 12172f3de30SBruce Richardson } 12272f3de30SBruce Richardson 12372f3de30SBruce Richardson rh = bar->vaddr; 12472f3de30SBruce Richardson mrh = bar->vaddr; 12572f3de30SBruce Richardson if (!rh) { 12672f3de30SBruce Richardson pr_err("vNIC BAR0 res hdr not mem-mapped\n"); 12772f3de30SBruce Richardson return -EINVAL; 12872f3de30SBruce Richardson } 12972f3de30SBruce Richardson 13072f3de30SBruce Richardson /* Check for mgmt vnic in addition to normal vnic */ 13172f3de30SBruce Richardson if ((ioread32(&rh->magic) != VNIC_RES_MAGIC) || 13272f3de30SBruce Richardson (ioread32(&rh->version) != VNIC_RES_VERSION)) { 13372f3de30SBruce Richardson if ((ioread32(&mrh->magic) != MGMTVNIC_MAGIC) || 13472f3de30SBruce Richardson (ioread32(&mrh->version) != MGMTVNIC_VERSION)) { 13572f3de30SBruce Richardson pr_err("vNIC BAR0 res magic/version error " \ 13672f3de30SBruce Richardson "exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n", 13772f3de30SBruce Richardson VNIC_RES_MAGIC, VNIC_RES_VERSION, 13872f3de30SBruce Richardson MGMTVNIC_MAGIC, MGMTVNIC_VERSION, 13972f3de30SBruce Richardson ioread32(&rh->magic), ioread32(&rh->version)); 14072f3de30SBruce Richardson return -EINVAL; 14172f3de30SBruce Richardson } 14272f3de30SBruce Richardson } 14372f3de30SBruce Richardson 14472f3de30SBruce Richardson if (ioread32(&mrh->magic) == MGMTVNIC_MAGIC) 14572f3de30SBruce Richardson r = (struct vnic_resource __iomem *)(mrh + 1); 14672f3de30SBruce Richardson else 14772f3de30SBruce Richardson r = (struct vnic_resource __iomem *)(rh + 1); 14872f3de30SBruce Richardson 14972f3de30SBruce Richardson 15072f3de30SBruce Richardson while ((type = ioread8(&r->type)) != RES_TYPE_EOL) { 15104e8ec74SJohn Daley uint8_t bar_num = ioread8(&r->bar); 15204e8ec74SJohn Daley uint32_t bar_offset = ioread32(&r->bar_offset); 15304e8ec74SJohn Daley uint32_t count = ioread32(&r->count); 15404e8ec74SJohn Daley uint32_t len; 15572f3de30SBruce Richardson 15672f3de30SBruce Richardson r++; 15772f3de30SBruce Richardson 15872f3de30SBruce Richardson if (bar_num >= num_bars) 15972f3de30SBruce Richardson continue; 16072f3de30SBruce Richardson 16172f3de30SBruce Richardson if (!bar[bar_num].len || !bar[bar_num].vaddr) 16272f3de30SBruce Richardson continue; 16372f3de30SBruce Richardson 16472f3de30SBruce Richardson switch (type) { 16572f3de30SBruce Richardson case RES_TYPE_WQ: 16672f3de30SBruce Richardson case RES_TYPE_RQ: 16772f3de30SBruce Richardson case RES_TYPE_CQ: 16872f3de30SBruce Richardson case RES_TYPE_INTR_CTRL: 169*00ce4311SHyong Youb Kim case RES_TYPE_ADMIN_WQ: 170*00ce4311SHyong Youb Kim case RES_TYPE_ADMIN_RQ: 171*00ce4311SHyong Youb Kim case RES_TYPE_ADMIN_CQ: 17272f3de30SBruce Richardson /* each count is stride bytes long */ 17372f3de30SBruce Richardson len = count * VNIC_RES_STRIDE; 17472f3de30SBruce Richardson if (len + bar_offset > bar[bar_num].len) { 17572f3de30SBruce Richardson pr_err("vNIC BAR0 resource %d " \ 17672f3de30SBruce Richardson "out-of-bounds, offset 0x%x + " \ 17772f3de30SBruce Richardson "size 0x%x > bar len 0x%lx\n", 17872f3de30SBruce Richardson type, bar_offset, 17972f3de30SBruce Richardson len, 18072f3de30SBruce Richardson bar[bar_num].len); 18172f3de30SBruce Richardson return -EINVAL; 18272f3de30SBruce Richardson } 18372f3de30SBruce Richardson break; 18472f3de30SBruce Richardson case RES_TYPE_INTR_PBA_LEGACY: 18572f3de30SBruce Richardson case RES_TYPE_DEVCMD: 18672f3de30SBruce Richardson len = count; 18772f3de30SBruce Richardson break; 18872f3de30SBruce Richardson default: 18972f3de30SBruce Richardson continue; 19072f3de30SBruce Richardson } 19172f3de30SBruce Richardson 19272f3de30SBruce Richardson vdev->res[type].count = count; 19372f3de30SBruce Richardson vdev->res[type].vaddr = (char __iomem *)bar[bar_num].vaddr + 19472f3de30SBruce Richardson bar_offset; 19572f3de30SBruce Richardson vdev->res[type].bus_addr = bar[bar_num].bus_addr + bar_offset; 19672f3de30SBruce Richardson } 19772f3de30SBruce Richardson 19872f3de30SBruce Richardson return 0; 19972f3de30SBruce Richardson } 20072f3de30SBruce Richardson 20172f3de30SBruce Richardson unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, 20272f3de30SBruce Richardson enum vnic_res_type type) 20372f3de30SBruce Richardson { 20472f3de30SBruce Richardson return vdev->res[type].count; 20572f3de30SBruce Richardson } 20672f3de30SBruce Richardson 20772f3de30SBruce Richardson void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, 20872f3de30SBruce Richardson unsigned int index) 20972f3de30SBruce Richardson { 21072f3de30SBruce Richardson if (!vdev->res[type].vaddr) 21172f3de30SBruce Richardson return NULL; 21272f3de30SBruce Richardson 21372f3de30SBruce Richardson switch (type) { 21472f3de30SBruce Richardson case RES_TYPE_WQ: 21572f3de30SBruce Richardson case RES_TYPE_RQ: 21672f3de30SBruce Richardson case RES_TYPE_CQ: 21772f3de30SBruce Richardson case RES_TYPE_INTR_CTRL: 218*00ce4311SHyong Youb Kim case RES_TYPE_ADMIN_WQ: 219*00ce4311SHyong Youb Kim case RES_TYPE_ADMIN_RQ: 220*00ce4311SHyong Youb Kim case RES_TYPE_ADMIN_CQ: 22172f3de30SBruce Richardson return (char __iomem *)vdev->res[type].vaddr + 22272f3de30SBruce Richardson index * VNIC_RES_STRIDE; 22372f3de30SBruce Richardson default: 22472f3de30SBruce Richardson return (char __iomem *)vdev->res[type].vaddr; 22572f3de30SBruce Richardson } 22672f3de30SBruce Richardson } 22772f3de30SBruce Richardson 22872f3de30SBruce Richardson unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, 22972f3de30SBruce Richardson unsigned int desc_count, unsigned int desc_size) 23072f3de30SBruce Richardson { 23172f3de30SBruce Richardson /* The base address of the desc rings must be 512 byte aligned. 23272f3de30SBruce Richardson * Descriptor count is aligned to groups of 32 descriptors. A 23372f3de30SBruce Richardson * count of 0 means the maximum 4096 descriptors. Descriptor 23472f3de30SBruce Richardson * size is aligned to 16 bytes. 23572f3de30SBruce Richardson */ 23672f3de30SBruce Richardson 23772f3de30SBruce Richardson unsigned int count_align = 32; 23872f3de30SBruce Richardson unsigned int desc_align = 16; 23972f3de30SBruce Richardson 24072f3de30SBruce Richardson ring->base_align = 512; 24172f3de30SBruce Richardson 24272f3de30SBruce Richardson if (desc_count == 0) 24372f3de30SBruce Richardson desc_count = 4096; 24472f3de30SBruce Richardson 24572f3de30SBruce Richardson ring->desc_count = VNIC_ALIGN(desc_count, count_align); 24672f3de30SBruce Richardson 24772f3de30SBruce Richardson ring->desc_size = VNIC_ALIGN(desc_size, desc_align); 24872f3de30SBruce Richardson 24972f3de30SBruce Richardson ring->size = ring->desc_count * ring->desc_size; 25072f3de30SBruce Richardson ring->size_unaligned = ring->size + ring->base_align; 25172f3de30SBruce Richardson 25272f3de30SBruce Richardson return ring->size_unaligned; 25372f3de30SBruce Richardson } 25472f3de30SBruce Richardson 25572f3de30SBruce Richardson void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring) 25672f3de30SBruce Richardson { 25772f3de30SBruce Richardson memset(ring->descs, 0, ring->size); 25872f3de30SBruce Richardson } 25972f3de30SBruce Richardson 260d1079807SNelson Escobar int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, 26172f3de30SBruce Richardson struct vnic_dev_ring *ring, 262d1079807SNelson Escobar unsigned int desc_count, unsigned int desc_size, 263f2fc83b4SThomas Monjalon __rte_unused unsigned int socket_id, 26472f3de30SBruce Richardson char *z_name) 26572f3de30SBruce Richardson { 26661789822SAaron Conole void *alloc_addr; 267d1079807SNelson Escobar dma_addr_t alloc_pa = 0; 26872f3de30SBruce Richardson 26972f3de30SBruce Richardson vnic_dev_desc_ring_size(ring, desc_count, desc_size); 270d1079807SNelson Escobar alloc_addr = vdev->alloc_consistent(vdev->priv, 271d1079807SNelson Escobar ring->size_unaligned, 27204e8ec74SJohn Daley &alloc_pa, (uint8_t *)z_name); 273d1079807SNelson Escobar if (!alloc_addr) { 27472f3de30SBruce Richardson pr_err("Failed to allocate ring (size=%d), aborting\n", 27572f3de30SBruce Richardson (int)ring->size); 27672f3de30SBruce Richardson return -ENOMEM; 27772f3de30SBruce Richardson } 278d1079807SNelson Escobar ring->descs_unaligned = alloc_addr; 279d1079807SNelson Escobar if (!alloc_pa) { 28072f3de30SBruce Richardson pr_err("Failed to map allocated ring (size=%d), aborting\n", 28172f3de30SBruce Richardson (int)ring->size); 282d1079807SNelson Escobar vdev->free_consistent(vdev->priv, 283d1079807SNelson Escobar ring->size_unaligned, 284d1079807SNelson Escobar alloc_addr, 285d1079807SNelson Escobar alloc_pa); 28672f3de30SBruce Richardson return -ENOMEM; 28772f3de30SBruce Richardson } 288d1079807SNelson Escobar ring->base_addr_unaligned = alloc_pa; 28972f3de30SBruce Richardson 29072f3de30SBruce Richardson ring->base_addr = VNIC_ALIGN(ring->base_addr_unaligned, 29172f3de30SBruce Richardson ring->base_align); 29204e8ec74SJohn Daley ring->descs = (uint8_t *)ring->descs_unaligned + 29372f3de30SBruce Richardson (ring->base_addr - ring->base_addr_unaligned); 29472f3de30SBruce Richardson 29572f3de30SBruce Richardson vnic_dev_clear_desc_ring(ring); 29672f3de30SBruce Richardson 29772f3de30SBruce Richardson ring->desc_avail = ring->desc_count - 1; 29872f3de30SBruce Richardson 29972f3de30SBruce Richardson return 0; 30072f3de30SBruce Richardson } 30172f3de30SBruce Richardson 302f2fc83b4SThomas Monjalon void vnic_dev_free_desc_ring(__rte_unused struct vnic_dev *vdev, 30372f3de30SBruce Richardson struct vnic_dev_ring *ring) 30472f3de30SBruce Richardson { 305d1079807SNelson Escobar if (ring->descs) { 306d1079807SNelson Escobar vdev->free_consistent(vdev->priv, 307d1079807SNelson Escobar ring->size_unaligned, 308d1079807SNelson Escobar ring->descs_unaligned, 309d1079807SNelson Escobar ring->base_addr_unaligned); 31072f3de30SBruce Richardson ring->descs = NULL; 31172f3de30SBruce Richardson } 312d1079807SNelson Escobar } 31372f3de30SBruce Richardson 31472f3de30SBruce Richardson static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 31572f3de30SBruce Richardson int wait) 31672f3de30SBruce Richardson { 31772f3de30SBruce Richardson struct vnic_devcmd __iomem *devcmd = vdev->devcmd; 31872f3de30SBruce Richardson unsigned int i; 31972f3de30SBruce Richardson int delay; 32004e8ec74SJohn Daley uint32_t status; 32172f3de30SBruce Richardson int err; 32272f3de30SBruce Richardson 32372f3de30SBruce Richardson status = ioread32(&devcmd->status); 32472f3de30SBruce Richardson if (status == 0xFFFFFFFF) { 32572f3de30SBruce Richardson /* PCI-e target device is gone */ 32672f3de30SBruce Richardson return -ENODEV; 32772f3de30SBruce Richardson } 32872f3de30SBruce Richardson if (status & STAT_BUSY) { 32972f3de30SBruce Richardson 33072f3de30SBruce Richardson pr_err("Busy devcmd %d\n", _CMD_N(cmd)); 33172f3de30SBruce Richardson return -EBUSY; 33272f3de30SBruce Richardson } 33372f3de30SBruce Richardson 33472f3de30SBruce Richardson if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) { 33572f3de30SBruce Richardson for (i = 0; i < VNIC_DEVCMD_NARGS; i++) 33672f3de30SBruce Richardson writeq(vdev->args[i], &devcmd->args[i]); 33704e8ec74SJohn Daley rte_wmb(); /* complete all writes initiated till now */ 33872f3de30SBruce Richardson } 33972f3de30SBruce Richardson 34072f3de30SBruce Richardson iowrite32(cmd, &devcmd->cmd); 34172f3de30SBruce Richardson 34272f3de30SBruce Richardson if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) 34372f3de30SBruce Richardson return 0; 34472f3de30SBruce Richardson 34572f3de30SBruce Richardson for (delay = 0; delay < wait; delay++) { 34672f3de30SBruce Richardson 34704e8ec74SJohn Daley usleep(100); 34872f3de30SBruce Richardson 34972f3de30SBruce Richardson status = ioread32(&devcmd->status); 35072f3de30SBruce Richardson if (status == 0xFFFFFFFF) { 35172f3de30SBruce Richardson /* PCI-e target device is gone */ 35272f3de30SBruce Richardson return -ENODEV; 35372f3de30SBruce Richardson } 35472f3de30SBruce Richardson 35572f3de30SBruce Richardson if (!(status & STAT_BUSY)) { 35672f3de30SBruce Richardson if (status & STAT_ERROR) { 35772f3de30SBruce Richardson err = -(int)readq(&devcmd->args[0]); 3587e6be797SHyong Youb Kim if (cmd != CMD_CAPABILITY && 3597e6be797SHyong Youb Kim cmd != CMD_OVERLAY_OFFLOAD_CTRL && 3607e6be797SHyong Youb Kim cmd != CMD_GET_SUPP_FEATURE_VER) 36172f3de30SBruce Richardson pr_err("Devcmd %d failed " \ 36272f3de30SBruce Richardson "with error code %d\n", 36372f3de30SBruce Richardson _CMD_N(cmd), err); 36472f3de30SBruce Richardson return err; 36572f3de30SBruce Richardson } 36672f3de30SBruce Richardson 36772f3de30SBruce Richardson if (_CMD_DIR(cmd) & _CMD_DIR_READ) { 36804e8ec74SJohn Daley rte_rmb();/* finish all reads */ 36972f3de30SBruce Richardson for (i = 0; i < VNIC_DEVCMD_NARGS; i++) 37072f3de30SBruce Richardson vdev->args[i] = readq(&devcmd->args[i]); 37172f3de30SBruce Richardson } 37272f3de30SBruce Richardson 37372f3de30SBruce Richardson return 0; 37472f3de30SBruce Richardson } 37572f3de30SBruce Richardson } 37672f3de30SBruce Richardson 37772f3de30SBruce Richardson pr_err("Timedout devcmd %d\n", _CMD_N(cmd)); 37872f3de30SBruce Richardson return -ETIMEDOUT; 37972f3de30SBruce Richardson } 38072f3de30SBruce Richardson 38172f3de30SBruce Richardson static int vnic_dev_cmd_proxy(struct vnic_dev *vdev, 38272f3de30SBruce Richardson enum vnic_devcmd_cmd proxy_cmd, enum vnic_devcmd_cmd cmd, 38304e8ec74SJohn Daley uint64_t *args, int nargs, int wait) 38472f3de30SBruce Richardson { 38504e8ec74SJohn Daley uint32_t status; 38672f3de30SBruce Richardson int err; 38772f3de30SBruce Richardson 388322b355fSJohn Daley /* 389322b355fSJohn Daley * Proxy command consumes 2 arguments. One for proxy index, 390322b355fSJohn Daley * the other is for command to be proxied 391322b355fSJohn Daley */ 392322b355fSJohn Daley if (nargs > VNIC_DEVCMD_NARGS - 2) { 393322b355fSJohn Daley pr_err("number of args %d exceeds the maximum\n", nargs); 394322b355fSJohn Daley return -EINVAL; 395322b355fSJohn Daley } 39672f3de30SBruce Richardson memset(vdev->args, 0, sizeof(vdev->args)); 39772f3de30SBruce Richardson 39872f3de30SBruce Richardson vdev->args[0] = vdev->proxy_index; 39972f3de30SBruce Richardson vdev->args[1] = cmd; 400322b355fSJohn Daley memcpy(&vdev->args[2], args, nargs * sizeof(args[0])); 40172f3de30SBruce Richardson 40272f3de30SBruce Richardson err = _vnic_dev_cmd(vdev, proxy_cmd, wait); 40372f3de30SBruce Richardson if (err) 40472f3de30SBruce Richardson return err; 40572f3de30SBruce Richardson 40604e8ec74SJohn Daley status = (uint32_t)vdev->args[0]; 40772f3de30SBruce Richardson if (status & STAT_ERROR) { 40872f3de30SBruce Richardson err = (int)vdev->args[1]; 40972f3de30SBruce Richardson if (err != ERR_ECMDUNKNOWN || 41072f3de30SBruce Richardson cmd != CMD_CAPABILITY) 41172f3de30SBruce Richardson pr_err("Error %d proxy devcmd %d\n", err, _CMD_N(cmd)); 41272f3de30SBruce Richardson return err; 41372f3de30SBruce Richardson } 41472f3de30SBruce Richardson 415322b355fSJohn Daley memcpy(args, &vdev->args[1], nargs * sizeof(args[0])); 41672f3de30SBruce Richardson 41772f3de30SBruce Richardson return 0; 41872f3de30SBruce Richardson } 41972f3de30SBruce Richardson 42072f3de30SBruce Richardson static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev, 42104e8ec74SJohn Daley enum vnic_devcmd_cmd cmd, uint64_t *args, int nargs, int wait) 42272f3de30SBruce Richardson { 42372f3de30SBruce Richardson int err; 42472f3de30SBruce Richardson 425322b355fSJohn Daley if (nargs > VNIC_DEVCMD_NARGS) { 426322b355fSJohn Daley pr_err("number of args %d exceeds the maximum\n", nargs); 427322b355fSJohn Daley return -EINVAL; 428322b355fSJohn Daley } 429322b355fSJohn Daley memset(vdev->args, 0, sizeof(vdev->args)); 430322b355fSJohn Daley memcpy(vdev->args, args, nargs * sizeof(args[0])); 43172f3de30SBruce Richardson 43272f3de30SBruce Richardson err = _vnic_dev_cmd(vdev, cmd, wait); 43372f3de30SBruce Richardson 434322b355fSJohn Daley memcpy(args, vdev->args, nargs * sizeof(args[0])); 43572f3de30SBruce Richardson 43672f3de30SBruce Richardson return err; 43772f3de30SBruce Richardson } 43872f3de30SBruce Richardson 4390e7312b9SHyong Youb Kim void vnic_dev_cmd_proxy_by_index_start(struct vnic_dev *vdev, uint16_t index) 4400e7312b9SHyong Youb Kim { 4410e7312b9SHyong Youb Kim vdev->proxy = PROXY_BY_INDEX; 4420e7312b9SHyong Youb Kim vdev->proxy_index = index; 4430e7312b9SHyong Youb Kim } 4440e7312b9SHyong Youb Kim 4450e7312b9SHyong Youb Kim void vnic_dev_cmd_proxy_end(struct vnic_dev *vdev) 4460e7312b9SHyong Youb Kim { 4470e7312b9SHyong Youb Kim vdev->proxy = PROXY_NONE; 4480e7312b9SHyong Youb Kim vdev->proxy_index = 0; 4490e7312b9SHyong Youb Kim } 4500e7312b9SHyong Youb Kim 45172f3de30SBruce Richardson int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 45204e8ec74SJohn Daley uint64_t *a0, uint64_t *a1, int wait) 45372f3de30SBruce Richardson { 45404e8ec74SJohn Daley uint64_t args[2]; 4550e7312b9SHyong Youb Kim bool vf_rep; 4560e7312b9SHyong Youb Kim int vf_idx; 457322b355fSJohn Daley int err; 458322b355fSJohn Daley 4590e7312b9SHyong Youb Kim vf_rep = false; 4600e7312b9SHyong Youb Kim if (vdev->pf_vdev) { 4610e7312b9SHyong Youb Kim vf_rep = true; 4620e7312b9SHyong Youb Kim vf_idx = vdev->vf_id; 4630e7312b9SHyong Youb Kim /* Everything below assumes PF vdev */ 4640e7312b9SHyong Youb Kim vdev = vdev->pf_vdev; 4650e7312b9SHyong Youb Kim } 4660e7312b9SHyong Youb Kim if (vdev->lock) 4670e7312b9SHyong Youb Kim vdev->lock(vdev->priv); 4680e7312b9SHyong Youb Kim /* For VF representor, proxy devcmd to VF index */ 4690e7312b9SHyong Youb Kim if (vf_rep) 4700e7312b9SHyong Youb Kim vnic_dev_cmd_proxy_by_index_start(vdev, vf_idx); 4710e7312b9SHyong Youb Kim 472322b355fSJohn Daley args[0] = *a0; 473322b355fSJohn Daley args[1] = *a1; 47472f3de30SBruce Richardson memset(vdev->args, 0, sizeof(vdev->args)); 47572f3de30SBruce Richardson 47672f3de30SBruce Richardson switch (vdev->proxy) { 47772f3de30SBruce Richardson case PROXY_BY_INDEX: 478322b355fSJohn Daley err = vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_INDEX, cmd, 479322b355fSJohn Daley args, ARRAY_SIZE(args), wait); 480322b355fSJohn Daley break; 48172f3de30SBruce Richardson case PROXY_BY_BDF: 482322b355fSJohn Daley err = vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_BDF, cmd, 483322b355fSJohn Daley args, ARRAY_SIZE(args), wait); 484322b355fSJohn Daley break; 48572f3de30SBruce Richardson case PROXY_NONE: 48672f3de30SBruce Richardson default: 487322b355fSJohn Daley err = vnic_dev_cmd_no_proxy(vdev, cmd, args, 2, wait); 488322b355fSJohn Daley break; 48972f3de30SBruce Richardson } 490322b355fSJohn Daley 4910e7312b9SHyong Youb Kim if (vf_rep) 4920e7312b9SHyong Youb Kim vnic_dev_cmd_proxy_end(vdev); 4930e7312b9SHyong Youb Kim if (vdev->unlock) 4940e7312b9SHyong Youb Kim vdev->unlock(vdev->priv); 495322b355fSJohn Daley if (err == 0) { 496322b355fSJohn Daley *a0 = args[0]; 497322b355fSJohn Daley *a1 = args[1]; 498322b355fSJohn Daley } 499322b355fSJohn Daley 500322b355fSJohn Daley return err; 501322b355fSJohn Daley } 502322b355fSJohn Daley 503322b355fSJohn Daley int vnic_dev_cmd_args(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 50404e8ec74SJohn Daley uint64_t *args, int nargs, int wait) 505322b355fSJohn Daley { 5060e7312b9SHyong Youb Kim bool vf_rep; 5070e7312b9SHyong Youb Kim int vf_idx; 5080e7312b9SHyong Youb Kim int err; 5090e7312b9SHyong Youb Kim 5100e7312b9SHyong Youb Kim vf_rep = false; 5110e7312b9SHyong Youb Kim if (vdev->pf_vdev) { 5120e7312b9SHyong Youb Kim vf_rep = true; 5130e7312b9SHyong Youb Kim vf_idx = vdev->vf_id; 5140e7312b9SHyong Youb Kim vdev = vdev->pf_vdev; 5150e7312b9SHyong Youb Kim } 5160e7312b9SHyong Youb Kim if (vdev->lock) 5170e7312b9SHyong Youb Kim vdev->lock(vdev->priv); 5180e7312b9SHyong Youb Kim if (vf_rep) 5190e7312b9SHyong Youb Kim vnic_dev_cmd_proxy_by_index_start(vdev, vf_idx); 5200e7312b9SHyong Youb Kim 521322b355fSJohn Daley switch (vdev->proxy) { 522322b355fSJohn Daley case PROXY_BY_INDEX: 5230e7312b9SHyong Youb Kim err = vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_INDEX, cmd, 524322b355fSJohn Daley args, nargs, wait); 5250e7312b9SHyong Youb Kim break; 526322b355fSJohn Daley case PROXY_BY_BDF: 5270e7312b9SHyong Youb Kim err = vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_BDF, cmd, 528322b355fSJohn Daley args, nargs, wait); 5290e7312b9SHyong Youb Kim break; 530322b355fSJohn Daley case PROXY_NONE: 531322b355fSJohn Daley default: 5320e7312b9SHyong Youb Kim err = vnic_dev_cmd_no_proxy(vdev, cmd, args, nargs, wait); 5330e7312b9SHyong Youb Kim break; 534322b355fSJohn Daley } 5350e7312b9SHyong Youb Kim 5360e7312b9SHyong Youb Kim if (vf_rep) 5370e7312b9SHyong Youb Kim vnic_dev_cmd_proxy_end(vdev); 5380e7312b9SHyong Youb Kim if (vdev->unlock) 5390e7312b9SHyong Youb Kim vdev->unlock(vdev->priv); 5400e7312b9SHyong Youb Kim return err; 541322b355fSJohn Daley } 542322b355fSJohn Daley 54329343067SHyong Youb Kim int vnic_dev_fw_info(struct vnic_dev *vdev, 54429343067SHyong Youb Kim struct vnic_devcmd_fw_info **fw_info) 54529343067SHyong Youb Kim { 546846ac76cSJohn Daley char name[RTE_MEMZONE_NAMESIZE]; 54704e8ec74SJohn Daley uint64_t a0, a1 = 0; 54829343067SHyong Youb Kim int wait = 1000; 54929343067SHyong Youb Kim int err = 0; 55004e8ec74SJohn Daley static uint32_t instance; 55129343067SHyong Youb Kim 55229343067SHyong Youb Kim if (!vdev->fw_info) { 55329343067SHyong Youb Kim snprintf((char *)name, sizeof(name), "vnic_fw_info-%u", 55429343067SHyong Youb Kim instance++); 55529343067SHyong Youb Kim vdev->fw_info = vdev->alloc_consistent(vdev->priv, 55629343067SHyong Youb Kim sizeof(struct vnic_devcmd_fw_info), 55704e8ec74SJohn Daley &vdev->fw_info_pa, (uint8_t *)name); 55829343067SHyong Youb Kim if (!vdev->fw_info) 55929343067SHyong Youb Kim return -ENOMEM; 56029343067SHyong Youb Kim a0 = vdev->fw_info_pa; 56129343067SHyong Youb Kim a1 = sizeof(struct vnic_devcmd_fw_info); 56229343067SHyong Youb Kim err = vnic_dev_cmd(vdev, CMD_MCPU_FW_INFO, 56329343067SHyong Youb Kim &a0, &a1, wait); 56429343067SHyong Youb Kim } 56529343067SHyong Youb Kim *fw_info = vdev->fw_info; 56629343067SHyong Youb Kim return err; 56729343067SHyong Youb Kim } 56829343067SHyong Youb Kim 56904e8ec74SJohn Daley static int vnic_dev_advanced_filters_cap(struct vnic_dev *vdev, uint64_t *args, 570322b355fSJohn Daley int nargs) 571322b355fSJohn Daley { 572322b355fSJohn Daley memset(args, 0, nargs * sizeof(*args)); 573322b355fSJohn Daley args[0] = CMD_ADD_ADV_FILTER; 574322b355fSJohn Daley args[1] = FILTER_CAP_MODE_V1_FLAG; 575322b355fSJohn Daley return vnic_dev_cmd_args(vdev, CMD_CAPABILITY, args, nargs, 1000); 57672f3de30SBruce Richardson } 57772f3de30SBruce Richardson 578dfbd6a9cSJohn Daley int vnic_dev_capable_adv_filters(struct vnic_dev *vdev) 579dfbd6a9cSJohn Daley { 58004e8ec74SJohn Daley uint64_t a0 = CMD_ADD_ADV_FILTER, a1 = 0; 581dfbd6a9cSJohn Daley int wait = 1000; 582dfbd6a9cSJohn Daley int err; 583dfbd6a9cSJohn Daley 584dfbd6a9cSJohn Daley err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); 585dfbd6a9cSJohn Daley if (err) 586dfbd6a9cSJohn Daley return 0; 58704e8ec74SJohn Daley return (a1 >= (uint32_t)FILTER_DPDK_1); 588dfbd6a9cSJohn Daley } 589dfbd6a9cSJohn Daley 59004e8ec74SJohn Daley int vnic_dev_flowman_cmd(struct vnic_dev *vdev, uint64_t *args, int nargs) 591ea7768b5SHyong Youb Kim { 592ea7768b5SHyong Youb Kim int wait = 1000; 593ea7768b5SHyong Youb Kim 594ea7768b5SHyong Youb Kim return vnic_dev_cmd_args(vdev, CMD_FLOW_MANAGER_OP, args, nargs, wait); 595ea7768b5SHyong Youb Kim } 596ea7768b5SHyong Youb Kim 59704e8ec74SJohn Daley static int vnic_dev_flowman_enable(struct vnic_dev *vdev, uint32_t *mode, 59804e8ec74SJohn Daley uint8_t *filter_actions) 599ea7768b5SHyong Youb Kim { 600846ac76cSJohn Daley char name[RTE_MEMZONE_NAMESIZE]; 60104e8ec74SJohn Daley uint64_t args[3]; 60204e8ec74SJohn Daley uint64_t ops; 60304e8ec74SJohn Daley static uint32_t instance; 604ea7768b5SHyong Youb Kim 605af397b3cSHyong Youb Kim /* Advanced filtering is a prerequisite */ 606af397b3cSHyong Youb Kim if (!vnic_dev_capable_adv_filters(vdev)) 607af397b3cSHyong Youb Kim return 0; 608ea7768b5SHyong Youb Kim /* flowman devcmd available? */ 609ea7768b5SHyong Youb Kim if (!vnic_dev_capable(vdev, CMD_FLOW_MANAGER_OP)) 610ea7768b5SHyong Youb Kim return 0; 611ea7768b5SHyong Youb Kim /* Have the version we are using? */ 612ea7768b5SHyong Youb Kim args[0] = FM_API_VERSION_QUERY; 613ea7768b5SHyong Youb Kim if (vnic_dev_flowman_cmd(vdev, args, 1)) 614ea7768b5SHyong Youb Kim return 0; 615ea7768b5SHyong Youb Kim if ((args[0] & (1ULL << FM_VERSION)) == 0) 616ea7768b5SHyong Youb Kim return 0; 617ea7768b5SHyong Youb Kim /* Select the version */ 618ea7768b5SHyong Youb Kim args[0] = FM_API_VERSION_SELECT; 619ea7768b5SHyong Youb Kim args[1] = FM_VERSION; 620ea7768b5SHyong Youb Kim if (vnic_dev_flowman_cmd(vdev, args, 2)) 621ea7768b5SHyong Youb Kim return 0; 622ea7768b5SHyong Youb Kim /* Can we get fm_info? */ 623ea7768b5SHyong Youb Kim if (!vdev->flowman_info) { 624846ac76cSJohn Daley snprintf((char *)name, sizeof(name), "vnic_fm_info-%u", 625ea7768b5SHyong Youb Kim instance++); 626ea7768b5SHyong Youb Kim vdev->flowman_info = vdev->alloc_consistent(vdev->priv, 627ea7768b5SHyong Youb Kim sizeof(struct fm_info), 62804e8ec74SJohn Daley &vdev->flowman_info_pa, (uint8_t *)name); 629ea7768b5SHyong Youb Kim if (!vdev->flowman_info) 630ea7768b5SHyong Youb Kim return 0; 631ea7768b5SHyong Youb Kim } 632ea7768b5SHyong Youb Kim args[0] = FM_INFO_QUERY; 633ea7768b5SHyong Youb Kim args[1] = vdev->flowman_info_pa; 634ea7768b5SHyong Youb Kim args[2] = sizeof(struct fm_info); 635ea7768b5SHyong Youb Kim if (vnic_dev_flowman_cmd(vdev, args, 3)) 636ea7768b5SHyong Youb Kim return 0; 637ea7768b5SHyong Youb Kim /* Have required operations? */ 638ea7768b5SHyong Youb Kim ops = (1ULL << FMOP_END) | 639ea7768b5SHyong Youb Kim (1ULL << FMOP_DROP) | 640ea7768b5SHyong Youb Kim (1ULL << FMOP_RQ_STEER) | 641ea7768b5SHyong Youb Kim (1ULL << FMOP_EXACT_MATCH) | 642ea7768b5SHyong Youb Kim (1ULL << FMOP_MARK) | 643ea7768b5SHyong Youb Kim (1ULL << FMOP_TAG) | 644ea7768b5SHyong Youb Kim (1ULL << FMOP_EG_HAIRPIN) | 645ea7768b5SHyong Youb Kim (1ULL << FMOP_ENCAP) | 646ea7768b5SHyong Youb Kim (1ULL << FMOP_DECAP_NOSTRIP); 647ea7768b5SHyong Youb Kim if ((vdev->flowman_info->fm_op_mask & ops) != ops) 648ea7768b5SHyong Youb Kim return 0; 649ea7768b5SHyong Youb Kim /* Good to use flowman now */ 650ea7768b5SHyong Youb Kim *mode = FILTER_FLOWMAN; 651ea7768b5SHyong Youb Kim *filter_actions = FILTER_ACTION_RQ_STEERING_FLAG | 652ea7768b5SHyong Youb Kim FILTER_ACTION_FILTER_ID_FLAG | 653ea7768b5SHyong Youb Kim FILTER_ACTION_COUNTER_FLAG | 654ea7768b5SHyong Youb Kim FILTER_ACTION_DROP_FLAG; 655ea7768b5SHyong Youb Kim return 1; 656ea7768b5SHyong Youb Kim } 657ea7768b5SHyong Youb Kim 658fb927454SHyong Youb Kim /* Determine the "best" filtering mode VIC is capable of. Returns one of 4 659fb927454SHyong Youb Kim * value or 0 if filtering is unavailble: 660ea7768b5SHyong Youb Kim * FILTER_FLOWMAN- flowman api capable 661322b355fSJohn Daley * FILTER_DPDK_1- advanced filters availabile 662322b355fSJohn Daley * FILTER_USNIC_IP_FLAG - advanced filters but with the restriction that 663322b355fSJohn Daley * the IP layer must explicitly specified. I.e. cannot have a UDP 664322b355fSJohn Daley * filter that matches both IPv4 and IPv6. 665322b355fSJohn Daley * FILTER_IPV4_5TUPLE - fallback if either of the 2 above aren't available. 666322b355fSJohn Daley * all other filter types are not available. 667322b355fSJohn Daley * Retrun true in filter_tags if supported 668322b355fSJohn Daley */ 66904e8ec74SJohn Daley int vnic_dev_capable_filter_mode(struct vnic_dev *vdev, uint32_t *mode, 67004e8ec74SJohn Daley uint8_t *filter_actions) 671322b355fSJohn Daley { 67204e8ec74SJohn Daley uint64_t args[4]; 673322b355fSJohn Daley int err; 67404e8ec74SJohn Daley uint32_t max_level = 0; 675322b355fSJohn Daley 676ea7768b5SHyong Youb Kim /* If flowman is available, use it as it is the most capable API */ 677ea7768b5SHyong Youb Kim if (vnic_dev_flowman_enable(vdev, mode, filter_actions)) 678ea7768b5SHyong Youb Kim return 0; 679ea7768b5SHyong Youb Kim 680322b355fSJohn Daley err = vnic_dev_advanced_filters_cap(vdev, args, 4); 681322b355fSJohn Daley 682036c545dSHyong Youb Kim /* determine supported filter actions */ 683036c545dSHyong Youb Kim *filter_actions = FILTER_ACTION_RQ_STEERING_FLAG; /* always available */ 684036c545dSHyong Youb Kim if (args[2] == FILTER_CAP_MODE_V1) 685036c545dSHyong Youb Kim *filter_actions = args[3]; 686322b355fSJohn Daley 687322b355fSJohn Daley if (err || ((args[0] == 1) && (args[1] == 0))) { 688322b355fSJohn Daley /* Adv filter Command not supported or adv filters available but 689322b355fSJohn Daley * not enabled. Try the normal filter capability command. 690322b355fSJohn Daley */ 691322b355fSJohn Daley args[0] = CMD_ADD_FILTER; 692322b355fSJohn Daley args[1] = 0; 693322b355fSJohn Daley err = vnic_dev_cmd_args(vdev, CMD_CAPABILITY, args, 2, 1000); 694fb927454SHyong Youb Kim /* 695fb927454SHyong Youb Kim * ERR_EPERM may be returned if, for example, vNIC is 696fb927454SHyong Youb Kim * on a VF. It simply means no filtering is available 697fb927454SHyong Youb Kim */ 698fb927454SHyong Youb Kim if (err == -ERR_EPERM) { 699fb927454SHyong Youb Kim *mode = 0; 700fb927454SHyong Youb Kim return 0; 701fb927454SHyong Youb Kim } 702322b355fSJohn Daley if (err) 703322b355fSJohn Daley return err; 704322b355fSJohn Daley max_level = args[1]; 705322b355fSJohn Daley goto parse_max_level; 706322b355fSJohn Daley } else if (args[2] == FILTER_CAP_MODE_V1) { 707322b355fSJohn Daley /* parse filter capability mask in args[1] */ 708322b355fSJohn Daley if (args[1] & FILTER_DPDK_1_FLAG) 709322b355fSJohn Daley *mode = FILTER_DPDK_1; 710322b355fSJohn Daley else if (args[1] & FILTER_USNIC_IP_FLAG) 711322b355fSJohn Daley *mode = FILTER_USNIC_IP; 712322b355fSJohn Daley else if (args[1] & FILTER_IPV4_5TUPLE_FLAG) 713322b355fSJohn Daley *mode = FILTER_IPV4_5TUPLE; 714322b355fSJohn Daley return 0; 715322b355fSJohn Daley } 716322b355fSJohn Daley max_level = args[1]; 717322b355fSJohn Daley parse_max_level: 71804e8ec74SJohn Daley if (max_level >= (uint32_t)FILTER_USNIC_IP) 719322b355fSJohn Daley *mode = FILTER_USNIC_IP; 720322b355fSJohn Daley else 721322b355fSJohn Daley *mode = FILTER_IPV4_5TUPLE; 722322b355fSJohn Daley return 0; 723322b355fSJohn Daley } 724322b355fSJohn Daley 7255bc989e6SHyong Youb Kim void vnic_dev_capable_udp_rss_weak(struct vnic_dev *vdev, bool *cfg_chk, 7265bc989e6SHyong Youb Kim bool *weak) 7275bc989e6SHyong Youb Kim { 72804e8ec74SJohn Daley uint64_t a0 = CMD_NIC_CFG, a1 = 0; 7295bc989e6SHyong Youb Kim int wait = 1000; 7305bc989e6SHyong Youb Kim int err; 7315bc989e6SHyong Youb Kim 7325bc989e6SHyong Youb Kim *cfg_chk = false; 7335bc989e6SHyong Youb Kim *weak = false; 7345bc989e6SHyong Youb Kim err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); 7355bc989e6SHyong Youb Kim if (err == 0 && a0 != 0 && a1 != 0) { 7365bc989e6SHyong Youb Kim *cfg_chk = true; 7375bc989e6SHyong Youb Kim *weak = !!((a1 >> 32) & CMD_NIC_CFG_CAPF_UDP_WEAK); 7385bc989e6SHyong Youb Kim } 7395bc989e6SHyong Youb Kim } 7405bc989e6SHyong Youb Kim 741322b355fSJohn Daley int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd) 74272f3de30SBruce Richardson { 74304e8ec74SJohn Daley uint64_t a0 = (uint32_t)cmd, a1 = 0; 74472f3de30SBruce Richardson int wait = 1000; 74572f3de30SBruce Richardson int err; 74672f3de30SBruce Richardson 74772f3de30SBruce Richardson err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); 74872f3de30SBruce Richardson 74972f3de30SBruce Richardson return !(err || a0); 75072f3de30SBruce Richardson } 75172f3de30SBruce Richardson 75272f3de30SBruce Richardson int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, size_t size, 75372f3de30SBruce Richardson void *value) 75472f3de30SBruce Richardson { 75504e8ec74SJohn Daley uint64_t a0, a1; 75672f3de30SBruce Richardson int wait = 1000; 75772f3de30SBruce Richardson int err; 75872f3de30SBruce Richardson 75972f3de30SBruce Richardson a0 = offset; 76072f3de30SBruce Richardson a1 = size; 76172f3de30SBruce Richardson 76272f3de30SBruce Richardson err = vnic_dev_cmd(vdev, CMD_DEV_SPEC, &a0, &a1, wait); 76372f3de30SBruce Richardson 76472f3de30SBruce Richardson switch (size) { 76572f3de30SBruce Richardson case 1: 76604e8ec74SJohn Daley *(uint8_t *)value = (uint8_t)a0; 76772f3de30SBruce Richardson break; 76872f3de30SBruce Richardson case 2: 76904e8ec74SJohn Daley *(uint16_t *)value = (uint16_t)a0; 77072f3de30SBruce Richardson break; 77172f3de30SBruce Richardson case 4: 77204e8ec74SJohn Daley *(uint32_t *)value = (uint32_t)a0; 77372f3de30SBruce Richardson break; 77472f3de30SBruce Richardson case 8: 77504e8ec74SJohn Daley *(uint64_t *)value = a0; 77672f3de30SBruce Richardson break; 77772f3de30SBruce Richardson default: 77872f3de30SBruce Richardson BUG(); 77972f3de30SBruce Richardson break; 78072f3de30SBruce Richardson } 78172f3de30SBruce Richardson 78272f3de30SBruce Richardson return err; 78372f3de30SBruce Richardson } 78472f3de30SBruce Richardson 78572f3de30SBruce Richardson int vnic_dev_stats_clear(struct vnic_dev *vdev) 78672f3de30SBruce Richardson { 78704e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 78872f3de30SBruce Richardson int wait = 1000; 78972f3de30SBruce Richardson 79072f3de30SBruce Richardson return vnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait); 79172f3de30SBruce Richardson } 79272f3de30SBruce Richardson 79372f3de30SBruce Richardson int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) 79472f3de30SBruce Richardson { 79504e8ec74SJohn Daley uint64_t a0, a1; 79672f3de30SBruce Richardson int wait = 1000; 79772f3de30SBruce Richardson 79872f3de30SBruce Richardson if (!vdev->stats) 79972f3de30SBruce Richardson return -ENOMEM; 80072f3de30SBruce Richardson 80172f3de30SBruce Richardson *stats = vdev->stats; 80272f3de30SBruce Richardson a0 = vdev->stats_pa; 80372f3de30SBruce Richardson a1 = sizeof(struct vnic_stats); 80472f3de30SBruce Richardson 80572f3de30SBruce Richardson return vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait); 80672f3de30SBruce Richardson } 80772f3de30SBruce Richardson 80872f3de30SBruce Richardson int vnic_dev_close(struct vnic_dev *vdev) 80972f3de30SBruce Richardson { 81004e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 81172f3de30SBruce Richardson int wait = 1000; 81272f3de30SBruce Richardson 81372f3de30SBruce Richardson return vnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait); 81472f3de30SBruce Richardson } 81572f3de30SBruce Richardson 81672f3de30SBruce Richardson int vnic_dev_enable_wait(struct vnic_dev *vdev) 81772f3de30SBruce Richardson { 81804e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 81972f3de30SBruce Richardson int wait = 1000; 82072f3de30SBruce Richardson 82172f3de30SBruce Richardson if (vnic_dev_capable(vdev, CMD_ENABLE_WAIT)) 82272f3de30SBruce Richardson return vnic_dev_cmd(vdev, CMD_ENABLE_WAIT, &a0, &a1, wait); 82372f3de30SBruce Richardson else 82472f3de30SBruce Richardson return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait); 82572f3de30SBruce Richardson } 82672f3de30SBruce Richardson 82772f3de30SBruce Richardson int vnic_dev_disable(struct vnic_dev *vdev) 82872f3de30SBruce Richardson { 82904e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 83072f3de30SBruce Richardson int wait = 1000; 83172f3de30SBruce Richardson 83272f3de30SBruce Richardson return vnic_dev_cmd(vdev, CMD_DISABLE, &a0, &a1, wait); 83372f3de30SBruce Richardson } 83472f3de30SBruce Richardson 83572f3de30SBruce Richardson int vnic_dev_open(struct vnic_dev *vdev, int arg) 83672f3de30SBruce Richardson { 83704e8ec74SJohn Daley uint64_t a0 = (uint32_t)arg, a1 = 0; 83872f3de30SBruce Richardson int wait = 1000; 83972f3de30SBruce Richardson 84072f3de30SBruce Richardson return vnic_dev_cmd(vdev, CMD_OPEN, &a0, &a1, wait); 84172f3de30SBruce Richardson } 84272f3de30SBruce Richardson 84372f3de30SBruce Richardson int vnic_dev_open_done(struct vnic_dev *vdev, int *done) 84472f3de30SBruce Richardson { 84504e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 84672f3de30SBruce Richardson int wait = 1000; 84772f3de30SBruce Richardson int err; 84872f3de30SBruce Richardson 84972f3de30SBruce Richardson *done = 0; 85072f3de30SBruce Richardson 85172f3de30SBruce Richardson err = vnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait); 85272f3de30SBruce Richardson if (err) 85372f3de30SBruce Richardson return err; 85472f3de30SBruce Richardson 85572f3de30SBruce Richardson *done = (a0 == 0); 85672f3de30SBruce Richardson 85772f3de30SBruce Richardson return 0; 85872f3de30SBruce Richardson } 85972f3de30SBruce Richardson 86004e8ec74SJohn Daley int vnic_dev_get_mac_addr(struct vnic_dev *vdev, uint8_t *mac_addr) 86172f3de30SBruce Richardson { 86204e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 86372f3de30SBruce Richardson int wait = 1000; 86472f3de30SBruce Richardson int err, i; 86572f3de30SBruce Richardson 866846ac76cSJohn Daley for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) 86772f3de30SBruce Richardson mac_addr[i] = 0; 86872f3de30SBruce Richardson 86972f3de30SBruce Richardson err = vnic_dev_cmd(vdev, CMD_GET_MAC_ADDR, &a0, &a1, wait); 87072f3de30SBruce Richardson if (err) 87172f3de30SBruce Richardson return err; 87272f3de30SBruce Richardson 873846ac76cSJohn Daley for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) 87404e8ec74SJohn Daley mac_addr[i] = ((uint8_t *)&a0)[i]; 87572f3de30SBruce Richardson 87672f3de30SBruce Richardson return 0; 87772f3de30SBruce Richardson } 87872f3de30SBruce Richardson 87972f3de30SBruce Richardson int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, 88072f3de30SBruce Richardson int broadcast, int promisc, int allmulti) 88172f3de30SBruce Richardson { 88204e8ec74SJohn Daley uint64_t a0, a1 = 0; 88372f3de30SBruce Richardson int wait = 1000; 88472f3de30SBruce Richardson int err; 88572f3de30SBruce Richardson 88672f3de30SBruce Richardson a0 = (directed ? CMD_PFILTER_DIRECTED : 0) | 88772f3de30SBruce Richardson (multicast ? CMD_PFILTER_MULTICAST : 0) | 88872f3de30SBruce Richardson (broadcast ? CMD_PFILTER_BROADCAST : 0) | 88972f3de30SBruce Richardson (promisc ? CMD_PFILTER_PROMISCUOUS : 0) | 89072f3de30SBruce Richardson (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0); 89172f3de30SBruce Richardson 89272f3de30SBruce Richardson err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait); 89372f3de30SBruce Richardson if (err) 89472f3de30SBruce Richardson pr_err("Can't set packet filter\n"); 89572f3de30SBruce Richardson 89672f3de30SBruce Richardson return err; 89772f3de30SBruce Richardson } 89872f3de30SBruce Richardson 89904e8ec74SJohn Daley int vnic_dev_add_addr(struct vnic_dev *vdev, uint8_t *addr) 90072f3de30SBruce Richardson { 90104e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 90272f3de30SBruce Richardson int wait = 1000; 90372f3de30SBruce Richardson int err; 90472f3de30SBruce Richardson int i; 90572f3de30SBruce Richardson 906846ac76cSJohn Daley for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) 90704e8ec74SJohn Daley ((uint8_t *)&a0)[i] = addr[i]; 90872f3de30SBruce Richardson 90972f3de30SBruce Richardson err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); 91072f3de30SBruce Richardson if (err) 911c2c4f87bSAman Deep Singh pr_err("Can't add addr [" RTE_ETHER_ADDR_PRT_FMT "], %d\n", 91272f3de30SBruce Richardson addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], 91372f3de30SBruce Richardson err); 91472f3de30SBruce Richardson 91572f3de30SBruce Richardson return err; 91672f3de30SBruce Richardson } 91772f3de30SBruce Richardson 91804e8ec74SJohn Daley int vnic_dev_del_addr(struct vnic_dev *vdev, uint8_t *addr) 91972f3de30SBruce Richardson { 92004e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 92172f3de30SBruce Richardson int wait = 1000; 92272f3de30SBruce Richardson int err; 92372f3de30SBruce Richardson int i; 92472f3de30SBruce Richardson 925846ac76cSJohn Daley for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) 92604e8ec74SJohn Daley ((uint8_t *)&a0)[i] = addr[i]; 92772f3de30SBruce Richardson 92872f3de30SBruce Richardson err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); 92972f3de30SBruce Richardson if (err) 930c2c4f87bSAman Deep Singh pr_err("Can't del addr [" RTE_ETHER_ADDR_PRT_FMT "], %d\n", 93172f3de30SBruce Richardson addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], 93272f3de30SBruce Richardson err); 93372f3de30SBruce Richardson 93472f3de30SBruce Richardson return err; 93572f3de30SBruce Richardson } 93672f3de30SBruce Richardson 93772f3de30SBruce Richardson int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev, 93804e8ec74SJohn Daley uint8_t ig_vlan_rewrite_mode) 93972f3de30SBruce Richardson { 94004e8ec74SJohn Daley uint64_t a0 = ig_vlan_rewrite_mode, a1 = 0; 94172f3de30SBruce Richardson int wait = 1000; 94272f3de30SBruce Richardson 94372f3de30SBruce Richardson if (vnic_dev_capable(vdev, CMD_IG_VLAN_REWRITE_MODE)) 94472f3de30SBruce Richardson return vnic_dev_cmd(vdev, CMD_IG_VLAN_REWRITE_MODE, 94572f3de30SBruce Richardson &a0, &a1, wait); 94672f3de30SBruce Richardson else 94772f3de30SBruce Richardson return 0; 94872f3de30SBruce Richardson } 94972f3de30SBruce Richardson 95072f3de30SBruce Richardson void vnic_dev_set_reset_flag(struct vnic_dev *vdev, int state) 95172f3de30SBruce Richardson { 95272f3de30SBruce Richardson vdev->in_reset = state; 95372f3de30SBruce Richardson } 95472f3de30SBruce Richardson 95572f3de30SBruce Richardson static inline int vnic_dev_in_reset(struct vnic_dev *vdev) 95672f3de30SBruce Richardson { 95772f3de30SBruce Richardson return vdev->in_reset; 95872f3de30SBruce Richardson } 95972f3de30SBruce Richardson 96072f3de30SBruce Richardson int vnic_dev_notify_setcmd(struct vnic_dev *vdev, 96104e8ec74SJohn Daley void *notify_addr, dma_addr_t notify_pa, uint16_t intr) 96272f3de30SBruce Richardson { 96304e8ec74SJohn Daley uint64_t a0, a1; 96472f3de30SBruce Richardson int wait = 1000; 96572f3de30SBruce Richardson int r; 96672f3de30SBruce Richardson 96772f3de30SBruce Richardson memset(notify_addr, 0, sizeof(struct vnic_devcmd_notify)); 96872f3de30SBruce Richardson if (!vnic_dev_in_reset(vdev)) { 96972f3de30SBruce Richardson vdev->notify = notify_addr; 97072f3de30SBruce Richardson vdev->notify_pa = notify_pa; 97172f3de30SBruce Richardson } 97272f3de30SBruce Richardson 97304e8ec74SJohn Daley a0 = (uint64_t)notify_pa; 97404e8ec74SJohn Daley a1 = ((uint64_t)intr << 32) & 0x0000ffff00000000ULL; 97572f3de30SBruce Richardson a1 += sizeof(struct vnic_devcmd_notify); 97672f3de30SBruce Richardson 97772f3de30SBruce Richardson r = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); 97872f3de30SBruce Richardson if (!vnic_dev_in_reset(vdev)) 97904e8ec74SJohn Daley vdev->notify_sz = (r == 0) ? (uint32_t)a1 : 0; 98072f3de30SBruce Richardson 98172f3de30SBruce Richardson return r; 98272f3de30SBruce Richardson } 98372f3de30SBruce Richardson 98404e8ec74SJohn Daley int vnic_dev_notify_set(struct vnic_dev *vdev, uint16_t intr) 98572f3de30SBruce Richardson { 98672f3de30SBruce Richardson void *notify_addr = NULL; 98772f3de30SBruce Richardson dma_addr_t notify_pa = 0; 988846ac76cSJohn Daley char name[RTE_MEMZONE_NAMESIZE]; 98904e8ec74SJohn Daley static uint32_t instance; 99072f3de30SBruce Richardson 99172f3de30SBruce Richardson if (vdev->notify || vdev->notify_pa) { 9927fbf050cSJohn Daley return vnic_dev_notify_setcmd(vdev, vdev->notify, 9937fbf050cSJohn Daley vdev->notify_pa, intr); 99472f3de30SBruce Richardson } 99572f3de30SBruce Richardson if (!vnic_dev_in_reset(vdev)) { 99672f3de30SBruce Richardson snprintf((char *)name, sizeof(name), 99732d1206eSAaron Conole "vnic_notify-%u", instance++); 99872f3de30SBruce Richardson notify_addr = vdev->alloc_consistent(vdev->priv, 99972f3de30SBruce Richardson sizeof(struct vnic_devcmd_notify), 100004e8ec74SJohn Daley ¬ify_pa, (uint8_t *)name); 100172f3de30SBruce Richardson if (!notify_addr) 100272f3de30SBruce Richardson return -ENOMEM; 100372f3de30SBruce Richardson } 100472f3de30SBruce Richardson 100572f3de30SBruce Richardson return vnic_dev_notify_setcmd(vdev, notify_addr, notify_pa, intr); 100672f3de30SBruce Richardson } 100772f3de30SBruce Richardson 100872f3de30SBruce Richardson int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev) 100972f3de30SBruce Richardson { 101004e8ec74SJohn Daley uint64_t a0, a1; 101172f3de30SBruce Richardson int wait = 1000; 101272f3de30SBruce Richardson int err; 101372f3de30SBruce Richardson 101472f3de30SBruce Richardson a0 = 0; /* paddr = 0 to unset notify buffer */ 101572f3de30SBruce Richardson a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */ 101672f3de30SBruce Richardson a1 += sizeof(struct vnic_devcmd_notify); 101772f3de30SBruce Richardson 101872f3de30SBruce Richardson err = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); 101972f3de30SBruce Richardson if (!vnic_dev_in_reset(vdev)) { 102072f3de30SBruce Richardson vdev->notify = NULL; 102172f3de30SBruce Richardson vdev->notify_pa = 0; 102272f3de30SBruce Richardson vdev->notify_sz = 0; 102372f3de30SBruce Richardson } 102472f3de30SBruce Richardson 102572f3de30SBruce Richardson return err; 102672f3de30SBruce Richardson } 102772f3de30SBruce Richardson 102872f3de30SBruce Richardson int vnic_dev_notify_unset(struct vnic_dev *vdev) 102972f3de30SBruce Richardson { 103072f3de30SBruce Richardson if (vdev->notify && !vnic_dev_in_reset(vdev)) { 1031da5f560bSNelson Escobar vdev->free_consistent(vdev->priv, 103272f3de30SBruce Richardson sizeof(struct vnic_devcmd_notify), 103372f3de30SBruce Richardson vdev->notify, 103472f3de30SBruce Richardson vdev->notify_pa); 103572f3de30SBruce Richardson } 103672f3de30SBruce Richardson 103772f3de30SBruce Richardson return vnic_dev_notify_unsetcmd(vdev); 103872f3de30SBruce Richardson } 103972f3de30SBruce Richardson 104072f3de30SBruce Richardson static int vnic_dev_notify_ready(struct vnic_dev *vdev) 104172f3de30SBruce Richardson { 104204e8ec74SJohn Daley uint32_t *words; 104372f3de30SBruce Richardson unsigned int nwords = vdev->notify_sz / 4; 104472f3de30SBruce Richardson unsigned int i; 104504e8ec74SJohn Daley uint32_t csum; 104672f3de30SBruce Richardson 104772f3de30SBruce Richardson if (!vdev->notify || !vdev->notify_sz) 104872f3de30SBruce Richardson return 0; 104972f3de30SBruce Richardson 105072f3de30SBruce Richardson do { 105172f3de30SBruce Richardson csum = 0; 105272f3de30SBruce Richardson rte_memcpy(&vdev->notify_copy, vdev->notify, vdev->notify_sz); 105304e8ec74SJohn Daley words = (uint32_t *)&vdev->notify_copy; 105472f3de30SBruce Richardson for (i = 1; i < nwords; i++) 105572f3de30SBruce Richardson csum += words[i]; 105672f3de30SBruce Richardson } while (csum != words[0]); 105772f3de30SBruce Richardson 105872f3de30SBruce Richardson return 1; 105972f3de30SBruce Richardson } 106072f3de30SBruce Richardson 106172f3de30SBruce Richardson int vnic_dev_init(struct vnic_dev *vdev, int arg) 106272f3de30SBruce Richardson { 106304e8ec74SJohn Daley uint64_t a0 = (uint32_t)arg, a1 = 0; 106472f3de30SBruce Richardson int wait = 1000; 106572f3de30SBruce Richardson int r = 0; 106672f3de30SBruce Richardson 106772f3de30SBruce Richardson if (vnic_dev_capable(vdev, CMD_INIT)) 106872f3de30SBruce Richardson r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); 106972f3de30SBruce Richardson else { 107072f3de30SBruce Richardson vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait); 107172f3de30SBruce Richardson if (a0 & CMD_INITF_DEFAULT_MAC) { 107272f3de30SBruce Richardson /* Emulate these for old CMD_INIT_v1 which 107372f3de30SBruce Richardson * didn't pass a0 so no CMD_INITF_*. 107472f3de30SBruce Richardson */ 107572f3de30SBruce Richardson vnic_dev_cmd(vdev, CMD_GET_MAC_ADDR, &a0, &a1, wait); 107672f3de30SBruce Richardson vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); 107772f3de30SBruce Richardson } 107872f3de30SBruce Richardson } 107972f3de30SBruce Richardson return r; 108072f3de30SBruce Richardson } 108172f3de30SBruce Richardson 108272f3de30SBruce Richardson void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev) 108372f3de30SBruce Richardson { 108472f3de30SBruce Richardson /* Default: hardware intr coal timer is in units of 1.5 usecs */ 108572f3de30SBruce Richardson vdev->intr_coal_timer_info.mul = 2; 108672f3de30SBruce Richardson vdev->intr_coal_timer_info.div = 3; 108772f3de30SBruce Richardson vdev->intr_coal_timer_info.max_usec = 108872f3de30SBruce Richardson vnic_dev_intr_coal_timer_hw_to_usec(vdev, 0xffff); 108972f3de30SBruce Richardson } 109072f3de30SBruce Richardson 109172f3de30SBruce Richardson int vnic_dev_link_status(struct vnic_dev *vdev) 109272f3de30SBruce Richardson { 109372f3de30SBruce Richardson if (!vnic_dev_notify_ready(vdev)) 109472f3de30SBruce Richardson return 0; 109572f3de30SBruce Richardson 109672f3de30SBruce Richardson return vdev->notify_copy.link_state; 109772f3de30SBruce Richardson } 109872f3de30SBruce Richardson 109904e8ec74SJohn Daley uint32_t vnic_dev_port_speed(struct vnic_dev *vdev) 110072f3de30SBruce Richardson { 110172f3de30SBruce Richardson if (!vnic_dev_notify_ready(vdev)) 110272f3de30SBruce Richardson return 0; 110372f3de30SBruce Richardson 110472f3de30SBruce Richardson return vdev->notify_copy.port_speed; 110572f3de30SBruce Richardson } 110672f3de30SBruce Richardson 11070e7312b9SHyong Youb Kim uint32_t vnic_dev_mtu(struct vnic_dev *vdev) 11080e7312b9SHyong Youb Kim { 11090e7312b9SHyong Youb Kim if (!vnic_dev_notify_ready(vdev)) 11100e7312b9SHyong Youb Kim return 0; 11110e7312b9SHyong Youb Kim 11120e7312b9SHyong Youb Kim return vdev->notify_copy.mtu; 11130e7312b9SHyong Youb Kim } 11140e7312b9SHyong Youb Kim 11150e7312b9SHyong Youb Kim uint32_t vnic_dev_uif(struct vnic_dev *vdev) 11160e7312b9SHyong Youb Kim { 11170e7312b9SHyong Youb Kim if (!vnic_dev_notify_ready(vdev)) 11180e7312b9SHyong Youb Kim return 0; 11190e7312b9SHyong Youb Kim 11200e7312b9SHyong Youb Kim return vdev->notify_copy.uif; 11210e7312b9SHyong Youb Kim } 11220e7312b9SHyong Youb Kim 112304e8ec74SJohn Daley uint32_t vnic_dev_intr_coal_timer_usec_to_hw(struct vnic_dev *vdev, 112404e8ec74SJohn Daley uint32_t usec) 112572f3de30SBruce Richardson { 112672f3de30SBruce Richardson return (usec * vdev->intr_coal_timer_info.mul) / 112772f3de30SBruce Richardson vdev->intr_coal_timer_info.div; 112872f3de30SBruce Richardson } 112972f3de30SBruce Richardson 113004e8ec74SJohn Daley uint32_t vnic_dev_intr_coal_timer_hw_to_usec(struct vnic_dev *vdev, 113104e8ec74SJohn Daley uint32_t hw_cycles) 113272f3de30SBruce Richardson { 113372f3de30SBruce Richardson return (hw_cycles * vdev->intr_coal_timer_info.div) / 113472f3de30SBruce Richardson vdev->intr_coal_timer_info.mul; 113572f3de30SBruce Richardson } 113672f3de30SBruce Richardson 113704e8ec74SJohn Daley uint32_t vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev) 113872f3de30SBruce Richardson { 113972f3de30SBruce Richardson return vdev->intr_coal_timer_info.max_usec; 114072f3de30SBruce Richardson } 114172f3de30SBruce Richardson 11428d782f3fSHyong Youb Kim int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev) 11438d782f3fSHyong Youb Kim { 1144846ac76cSJohn Daley char name[RTE_MEMZONE_NAMESIZE]; 114504e8ec74SJohn Daley static uint32_t instance; 11468d782f3fSHyong Youb Kim 11478d782f3fSHyong Youb Kim snprintf((char *)name, sizeof(name), "vnic_stats-%u", instance++); 11488d782f3fSHyong Youb Kim vdev->stats = vdev->alloc_consistent(vdev->priv, 11498d782f3fSHyong Youb Kim sizeof(struct vnic_stats), 115004e8ec74SJohn Daley &vdev->stats_pa, (uint8_t *)name); 11518d782f3fSHyong Youb Kim return vdev->stats == NULL ? -ENOMEM : 0; 11528d782f3fSHyong Youb Kim } 11538d782f3fSHyong Youb Kim 1154*00ce4311SHyong Youb Kim int vnic_dev_alloc_sriov_stats_mem(struct vnic_dev *vdev) 1155*00ce4311SHyong Youb Kim { 1156*00ce4311SHyong Youb Kim char name[RTE_MEMZONE_NAMESIZE]; 1157*00ce4311SHyong Youb Kim static uint32_t instance; 1158*00ce4311SHyong Youb Kim 1159*00ce4311SHyong Youb Kim snprintf((char *)name, sizeof(name), "vnic_sriov_stats-%u", instance++); 1160*00ce4311SHyong Youb Kim vdev->sriov_stats = vdev->alloc_consistent(vdev->priv, 1161*00ce4311SHyong Youb Kim sizeof(struct vnic_sriov_stats), 1162*00ce4311SHyong Youb Kim &vdev->sriov_stats_pa, (uint8_t *)name); 1163*00ce4311SHyong Youb Kim return vdev->sriov_stats == NULL ? -ENOMEM : 0; 1164*00ce4311SHyong Youb Kim } 1165*00ce4311SHyong Youb Kim 116672f3de30SBruce Richardson void vnic_dev_unregister(struct vnic_dev *vdev) 116772f3de30SBruce Richardson { 116872f3de30SBruce Richardson if (vdev) { 116972f3de30SBruce Richardson if (vdev->notify) 1170da5f560bSNelson Escobar vdev->free_consistent(vdev->priv, 117172f3de30SBruce Richardson sizeof(struct vnic_devcmd_notify), 117272f3de30SBruce Richardson vdev->notify, 117372f3de30SBruce Richardson vdev->notify_pa); 117472f3de30SBruce Richardson if (vdev->stats) 1175da5f560bSNelson Escobar vdev->free_consistent(vdev->priv, 117672f3de30SBruce Richardson sizeof(struct vnic_stats), 117772f3de30SBruce Richardson vdev->stats, vdev->stats_pa); 1178*00ce4311SHyong Youb Kim if (vdev->sriov_stats) 1179*00ce4311SHyong Youb Kim vdev->free_consistent(vdev->priv, 1180*00ce4311SHyong Youb Kim sizeof(struct vnic_sriov_stats), 1181*00ce4311SHyong Youb Kim vdev->sriov_stats, vdev->sriov_stats_pa); 1182ea7768b5SHyong Youb Kim if (vdev->flowman_info) 1183ea7768b5SHyong Youb Kim vdev->free_consistent(vdev->priv, 1184ea7768b5SHyong Youb Kim sizeof(struct fm_info), 1185ea7768b5SHyong Youb Kim vdev->flowman_info, vdev->flowman_info_pa); 118672f3de30SBruce Richardson if (vdev->fw_info) 1187da5f560bSNelson Escobar vdev->free_consistent(vdev->priv, 118872f3de30SBruce Richardson sizeof(struct vnic_devcmd_fw_info), 118972f3de30SBruce Richardson vdev->fw_info, vdev->fw_info_pa); 11900e804034SJohn Daley rte_free(vdev); 119172f3de30SBruce Richardson } 119272f3de30SBruce Richardson } 119372f3de30SBruce Richardson 119472f3de30SBruce Richardson struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, 119572f3de30SBruce Richardson void *priv, struct rte_pci_device *pdev, struct vnic_dev_bar *bar, 119672f3de30SBruce Richardson unsigned int num_bars) 119772f3de30SBruce Richardson { 119872f3de30SBruce Richardson if (!vdev) { 1199846ac76cSJohn Daley char name[RTE_MEMZONE_NAMESIZE]; 12000e804034SJohn Daley snprintf((char *)name, sizeof(name), "%s-vnic", 12010e804034SJohn Daley pdev->device.name); 12020e804034SJohn Daley vdev = (struct vnic_dev *)rte_zmalloc_socket(name, 12030e804034SJohn Daley sizeof(struct vnic_dev), 12040e804034SJohn Daley RTE_CACHE_LINE_SIZE, 12050e804034SJohn Daley pdev->device.numa_node); 120672f3de30SBruce Richardson if (!vdev) 120772f3de30SBruce Richardson return NULL; 120872f3de30SBruce Richardson } 120972f3de30SBruce Richardson 121072f3de30SBruce Richardson vdev->priv = priv; 121172f3de30SBruce Richardson vdev->pdev = pdev; 121272f3de30SBruce Richardson 121372f3de30SBruce Richardson if (vnic_dev_discover_res(vdev, bar, num_bars)) 121472f3de30SBruce Richardson goto err_out; 121572f3de30SBruce Richardson 121672f3de30SBruce Richardson vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); 121772f3de30SBruce Richardson if (!vdev->devcmd) 121872f3de30SBruce Richardson goto err_out; 121972f3de30SBruce Richardson 122072f3de30SBruce Richardson return vdev; 122172f3de30SBruce Richardson 122272f3de30SBruce Richardson err_out: 122372f3de30SBruce Richardson vnic_dev_unregister(vdev); 122472f3de30SBruce Richardson return NULL; 122572f3de30SBruce Richardson } 122672f3de30SBruce Richardson 12270e7312b9SHyong Youb Kim struct vnic_dev *vnic_vf_rep_register(void *priv, struct vnic_dev *pf_vdev, 12280e7312b9SHyong Youb Kim int vf_id) 12290e7312b9SHyong Youb Kim { 12300e7312b9SHyong Youb Kim struct vnic_dev *vdev; 12310e7312b9SHyong Youb Kim 12320e7312b9SHyong Youb Kim vdev = (struct vnic_dev *)rte_zmalloc("enic-vf-rep-vdev", 12330e7312b9SHyong Youb Kim sizeof(struct vnic_dev), RTE_CACHE_LINE_SIZE); 12340e7312b9SHyong Youb Kim if (!vdev) 12350e7312b9SHyong Youb Kim return NULL; 12360e7312b9SHyong Youb Kim vdev->priv = priv; 12370e7312b9SHyong Youb Kim vdev->pf_vdev = pf_vdev; 12380e7312b9SHyong Youb Kim vdev->vf_id = vf_id; 12390e7312b9SHyong Youb Kim vdev->alloc_consistent = pf_vdev->alloc_consistent; 12400e7312b9SHyong Youb Kim vdev->free_consistent = pf_vdev->free_consistent; 12410e7312b9SHyong Youb Kim return vdev; 12420e7312b9SHyong Youb Kim } 12430e7312b9SHyong Youb Kim 124472f3de30SBruce Richardson /* 124572f3de30SBruce Richardson * vnic_dev_classifier: Add/Delete classifier entries 124672f3de30SBruce Richardson * @vdev: vdev of the device 124772f3de30SBruce Richardson * @cmd: CLSF_ADD for Add filter 124872f3de30SBruce Richardson * CLSF_DEL for Delete filter 124972f3de30SBruce Richardson * @entry: In case of ADD filter, the caller passes the RQ number in this 125072f3de30SBruce Richardson * variable. 125172f3de30SBruce Richardson * This function stores the filter_id returned by the 125272f3de30SBruce Richardson * firmware in the same variable before return; 125372f3de30SBruce Richardson * 125472f3de30SBruce Richardson * In case of DEL filter, the caller passes the RQ number. Return 125572f3de30SBruce Richardson * value is irrelevant. 125672f3de30SBruce Richardson * @data: filter data 1257322b355fSJohn Daley * @action: action data 125872f3de30SBruce Richardson */ 125904e8ec74SJohn Daley int vnic_dev_classifier(struct vnic_dev *vdev, uint8_t cmd, uint16_t *entry, 1260322b355fSJohn Daley struct filter_v2 *data, struct filter_action_v2 *action_v2) 126172f3de30SBruce Richardson { 126204e8ec74SJohn Daley uint64_t a0 = 0, a1 = 0; 126372f3de30SBruce Richardson int wait = 1000; 126472f3de30SBruce Richardson dma_addr_t tlv_pa; 126572f3de30SBruce Richardson int ret = -EINVAL; 126672f3de30SBruce Richardson struct filter_tlv *tlv, *tlv_va; 126704e8ec74SJohn Daley uint64_t tlv_size; 126804e8ec74SJohn Daley uint32_t filter_size, action_size; 126972f3de30SBruce Richardson static unsigned int unique_id; 127072f3de30SBruce Richardson char z_name[RTE_MEMZONE_NAMESIZE]; 1271dfbd6a9cSJohn Daley enum vnic_devcmd_cmd dev_cmd; 1272dfbd6a9cSJohn Daley 127372f3de30SBruce Richardson if (cmd == CLSF_ADD) { 1274322b355fSJohn Daley dev_cmd = (data->type >= FILTER_DPDK_1) ? 1275322b355fSJohn Daley CMD_ADD_ADV_FILTER : CMD_ADD_FILTER; 1276dfbd6a9cSJohn Daley 1277dfbd6a9cSJohn Daley filter_size = vnic_filter_size(data); 1278322b355fSJohn Daley action_size = vnic_action_size(action_v2); 1279322b355fSJohn Daley 1280322b355fSJohn Daley tlv_size = filter_size + action_size + 128172f3de30SBruce Richardson 2*sizeof(struct filter_tlv); 128272f3de30SBruce Richardson snprintf((char *)z_name, sizeof(z_name), 128332d1206eSAaron Conole "vnic_clsf_%u", unique_id++); 128472f3de30SBruce Richardson tlv_va = vdev->alloc_consistent(vdev->priv, 128504e8ec74SJohn Daley tlv_size, &tlv_pa, (uint8_t *)z_name); 128672f3de30SBruce Richardson if (!tlv_va) 128772f3de30SBruce Richardson return -ENOMEM; 128872f3de30SBruce Richardson tlv = tlv_va; 128972f3de30SBruce Richardson a0 = tlv_pa; 129072f3de30SBruce Richardson a1 = tlv_size; 129172f3de30SBruce Richardson memset(tlv, 0, tlv_size); 129272f3de30SBruce Richardson tlv->type = CLSF_TLV_FILTER; 1293dfbd6a9cSJohn Daley tlv->length = filter_size; 1294dfbd6a9cSJohn Daley memcpy(&tlv->val, (void *)data, filter_size); 129572f3de30SBruce Richardson 129672f3de30SBruce Richardson tlv = (struct filter_tlv *)((char *)tlv + 129772f3de30SBruce Richardson sizeof(struct filter_tlv) + 1298dfbd6a9cSJohn Daley filter_size); 129972f3de30SBruce Richardson 130072f3de30SBruce Richardson tlv->type = CLSF_TLV_ACTION; 1301322b355fSJohn Daley tlv->length = action_size; 1302322b355fSJohn Daley memcpy(&tlv->val, (void *)action_v2, action_size); 1303dfbd6a9cSJohn Daley ret = vnic_dev_cmd(vdev, dev_cmd, &a0, &a1, wait); 130404e8ec74SJohn Daley *entry = (uint16_t)a0; 1305da5f560bSNelson Escobar vdev->free_consistent(vdev->priv, tlv_size, tlv_va, tlv_pa); 130672f3de30SBruce Richardson } else if (cmd == CLSF_DEL) { 130772f3de30SBruce Richardson a0 = *entry; 130872f3de30SBruce Richardson ret = vnic_dev_cmd(vdev, CMD_DEL_FILTER, &a0, &a1, wait); 130972f3de30SBruce Richardson } 131072f3de30SBruce Richardson 131172f3de30SBruce Richardson return ret; 131272f3de30SBruce Richardson } 131393fb21fdSHyong Youb Kim 131404e8ec74SJohn Daley int vnic_dev_overlay_offload_ctrl(struct vnic_dev *vdev, uint8_t overlay, 131504e8ec74SJohn Daley uint8_t config) 131693fb21fdSHyong Youb Kim { 131704e8ec74SJohn Daley uint64_t a0 = overlay; 131804e8ec74SJohn Daley uint64_t a1 = config; 131993fb21fdSHyong Youb Kim int wait = 1000; 132093fb21fdSHyong Youb Kim 132193fb21fdSHyong Youb Kim return vnic_dev_cmd(vdev, CMD_OVERLAY_OFFLOAD_CTRL, &a0, &a1, wait); 132293fb21fdSHyong Youb Kim } 132393fb21fdSHyong Youb Kim 132404e8ec74SJohn Daley int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, uint8_t overlay, 132504e8ec74SJohn Daley uint16_t vxlan_udp_port_number) 132693fb21fdSHyong Youb Kim { 132704e8ec74SJohn Daley uint64_t a1 = vxlan_udp_port_number; 132804e8ec74SJohn Daley uint64_t a0 = overlay; 132993fb21fdSHyong Youb Kim int wait = 1000; 133093fb21fdSHyong Youb Kim 133193fb21fdSHyong Youb Kim return vnic_dev_cmd(vdev, CMD_OVERLAY_OFFLOAD_CFG, &a0, &a1, wait); 133293fb21fdSHyong Youb Kim } 133393fb21fdSHyong Youb Kim 133493fb21fdSHyong Youb Kim int vnic_dev_capable_vxlan(struct vnic_dev *vdev) 133593fb21fdSHyong Youb Kim { 133604e8ec74SJohn Daley uint64_t a0 = VIC_FEATURE_VXLAN; 133704e8ec74SJohn Daley uint64_t a1 = 0; 133893fb21fdSHyong Youb Kim int wait = 1000; 133993fb21fdSHyong Youb Kim int ret; 134093fb21fdSHyong Youb Kim 134193fb21fdSHyong Youb Kim ret = vnic_dev_cmd(vdev, CMD_GET_SUPP_FEATURE_VER, &a0, &a1, wait); 134293fb21fdSHyong Youb Kim /* 1 if the NIC can do VXLAN for both IPv4 and IPv6 with multiple WQs */ 134393fb21fdSHyong Youb Kim return ret == 0 && 134493fb21fdSHyong Youb Kim (a1 & (FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ)) == 134593fb21fdSHyong Youb Kim (FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ); 134693fb21fdSHyong Youb Kim } 1347c02a96fcSHyong Youb Kim 1348c02a96fcSHyong Youb Kim int vnic_dev_capable_geneve(struct vnic_dev *vdev) 1349c02a96fcSHyong Youb Kim { 135004e8ec74SJohn Daley uint64_t a0 = VIC_FEATURE_GENEVE; 135104e8ec74SJohn Daley uint64_t a1 = 0; 1352c02a96fcSHyong Youb Kim int wait = 1000; 1353c02a96fcSHyong Youb Kim int ret; 1354c02a96fcSHyong Youb Kim 1355c02a96fcSHyong Youb Kim ret = vnic_dev_cmd(vdev, CMD_GET_SUPP_FEATURE_VER, &a0, &a1, wait); 135661c7b522SJohn Daley return ret == 0 && !!(a1 & FEATURE_GENEVE_OPTIONS); 1357c02a96fcSHyong Youb Kim } 13588b428cb5SHyong Youb Kim 13598b428cb5SHyong Youb Kim uint64_t vnic_dev_capable_cq_entry_size(struct vnic_dev *vdev) 13608b428cb5SHyong Youb Kim { 13618b428cb5SHyong Youb Kim uint64_t a0 = CMD_CQ_ENTRY_SIZE_SET; 13628b428cb5SHyong Youb Kim uint64_t a1 = 0; 13638b428cb5SHyong Youb Kim int wait = 1000; 13648b428cb5SHyong Youb Kim int ret; 13658b428cb5SHyong Youb Kim 13668b428cb5SHyong Youb Kim ret = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); 13678b428cb5SHyong Youb Kim /* All models support 16B CQ entry by default */ 13688b428cb5SHyong Youb Kim if (!(ret == 0 && a0 == 0)) 13698b428cb5SHyong Youb Kim a1 = VNIC_RQ_CQ_ENTRY_SIZE_16_CAPABLE; 13708b428cb5SHyong Youb Kim return a1; 13718b428cb5SHyong Youb Kim } 13728b428cb5SHyong Youb Kim 13738b428cb5SHyong Youb Kim int vnic_dev_set_cq_entry_size(struct vnic_dev *vdev, uint32_t rq_idx, 13748b428cb5SHyong Youb Kim uint32_t size_flag) 13758b428cb5SHyong Youb Kim { 13768b428cb5SHyong Youb Kim uint64_t a0 = rq_idx; 13778b428cb5SHyong Youb Kim uint64_t a1 = size_flag; 13788b428cb5SHyong Youb Kim int wait = 1000; 13798b428cb5SHyong Youb Kim 13808b428cb5SHyong Youb Kim return vnic_dev_cmd(vdev, CMD_CQ_ENTRY_SIZE_SET, &a0, &a1, wait); 13818b428cb5SHyong Youb Kim } 1382*00ce4311SHyong Youb Kim 1383*00ce4311SHyong Youb Kim int vnic_dev_enable_admin_qp(struct vnic_dev *vdev, uint32_t enable) 1384*00ce4311SHyong Youb Kim { 1385*00ce4311SHyong Youb Kim uint64_t a0, a1; 1386*00ce4311SHyong Youb Kim int wait = 1000; 1387*00ce4311SHyong Youb Kim 1388*00ce4311SHyong Youb Kim a0 = QP_TYPE_ADMIN; 1389*00ce4311SHyong Youb Kim a1 = enable; 1390*00ce4311SHyong Youb Kim return vnic_dev_cmd(vdev, CMD_QP_TYPE_SET, &a0, &a1, wait); 1391*00ce4311SHyong Youb Kim } 1392*00ce4311SHyong Youb Kim 1393*00ce4311SHyong Youb Kim int vnic_dev_sriov_stats(struct vnic_dev *vdev, struct vnic_sriov_stats **stats) 1394*00ce4311SHyong Youb Kim { 1395*00ce4311SHyong Youb Kim uint64_t a0, a1; 1396*00ce4311SHyong Youb Kim int wait = 1000; 1397*00ce4311SHyong Youb Kim int err; 1398*00ce4311SHyong Youb Kim 1399*00ce4311SHyong Youb Kim a0 = vdev->sriov_stats_pa; 1400*00ce4311SHyong Youb Kim a1 = sizeof(struct vnic_sriov_stats); 1401*00ce4311SHyong Youb Kim err = vnic_dev_cmd(vdev, CMD_SRIOV_STATS_GET, &a0, &a1, wait); 1402*00ce4311SHyong Youb Kim if (!err) 1403*00ce4311SHyong Youb Kim *stats = vdev->sriov_stats; 1404*00ce4311SHyong Youb Kim return err; 1405*00ce4311SHyong Youb Kim } 1406