diff options
Diffstat (limited to 'sys/dev/enic')
-rw-r--r-- | sys/dev/enic/cq_desc.h | 15 | ||||
-rw-r--r-- | sys/dev/enic/enic.h | 78 | ||||
-rw-r--r-- | sys/dev/enic/enic_res.c | 4 | ||||
-rw-r--r-- | sys/dev/enic/enic_res.h | 2 | ||||
-rw-r--r-- | sys/dev/enic/enic_txrx.c | 39 | ||||
-rw-r--r-- | sys/dev/enic/if_enic.c | 192 | ||||
-rw-r--r-- | sys/dev/enic/vnic_cq.c | 2 | ||||
-rw-r--r-- | sys/dev/enic/vnic_cq.h | 9 | ||||
-rw-r--r-- | sys/dev/enic/vnic_dev.c | 244 | ||||
-rw-r--r-- | sys/dev/enic/vnic_dev.h | 9 | ||||
-rw-r--r-- | sys/dev/enic/vnic_intr.c | 2 | ||||
-rw-r--r-- | sys/dev/enic/vnic_intr.h | 2 | ||||
-rw-r--r-- | sys/dev/enic/vnic_resource.h | 1 | ||||
-rw-r--r-- | sys/dev/enic/vnic_rq.c | 7 | ||||
-rw-r--r-- | sys/dev/enic/vnic_rq.h | 1 | ||||
-rw-r--r-- | sys/dev/enic/vnic_rss.h | 5 | ||||
-rw-r--r-- | sys/dev/enic/vnic_wq.c | 106 | ||||
-rw-r--r-- | sys/dev/enic/vnic_wq.h | 18 |
18 files changed, 570 insertions, 166 deletions
diff --git a/sys/dev/enic/cq_desc.h b/sys/dev/enic/cq_desc.h index ae8847c6d9a1..4fb8cce7212e 100644 --- a/sys/dev/enic/cq_desc.h +++ b/sys/dev/enic/cq_desc.h @@ -44,14 +44,6 @@ struct cq_desc { #define CQ_DESC_COMP_NDX_BITS 12 #define CQ_DESC_COMP_NDX_MASK ((1 << CQ_DESC_COMP_NDX_BITS) - 1) -static inline void cq_color_enc(struct cq_desc *desc, const u8 color) -{ - if (color) - desc->type_color |= (1 << CQ_DESC_COLOR_SHIFT); - else - desc->type_color &= ~(1 << CQ_DESC_COLOR_SHIFT); -} - static inline void cq_desc_enc(struct cq_desc *desc, const u8 type, const u8 color, const u16 q_number, const u16 completed_index) @@ -87,11 +79,4 @@ static inline void cq_desc_dec(const struct cq_desc *desc_arg, CQ_DESC_COMP_NDX_MASK; } -static inline void cq_color_dec(const struct cq_desc *desc_arg, u8 *color) -{ - volatile const struct cq_desc *desc = desc_arg; - - *color = (desc->type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK; -} - #endif /* _CQ_DESC_H_ */ diff --git a/sys/dev/enic/enic.h b/sys/dev/enic/enic.h index 6d0eb8563efd..eec6de823c9d 100644 --- a/sys/dev/enic/enic.h +++ b/sys/dev/enic/enic.h @@ -108,13 +108,13 @@ struct vnic_res { #define ENIC_DEFAULT_VXLAN_PORT 4789 /* - * Interrupt 0: LSC and errors * Interrupt 1: rx queue 0 * Interrupt 2: rx queue 1 * ... + * Interrupt x: LSC and errors */ #define ENICPMD_LSC_INTR_OFFSET 0 -#define ENICPMD_RXQ_INTR_OFFSET 1 +#define ENICPMD_RXQ_INTR_OFFSET 0 #include "vnic_devcmd.h" @@ -152,6 +152,9 @@ struct vnic_dev { u64 args[VNIC_DEVCMD_NARGS]; int in_reset; struct vnic_intr_coal_timer_info intr_coal_timer_info; + struct devcmd2_controller *devcmd2; + int (*devcmd_rtn)(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, + int wait); void *(*alloc_consistent)(void *priv, size_t size, bus_addr_t *dma_handle, struct iflib_dma_info *res, u8 *name); void (*free_consistent)(void *priv, size_t size, void *vaddr, @@ -175,6 +178,28 @@ struct intr_queue { struct enic_softc *softc; }; +#define ENIC_MAX_LINK_SPEEDS 3 +#define ENIC_LINK_SPEED_10G 10000 +#define ENIC_LINK_SPEED_4G 4000 +#define ENIC_LINK_40G_INDEX 2 +#define ENIC_LINK_10G_INDEX 1 +#define ENIC_LINK_4G_INDEX 0 +#define ENIC_RX_COALESCE_RANGE_END 125 +#define ENIC_AIC_TS_BREAK 100 + +struct enic_rx_coal { + u32 small_pkt_range_start; + u32 large_pkt_range_start; + u32 range_end; + u32 use_adaptive_rx_coalesce; +}; + +/* Store only the lower range. Higher range is given by fw. */ +struct enic_intr_mod_range { + u32 small_pkt_range_start; + u32 large_pkt_range_start; +}; + struct enic { struct enic *next; struct rte_pci_device *pdev; @@ -228,7 +253,7 @@ struct enic { /* interrupt vectors (len = conf_intr_count) */ struct vnic_intr *intr; - struct intr_queue *intr_queues;; + struct intr_queue *intr_queues; unsigned int intr_count; /* equals enabled interrupts (lsc + rxqs) */ @@ -267,6 +292,9 @@ struct enic { uint64_t tx_offload_mask; /* PKT_TX flags accepted */ struct enic_softc *softc; int port_mtu; + struct enic_rx_coal rx_coalesce_setting; + u32 rx_coalesce_usecs; + u32 tx_coalesce_usecs; }; struct enic_softc { @@ -307,11 +335,6 @@ struct enic_softc { /* Per-instance private data structure */ -static inline unsigned int enic_vnic_rq_count(struct enic *enic) -{ - return enic->rq_count; -} - static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq) { return rq; @@ -323,21 +346,6 @@ static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq) } static inline uint32_t -enic_ring_add(uint32_t n_descriptors, uint32_t i0, uint32_t i1) -{ - uint32_t d = i0 + i1; - d -= (d >= n_descriptors) ? n_descriptors : 0; - return d; -} - -static inline uint32_t -enic_ring_sub(uint32_t n_descriptors, uint32_t i0, uint32_t i1) -{ - int32_t d = i1 - i0; - return (uint32_t)((d < 0) ? ((int32_t)n_descriptors + d) : d); -} - -static inline uint32_t enic_ring_incr(uint32_t n_descriptors, uint32_t idx) { idx++; @@ -346,34 +354,14 @@ enic_ring_incr(uint32_t n_descriptors, uint32_t idx) return idx; } -void enic_free_wq(void *txq); -int enic_alloc_intr_resources(struct enic *enic); int enic_setup_finish(struct enic *enic); -int enic_alloc_wq(struct enic *enic, uint16_t queue_idx, - unsigned int socket_id, uint16_t nb_desc); void enic_start_wq(struct enic *enic, uint16_t queue_idx); int enic_stop_wq(struct enic *enic, uint16_t queue_idx); void enic_start_rq(struct enic *enic, uint16_t queue_idx); -void enic_free_rq(void *rxq); -int enic_set_vnic_res(struct enic *enic); -int enic_init_rss_nic_cfg(struct enic *enic); -int enic_set_rss_reta(struct enic *enic, union vnic_rss_cpu *rss_cpu); -int enic_set_vlan_strip(struct enic *enic); +int enic_stop_rq(struct enic *enic, uint16_t queue_idx); +void enic_dev_disable(struct enic *enic); int enic_enable(struct enic *enic); int enic_disable(struct enic *enic); -void enic_remove(struct enic *enic); -int enic_get_link_status(struct enic *enic); -void enic_dev_stats_clear(struct enic *enic); -void enic_add_packet_filter(struct enic *enic); -int enic_set_mac_address(struct enic *enic, uint8_t *mac_addr); -int enic_del_mac_address(struct enic *enic, int mac_index); -unsigned int enic_cleanup_wq(struct enic *enic, struct vnic_wq *wq); - -void enic_post_wq_index(struct vnic_wq *wq); -int enic_probe(struct enic *enic); -int enic_clsf_init(struct enic *enic); -void enic_clsf_destroy(struct enic *enic); -int enic_set_mtu(struct enic *enic, uint16_t new_mtu); int enic_link_update(struct enic *enic); bool enic_use_vector_rx_handler(struct enic *enic); void enic_fdir_info(struct enic *enic); diff --git a/sys/dev/enic/enic_res.c b/sys/dev/enic/enic_res.c index d264874557a0..413873ad0fb4 100644 --- a/sys/dev/enic/enic_res.c +++ b/sys/dev/enic/enic_res.c @@ -95,11 +95,11 @@ int enic_get_vnic_config(struct enic *enic) dev_info(enic_get_dev(enic), "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x " - "wq/rq %d/%d mtu d, max mtu:%d\n", + "wq/rq %d/%d mtu %d, max mtu:%d\n", enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2], enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5], c->wq_desc_count, c->rq_desc_count, - /* enic->rte_dev->data->mtu, */ enic->max_mtu); + c->mtu, enic->max_mtu); dev_info(enic_get_dev(enic), "vNIC csum tx/rx %s/%s " "rss %s intr mode %s type %s timer %d usec " "loopback tag 0x%04x\n", diff --git a/sys/dev/enic/enic_res.h b/sys/dev/enic/enic_res.h index 1a6f3a3ca98f..82963e61a44f 100644 --- a/sys/dev/enic/enic_res.h +++ b/sys/dev/enic/enic_res.h @@ -67,7 +67,5 @@ int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type, u8 ig_vlan_strip_en); void enic_get_res_counts(struct enic *enic); void enic_init_vnic_resources(struct enic *enic); -int enic_alloc_vnic_resources(struct enic *); -void enic_free_vnic_resources(struct enic *); #endif /* _ENIC_RES_H_ */ diff --git a/sys/dev/enic/enic_txrx.c b/sys/dev/enic/enic_txrx.c index 5a557fc7f94a..169041587d06 100644 --- a/sys/dev/enic/enic_txrx.c +++ b/sys/dev/enic/enic_txrx.c @@ -103,6 +103,7 @@ enic_isc_txd_encap(void *vsc, if_pkt_info_t pi) softc = vsc; enic = &softc->enic; + if_softc_ctx_t scctx = softc->scctx; wq = &enic->wq[pi->ipi_qsidx]; nsegs = pi->ipi_nsegs; @@ -112,6 +113,9 @@ enic_isc_txd_encap(void *vsc, if_pkt_info_t pi) head_idx = wq->head_idx; desc_count = wq->ring.desc_count; + if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0) + offload_mode |= WQ_ENET_OFFLOAD_MODE_CSUM; + for (i = 0; i < nsegs; i++) { eop = 0; cq = 0; @@ -320,7 +324,7 @@ enic_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx) static int enic_legacy_intr(void *xsc) { - return -1; + return (1); } static inline void @@ -375,7 +379,7 @@ enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, u8 type, vnic_wq_service(&enic->wq[q_number], cq_desc, completed_index, NULL, opaque); - return 0; + return (0); } static void @@ -384,7 +388,7 @@ vnic_rq_service(struct vnic_rq *rq, struct cq_desc *cq_desc, void(*buf_service)(struct vnic_rq *rq, struct cq_desc *cq_desc, /* struct vnic_rq_buf * *buf, */ int skipped, void *opaque), void *opaque) { - + if_softc_ctx_t scctx; if_rxd_info_t ri = (if_rxd_info_t) opaque; u8 type, color, eop, sop, ingress_port, vlan_stripped; u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof; @@ -396,6 +400,8 @@ vnic_rq_service(struct vnic_rq *rq, struct cq_desc *cq_desc, int cqidx; if_rxd_frag_t frag; + scctx = rq->vdev->softc->scctx; + cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc, &type, &color, &q_number, &completed_index, &ingress_port, &fcoe, &eop, &sop, &rss_type, @@ -419,6 +425,11 @@ vnic_rq_service(struct vnic_rq *rq, struct cq_desc *cq_desc, ri->iri_cidx = cqidx; ri->iri_nfrags = 1; ri->iri_len = bytes_written; + + if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0) + if (!csum_not_calc && (tcp_udp_csum_ok || ipv4_csum_ok)) { + ri->iri_csum_flags = (CSUM_IP_CHECKED | CSUM_IP_VALID); + } } static int @@ -431,7 +442,7 @@ enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, vnic_rq_service(&enic->rq[ri->iri_qsidx], cq_desc, completed_index, VNIC_RQ_RETURN_DESC, NULL, /* enic_rq_indicate_buf, */ opaque); - return 0; + return (0); } void @@ -468,10 +479,8 @@ enic_stop_wq(struct enic *enic, uint16_t queue_idx) int ret; ret = vnic_wq_disable(&enic->wq[queue_idx]); - if (ret) - return ret; - return 0; + return (ret); } void @@ -483,3 +492,19 @@ enic_start_rq(struct enic *enic, uint16_t queue_idx) vnic_rq_enable(rq); enic_initial_post_rx(enic, rq); } + +int +enic_stop_rq(struct enic *enic, uint16_t queue_idx) +{ + int ret; + + ret = vnic_rq_disable(&enic->rq[queue_idx]); + + return (ret); +} + + +void +enic_dev_disable(struct enic *enic) { + vnic_dev_disable(enic->vdev); +} diff --git a/sys/dev/enic/if_enic.c b/sys/dev/enic/if_enic.c index dc0c0d028e20..35620fece6bf 100644 --- a/sys/dev/enic/if_enic.c +++ b/sys/dev/enic/if_enic.c @@ -201,11 +201,11 @@ static struct if_shared_ctx enic_sctx_init = { * descriptor */ .isc_rx_nsegments = 1, /* One mapping per descriptor */ .isc_rx_maxsegsize = ENIC_DEFAULT_RX_MAX_PKT_SIZE, - .isc_admin_intrcnt = 3, + .isc_admin_intrcnt = 2, .isc_vendor_info = enic_vendor_info_array, .isc_driver_version = "1", .isc_driver = &enic_iflib_driver, - .isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ, + .isc_flags = IFLIB_HAS_RXCQ | IFLIB_HAS_TXCQ | IFLIB_SKIP_MSIX, /* * Number of receive queues per receive queue set, with associated @@ -236,6 +236,99 @@ enic_register(device_t dev) } static int +enic_allocate_msix(struct enic_softc *softc) { + if_ctx_t ctx; + if_softc_ctx_t scctx; + if_shared_ctx_t sctx; + device_t dev; + cpuset_t cpus; + int queues, vectors, requested; + int err = 0; + + dev = softc->dev; + ctx = softc->ctx; + scctx = softc->scctx; + sctx = iflib_get_sctx(ctx); + + if (bus_get_cpus(dev, INTR_CPUS, sizeof(cpus), &cpus) != 0) { + device_printf(dev, "Unable to fetch CPU list\n"); + CPU_COPY(&all_cpus, &cpus); + } + + + queues = CPU_COUNT(&cpus); + queues = imin(queues, scctx->isc_nrxqsets); + queues = imin(queues, scctx->isc_ntxqsets); + requested = queues * 2 + sctx->isc_admin_intrcnt; + scctx->isc_nrxqsets = queues; + scctx->isc_ntxqsets = queues; + + vectors = requested; + if ((err = pci_alloc_msix(dev, &vectors)) != 0) { + device_printf(dev, + "failed to allocate %d MSI-X vectors, err: %d\n", requested, + err); + err = 1; + goto enic_allocate_msix_out; + } else { + if (vectors != requested) { + device_printf(dev, + "Unable to allocate sufficient MSI-X vectors " + "(got %d, need %d)\n", requested, vectors); + pci_release_msi(dev); + err = 1; + goto enic_allocate_msix_out; + } + } + + device_printf(dev, "Using MSI-X interrupts with %d vectors\n", + vectors); + + scctx->isc_intr = IFLIB_INTR_MSIX; + scctx->isc_vectors = vectors; + +enic_allocate_msix_out: + return (err); + +} + +static struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = { + {0, 0}, /* 0 - 4 Gbps */ + {0, 3}, /* 4 - 10 Gbps */ + {3, 6}, /* 10 - 40 Gbps */ +}; + +static void enic_set_rx_coal_setting(struct enic *enic) +{ + unsigned int speed; + int index = -1; + struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting; + + /* 1. Read the link speed from fw + * 2. Pick the default range for the speed + * 3. Update it in enic->rx_coalesce_setting + */ + speed = vnic_dev_port_speed(enic->vdev); + if (ENIC_LINK_SPEED_10G < speed) + index = ENIC_LINK_40G_INDEX; + else if (ENIC_LINK_SPEED_4G < speed) + index = ENIC_LINK_10G_INDEX; + else + index = ENIC_LINK_4G_INDEX; + + rx_coal->small_pkt_range_start = mod_range[index].small_pkt_range_start; + rx_coal->large_pkt_range_start = mod_range[index].large_pkt_range_start; + rx_coal->range_end = ENIC_RX_COALESCE_RANGE_END; + + /* Start with the value provided by UCSM */ + for (index = 0; index < enic->rq_count; index++) + enic->cq[index].cur_rx_coal_timeval = + enic->config.intr_timer_usec; + + rx_coal->use_adaptive_rx_coalesce = 1; +} + +static int enic_attach_pre(if_ctx_t ctx) { if_softc_ctx_t scctx; @@ -283,6 +376,8 @@ enic_attach_pre(if_ctx_t ctx) ENIC_LOCK(softc); vnic_dev_register(vdev, &softc->mem, 1); enic->vdev = vdev; + vnic_dev_cmd_init(enic->vdev); + vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait); @@ -326,6 +421,7 @@ enic_attach_pre(if_ctx_t ctx) /* Set ingress vlan rewrite mode before vnic initialization */ enic->ig_vlan_rewrite_mode = IG_VLAN_REWRITE_MODE_UNTAG_DEFAULT_VLAN; + enic->ig_vlan_rewrite_mode = IG_VLAN_REWRITE_MODE_PRIORITY_TAG_DEFAULT_VLAN; err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev, enic->ig_vlan_rewrite_mode); if (err) { @@ -360,8 +456,10 @@ enic_attach_pre(if_ctx_t ctx) softc->scctx = iflib_get_softc_ctx(ctx); scctx = softc->scctx; scctx->isc_txrx = &enic_txrx; - scctx->isc_capabilities = scctx->isc_capenable = 0; + scctx->isc_capabilities = scctx->isc_capenable = \ + IFCAP_HWCSUM; scctx->isc_tx_csum_flags = 0; + if_setmtu(softc->ifp, enic->config.mtu); scctx->isc_max_frame_size = enic->config.mtu + ETHER_HDR_LEN + \ ETHER_CRC_LEN; scctx->isc_nrxqsets_max = enic->conf_rq_count; @@ -389,7 +487,6 @@ enic_attach_pre(if_ctx_t ctx) } scctx->isc_tx_nsegments = 31; - scctx->isc_vectors = enic->conf_cq_count; scctx->isc_msix_bar = -1; ifmedia_add(softc->media, IFM_ETHER | IFM_AUTO, 0, NULL); @@ -397,8 +494,7 @@ enic_attach_pre(if_ctx_t ctx) ifmedia_add(softc->media, IFM_ETHER | IFM_10_FL, 0, NULL); /* - * Allocate the CQ here since TX is called first before RX for now - * assume RX and TX are the same + * Allocate the CQ here since TX is called first before RX. */ if (softc->enic.cq == NULL) softc->enic.cq = malloc(sizeof(struct vnic_cq) * @@ -407,8 +503,6 @@ enic_attach_pre(if_ctx_t ctx) if (softc->enic.cq == NULL) return (ENOMEM); - softc->enic.cq->ntxqsets = softc->enic.wq_count + softc->enic.rq_count; - /* * Allocate the consistent memory for stats and counters upfront so * both primary and secondary processes can access them. @@ -416,12 +510,20 @@ enic_attach_pre(if_ctx_t ctx) err = vnic_dev_alloc_stats_mem(enic->vdev); if (err) { dev_err(enic, "Failed to allocate cmd memory, aborting\n"); + goto err_out_dev_close; + } + + err = enic_allocate_msix(softc); + if (err) { + dev_err(enic, "Failed to allocate MSIX, aborting\n"); + goto err_out_dev_close; } return (rc); err_out_dev_close: vnic_dev_close(enic->vdev); + vnic_dev_deinit_devcmd2(enic->vdev); err_out_unregister: free(softc->vdev.devcmd, M_DEVBUF); free(softc->enic.intr_queues, M_DEVBUF); @@ -482,9 +584,10 @@ enic_msix_intr_assign(if_ctx_t ctx, int msix) snprintf(irq_name, sizeof(irq_name), "etxq%d:%d", i - scctx->isc_nrxqsets, device_get_unit(softc->dev)); - - iflib_softirq_alloc_generic(ctx, &enic->intr_queues[i].intr_irq, IFLIB_INTR_TX, &enic->wq[i - scctx->isc_nrxqsets], i - scctx->isc_nrxqsets, irq_name); - + iflib_softirq_alloc_generic(ctx, + &enic->intr_queues[i].intr_irq, IFLIB_INTR_TX, + &enic->wq[i - scctx->isc_nrxqsets], i - scctx->isc_nrxqsets, + irq_name); enic->intr[i].index = i; enic->intr[i].vdev = enic->vdev; @@ -567,6 +670,7 @@ enic_attach_post(if_ctx_t ctx) enic_setup_sysctl(softc); enic_init_vnic_resources(enic); + enic_set_rx_coal_setting(enic); enic_setup_finish(enic); ifmedia_add(softc->media, IFM_ETHER | IFM_AUTO, 0, NULL); @@ -589,7 +693,9 @@ enic_detach(if_ctx_t ctx) enic_free_irqs(softc); ENIC_LOCK(softc); + vnic_dev_deinit(enic->vdev); vnic_dev_close(enic->vdev); + vnic_dev_deinit_devcmd2(enic->vdev); free(softc->vdev.devcmd, M_DEVBUF); pci_disable_busmaster(softc->dev); enic_pci_mapping_free(softc); @@ -626,7 +732,7 @@ enic_tx_queues_alloc(if_ctx_t ctx, caddr_t * vaddrs, uint64_t * paddrs, for (q = 0; q < ntxqsets; q++) { struct vnic_wq *wq; struct vnic_cq *cq; - unsigned int cq_wq; + unsigned int cq_wq; wq = &softc->enic.wq[q]; cq_wq = enic_cq_wq(&softc->enic, q); @@ -646,7 +752,6 @@ enic_tx_queues_alloc(if_ctx_t ctx, caddr_t * vaddrs, uint64_t * paddrs, wq->head_idx = 0; wq->tail_idx = 0; - wq->ring.size = wq->ring.desc_count * wq->ring.desc_size; wq->ring.descs = vaddrs[q * ntxqs + 0]; wq->ring.base_addr = paddrs[q * ntxqs + 0]; @@ -659,7 +764,6 @@ enic_tx_queues_alloc(if_ctx_t ctx, caddr_t * vaddrs, uint64_t * paddrs, cq->ring.desc_count = softc->scctx->isc_ntxd[q]; cq->ring.desc_avail = cq->ring.desc_count - 1; - cq->ring.size = cq->ring.desc_count * cq->ring.desc_size; cq->ring.descs = vaddrs[q * ntxqs + 1]; cq->ring.base_addr = paddrs[q * ntxqs + 1]; @@ -715,7 +819,6 @@ enic_rx_queues_alloc(if_ctx_t ctx, caddr_t * vaddrs, uint64_t * paddrs, cq->ring.desc_count = softc->scctx->isc_nrxd[1]; cq->ring.desc_avail = cq->ring.desc_count - 1; - cq->ring.size = cq->ring.desc_count * cq->ring.desc_size; cq->ring.descs = vaddrs[q * nrxqs + 0]; cq->ring.base_addr = paddrs[q * nrxqs + 0]; @@ -731,7 +834,6 @@ enic_rx_queues_alloc(if_ctx_t ctx, caddr_t * vaddrs, uint64_t * paddrs, rq->ring.desc_count = softc->scctx->isc_nrxd[0]; rq->ring.desc_avail = rq->ring.desc_count - 1; - rq->ring.size = rq->ring.desc_count * rq->ring.desc_size; rq->ring.descs = vaddrs[q * nrxqs + 1]; rq->ring.base_addr = paddrs[q * nrxqs + 1]; rq->need_initial_post = true; @@ -807,6 +909,11 @@ enic_stop(if_ctx_t ctx) struct enic *enic; if_softc_ctx_t scctx; unsigned int index; + struct vnic_wq *wq; + struct vnic_rq *rq; + struct vnic_cq *cq; + unsigned int cq_wq, cq_rq; + softc = iflib_get_softc(ctx); scctx = softc->scctx; @@ -817,15 +924,36 @@ enic_stop(if_ctx_t ctx) softc->link_active = 0; softc->stopped = 1; + enic_dev_disable(enic); + for (index = 0; index < scctx->isc_ntxqsets; index++) { enic_stop_wq(enic, index); vnic_wq_clean(&enic->wq[index]); vnic_cq_clean(&enic->cq[enic_cq_rq(enic, index)]); + + wq = &softc->enic.wq[index]; + wq->ring.desc_avail = wq->ring.desc_count - 1; + wq->ring.last_count = wq->ring.desc_count; + wq->head_idx = 0; + wq->tail_idx = 0; + + cq_wq = enic_cq_wq(&softc->enic, index); + cq = &softc->enic.cq[cq_wq]; + cq->ring.desc_avail = cq->ring.desc_count - 1; } for (index = 0; index < scctx->isc_nrxqsets; index++) { + enic_stop_rq(enic, index); vnic_rq_clean(&enic->rq[index]); vnic_cq_clean(&enic->cq[enic_cq_wq(enic, index)]); + + rq = &softc->enic.rq[index]; + cq_rq = enic_cq_rq(&softc->enic, index); + cq = &softc->enic.cq[cq_rq]; + + cq->ring.desc_avail = cq->ring.desc_count - 1; + rq->ring.desc_avail = rq->ring.desc_count - 1; + rq->need_initial_post = true; } for (index = 0; index < scctx->isc_vectors; index++) { @@ -845,6 +973,9 @@ enic_init(if_ctx_t ctx) scctx = softc->scctx; enic = &softc->enic; + + enic_init_vnic_resources(enic); + for (index = 0; index < scctx->isc_ntxqsets; index++) enic_prep_wq_for_simple_tx(&softc->enic, index); @@ -862,6 +993,8 @@ enic_init(if_ctx_t ctx) vnic_dev_enable_wait(enic->vdev); ENIC_UNLOCK(softc); + softc->stopped = 0; + enic_link_status(softc); } @@ -942,12 +1075,14 @@ enic_mtu_set(if_ctx_t ctx, uint32_t mtu) softc = iflib_get_softc(ctx); enic = &softc->enic; + enic_stop(softc->ctx); if (mtu > enic->port_mtu){ return (EINVAL); } enic->config.mtu = mtu; scctx->isc_max_frame_size = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + enic_init(softc->ctx); return (0); } @@ -1026,7 +1161,6 @@ static void enic_update_admin_status(if_ctx_t ctx) { struct enic_softc *softc; - softc = iflib_get_softc(ctx); enic_link_status(softc); @@ -1100,7 +1234,9 @@ enic_setup_txq_sysctl(struct vnic_wq *wq, int i, struct sysctl_ctx_list *ctx, { struct sysctl_oid *txsnode; struct sysctl_oid_list *txslist; - struct vnic_stats *stats = wq[i].vdev->stats; + struct vnic_stats *stats; + + stats = wq[i].vdev->stats; txsnode = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "hstats", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics"); @@ -1136,7 +1272,9 @@ enic_setup_rxq_sysctl(struct vnic_rq *rq, int i, struct sysctl_ctx_list *ctx, { struct sysctl_oid *rxsnode; struct sysctl_oid_list *rxslist; - struct vnic_stats *stats = rq[i].vdev->stats; + struct vnic_stats *stats; + + stats = rq[i].vdev->stats; rxsnode = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "hstats", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Host Statistics"); @@ -1357,7 +1495,7 @@ enic_dev_init(struct enic *enic) if (vnic_dev_overlay_offload_cfg(enic->vdev, OVERLAY_CFG_VXLAN_PORT_UPDATE, ENIC_DEFAULT_VXLAN_PORT)) { dev_err(enic, "failed to update vxlan port\n"); - return -EINVAL; + return (EINVAL); } } return 0; @@ -1441,7 +1579,7 @@ enic_dev_wait(struct vnic_dev *vdev, int (*start) (struct vnic_dev *, int), return 0; usleep(1000); } - return -ETIMEDOUT; + return (ETIMEDOUT); } static int @@ -1452,7 +1590,7 @@ enic_map_bar(struct enic_softc *softc, struct enic_bar_info *bar, int bar_num, if (bar->res != NULL) { device_printf(softc->dev, "Bar %d already mapped\n", bar_num); - return EDOOFUS; + return (EDOOFUS); } bar->rid = PCIR_BAR(bar_num); @@ -1481,20 +1619,18 @@ enic_init_vnic_resources(struct enic *enic) unsigned int rxq_interrupt_enable = 0; unsigned int rxq_interrupt_offset = ENICPMD_RXQ_INTR_OFFSET; unsigned int txq_interrupt_enable = 0; - unsigned int txq_interrupt_offset = ENICPMD_RXQ_INTR_OFFSET; + unsigned int txq_interrupt_offset; unsigned int index = 0; unsigned int cq_idx; if_softc_ctx_t scctx; scctx = enic->softc->scctx; - rxq_interrupt_enable = 1; - txq_interrupt_enable = 1; + txq_interrupt_enable = 0; rxq_interrupt_offset = 0; - txq_interrupt_offset = enic->intr_count - 2; - txq_interrupt_offset = 1; + txq_interrupt_offset = scctx->isc_nrxqsets; for (index = 0; index < enic->intr_count; index++) { vnic_intr_alloc(enic->vdev, &enic->intr[index], index); @@ -1568,7 +1704,7 @@ enic_update_packet_filter(struct enic *enic) } static bool -enic_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event) +enic_if_needs_restart(if_ctx_t ctx, enum iflib_restart_event event) { switch (event) { case IFLIB_RESTART_VLAN_CONFIG: diff --git a/sys/dev/enic/vnic_cq.c b/sys/dev/enic/vnic_cq.c index 72de29e5a381..bd3629530a61 100644 --- a/sys/dev/enic/vnic_cq.c +++ b/sys/dev/enic/vnic_cq.c @@ -40,6 +40,4 @@ void vnic_cq_clean(struct vnic_cq *cq) ENIC_BUS_WRITE_4(cq->ctrl, CQ_HEAD, 0); ENIC_BUS_WRITE_4(cq->ctrl, CQ_TAIL, 0); ENIC_BUS_WRITE_4(cq->ctrl, CQ_TAIL_COLOR, 1); - - vnic_dev_clear_desc_ring(&cq->ring); } diff --git a/sys/dev/enic/vnic_cq.h b/sys/dev/enic/vnic_cq.h index 26f9009612c5..7f875d57ed74 100644 --- a/sys/dev/enic/vnic_cq.h +++ b/sys/dev/enic/vnic_cq.h @@ -63,27 +63,22 @@ struct vnic_cq { unsigned int to_clean; unsigned int last_color; unsigned int interrupt_offset; + unsigned int cur_rx_coal_timeval; + unsigned int tobe_rx_coal_timeval; #ifdef ENIC_AIC struct vnic_rx_bytes_counter pkt_size_counter; unsigned int cur_rx_coal_timeval; unsigned int tobe_rx_coal_timeval; ktime_t prev_ts; #endif - int ntxqsets; - int nrxqsets; - int ntxqsets_start; - int nrxqsets_start; }; -void vnic_cq_free(struct vnic_cq *cq); void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, unsigned int cq_tail_color, unsigned int interrupt_enable, unsigned int cq_entry_enable, unsigned int message_enable, unsigned int interrupt_offset, u64 message_addr); void vnic_cq_clean(struct vnic_cq *cq); -int vnic_cq_mem_size(struct vnic_cq *cq, unsigned int desc_count, - unsigned int desc_size); static inline unsigned int vnic_cq_service(struct vnic_cq *cq, unsigned int work_to_do, 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); +} diff --git a/sys/dev/enic/vnic_dev.h b/sys/dev/enic/vnic_dev.h index f8ca29f4e175..66583f4d278d 100644 --- a/sys/dev/enic/vnic_dev.h +++ b/sys/dev/enic/vnic_dev.h @@ -38,6 +38,7 @@ struct vnic_dev_ring { unsigned int desc_count; unsigned int desc_avail; unsigned int last_count; + iflib_dma_info_t ifdip; }; struct vnic_dev_iomap_info { @@ -68,7 +69,10 @@ unsigned long vnic_dev_get_res_type_len(struct vnic_dev *vdev, enum vnic_res_type type); unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, unsigned int desc_count, unsigned int desc_size); -void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring); +int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, + unsigned int desc_count, unsigned int desc_size); +void vnic_dev_free_desc_ring(struct vnic_dev *vdev, + struct vnic_dev_ring *ring); int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, u64 *a0, u64 *a1, int wait); int vnic_dev_cmd_args(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, @@ -143,7 +147,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, struct rte_pci_device *vnic_dev_get_pdev(struct vnic_dev *vdev); int vnic_dev_alloc_stats_mem(struct vnic_dev *vdev); int vnic_dev_alloc_counter_mem(struct vnic_dev *vdev); -int vnic_dev_cmd_init(struct vnic_dev *vdev, int fallback); +int vnic_dev_cmd_init(struct vnic_dev *vdev); int vnic_dev_get_size(void); int vnic_dev_int13(struct vnic_dev *vdev, u64 arg, u32 op); int vnic_dev_perbi(struct vnic_dev *vdev, u64 arg, u32 op); @@ -164,6 +168,7 @@ bool vnic_dev_counter_alloc(struct vnic_dev *vdev, uint32_t *idx); bool vnic_dev_counter_free(struct vnic_dev *vdev, uint32_t idx); bool vnic_dev_counter_query(struct vnic_dev *vdev, uint32_t idx, bool reset, uint64_t *packets, uint64_t *bytes); +void vnic_dev_deinit_devcmd2(struct vnic_dev *vdev); device_t dev_from_vnic_dev(struct vnic_dev *vdev); diff --git a/sys/dev/enic/vnic_intr.c b/sys/dev/enic/vnic_intr.c index 38e2ea6e066b..8a6494efd5f3 100644 --- a/sys/dev/enic/vnic_intr.c +++ b/sys/dev/enic/vnic_intr.c @@ -21,7 +21,7 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index); if (!intr->ctrl) { pr_err("Failed to hook INTR[%d].ctrl resource\n", index); - return -EINVAL; + return (EINVAL); } return 0; diff --git a/sys/dev/enic/vnic_intr.h b/sys/dev/enic/vnic_intr.h index 22db66096aae..6d1e8e1cf050 100644 --- a/sys/dev/enic/vnic_intr.h +++ b/sys/dev/enic/vnic_intr.h @@ -76,7 +76,7 @@ static inline void vnic_intr_return_credits(struct vnic_intr *intr, static inline unsigned int vnic_intr_credits(struct vnic_intr *intr) { - return ENIC_BUS_READ_4(intr->ctrl, INTR_CREDITS); + return (ENIC_BUS_READ_4(intr->ctrl, INTR_CREDITS)); } static inline void vnic_intr_return_all_credits(struct vnic_intr *intr) diff --git a/sys/dev/enic/vnic_resource.h b/sys/dev/enic/vnic_resource.h index 184bfa7401df..d365b8d914ba 100644 --- a/sys/dev/enic/vnic_resource.h +++ b/sys/dev/enic/vnic_resource.h @@ -39,6 +39,7 @@ enum vnic_res_type { RES_TYPE_MQ_RQ, /* MQ Receive queues */ RES_TYPE_MQ_CQ, /* MQ Completion queues */ RES_TYPE_DEPRECATED1, /* Old version of devcmd 2 */ + RES_TYPE_DEPRECATED2, /* Old version of devcmd 2 */ RES_TYPE_DEVCMD2, /* Device control region */ RES_TYPE_MAX, /* Count of resource types */ }; diff --git a/sys/dev/enic/vnic_rq.c b/sys/dev/enic/vnic_rq.c index 3720da5f9aa6..4c02347579b1 100644 --- a/sys/dev/enic/vnic_rq.c +++ b/sys/dev/enic/vnic_rq.c @@ -40,6 +40,7 @@ void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, fetch_index = 0; } + fetch_index = 0; vnic_rq_init_start(rq, cq_index, fetch_index, fetch_index, error_interrupt_enable, @@ -50,7 +51,7 @@ void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, unsigned int vnic_rq_error_status(struct vnic_rq *rq) { - return ENIC_BUS_READ_4(rq->ctrl, RX_ERROR_STATUS); + return (ENIC_BUS_READ_4(rq->ctrl, RX_ERROR_STATUS)); } void vnic_rq_enable(struct vnic_rq *rq) @@ -73,7 +74,7 @@ int vnic_rq_disable(struct vnic_rq *rq) pr_err("Failed to disable RQ[%d]\n", rq->index); - return -ETIMEDOUT; + return (ETIMEDOUT); } void vnic_rq_clean(struct vnic_rq *rq) @@ -92,6 +93,4 @@ void vnic_rq_clean(struct vnic_rq *rq) } ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, fetch_index); - - vnic_dev_clear_desc_ring(&rq->ring); } diff --git a/sys/dev/enic/vnic_rq.h b/sys/dev/enic/vnic_rq.h index ae8c1fdc39bd..9e3d239809c4 100644 --- a/sys/dev/enic/vnic_rq.h +++ b/sys/dev/enic/vnic_rq.h @@ -133,7 +133,6 @@ void vnic_rq_init_start(struct vnic_rq *rq, unsigned int cq_index, void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset); -void vnic_rq_error_out(struct vnic_rq *rq, unsigned int error); unsigned int vnic_rq_error_status(struct vnic_rq *rq); void vnic_rq_enable(struct vnic_rq *rq); int vnic_rq_disable(struct vnic_rq *rq); diff --git a/sys/dev/enic/vnic_rss.h b/sys/dev/enic/vnic_rss.h index abd7b9f131aa..039041ece5b2 100644 --- a/sys/dev/enic/vnic_rss.h +++ b/sys/dev/enic/vnic_rss.h @@ -24,9 +24,4 @@ union vnic_rss_cpu { u64 raw[32]; }; -void vnic_set_rss_key(union vnic_rss_key *rss_key, u8 *key); -void vnic_set_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu); -void vnic_get_rss_key(union vnic_rss_key *rss_key, u8 *key); -void vnic_get_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu); - #endif /* _VNIC_RSS_H_ */ diff --git a/sys/dev/enic/vnic_wq.c b/sys/dev/enic/vnic_wq.c index b032df3392b2..1d3120798798 100644 --- a/sys/dev/enic/vnic_wq.c +++ b/sys/dev/enic/vnic_wq.c @@ -7,7 +7,103 @@ #include "vnic_dev.h" #include "vnic_wq.h" -void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, +int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, + struct vnic_dev_ring *ring, unsigned int desc_count, unsigned int desc_size) +{ + iflib_dma_info_t ifdip; + int err; + + if ((ifdip = malloc(sizeof(struct iflib_dma_info), + M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { + device_printf(dev_from_vnic_dev(vdev), + "Unable to allocate DMA info memory\n"); + return (ENOMEM); + } + + err = iflib_dma_alloc(vdev->softc->ctx, desc_count * desc_size, + ifdip, 0); + if (err) { + device_printf(dev_from_vnic_dev(vdev), + "Unable to allocate DEVCMD2 descriptors\n"); + err = ENOMEM; + goto err_out_alloc; + } + + ring->base_addr = ifdip->idi_paddr; + ring->descs = ifdip->idi_vaddr; + ring->ifdip = ifdip; + ring->desc_size = desc_size; + ring->desc_count = desc_count; + ring->last_count = 0; + ring->desc_avail = ring->desc_count - 1; + + ring->base_align = 512; + ring->size_unaligned = ring->desc_count * ring->desc_size \ + + ring->base_align; + + return (err); + + iflib_dma_free(ifdip); + +err_out_alloc: + free(ifdip, M_DEVBUF); + return (err); +} + +void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring) +{ + if (ring && ring->descs) { + iflib_dma_free(ring->ifdip); + free(ring->ifdip, M_DEVBUF); + ring->descs = NULL; + } +} + +void vnic_wq_free(struct vnic_wq *wq) { + vnic_dev_free_desc_ring(wq->vdev, &wq->ring); + wq->ctrl = NULL; +} + +int enic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, + unsigned int desc_count, unsigned int desc_size) +{ + int err; + + wq->index = 0; + wq->vdev = vdev; + + + wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0); + if (!wq->ctrl) + return (EINVAL); + vnic_wq_disable(wq); + err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); + + return (err); +} + +void vnic_dev_deinit_devcmd2(struct vnic_dev *vdev) +{ + if (vdev->devcmd2) { + vnic_wq_disable(&vdev->devcmd2->wq); + 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; + } +} + +int vnic_dev_deinit(struct vnic_dev *vdev) { + u64 a0 = 0, a1 = 0; + int wait = 1000; + + return (vnic_dev_cmd(vdev, CMD_DEINIT, &a0, &a1, wait)); + return (0); +} + +void enic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, unsigned int fetch_index, unsigned int posted_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset) @@ -33,7 +129,7 @@ void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset) { - vnic_wq_init_start(wq, cq_index, 0, 0, + enic_wq_init_start(wq, cq_index, 0, 0, error_interrupt_enable, error_interrupt_offset); wq->cq_pend = 0; @@ -42,7 +138,7 @@ void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, unsigned int vnic_wq_error_status(struct vnic_wq *wq) { - return ENIC_BUS_READ_4(wq->ctrl, TX_ERROR_STATUS); + return (ENIC_BUS_READ_4(wq->ctrl, TX_ERROR_STATUS)); } void vnic_wq_enable(struct vnic_wq *wq) @@ -65,7 +161,7 @@ int vnic_wq_disable(struct vnic_wq *wq) pr_err("Failed to disable WQ[%d]\n", wq->index); - return -ETIMEDOUT; + return (ETIMEDOUT); } void vnic_wq_clean(struct vnic_wq *wq) @@ -84,6 +180,4 @@ void vnic_wq_clean(struct vnic_wq *wq) ENIC_BUS_WRITE_4(wq->ctrl, TX_FETCH_INDEX, 0); ENIC_BUS_WRITE_4(wq->ctrl, TX_POSTED_INDEX, 0); ENIC_BUS_WRITE_4(wq->ctrl, TX_ERROR_STATUS, 0); - - vnic_dev_clear_desc_ring(&wq->ring); } diff --git a/sys/dev/enic/vnic_wq.h b/sys/dev/enic/vnic_wq.h index c4f551de8441..9ef492adba24 100644 --- a/sys/dev/enic/vnic_wq.h +++ b/sys/dev/enic/vnic_wq.h @@ -61,6 +61,20 @@ struct vnic_wq { uint64_t offloads; }; +struct devcmd2_controller { + struct vnic_res *wq_ctrl; + struct vnic_devcmd2 *cmd_ring; + struct devcmd2_result *result; + u16 next_result; + u16 result_size; + int color; + struct vnic_dev_ring results_ring; + struct vnic_res *results_ctrl; + struct vnic_wq wq; + u32 posted; +}; + + static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq) { /* how many does SW own? */ @@ -92,7 +106,7 @@ buf_idx_incr(uint32_t n_descriptors, uint32_t idx) } void vnic_wq_free(struct vnic_wq *wq); -void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, +void enic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, unsigned int fetch_index, unsigned int posted_index, unsigned int error_interrupt_enable, unsigned int error_interrupt_offset); @@ -104,5 +118,7 @@ unsigned int vnic_wq_error_status(struct vnic_wq *wq); void vnic_wq_enable(struct vnic_wq *wq); int vnic_wq_disable(struct vnic_wq *wq); void vnic_wq_clean(struct vnic_wq *wq); +int enic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, + unsigned int desc_count, unsigned int desc_size); #endif /* _VNIC_WQ_H_ */ |