xref: /freebsd/sys/dev/enic/enic_txrx.c (revision 9c067b84)
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;
1069c067b84SDoug Ambrisko 
1079c067b84SDoug Ambrisko 	wq = &enic->wq[pi->ipi_qsidx];
1089c067b84SDoug Ambrisko 	nsegs = pi->ipi_nsegs;
1099c067b84SDoug Ambrisko 
1109c067b84SDoug Ambrisko 	ENIC_LOCK(softc);
1119c067b84SDoug Ambrisko 	wq_desc_avail = vnic_wq_desc_avail(wq);
1129c067b84SDoug Ambrisko 	head_idx = wq->head_idx;
1139c067b84SDoug Ambrisko 	desc_count = wq->ring.desc_count;
1149c067b84SDoug Ambrisko 
1159c067b84SDoug Ambrisko 	for (i = 0; i < nsegs; i++) {
1169c067b84SDoug Ambrisko 		eop = 0;
1179c067b84SDoug Ambrisko 		cq = 0;
1189c067b84SDoug Ambrisko 		wq->cq_pend++;
1199c067b84SDoug Ambrisko 		if (i + 1 == nsegs) {
1209c067b84SDoug Ambrisko 			eop = 1;
1219c067b84SDoug Ambrisko 			cq = 1;
1229c067b84SDoug Ambrisko 			wq->cq_pend = 0;
1239c067b84SDoug Ambrisko 		}
1249c067b84SDoug Ambrisko 		desc = wq->ring.descs;
1259c067b84SDoug Ambrisko 		bus_addr = pi->ipi_segs[i].ds_addr;
1269c067b84SDoug Ambrisko 		data_len = pi->ipi_segs[i].ds_len;
1279c067b84SDoug Ambrisko 
1289c067b84SDoug Ambrisko 		wq_enet_desc_enc(&desc[head_idx], bus_addr, data_len, mss,
1299c067b84SDoug Ambrisko 				 header_len, offload_mode, eop, cq, 0,
1309c067b84SDoug Ambrisko 				 vlan_tag_insert, vlan_id, 0);
1319c067b84SDoug Ambrisko 
1329c067b84SDoug Ambrisko 		head_idx = enic_ring_incr(desc_count, head_idx);
1339c067b84SDoug Ambrisko 		wq_desc_avail--;
1349c067b84SDoug Ambrisko 	}
1359c067b84SDoug Ambrisko 
1369c067b84SDoug Ambrisko 	wq->ring.desc_avail = wq_desc_avail;
1379c067b84SDoug Ambrisko 	wq->head_idx = head_idx;
1389c067b84SDoug Ambrisko 
1399c067b84SDoug Ambrisko 	pi->ipi_new_pidx = head_idx;
1409c067b84SDoug Ambrisko 	ENIC_UNLOCK(softc);
1419c067b84SDoug Ambrisko 
1429c067b84SDoug Ambrisko 	return (0);
1439c067b84SDoug Ambrisko }
1449c067b84SDoug Ambrisko 
1459c067b84SDoug Ambrisko static void
enic_isc_txd_flush(void * vsc,uint16_t txqid,qidx_t pidx)1469c067b84SDoug Ambrisko enic_isc_txd_flush(void *vsc, uint16_t txqid, qidx_t pidx)
1479c067b84SDoug Ambrisko {
1489c067b84SDoug Ambrisko 	struct enic_softc *softc;
1499c067b84SDoug Ambrisko 	struct enic *enic;
1509c067b84SDoug Ambrisko 	struct vnic_wq *wq;
1519c067b84SDoug Ambrisko 	int head_idx;
1529c067b84SDoug Ambrisko 
1539c067b84SDoug Ambrisko 	softc = vsc;
1549c067b84SDoug Ambrisko 	enic = &softc->enic;
1559c067b84SDoug Ambrisko 
1569c067b84SDoug Ambrisko 	ENIC_LOCK(softc);
1579c067b84SDoug Ambrisko 	wq = &enic->wq[txqid];
1589c067b84SDoug Ambrisko 	head_idx = wq->head_idx;
1599c067b84SDoug Ambrisko 
1609c067b84SDoug Ambrisko 	ENIC_BUS_WRITE_4(wq->ctrl, TX_POSTED_INDEX, head_idx);
1619c067b84SDoug Ambrisko 	ENIC_UNLOCK(softc);
1629c067b84SDoug Ambrisko }
1639c067b84SDoug Ambrisko 
1649c067b84SDoug Ambrisko static int
enic_isc_txd_credits_update(void * vsc,uint16_t txqid,bool clear)1659c067b84SDoug Ambrisko enic_isc_txd_credits_update(void *vsc, uint16_t txqid, bool clear)
1669c067b84SDoug Ambrisko {
1679c067b84SDoug Ambrisko 
1689c067b84SDoug Ambrisko 	struct enic_softc *softc;
1699c067b84SDoug Ambrisko 	struct enic *enic;
1709c067b84SDoug Ambrisko 	struct vnic_wq *wq;
1719c067b84SDoug Ambrisko 	struct vnic_cq *cq;
1729c067b84SDoug Ambrisko 	int processed;
1739c067b84SDoug Ambrisko 	unsigned int cq_wq;
1749c067b84SDoug Ambrisko 	unsigned int wq_work_to_do = 10;
1759c067b84SDoug Ambrisko 	unsigned int wq_work_avail;
1769c067b84SDoug Ambrisko 
1779c067b84SDoug Ambrisko 	softc = vsc;
1789c067b84SDoug Ambrisko 	enic = &softc->enic;
1799c067b84SDoug Ambrisko 	wq = &softc->enic.wq[txqid];
1809c067b84SDoug Ambrisko 
1819c067b84SDoug Ambrisko 	cq_wq = enic_cq_wq(enic, txqid);
1829c067b84SDoug Ambrisko 	cq = &enic->cq[cq_wq];
1839c067b84SDoug Ambrisko 
1849c067b84SDoug Ambrisko 	ENIC_LOCK(softc);
1859c067b84SDoug Ambrisko 	wq_work_avail = vnic_cq_work(cq, wq_work_to_do);
1869c067b84SDoug Ambrisko 	ENIC_UNLOCK(softc);
1879c067b84SDoug Ambrisko 
1889c067b84SDoug Ambrisko 	if (wq_work_avail == 0)
1899c067b84SDoug Ambrisko 		return (0);
1909c067b84SDoug Ambrisko 
1919c067b84SDoug Ambrisko 	if (!clear)
1929c067b84SDoug Ambrisko 		return (1);
1939c067b84SDoug Ambrisko 
1949c067b84SDoug Ambrisko 	ENIC_LOCK(softc);
1959c067b84SDoug Ambrisko 	vnic_cq_service(cq, wq_work_to_do,
1969c067b84SDoug Ambrisko 		    enic_wq_service, NULL);
1979c067b84SDoug Ambrisko 
1989c067b84SDoug Ambrisko 	processed = wq->processed;
1999c067b84SDoug Ambrisko 	wq->processed = 0;
2009c067b84SDoug Ambrisko 
2019c067b84SDoug Ambrisko 	ENIC_UNLOCK(softc);
2029c067b84SDoug Ambrisko 
2039c067b84SDoug Ambrisko 	return (processed);
2049c067b84SDoug Ambrisko }
2059c067b84SDoug Ambrisko 
2069c067b84SDoug Ambrisko static int
enic_isc_rxd_available(void * vsc,uint16_t rxqid,qidx_t idx,qidx_t budget)2079c067b84SDoug Ambrisko enic_isc_rxd_available(void *vsc, uint16_t rxqid, qidx_t idx, qidx_t budget)
2089c067b84SDoug Ambrisko {
2099c067b84SDoug Ambrisko 	struct enic_softc *softc;
2109c067b84SDoug Ambrisko 	struct enic *enic;
2119c067b84SDoug Ambrisko 	struct vnic_cq *cq;
2129c067b84SDoug Ambrisko 	unsigned int rq_work_to_do = budget;
2139c067b84SDoug Ambrisko 	unsigned int rq_work_avail = 0;
2149c067b84SDoug Ambrisko 	unsigned int cq_rq;
2159c067b84SDoug Ambrisko 
2169c067b84SDoug Ambrisko 	softc = vsc;
2179c067b84SDoug Ambrisko 	enic = &softc->enic;
2189c067b84SDoug Ambrisko 
2199c067b84SDoug Ambrisko 	cq_rq = enic_cq_rq(&softc->enic, rxqid);
2209c067b84SDoug Ambrisko 	cq = &enic->cq[cq_rq];
2219c067b84SDoug Ambrisko 
2229c067b84SDoug Ambrisko 	rq_work_avail = vnic_cq_work(cq, rq_work_to_do);
2239c067b84SDoug Ambrisko 	return rq_work_avail;
2249c067b84SDoug Ambrisko }
2259c067b84SDoug Ambrisko 
2269c067b84SDoug Ambrisko static int
enic_isc_rxd_pkt_get(void * vsc,if_rxd_info_t ri)2279c067b84SDoug Ambrisko enic_isc_rxd_pkt_get(void *vsc, if_rxd_info_t ri)
2289c067b84SDoug Ambrisko {
2299c067b84SDoug Ambrisko 	struct enic_softc *softc;
2309c067b84SDoug Ambrisko 	struct enic *enic;
2319c067b84SDoug Ambrisko 	struct vnic_cq *cq;
2329c067b84SDoug Ambrisko 	unsigned int rq_work_to_do = 1;
2339c067b84SDoug Ambrisko 	unsigned int rq_work_done = 0;
2349c067b84SDoug Ambrisko 	unsigned int cq_rq;
2359c067b84SDoug Ambrisko 
2369c067b84SDoug Ambrisko 	softc = vsc;
2379c067b84SDoug Ambrisko 	enic = &softc->enic;
2389c067b84SDoug Ambrisko 
2399c067b84SDoug Ambrisko 	cq_rq = enic_cq_rq(&softc->enic, ri->iri_qsidx);
2409c067b84SDoug Ambrisko 	cq = &enic->cq[cq_rq];
2419c067b84SDoug Ambrisko 	ENIC_LOCK(softc);
2429c067b84SDoug Ambrisko 	rq_work_done = vnic_cq_service(cq, rq_work_to_do, enic_rq_service, ri);
2439c067b84SDoug Ambrisko 
2449c067b84SDoug Ambrisko 	if (rq_work_done != 0) {
2459c067b84SDoug Ambrisko 		vnic_intr_return_credits(&enic->intr[cq_rq], rq_work_done, 0,
2469c067b84SDoug Ambrisko 		    1);
2479c067b84SDoug Ambrisko 		ENIC_UNLOCK(softc);
2489c067b84SDoug Ambrisko 		return (0);
2499c067b84SDoug Ambrisko 	} else {
2509c067b84SDoug Ambrisko 		ENIC_UNLOCK(softc);
2519c067b84SDoug Ambrisko 		return (-1);
2529c067b84SDoug Ambrisko 	}
2539c067b84SDoug Ambrisko 
2549c067b84SDoug Ambrisko }
2559c067b84SDoug Ambrisko 
2569c067b84SDoug Ambrisko static void
enic_isc_rxd_refill(void * vsc,if_rxd_update_t iru)2579c067b84SDoug Ambrisko enic_isc_rxd_refill(void *vsc, if_rxd_update_t iru)
2589c067b84SDoug Ambrisko {
2599c067b84SDoug Ambrisko 	struct enic_softc *softc;
2609c067b84SDoug Ambrisko 	struct vnic_rq *rq;
2619c067b84SDoug Ambrisko 	struct rq_enet_desc *rqd;
2629c067b84SDoug Ambrisko 
2639c067b84SDoug Ambrisko 	uint64_t *paddrs;
2649c067b84SDoug Ambrisko 	int count;
2659c067b84SDoug Ambrisko 	uint32_t pidx;
2669c067b84SDoug Ambrisko 	int len;
2679c067b84SDoug Ambrisko 	int idx;
2689c067b84SDoug Ambrisko 	int i;
2699c067b84SDoug Ambrisko 
2709c067b84SDoug Ambrisko 	count = iru->iru_count;
2719c067b84SDoug Ambrisko 	len = iru->iru_buf_size;
2729c067b84SDoug Ambrisko 	paddrs = iru->iru_paddrs;
2739c067b84SDoug Ambrisko 	pidx = iru->iru_pidx;
2749c067b84SDoug Ambrisko 
2759c067b84SDoug Ambrisko 	softc = vsc;
2769c067b84SDoug Ambrisko 	rq = &softc->enic.rq[iru->iru_qsidx];
2779c067b84SDoug Ambrisko 	rqd = rq->ring.descs;
2789c067b84SDoug Ambrisko 
2799c067b84SDoug Ambrisko 	idx = pidx;
2809c067b84SDoug Ambrisko 	for (i = 0; i < count; i++, idx++) {
2819c067b84SDoug Ambrisko 
2829c067b84SDoug Ambrisko 		if (idx == rq->ring.desc_count)
2839c067b84SDoug Ambrisko 			idx = 0;
2849c067b84SDoug Ambrisko 		rq_enet_desc_enc(&rqd[idx], paddrs[i],
2859c067b84SDoug Ambrisko 				 RQ_ENET_TYPE_ONLY_SOP,
2869c067b84SDoug Ambrisko 				 len);
2879c067b84SDoug Ambrisko 
2889c067b84SDoug Ambrisko 	}
2899c067b84SDoug Ambrisko 
2909c067b84SDoug Ambrisko 	rq->in_use = 1;
2919c067b84SDoug Ambrisko 
2929c067b84SDoug Ambrisko 	if (rq->need_initial_post) {
2939c067b84SDoug Ambrisko 		ENIC_BUS_WRITE_4(rq->ctrl, RX_FETCH_INDEX, 0);
2949c067b84SDoug Ambrisko 	}
2959c067b84SDoug Ambrisko 
2969c067b84SDoug Ambrisko 	enic_initial_post_rx(&softc->enic, rq);
2979c067b84SDoug Ambrisko }
2989c067b84SDoug Ambrisko 
2999c067b84SDoug Ambrisko static void
enic_isc_rxd_flush(void * vsc,uint16_t rxqid,uint8_t flid,qidx_t pidx)3009c067b84SDoug Ambrisko enic_isc_rxd_flush(void *vsc, uint16_t rxqid, uint8_t flid, qidx_t pidx)
3019c067b84SDoug Ambrisko {
3029c067b84SDoug Ambrisko 
3039c067b84SDoug Ambrisko 	struct enic_softc *softc;
3049c067b84SDoug Ambrisko 	struct vnic_rq *rq;
3059c067b84SDoug Ambrisko 
3069c067b84SDoug Ambrisko 	softc = vsc;
3079c067b84SDoug Ambrisko 	rq = &softc->enic.rq[rxqid];
3089c067b84SDoug Ambrisko 
3099c067b84SDoug Ambrisko 	/*
3109c067b84SDoug Ambrisko 	 * pidx is the index of the last descriptor with a buffer the device
3119c067b84SDoug Ambrisko 	 * can use, and the device needs to be told which index is one past
3129c067b84SDoug Ambrisko 	 * that.
3139c067b84SDoug Ambrisko 	 */
3149c067b84SDoug Ambrisko 
3159c067b84SDoug Ambrisko 	ENIC_LOCK(softc);
3169c067b84SDoug Ambrisko 	ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, pidx);
3179c067b84SDoug Ambrisko 	ENIC_UNLOCK(softc);
3189c067b84SDoug Ambrisko }
3199c067b84SDoug Ambrisko 
3209c067b84SDoug Ambrisko static int
enic_legacy_intr(void * xsc)3219c067b84SDoug Ambrisko enic_legacy_intr(void *xsc)
3229c067b84SDoug Ambrisko {
3239c067b84SDoug Ambrisko 	return -1;
3249c067b84SDoug Ambrisko }
3259c067b84SDoug Ambrisko 
3269c067b84SDoug 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)3279c067b84SDoug Ambrisko vnic_wq_service(struct vnic_wq *wq, struct cq_desc *cq_desc,
3289c067b84SDoug Ambrisko     u16 completed_index, void (*buf_service) (struct vnic_wq *wq,
3299c067b84SDoug Ambrisko     struct cq_desc *cq_desc, /* struct vnic_wq_buf * *buf, */ void *opaque),
3309c067b84SDoug Ambrisko     void *opaque)
3319c067b84SDoug Ambrisko {
3329c067b84SDoug Ambrisko 	int processed;
3339c067b84SDoug Ambrisko 
3349c067b84SDoug Ambrisko 	processed = completed_index - wq->ring.last_count;
3359c067b84SDoug Ambrisko 	if (processed < 0)
3369c067b84SDoug Ambrisko 		processed += wq->ring.desc_count;
3379c067b84SDoug Ambrisko 	if (processed == 0)
3389c067b84SDoug Ambrisko 		processed++;
3399c067b84SDoug Ambrisko 
3409c067b84SDoug Ambrisko 	wq->ring.desc_avail += processed;
3419c067b84SDoug Ambrisko 	wq->processed += processed;
3429c067b84SDoug Ambrisko 	wq->ring.last_count = completed_index;
3439c067b84SDoug Ambrisko }
3449c067b84SDoug Ambrisko 
3459c067b84SDoug Ambrisko /*
3469c067b84SDoug Ambrisko  * Post the Rx buffers for the first time. enic_alloc_rx_queue_mbufs() has
3479c067b84SDoug Ambrisko  * allocated the buffers and filled the RQ descriptor ring. Just need to push
3489c067b84SDoug Ambrisko  * the post index to the NIC.
3499c067b84SDoug Ambrisko  */
3509c067b84SDoug Ambrisko static void
enic_initial_post_rx(struct enic * enic,struct vnic_rq * rq)3519c067b84SDoug Ambrisko enic_initial_post_rx(struct enic *enic, struct vnic_rq *rq)
3529c067b84SDoug Ambrisko {
3539c067b84SDoug Ambrisko 	struct enic_softc *softc = enic->softc;
3549c067b84SDoug Ambrisko 	if (!rq->in_use || !rq->need_initial_post)
3559c067b84SDoug Ambrisko 		return;
3569c067b84SDoug Ambrisko 
3579c067b84SDoug Ambrisko 	ENIC_LOCK(softc);
3589c067b84SDoug Ambrisko 	/* make sure all prior writes are complete before doing the PIO write */
3599c067b84SDoug Ambrisko 	/* Post all but the last buffer to VIC. */
3609c067b84SDoug Ambrisko 	rq->posted_index = rq->ring.desc_count - 1;
3619c067b84SDoug Ambrisko 
3629c067b84SDoug Ambrisko 	rq->rx_nb_hold = 0;
3639c067b84SDoug Ambrisko 
3649c067b84SDoug Ambrisko 	ENIC_BUS_WRITE_4(rq->ctrl, RX_POSTED_INDEX, rq->posted_index);
3659c067b84SDoug Ambrisko 
3669c067b84SDoug Ambrisko 	rq->need_initial_post = false;
3679c067b84SDoug Ambrisko 	ENIC_UNLOCK(softc);
3689c067b84SDoug Ambrisko }
3699c067b84SDoug Ambrisko 
3709c067b84SDoug 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)3719c067b84SDoug Ambrisko enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, u8 type,
3729c067b84SDoug Ambrisko     u16 q_number, u16 completed_index, void *opaque)
3739c067b84SDoug Ambrisko {
3749c067b84SDoug Ambrisko 	struct enic *enic = vnic_dev_priv(vdev);
3759c067b84SDoug Ambrisko 
3769c067b84SDoug Ambrisko 	vnic_wq_service(&enic->wq[q_number], cq_desc,
3779c067b84SDoug Ambrisko 			completed_index, NULL, opaque);
3789c067b84SDoug Ambrisko 	return 0;
3799c067b84SDoug Ambrisko }
3809c067b84SDoug Ambrisko 
3819c067b84SDoug 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)3829c067b84SDoug Ambrisko vnic_rq_service(struct vnic_rq *rq, struct cq_desc *cq_desc,
3839c067b84SDoug Ambrisko     u16 in_completed_index, int desc_return,
3849c067b84SDoug Ambrisko     void(*buf_service)(struct vnic_rq *rq, struct cq_desc *cq_desc,
3859c067b84SDoug Ambrisko     /* struct vnic_rq_buf * *buf, */ int skipped, void *opaque), void *opaque)
3869c067b84SDoug Ambrisko {
3879c067b84SDoug Ambrisko 
3889c067b84SDoug Ambrisko 	if_rxd_info_t ri = (if_rxd_info_t) opaque;
3899c067b84SDoug Ambrisko 	u8 type, color, eop, sop, ingress_port, vlan_stripped;
3909c067b84SDoug Ambrisko 	u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
3919c067b84SDoug Ambrisko 	u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
3929c067b84SDoug Ambrisko 	u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
3939c067b84SDoug Ambrisko 	u8 packet_error;
3949c067b84SDoug Ambrisko 	u16 q_number, completed_index, bytes_written, vlan_tci, checksum;
3959c067b84SDoug Ambrisko 	u32 rss_hash;
3969c067b84SDoug Ambrisko 	int cqidx;
3979c067b84SDoug Ambrisko 	if_rxd_frag_t frag;
3989c067b84SDoug Ambrisko 
3999c067b84SDoug Ambrisko 	cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
4009c067b84SDoug Ambrisko 	    &type, &color, &q_number, &completed_index,
4019c067b84SDoug Ambrisko 	    &ingress_port, &fcoe, &eop, &sop, &rss_type,
4029c067b84SDoug Ambrisko 	    &csum_not_calc, &rss_hash, &bytes_written,
4039c067b84SDoug Ambrisko 	    &packet_error, &vlan_stripped, &vlan_tci, &checksum,
4049c067b84SDoug Ambrisko 	    &fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
4059c067b84SDoug Ambrisko 	    &fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
4069c067b84SDoug Ambrisko 	    &ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
4079c067b84SDoug Ambrisko 	    &fcs_ok);
4089c067b84SDoug Ambrisko 
4099c067b84SDoug Ambrisko 	cqidx = ri->iri_cidx;
4109c067b84SDoug Ambrisko 
4119c067b84SDoug Ambrisko 	frag = &ri->iri_frags[0];
4129c067b84SDoug Ambrisko 	frag->irf_idx = cqidx;
4139c067b84SDoug Ambrisko 	frag->irf_len = bytes_written;
4149c067b84SDoug Ambrisko 
4159c067b84SDoug Ambrisko 	if (++cqidx == rq->ring.desc_count) {
4169c067b84SDoug Ambrisko 		cqidx = 0;
4179c067b84SDoug Ambrisko 	}
4189c067b84SDoug Ambrisko 
4199c067b84SDoug Ambrisko 	ri->iri_cidx = cqidx;
4209c067b84SDoug Ambrisko 	ri->iri_nfrags = 1;
4219c067b84SDoug Ambrisko 	ri->iri_len = bytes_written;
4229c067b84SDoug Ambrisko }
4239c067b84SDoug Ambrisko 
4249c067b84SDoug 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)4259c067b84SDoug Ambrisko enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
4269c067b84SDoug Ambrisko 		u8 type, u16 q_number, u16 completed_index, void *opaque)
4279c067b84SDoug Ambrisko {
4289c067b84SDoug Ambrisko 	struct enic *enic = vnic_dev_priv(vdev);
4299c067b84SDoug Ambrisko 	if_rxd_info_t ri = (if_rxd_info_t) opaque;
4309c067b84SDoug Ambrisko 
4319c067b84SDoug Ambrisko 	vnic_rq_service(&enic->rq[ri->iri_qsidx], cq_desc, completed_index,
4329c067b84SDoug Ambrisko 	    VNIC_RQ_RETURN_DESC, NULL, /* enic_rq_indicate_buf, */ opaque);
4339c067b84SDoug Ambrisko 
4349c067b84SDoug Ambrisko 	return 0;
4359c067b84SDoug Ambrisko }
4369c067b84SDoug Ambrisko 
4379c067b84SDoug Ambrisko void
enic_prep_wq_for_simple_tx(struct enic * enic,uint16_t queue_idx)4389c067b84SDoug Ambrisko enic_prep_wq_for_simple_tx(struct enic *enic, uint16_t queue_idx)
4399c067b84SDoug Ambrisko {
4409c067b84SDoug Ambrisko 	struct wq_enet_desc *desc;
4419c067b84SDoug Ambrisko 	struct vnic_wq *wq;
4429c067b84SDoug Ambrisko 	unsigned int i;
4439c067b84SDoug Ambrisko 
4449c067b84SDoug Ambrisko 	/*
4459c067b84SDoug Ambrisko 	 * Fill WQ descriptor fields that never change. Every descriptor is
4469c067b84SDoug Ambrisko 	 * one packet, so set EOP. Also set CQ_ENTRY every ENIC_WQ_CQ_THRESH
4479c067b84SDoug Ambrisko 	 * descriptors (i.e. request one completion update every 32 packets).
4489c067b84SDoug Ambrisko 	 */
4499c067b84SDoug Ambrisko 	wq = &enic->wq[queue_idx];
4509c067b84SDoug Ambrisko 	desc = (struct wq_enet_desc *)wq->ring.descs;
4519c067b84SDoug Ambrisko 	for (i = 0; i < wq->ring.desc_count; i++, desc++) {
4529c067b84SDoug Ambrisko 		desc->header_length_flags = 1 << WQ_ENET_FLAGS_EOP_SHIFT;
4539c067b84SDoug Ambrisko 		if (i % ENIC_WQ_CQ_THRESH == ENIC_WQ_CQ_THRESH - 1)
4549c067b84SDoug Ambrisko 			desc->header_length_flags |=
4559c067b84SDoug Ambrisko 			    (1 << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT);
4569c067b84SDoug Ambrisko 	}
4579c067b84SDoug Ambrisko }
4589c067b84SDoug Ambrisko 
4599c067b84SDoug Ambrisko void
enic_start_wq(struct enic * enic,uint16_t queue_idx)4609c067b84SDoug Ambrisko enic_start_wq(struct enic *enic, uint16_t queue_idx)
4619c067b84SDoug Ambrisko {
4629c067b84SDoug Ambrisko 	vnic_wq_enable(&enic->wq[queue_idx]);
4639c067b84SDoug Ambrisko }
4649c067b84SDoug Ambrisko 
4659c067b84SDoug Ambrisko int
enic_stop_wq(struct enic * enic,uint16_t queue_idx)4669c067b84SDoug Ambrisko enic_stop_wq(struct enic *enic, uint16_t queue_idx)
4679c067b84SDoug Ambrisko {
4689c067b84SDoug Ambrisko 	int ret;
4699c067b84SDoug Ambrisko 
4709c067b84SDoug Ambrisko 	ret = vnic_wq_disable(&enic->wq[queue_idx]);
4719c067b84SDoug Ambrisko 	if (ret)
4729c067b84SDoug Ambrisko 		return ret;
4739c067b84SDoug Ambrisko 
4749c067b84SDoug Ambrisko 	return 0;
4759c067b84SDoug Ambrisko }
4769c067b84SDoug Ambrisko 
4779c067b84SDoug Ambrisko void
enic_start_rq(struct enic * enic,uint16_t queue_idx)4789c067b84SDoug Ambrisko enic_start_rq(struct enic *enic, uint16_t queue_idx)
4799c067b84SDoug Ambrisko {
4809c067b84SDoug Ambrisko 	struct vnic_rq *rq;
4819c067b84SDoug Ambrisko 
4829c067b84SDoug Ambrisko 	rq = &enic->rq[queue_idx];
4839c067b84SDoug Ambrisko 	vnic_rq_enable(rq);
4849c067b84SDoug Ambrisko 	enic_initial_post_rx(enic, rq);
4859c067b84SDoug Ambrisko }
486