aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/enic/vnic_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/enic/vnic_dev.c')
-rw-r--r--sys/dev/enic/vnic_dev.c244
1 files changed, 207 insertions, 37 deletions
diff --git a/sys/dev/enic/vnic_dev.c b/sys/dev/enic/vnic_dev.c
index 3425d7372e56..a8228aed69aa 100644
--- a/sys/dev/enic/vnic_dev.c
+++ b/sys/dev/enic/vnic_dev.c
@@ -44,7 +44,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
u8 type;
if (num_bars == 0)
- return -EINVAL;
+ return (EINVAL);
rh = malloc(sizeof(*rh), M_DEVBUF, M_NOWAIT | M_ZERO);
mrh = malloc(sizeof(*mrh), M_DEVBUF, M_NOWAIT | M_ZERO);
@@ -52,7 +52,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
pr_err("vNIC BAR0 res hdr not mem-mapped\n");
free(rh, M_DEVBUF);
free(mrh, M_DEVBUF);
- return -EINVAL;
+ return (EINVAL);
}
/* Check for mgmt vnic in addition to normal vnic */
@@ -69,7 +69,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
rh->magic, rh->version);
free(rh, M_DEVBUF);
free(mrh, M_DEVBUF);
- return -EINVAL;
+ return (EINVAL);
}
}
@@ -97,6 +97,7 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
case RES_TYPE_INTR_CTRL:
case RES_TYPE_INTR_PBA_LEGACY:
case RES_TYPE_DEVCMD:
+ case RES_TYPE_DEVCMD2:
break;
default:
ENIC_BUS_READ_REGION_4(softc, mem, r_offset, (void *)r, sizeof(*r) / 4);
@@ -167,17 +168,12 @@ unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
ring->desc_size = VNIC_ALIGN(desc_size, desc_align);
- ring->size = ring->desc_count * ring->desc_size;
- ring->size_unaligned = ring->size + ring->base_align;
+ ring->size_unaligned = ring->desc_count * ring->desc_size \
+ + ring->base_align;
return ring->size_unaligned;
}
-void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring)
-{
- memset(ring->descs, 0, ring->size);
-}
-
static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
int wait)
{
@@ -189,12 +185,12 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
status = ENIC_BUS_READ_4(devcmd, DEVCMD_STATUS);
if (status == 0xFFFFFFFF) {
/* PCI-e target device is gone */
- return -ENODEV;
+ return (ENODEV);
}
if (status & STAT_BUSY) {
pr_err("Busy devcmd %d\n", _CMD_N(cmd));
- return -EBUSY;
+ return (EBUSY);
}
if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) {
@@ -214,7 +210,7 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
status = ENIC_BUS_READ_4(devcmd, DEVCMD_STATUS);
if (status == 0xFFFFFFFF) {
/* PCI-e target device is gone */
- return -ENODEV;
+ return (ENODEV);
}
if (!(status & STAT_BUSY)) {
@@ -225,7 +221,7 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
pr_err("Devcmd %d failed " \
"with error code %d\n",
_CMD_N(cmd), err);
- return err;
+ return (err);
}
if (_CMD_DIR(cmd) & _CMD_DIR_READ) {
@@ -237,7 +233,82 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
}
pr_err("Timedout devcmd %d\n", _CMD_N(cmd));
- return -ETIMEDOUT;
+ return (ETIMEDOUT);
+}
+
+static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
+ int wait)
+{
+ struct devcmd2_controller *dc2c = vdev->devcmd2;
+ struct devcmd2_result *result;
+ u8 color;
+ unsigned int i;
+ u32 fetch_index, new_posted;
+ int delay, err;
+ u32 posted = dc2c->posted;
+
+ fetch_index = ENIC_BUS_READ_4(dc2c->wq_ctrl, TX_FETCH_INDEX);
+ if (fetch_index == 0xFFFFFFFF)
+ return (ENODEV);
+
+ new_posted = (posted + 1) % DEVCMD2_RING_SIZE;
+
+ if (new_posted == fetch_index) {
+ device_printf(dev_from_vnic_dev(vdev),
+ "devcmd2 %d: wq is full. fetch index: %u, posted index: %u\n",
+ _CMD_N(cmd), fetch_index, posted);
+ return (EBUSY);
+ }
+
+ dc2c->cmd_ring[posted].cmd = cmd;
+ dc2c->cmd_ring[posted].flags = 0;
+
+ if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT))
+ dc2c->cmd_ring[posted].flags |= DEVCMD2_FNORESULT;
+ if (_CMD_DIR(cmd) & _CMD_DIR_WRITE)
+ for (i = 0; i < VNIC_DEVCMD_NARGS; i++)
+ dc2c->cmd_ring[posted].args[i] = vdev->args[i];
+
+ ENIC_BUS_WRITE_4(dc2c->wq_ctrl, TX_POSTED_INDEX, new_posted);
+ dc2c->posted = new_posted;
+
+ if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT)
+ return (0);
+
+ result = dc2c->result + dc2c->next_result;
+ color = dc2c->color;
+
+ dc2c->next_result++;
+ if (dc2c->next_result == dc2c->result_size) {
+ dc2c->next_result = 0;
+ dc2c->color = dc2c->color ? 0 : 1;
+ }
+
+ for (delay = 0; delay < wait; delay++) {
+ if (result->color == color) {
+ if (result->error) {
+ err = result->error;
+ if (err != ERR_ECMDUNKNOWN ||
+ cmd != CMD_CAPABILITY)
+ device_printf(dev_from_vnic_dev(vdev),
+ "Error %d devcmd %d\n", err,
+ _CMD_N(cmd));
+ return (err);
+ }
+ if (_CMD_DIR(cmd) & _CMD_DIR_READ)
+ for (i = 0; i < VNIC_DEVCMD2_NARGS; i++)
+ vdev->args[i] = result->results[i];
+
+ return 0;
+ }
+ udelay(100);
+ }
+
+ device_printf(dev_from_vnic_dev(vdev),
+ "devcmd %d timed out\n", _CMD_N(cmd));
+
+
+ return (ETIMEDOUT);
}
static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
@@ -253,7 +324,7 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
*/
if (nargs > VNIC_DEVCMD_NARGS - 2) {
pr_err("number of args %d exceeds the maximum\n", nargs);
- return -EINVAL;
+ return (EINVAL);
}
memset(vdev->args, 0, sizeof(vdev->args));
@@ -261,9 +332,9 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
vdev->args[1] = cmd;
memcpy(&vdev->args[2], args, nargs * sizeof(args[0]));
- err = _vnic_dev_cmd(vdev, proxy_cmd, wait);
+ err = vdev->devcmd_rtn(vdev, proxy_cmd, wait);
if (err)
- return err;
+ return (err);
status = (u32)vdev->args[0];
if (status & STAT_ERROR) {
@@ -271,7 +342,7 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
if (err != ERR_ECMDUNKNOWN ||
cmd != CMD_CAPABILITY)
pr_err("Error %d proxy devcmd %d\n", err, _CMD_N(cmd));
- return err;
+ return (err);
}
memcpy(args, &vdev->args[1], nargs * sizeof(args[0]));
@@ -286,16 +357,16 @@ static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev,
if (nargs > VNIC_DEVCMD_NARGS) {
pr_err("number of args %d exceeds the maximum\n", nargs);
- return -EINVAL;
+ return (EINVAL);
}
memset(vdev->args, 0, sizeof(vdev->args));
memcpy(vdev->args, args, nargs * sizeof(args[0]));
- err = _vnic_dev_cmd(vdev, cmd, wait);
+ err = vdev->devcmd_rtn(vdev, cmd, wait);
memcpy(args, vdev->args, nargs * sizeof(args[0]));
- return err;
+ return (err);
}
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
@@ -328,7 +399,7 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
*a1 = args[1];
}
- return err;
+ return (err);
}
int vnic_dev_cmd_args(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
@@ -400,7 +471,7 @@ int vnic_dev_capable_filter_mode(struct vnic_dev *vdev, u32 *mode,
args[1] = 0;
err = vnic_dev_cmd_args(vdev, CMD_CAPABILITY, args, 2, 1000);
if (err)
- return err;
+ return (err);
max_level = args[1];
goto parse_max_level;
} else if (args[2] == FILTER_CAP_MODE_V1) {
@@ -479,7 +550,7 @@ int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, size_t size,
break;
}
- return err;
+ return (err);
}
int vnic_dev_stats_clear(struct vnic_dev *vdev)
@@ -497,7 +568,7 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
int rc;
if (!vdev->stats)
- return -ENOMEM;
+ return (ENOMEM);
*stats = vdev->stats;
a0 = vdev->stats_res.idi_paddr;
@@ -524,10 +595,10 @@ int vnic_dev_counter_dma_cfg(struct vnic_dev *vdev, u32 period,
int err;
if (num_counters > VNIC_MAX_FLOW_COUNTERS)
- return -ENOMEM;
+ return (ENOMEM);
if (period > 0 && (period < VNIC_COUNTER_DMA_MIN_PERIOD ||
num_counters == 0))
- return -EINVAL;
+ return (EINVAL);
args[0] = num_counters;
args[1] = vdev->flow_counters_res.idi_paddr;
@@ -545,7 +616,7 @@ int vnic_dev_counter_dma_cfg(struct vnic_dev *vdev, u32 period,
vdev->flow_counters_dma_active = (num_counters != 0 &&
period != 0);
- return err;
+ return (err);
}
int vnic_dev_close(struct vnic_dev *vdev)
@@ -593,7 +664,7 @@ int vnic_dev_open_done(struct vnic_dev *vdev, int *done)
err = vnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait);
if (err)
- return err;
+ return (err);
*done = (a0 == 0);
@@ -611,7 +682,7 @@ int vnic_dev_get_mac_addr(struct vnic_dev *vdev, u8 *mac_addr)
err = vnic_dev_cmd(vdev, CMD_GET_MAC_ADDR, &a0, &a1, wait);
if (err)
- return err;
+ return (err);
for (i = 0; i < ETH_ALEN; i++)
mac_addr[i] = ((u8 *)&a0)[i];
@@ -636,7 +707,7 @@ int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
if (err)
pr_err("Can't set packet filter\n");
- return err;
+ return (err);
}
int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
@@ -655,7 +726,7 @@ int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
err);
- return err;
+ return (err);
}
int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
@@ -674,7 +745,7 @@ int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
err);
- return err;
+ return (err);
}
int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
@@ -771,7 +842,7 @@ int vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
vdev->notify_sz = 0;
}
- return err;
+ return (err);
}
int vnic_dev_notify_unset(struct vnic_dev *vdev)
@@ -807,7 +878,8 @@ static int vnic_dev_notify_ready(struct vnic_dev *vdev)
csum += words[i];
} while (csum != words[0]);
- return 1;
+
+ return (1);
}
int vnic_dev_init(struct vnic_dev *vdev, int arg)
@@ -923,7 +995,7 @@ int vnic_dev_alloc_counter_mem(struct vnic_dev *vdev)
iflib_dma_alloc(softc->ctx, sizeof(struct vnic_counter_counts) * VNIC_MAX_FLOW_COUNTERS, &vdev->flow_counters_res, 0);
vdev->flow_counters = (struct vnic_counter_counts *)vdev->flow_counters_res.idi_vaddr;
vdev->flow_counters_dma_active = 0;
- return vdev->flow_counters == NULL ? -ENOMEM : 0;
+ return (vdev->flow_counters == NULL ? ENOMEM : 0);
}
struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
@@ -942,6 +1014,85 @@ err_out:
return NULL;
}
+static int vnic_dev_init_devcmd1(struct vnic_dev *vdev)
+{
+ vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0);
+ if (!vdev->devcmd)
+ return (ENODEV);
+ vdev->devcmd_rtn = _vnic_dev_cmd;
+
+ return 0;
+}
+
+static int vnic_dev_init_devcmd2(struct vnic_dev *vdev)
+{
+ int err;
+ unsigned int fetch_index;
+
+
+ err = 0;
+
+ if (vdev->devcmd2)
+ return (0);
+
+ vdev->devcmd2 = malloc(sizeof(*vdev->devcmd2), M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+
+ if (!vdev->devcmd2) {
+ return (ENOMEM);
+ }
+
+ vdev->devcmd2->color = 1;
+ vdev->devcmd2->result_size = DEVCMD2_RING_SIZE;
+
+ err = enic_wq_devcmd2_alloc(vdev, &vdev->devcmd2->wq, DEVCMD2_RING_SIZE,
+ DEVCMD2_DESC_SIZE);
+
+ if (err) {
+ goto err_free_devcmd2;
+ }
+ vdev->devcmd2->wq_ctrl = vdev->devcmd2->wq.ctrl;
+ vdev->devcmd2->cmd_ring = vdev->devcmd2->wq.ring.descs;
+
+ fetch_index = ENIC_BUS_READ_4(vdev->devcmd2->wq.ctrl, TX_FETCH_INDEX);
+ if (fetch_index == 0xFFFFFFFF)
+ return (ENODEV);
+
+ enic_wq_init_start(&vdev->devcmd2->wq, 0, fetch_index, fetch_index, 0,
+ 0);
+ vdev->devcmd2->posted = fetch_index;
+ vnic_wq_enable(&vdev->devcmd2->wq);
+
+ err = vnic_dev_alloc_desc_ring(vdev, &vdev->devcmd2->results_ring,
+ DEVCMD2_RING_SIZE, DEVCMD2_DESC_SIZE);
+ if (err)
+ goto err_free_devcmd2;
+
+ vdev->devcmd2->result = vdev->devcmd2->results_ring.descs;
+ vdev->args[0] = (u64)vdev->devcmd2->results_ring.base_addr |
+ VNIC_PADDR_TARGET;
+ vdev->args[1] = DEVCMD2_RING_SIZE;
+
+ err = _vnic_dev_cmd2(vdev, CMD_INITIALIZE_DEVCMD2, 1000);
+ if (err)
+ goto err_free_devcmd2;
+
+ vdev->devcmd_rtn = _vnic_dev_cmd2;
+
+ return (err);
+
+err_free_devcmd2:
+ err = ENOMEM;
+ if (vdev->devcmd2->wq_ctrl)
+ vnic_wq_free(&vdev->devcmd2->wq);
+ if (vdev->devcmd2->result)
+ vnic_dev_free_desc_ring(vdev, &vdev->devcmd2->results_ring);
+ free(vdev->devcmd2, M_DEVBUF);
+ vdev->devcmd2 = NULL;
+
+ return (err);
+}
+
/*
* vnic_dev_classifier: Add/Delete classifier entries
* @vdev: vdev of the device
@@ -1037,3 +1188,22 @@ bool vnic_dev_counter_query(struct vnic_dev *vdev, uint32_t idx,
device_t dev_from_vnic_dev(struct vnic_dev *vdev) {
return (vdev->softc->dev);
}
+
+int vnic_dev_cmd_init(struct vnic_dev *vdev) {
+ int err;
+ void __iomem *res;
+
+ res = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0);
+ if (res) {
+ err = vnic_dev_init_devcmd2(vdev);
+ if (err)
+ device_printf(dev_from_vnic_dev(vdev),
+ "DEVCMD2 init failed, Using DEVCMD1\n");
+ else
+ return 0;
+ }
+
+ err = vnic_dev_init_devcmd1(vdev);
+
+ return (err);
+}