19c067b84SDoug Ambrisko /* SPDX-License-Identifier: BSD-3-Clause 29c067b84SDoug Ambrisko * Copyright 2008-2017 Cisco Systems, Inc. All rights reserved. 39c067b84SDoug Ambrisko * Copyright 2007 Nuova Systems, Inc. All rights reserved. 49c067b84SDoug Ambrisko */ 59c067b84SDoug Ambrisko 69c067b84SDoug Ambrisko #include "enic.h" 79c067b84SDoug Ambrisko #include "vnic_dev.h" 89c067b84SDoug Ambrisko #include "vnic_resource.h" 99c067b84SDoug Ambrisko #include "vnic_devcmd.h" 109c067b84SDoug Ambrisko #include "vnic_nic.h" 119c067b84SDoug Ambrisko #include "vnic_stats.h" 129c067b84SDoug Ambrisko 139c067b84SDoug Ambrisko #define VNIC_MAX_RES_HDR_SIZE \ 149c067b84SDoug Ambrisko (sizeof(struct vnic_resource_header) + \ 159c067b84SDoug Ambrisko sizeof(struct vnic_resource) * RES_TYPE_MAX) 169c067b84SDoug Ambrisko #define VNIC_RES_STRIDE 128 179c067b84SDoug Ambrisko 189c067b84SDoug Ambrisko #define VNIC_MAX_FLOW_COUNTERS 2048 199c067b84SDoug Ambrisko 209c067b84SDoug Ambrisko void *vnic_dev_priv(struct vnic_dev *vdev) 219c067b84SDoug Ambrisko { 229c067b84SDoug Ambrisko return vdev->priv; 239c067b84SDoug Ambrisko } 249c067b84SDoug Ambrisko 259c067b84SDoug Ambrisko void vnic_register_cbacks(struct vnic_dev *vdev, 269c067b84SDoug Ambrisko void *(*alloc_consistent)(void *priv, size_t size, 279c067b84SDoug Ambrisko bus_addr_t *dma_handle, struct iflib_dma_info *res,u8 *name), 289c067b84SDoug Ambrisko void (*free_consistent)(void *priv, 299c067b84SDoug Ambrisko size_t size, void *vaddr, 309c067b84SDoug Ambrisko bus_addr_t dma_handle,struct iflib_dma_info *res)) 319c067b84SDoug Ambrisko { 329c067b84SDoug Ambrisko vdev->alloc_consistent = alloc_consistent; 339c067b84SDoug Ambrisko vdev->free_consistent = free_consistent; 349c067b84SDoug Ambrisko } 359c067b84SDoug Ambrisko 369c067b84SDoug Ambrisko static int vnic_dev_discover_res(struct vnic_dev *vdev, 379c067b84SDoug Ambrisko struct vnic_dev_bar *bar, unsigned int num_bars) 389c067b84SDoug Ambrisko { 399c067b84SDoug Ambrisko struct enic_softc *softc = vdev->softc; 409c067b84SDoug Ambrisko struct vnic_resource_header __iomem *rh; 419c067b84SDoug Ambrisko struct mgmt_barmap_hdr __iomem *mrh; 429c067b84SDoug Ambrisko struct vnic_resource __iomem *r; 439c067b84SDoug Ambrisko int r_offset; 449c067b84SDoug Ambrisko u8 type; 459c067b84SDoug Ambrisko 469c067b84SDoug Ambrisko if (num_bars == 0) 47*0acab8b3SDoug Ambrisko return (EINVAL); 489c067b84SDoug Ambrisko 499c067b84SDoug Ambrisko rh = malloc(sizeof(*rh), M_DEVBUF, M_NOWAIT | M_ZERO); 509c067b84SDoug Ambrisko mrh = malloc(sizeof(*mrh), M_DEVBUF, M_NOWAIT | M_ZERO); 519c067b84SDoug Ambrisko if (!rh) { 529c067b84SDoug Ambrisko pr_err("vNIC BAR0 res hdr not mem-mapped\n"); 539c067b84SDoug Ambrisko free(rh, M_DEVBUF); 549c067b84SDoug Ambrisko free(mrh, M_DEVBUF); 55*0acab8b3SDoug Ambrisko return (EINVAL); 569c067b84SDoug Ambrisko } 579c067b84SDoug Ambrisko 589c067b84SDoug Ambrisko /* Check for mgmt vnic in addition to normal vnic */ 599c067b84SDoug Ambrisko ENIC_BUS_READ_REGION_4(softc, mem, 0, (void *)rh, sizeof(*rh) / 4); 609c067b84SDoug Ambrisko ENIC_BUS_READ_REGION_4(softc, mem, 0, (void *)mrh, sizeof(*mrh) / 4); 619c067b84SDoug Ambrisko if ((rh->magic != VNIC_RES_MAGIC) || 629c067b84SDoug Ambrisko (rh->version != VNIC_RES_VERSION)) { 639c067b84SDoug Ambrisko if ((mrh->magic != MGMTVNIC_MAGIC) || 649c067b84SDoug Ambrisko mrh->version != MGMTVNIC_VERSION) { 659c067b84SDoug Ambrisko pr_err("vNIC BAR0 res magic/version error " \ 669c067b84SDoug Ambrisko "exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n", 679c067b84SDoug Ambrisko VNIC_RES_MAGIC, VNIC_RES_VERSION, 689c067b84SDoug Ambrisko MGMTVNIC_MAGIC, MGMTVNIC_VERSION, 699c067b84SDoug Ambrisko rh->magic, rh->version); 709c067b84SDoug Ambrisko free(rh, M_DEVBUF); 719c067b84SDoug Ambrisko free(mrh, M_DEVBUF); 72*0acab8b3SDoug Ambrisko return (EINVAL); 739c067b84SDoug Ambrisko } 749c067b84SDoug Ambrisko } 759c067b84SDoug Ambrisko 769c067b84SDoug Ambrisko if (mrh->magic == MGMTVNIC_MAGIC) 779c067b84SDoug Ambrisko r_offset = sizeof(*mrh); 789c067b84SDoug Ambrisko else 799c067b84SDoug Ambrisko r_offset = sizeof(*rh); 809c067b84SDoug Ambrisko 819c067b84SDoug Ambrisko r = malloc(sizeof(*r), M_DEVBUF, M_NOWAIT | M_ZERO); 829c067b84SDoug Ambrisko ENIC_BUS_READ_REGION_4(softc, mem, r_offset, (void *)r, sizeof(*r) / 4); 839c067b84SDoug Ambrisko while ((type = r->type) != RES_TYPE_EOL) { 849c067b84SDoug Ambrisko u8 bar_num = r->bar; 859c067b84SDoug Ambrisko u32 bar_offset =r->bar_offset; 869c067b84SDoug Ambrisko u32 count = r->count; 879c067b84SDoug Ambrisko 889c067b84SDoug Ambrisko r_offset += sizeof(*r); 899c067b84SDoug Ambrisko 909c067b84SDoug Ambrisko if (bar_num >= num_bars) 919c067b84SDoug Ambrisko continue; 929c067b84SDoug Ambrisko 939c067b84SDoug Ambrisko switch (type) { 949c067b84SDoug Ambrisko case RES_TYPE_WQ: 959c067b84SDoug Ambrisko case RES_TYPE_RQ: 969c067b84SDoug Ambrisko case RES_TYPE_CQ: 979c067b84SDoug Ambrisko case RES_TYPE_INTR_CTRL: 989c067b84SDoug Ambrisko case RES_TYPE_INTR_PBA_LEGACY: 999c067b84SDoug Ambrisko case RES_TYPE_DEVCMD: 100*0acab8b3SDoug Ambrisko case RES_TYPE_DEVCMD2: 1019c067b84SDoug Ambrisko break; 1029c067b84SDoug Ambrisko default: 1039c067b84SDoug Ambrisko ENIC_BUS_READ_REGION_4(softc, mem, r_offset, (void *)r, sizeof(*r) / 4); 1049c067b84SDoug Ambrisko continue; 1059c067b84SDoug Ambrisko } 1069c067b84SDoug Ambrisko 1079c067b84SDoug Ambrisko vdev->res[type].count = count; 1089c067b84SDoug Ambrisko bcopy(&softc->mem, &vdev->res[type].bar, sizeof(softc->mem)); 1099c067b84SDoug Ambrisko vdev->res[type].bar.offset = bar_offset; 1109c067b84SDoug Ambrisko ENIC_BUS_READ_REGION_4(softc, mem, r_offset, (void *)r, sizeof(*r) / 4); 1119c067b84SDoug Ambrisko } 1129c067b84SDoug Ambrisko 1139c067b84SDoug Ambrisko free(rh, M_DEVBUF); 1149c067b84SDoug Ambrisko free(mrh, M_DEVBUF); 1159c067b84SDoug Ambrisko free(r, M_DEVBUF); 1169c067b84SDoug Ambrisko return 0; 1179c067b84SDoug Ambrisko } 1189c067b84SDoug Ambrisko 1199c067b84SDoug Ambrisko unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, 1209c067b84SDoug Ambrisko enum vnic_res_type type) 1219c067b84SDoug Ambrisko { 1229c067b84SDoug Ambrisko return vdev->res[type].count; 1239c067b84SDoug Ambrisko } 1249c067b84SDoug Ambrisko 1259c067b84SDoug Ambrisko void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, 1269c067b84SDoug Ambrisko unsigned int index) 1279c067b84SDoug Ambrisko { 1289c067b84SDoug Ambrisko struct vnic_res *res; 1299c067b84SDoug Ambrisko 1309c067b84SDoug Ambrisko if (!vdev->res[type].bar.tag) 1319c067b84SDoug Ambrisko return NULL; 1329c067b84SDoug Ambrisko 1339c067b84SDoug Ambrisko res = malloc(sizeof(*res), M_DEVBUF, M_NOWAIT | M_ZERO); 1349c067b84SDoug Ambrisko bcopy(&vdev->res[type], res, sizeof(*res)); 1359c067b84SDoug Ambrisko 1369c067b84SDoug Ambrisko switch (type) { 1379c067b84SDoug Ambrisko case RES_TYPE_WQ: 1389c067b84SDoug Ambrisko case RES_TYPE_RQ: 1399c067b84SDoug Ambrisko case RES_TYPE_CQ: 1409c067b84SDoug Ambrisko case RES_TYPE_INTR_CTRL: 1419c067b84SDoug Ambrisko res->bar.offset += 1429c067b84SDoug Ambrisko index * VNIC_RES_STRIDE; 1439c067b84SDoug Ambrisko default: 1449c067b84SDoug Ambrisko res->bar.offset += 0; 1459c067b84SDoug Ambrisko } 1469c067b84SDoug Ambrisko 1479c067b84SDoug Ambrisko return res; 1489c067b84SDoug Ambrisko } 1499c067b84SDoug Ambrisko 1509c067b84SDoug Ambrisko unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, 1519c067b84SDoug Ambrisko unsigned int desc_count, unsigned int desc_size) 1529c067b84SDoug Ambrisko { 1539c067b84SDoug Ambrisko /* The base address of the desc rings must be 512 byte aligned. 1549c067b84SDoug Ambrisko * Descriptor count is aligned to groups of 32 descriptors. A 1559c067b84SDoug Ambrisko * count of 0 means the maximum 4096 descriptors. Descriptor 1569c067b84SDoug Ambrisko * size is aligned to 16 bytes. 1579c067b84SDoug Ambrisko */ 1589c067b84SDoug Ambrisko 1599c067b84SDoug Ambrisko unsigned int count_align = 32; 1609c067b84SDoug Ambrisko unsigned int desc_align = 16; 1619c067b84SDoug Ambrisko 1629c067b84SDoug Ambrisko ring->base_align = 512; 1639c067b84SDoug Ambrisko 1649c067b84SDoug Ambrisko if (desc_count == 0) 1659c067b84SDoug Ambrisko desc_count = 4096; 1669c067b84SDoug Ambrisko 1679c067b84SDoug Ambrisko ring->desc_count = VNIC_ALIGN(desc_count, count_align); 1689c067b84SDoug Ambrisko 1699c067b84SDoug Ambrisko ring->desc_size = VNIC_ALIGN(desc_size, desc_align); 1709c067b84SDoug Ambrisko 1719c067b84SDoug Ambrisko ring->size = ring->desc_count * ring->desc_size; 1729c067b84SDoug Ambrisko ring->size_unaligned = ring->size + ring->base_align; 1739c067b84SDoug Ambrisko 1749c067b84SDoug Ambrisko return ring->size_unaligned; 1759c067b84SDoug Ambrisko } 1769c067b84SDoug Ambrisko 1779c067b84SDoug Ambrisko void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring) 1789c067b84SDoug Ambrisko { 1799c067b84SDoug Ambrisko memset(ring->descs, 0, ring->size); 1809c067b84SDoug Ambrisko } 1819c067b84SDoug Ambrisko 1829c067b84SDoug Ambrisko static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 1839c067b84SDoug Ambrisko int wait) 1849c067b84SDoug Ambrisko { 1859c067b84SDoug Ambrisko struct vnic_res __iomem *devcmd = vdev->devcmd; 1869c067b84SDoug Ambrisko int delay; 1879c067b84SDoug Ambrisko u32 status; 1889c067b84SDoug Ambrisko int err; 1899c067b84SDoug Ambrisko 1909c067b84SDoug Ambrisko status = ENIC_BUS_READ_4(devcmd, DEVCMD_STATUS); 1919c067b84SDoug Ambrisko if (status == 0xFFFFFFFF) { 1929c067b84SDoug Ambrisko /* PCI-e target device is gone */ 193*0acab8b3SDoug Ambrisko return (ENODEV); 1949c067b84SDoug Ambrisko } 1959c067b84SDoug Ambrisko if (status & STAT_BUSY) { 1969c067b84SDoug Ambrisko 1979c067b84SDoug Ambrisko pr_err("Busy devcmd %d\n", _CMD_N(cmd)); 198*0acab8b3SDoug Ambrisko return (EBUSY); 1999c067b84SDoug Ambrisko } 2009c067b84SDoug Ambrisko 2019c067b84SDoug Ambrisko if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) { 2029c067b84SDoug Ambrisko ENIC_BUS_WRITE_REGION_4(devcmd, DEVCMD_ARGS(0), (void *)&vdev->args[0], VNIC_DEVCMD_NARGS * 2); 2039c067b84SDoug Ambrisko } 2049c067b84SDoug Ambrisko 2059c067b84SDoug Ambrisko ENIC_BUS_WRITE_4(devcmd, DEVCMD_CMD, cmd); 2069c067b84SDoug Ambrisko 2079c067b84SDoug Ambrisko if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) { 2089c067b84SDoug Ambrisko return 0; 2099c067b84SDoug Ambrisko } 2109c067b84SDoug Ambrisko 2119c067b84SDoug Ambrisko for (delay = 0; delay < wait; delay++) { 2129c067b84SDoug Ambrisko 2139c067b84SDoug Ambrisko udelay(100); 2149c067b84SDoug Ambrisko 2159c067b84SDoug Ambrisko status = ENIC_BUS_READ_4(devcmd, DEVCMD_STATUS); 2169c067b84SDoug Ambrisko if (status == 0xFFFFFFFF) { 2179c067b84SDoug Ambrisko /* PCI-e target device is gone */ 218*0acab8b3SDoug Ambrisko return (ENODEV); 2199c067b84SDoug Ambrisko } 2209c067b84SDoug Ambrisko 2219c067b84SDoug Ambrisko if (!(status & STAT_BUSY)) { 2229c067b84SDoug Ambrisko if (status & STAT_ERROR) { 2239c067b84SDoug Ambrisko err = -(int)ENIC_BUS_READ_8(devcmd, DEVCMD_ARGS(0)); 2249c067b84SDoug Ambrisko 2259c067b84SDoug Ambrisko if (cmd != CMD_CAPABILITY) 2269c067b84SDoug Ambrisko pr_err("Devcmd %d failed " \ 2279c067b84SDoug Ambrisko "with error code %d\n", 2289c067b84SDoug Ambrisko _CMD_N(cmd), err); 229*0acab8b3SDoug Ambrisko return (err); 2309c067b84SDoug Ambrisko } 2319c067b84SDoug Ambrisko 2329c067b84SDoug Ambrisko if (_CMD_DIR(cmd) & _CMD_DIR_READ) { 2339c067b84SDoug Ambrisko ENIC_BUS_READ_REGION_4(devcmd, bar, DEVCMD_ARGS(0), (void *)&vdev->args[0], VNIC_DEVCMD_NARGS * 2); 2349c067b84SDoug Ambrisko } 2359c067b84SDoug Ambrisko 2369c067b84SDoug Ambrisko return 0; 2379c067b84SDoug Ambrisko } 2389c067b84SDoug Ambrisko } 2399c067b84SDoug Ambrisko 2409c067b84SDoug Ambrisko pr_err("Timedout devcmd %d\n", _CMD_N(cmd)); 241*0acab8b3SDoug Ambrisko return (ETIMEDOUT); 242*0acab8b3SDoug Ambrisko } 243*0acab8b3SDoug Ambrisko 244*0acab8b3SDoug Ambrisko static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 245*0acab8b3SDoug Ambrisko int wait) 246*0acab8b3SDoug Ambrisko { 247*0acab8b3SDoug Ambrisko struct devcmd2_controller *dc2c = vdev->devcmd2; 248*0acab8b3SDoug Ambrisko struct devcmd2_result *result; 249*0acab8b3SDoug Ambrisko u8 color; 250*0acab8b3SDoug Ambrisko unsigned int i; 251*0acab8b3SDoug Ambrisko u32 fetch_index, new_posted; 252*0acab8b3SDoug Ambrisko int delay, err; 253*0acab8b3SDoug Ambrisko u32 posted = dc2c->posted; 254*0acab8b3SDoug Ambrisko 255*0acab8b3SDoug Ambrisko fetch_index = ENIC_BUS_READ_4(dc2c->wq_ctrl, TX_FETCH_INDEX); 256*0acab8b3SDoug Ambrisko if (fetch_index == 0xFFFFFFFF) 257*0acab8b3SDoug Ambrisko return (ENODEV); 258*0acab8b3SDoug Ambrisko 259*0acab8b3SDoug Ambrisko new_posted = (posted + 1) % DEVCMD2_RING_SIZE; 260*0acab8b3SDoug Ambrisko 261*0acab8b3SDoug Ambrisko if (new_posted == fetch_index) { 262*0acab8b3SDoug Ambrisko device_printf(dev_from_vnic_dev(vdev), 263*0acab8b3SDoug Ambrisko "devcmd2 %d: wq is full. fetch index: %u, posted index: %u\n", 264*0acab8b3SDoug Ambrisko _CMD_N(cmd), fetch_index, posted); 265*0acab8b3SDoug Ambrisko return (EBUSY); 266*0acab8b3SDoug Ambrisko } 267*0acab8b3SDoug Ambrisko 268*0acab8b3SDoug Ambrisko dc2c->cmd_ring[posted].cmd = cmd; 269*0acab8b3SDoug Ambrisko dc2c->cmd_ring[posted].flags = 0; 270*0acab8b3SDoug Ambrisko 271*0acab8b3SDoug Ambrisko if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) 272*0acab8b3SDoug Ambrisko dc2c->cmd_ring[posted].flags |= DEVCMD2_FNORESULT; 273*0acab8b3SDoug Ambrisko if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) 274*0acab8b3SDoug Ambrisko for (i = 0; i < VNIC_DEVCMD_NARGS; i++) 275*0acab8b3SDoug Ambrisko dc2c->cmd_ring[posted].args[i] = vdev->args[i]; 276*0acab8b3SDoug Ambrisko 277*0acab8b3SDoug Ambrisko ENIC_BUS_WRITE_4(dc2c->wq_ctrl, TX_POSTED_INDEX, new_posted); 278*0acab8b3SDoug Ambrisko dc2c->posted = new_posted; 279*0acab8b3SDoug Ambrisko 280*0acab8b3SDoug Ambrisko if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT) 281*0acab8b3SDoug Ambrisko return (0); 282*0acab8b3SDoug Ambrisko 283*0acab8b3SDoug Ambrisko result = dc2c->result + dc2c->next_result; 284*0acab8b3SDoug Ambrisko color = dc2c->color; 285*0acab8b3SDoug Ambrisko 286*0acab8b3SDoug Ambrisko dc2c->next_result++; 287*0acab8b3SDoug Ambrisko if (dc2c->next_result == dc2c->result_size) { 288*0acab8b3SDoug Ambrisko dc2c->next_result = 0; 289*0acab8b3SDoug Ambrisko dc2c->color = dc2c->color ? 0 : 1; 290*0acab8b3SDoug Ambrisko } 291*0acab8b3SDoug Ambrisko 292*0acab8b3SDoug Ambrisko for (delay = 0; delay < wait; delay++) { 293*0acab8b3SDoug Ambrisko if (result->color == color) { 294*0acab8b3SDoug Ambrisko if (result->error) { 295*0acab8b3SDoug Ambrisko err = result->error; 296*0acab8b3SDoug Ambrisko if (err != ERR_ECMDUNKNOWN || 297*0acab8b3SDoug Ambrisko cmd != CMD_CAPABILITY) 298*0acab8b3SDoug Ambrisko device_printf(dev_from_vnic_dev(vdev), 299*0acab8b3SDoug Ambrisko "Error %d devcmd %d\n", err, 300*0acab8b3SDoug Ambrisko _CMD_N(cmd)); 301*0acab8b3SDoug Ambrisko return (err); 302*0acab8b3SDoug Ambrisko } 303*0acab8b3SDoug Ambrisko if (_CMD_DIR(cmd) & _CMD_DIR_READ) 304*0acab8b3SDoug Ambrisko for (i = 0; i < VNIC_DEVCMD2_NARGS; i++) 305*0acab8b3SDoug Ambrisko vdev->args[i] = result->results[i]; 306*0acab8b3SDoug Ambrisko 307*0acab8b3SDoug Ambrisko return 0; 308*0acab8b3SDoug Ambrisko } 309*0acab8b3SDoug Ambrisko udelay(100); 310*0acab8b3SDoug Ambrisko } 311*0acab8b3SDoug Ambrisko 312*0acab8b3SDoug Ambrisko device_printf(dev_from_vnic_dev(vdev), 313*0acab8b3SDoug Ambrisko "devcmd %d timed out\n", _CMD_N(cmd)); 314*0acab8b3SDoug Ambrisko 315*0acab8b3SDoug Ambrisko 316*0acab8b3SDoug Ambrisko return (ETIMEDOUT); 3179c067b84SDoug Ambrisko } 3189c067b84SDoug Ambrisko 3199c067b84SDoug Ambrisko static int vnic_dev_cmd_proxy(struct vnic_dev *vdev, 3209c067b84SDoug Ambrisko enum vnic_devcmd_cmd proxy_cmd, enum vnic_devcmd_cmd cmd, 3219c067b84SDoug Ambrisko u64 *args, int nargs, int wait) 3229c067b84SDoug Ambrisko { 3239c067b84SDoug Ambrisko u32 status; 3249c067b84SDoug Ambrisko int err; 3259c067b84SDoug Ambrisko 3269c067b84SDoug Ambrisko /* 3279c067b84SDoug Ambrisko * Proxy command consumes 2 arguments. One for proxy index, 3289c067b84SDoug Ambrisko * the other is for command to be proxied 3299c067b84SDoug Ambrisko */ 3309c067b84SDoug Ambrisko if (nargs > VNIC_DEVCMD_NARGS - 2) { 3319c067b84SDoug Ambrisko pr_err("number of args %d exceeds the maximum\n", nargs); 332*0acab8b3SDoug Ambrisko return (EINVAL); 3339c067b84SDoug Ambrisko } 3349c067b84SDoug Ambrisko memset(vdev->args, 0, sizeof(vdev->args)); 3359c067b84SDoug Ambrisko 3369c067b84SDoug Ambrisko vdev->args[0] = vdev->proxy_index; 3379c067b84SDoug Ambrisko vdev->args[1] = cmd; 3389c067b84SDoug Ambrisko memcpy(&vdev->args[2], args, nargs * sizeof(args[0])); 3399c067b84SDoug Ambrisko 340*0acab8b3SDoug Ambrisko err = vdev->devcmd_rtn(vdev, proxy_cmd, wait); 3419c067b84SDoug Ambrisko if (err) 342*0acab8b3SDoug Ambrisko return (err); 3439c067b84SDoug Ambrisko 3449c067b84SDoug Ambrisko status = (u32)vdev->args[0]; 3459c067b84SDoug Ambrisko if (status & STAT_ERROR) { 3469c067b84SDoug Ambrisko err = (int)vdev->args[1]; 3479c067b84SDoug Ambrisko if (err != ERR_ECMDUNKNOWN || 3489c067b84SDoug Ambrisko cmd != CMD_CAPABILITY) 3499c067b84SDoug Ambrisko pr_err("Error %d proxy devcmd %d\n", err, _CMD_N(cmd)); 350*0acab8b3SDoug Ambrisko return (err); 3519c067b84SDoug Ambrisko } 3529c067b84SDoug Ambrisko 3539c067b84SDoug Ambrisko memcpy(args, &vdev->args[1], nargs * sizeof(args[0])); 3549c067b84SDoug Ambrisko 3559c067b84SDoug Ambrisko return 0; 3569c067b84SDoug Ambrisko } 3579c067b84SDoug Ambrisko 3589c067b84SDoug Ambrisko static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev, 3599c067b84SDoug Ambrisko enum vnic_devcmd_cmd cmd, u64 *args, int nargs, int wait) 3609c067b84SDoug Ambrisko { 3619c067b84SDoug Ambrisko int err; 3629c067b84SDoug Ambrisko 3639c067b84SDoug Ambrisko if (nargs > VNIC_DEVCMD_NARGS) { 3649c067b84SDoug Ambrisko pr_err("number of args %d exceeds the maximum\n", nargs); 365*0acab8b3SDoug Ambrisko return (EINVAL); 3669c067b84SDoug Ambrisko } 3679c067b84SDoug Ambrisko memset(vdev->args, 0, sizeof(vdev->args)); 3689c067b84SDoug Ambrisko memcpy(vdev->args, args, nargs * sizeof(args[0])); 3699c067b84SDoug Ambrisko 370*0acab8b3SDoug Ambrisko err = vdev->devcmd_rtn(vdev, cmd, wait); 3719c067b84SDoug Ambrisko 3729c067b84SDoug Ambrisko memcpy(args, vdev->args, nargs * sizeof(args[0])); 3739c067b84SDoug Ambrisko 374*0acab8b3SDoug Ambrisko return (err); 3759c067b84SDoug Ambrisko } 3769c067b84SDoug Ambrisko 3779c067b84SDoug Ambrisko int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 3789c067b84SDoug Ambrisko u64 *a0, u64 *a1, int wait) 3799c067b84SDoug Ambrisko { 3809c067b84SDoug Ambrisko u64 args[2]; 3819c067b84SDoug Ambrisko int err; 3829c067b84SDoug Ambrisko 3839c067b84SDoug Ambrisko args[0] = *a0; 3849c067b84SDoug Ambrisko args[1] = *a1; 3859c067b84SDoug Ambrisko memset(vdev->args, 0, sizeof(vdev->args)); 3869c067b84SDoug Ambrisko 3879c067b84SDoug Ambrisko switch (vdev->proxy) { 3889c067b84SDoug Ambrisko case PROXY_BY_INDEX: 3899c067b84SDoug Ambrisko err = vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_INDEX, cmd, 3909c067b84SDoug Ambrisko args, ARRAY_SIZE(args), wait); 3919c067b84SDoug Ambrisko break; 3929c067b84SDoug Ambrisko case PROXY_BY_BDF: 3939c067b84SDoug Ambrisko err = vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_BDF, cmd, 3949c067b84SDoug Ambrisko args, ARRAY_SIZE(args), wait); 3959c067b84SDoug Ambrisko break; 3969c067b84SDoug Ambrisko case PROXY_NONE: 3979c067b84SDoug Ambrisko default: 3989c067b84SDoug Ambrisko err = vnic_dev_cmd_no_proxy(vdev, cmd, args, 2, wait); 3999c067b84SDoug Ambrisko break; 4009c067b84SDoug Ambrisko } 4019c067b84SDoug Ambrisko 4029c067b84SDoug Ambrisko if (err == 0) { 4039c067b84SDoug Ambrisko *a0 = args[0]; 4049c067b84SDoug Ambrisko *a1 = args[1]; 4059c067b84SDoug Ambrisko } 4069c067b84SDoug Ambrisko 407*0acab8b3SDoug Ambrisko return (err); 4089c067b84SDoug Ambrisko } 4099c067b84SDoug Ambrisko 4109c067b84SDoug Ambrisko int vnic_dev_cmd_args(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, 4119c067b84SDoug Ambrisko u64 *args, int nargs, int wait) 4129c067b84SDoug Ambrisko { 4139c067b84SDoug Ambrisko switch (vdev->proxy) { 4149c067b84SDoug Ambrisko case PROXY_BY_INDEX: 4159c067b84SDoug Ambrisko return vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_INDEX, cmd, 4169c067b84SDoug Ambrisko args, nargs, wait); 4179c067b84SDoug Ambrisko case PROXY_BY_BDF: 4189c067b84SDoug Ambrisko return vnic_dev_cmd_proxy(vdev, CMD_PROXY_BY_BDF, cmd, 4199c067b84SDoug Ambrisko args, nargs, wait); 4209c067b84SDoug Ambrisko case PROXY_NONE: 4219c067b84SDoug Ambrisko default: 4229c067b84SDoug Ambrisko return vnic_dev_cmd_no_proxy(vdev, cmd, args, nargs, wait); 4239c067b84SDoug Ambrisko } 4249c067b84SDoug Ambrisko } 4259c067b84SDoug Ambrisko 4269c067b84SDoug Ambrisko static int vnic_dev_advanced_filters_cap(struct vnic_dev *vdev, u64 *args, 4279c067b84SDoug Ambrisko int nargs) 4289c067b84SDoug Ambrisko { 4299c067b84SDoug Ambrisko memset(args, 0, nargs * sizeof(*args)); 4309c067b84SDoug Ambrisko args[0] = CMD_ADD_ADV_FILTER; 4319c067b84SDoug Ambrisko args[1] = FILTER_CAP_MODE_V1_FLAG; 4329c067b84SDoug Ambrisko return vnic_dev_cmd_args(vdev, CMD_CAPABILITY, args, nargs, 1000); 4339c067b84SDoug Ambrisko } 4349c067b84SDoug Ambrisko 4359c067b84SDoug Ambrisko int vnic_dev_capable_adv_filters(struct vnic_dev *vdev) 4369c067b84SDoug Ambrisko { 4379c067b84SDoug Ambrisko u64 a0 = CMD_ADD_ADV_FILTER, a1 = 0; 4389c067b84SDoug Ambrisko int wait = 1000; 4399c067b84SDoug Ambrisko int err; 4409c067b84SDoug Ambrisko 4419c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); 4429c067b84SDoug Ambrisko if (err) 4439c067b84SDoug Ambrisko return 0; 4449c067b84SDoug Ambrisko return (a1 >= (u32)FILTER_DPDK_1); 4459c067b84SDoug Ambrisko } 4469c067b84SDoug Ambrisko 4479c067b84SDoug Ambrisko /* Determine the "best" filtering mode VIC is capaible of. Returns one of 3 4489c067b84SDoug Ambrisko * value or 0 on error: 4499c067b84SDoug Ambrisko * FILTER_DPDK_1- advanced filters availabile 4509c067b84SDoug Ambrisko * FILTER_USNIC_IP_FLAG - advanced filters but with the restriction that 4519c067b84SDoug Ambrisko * the IP layer must explicitly specified. I.e. cannot have a UDP 4529c067b84SDoug Ambrisko * filter that matches both IPv4 and IPv6. 4539c067b84SDoug Ambrisko * FILTER_IPV4_5TUPLE - fallback if either of the 2 above aren't available. 4549c067b84SDoug Ambrisko * all other filter types are not available. 4559c067b84SDoug Ambrisko * Retrun true in filter_tags if supported 4569c067b84SDoug Ambrisko */ 4579c067b84SDoug Ambrisko int vnic_dev_capable_filter_mode(struct vnic_dev *vdev, u32 *mode, 4589c067b84SDoug Ambrisko u8 *filter_actions) 4599c067b84SDoug Ambrisko { 4609c067b84SDoug Ambrisko u64 args[4]; 4619c067b84SDoug Ambrisko int err; 4629c067b84SDoug Ambrisko u32 max_level = 0; 4639c067b84SDoug Ambrisko 4649c067b84SDoug Ambrisko err = vnic_dev_advanced_filters_cap(vdev, args, 4); 4659c067b84SDoug Ambrisko 4669c067b84SDoug Ambrisko /* determine supported filter actions */ 4679c067b84SDoug Ambrisko *filter_actions = FILTER_ACTION_RQ_STEERING_FLAG; /* always available */ 4689c067b84SDoug Ambrisko if (args[2] == FILTER_CAP_MODE_V1) 4699c067b84SDoug Ambrisko *filter_actions = args[3]; 4709c067b84SDoug Ambrisko 4719c067b84SDoug Ambrisko if (err || ((args[0] == 1) && (args[1] == 0))) { 4729c067b84SDoug Ambrisko /* Adv filter Command not supported or adv filters available but 4739c067b84SDoug Ambrisko * not enabled. Try the normal filter capability command. 4749c067b84SDoug Ambrisko */ 4759c067b84SDoug Ambrisko args[0] = CMD_ADD_FILTER; 4769c067b84SDoug Ambrisko args[1] = 0; 4779c067b84SDoug Ambrisko err = vnic_dev_cmd_args(vdev, CMD_CAPABILITY, args, 2, 1000); 4789c067b84SDoug Ambrisko if (err) 479*0acab8b3SDoug Ambrisko return (err); 4809c067b84SDoug Ambrisko max_level = args[1]; 4819c067b84SDoug Ambrisko goto parse_max_level; 4829c067b84SDoug Ambrisko } else if (args[2] == FILTER_CAP_MODE_V1) { 4839c067b84SDoug Ambrisko /* parse filter capability mask in args[1] */ 4849c067b84SDoug Ambrisko if (args[1] & FILTER_DPDK_1_FLAG) 4859c067b84SDoug Ambrisko *mode = FILTER_DPDK_1; 4869c067b84SDoug Ambrisko else if (args[1] & FILTER_USNIC_IP_FLAG) 4879c067b84SDoug Ambrisko *mode = FILTER_USNIC_IP; 4889c067b84SDoug Ambrisko else if (args[1] & FILTER_IPV4_5TUPLE_FLAG) 4899c067b84SDoug Ambrisko *mode = FILTER_IPV4_5TUPLE; 4909c067b84SDoug Ambrisko return 0; 4919c067b84SDoug Ambrisko } 4929c067b84SDoug Ambrisko max_level = args[1]; 4939c067b84SDoug Ambrisko parse_max_level: 4949c067b84SDoug Ambrisko if (max_level >= (u32)FILTER_USNIC_IP) 4959c067b84SDoug Ambrisko *mode = FILTER_USNIC_IP; 4969c067b84SDoug Ambrisko else 4979c067b84SDoug Ambrisko *mode = FILTER_IPV4_5TUPLE; 4989c067b84SDoug Ambrisko return 0; 4999c067b84SDoug Ambrisko } 5009c067b84SDoug Ambrisko 5019c067b84SDoug Ambrisko void vnic_dev_capable_udp_rss_weak(struct vnic_dev *vdev, bool *cfg_chk, 5029c067b84SDoug Ambrisko bool *weak) 5039c067b84SDoug Ambrisko { 5049c067b84SDoug Ambrisko u64 a0 = CMD_NIC_CFG, a1 = 0; 5059c067b84SDoug Ambrisko int wait = 1000; 5069c067b84SDoug Ambrisko int err; 5079c067b84SDoug Ambrisko 5089c067b84SDoug Ambrisko *cfg_chk = false; 5099c067b84SDoug Ambrisko *weak = false; 5109c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); 5119c067b84SDoug Ambrisko if (err == 0 && a0 != 0 && a1 != 0) { 5129c067b84SDoug Ambrisko *cfg_chk = true; 5139c067b84SDoug Ambrisko *weak = !!((a1 >> 32) & CMD_NIC_CFG_CAPF_UDP_WEAK); 5149c067b84SDoug Ambrisko } 5159c067b84SDoug Ambrisko } 5169c067b84SDoug Ambrisko 5179c067b84SDoug Ambrisko int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd) 5189c067b84SDoug Ambrisko { 5199c067b84SDoug Ambrisko u64 a0 = (u32)cmd, a1 = 0; 5209c067b84SDoug Ambrisko int wait = 1000; 5219c067b84SDoug Ambrisko int err; 5229c067b84SDoug Ambrisko 5239c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); 5249c067b84SDoug Ambrisko 5259c067b84SDoug Ambrisko return !(err || a0); 5269c067b84SDoug Ambrisko } 5279c067b84SDoug Ambrisko 5289c067b84SDoug Ambrisko int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, size_t size, 5299c067b84SDoug Ambrisko void *value) 5309c067b84SDoug Ambrisko { 5319c067b84SDoug Ambrisko u64 a0, a1; 5329c067b84SDoug Ambrisko int wait = 1000; 5339c067b84SDoug Ambrisko int err; 5349c067b84SDoug Ambrisko 5359c067b84SDoug Ambrisko a0 = offset; 5369c067b84SDoug Ambrisko a1 = size; 5379c067b84SDoug Ambrisko 5389c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_DEV_SPEC, &a0, &a1, wait); 5399c067b84SDoug Ambrisko 5409c067b84SDoug Ambrisko switch (size) { 5419c067b84SDoug Ambrisko case 1: 5429c067b84SDoug Ambrisko *(u8 *)value = (u8)a0; 5439c067b84SDoug Ambrisko break; 5449c067b84SDoug Ambrisko case 2: 5459c067b84SDoug Ambrisko *(u16 *)value = (u16)a0; 5469c067b84SDoug Ambrisko break; 5479c067b84SDoug Ambrisko case 4: 5489c067b84SDoug Ambrisko *(u32 *)value = (u32)a0; 5499c067b84SDoug Ambrisko break; 5509c067b84SDoug Ambrisko case 8: 5519c067b84SDoug Ambrisko *(u64 *)value = a0; 5529c067b84SDoug Ambrisko break; 5539c067b84SDoug Ambrisko default: 5549c067b84SDoug Ambrisko BUG(); 5559c067b84SDoug Ambrisko break; 5569c067b84SDoug Ambrisko } 5579c067b84SDoug Ambrisko 558*0acab8b3SDoug Ambrisko return (err); 5599c067b84SDoug Ambrisko } 5609c067b84SDoug Ambrisko 5619c067b84SDoug Ambrisko int vnic_dev_stats_clear(struct vnic_dev *vdev) 5629c067b84SDoug Ambrisko { 5639c067b84SDoug Ambrisko u64 a0 = 0, a1 = 0; 5649c067b84SDoug Ambrisko int wait = 1000; 5659c067b84SDoug Ambrisko 5669c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait); 5679c067b84SDoug Ambrisko } 5689c067b84SDoug Ambrisko 5699c067b84SDoug Ambrisko int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) 5709c067b84SDoug Ambrisko { 5719c067b84SDoug Ambrisko u64 a0, a1; 5729c067b84SDoug Ambrisko int wait = 1000; 5739c067b84SDoug Ambrisko int rc; 5749c067b84SDoug Ambrisko 5759c067b84SDoug Ambrisko if (!vdev->stats) 576*0acab8b3SDoug Ambrisko return (ENOMEM); 5779c067b84SDoug Ambrisko 5789c067b84SDoug Ambrisko *stats = vdev->stats; 5799c067b84SDoug Ambrisko a0 = vdev->stats_res.idi_paddr; 5809c067b84SDoug Ambrisko a1 = sizeof(struct vnic_stats); 5819c067b84SDoug Ambrisko 5829c067b84SDoug Ambrisko bus_dmamap_sync(vdev->stats_res.idi_tag, 5839c067b84SDoug Ambrisko vdev->stats_res.idi_map, 5849c067b84SDoug Ambrisko BUS_DMASYNC_POSTREAD); 5859c067b84SDoug Ambrisko rc = vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait); 5869c067b84SDoug Ambrisko bus_dmamap_sync(vdev->stats_res.idi_tag, 5879c067b84SDoug Ambrisko vdev->stats_res.idi_map, 5889c067b84SDoug Ambrisko BUS_DMASYNC_PREREAD); 5899c067b84SDoug Ambrisko return (rc); 5909c067b84SDoug Ambrisko } 5919c067b84SDoug Ambrisko 5929c067b84SDoug Ambrisko /* 5939c067b84SDoug Ambrisko * Configure counter DMA 5949c067b84SDoug Ambrisko */ 5959c067b84SDoug Ambrisko int vnic_dev_counter_dma_cfg(struct vnic_dev *vdev, u32 period, 5969c067b84SDoug Ambrisko u32 num_counters) 5979c067b84SDoug Ambrisko { 5989c067b84SDoug Ambrisko u64 args[3]; 5999c067b84SDoug Ambrisko int wait = 1000; 6009c067b84SDoug Ambrisko int err; 6019c067b84SDoug Ambrisko 6029c067b84SDoug Ambrisko if (num_counters > VNIC_MAX_FLOW_COUNTERS) 603*0acab8b3SDoug Ambrisko return (ENOMEM); 6049c067b84SDoug Ambrisko if (period > 0 && (period < VNIC_COUNTER_DMA_MIN_PERIOD || 6059c067b84SDoug Ambrisko num_counters == 0)) 606*0acab8b3SDoug Ambrisko return (EINVAL); 6079c067b84SDoug Ambrisko 6089c067b84SDoug Ambrisko args[0] = num_counters; 6099c067b84SDoug Ambrisko args[1] = vdev->flow_counters_res.idi_paddr; 6109c067b84SDoug Ambrisko args[2] = period; 6119c067b84SDoug Ambrisko bus_dmamap_sync(vdev->flow_counters_res.idi_tag, 6129c067b84SDoug Ambrisko vdev->flow_counters_res.idi_map, 6139c067b84SDoug Ambrisko BUS_DMASYNC_POSTREAD); 6149c067b84SDoug Ambrisko err = vnic_dev_cmd_args(vdev, CMD_COUNTER_DMA_CONFIG, args, 3, wait); 6159c067b84SDoug Ambrisko bus_dmamap_sync(vdev->flow_counters_res.idi_tag, 6169c067b84SDoug Ambrisko vdev->flow_counters_res.idi_map, 6179c067b84SDoug Ambrisko BUS_DMASYNC_PREREAD); 6189c067b84SDoug Ambrisko 6199c067b84SDoug Ambrisko /* record if DMAs need to be stopped on close */ 6209c067b84SDoug Ambrisko if (!err) 6219c067b84SDoug Ambrisko vdev->flow_counters_dma_active = (num_counters != 0 && 6229c067b84SDoug Ambrisko period != 0); 6239c067b84SDoug Ambrisko 624*0acab8b3SDoug Ambrisko return (err); 6259c067b84SDoug Ambrisko } 6269c067b84SDoug Ambrisko 6279c067b84SDoug Ambrisko int vnic_dev_close(struct vnic_dev *vdev) 6289c067b84SDoug Ambrisko { 6299c067b84SDoug Ambrisko u64 a0 = 0, a1 = 0; 6309c067b84SDoug Ambrisko int wait = 1000; 6319c067b84SDoug Ambrisko 6329c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait); 6339c067b84SDoug Ambrisko } 6349c067b84SDoug Ambrisko 6359c067b84SDoug Ambrisko int vnic_dev_enable_wait(struct vnic_dev *vdev) 6369c067b84SDoug Ambrisko { 6379c067b84SDoug Ambrisko u64 a0 = 0, a1 = 0; 6389c067b84SDoug Ambrisko int wait = 1000; 6399c067b84SDoug Ambrisko 6409c067b84SDoug Ambrisko if (vnic_dev_capable(vdev, CMD_ENABLE_WAIT)) 6419c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_ENABLE_WAIT, &a0, &a1, wait); 6429c067b84SDoug Ambrisko else 6439c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait); 6449c067b84SDoug Ambrisko } 6459c067b84SDoug Ambrisko 6469c067b84SDoug Ambrisko int vnic_dev_disable(struct vnic_dev *vdev) 6479c067b84SDoug Ambrisko { 6489c067b84SDoug Ambrisko u64 a0 = 0, a1 = 0; 6499c067b84SDoug Ambrisko int wait = 1000; 6509c067b84SDoug Ambrisko 6519c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_DISABLE, &a0, &a1, wait); 6529c067b84SDoug Ambrisko } 6539c067b84SDoug Ambrisko 6549c067b84SDoug Ambrisko int vnic_dev_open(struct vnic_dev *vdev, int arg) 6559c067b84SDoug Ambrisko { 6569c067b84SDoug Ambrisko u64 a0 = (u32)arg, a1 = 0; 6579c067b84SDoug Ambrisko int wait = 1000; 6589c067b84SDoug Ambrisko 6599c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_OPEN, &a0, &a1, wait); 6609c067b84SDoug Ambrisko } 6619c067b84SDoug Ambrisko 6629c067b84SDoug Ambrisko int vnic_dev_open_done(struct vnic_dev *vdev, int *done) 6639c067b84SDoug Ambrisko { 6649c067b84SDoug Ambrisko u64 a0 = 0, a1 = 0; 6659c067b84SDoug Ambrisko int wait = 1000; 6669c067b84SDoug Ambrisko int err; 6679c067b84SDoug Ambrisko 6689c067b84SDoug Ambrisko *done = 0; 6699c067b84SDoug Ambrisko 6709c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait); 6719c067b84SDoug Ambrisko if (err) 672*0acab8b3SDoug Ambrisko return (err); 6739c067b84SDoug Ambrisko 6749c067b84SDoug Ambrisko *done = (a0 == 0); 6759c067b84SDoug Ambrisko 6769c067b84SDoug Ambrisko return 0; 6779c067b84SDoug Ambrisko } 6789c067b84SDoug Ambrisko 6799c067b84SDoug Ambrisko int vnic_dev_get_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) 6809c067b84SDoug Ambrisko { 6819c067b84SDoug Ambrisko u64 a0 = 0, a1 = 0; 6829c067b84SDoug Ambrisko int wait = 1000; 6839c067b84SDoug Ambrisko int err, i; 6849c067b84SDoug Ambrisko 6859c067b84SDoug Ambrisko for (i = 0; i < ETH_ALEN; i++) 6869c067b84SDoug Ambrisko mac_addr[i] = 0; 6879c067b84SDoug Ambrisko 6889c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_GET_MAC_ADDR, &a0, &a1, wait); 6899c067b84SDoug Ambrisko if (err) 690*0acab8b3SDoug Ambrisko return (err); 6919c067b84SDoug Ambrisko 6929c067b84SDoug Ambrisko for (i = 0; i < ETH_ALEN; i++) 6939c067b84SDoug Ambrisko mac_addr[i] = ((u8 *)&a0)[i]; 6949c067b84SDoug Ambrisko 6959c067b84SDoug Ambrisko return 0; 6969c067b84SDoug Ambrisko } 6979c067b84SDoug Ambrisko 6989c067b84SDoug Ambrisko int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, 6999c067b84SDoug Ambrisko int broadcast, int promisc, int allmulti) 7009c067b84SDoug Ambrisko { 7019c067b84SDoug Ambrisko u64 a0, a1 = 0; 7029c067b84SDoug Ambrisko int wait = 1000; 7039c067b84SDoug Ambrisko int err; 7049c067b84SDoug Ambrisko 7059c067b84SDoug Ambrisko a0 = (directed ? CMD_PFILTER_DIRECTED : 0) | 7069c067b84SDoug Ambrisko (multicast ? CMD_PFILTER_MULTICAST : 0) | 7079c067b84SDoug Ambrisko (broadcast ? CMD_PFILTER_BROADCAST : 0) | 7089c067b84SDoug Ambrisko (promisc ? CMD_PFILTER_PROMISCUOUS : 0) | 7099c067b84SDoug Ambrisko (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0); 7109c067b84SDoug Ambrisko 7119c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait); 7129c067b84SDoug Ambrisko if (err) 7139c067b84SDoug Ambrisko pr_err("Can't set packet filter\n"); 7149c067b84SDoug Ambrisko 715*0acab8b3SDoug Ambrisko return (err); 7169c067b84SDoug Ambrisko } 7179c067b84SDoug Ambrisko 7189c067b84SDoug Ambrisko int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) 7199c067b84SDoug Ambrisko { 7209c067b84SDoug Ambrisko u64 a0 = 0, a1 = 0; 7219c067b84SDoug Ambrisko int wait = 1000; 7229c067b84SDoug Ambrisko int err; 7239c067b84SDoug Ambrisko int i; 7249c067b84SDoug Ambrisko 7259c067b84SDoug Ambrisko for (i = 0; i < ETH_ALEN; i++) 7269c067b84SDoug Ambrisko ((u8 *)&a0)[i] = addr[i]; 7279c067b84SDoug Ambrisko 7289c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); 7299c067b84SDoug Ambrisko if (err) 7309c067b84SDoug Ambrisko pr_err("Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", 7319c067b84SDoug Ambrisko addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], 7329c067b84SDoug Ambrisko err); 7339c067b84SDoug Ambrisko 734*0acab8b3SDoug Ambrisko return (err); 7359c067b84SDoug Ambrisko } 7369c067b84SDoug Ambrisko 7379c067b84SDoug Ambrisko int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) 7389c067b84SDoug Ambrisko { 7399c067b84SDoug Ambrisko u64 a0 = 0, a1 = 0; 7409c067b84SDoug Ambrisko int wait = 1000; 7419c067b84SDoug Ambrisko int err; 7429c067b84SDoug Ambrisko int i; 7439c067b84SDoug Ambrisko 7449c067b84SDoug Ambrisko for (i = 0; i < ETH_ALEN; i++) 7459c067b84SDoug Ambrisko ((u8 *)&a0)[i] = addr[i]; 7469c067b84SDoug Ambrisko 7479c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); 7489c067b84SDoug Ambrisko if (err) 7499c067b84SDoug Ambrisko pr_err("Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", 7509c067b84SDoug Ambrisko addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], 7519c067b84SDoug Ambrisko err); 7529c067b84SDoug Ambrisko 753*0acab8b3SDoug Ambrisko return (err); 7549c067b84SDoug Ambrisko } 7559c067b84SDoug Ambrisko 7569c067b84SDoug Ambrisko int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev, 7579c067b84SDoug Ambrisko u8 ig_vlan_rewrite_mode) 7589c067b84SDoug Ambrisko { 7599c067b84SDoug Ambrisko u64 a0 = ig_vlan_rewrite_mode, a1 = 0; 7609c067b84SDoug Ambrisko int wait = 1000; 7619c067b84SDoug Ambrisko 7629c067b84SDoug Ambrisko if (vnic_dev_capable(vdev, CMD_IG_VLAN_REWRITE_MODE)) 7639c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_IG_VLAN_REWRITE_MODE, 7649c067b84SDoug Ambrisko &a0, &a1, wait); 7659c067b84SDoug Ambrisko else 7669c067b84SDoug Ambrisko return 0; 7679c067b84SDoug Ambrisko } 7689c067b84SDoug Ambrisko 7699c067b84SDoug Ambrisko void vnic_dev_set_reset_flag(struct vnic_dev *vdev, int state) 7709c067b84SDoug Ambrisko { 7719c067b84SDoug Ambrisko vdev->in_reset = state; 7729c067b84SDoug Ambrisko } 7739c067b84SDoug Ambrisko 7749c067b84SDoug Ambrisko static inline int vnic_dev_in_reset(struct vnic_dev *vdev) 7759c067b84SDoug Ambrisko { 7769c067b84SDoug Ambrisko return vdev->in_reset; 7779c067b84SDoug Ambrisko } 7789c067b84SDoug Ambrisko 7799c067b84SDoug Ambrisko int vnic_dev_notify_setcmd(struct vnic_dev *vdev, 7809c067b84SDoug Ambrisko void *notify_addr, bus_addr_t notify_pa, u16 intr) 7819c067b84SDoug Ambrisko { 7829c067b84SDoug Ambrisko u64 a0, a1; 7839c067b84SDoug Ambrisko int wait = 1000; 7849c067b84SDoug Ambrisko int r; 7859c067b84SDoug Ambrisko 7869c067b84SDoug Ambrisko bus_dmamap_sync(vdev->notify_res.idi_tag, 7879c067b84SDoug Ambrisko vdev->notify_res.idi_map, 7889c067b84SDoug Ambrisko BUS_DMASYNC_PREWRITE); 7899c067b84SDoug Ambrisko memset(notify_addr, 0, sizeof(struct vnic_devcmd_notify)); 7909c067b84SDoug Ambrisko bus_dmamap_sync(vdev->notify_res.idi_tag, 7919c067b84SDoug Ambrisko vdev->notify_res.idi_map, 7929c067b84SDoug Ambrisko BUS_DMASYNC_POSTWRITE); 7939c067b84SDoug Ambrisko if (!vnic_dev_in_reset(vdev)) { 7949c067b84SDoug Ambrisko vdev->notify = notify_addr; 7959c067b84SDoug Ambrisko vdev->notify_pa = notify_pa; 7969c067b84SDoug Ambrisko } 7979c067b84SDoug Ambrisko 7989c067b84SDoug Ambrisko a0 = (u64)notify_pa; 7999c067b84SDoug Ambrisko a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; 8009c067b84SDoug Ambrisko a1 += sizeof(struct vnic_devcmd_notify); 8019c067b84SDoug Ambrisko 8029c067b84SDoug Ambrisko r = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); 8039c067b84SDoug Ambrisko if (!vnic_dev_in_reset(vdev)) 8049c067b84SDoug Ambrisko vdev->notify_sz = (r == 0) ? (u32)a1 : 0; 8059c067b84SDoug Ambrisko 8069c067b84SDoug Ambrisko return r; 8079c067b84SDoug Ambrisko } 8089c067b84SDoug Ambrisko 8099c067b84SDoug Ambrisko int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) 8109c067b84SDoug Ambrisko { 8119c067b84SDoug Ambrisko void *notify_addr = NULL; 8129c067b84SDoug Ambrisko bus_addr_t notify_pa = 0; 8139c067b84SDoug Ambrisko char name[NAME_MAX]; 8149c067b84SDoug Ambrisko static u32 instance; 8159c067b84SDoug Ambrisko 8169c067b84SDoug Ambrisko if (vdev->notify || vdev->notify_pa) { 8179c067b84SDoug Ambrisko return vnic_dev_notify_setcmd(vdev, vdev->notify, 8189c067b84SDoug Ambrisko vdev->notify_pa, intr); 8199c067b84SDoug Ambrisko } 8209c067b84SDoug Ambrisko if (!vnic_dev_in_reset(vdev)) { 8219c067b84SDoug Ambrisko snprintf((char *)name, sizeof(name), 8229c067b84SDoug Ambrisko "vnic_notify-%u", instance++); 8239c067b84SDoug Ambrisko iflib_dma_alloc(vdev->softc->ctx, 8249c067b84SDoug Ambrisko sizeof(struct vnic_devcmd_notify), 8259c067b84SDoug Ambrisko &vdev->notify_res, BUS_DMA_NOWAIT); 8269c067b84SDoug Ambrisko notify_pa = vdev->notify_res.idi_paddr; 8279c067b84SDoug Ambrisko notify_addr = vdev->notify_res.idi_vaddr; 8289c067b84SDoug Ambrisko } 8299c067b84SDoug Ambrisko 8309c067b84SDoug Ambrisko return vnic_dev_notify_setcmd(vdev, notify_addr, notify_pa, intr); 8319c067b84SDoug Ambrisko } 8329c067b84SDoug Ambrisko 8339c067b84SDoug Ambrisko int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev) 8349c067b84SDoug Ambrisko { 8359c067b84SDoug Ambrisko u64 a0, a1; 8369c067b84SDoug Ambrisko int wait = 1000; 8379c067b84SDoug Ambrisko int err; 8389c067b84SDoug Ambrisko 8399c067b84SDoug Ambrisko a0 = 0; /* paddr = 0 to unset notify buffer */ 8409c067b84SDoug Ambrisko a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */ 8419c067b84SDoug Ambrisko a1 += sizeof(struct vnic_devcmd_notify); 8429c067b84SDoug Ambrisko 8439c067b84SDoug Ambrisko err = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); 8449c067b84SDoug Ambrisko if (!vnic_dev_in_reset(vdev)) { 8459c067b84SDoug Ambrisko vdev->notify = NULL; 8469c067b84SDoug Ambrisko vdev->notify_pa = 0; 8479c067b84SDoug Ambrisko vdev->notify_sz = 0; 8489c067b84SDoug Ambrisko } 8499c067b84SDoug Ambrisko 850*0acab8b3SDoug Ambrisko return (err); 8519c067b84SDoug Ambrisko } 8529c067b84SDoug Ambrisko 8539c067b84SDoug Ambrisko int vnic_dev_notify_unset(struct vnic_dev *vdev) 8549c067b84SDoug Ambrisko { 8559c067b84SDoug Ambrisko if (vdev->notify && !vnic_dev_in_reset(vdev)) { 8569c067b84SDoug Ambrisko iflib_dma_free(&vdev->notify_res); 8579c067b84SDoug Ambrisko } 8589c067b84SDoug Ambrisko 8599c067b84SDoug Ambrisko return vnic_dev_notify_unsetcmd(vdev); 8609c067b84SDoug Ambrisko } 8619c067b84SDoug Ambrisko 8629c067b84SDoug Ambrisko static int vnic_dev_notify_ready(struct vnic_dev *vdev) 8639c067b84SDoug Ambrisko { 8649c067b84SDoug Ambrisko u32 *words; 8659c067b84SDoug Ambrisko unsigned int nwords = vdev->notify_sz / 4; 8669c067b84SDoug Ambrisko unsigned int i; 8679c067b84SDoug Ambrisko u32 csum; 8689c067b84SDoug Ambrisko 8699c067b84SDoug Ambrisko if (!vdev->notify || !vdev->notify_sz) 8709c067b84SDoug Ambrisko return 0; 8719c067b84SDoug Ambrisko 8729c067b84SDoug Ambrisko do { 8739c067b84SDoug Ambrisko csum = 0; 8749c067b84SDoug Ambrisko bus_dmamap_sync(vdev->notify_res.idi_tag, 8759c067b84SDoug Ambrisko vdev->notify_res.idi_map, 8769c067b84SDoug Ambrisko BUS_DMASYNC_PREREAD); 8779c067b84SDoug Ambrisko memcpy(&vdev->notify_copy, vdev->notify, vdev->notify_sz); 8789c067b84SDoug Ambrisko bus_dmamap_sync(vdev->notify_res.idi_tag, 8799c067b84SDoug Ambrisko vdev->notify_res.idi_map, 8809c067b84SDoug Ambrisko BUS_DMASYNC_POSTREAD); 8819c067b84SDoug Ambrisko words = (u32 *)&vdev->notify_copy; 8829c067b84SDoug Ambrisko for (i = 1; i < nwords; i++) 8839c067b84SDoug Ambrisko csum += words[i]; 8849c067b84SDoug Ambrisko } while (csum != words[0]); 8859c067b84SDoug Ambrisko 886*0acab8b3SDoug Ambrisko 887*0acab8b3SDoug Ambrisko return (1); 8889c067b84SDoug Ambrisko } 8899c067b84SDoug Ambrisko 8909c067b84SDoug Ambrisko int vnic_dev_init(struct vnic_dev *vdev, int arg) 8919c067b84SDoug Ambrisko { 8929c067b84SDoug Ambrisko u64 a0 = (u32)arg, a1 = 0; 8939c067b84SDoug Ambrisko int wait = 1000; 8949c067b84SDoug Ambrisko int r = 0; 8959c067b84SDoug Ambrisko 8969c067b84SDoug Ambrisko if (vnic_dev_capable(vdev, CMD_INIT)) 8979c067b84SDoug Ambrisko r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); 8989c067b84SDoug Ambrisko else { 8999c067b84SDoug Ambrisko vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait); 9009c067b84SDoug Ambrisko if (a0 & CMD_INITF_DEFAULT_MAC) { 9019c067b84SDoug Ambrisko /* Emulate these for old CMD_INIT_v1 which 9029c067b84SDoug Ambrisko * didn't pass a0 so no CMD_INITF_*. 9039c067b84SDoug Ambrisko */ 9049c067b84SDoug Ambrisko vnic_dev_cmd(vdev, CMD_GET_MAC_ADDR, &a0, &a1, wait); 9059c067b84SDoug Ambrisko vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); 9069c067b84SDoug Ambrisko } 9079c067b84SDoug Ambrisko } 9089c067b84SDoug Ambrisko return r; 9099c067b84SDoug Ambrisko } 9109c067b84SDoug Ambrisko 9119c067b84SDoug Ambrisko void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev) 9129c067b84SDoug Ambrisko { 9139c067b84SDoug Ambrisko /* Default: hardware intr coal timer is in units of 1.5 usecs */ 9149c067b84SDoug Ambrisko vdev->intr_coal_timer_info.mul = 2; 9159c067b84SDoug Ambrisko vdev->intr_coal_timer_info.div = 3; 9169c067b84SDoug Ambrisko vdev->intr_coal_timer_info.max_usec = 9179c067b84SDoug Ambrisko vnic_dev_intr_coal_timer_hw_to_usec(vdev, 0xffff); 9189c067b84SDoug Ambrisko } 9199c067b84SDoug Ambrisko 9209c067b84SDoug Ambrisko int vnic_dev_link_status(struct vnic_dev *vdev) 9219c067b84SDoug Ambrisko { 9229c067b84SDoug Ambrisko if (!vnic_dev_notify_ready(vdev)) 9239c067b84SDoug Ambrisko return 0; 9249c067b84SDoug Ambrisko 9259c067b84SDoug Ambrisko return vdev->notify_copy.link_state; 9269c067b84SDoug Ambrisko } 9279c067b84SDoug Ambrisko 9289c067b84SDoug Ambrisko u32 vnic_dev_port_speed(struct vnic_dev *vdev) 9299c067b84SDoug Ambrisko { 9309c067b84SDoug Ambrisko if (!vnic_dev_notify_ready(vdev)) 9319c067b84SDoug Ambrisko return 0; 9329c067b84SDoug Ambrisko 9339c067b84SDoug Ambrisko return vdev->notify_copy.port_speed; 9349c067b84SDoug Ambrisko } 9359c067b84SDoug Ambrisko 9369c067b84SDoug Ambrisko u32 vnic_dev_intr_coal_timer_usec_to_hw(struct vnic_dev *vdev, u32 usec) 9379c067b84SDoug Ambrisko { 9389c067b84SDoug Ambrisko return (usec * vdev->intr_coal_timer_info.mul) / 9399c067b84SDoug Ambrisko vdev->intr_coal_timer_info.div; 9409c067b84SDoug Ambrisko } 9419c067b84SDoug Ambrisko 9429c067b84SDoug Ambrisko u32 vnic_dev_intr_coal_timer_hw_to_usec(struct vnic_dev *vdev, u32 hw_cycles) 9439c067b84SDoug Ambrisko { 9449c067b84SDoug Ambrisko return (hw_cycles * vdev->intr_coal_timer_info.div) / 9459c067b84SDoug Ambrisko vdev->intr_coal_timer_info.mul; 9469c067b84SDoug Ambrisko } 9479c067b84SDoug Ambrisko 9489c067b84SDoug Ambrisko u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev) 9499c067b84SDoug Ambrisko { 9509c067b84SDoug Ambrisko return vdev->intr_coal_timer_info.max_usec; 9519c067b84SDoug Ambrisko } 9529c067b84SDoug Ambrisko 9539c067b84SDoug Ambrisko u32 vnic_dev_mtu(struct vnic_dev *vdev) 9549c067b84SDoug Ambrisko { 9559c067b84SDoug Ambrisko if (!vnic_dev_notify_ready(vdev)) 9569c067b84SDoug Ambrisko return 0; 9579c067b84SDoug Ambrisko 9589c067b84SDoug Ambrisko return vdev->notify_copy.mtu; 9599c067b84SDoug Ambrisko } 9609c067b84SDoug Ambrisko 9619c067b84SDoug Ambrisko void vnic_dev_set_intr_mode(struct vnic_dev *vdev, 9629c067b84SDoug Ambrisko enum vnic_dev_intr_mode intr_mode) 9639c067b84SDoug Ambrisko { 9649c067b84SDoug Ambrisko vdev->intr_mode = intr_mode; 9659c067b84SDoug Ambrisko } 9669c067b84SDoug Ambrisko 9679c067b84SDoug Ambrisko enum vnic_dev_intr_mode vnic_dev_get_intr_mode( 9689c067b84SDoug Ambrisko struct vnic_dev *vdev) 9699c067b84SDoug Ambrisko { 9709c067b84SDoug Ambrisko return vdev->intr_mode; 9719c067b84SDoug Ambrisko } 9729c067b84SDoug Ambrisko 9739c067b84SDoug Ambrisko 9749c067b84SDoug Ambrisko int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev) 9759c067b84SDoug Ambrisko { 9769c067b84SDoug Ambrisko char name[NAME_MAX]; 9779c067b84SDoug Ambrisko static u32 instance; 9789c067b84SDoug Ambrisko struct enic_softc *softc; 9799c067b84SDoug Ambrisko 9809c067b84SDoug Ambrisko softc = vdev->softc; 9819c067b84SDoug Ambrisko 9829c067b84SDoug Ambrisko snprintf((char *)name, sizeof(name), "vnic_stats-%u", instance++); 9839c067b84SDoug Ambrisko iflib_dma_alloc(softc->ctx, sizeof(struct vnic_stats), &vdev->stats_res, 0); 9849c067b84SDoug Ambrisko vdev->stats = (struct vnic_stats *)vdev->stats_res.idi_vaddr; 9859c067b84SDoug Ambrisko return vdev->stats == NULL ? -ENOMEM : 0; 9869c067b84SDoug Ambrisko } 9879c067b84SDoug Ambrisko 9889c067b84SDoug Ambrisko /* 9899c067b84SDoug Ambrisko * Initialize for up to VNIC_MAX_FLOW_COUNTERS 9909c067b84SDoug Ambrisko */ 9919c067b84SDoug Ambrisko int vnic_dev_alloc_counter_mem(struct vnic_dev *vdev) 9929c067b84SDoug Ambrisko { 9939c067b84SDoug Ambrisko char name[NAME_MAX]; 9949c067b84SDoug Ambrisko static u32 instance; 9959c067b84SDoug Ambrisko struct enic_softc *softc; 9969c067b84SDoug Ambrisko 9979c067b84SDoug Ambrisko softc = vdev->softc; 9989c067b84SDoug Ambrisko 9999c067b84SDoug Ambrisko snprintf((char *)name, sizeof(name), "vnic_flow_ctrs-%u", instance++); 10009c067b84SDoug Ambrisko iflib_dma_alloc(softc->ctx, sizeof(struct vnic_counter_counts) * VNIC_MAX_FLOW_COUNTERS, &vdev->flow_counters_res, 0); 10019c067b84SDoug Ambrisko vdev->flow_counters = (struct vnic_counter_counts *)vdev->flow_counters_res.idi_vaddr; 10029c067b84SDoug Ambrisko vdev->flow_counters_dma_active = 0; 1003*0acab8b3SDoug Ambrisko return (vdev->flow_counters == NULL ? ENOMEM : 0); 10049c067b84SDoug Ambrisko } 10059c067b84SDoug Ambrisko 10069c067b84SDoug Ambrisko struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, 10079c067b84SDoug Ambrisko struct enic_bar_info *mem, unsigned int num_bars) 10089c067b84SDoug Ambrisko { 10099c067b84SDoug Ambrisko if (vnic_dev_discover_res(vdev, NULL, num_bars)) 10109c067b84SDoug Ambrisko goto err_out; 10119c067b84SDoug Ambrisko 10129c067b84SDoug Ambrisko vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); 10139c067b84SDoug Ambrisko if (!vdev->devcmd) 10149c067b84SDoug Ambrisko goto err_out; 10159c067b84SDoug Ambrisko 10169c067b84SDoug Ambrisko return vdev; 10179c067b84SDoug Ambrisko 10189c067b84SDoug Ambrisko err_out: 10199c067b84SDoug Ambrisko return NULL; 10209c067b84SDoug Ambrisko } 10219c067b84SDoug Ambrisko 1022*0acab8b3SDoug Ambrisko static int vnic_dev_init_devcmd1(struct vnic_dev *vdev) 1023*0acab8b3SDoug Ambrisko { 1024*0acab8b3SDoug Ambrisko vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); 1025*0acab8b3SDoug Ambrisko if (!vdev->devcmd) 1026*0acab8b3SDoug Ambrisko return (ENODEV); 1027*0acab8b3SDoug Ambrisko vdev->devcmd_rtn = _vnic_dev_cmd; 1028*0acab8b3SDoug Ambrisko 1029*0acab8b3SDoug Ambrisko return 0; 1030*0acab8b3SDoug Ambrisko } 1031*0acab8b3SDoug Ambrisko 1032*0acab8b3SDoug Ambrisko static int vnic_dev_init_devcmd2(struct vnic_dev *vdev) 1033*0acab8b3SDoug Ambrisko { 1034*0acab8b3SDoug Ambrisko int err; 1035*0acab8b3SDoug Ambrisko unsigned int fetch_index; 1036*0acab8b3SDoug Ambrisko 1037*0acab8b3SDoug Ambrisko 1038*0acab8b3SDoug Ambrisko err = 0; 1039*0acab8b3SDoug Ambrisko 1040*0acab8b3SDoug Ambrisko if (vdev->devcmd2) 1041*0acab8b3SDoug Ambrisko return (0); 1042*0acab8b3SDoug Ambrisko 1043*0acab8b3SDoug Ambrisko vdev->devcmd2 = malloc(sizeof(*vdev->devcmd2), M_DEVBUF, 1044*0acab8b3SDoug Ambrisko M_NOWAIT | M_ZERO); 1045*0acab8b3SDoug Ambrisko 1046*0acab8b3SDoug Ambrisko if (!vdev->devcmd2) { 1047*0acab8b3SDoug Ambrisko return (ENOMEM); 1048*0acab8b3SDoug Ambrisko } 1049*0acab8b3SDoug Ambrisko 1050*0acab8b3SDoug Ambrisko vdev->devcmd2->color = 1; 1051*0acab8b3SDoug Ambrisko vdev->devcmd2->result_size = DEVCMD2_RING_SIZE; 1052*0acab8b3SDoug Ambrisko 1053*0acab8b3SDoug Ambrisko err = enic_wq_devcmd2_alloc(vdev, &vdev->devcmd2->wq, DEVCMD2_RING_SIZE, 1054*0acab8b3SDoug Ambrisko DEVCMD2_DESC_SIZE); 1055*0acab8b3SDoug Ambrisko 1056*0acab8b3SDoug Ambrisko if (err) { 1057*0acab8b3SDoug Ambrisko goto err_free_devcmd2; 1058*0acab8b3SDoug Ambrisko } 1059*0acab8b3SDoug Ambrisko vdev->devcmd2->wq_ctrl = vdev->devcmd2->wq.ctrl; 1060*0acab8b3SDoug Ambrisko vdev->devcmd2->cmd_ring = vdev->devcmd2->wq.ring.descs; 1061*0acab8b3SDoug Ambrisko 1062*0acab8b3SDoug Ambrisko fetch_index = ENIC_BUS_READ_4(vdev->devcmd2->wq.ctrl, TX_FETCH_INDEX); 1063*0acab8b3SDoug Ambrisko if (fetch_index == 0xFFFFFFFF) 1064*0acab8b3SDoug Ambrisko return (ENODEV); 1065*0acab8b3SDoug Ambrisko 1066*0acab8b3SDoug Ambrisko enic_wq_init_start(&vdev->devcmd2->wq, 0, fetch_index, fetch_index, 0, 1067*0acab8b3SDoug Ambrisko 0); 1068*0acab8b3SDoug Ambrisko vdev->devcmd2->posted = fetch_index; 1069*0acab8b3SDoug Ambrisko vnic_wq_enable(&vdev->devcmd2->wq); 1070*0acab8b3SDoug Ambrisko 1071*0acab8b3SDoug Ambrisko err = vnic_dev_alloc_desc_ring(vdev, &vdev->devcmd2->results_ring, 1072*0acab8b3SDoug Ambrisko DEVCMD2_RING_SIZE, DEVCMD2_DESC_SIZE); 1073*0acab8b3SDoug Ambrisko if (err) 1074*0acab8b3SDoug Ambrisko goto err_free_devcmd2; 1075*0acab8b3SDoug Ambrisko 1076*0acab8b3SDoug Ambrisko vdev->devcmd2->result = vdev->devcmd2->results_ring.descs; 1077*0acab8b3SDoug Ambrisko vdev->args[0] = (u64)vdev->devcmd2->results_ring.base_addr | 1078*0acab8b3SDoug Ambrisko VNIC_PADDR_TARGET; 1079*0acab8b3SDoug Ambrisko vdev->args[1] = DEVCMD2_RING_SIZE; 1080*0acab8b3SDoug Ambrisko 1081*0acab8b3SDoug Ambrisko err = _vnic_dev_cmd2(vdev, CMD_INITIALIZE_DEVCMD2, 1000); 1082*0acab8b3SDoug Ambrisko if (err) 1083*0acab8b3SDoug Ambrisko goto err_free_devcmd2; 1084*0acab8b3SDoug Ambrisko 1085*0acab8b3SDoug Ambrisko vdev->devcmd_rtn = _vnic_dev_cmd2; 1086*0acab8b3SDoug Ambrisko 1087*0acab8b3SDoug Ambrisko return (err); 1088*0acab8b3SDoug Ambrisko 1089*0acab8b3SDoug Ambrisko err_free_devcmd2: 1090*0acab8b3SDoug Ambrisko err = ENOMEM; 1091*0acab8b3SDoug Ambrisko if (vdev->devcmd2->wq_ctrl) 1092*0acab8b3SDoug Ambrisko vnic_wq_free(&vdev->devcmd2->wq); 1093*0acab8b3SDoug Ambrisko if (vdev->devcmd2->result) 1094*0acab8b3SDoug Ambrisko vnic_dev_free_desc_ring(vdev, &vdev->devcmd2->results_ring); 1095*0acab8b3SDoug Ambrisko free(vdev->devcmd2, M_DEVBUF); 1096*0acab8b3SDoug Ambrisko vdev->devcmd2 = NULL; 1097*0acab8b3SDoug Ambrisko 1098*0acab8b3SDoug Ambrisko return (err); 1099*0acab8b3SDoug Ambrisko } 1100*0acab8b3SDoug Ambrisko 11019c067b84SDoug Ambrisko /* 11029c067b84SDoug Ambrisko * vnic_dev_classifier: Add/Delete classifier entries 11039c067b84SDoug Ambrisko * @vdev: vdev of the device 11049c067b84SDoug Ambrisko * @cmd: CLSF_ADD for Add filter 11059c067b84SDoug Ambrisko * CLSF_DEL for Delete filter 11069c067b84SDoug Ambrisko * @entry: In case of ADD filter, the caller passes the RQ number in this 11079c067b84SDoug Ambrisko * variable. 11089c067b84SDoug Ambrisko * This function stores the filter_id returned by the 11099c067b84SDoug Ambrisko * firmware in the same variable before return; 11109c067b84SDoug Ambrisko * 11119c067b84SDoug Ambrisko * In case of DEL filter, the caller passes the RQ number. Return 11129c067b84SDoug Ambrisko * value is irrelevant. 11139c067b84SDoug Ambrisko * @data: filter data 11149c067b84SDoug Ambrisko * @action: action data 11159c067b84SDoug Ambrisko */ 11169c067b84SDoug Ambrisko 11179c067b84SDoug Ambrisko int vnic_dev_overlay_offload_ctrl(struct vnic_dev *vdev, u8 overlay, u8 config) 11189c067b84SDoug Ambrisko { 11199c067b84SDoug Ambrisko u64 a0 = overlay; 11209c067b84SDoug Ambrisko u64 a1 = config; 11219c067b84SDoug Ambrisko int wait = 1000; 11229c067b84SDoug Ambrisko 11239c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_OVERLAY_OFFLOAD_CTRL, &a0, &a1, wait); 11249c067b84SDoug Ambrisko } 11259c067b84SDoug Ambrisko 11269c067b84SDoug Ambrisko int vnic_dev_overlay_offload_cfg(struct vnic_dev *vdev, u8 overlay, 11279c067b84SDoug Ambrisko u16 vxlan_udp_port_number) 11289c067b84SDoug Ambrisko { 11299c067b84SDoug Ambrisko u64 a1 = vxlan_udp_port_number; 11309c067b84SDoug Ambrisko u64 a0 = overlay; 11319c067b84SDoug Ambrisko int wait = 1000; 11329c067b84SDoug Ambrisko 11339c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_OVERLAY_OFFLOAD_CFG, &a0, &a1, wait); 11349c067b84SDoug Ambrisko } 11359c067b84SDoug Ambrisko 11369c067b84SDoug Ambrisko int vnic_dev_capable_vxlan(struct vnic_dev *vdev) 11379c067b84SDoug Ambrisko { 11389c067b84SDoug Ambrisko u64 a0 = VIC_FEATURE_VXLAN; 11399c067b84SDoug Ambrisko u64 a1 = 0; 11409c067b84SDoug Ambrisko int wait = 1000; 11419c067b84SDoug Ambrisko int ret; 11429c067b84SDoug Ambrisko 11439c067b84SDoug Ambrisko ret = vnic_dev_cmd(vdev, CMD_GET_SUPP_FEATURE_VER, &a0, &a1, wait); 11449c067b84SDoug Ambrisko /* 1 if the NIC can do VXLAN for both IPv4 and IPv6 with multiple WQs */ 11459c067b84SDoug Ambrisko return ret == 0 && 11469c067b84SDoug Ambrisko (a1 & (FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ)) == 11479c067b84SDoug Ambrisko (FEATURE_VXLAN_IPV6 | FEATURE_VXLAN_MULTI_WQ); 11489c067b84SDoug Ambrisko } 11499c067b84SDoug Ambrisko 11509c067b84SDoug Ambrisko bool vnic_dev_counter_alloc(struct vnic_dev *vdev, uint32_t *idx) 11519c067b84SDoug Ambrisko { 11529c067b84SDoug Ambrisko u64 a0 = 0; 11539c067b84SDoug Ambrisko u64 a1 = 0; 11549c067b84SDoug Ambrisko int wait = 1000; 11559c067b84SDoug Ambrisko 11569c067b84SDoug Ambrisko if (vnic_dev_cmd(vdev, CMD_COUNTER_ALLOC, &a0, &a1, wait)) 11579c067b84SDoug Ambrisko return false; 11589c067b84SDoug Ambrisko *idx = (uint32_t)a0; 11599c067b84SDoug Ambrisko return true; 11609c067b84SDoug Ambrisko } 11619c067b84SDoug Ambrisko 11629c067b84SDoug Ambrisko bool vnic_dev_counter_free(struct vnic_dev *vdev, uint32_t idx) 11639c067b84SDoug Ambrisko { 11649c067b84SDoug Ambrisko u64 a0 = idx; 11659c067b84SDoug Ambrisko u64 a1 = 0; 11669c067b84SDoug Ambrisko int wait = 1000; 11679c067b84SDoug Ambrisko 11689c067b84SDoug Ambrisko return vnic_dev_cmd(vdev, CMD_COUNTER_FREE, &a0, &a1, 11699c067b84SDoug Ambrisko wait) == 0; 11709c067b84SDoug Ambrisko } 11719c067b84SDoug Ambrisko 11729c067b84SDoug Ambrisko bool vnic_dev_counter_query(struct vnic_dev *vdev, uint32_t idx, 11739c067b84SDoug Ambrisko bool reset, uint64_t *packets, uint64_t *bytes) 11749c067b84SDoug Ambrisko { 11759c067b84SDoug Ambrisko u64 a0 = idx; 11769c067b84SDoug Ambrisko u64 a1 = reset ? 1 : 0; 11779c067b84SDoug Ambrisko int wait = 1000; 11789c067b84SDoug Ambrisko 11799c067b84SDoug Ambrisko if (reset) { 11809c067b84SDoug Ambrisko /* query/reset returns updated counters */ 11819c067b84SDoug Ambrisko if (vnic_dev_cmd(vdev, CMD_COUNTER_QUERY, &a0, &a1, wait)) 11829c067b84SDoug Ambrisko return false; 11839c067b84SDoug Ambrisko *packets = a0; 11849c067b84SDoug Ambrisko *bytes = a1; 11859c067b84SDoug Ambrisko } else { 11869c067b84SDoug Ambrisko /* Get values DMA'd from the adapter */ 11879c067b84SDoug Ambrisko *packets = vdev->flow_counters[idx].vcc_packets; 11889c067b84SDoug Ambrisko *bytes = vdev->flow_counters[idx].vcc_bytes; 11899c067b84SDoug Ambrisko } 11909c067b84SDoug Ambrisko return true; 11919c067b84SDoug Ambrisko } 11929c067b84SDoug Ambrisko 11939c067b84SDoug Ambrisko device_t dev_from_vnic_dev(struct vnic_dev *vdev) { 11949c067b84SDoug Ambrisko return (vdev->softc->dev); 11959c067b84SDoug Ambrisko } 1196*0acab8b3SDoug Ambrisko 1197*0acab8b3SDoug Ambrisko int vnic_dev_cmd_init(struct vnic_dev *vdev) { 1198*0acab8b3SDoug Ambrisko int err; 1199*0acab8b3SDoug Ambrisko void __iomem *res; 1200*0acab8b3SDoug Ambrisko 1201*0acab8b3SDoug Ambrisko res = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0); 1202*0acab8b3SDoug Ambrisko if (res) { 1203*0acab8b3SDoug Ambrisko err = vnic_dev_init_devcmd2(vdev); 1204*0acab8b3SDoug Ambrisko if (err) 1205*0acab8b3SDoug Ambrisko device_printf(dev_from_vnic_dev(vdev), 1206*0acab8b3SDoug Ambrisko "DEVCMD2 init failed, Using DEVCMD1\n"); 1207*0acab8b3SDoug Ambrisko else 1208*0acab8b3SDoug Ambrisko return 0; 1209*0acab8b3SDoug Ambrisko } 1210*0acab8b3SDoug Ambrisko 1211*0acab8b3SDoug Ambrisko err = vnic_dev_init_devcmd1(vdev); 1212*0acab8b3SDoug Ambrisko 1213*0acab8b3SDoug Ambrisko return (err); 1214*0acab8b3SDoug Ambrisko } 1215