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 "opt_rss.h" 79c067b84SDoug Ambrisko 89c067b84SDoug Ambrisko #include <sys/param.h> 99c067b84SDoug Ambrisko #include <sys/systm.h> 109c067b84SDoug Ambrisko #include <sys/kernel.h> 119c067b84SDoug Ambrisko #include <sys/endian.h> 129c067b84SDoug Ambrisko #include <sys/sockio.h> 139c067b84SDoug Ambrisko #include <sys/mbuf.h> 149c067b84SDoug Ambrisko #include <sys/malloc.h> 159c067b84SDoug Ambrisko #include <sys/module.h> 169c067b84SDoug Ambrisko #include <sys/socket.h> 179c067b84SDoug Ambrisko #include <sys/sysctl.h> 189c067b84SDoug Ambrisko #include <sys/smp.h> 199c067b84SDoug Ambrisko #include <vm/vm.h> 209c067b84SDoug Ambrisko #include <vm/pmap.h> 219c067b84SDoug Ambrisko 229c067b84SDoug Ambrisko #include <net/ethernet.h> 239c067b84SDoug Ambrisko #include <net/if.h> 249c067b84SDoug Ambrisko #include <net/if_var.h> 259c067b84SDoug Ambrisko #include <net/if_arp.h> 269c067b84SDoug Ambrisko #include <net/if_dl.h> 279c067b84SDoug Ambrisko #include <net/if_types.h> 289c067b84SDoug Ambrisko #include <net/if_media.h> 299c067b84SDoug Ambrisko #include <net/if_vlan_var.h> 309c067b84SDoug Ambrisko #include <net/iflib.h> 319c067b84SDoug Ambrisko #ifdef RSS 329c067b84SDoug Ambrisko #include <net/rss_config.h> 339c067b84SDoug Ambrisko #endif 349c067b84SDoug Ambrisko 359c067b84SDoug Ambrisko #include <netinet/in_systm.h> 369c067b84SDoug Ambrisko #include <netinet/in.h> 379c067b84SDoug Ambrisko #include <netinet/ip.h> 389c067b84SDoug Ambrisko #include <netinet/ip6.h> 399c067b84SDoug Ambrisko #include <netinet6/ip6_var.h> 409c067b84SDoug Ambrisko #include <netinet/udp.h> 419c067b84SDoug Ambrisko #include <netinet/tcp.h> 429c067b84SDoug Ambrisko 439c067b84SDoug Ambrisko #include <machine/bus.h> 449c067b84SDoug Ambrisko #include <machine/resource.h> 459c067b84SDoug Ambrisko #include <sys/bus.h> 469c067b84SDoug Ambrisko #include <sys/rman.h> 479c067b84SDoug Ambrisko 489c067b84SDoug Ambrisko #include <dev/pci/pcireg.h> 499c067b84SDoug Ambrisko #include <dev/pci/pcivar.h> 509c067b84SDoug Ambrisko 519c067b84SDoug Ambrisko #include "ifdi_if.h" 529c067b84SDoug Ambrisko #include "enic.h" 539c067b84SDoug Ambrisko 549c067b84SDoug Ambrisko #include "opt_inet.h" 559c067b84SDoug Ambrisko #include "opt_inet6.h" 569c067b84SDoug Ambrisko 579c067b84SDoug Ambrisko static int enic_isc_txd_encap(void *, if_pkt_info_t); 589c067b84SDoug Ambrisko static void enic_isc_txd_flush(void *, uint16_t, qidx_t); 599c067b84SDoug Ambrisko static int enic_isc_txd_credits_update(void *, uint16_t, bool); 609c067b84SDoug Ambrisko static int enic_isc_rxd_available(void *, uint16_t, qidx_t, qidx_t); 619c067b84SDoug Ambrisko static int enic_isc_rxd_pkt_get(void *, if_rxd_info_t); 629c067b84SDoug Ambrisko static void enic_isc_rxd_refill(void *, if_rxd_update_t); 639c067b84SDoug Ambrisko static void enic_isc_rxd_flush(void *, uint16_t, uint8_t, qidx_t); 649c067b84SDoug Ambrisko static int enic_legacy_intr(void *); 659c067b84SDoug Ambrisko static void enic_initial_post_rx(struct enic *, struct vnic_rq *); 669c067b84SDoug Ambrisko static int enic_wq_service(struct vnic_dev *, struct cq_desc *, u8, u16, u16, 679c067b84SDoug Ambrisko void *); 689c067b84SDoug Ambrisko static int enic_rq_service(struct vnic_dev *, struct cq_desc *, u8, u16, u16, 699c067b84SDoug Ambrisko void *); 709c067b84SDoug Ambrisko 719c067b84SDoug Ambrisko struct if_txrx enic_txrx = { 729c067b84SDoug Ambrisko .ift_txd_encap = enic_isc_txd_encap, 739c067b84SDoug Ambrisko .ift_txd_flush = enic_isc_txd_flush, 749c067b84SDoug Ambrisko .ift_txd_credits_update = enic_isc_txd_credits_update, 759c067b84SDoug Ambrisko .ift_rxd_available = enic_isc_rxd_available, 769c067b84SDoug Ambrisko .ift_rxd_pkt_get = enic_isc_rxd_pkt_get, 779c067b84SDoug Ambrisko .ift_rxd_refill = enic_isc_rxd_refill, 789c067b84SDoug Ambrisko .ift_rxd_flush = enic_isc_rxd_flush, 799c067b84SDoug Ambrisko .ift_legacy_intr = enic_legacy_intr 809c067b84SDoug Ambrisko }; 819c067b84SDoug Ambrisko 829c067b84SDoug Ambrisko static int 839c067b84SDoug Ambrisko enic_isc_txd_encap(void *vsc, if_pkt_info_t pi) 849c067b84SDoug Ambrisko { 859c067b84SDoug Ambrisko struct enic_softc *softc; 869c067b84SDoug Ambrisko struct enic *enic; 879c067b84SDoug Ambrisko struct vnic_wq *wq; 889c067b84SDoug Ambrisko int nsegs; 899c067b84SDoug Ambrisko int i; 909c067b84SDoug Ambrisko 919c067b84SDoug Ambrisko struct wq_enet_desc *desc; 929c067b84SDoug Ambrisko uint64_t bus_addr; 939c067b84SDoug Ambrisko uint16_t mss = 7; 949c067b84SDoug Ambrisko uint16_t header_len = 0; 959c067b84SDoug Ambrisko uint8_t offload_mode = 0; 969c067b84SDoug Ambrisko uint8_t eop = 0, cq; 979c067b84SDoug Ambrisko uint8_t vlan_tag_insert = 0; 989c067b84SDoug Ambrisko unsigned short vlan_id = 0; 999c067b84SDoug Ambrisko 1009c067b84SDoug Ambrisko unsigned int wq_desc_avail; 1019c067b84SDoug Ambrisko int head_idx; 1029c067b84SDoug Ambrisko unsigned int desc_count, data_len; 1039c067b84SDoug Ambrisko 1049c067b84SDoug Ambrisko softc = vsc; 1059c067b84SDoug Ambrisko enic = &softc->enic; 106*0acab8b3SDoug Ambrisko if_softc_ctx_t scctx = softc->scctx; 1079c067b84SDoug Ambrisko 1089c067b84SDoug Ambrisko wq = &enic->wq[pi->ipi_qsidx]; 1099c067b84SDoug Ambrisko nsegs = pi->ipi_nsegs; 1109c067b84SDoug Ambrisko 1119c067b84SDoug Ambrisko ENIC_LOCK(softc); 1129c067b84SDoug Ambrisko wq_desc_avail = vnic_wq_desc_avail(wq); 1139c067b84SDoug Ambrisko head_idx = wq->head_idx; 1149c067b84SDoug Ambrisko desc_count = wq->ring.desc_count; 1159c067b84SDoug Ambrisko 116*0acab8b3SDoug Ambrisko if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0) 117*0acab8b3SDoug Ambrisko offload_mode |= WQ_ENET_OFFLOAD_MODE_CSUM; 118*0acab8b3SDoug Ambrisko 1199c067b84SDoug Ambrisko for (i = 0; i < nsegs; i++) { 1209c067b84SDoug Ambrisko eop = 0; 1219c067b84SDoug Ambrisko cq = 0; 1229c067b84SDoug Ambrisko wq->cq_pend++; 1239c067b84SDoug Ambrisko if (i + 1 == nsegs) { 1249c067b84SDoug Ambrisko eop = 1; 1259c067b84SDoug Ambrisko cq = 1; 1269c067b84SDoug Ambrisko wq->cq_pend = 0; 1279c067b84SDoug Ambrisko } 1289c067b84SDoug Ambrisko desc = wq->ring.descs; 1299c067b84SDoug Ambrisko bus_addr = pi->ipi_segs[i].ds_addr; 1309c067b84SDoug Ambrisko data_len = pi->ipi_segs[i].ds_len; 1319c067b84SDoug Ambrisko 1329c067b84SDoug Ambrisko wq_enet_desc_enc(&desc[head_idx], bus_addr, data_len, mss, 1339c067b84SDoug Ambrisko header_len, offload_mode, eop, cq, 0, 1349c067b84SDoug Ambrisko vlan_tag_insert, vlan_id, 0); 1359c067b84SDoug Ambrisko 1369c067b84SDoug Ambrisko head_idx = enic_ring_incr(desc_count, head_idx); 1379c067b84SDoug Ambrisko wq_desc_avail--; 1389c067b84SDoug Ambrisko } 1399c067b84SDoug Ambrisko 1409c067b84SDoug Ambrisko wq->ring.desc_avail = wq_desc_avail; 1419c067b84SDoug Ambrisko wq->head_idx = head_idx; 1429c067b84SDoug Ambrisko 1439c067b84SDoug Ambrisko pi->ipi_new_pidx = head_idx; 1449c067b84SDoug Ambrisko ENIC_UNLOCK(softc); 1459c067b84SDoug Ambrisko 1469c067b84SDoug Ambrisko return (0); 1479c067b84SDoug Ambrisko } 1489c067b84SDoug Ambrisko 1499c067b84SDoug Ambrisko static void 1509c067b84SDoug Ambrisko enic_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx) 1519c067b84SDoug Ambrisko { 1529c067b84SDoug Ambrisko struct enic_softc *softc; 1539c067b84SDoug Ambrisko struct enic *enic; 1549c067b84SDoug Ambrisko struct vnic_wq *wq; 1559c067b84SDoug Ambrisko int head_idx; 1569c067b84SDoug Ambrisko 1579c067b84SDoug Ambrisko softc = vsc; 1589c067b84SDoug Ambrisko enic = &softc->enic; 1599c067b84SDoug Ambrisko 1609c067b84SDoug Ambrisko ENIC_LOCK(softc); 1619c067b84SDoug Ambrisko wq = &enic->wq[txqid]; 1629c067b84SDoug Ambrisko head_idx = wq->head_idx; 1639c067b84SDoug Ambrisko 1649c067b84SDoug Ambrisko ENIC_BUS_WRITE_4(wq->ctrl, TX_POSTED_INDEX, head_idx); 1659c067b84SDoug Ambrisko ENIC_UNLOCK(softc); 1669c067b84SDoug Ambrisko } 1679c067b84SDoug Ambrisko 1689c067b84SDoug Ambrisko static int 1699c067b84SDoug Ambrisko enic_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear) 1709c067b84SDoug Ambrisko { 1719c067b84SDoug Ambrisko 1729c067b84SDoug Ambrisko struct enic_softc *softc; 1739c067b84SDoug Ambrisko struct enic *enic; 1749c067b84SDoug Ambrisko struct vnic_wq *wq; 1759c067b84SDoug Ambrisko struct vnic_cq *cq; 1769c067b84SDoug Ambrisko int processed; 1779c067b84SDoug Ambrisko unsigned int cq_wq; 1789c067b84SDoug Ambrisko unsigned int wq_work_to_do = 10; 1799c067b84SDoug Ambrisko unsigned int wq_work_avail; 1809c067b84SDoug Ambrisko 1819c067b84SDoug Ambrisko softc = vsc; 1829c067b84SDoug Ambrisko enic = &softc->enic; 1839c067b84SDoug Ambrisko wq = &softc->enic.wq[txqid]; 1849c067b84SDoug Ambrisko 1859c067b84SDoug Ambrisko cq_wq = enic_cq_wq(enic, txqid); 1869c067b84SDoug Ambrisko cq = &enic->cq[cq_wq]; 1879c067b84SDoug Ambrisko 1889c067b84SDoug Ambrisko ENIC_LOCK(softc); 1899c067b84SDoug Ambrisko wq_work_avail = vnic_cq_work(cq, wq_work_to_do); 1909c067b84SDoug Ambrisko ENIC_UNLOCK(softc); 1919c067b84SDoug Ambrisko 1929c067b84SDoug Ambrisko if (wq_work_avail == 0) 1939c067b84SDoug Ambrisko return (0); 1949c067b84SDoug Ambrisko 1959c067b84SDoug Ambrisko if (!clear) 1969c067b84SDoug Ambrisko return (1); 1979c067b84SDoug Ambrisko 1989c067b84SDoug Ambrisko ENIC_LOCK(softc); 1999c067b84SDoug Ambrisko vnic_cq_service(cq, wq_work_to_do, 2009c067b84SDoug Ambrisko enic_wq_service, NULL); 2019c067b84SDoug Ambrisko 2029c067b84SDoug Ambrisko processed = wq->processed; 2039c067b84SDoug Ambrisko wq->processed = 0; 2049c067b84SDoug Ambrisko 2059c067b84SDoug Ambrisko ENIC_UNLOCK(softc); 2069c067b84SDoug Ambrisko 2079c067b84SDoug Ambrisko return (processed); 2089c067b84SDoug Ambrisko } 2099c067b84SDoug Ambrisko 2109c067b84SDoug Ambrisko static int 2119c067b84SDoug Ambrisko enic_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget) 2129c067b84SDoug Ambrisko { 2139c067b84SDoug Ambrisko struct enic_softc *softc; 2149c067b84SDoug Ambrisko struct enic *enic; 2159c067b84SDoug Ambrisko struct vnic_cq *cq; 2169c067b84SDoug Ambrisko unsigned int rq_work_to_do = budget; 2179c067b84SDoug Ambrisko unsigned int rq_work_avail = 0; 2189c067b84SDoug Ambrisko unsigned int cq_rq; 2199c067b84SDoug Ambrisko 2209c067b84SDoug Ambrisko softc = vsc; 2219c067b84SDoug Ambrisko enic = &softc->enic; 2229c067b84SDoug Ambrisko 2239c067b84SDoug Ambrisko cq_rq = enic_cq_rq(&softc->enic, rxqid); 2249c067b84SDoug Ambrisko cq = &enic->cq[cq_rq]; 2259c067b84SDoug Ambrisko 2269c067b84SDoug Ambrisko rq_work_avail = vnic_cq_work(cq, rq_work_to_do); 2279c067b84SDoug Ambrisko return rq_work_avail; 2289c067b84SDoug Ambrisko } 2299c067b84SDoug Ambrisko 2309c067b84SDoug Ambrisko static int 2319c067b84SDoug Ambrisko enic_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri) 2329c067b84SDoug Ambrisko { 2339c067b84SDoug Ambrisko struct enic_softc *softc; 2349c067b84SDoug Ambrisko struct enic *enic; 2359c067b84SDoug Ambrisko struct vnic_cq *cq; 2369c067b84SDoug Ambrisko unsigned int rq_work_to_do = 1; 2379c067b84SDoug Ambrisko unsigned int rq_work_done = 0; 2389c067b84SDoug Ambrisko unsigned int cq_rq; 2399c067b84SDoug Ambrisko 2409c067b84SDoug Ambrisko softc = vsc; 2419c067b84SDoug Ambrisko enic = &softc->enic; 2429c067b84SDoug Ambrisko 2439c067b84SDoug Ambrisko cq_rq = enic_cq_rq(&softc->enic, ri->iri_qsidx); 2449c067b84SDoug Ambrisko cq = &enic->cq[cq_rq]; 2459c067b84SDoug Ambrisko ENIC_LOCK(softc); 2469c067b84SDoug Ambrisko rq_work_done = vnic_cq_service(cq, rq_work_to_do, enic_rq_service, ri); 2479c067b84SDoug Ambrisko 2489c067b84SDoug Ambrisko if (rq_work_done != 0) { 2499c067b84SDoug Ambrisko vnic_intr_return_credits(&enic->intr[cq_rq], rq_work_done, 0, 2509c067b84SDoug Ambrisko 1); 2519c067b84SDoug Ambrisko ENIC_UNLOCK(softc); 2529c067b84SDoug Ambrisko return (0); 2539c067b84SDoug Ambrisko } else { 2549c067b84SDoug Ambrisko ENIC_UNLOCK(softc); 2559c067b84SDoug Ambrisko return (-1); 2569c067b84SDoug Ambrisko } 2579c067b84SDoug Ambrisko 2589c067b84SDoug Ambrisko } 2599c067b84SDoug Ambrisko 2609c067b84SDoug Ambrisko static void 2619c067b84SDoug Ambrisko enic_isc_rxd_refill(void *vsc, if_rxd_update_t iru) 2629c067b84SDoug Ambrisko { 2639c067b84SDoug Ambrisko struct enic_softc *softc; 2649c067b84SDoug Ambrisko struct vnic_rq *rq; 2659c067b84SDoug Ambrisko struct rq_enet_desc *rqd; 2669c067b84SDoug Ambrisko 2679c067b84SDoug Ambrisko uint64_t *paddrs; 2689c067b84SDoug Ambrisko int count; 2699c067b84SDoug Ambrisko uint32_t pidx; 2709c067b84SDoug Ambrisko int len; 2719c067b84SDoug Ambrisko int idx; 2729c067b84SDoug Ambrisko int i; 2739c067b84SDoug Ambrisko 2749c067b84SDoug Ambrisko count = iru->iru_count; 2759c067b84SDoug Ambrisko len = iru->iru_buf_size; 2769c067b84SDoug Ambrisko paddrs = iru->iru_paddrs; 2779c067b84SDoug Ambrisko pidx = iru->iru_pidx; 2789c067b84SDoug Ambrisko 2799c067b84SDoug Ambrisko softc = vsc; 2809c067b84SDoug Ambrisko rq = &softc->enic.rq[iru->iru_qsidx]; 2819c067b84SDoug Ambrisko rqd = rq->ring.descs; 2829c067b84SDoug Ambrisko 2839c067b84SDoug Ambrisko idx = pidx; 2849c067b84SDoug Ambrisko for (i = 0; i < count; i++, idx++) { 2859c067b84SDoug Ambrisko 2869c067b84SDoug Ambrisko if (idx == rq->ring.desc_count) 2879c067b84SDoug Ambrisko idx = 0; 2889c067b84SDoug Ambrisko rq_enet_desc_enc(&rqd[idx], paddrs[i], 2899c067b84SDoug Ambrisko RQ_ENET_TYPE_ONLY_SOP, 2909c067b84SDoug Ambrisko len); 2919c067b84SDoug Ambrisko 2929c067b84SDoug Ambrisko } 2939c067b84SDoug Ambrisko 2949c067b84SDoug Ambrisko rq->in_use = 1; 2959c067b84SDoug Ambrisko 2969c067b84SDoug Ambrisko if (rq->need_initial_post) { 2979c067b84SDoug Ambrisko ENIC_BUS_WRITE_4(rq->ctrl, RX_FETCH_INDEX, 0); 2989c067b84SDoug Ambrisko } 2999c067b84SDoug Ambrisko 3009c067b84SDoug Ambrisko enic_initial_post_rx(&softc->enic, rq); 3019c067b84SDoug Ambrisko } 3029c067b84SDoug Ambrisko 3039c067b84SDoug Ambrisko static void 3049c067b84SDoug Ambrisko enic_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx) 3059c067b84SDoug Ambrisko { 3069c067b84SDoug Ambrisko 3079c067b84SDoug Ambrisko struct enic_softc *softc; 3089c067b84SDoug Ambrisko struct vnic_rq *rq; 3099c067b84SDoug Ambrisko 3109c067b84SDoug Ambrisko softc = vsc; 3119c067b84SDoug Ambrisko rq = &softc->enic.rq[rxqid]; 3129c067b84SDoug Ambrisko 3139c067b84SDoug Ambrisko /* 3149c067b84SDoug Ambrisko * pidx is the index of the last descriptor with a buffer the device 3159c067b84SDoug Ambrisko * can use, and the device needs to be told which index is one past 3169c067b84SDoug Ambrisko * that. 3179c067b84SDoug Ambrisko */ 3189c067b84SDoug Ambrisko 3199c067b84SDoug Ambrisko ENIC_LOCK(softc); 3209c067b84SDoug Ambrisko ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, pidx); 3219c067b84SDoug Ambrisko ENIC_UNLOCK(softc); 3229c067b84SDoug Ambrisko } 3239c067b84SDoug Ambrisko 3249c067b84SDoug Ambrisko static int 3259c067b84SDoug Ambrisko enic_legacy_intr(void *xsc) 3269c067b84SDoug Ambrisko { 327*0acab8b3SDoug Ambrisko return (1); 3289c067b84SDoug Ambrisko } 3299c067b84SDoug Ambrisko 3309c067b84SDoug Ambrisko static inline void 3319c067b84SDoug Ambrisko vnic_wq_service(struct vnic_wq *wq, struct cq_desc *cq_desc, 3329c067b84SDoug Ambrisko u16 completed_index, void (*buf_service) (struct vnic_wq *wq, 3339c067b84SDoug Ambrisko struct cq_desc *cq_desc, /* struct vnic_wq_buf * *buf, */ void *opaque), 3349c067b84SDoug Ambrisko void *opaque) 3359c067b84SDoug Ambrisko { 3369c067b84SDoug Ambrisko int processed; 3379c067b84SDoug Ambrisko 3389c067b84SDoug Ambrisko processed = completed_index - wq->ring.last_count; 3399c067b84SDoug Ambrisko if (processed < 0) 3409c067b84SDoug Ambrisko processed += wq->ring.desc_count; 3419c067b84SDoug Ambrisko if (processed == 0) 3429c067b84SDoug Ambrisko processed++; 3439c067b84SDoug Ambrisko 3449c067b84SDoug Ambrisko wq->ring.desc_avail += processed; 3459c067b84SDoug Ambrisko wq->processed += processed; 3469c067b84SDoug Ambrisko wq->ring.last_count = completed_index; 3479c067b84SDoug Ambrisko } 3489c067b84SDoug Ambrisko 3499c067b84SDoug Ambrisko /* 3509c067b84SDoug Ambrisko * Post the Rx buffers for the first time. enic_alloc_rx_queue_mbufs() has 3519c067b84SDoug Ambrisko * allocated the buffers and filled the RQ descriptor ring. Just need to push 3529c067b84SDoug Ambrisko * the post index to the NIC. 3539c067b84SDoug Ambrisko */ 3549c067b84SDoug Ambrisko static void 3559c067b84SDoug Ambrisko enic_initial_post_rx(struct enic *enic, struct vnic_rq *rq) 3569c067b84SDoug Ambrisko { 3579c067b84SDoug Ambrisko struct enic_softc *softc = enic->softc; 3589c067b84SDoug Ambrisko if (!rq->in_use || !rq->need_initial_post) 3599c067b84SDoug Ambrisko return; 3609c067b84SDoug Ambrisko 3619c067b84SDoug Ambrisko ENIC_LOCK(softc); 3629c067b84SDoug Ambrisko /* make sure all prior writes are complete before doing the PIO write */ 3639c067b84SDoug Ambrisko /* Post all but the last buffer to VIC. */ 3649c067b84SDoug Ambrisko rq->posted_index = rq->ring.desc_count - 1; 3659c067b84SDoug Ambrisko 3669c067b84SDoug Ambrisko rq->rx_nb_hold = 0; 3679c067b84SDoug Ambrisko 3689c067b84SDoug Ambrisko ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, rq->posted_index); 3699c067b84SDoug Ambrisko 3709c067b84SDoug Ambrisko rq->need_initial_post = false; 3719c067b84SDoug Ambrisko ENIC_UNLOCK(softc); 3729c067b84SDoug Ambrisko } 3739c067b84SDoug Ambrisko 3749c067b84SDoug Ambrisko static int 3759c067b84SDoug Ambrisko enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, u8 type, 3769c067b84SDoug Ambrisko u16 q_number, u16 completed_index, void *opaque) 3779c067b84SDoug Ambrisko { 3789c067b84SDoug Ambrisko struct enic *enic = vnic_dev_priv(vdev); 3799c067b84SDoug Ambrisko 3809c067b84SDoug Ambrisko vnic_wq_service(&enic->wq[q_number], cq_desc, 3819c067b84SDoug Ambrisko completed_index, NULL, opaque); 382*0acab8b3SDoug Ambrisko return (0); 3839c067b84SDoug Ambrisko } 3849c067b84SDoug Ambrisko 3859c067b84SDoug Ambrisko static void 3869c067b84SDoug Ambrisko vnic_rq_service(struct vnic_rq *rq, struct cq_desc *cq_desc, 3879c067b84SDoug Ambrisko u16 in_completed_index, int desc_return, 3889c067b84SDoug Ambrisko void(*buf_service)(struct vnic_rq *rq, struct cq_desc *cq_desc, 3899c067b84SDoug Ambrisko /* struct vnic_rq_buf * *buf, */ int skipped, void *opaque), void *opaque) 3909c067b84SDoug Ambrisko { 391*0acab8b3SDoug Ambrisko if_softc_ctx_t scctx; 3929c067b84SDoug Ambrisko if_rxd_info_t ri = (if_rxd_info_t) opaque; 3939c067b84SDoug Ambrisko u8 type, color, eop, sop, ingress_port, vlan_stripped; 3949c067b84SDoug Ambrisko u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof; 3959c067b84SDoug Ambrisko u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok; 3969c067b84SDoug Ambrisko u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc; 3979c067b84SDoug Ambrisko u8 packet_error; 3989c067b84SDoug Ambrisko u16 q_number, completed_index, bytes_written, vlan_tci, checksum; 3999c067b84SDoug Ambrisko u32 rss_hash; 4009c067b84SDoug Ambrisko int cqidx; 4019c067b84SDoug Ambrisko if_rxd_frag_t frag; 4029c067b84SDoug Ambrisko 403*0acab8b3SDoug Ambrisko scctx = rq->vdev->softc->scctx; 404*0acab8b3SDoug Ambrisko 4059c067b84SDoug Ambrisko cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc, 4069c067b84SDoug Ambrisko &type, &color, &q_number, &completed_index, 4079c067b84SDoug Ambrisko &ingress_port, &fcoe, &eop, &sop, &rss_type, 4089c067b84SDoug Ambrisko &csum_not_calc, &rss_hash, &bytes_written, 4099c067b84SDoug Ambrisko &packet_error, &vlan_stripped, &vlan_tci, &checksum, 4109c067b84SDoug Ambrisko &fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error, 4119c067b84SDoug Ambrisko &fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp, 4129c067b84SDoug Ambrisko &ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment, 4139c067b84SDoug Ambrisko &fcs_ok); 4149c067b84SDoug Ambrisko 4159c067b84SDoug Ambrisko cqidx = ri->iri_cidx; 4169c067b84SDoug Ambrisko 4179c067b84SDoug Ambrisko frag = &ri->iri_frags[0]; 4189c067b84SDoug Ambrisko frag->irf_idx = cqidx; 4199c067b84SDoug Ambrisko frag->irf_len = bytes_written; 4209c067b84SDoug Ambrisko 4219c067b84SDoug Ambrisko if (++cqidx == rq->ring.desc_count) { 4229c067b84SDoug Ambrisko cqidx = 0; 4239c067b84SDoug Ambrisko } 4249c067b84SDoug Ambrisko 4259c067b84SDoug Ambrisko ri->iri_cidx = cqidx; 4269c067b84SDoug Ambrisko ri->iri_nfrags = 1; 4279c067b84SDoug Ambrisko ri->iri_len = bytes_written; 428*0acab8b3SDoug Ambrisko 429*0acab8b3SDoug Ambrisko if ((scctx->isc_capenable & IFCAP_RXCSUM) != 0) 430*0acab8b3SDoug Ambrisko if (!csum_not_calc && (tcp_udp_csum_ok || ipv4_csum_ok)) { 431*0acab8b3SDoug Ambrisko ri->iri_csum_flags = (CSUM_IP_CHECKED | CSUM_IP_VALID); 432*0acab8b3SDoug Ambrisko } 4339c067b84SDoug Ambrisko } 4349c067b84SDoug Ambrisko 4359c067b84SDoug Ambrisko static int 4369c067b84SDoug Ambrisko enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, 4379c067b84SDoug Ambrisko u8 type, u16 q_number, u16 completed_index, void *opaque) 4389c067b84SDoug Ambrisko { 4399c067b84SDoug Ambrisko struct enic *enic = vnic_dev_priv(vdev); 4409c067b84SDoug Ambrisko if_rxd_info_t ri = (if_rxd_info_t) opaque; 4419c067b84SDoug Ambrisko 4429c067b84SDoug Ambrisko vnic_rq_service(&enic->rq[ri->iri_qsidx], cq_desc, completed_index, 4439c067b84SDoug Ambrisko VNIC_RQ_RETURN_DESC, NULL, /* enic_rq_indicate_buf, */ opaque); 4449c067b84SDoug Ambrisko 445*0acab8b3SDoug Ambrisko return (0); 4469c067b84SDoug Ambrisko } 4479c067b84SDoug Ambrisko 4489c067b84SDoug Ambrisko void 4499c067b84SDoug Ambrisko enic_prep_wq_for_simple_tx(struct enic *enic, uint16_t queue_idx) 4509c067b84SDoug Ambrisko { 4519c067b84SDoug Ambrisko struct wq_enet_desc *desc; 4529c067b84SDoug Ambrisko struct vnic_wq *wq; 4539c067b84SDoug Ambrisko unsigned int i; 4549c067b84SDoug Ambrisko 4559c067b84SDoug Ambrisko /* 4569c067b84SDoug Ambrisko * Fill WQ descriptor fields that never change. Every descriptor is 4579c067b84SDoug Ambrisko * one packet, so set EOP. Also set CQ_ENTRY every ENIC_WQ_CQ_THRESH 4589c067b84SDoug Ambrisko * descriptors (i.e. request one completion update every 32 packets). 4599c067b84SDoug Ambrisko */ 4609c067b84SDoug Ambrisko wq = &enic->wq[queue_idx]; 4619c067b84SDoug Ambrisko desc = (struct wq_enet_desc *)wq->ring.descs; 4629c067b84SDoug Ambrisko for (i = 0; i < wq->ring.desc_count; i++, desc++) { 4639c067b84SDoug Ambrisko desc->header_length_flags = 1 << WQ_ENET_FLAGS_EOP_SHIFT; 4649c067b84SDoug Ambrisko if (i % ENIC_WQ_CQ_THRESH == ENIC_WQ_CQ_THRESH - 1) 4659c067b84SDoug Ambrisko desc->header_length_flags |= 4669c067b84SDoug Ambrisko (1 << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT); 4679c067b84SDoug Ambrisko } 4689c067b84SDoug Ambrisko } 4699c067b84SDoug Ambrisko 4709c067b84SDoug Ambrisko void 4719c067b84SDoug Ambrisko enic_start_wq(struct enic *enic, uint16_t queue_idx) 4729c067b84SDoug Ambrisko { 4739c067b84SDoug Ambrisko vnic_wq_enable(&enic->wq[queue_idx]); 4749c067b84SDoug Ambrisko } 4759c067b84SDoug Ambrisko 4769c067b84SDoug Ambrisko int 4779c067b84SDoug Ambrisko enic_stop_wq(struct enic *enic, uint16_t queue_idx) 4789c067b84SDoug Ambrisko { 4799c067b84SDoug Ambrisko int ret; 4809c067b84SDoug Ambrisko 4819c067b84SDoug Ambrisko ret = vnic_wq_disable(&enic->wq[queue_idx]); 4829c067b84SDoug Ambrisko 483*0acab8b3SDoug Ambrisko return (ret); 4849c067b84SDoug Ambrisko } 4859c067b84SDoug Ambrisko 4869c067b84SDoug Ambrisko void 4879c067b84SDoug Ambrisko enic_start_rq(struct enic *enic, uint16_t queue_idx) 4889c067b84SDoug Ambrisko { 4899c067b84SDoug Ambrisko struct vnic_rq *rq; 4909c067b84SDoug Ambrisko 4919c067b84SDoug Ambrisko rq = &enic->rq[queue_idx]; 4929c067b84SDoug Ambrisko vnic_rq_enable(rq); 4939c067b84SDoug Ambrisko enic_initial_post_rx(enic, rq); 4949c067b84SDoug Ambrisko } 495*0acab8b3SDoug Ambrisko 496*0acab8b3SDoug Ambrisko int 497*0acab8b3SDoug Ambrisko enic_stop_rq(struct enic *enic, uint16_t queue_idx) 498*0acab8b3SDoug Ambrisko { 499*0acab8b3SDoug Ambrisko int ret; 500*0acab8b3SDoug Ambrisko 501*0acab8b3SDoug Ambrisko ret = vnic_rq_disable(&enic->rq[queue_idx]); 502*0acab8b3SDoug Ambrisko 503*0acab8b3SDoug Ambrisko return (ret); 504*0acab8b3SDoug Ambrisko } 505*0acab8b3SDoug Ambrisko 506*0acab8b3SDoug Ambrisko 507*0acab8b3SDoug Ambrisko void 508*0acab8b3SDoug Ambrisko enic_dev_disable(struct enic *enic) { 509*0acab8b3SDoug Ambrisko vnic_dev_disable(enic->vdev); 510*0acab8b3SDoug Ambrisko } 511