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
enic_isc_txd_encap(void * vsc,if_pkt_info_t pi)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
enic_isc_txd_flush(void * vsc,uint16_t txqid,qidx_t pidx)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
enic_isc_txd_credits_update(void * vsc,uint16_t txqid,bool clear)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
enic_isc_rxd_available(void * vsc,uint16_t rxqid,qidx_t idx,qidx_t budget)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
enic_isc_rxd_pkt_get(void * vsc,if_rxd_info_t ri)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
enic_isc_rxd_refill(void * vsc,if_rxd_update_t iru)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
enic_isc_rxd_flush(void * vsc,uint16_t rxqid,uint8_t flid,qidx_t pidx)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
enic_legacy_intr(void * xsc)3259c067b84SDoug Ambrisko enic_legacy_intr(void *xsc)
3269c067b84SDoug Ambrisko {
327*0acab8b3SDoug Ambrisko return (1);
3289c067b84SDoug Ambrisko }
3299c067b84SDoug Ambrisko
3309c067b84SDoug Ambrisko static inline void
vnic_wq_service(struct vnic_wq * wq,struct cq_desc * cq_desc,u16 completed_index,void (* buf_service)(struct vnic_wq * wq,struct cq_desc * cq_desc,void * opaque),void * opaque)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
enic_initial_post_rx(struct enic * enic,struct vnic_rq * rq)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
enic_wq_service(struct vnic_dev * vdev,struct cq_desc * cq_desc,u8 type,u16 q_number,u16 completed_index,void * opaque)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
vnic_rq_service(struct vnic_rq * rq,struct cq_desc * cq_desc,u16 in_completed_index,int desc_return,void (* buf_service)(struct vnic_rq * rq,struct cq_desc * cq_desc,int skipped,void * opaque),void * opaque)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
enic_rq_service(struct vnic_dev * vdev,struct cq_desc * cq_desc,u8 type,u16 q_number,u16 completed_index,void * opaque)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
enic_prep_wq_for_simple_tx(struct enic * enic,uint16_t queue_idx)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
enic_start_wq(struct enic * enic,uint16_t queue_idx)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
enic_stop_wq(struct enic * enic,uint16_t queue_idx)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
enic_start_rq(struct enic * enic,uint16_t queue_idx)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
enic_stop_rq(struct enic * enic,uint16_t queue_idx)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
enic_dev_disable(struct enic * enic)508*0acab8b3SDoug Ambrisko enic_dev_disable(struct enic *enic) {
509*0acab8b3SDoug Ambrisko vnic_dev_disable(enic->vdev);
510*0acab8b3SDoug Ambrisko }
511