xref: /freebsd-src/sys/dev/enic/vnic_dev.c (revision 0acab8b3d1336d4db73a9946ef76b4bcd0b0aabe)
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