xref: /netbsd-src/sys/arch/sparc64/dev/vnet.c (revision 3194cf25b2bcc7b155490c9dd74d3ebbd7fc1636)
1*3194cf25Sandvar /*	$NetBSD: vnet.c,v 1.10 2023/12/14 20:17:18 andvar Exp $	*/
26902eb25Spalle /*	$OpenBSD: vnet.c,v 1.62 2020/07/10 13:26:36 patrick Exp $	*/
36902eb25Spalle /*
46902eb25Spalle  * Copyright (c) 2009, 2015 Mark Kettenis
56902eb25Spalle  *
66902eb25Spalle  * Permission to use, copy, modify, and distribute this software for any
76902eb25Spalle  * purpose with or without fee is hereby granted, provided that the above
86902eb25Spalle  * copyright notice and this permission notice appear in all copies.
96902eb25Spalle  *
106902eb25Spalle  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
116902eb25Spalle  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
126902eb25Spalle  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
136902eb25Spalle  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
146902eb25Spalle  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
156902eb25Spalle  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
166902eb25Spalle  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
176902eb25Spalle  */
186902eb25Spalle 
196902eb25Spalle #include <sys/kmem.h>
206902eb25Spalle #include <sys/param.h>
216902eb25Spalle #include <sys/atomic.h>
2291d5826aSpalle #include <sys/callout.h>
236902eb25Spalle #include <sys/device.h>
246902eb25Spalle #include <sys/malloc.h>
256902eb25Spalle #include <sys/pool.h>
266902eb25Spalle #include <sys/mbuf.h>
276902eb25Spalle #include <sys/socket.h>
286902eb25Spalle #include <sys/sockio.h>
296902eb25Spalle #include <sys/systm.h>
306902eb25Spalle 
316902eb25Spalle #include <machine/autoconf.h>
326902eb25Spalle #include <machine/hypervisor.h>
336902eb25Spalle #include <machine/openfirm.h>
346902eb25Spalle 
356902eb25Spalle #include <net/if.h>
366902eb25Spalle #include <net/if_media.h>
376902eb25Spalle 
386902eb25Spalle #include <netinet/in.h>
396902eb25Spalle #include <net/if_ether.h>
406902eb25Spalle 
416902eb25Spalle #if NBPFILTER > 0
426902eb25Spalle #include <net/bpf.h>
436902eb25Spalle #endif
446902eb25Spalle 
456902eb25Spalle #include <uvm/uvm_extern.h>
466902eb25Spalle 
476902eb25Spalle #include <sparc64/dev/cbusvar.h>
486902eb25Spalle #include <sparc64/dev/ldcvar.h>
496902eb25Spalle #include <sparc64/dev/viovar.h>
506902eb25Spalle 
516902eb25Spalle #ifdef VNET_DEBUG
526902eb25Spalle #define DPRINTF(x)	printf x
536902eb25Spalle #else
546902eb25Spalle #define DPRINTF(x)
556902eb25Spalle #endif
566902eb25Spalle 
576902eb25Spalle #define VNET_TX_ENTRIES		32
586902eb25Spalle #define VNET_RX_ENTRIES		32
596902eb25Spalle 
606902eb25Spalle struct vnet_attr_info {
616902eb25Spalle 	struct vio_msg_tag	tag;
626902eb25Spalle 	uint8_t			xfer_mode;
636902eb25Spalle 	uint8_t			addr_type;
646902eb25Spalle 	uint16_t		ack_freq;
656902eb25Spalle 	uint32_t		_reserved1;
666902eb25Spalle 	uint64_t		addr;
676902eb25Spalle 	uint64_t		mtu;
686902eb25Spalle 	uint64_t		_reserved2[3];
696902eb25Spalle };
706902eb25Spalle 
716902eb25Spalle /* Address types. */
726902eb25Spalle #define VNET_ADDR_ETHERMAC	0x01
736902eb25Spalle 
746902eb25Spalle /* Sub-Type envelopes. */
756902eb25Spalle #define VNET_MCAST_INFO		0x0101
766902eb25Spalle 
776902eb25Spalle #define VNET_NUM_MCAST		7
786902eb25Spalle 
796902eb25Spalle struct vnet_mcast_info {
806902eb25Spalle 	struct vio_msg_tag	tag;
816902eb25Spalle 	uint8_t			set;
826902eb25Spalle 	uint8_t			count;
836902eb25Spalle 	uint8_t			mcast_addr[VNET_NUM_MCAST][ETHER_ADDR_LEN];
846902eb25Spalle 	uint32_t		_reserved;
856902eb25Spalle };
866902eb25Spalle 
876902eb25Spalle struct vnet_desc {
886902eb25Spalle 	struct vio_dring_hdr	hdr;
896902eb25Spalle 	uint32_t		nbytes;
906902eb25Spalle 	uint32_t		ncookies;
916902eb25Spalle 	struct ldc_cookie	cookie[2];
926902eb25Spalle };
936902eb25Spalle 
946902eb25Spalle struct vnet_desc_msg {
956902eb25Spalle 	struct vio_msg_tag	tag;
966902eb25Spalle 	uint64_t		seq_no;
976902eb25Spalle 	uint64_t		desc_handle;
986902eb25Spalle 	uint32_t		nbytes;
996902eb25Spalle 	uint32_t		ncookies;
1006902eb25Spalle 	struct ldc_cookie	cookie[1];
1016902eb25Spalle };
1026902eb25Spalle 
1036902eb25Spalle struct vnet_dring {
1046902eb25Spalle 	bus_dmamap_t		vd_map;
1056902eb25Spalle 	bus_dma_segment_t	vd_seg;
1066902eb25Spalle 	struct vnet_desc	*vd_desc;
1076902eb25Spalle 	int			vd_nentries;
1086902eb25Spalle };
1096902eb25Spalle 
1106902eb25Spalle struct vnet_dring *vnet_dring_alloc(bus_dma_tag_t, int);
1116902eb25Spalle void	vnet_dring_free(bus_dma_tag_t, struct vnet_dring *);
1126902eb25Spalle 
1136902eb25Spalle /*
1146902eb25Spalle  * For now, we only support vNet 1.0.
1156902eb25Spalle  */
1166902eb25Spalle #define VNET_MAJOR	1
1176902eb25Spalle #define VNET_MINOR	0
1186902eb25Spalle 
1196902eb25Spalle /*
1206902eb25Spalle  * The vNet protocol wants the IP header to be 64-bit aligned, so
1216902eb25Spalle  * define out own variant of ETHER_ALIGN.
1226902eb25Spalle  */
1236902eb25Spalle #define VNET_ETHER_ALIGN	6
1246902eb25Spalle 
1256902eb25Spalle struct vnet_soft_desc {
1266902eb25Spalle 	int		vsd_map_idx;
1276902eb25Spalle 	unsigned char *vsd_buf;
1286902eb25Spalle };
1296902eb25Spalle 
1306902eb25Spalle struct vnet_softc {
131efd62f8cSriastradh 	device_t	sc_dv;
1326902eb25Spalle 	bus_space_tag_t	sc_bustag;
1336902eb25Spalle 	bus_dma_tag_t	sc_dmatag;
1346902eb25Spalle 
1356902eb25Spalle 	uint64_t	sc_tx_ino;
1366902eb25Spalle 	uint64_t	sc_rx_ino;
1376902eb25Spalle 	void		*sc_tx_ih;
1386902eb25Spalle 	void		*sc_rx_ih;
1396902eb25Spalle 
1406902eb25Spalle 	struct ldc_conn	sc_lc;
1416902eb25Spalle 
1426902eb25Spalle 	uint16_t	sc_vio_state;
1436902eb25Spalle #define VIO_SND_VER_INFO	0x0001
1446902eb25Spalle #define VIO_ACK_VER_INFO	0x0002
1456902eb25Spalle #define VIO_RCV_VER_INFO	0x0004
1466902eb25Spalle #define VIO_SND_ATTR_INFO	0x0008
1476902eb25Spalle #define VIO_ACK_ATTR_INFO	0x0010
1486902eb25Spalle #define VIO_RCV_ATTR_INFO	0x0020
1496902eb25Spalle #define VIO_SND_DRING_REG	0x0040
1506902eb25Spalle #define VIO_ACK_DRING_REG	0x0080
1516902eb25Spalle #define VIO_RCV_DRING_REG	0x0100
1526902eb25Spalle #define VIO_SND_RDX		0x0200
1536902eb25Spalle #define VIO_ACK_RDX		0x0400
1546902eb25Spalle #define VIO_RCV_RDX		0x0800
1556902eb25Spalle 
156f7c20774Spalle 	struct callout	sc_handshake_co;
1576902eb25Spalle 
1586902eb25Spalle 	uint8_t		sc_xfer_mode;
1596902eb25Spalle 
1606902eb25Spalle 	uint32_t	sc_local_sid;
1616902eb25Spalle 	uint64_t	sc_dring_ident;
1626902eb25Spalle 	uint64_t	sc_seq_no;
1636902eb25Spalle 
1646902eb25Spalle 	u_int		sc_tx_prod;
1656902eb25Spalle 	u_int		sc_tx_cons;
1666902eb25Spalle 
1676902eb25Spalle 	u_int		sc_peer_state;
1686902eb25Spalle 
1696902eb25Spalle 	struct ldc_map	*sc_lm;
1706902eb25Spalle 	struct vnet_dring *sc_vd;
1716902eb25Spalle 	struct vnet_soft_desc *sc_vsd;
1726902eb25Spalle #define VNET_NUM_SOFT_DESC	128
1736902eb25Spalle 
1746902eb25Spalle 	size_t		sc_peer_desc_size;
1756902eb25Spalle 	struct ldc_cookie sc_peer_dring_cookie;
1766902eb25Spalle 	int		sc_peer_dring_nentries;
1776902eb25Spalle 
1786902eb25Spalle 	struct pool	sc_pool;
1796902eb25Spalle 
1806902eb25Spalle 	struct ethercom	sc_ethercom;
1816902eb25Spalle 	struct ifmedia	sc_media;
1826902eb25Spalle 	u_int8_t sc_macaddr[ETHER_ADDR_LEN];
1836902eb25Spalle };
1846902eb25Spalle 
1856902eb25Spalle int vnet_match (device_t, cfdata_t, void *);
1866902eb25Spalle void vnet_attach (device_t, device_t, void *);
1876902eb25Spalle 
1886902eb25Spalle CFATTACH_DECL_NEW(vnet, sizeof(struct vnet_softc),
1896902eb25Spalle     vnet_match, vnet_attach, NULL, NULL);
1906902eb25Spalle 
1916902eb25Spalle int	vnet_tx_intr(void *);
1926902eb25Spalle int	vnet_rx_intr(void *);
1936902eb25Spalle void	vnet_handshake(void *);
1946902eb25Spalle 
1956902eb25Spalle void	vio_rx_data(struct ldc_conn *, struct ldc_pkt *);
1966902eb25Spalle void	vnet_rx_vio_ctrl(struct vnet_softc *, struct vio_msg *);
1976902eb25Spalle void	vnet_rx_vio_ver_info(struct vnet_softc *, struct vio_msg_tag *);
1986902eb25Spalle void	vnet_rx_vio_attr_info(struct vnet_softc *, struct vio_msg_tag *);
1996902eb25Spalle void	vnet_rx_vio_dring_reg(struct vnet_softc *, struct vio_msg_tag *);
2006902eb25Spalle void	vnet_rx_vio_rdx(struct vnet_softc *sc, struct vio_msg_tag *);
201b7b2672bSpalle void	vnet_rx_vio_mcast_info(struct vnet_softc *sc, struct vio_msg_tag *);
2026902eb25Spalle void	vnet_rx_vio_data(struct vnet_softc *sc, struct vio_msg *);
2036902eb25Spalle void	vnet_rx_vio_desc_data(struct vnet_softc *sc, struct vio_msg_tag *);
2046902eb25Spalle void	vnet_rx_vio_dring_data(struct vnet_softc *sc, struct vio_msg_tag *);
2056902eb25Spalle 
2066902eb25Spalle void	vnet_ldc_reset(struct ldc_conn *);
2076902eb25Spalle void	vnet_ldc_start(struct ldc_conn *);
2086902eb25Spalle 
2096902eb25Spalle void	vnet_sendmsg(struct vnet_softc *, void *, size_t);
2106902eb25Spalle void	vnet_send_ver_info(struct vnet_softc *, uint16_t, uint16_t);
2116902eb25Spalle void	vnet_send_attr_info(struct vnet_softc *);
2126902eb25Spalle void	vnet_send_dring_reg(struct vnet_softc *);
2136902eb25Spalle void	vio_send_rdx(struct vnet_softc *);
2146902eb25Spalle void	vnet_send_dring_data(struct vnet_softc *, uint32_t);
2156902eb25Spalle 
2166902eb25Spalle void	vnet_start(struct ifnet *);
2176902eb25Spalle void	vnet_start_desc(struct ifnet *);
2186902eb25Spalle int		vnet_ioctl(struct ifnet *, u_long, void *);
2196902eb25Spalle void	vnet_watchdog(struct ifnet *);
2206902eb25Spalle 
2216902eb25Spalle int		vnet_media_change(struct ifnet *);
2226902eb25Spalle void	vnet_media_status(struct ifnet *, struct ifmediareq *);
2236902eb25Spalle 
2246902eb25Spalle void	vnet_link_state(struct vnet_softc *sc);
2256902eb25Spalle 
2266902eb25Spalle void	vnet_setmulti(struct vnet_softc *, int);
2276902eb25Spalle 
228f7c20774Spalle int		vnet_init(struct ifnet *);
229f7c20774Spalle void	vnet_stop(struct ifnet *, int);
2306902eb25Spalle 
vnet_match(device_t parent,cfdata_t match,void * aux)2316902eb25Spalle int vnet_match(device_t parent, cfdata_t match, void *aux)
2326902eb25Spalle {
2336902eb25Spalle 
2346902eb25Spalle 	struct cbus_attach_args *ca = aux;
235f7c20774Spalle 
2366902eb25Spalle 	if (strcmp(ca->ca_name, "network") == 0)
2376902eb25Spalle 		return (1);
2386902eb25Spalle 
2396902eb25Spalle 	return (0);
2406902eb25Spalle }
2416902eb25Spalle 
2426902eb25Spalle void
vnet_attach(struct device * parent,struct device * self,void * aux)2436902eb25Spalle vnet_attach(struct device *parent, struct device *self, void *aux)
2446902eb25Spalle {
2456902eb25Spalle 	struct vnet_softc *sc = device_private(self);
2466902eb25Spalle 	struct cbus_attach_args *ca = aux;
2476902eb25Spalle 	struct ldc_conn *lc;
2486902eb25Spalle 	struct ifnet *ifp;
2496902eb25Spalle 
250efd62f8cSriastradh 	sc->sc_dv = self;
2516902eb25Spalle 	sc->sc_bustag = ca->ca_bustag;
2526902eb25Spalle 	sc->sc_dmatag = ca->ca_dmatag;
2536902eb25Spalle 	sc->sc_tx_ino = ca->ca_tx_ino;
2546902eb25Spalle 	sc->sc_rx_ino = ca->ca_rx_ino;
2556902eb25Spalle 
256c8dcbb02Spalle 	printf(": ivec 0x%" PRIx64 ", 0x%" PRIx64, sc->sc_tx_ino, sc->sc_rx_ino);
2576902eb25Spalle 
2586902eb25Spalle 	/*
2596902eb25Spalle 	 * Un-configure queues before registering interrupt handlers,
2606902eb25Spalle 	 * such that we dont get any stale LDC packets or events.
2616902eb25Spalle 	 */
2626902eb25Spalle 	hv_ldc_tx_qconf(ca->ca_id, 0, 0);
2636902eb25Spalle 	hv_ldc_rx_qconf(ca->ca_id, 0, 0);
2646902eb25Spalle 
2656902eb25Spalle 	sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_ino,
2666902eb25Spalle 	    IPL_NET, vnet_tx_intr, sc);
2676902eb25Spalle 	sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_ino,
2686902eb25Spalle 	    IPL_NET, vnet_rx_intr, sc);
2696902eb25Spalle 	if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) {
2706902eb25Spalle 		printf(", can't establish interrupts\n");
2716902eb25Spalle 		return;
2726902eb25Spalle 	}
2736902eb25Spalle 
2746902eb25Spalle 	lc = &sc->sc_lc;
2756902eb25Spalle 	lc->lc_id = ca->ca_id;
2766902eb25Spalle 	lc->lc_sc = sc;
2776902eb25Spalle 	lc->lc_reset = vnet_ldc_reset;
2786902eb25Spalle 	lc->lc_start = vnet_ldc_start;
2796902eb25Spalle 	lc->lc_rx_data = vio_rx_data;
2806902eb25Spalle 
281f7c20774Spalle 	callout_init(&sc->sc_handshake_co, 0);
28291d5826aSpalle 
2836902eb25Spalle 	sc->sc_peer_state = VIO_DP_STOPPED;
2846902eb25Spalle 
2856902eb25Spalle 	lc->lc_txq = ldc_queue_alloc(VNET_TX_ENTRIES);
2866902eb25Spalle 	if (lc->lc_txq == NULL) {
2876902eb25Spalle 		printf(", can't allocate tx queue\n");
2886902eb25Spalle 		return;
2896902eb25Spalle 	}
2906902eb25Spalle 
2916902eb25Spalle 	lc->lc_rxq = ldc_queue_alloc(VNET_RX_ENTRIES);
2926902eb25Spalle 	if (lc->lc_rxq == NULL) {
2936902eb25Spalle 		printf(", can't allocate rx queue\n");
2946902eb25Spalle 		goto free_txqueue;
2956902eb25Spalle 	}
2966902eb25Spalle 
2976902eb25Spalle 	if (OF_getprop(ca->ca_node, "local-mac-address",
2986902eb25Spalle 				   sc->sc_macaddr, ETHER_ADDR_LEN) > 0) {
2996902eb25Spalle 		printf(", address %s", ether_sprintf(sc->sc_macaddr));
3006902eb25Spalle 	} else {
3016902eb25Spalle 		printf(", cannot retrieve local mac address\n");
3026902eb25Spalle 		return;
3036902eb25Spalle 	}
3046902eb25Spalle 
3056902eb25Spalle 	/*
3066902eb25Spalle 	 * Each interface gets its own pool.
3076902eb25Spalle 	 */
308efd62f8cSriastradh 	pool_init(&sc->sc_pool, /*size*/2048, /*align*/0, /*align_offset*/0,
309efd62f8cSriastradh 	    /*flags*/0, /*wchan*/device_xname(sc->sc_dv), /*palloc*/NULL,
310efd62f8cSriastradh 	    IPL_NET);
3116902eb25Spalle 
3126902eb25Spalle 	ifp = &sc->sc_ethercom.ec_if;
3136902eb25Spalle 	ifp->if_softc = sc;
3146902eb25Spalle 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
315f7c20774Spalle 	ifp->if_init = vnet_init;
3166902eb25Spalle 	ifp->if_ioctl = vnet_ioctl;
3176902eb25Spalle 	ifp->if_start = vnet_start;
318f7c20774Spalle 	ifp->if_stop = vnet_stop;
3196902eb25Spalle 	ifp->if_watchdog = vnet_watchdog;
3206902eb25Spalle 	strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
3216902eb25Spalle 	IFQ_SET_MAXLEN(&ifp->if_snd, 31); /* XXX */
3226902eb25Spalle 
3236902eb25Spalle 	ifmedia_init(&sc->sc_media, 0, vnet_media_change, vnet_media_status);
3246902eb25Spalle 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
3256902eb25Spalle 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
3266902eb25Spalle 
327f7c20774Spalle 	if_attach(ifp);
328f7c20774Spalle 	ether_ifattach(ifp, sc->sc_macaddr);
32991d5826aSpalle 
3306902eb25Spalle 	printf("\n");
3316902eb25Spalle 	return;
3326902eb25Spalle free_txqueue:
3336902eb25Spalle 	ldc_queue_free(lc->lc_txq);
3346902eb25Spalle }
3356902eb25Spalle 
3366902eb25Spalle int
vnet_tx_intr(void * arg)3376902eb25Spalle vnet_tx_intr(void *arg)
3386902eb25Spalle {
3396902eb25Spalle 	struct vnet_softc *sc = arg;
3406902eb25Spalle 	struct ldc_conn *lc = &sc->sc_lc;
3416902eb25Spalle 	uint64_t tx_head, tx_tail, tx_state;
3426902eb25Spalle 
3436902eb25Spalle 	hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
3446902eb25Spalle 	if (tx_state != lc->lc_tx_state) {
3456902eb25Spalle 		switch (tx_state) {
3466902eb25Spalle 		case LDC_CHANNEL_DOWN:
3476902eb25Spalle 			DPRINTF(("%s: Tx link down\n", __func__));
3486902eb25Spalle 			break;
3496902eb25Spalle 		case LDC_CHANNEL_UP:
3506902eb25Spalle 			DPRINTF(("%s: Tx link up\n", __func__));
3516902eb25Spalle 			break;
3526902eb25Spalle 		case LDC_CHANNEL_RESET:
3536902eb25Spalle 			DPRINTF(("%s: Tx link reset\n", __func__));
3546902eb25Spalle 			break;
3556902eb25Spalle 		}
3566902eb25Spalle 		lc->lc_tx_state = tx_state;
3576902eb25Spalle 	}
3586902eb25Spalle 
3596902eb25Spalle 	return (1);
3606902eb25Spalle }
3616902eb25Spalle 
3626902eb25Spalle int
vnet_rx_intr(void * arg)3636902eb25Spalle vnet_rx_intr(void *arg)
3646902eb25Spalle {
3656902eb25Spalle 	struct vnet_softc *sc = arg;
3666902eb25Spalle 	struct ldc_conn *lc = &sc->sc_lc;
3676902eb25Spalle 	uint64_t rx_head, rx_tail, rx_state;
3686902eb25Spalle 	struct ldc_pkt *lp;
3696902eb25Spalle 	int err;
3706902eb25Spalle 
3716902eb25Spalle 	err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state);
372f7c20774Spalle 	if (err == H_EINVAL) {
373f7c20774Spalle 		printf("hv_ldc_rx_get_state failed\n");
3746902eb25Spalle 		return (0);
375f7c20774Spalle 	}
3766902eb25Spalle 	if (err != H_EOK) {
3776902eb25Spalle 		printf("hv_ldc_rx_get_state %d\n", err);
3786902eb25Spalle 		return (0);
3796902eb25Spalle 	}
3806902eb25Spalle 
3816902eb25Spalle 	if (rx_state != lc->lc_rx_state) {
3826902eb25Spalle 		switch (rx_state) {
3836902eb25Spalle 		case LDC_CHANNEL_DOWN:
3846902eb25Spalle 			lc->lc_tx_seqid = 0;
3856902eb25Spalle 			lc->lc_state = 0;
3866902eb25Spalle 			lc->lc_reset(lc);
3876902eb25Spalle 			if (rx_head == rx_tail)
3886902eb25Spalle 				break;
3896902eb25Spalle 			/* Discard and ack pending I/O. */
390f7c20774Spalle 			DPRINTF(("setting rx qhead to %" PRId64 "\n", rx_tail));
3916902eb25Spalle 			err = hv_ldc_rx_set_qhead(lc->lc_id, rx_tail);
3926902eb25Spalle 			if (err == H_EOK)
3936902eb25Spalle 				break;
3946902eb25Spalle 			printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
3956902eb25Spalle 			break;
3966902eb25Spalle 		case LDC_CHANNEL_UP:
397f7c20774Spalle 			callout_reset(&sc->sc_handshake_co, hz / 2, vnet_handshake, sc);
3986902eb25Spalle 			break;
3996902eb25Spalle 		case LDC_CHANNEL_RESET:
4006902eb25Spalle 			DPRINTF(("%s: Rx link reset\n", __func__));
4016902eb25Spalle 			lc->lc_tx_seqid = 0;
4026902eb25Spalle 			lc->lc_state = 0;
4036902eb25Spalle 			lc->lc_reset(lc);
404f7c20774Spalle 			callout_reset(&sc->sc_handshake_co, hz / 2, vnet_handshake, sc);
405f7c20774Spalle 			if (rx_head == rx_tail) {
4066902eb25Spalle 				break;
407f7c20774Spalle 			}
4086902eb25Spalle 			/* Discard and ack pending I/O. */
409f7c20774Spalle 			DPRINTF(("setting rx qhead to %" PRId64 "\n", rx_tail));
4106902eb25Spalle 			err = hv_ldc_rx_set_qhead(lc->lc_id, rx_tail);
4116902eb25Spalle 			if (err == H_EOK)
4126902eb25Spalle 				break;
4136902eb25Spalle 			printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
4146902eb25Spalle 			break;
415f7c20774Spalle 		default:
416f7c20774Spalle 			DPRINTF(("%s: unhandled rx_state %" PRIx64 "\n", __func__, rx_state));
417f7c20774Spalle 			break;
4186902eb25Spalle 		}
4196902eb25Spalle 		lc->lc_rx_state = rx_state;
4206902eb25Spalle 		return (1);
421f7c20774Spalle 	} else {
4226902eb25Spalle 	}
4236902eb25Spalle 
4246902eb25Spalle 	if (rx_head == rx_tail)
425f7c20774Spalle 	{
426f7c20774Spalle 		DPRINTF(("%s: head eq tail\n", __func__));
4276902eb25Spalle 		return (0);
428f7c20774Spalle 	}
429c8dcbb02Spalle 	lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_rxq->lq_va + rx_head);
4306902eb25Spalle 	switch (lp->type) {
4316902eb25Spalle 	case LDC_CTRL:
432f7c20774Spalle 		DPRINTF(("%s: LDC_CTRL\n", __func__));
4336902eb25Spalle 		ldc_rx_ctrl(lc, lp);
4346902eb25Spalle 		break;
4356902eb25Spalle 
4366902eb25Spalle 	case LDC_DATA:
437f7c20774Spalle 		DPRINTF(("%s: LDC_DATA\n", __func__));
4386902eb25Spalle 		ldc_rx_data(lc, lp);
4396902eb25Spalle 		break;
4406902eb25Spalle 
4416902eb25Spalle 	default:
442f7c20774Spalle 		DPRINTF(("%s: unhandled type %0x02/%0x02/%0x02\n",
443f7c20774Spalle 				 __func__, lp->type, lp->stype, lp->ctrl));
444*3194cf25Sandvar 		console_debugger();
4456902eb25Spalle 		ldc_reset(lc);
4466902eb25Spalle 		break;
4476902eb25Spalle 	}
4486902eb25Spalle 
4496902eb25Spalle 	if (lc->lc_state == 0)
4506902eb25Spalle 		return (1);
4516902eb25Spalle 
4526902eb25Spalle 	rx_head += sizeof(*lp);
4536902eb25Spalle 	rx_head &= ((lc->lc_rxq->lq_nentries * sizeof(*lp)) - 1);
4546902eb25Spalle 	err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head);
4556902eb25Spalle 	if (err != H_EOK)
4566902eb25Spalle 		printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
4576902eb25Spalle 	return (1);
4586902eb25Spalle }
4596902eb25Spalle 
4606902eb25Spalle void
vnet_handshake(void * arg)4616902eb25Spalle vnet_handshake(void *arg)
4626902eb25Spalle {
4636902eb25Spalle 	struct vnet_softc *sc = arg;
4646902eb25Spalle 
4656902eb25Spalle 	ldc_send_vers(&sc->sc_lc);
4666902eb25Spalle }
4676902eb25Spalle 
4686902eb25Spalle void
vio_rx_data(struct ldc_conn * lc,struct ldc_pkt * lp)4696902eb25Spalle vio_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
4706902eb25Spalle {
4716902eb25Spalle 	struct vio_msg *vm = (struct vio_msg *)lp;
4726902eb25Spalle 
4736902eb25Spalle 	switch (vm->type) {
4746902eb25Spalle 	case VIO_TYPE_CTRL:
4756902eb25Spalle 		if ((lp->env & LDC_FRAG_START) == 0 &&
476f7c20774Spalle 		    (lp->env & LDC_FRAG_STOP) == 0) {
477f7c20774Spalle 			DPRINTF(("%s: FRAG_START==0 and FRAG_STOP==0\n", __func__));
4786902eb25Spalle 			return;
479f7c20774Spalle 		}
4806902eb25Spalle 		vnet_rx_vio_ctrl(lc->lc_sc, vm);
4816902eb25Spalle 		break;
4826902eb25Spalle 
4836902eb25Spalle 	case VIO_TYPE_DATA:
484f7c20774Spalle 		if((lp->env & LDC_FRAG_START) == 0) {
485f7c20774Spalle 			DPRINTF(("%s: FRAG_START==0\n", __func__));
4866902eb25Spalle 			return;
487f7c20774Spalle 		}
4886902eb25Spalle 		vnet_rx_vio_data(lc->lc_sc, vm);
4896902eb25Spalle 		break;
4906902eb25Spalle 
4916902eb25Spalle 	default:
4926902eb25Spalle 		DPRINTF(("Unhandled packet type 0x%02x\n", vm->type));
4936902eb25Spalle 		ldc_reset(lc);
4946902eb25Spalle 		break;
4956902eb25Spalle 	}
4966902eb25Spalle }
4976902eb25Spalle 
4986902eb25Spalle void
vnet_rx_vio_ctrl(struct vnet_softc * sc,struct vio_msg * vm)4996902eb25Spalle vnet_rx_vio_ctrl(struct vnet_softc *sc, struct vio_msg *vm)
5006902eb25Spalle {
5016902eb25Spalle 	struct vio_msg_tag *tag = (struct vio_msg_tag *)&vm->type;
5026902eb25Spalle 
5036902eb25Spalle 	switch (tag->stype_env) {
5046902eb25Spalle 	case VIO_VER_INFO:
5056902eb25Spalle 		vnet_rx_vio_ver_info(sc, tag);
5066902eb25Spalle 		break;
5076902eb25Spalle 	case VIO_ATTR_INFO:
5086902eb25Spalle 		vnet_rx_vio_attr_info(sc, tag);
5096902eb25Spalle 		break;
5106902eb25Spalle 	case VIO_DRING_REG:
5116902eb25Spalle 		vnet_rx_vio_dring_reg(sc, tag);
5126902eb25Spalle 		break;
5136902eb25Spalle 	case VIO_RDX:
5146902eb25Spalle 		vnet_rx_vio_rdx(sc, tag);
5156902eb25Spalle 		break;
516b7b2672bSpalle 	case VNET_MCAST_INFO:
517b7b2672bSpalle 		vnet_rx_vio_mcast_info(sc, tag);
518b7b2672bSpalle 		break;
5196902eb25Spalle 	default:
520f7c20774Spalle 		printf("%s: CTRL/0x%02x/0x%04x FIXME\n",
521f7c20774Spalle 				 __func__, tag->stype, tag->stype_env);
5226902eb25Spalle 		break;
5236902eb25Spalle 	}
5246902eb25Spalle }
5256902eb25Spalle 
5266902eb25Spalle void
vnet_rx_vio_ver_info(struct vnet_softc * sc,struct vio_msg_tag * tag)5276902eb25Spalle vnet_rx_vio_ver_info(struct vnet_softc *sc, struct vio_msg_tag *tag)
5286902eb25Spalle {
5296902eb25Spalle 	struct vio_ver_info *vi = (struct vio_ver_info *)tag;
5306902eb25Spalle 
5316902eb25Spalle 	switch (vi->tag.stype) {
5326902eb25Spalle 	case VIO_SUBTYPE_INFO:
5336902eb25Spalle 		DPRINTF(("CTRL/INFO/VER_INFO\n"));
5346902eb25Spalle 
5356902eb25Spalle 		/* Make sure we're talking to a virtual network device. */
5366902eb25Spalle 		if (vi->dev_class != VDEV_NETWORK &&
5376902eb25Spalle 		    vi->dev_class != VDEV_NETWORK_SWITCH) {
538f7c20774Spalle 			DPRINTF(("Class is not network or network switch\n"));
5396902eb25Spalle 			/* Huh, we're not talking to a network device? */
5406902eb25Spalle 			printf("Not a network device\n");
5416902eb25Spalle 			vi->tag.stype = VIO_SUBTYPE_NACK;
5426902eb25Spalle 			vnet_sendmsg(sc, vi, sizeof(*vi));
5436902eb25Spalle 			return;
5446902eb25Spalle 		}
5456902eb25Spalle 
5466902eb25Spalle 		if (vi->major != VNET_MAJOR) {
547f7c20774Spalle 			DPRINTF(("Major mismatch %" PRId8 " vs %" PRId8 "\n",
548f7c20774Spalle 					 vi->major, VNET_MAJOR));
5496902eb25Spalle 			vi->tag.stype = VIO_SUBTYPE_NACK;
5506902eb25Spalle 			vi->major = VNET_MAJOR;
5516902eb25Spalle 			vi->minor = VNET_MINOR;
5526902eb25Spalle 			vnet_sendmsg(sc, vi, sizeof(*vi));
5536902eb25Spalle 			return;
5546902eb25Spalle 		}
5556902eb25Spalle 
5566902eb25Spalle 		vi->tag.stype = VIO_SUBTYPE_ACK;
5576902eb25Spalle 		vi->tag.sid = sc->sc_local_sid;
5586902eb25Spalle 		vi->minor = VNET_MINOR;
5596902eb25Spalle 		vnet_sendmsg(sc, vi, sizeof(*vi));
5606902eb25Spalle 		sc->sc_vio_state |= VIO_RCV_VER_INFO;
5616902eb25Spalle 		break;
5626902eb25Spalle 
5636902eb25Spalle 	case VIO_SUBTYPE_ACK:
5646902eb25Spalle 		DPRINTF(("CTRL/ACK/VER_INFO\n"));
5656902eb25Spalle 		if (!ISSET(sc->sc_vio_state, VIO_SND_VER_INFO)) {
5666902eb25Spalle 			ldc_reset(&sc->sc_lc);
5676902eb25Spalle 			break;
5686902eb25Spalle 		}
5696902eb25Spalle 		sc->sc_vio_state |= VIO_ACK_VER_INFO;
5706902eb25Spalle 		break;
5716902eb25Spalle 
5726902eb25Spalle 	default:
5736902eb25Spalle 		DPRINTF(("CTRL/0x%02x/VER_INFO\n", vi->tag.stype));
5746902eb25Spalle 		break;
5756902eb25Spalle 	}
5766902eb25Spalle 
5776902eb25Spalle 	if (ISSET(sc->sc_vio_state, VIO_RCV_VER_INFO) &&
5786902eb25Spalle 	    ISSET(sc->sc_vio_state, VIO_ACK_VER_INFO))
5796902eb25Spalle 		vnet_send_attr_info(sc);
5806902eb25Spalle }
5816902eb25Spalle 
5826902eb25Spalle void
vnet_rx_vio_attr_info(struct vnet_softc * sc,struct vio_msg_tag * tag)5836902eb25Spalle vnet_rx_vio_attr_info(struct vnet_softc *sc, struct vio_msg_tag *tag)
5846902eb25Spalle {
5856902eb25Spalle 	struct vnet_attr_info *ai = (struct vnet_attr_info *)tag;
5866902eb25Spalle 
5876902eb25Spalle 	switch (ai->tag.stype) {
5886902eb25Spalle 	case VIO_SUBTYPE_INFO:
5896902eb25Spalle 		DPRINTF(("CTRL/INFO/ATTR_INFO\n"));
5906902eb25Spalle 		sc->sc_xfer_mode = ai->xfer_mode;
5916902eb25Spalle 		ai->tag.stype = VIO_SUBTYPE_ACK;
5926902eb25Spalle 		ai->tag.sid = sc->sc_local_sid;
5936902eb25Spalle 		vnet_sendmsg(sc, ai, sizeof(*ai));
5946902eb25Spalle 		sc->sc_vio_state |= VIO_RCV_ATTR_INFO;
5956902eb25Spalle 		break;
5966902eb25Spalle 
5976902eb25Spalle 	case VIO_SUBTYPE_ACK:
5986902eb25Spalle 		DPRINTF(("CTRL/ACK/ATTR_INFO\n"));
5996902eb25Spalle 		if (!ISSET(sc->sc_vio_state, VIO_SND_ATTR_INFO)) {
6006902eb25Spalle 			ldc_reset(&sc->sc_lc);
6016902eb25Spalle 			break;
6026902eb25Spalle 		}
6036902eb25Spalle 		sc->sc_vio_state |= VIO_ACK_ATTR_INFO;
6046902eb25Spalle 		break;
6056902eb25Spalle 
6066902eb25Spalle 	default:
6076902eb25Spalle 		DPRINTF(("CTRL/0x%02x/ATTR_INFO\n", ai->tag.stype));
6086902eb25Spalle 		break;
6096902eb25Spalle 	}
6106902eb25Spalle 
6116902eb25Spalle 	if (ISSET(sc->sc_vio_state, VIO_RCV_ATTR_INFO) &&
6126902eb25Spalle 	    ISSET(sc->sc_vio_state, VIO_ACK_ATTR_INFO)) {
6136902eb25Spalle 		if (sc->sc_xfer_mode == VIO_DRING_MODE)
6146902eb25Spalle 			vnet_send_dring_reg(sc);
6156902eb25Spalle 		else
6166902eb25Spalle 			vio_send_rdx(sc);
6176902eb25Spalle 	}
6186902eb25Spalle }
6196902eb25Spalle 
6206902eb25Spalle void
vnet_rx_vio_dring_reg(struct vnet_softc * sc,struct vio_msg_tag * tag)6216902eb25Spalle vnet_rx_vio_dring_reg(struct vnet_softc *sc, struct vio_msg_tag *tag)
6226902eb25Spalle {
6236902eb25Spalle 	struct vio_dring_reg *dr = (struct vio_dring_reg *)tag;
6246902eb25Spalle 
6256902eb25Spalle 	switch (dr->tag.stype) {
6266902eb25Spalle 	case VIO_SUBTYPE_INFO:
6276902eb25Spalle 		DPRINTF(("CTRL/INFO/DRING_REG\n"));
6286902eb25Spalle 		sc->sc_peer_dring_nentries = dr->num_descriptors;
6296902eb25Spalle 		sc->sc_peer_desc_size = dr->descriptor_size;
6306902eb25Spalle 		sc->sc_peer_dring_cookie = dr->cookie[0];
6316902eb25Spalle 
6326902eb25Spalle 		dr->tag.stype = VIO_SUBTYPE_ACK;
6336902eb25Spalle 		dr->tag.sid = sc->sc_local_sid;
6346902eb25Spalle 		vnet_sendmsg(sc, dr, sizeof(*dr));
6356902eb25Spalle 		sc->sc_vio_state |= VIO_RCV_DRING_REG;
6366902eb25Spalle 		break;
6376902eb25Spalle 
6386902eb25Spalle 	case VIO_SUBTYPE_ACK:
6396902eb25Spalle 		DPRINTF(("CTRL/ACK/DRING_REG\n"));
6406902eb25Spalle 		if (!ISSET(sc->sc_vio_state, VIO_SND_DRING_REG)) {
6416902eb25Spalle 			ldc_reset(&sc->sc_lc);
6426902eb25Spalle 			break;
6436902eb25Spalle 		}
6446902eb25Spalle 
6456902eb25Spalle 		sc->sc_dring_ident = dr->dring_ident;
6466902eb25Spalle 		sc->sc_seq_no = 1;
6476902eb25Spalle 
6486902eb25Spalle 		sc->sc_vio_state |= VIO_ACK_DRING_REG;
6496902eb25Spalle 		break;
6506902eb25Spalle 
6516902eb25Spalle 	default:
6526902eb25Spalle 		DPRINTF(("CTRL/0x%02x/DRING_REG\n", dr->tag.stype));
6536902eb25Spalle 		break;
6546902eb25Spalle 	}
6556902eb25Spalle 
6566902eb25Spalle 	if (ISSET(sc->sc_vio_state, VIO_RCV_DRING_REG) &&
6576902eb25Spalle 	    ISSET(sc->sc_vio_state, VIO_ACK_DRING_REG))
6586902eb25Spalle 		vio_send_rdx(sc);
6596902eb25Spalle }
6606902eb25Spalle 
6616902eb25Spalle void
vnet_rx_vio_rdx(struct vnet_softc * sc,struct vio_msg_tag * tag)6626902eb25Spalle vnet_rx_vio_rdx(struct vnet_softc *sc, struct vio_msg_tag *tag)
6636902eb25Spalle {
6646902eb25Spalle 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
6656902eb25Spalle 
6666902eb25Spalle 	switch(tag->stype) {
6676902eb25Spalle 	case VIO_SUBTYPE_INFO:
6686902eb25Spalle 		DPRINTF(("CTRL/INFO/RDX\n"));
6696902eb25Spalle 		tag->stype = VIO_SUBTYPE_ACK;
6706902eb25Spalle 		tag->sid = sc->sc_local_sid;
6716902eb25Spalle 		vnet_sendmsg(sc, tag, sizeof(*tag));
6726902eb25Spalle 		sc->sc_vio_state |= VIO_RCV_RDX;
6736902eb25Spalle 		break;
6746902eb25Spalle 
6756902eb25Spalle 	case VIO_SUBTYPE_ACK:
6766902eb25Spalle 		DPRINTF(("CTRL/ACK/RDX\n"));
6776902eb25Spalle 		if (!ISSET(sc->sc_vio_state, VIO_SND_RDX)) {
6786902eb25Spalle 			ldc_reset(&sc->sc_lc);
6796902eb25Spalle 			break;
6806902eb25Spalle 		}
6816902eb25Spalle 		sc->sc_vio_state |= VIO_ACK_RDX;
6826902eb25Spalle 		break;
6836902eb25Spalle 
6846902eb25Spalle 	default:
6856902eb25Spalle 		DPRINTF(("CTRL/0x%02x/RDX (VIO)\n", tag->stype));
6866902eb25Spalle 		break;
6876902eb25Spalle 	}
6886902eb25Spalle 
6896902eb25Spalle 	if (ISSET(sc->sc_vio_state, VIO_RCV_RDX) &&
6906902eb25Spalle 	    ISSET(sc->sc_vio_state, VIO_ACK_RDX)) {
6916902eb25Spalle 		/* Link is up! */
6926902eb25Spalle 		vnet_link_state(sc);
6936902eb25Spalle 
6946902eb25Spalle 		/* Configure multicast now that we can. */
6956902eb25Spalle 		vnet_setmulti(sc, 1);
6966902eb25Spalle 
6976902eb25Spalle 		KERNEL_LOCK(1, curlwp);
6986902eb25Spalle 		vnet_start(ifp);
6996902eb25Spalle 		KERNEL_UNLOCK_ONE(curlwp);
7006902eb25Spalle 	}
7016902eb25Spalle }
7026902eb25Spalle 
7036902eb25Spalle void
vnet_rx_vio_mcast_info(struct vnet_softc * sc,struct vio_msg_tag * tag)704b7b2672bSpalle vnet_rx_vio_mcast_info(struct vnet_softc *sc, struct vio_msg_tag *tag)
705b7b2672bSpalle {
706b7b2672bSpalle 	switch(tag->stype) {
707b7b2672bSpalle 
708b7b2672bSpalle 		case VIO_SUBTYPE_INFO:
709b7b2672bSpalle 			DPRINTF(("CTRL/INFO/MCAST_INFO\n"));
710b7b2672bSpalle 			break;
711b7b2672bSpalle 
712b7b2672bSpalle 		case VIO_SUBTYPE_ACK:
713b7b2672bSpalle 			DPRINTF(("CTRL/ACK/MCAST_INFO\n"));
714b7b2672bSpalle 			break;
715b7b2672bSpalle 
716b7b2672bSpalle 		case VIO_SUBTYPE_NACK:
717b7b2672bSpalle 			DPRINTF(("CTRL/NACK/MCAST_INFO\n"));
718b7b2672bSpalle 			break;
719b7b2672bSpalle 
720b7b2672bSpalle 		default:
721b7b2672bSpalle 			printf("%s: CTRL/0x%02x/0x%04x\n",
722b7b2672bSpalle 				   __func__, tag->stype, tag->stype_env);
723b7b2672bSpalle 			break;
724b7b2672bSpalle 	}
725b7b2672bSpalle }
726b7b2672bSpalle 
727b7b2672bSpalle void
vnet_rx_vio_data(struct vnet_softc * sc,struct vio_msg * vm)7286902eb25Spalle vnet_rx_vio_data(struct vnet_softc *sc, struct vio_msg *vm)
7296902eb25Spalle {
7306902eb25Spalle 	struct vio_msg_tag *tag = (struct vio_msg_tag *)&vm->type;
7316902eb25Spalle 
7326902eb25Spalle 	if (!ISSET(sc->sc_vio_state, VIO_RCV_RDX) ||
7336902eb25Spalle 	    !ISSET(sc->sc_vio_state, VIO_ACK_RDX)) {
7346902eb25Spalle 		DPRINTF(("Spurious DATA/0x%02x/0x%04x\n", tag->stype,
7356902eb25Spalle 		    tag->stype_env));
7366902eb25Spalle 		return;
7376902eb25Spalle 	}
7386902eb25Spalle 
7396902eb25Spalle 	switch(tag->stype_env) {
7406902eb25Spalle 	case VIO_DESC_DATA:
7416902eb25Spalle 		vnet_rx_vio_desc_data(sc, tag);
7426902eb25Spalle 		break;
7436902eb25Spalle 
7446902eb25Spalle 	case VIO_DRING_DATA:
7456902eb25Spalle 		vnet_rx_vio_dring_data(sc, tag);
7466902eb25Spalle 		break;
7476902eb25Spalle 
7486902eb25Spalle 	default:
7496902eb25Spalle 		DPRINTF(("DATA/0x%02x/0x%04x\n", tag->stype, tag->stype_env));
7506902eb25Spalle 		break;
7516902eb25Spalle 	}
7526902eb25Spalle }
7536902eb25Spalle 
7546902eb25Spalle void
vnet_rx_vio_desc_data(struct vnet_softc * sc,struct vio_msg_tag * tag)7556902eb25Spalle vnet_rx_vio_desc_data(struct vnet_softc *sc, struct vio_msg_tag *tag)
7566902eb25Spalle {
757f7c20774Spalle 
7586902eb25Spalle 	struct vnet_desc_msg *dm = (struct vnet_desc_msg *)tag;
7596902eb25Spalle 	struct ldc_conn *lc = &sc->sc_lc;
7606902eb25Spalle 	struct ldc_map *map = sc->sc_lm;
7616902eb25Spalle 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
7626902eb25Spalle 	struct mbuf *m;
7636902eb25Spalle 	unsigned char *buf;
7646902eb25Spalle 	paddr_t pa;
7656902eb25Spalle 	psize_t nbytes;
7666902eb25Spalle 	u_int cons;
7676902eb25Spalle 	int err;
7686902eb25Spalle 
7696902eb25Spalle 	switch(tag->stype) {
7706902eb25Spalle 	case VIO_SUBTYPE_INFO:
7716902eb25Spalle 		buf = pool_get(&sc->sc_pool, PR_NOWAIT|PR_ZERO);
7726902eb25Spalle 		if (buf == NULL) {
7736902eb25Spalle 			if_statinc(ifp, if_ierrors);
7746902eb25Spalle 			goto skip;
7756902eb25Spalle 		}
7766902eb25Spalle 		nbytes = roundup(dm->nbytes, 8);
7776902eb25Spalle 
7786902eb25Spalle 		if (dm->nbytes > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
7796902eb25Spalle 			if_statinc(ifp, if_ierrors);
7806902eb25Spalle 			goto skip;
7816902eb25Spalle 		}
7826902eb25Spalle 
7836902eb25Spalle 		pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa);
7846902eb25Spalle 		err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN,
7856902eb25Spalle 		    dm->cookie[0].addr, pa, nbytes, &nbytes);
7866902eb25Spalle 		if (err != H_EOK) {
7876902eb25Spalle 			pool_put(&sc->sc_pool, buf);
7886902eb25Spalle 			if_statinc(ifp, if_ierrors);
7896902eb25Spalle 			goto skip;
7906902eb25Spalle 		}
7916902eb25Spalle 
7926902eb25Spalle 		/* Stupid OBP doesn't align properly. */
7936902eb25Spalle 		m = m_devget(buf, dm->nbytes, 0, ifp);
7946902eb25Spalle 		pool_put(&sc->sc_pool, buf);
7956902eb25Spalle 		if (m == NULL) {
7966902eb25Spalle 			if_statinc(ifp, if_ierrors);
7976902eb25Spalle 			goto skip;
7986902eb25Spalle 		}
7996902eb25Spalle 
8006902eb25Spalle 		/* Pass it on. */
8016902eb25Spalle 		if_percpuq_enqueue(ifp->if_percpuq, m);
8026902eb25Spalle 	skip:
8036902eb25Spalle 		dm->tag.stype = VIO_SUBTYPE_ACK;
8046902eb25Spalle 		dm->tag.sid = sc->sc_local_sid;
8056902eb25Spalle 		vnet_sendmsg(sc, dm, sizeof(*dm));
8066902eb25Spalle 		break;
8076902eb25Spalle 
8086902eb25Spalle 	case VIO_SUBTYPE_ACK:
8096902eb25Spalle 		DPRINTF(("DATA/ACK/DESC_DATA\n"));
8106902eb25Spalle 
8116902eb25Spalle 		if (dm->desc_handle != sc->sc_tx_cons) {
8126902eb25Spalle 			printf("out of order\n");
8136902eb25Spalle 			return;
8146902eb25Spalle 		}
8156902eb25Spalle 
8166902eb25Spalle 		cons = sc->sc_tx_cons & (sc->sc_vd->vd_nentries - 1);
8176902eb25Spalle 
8186902eb25Spalle 		map->lm_slot[sc->sc_vsd[cons].vsd_map_idx].entry = 0;
81991d5826aSpalle 		atomic_dec_32(&map->lm_count);
8206902eb25Spalle 
8216902eb25Spalle 		pool_put(&sc->sc_pool, sc->sc_vsd[cons].vsd_buf);
8226902eb25Spalle 		sc->sc_vsd[cons].vsd_buf = NULL;
8236902eb25Spalle 
8246902eb25Spalle 		sc->sc_tx_cons++;
8256902eb25Spalle 		break;
8266902eb25Spalle 
8276902eb25Spalle 	case VIO_SUBTYPE_NACK:
8286902eb25Spalle 		DPRINTF(("DATA/NACK/DESC_DATA\n"));
8296902eb25Spalle 		break;
8306902eb25Spalle 
8316902eb25Spalle 	default:
8326902eb25Spalle 		DPRINTF(("DATA/0x%02x/DESC_DATA\n", tag->stype));
8336902eb25Spalle 		break;
8346902eb25Spalle 	}
8356902eb25Spalle }
8366902eb25Spalle 
8376902eb25Spalle void
vnet_rx_vio_dring_data(struct vnet_softc * sc,struct vio_msg_tag * tag)8386902eb25Spalle vnet_rx_vio_dring_data(struct vnet_softc *sc, struct vio_msg_tag *tag)
8396902eb25Spalle {
8406902eb25Spalle 	struct vio_dring_msg *dm = (struct vio_dring_msg *)tag;
8416902eb25Spalle 	struct ldc_conn *lc = &sc->sc_lc;
8426902eb25Spalle 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
8436902eb25Spalle 	struct mbuf *m = NULL;
8446902eb25Spalle 	paddr_t pa;
8456902eb25Spalle 	psize_t nbytes;
8466902eb25Spalle 	int err;
8476902eb25Spalle 
8486902eb25Spalle 	switch(tag->stype) {
8496902eb25Spalle 	case VIO_SUBTYPE_INFO:
8506902eb25Spalle 	{
851f7c20774Spalle 		DPRINTF(("%s: VIO_SUBTYPE_INFO\n", __func__));
8526902eb25Spalle 		struct vnet_desc desc;
8536902eb25Spalle 		uint64_t cookie;
8546902eb25Spalle 		paddr_t desc_pa;
8556902eb25Spalle 		int idx, ack_end_idx = -1;
8566902eb25Spalle 
8576902eb25Spalle 		idx = dm->start_idx;
8586902eb25Spalle 		for (;;) {
8596902eb25Spalle 			cookie = sc->sc_peer_dring_cookie.addr;
8606902eb25Spalle 			cookie += idx * sc->sc_peer_desc_size;
8616902eb25Spalle 			nbytes = sc->sc_peer_desc_size;
8626902eb25Spalle 			pmap_extract(pmap_kernel(), (vaddr_t)&desc, &desc_pa);
8636902eb25Spalle 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN, cookie,
8646902eb25Spalle 			    desc_pa, nbytes, &nbytes);
8656902eb25Spalle 			if (err != H_EOK) {
8666902eb25Spalle 				printf("hv_ldc_copy_in %d\n", err);
8676902eb25Spalle 				break;
8686902eb25Spalle 			}
8696902eb25Spalle 
8706902eb25Spalle 			if (desc.hdr.dstate != VIO_DESC_READY)
8716902eb25Spalle 				break;
8726902eb25Spalle 
8736902eb25Spalle 			if (desc.nbytes > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
8746902eb25Spalle 				if_statinc(ifp, if_ierrors);
8756902eb25Spalle 				goto skip;
8766902eb25Spalle 			}
87791d5826aSpalle 
878f7c20774Spalle 			MGETHDR(m, M_DONTWAIT, MT_DATA);
879f7c20774Spalle 			if (m == NULL) {
880f7c20774Spalle 				DPRINTF(("%s: MGETHDR failed\n", __func__));
881f7c20774Spalle 				if_statinc(ifp, if_ierrors);
882f7c20774Spalle 				goto skip;
883f7c20774Spalle 			}
884f7c20774Spalle 			MCLGET(m, M_DONTWAIT);
8856902eb25Spalle 			if ((m->m_flags & M_EXT) == 0)
8866902eb25Spalle 				break;
8876902eb25Spalle 			m->m_len = m->m_pkthdr.len = desc.nbytes;
8886902eb25Spalle 			nbytes = roundup(desc.nbytes + VNET_ETHER_ALIGN, 8);
88991d5826aSpalle 
8906902eb25Spalle 			pmap_extract(pmap_kernel(), (vaddr_t)m->m_data, &pa);
8916902eb25Spalle 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN,
8926902eb25Spalle 			    desc.cookie[0].addr, pa, nbytes, &nbytes);
8936902eb25Spalle 			if (err != H_EOK) {
8946902eb25Spalle 				m_freem(m);
8956902eb25Spalle 				goto skip;
8966902eb25Spalle 			}
8976902eb25Spalle 			m->m_data += VNET_ETHER_ALIGN;
898b7b2672bSpalle 			m_set_rcvif(m, ifp);
8996902eb25Spalle 
9006902eb25Spalle 			if_percpuq_enqueue(ifp->if_percpuq, m);
9016902eb25Spalle 
9026902eb25Spalle 		skip:
9036902eb25Spalle 			desc.hdr.dstate = VIO_DESC_DONE;
9046902eb25Spalle 			nbytes = sc->sc_peer_desc_size;
9056902eb25Spalle 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT, cookie,
9066902eb25Spalle 			    desc_pa, nbytes, &nbytes);
9076902eb25Spalle 			if (err != H_EOK)
9086902eb25Spalle 				printf("hv_ldc_copy_out %d\n", err);
9096902eb25Spalle 
9106902eb25Spalle 			ack_end_idx = idx;
9116902eb25Spalle 			if (++idx == sc->sc_peer_dring_nentries)
9126902eb25Spalle 				idx = 0;
9136902eb25Spalle 		}
9146902eb25Spalle 
9156902eb25Spalle 		if (ack_end_idx == -1) {
9166902eb25Spalle 			dm->tag.stype = VIO_SUBTYPE_NACK;
9176902eb25Spalle 		} else {
9186902eb25Spalle 			dm->tag.stype = VIO_SUBTYPE_ACK;
9196902eb25Spalle 			dm->end_idx = ack_end_idx;
9206902eb25Spalle 		}
9216902eb25Spalle 		dm->tag.sid = sc->sc_local_sid;
9226902eb25Spalle 		dm->proc_state = VIO_DP_STOPPED;
9236902eb25Spalle 		vnet_sendmsg(sc, dm, sizeof(*dm));
9246902eb25Spalle 		break;
9256902eb25Spalle 	}
9266902eb25Spalle 
9276902eb25Spalle 	case VIO_SUBTYPE_ACK:
9286902eb25Spalle 	{
929f7c20774Spalle 		DPRINTF(("%s: VIO_SUBTYPE_ACK\n", __func__));
9306902eb25Spalle 		struct ldc_map *map = sc->sc_lm;
9316902eb25Spalle 		u_int cons, count;
9326902eb25Spalle 
9336902eb25Spalle 		sc->sc_peer_state = dm->proc_state;
9346902eb25Spalle 
9356902eb25Spalle 		cons = sc->sc_tx_cons & (sc->sc_vd->vd_nentries - 1);
9366902eb25Spalle 		while (sc->sc_vd->vd_desc[cons].hdr.dstate == VIO_DESC_DONE) {
9376902eb25Spalle 			map->lm_slot[sc->sc_vsd[cons].vsd_map_idx].entry = 0;
93891d5826aSpalle 			atomic_dec_32(&map->lm_count);
9396902eb25Spalle 
9406902eb25Spalle 			pool_put(&sc->sc_pool, sc->sc_vsd[cons].vsd_buf);
9416902eb25Spalle 			sc->sc_vsd[cons].vsd_buf = NULL;
9426902eb25Spalle 
9436902eb25Spalle 			sc->sc_vd->vd_desc[cons].hdr.dstate = VIO_DESC_FREE;
9446902eb25Spalle 			sc->sc_tx_cons++;
9456902eb25Spalle 			cons = sc->sc_tx_cons & (sc->sc_vd->vd_nentries - 1);
9466902eb25Spalle 		}
9476902eb25Spalle 
9486902eb25Spalle 		count = sc->sc_tx_prod - sc->sc_tx_cons;
9496902eb25Spalle 		if (count > 0 && sc->sc_peer_state != VIO_DP_ACTIVE)
9506902eb25Spalle 			vnet_send_dring_data(sc, cons);
9516902eb25Spalle 
9526902eb25Spalle 		KERNEL_LOCK(1, curlwp);
9536902eb25Spalle 		if (count == 0)
9546902eb25Spalle 			ifp->if_timer = 0;
9556902eb25Spalle 
9566902eb25Spalle 		vnet_start(ifp);
9576902eb25Spalle 		KERNEL_UNLOCK_ONE(curlwp);
9586902eb25Spalle 		break;
9596902eb25Spalle 	}
9606902eb25Spalle 
9616902eb25Spalle 	case VIO_SUBTYPE_NACK:
9626902eb25Spalle 		DPRINTF(("DATA/NACK/DRING_DATA\n"));
9636902eb25Spalle 		sc->sc_peer_state = VIO_DP_STOPPED;
9646902eb25Spalle 		break;
9656902eb25Spalle 
9666902eb25Spalle 	default:
9676902eb25Spalle 		DPRINTF(("DATA/0x%02x/DRING_DATA\n", tag->stype));
9686902eb25Spalle 		break;
9696902eb25Spalle 	}
9706902eb25Spalle }
9716902eb25Spalle 
9726902eb25Spalle void
vnet_ldc_reset(struct ldc_conn * lc)9736902eb25Spalle vnet_ldc_reset(struct ldc_conn *lc)
9746902eb25Spalle {
975f7c20774Spalle 
9766902eb25Spalle 	struct vnet_softc *sc = lc->lc_sc;
9776902eb25Spalle 	int i;
97891d5826aSpalle 
979f7c20774Spalle 	callout_stop(&sc->sc_handshake_co);
9806902eb25Spalle 	sc->sc_tx_prod = sc->sc_tx_cons = 0;
9816902eb25Spalle 	sc->sc_peer_state = VIO_DP_STOPPED;
9826902eb25Spalle 	sc->sc_vio_state = 0;
9836902eb25Spalle 	vnet_link_state(sc);
9846902eb25Spalle 
9856902eb25Spalle 	sc->sc_lm->lm_next = 1;
9866902eb25Spalle 	sc->sc_lm->lm_count = 1;
9876902eb25Spalle 	for (i = 1; i < sc->sc_lm->lm_nentries; i++)
9886902eb25Spalle 		sc->sc_lm->lm_slot[i].entry = 0;
9896902eb25Spalle 
9906902eb25Spalle 	for (i = 0; i < sc->sc_vd->vd_nentries; i++) {
9916902eb25Spalle 		if (sc->sc_vsd[i].vsd_buf) {
9926902eb25Spalle 			pool_put(&sc->sc_pool, sc->sc_vsd[i].vsd_buf);
9936902eb25Spalle 			sc->sc_vsd[i].vsd_buf = NULL;
9946902eb25Spalle 		}
9956902eb25Spalle 		sc->sc_vd->vd_desc[i].hdr.dstate = VIO_DESC_FREE;
9966902eb25Spalle 	}
9976902eb25Spalle }
9986902eb25Spalle 
9996902eb25Spalle void
vnet_ldc_start(struct ldc_conn * lc)10006902eb25Spalle vnet_ldc_start(struct ldc_conn *lc)
10016902eb25Spalle {
10026902eb25Spalle 	struct vnet_softc *sc = lc->lc_sc;
1003f7c20774Spalle 	callout_stop(&sc->sc_handshake_co);
10046902eb25Spalle 	vnet_send_ver_info(sc, VNET_MAJOR, VNET_MINOR);
10056902eb25Spalle }
10066902eb25Spalle 
10076902eb25Spalle void
vnet_sendmsg(struct vnet_softc * sc,void * msg,size_t len)10086902eb25Spalle vnet_sendmsg(struct vnet_softc *sc, void *msg, size_t len)
10096902eb25Spalle {
10106902eb25Spalle 	struct ldc_conn *lc = &sc->sc_lc;
10116902eb25Spalle 	int err;
10126902eb25Spalle 
10136902eb25Spalle 	err = ldc_send_unreliable(lc, msg, len);
10146902eb25Spalle 	if (err)
10156902eb25Spalle 		printf("%s: ldc_send_unreliable: %d\n", __func__, err);
10166902eb25Spalle }
10176902eb25Spalle 
10186902eb25Spalle void
vnet_send_ver_info(struct vnet_softc * sc,uint16_t major,uint16_t minor)10196902eb25Spalle vnet_send_ver_info(struct vnet_softc *sc, uint16_t major, uint16_t minor)
10206902eb25Spalle {
10216902eb25Spalle 	struct vio_ver_info vi;
10226902eb25Spalle 
10236902eb25Spalle 	bzero(&vi, sizeof(vi));
10246902eb25Spalle 	vi.tag.type = VIO_TYPE_CTRL;
10256902eb25Spalle 	vi.tag.stype = VIO_SUBTYPE_INFO;
10266902eb25Spalle 	vi.tag.stype_env = VIO_VER_INFO;
10276902eb25Spalle 	vi.tag.sid = sc->sc_local_sid;
10286902eb25Spalle 	vi.major = major;
10296902eb25Spalle 	vi.minor = minor;
10306902eb25Spalle 	vi.dev_class = VDEV_NETWORK;
10316902eb25Spalle 	vnet_sendmsg(sc, &vi, sizeof(vi));
10326902eb25Spalle 
10336902eb25Spalle 	sc->sc_vio_state |= VIO_SND_VER_INFO;
10346902eb25Spalle }
10356902eb25Spalle 
10366902eb25Spalle void
vnet_send_attr_info(struct vnet_softc * sc)10376902eb25Spalle vnet_send_attr_info(struct vnet_softc *sc)
10386902eb25Spalle {
10396902eb25Spalle 	struct vnet_attr_info ai;
10406902eb25Spalle 	int i;
10416902eb25Spalle 
10426902eb25Spalle 	bzero(&ai, sizeof(ai));
10436902eb25Spalle 	ai.tag.type = VIO_TYPE_CTRL;
10446902eb25Spalle 	ai.tag.stype = VIO_SUBTYPE_INFO;
10456902eb25Spalle 	ai.tag.stype_env = VIO_ATTR_INFO;
10466902eb25Spalle 	ai.tag.sid = sc->sc_local_sid;
10476902eb25Spalle 	ai.xfer_mode = VIO_DRING_MODE;
10486902eb25Spalle 	ai.addr_type = VNET_ADDR_ETHERMAC;
10496902eb25Spalle 	ai.ack_freq = 0;
10506902eb25Spalle 	ai.addr = 0;
10516902eb25Spalle 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
10526902eb25Spalle 		ai.addr <<= 8;
10536902eb25Spalle 		ai.addr |= sc->sc_macaddr[i];
10546902eb25Spalle 	}
10556902eb25Spalle 	ai.mtu = ETHER_MAX_LEN - ETHER_CRC_LEN;
10566902eb25Spalle 	vnet_sendmsg(sc, &ai, sizeof(ai));
10576902eb25Spalle 
10586902eb25Spalle 	sc->sc_vio_state |= VIO_SND_ATTR_INFO;
10596902eb25Spalle }
10606902eb25Spalle 
10616902eb25Spalle void
vnet_send_dring_reg(struct vnet_softc * sc)10626902eb25Spalle vnet_send_dring_reg(struct vnet_softc *sc)
10636902eb25Spalle {
10646902eb25Spalle 	struct vio_dring_reg dr;
10656902eb25Spalle 
10666902eb25Spalle 	bzero(&dr, sizeof(dr));
10676902eb25Spalle 	dr.tag.type = VIO_TYPE_CTRL;
10686902eb25Spalle 	dr.tag.stype = VIO_SUBTYPE_INFO;
10696902eb25Spalle 	dr.tag.stype_env = VIO_DRING_REG;
10706902eb25Spalle 	dr.tag.sid = sc->sc_local_sid;
10716902eb25Spalle 	dr.dring_ident = 0;
10726902eb25Spalle 	dr.num_descriptors = sc->sc_vd->vd_nentries;
10736902eb25Spalle 	dr.descriptor_size = sizeof(struct vnet_desc);
10746902eb25Spalle 	dr.options = VIO_TX_RING;
10756902eb25Spalle 	dr.ncookies = 1;
10766902eb25Spalle 	dr.cookie[0].addr = 0;
10776902eb25Spalle 	dr.cookie[0].size = PAGE_SIZE;
10786902eb25Spalle 	vnet_sendmsg(sc, &dr, sizeof(dr));
10796902eb25Spalle 
10806902eb25Spalle 	sc->sc_vio_state |= VIO_SND_DRING_REG;
10816902eb25Spalle };
10826902eb25Spalle 
10836902eb25Spalle void
vio_send_rdx(struct vnet_softc * sc)10846902eb25Spalle vio_send_rdx(struct vnet_softc *sc)
10856902eb25Spalle {
10866902eb25Spalle 	struct vio_msg_tag tag;
10876902eb25Spalle 
10886902eb25Spalle 	tag.type = VIO_TYPE_CTRL;
10896902eb25Spalle 	tag.stype = VIO_SUBTYPE_INFO;
10906902eb25Spalle 	tag.stype_env = VIO_RDX;
10916902eb25Spalle 	tag.sid = sc->sc_local_sid;
10926902eb25Spalle 	vnet_sendmsg(sc, &tag, sizeof(tag));
10936902eb25Spalle 
10946902eb25Spalle 	sc->sc_vio_state |= VIO_SND_RDX;
10956902eb25Spalle }
10966902eb25Spalle 
10976902eb25Spalle void
vnet_send_dring_data(struct vnet_softc * sc,uint32_t start_idx)10986902eb25Spalle vnet_send_dring_data(struct vnet_softc *sc, uint32_t start_idx)
10996902eb25Spalle {
11006902eb25Spalle 	struct vio_dring_msg dm;
11016902eb25Spalle 	u_int peer_state;
11026902eb25Spalle 
11036902eb25Spalle 	peer_state = atomic_swap_uint(&sc->sc_peer_state, VIO_DP_ACTIVE);
1104b7b2672bSpalle 	if (peer_state == VIO_DP_ACTIVE) {
1105b7b2672bSpalle 		DPRINTF(("%s: peer_state == VIO_DP_ACTIVE\n", __func__));
11066902eb25Spalle 		return;
1107b7b2672bSpalle 	}
11086902eb25Spalle 
11096902eb25Spalle 	bzero(&dm, sizeof(dm));
11106902eb25Spalle 	dm.tag.type = VIO_TYPE_DATA;
11116902eb25Spalle 	dm.tag.stype = VIO_SUBTYPE_INFO;
11126902eb25Spalle 	dm.tag.stype_env = VIO_DRING_DATA;
11136902eb25Spalle 	dm.tag.sid = sc->sc_local_sid;
11146902eb25Spalle 	dm.seq_no = sc->sc_seq_no++;
11156902eb25Spalle 	dm.dring_ident = sc->sc_dring_ident;
11166902eb25Spalle 	dm.start_idx = start_idx;
11176902eb25Spalle 	dm.end_idx = -1;
11186902eb25Spalle 	vnet_sendmsg(sc, &dm, sizeof(dm));
11196902eb25Spalle }
11206902eb25Spalle 
11216902eb25Spalle void
vnet_start(struct ifnet * ifp)11226902eb25Spalle vnet_start(struct ifnet *ifp)
11236902eb25Spalle {
11246902eb25Spalle 	struct vnet_softc *sc = ifp->if_softc;
11256902eb25Spalle 	struct ldc_conn *lc = &sc->sc_lc;
11266902eb25Spalle 	struct ldc_map *map = sc->sc_lm;
11276902eb25Spalle 	struct mbuf *m;
11286902eb25Spalle 	paddr_t pa;
11296902eb25Spalle 	unsigned char *buf;
11306902eb25Spalle 	uint64_t tx_head, tx_tail, tx_state;
11316902eb25Spalle 	u_int start, prod, count;
11326902eb25Spalle 	int err;
1133f7c20774Spalle 	if (!(ifp->if_flags & IFF_RUNNING))
1134f7c20774Spalle 	{
1135f7c20774Spalle 		DPRINTF(("%s: not in RUNNING state\n", __func__));
1136f7c20774Spalle 		return;
1137f7c20774Spalle 	}
11386902eb25Spalle 
11396902eb25Spalle 	if (IFQ_IS_EMPTY(&ifp->if_snd))
1140f7c20774Spalle 	{
1141f7c20774Spalle 		DPRINTF(("%s: queue is empty\n", __func__));
11426902eb25Spalle 		return;
1143b7b2672bSpalle 	} else {
1144b7b2672bSpalle 		DPRINTF(("%s: queue size %d\n", __func__, ifp->if_snd.ifq_len));
1145f7c20774Spalle 	}
11466902eb25Spalle 
11476902eb25Spalle 	/*
11486902eb25Spalle 	 * We cannot transmit packets until a VIO connection has been
11496902eb25Spalle 	 * established.
11506902eb25Spalle 	 */
11516902eb25Spalle 	if (!ISSET(sc->sc_vio_state, VIO_RCV_RDX) ||
11526902eb25Spalle 	    !ISSET(sc->sc_vio_state, VIO_ACK_RDX))
1153f7c20774Spalle 	{
1154f7c20774Spalle 		DPRINTF(("%s: vio connection not established yet\n", __func__));
11556902eb25Spalle 		return;
1156f7c20774Spalle 	}
11576902eb25Spalle 
11586902eb25Spalle 	/*
11596902eb25Spalle 	 * Make sure there is room in the LDC transmit queue to send a
11606902eb25Spalle 	 * DRING_DATA message.
11616902eb25Spalle 	 */
11626902eb25Spalle 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
1163f7c20774Spalle 	if (err != H_EOK) {
1164f7c20774Spalle 		DPRINTF(("%s: no room in ldc transmit queue\n", __func__));
11656902eb25Spalle 		return;
1166f7c20774Spalle 	}
11676902eb25Spalle 	tx_tail += sizeof(struct ldc_pkt);
11686902eb25Spalle 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(struct ldc_pkt)) - 1);
11696902eb25Spalle 	if (tx_tail == tx_head) {
1170f7c20774Spalle 		{
1171f7c20774Spalle 			DPRINTF(("%s: tail equals head\n", __func__));
11726902eb25Spalle 			return;
11736902eb25Spalle 		}
1174f7c20774Spalle 	}
11756902eb25Spalle 
11766902eb25Spalle 	if (sc->sc_xfer_mode == VIO_DESC_MODE) {
1177f7c20774Spalle 		DPRINTF(("%s: vio_desc_mode\n", __func__));
11786902eb25Spalle 		vnet_start_desc(ifp);
11796902eb25Spalle 		return;
11806902eb25Spalle 	}
11816902eb25Spalle 
11826902eb25Spalle 	start = prod = sc->sc_tx_prod & (sc->sc_vd->vd_nentries - 1);
11836902eb25Spalle 	while (sc->sc_vd->vd_desc[prod].hdr.dstate == VIO_DESC_FREE) {
11846902eb25Spalle 		count = sc->sc_tx_prod - sc->sc_tx_cons;
11856902eb25Spalle 		if (count >= (sc->sc_vd->vd_nentries - 1) ||
11866902eb25Spalle 		    map->lm_count >= map->lm_nentries) {
1187b7b2672bSpalle 			DPRINTF(("%s: count issue\n", __func__));
11886902eb25Spalle 			break;
11896902eb25Spalle 		}
11906902eb25Spalle 
11916902eb25Spalle 		buf = pool_get(&sc->sc_pool, PR_NOWAIT|PR_ZERO);
11926902eb25Spalle 		if (buf == NULL) {
1193b7b2672bSpalle 			DPRINTF(("%s: buff is NULL\n", __func__));
11946902eb25Spalle 			break;
11956902eb25Spalle 		}
11966902eb25Spalle 		IFQ_DEQUEUE(&ifp->if_snd, m);
11976902eb25Spalle 		if (m == NULL) {
11986902eb25Spalle 			pool_put(&sc->sc_pool, buf);
11996902eb25Spalle 			break;
12006902eb25Spalle 		}
12016902eb25Spalle 
12026902eb25Spalle 		m_copydata(m, 0, m->m_pkthdr.len, buf + VNET_ETHER_ALIGN);
120391d5826aSpalle 
12046902eb25Spalle #if NBPFILTER > 0
12056902eb25Spalle 		/*
12066902eb25Spalle 		 * If BPF is listening on this interface, let it see the
12076902eb25Spalle 		 * packet before we commit it to the wire.
12086902eb25Spalle 		 */
1209b7b2672bSpalle 		DPRINTF(("%s: before bpf\n", __func__));
1210fd86cb87Sandvar 		bpf_mtap(ifp, m, BPF_D_OUT);
1211b7b2672bSpalle 		DPRINTF(("%s: after bpf\n", __func__));
12126902eb25Spalle #endif
12136902eb25Spalle 
12146902eb25Spalle 		pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa);
12156902eb25Spalle 		KASSERT((pa & ~PAGE_MASK) == (pa & LDC_MTE_RA_MASK));
12166902eb25Spalle 		while (map->lm_slot[map->lm_next].entry != 0) {
12176902eb25Spalle 			map->lm_next++;
12186902eb25Spalle 			map->lm_next &= (map->lm_nentries - 1);
12196902eb25Spalle 		}
12206902eb25Spalle 		map->lm_slot[map->lm_next].entry = (pa & LDC_MTE_RA_MASK);
12216902eb25Spalle 		map->lm_slot[map->lm_next].entry |= LDC_MTE_CPR;
122291d5826aSpalle 		atomic_inc_32(&map->lm_count);
12236902eb25Spalle 		sc->sc_vd->vd_desc[prod].nbytes = MAX(m->m_pkthdr.len, 60);
12246902eb25Spalle 		sc->sc_vd->vd_desc[prod].ncookies = 1;
12256902eb25Spalle 		sc->sc_vd->vd_desc[prod].cookie[0].addr =
12266902eb25Spalle 		    map->lm_next << PAGE_SHIFT | (pa & PAGE_MASK);
12276902eb25Spalle 		sc->sc_vd->vd_desc[prod].cookie[0].size = 2048;
12286902eb25Spalle 		membar_producer();
12296902eb25Spalle 		sc->sc_vd->vd_desc[prod].hdr.dstate = VIO_DESC_READY;
12306902eb25Spalle 
12316902eb25Spalle 		sc->sc_vsd[prod].vsd_map_idx = map->lm_next;
12326902eb25Spalle 		sc->sc_vsd[prod].vsd_buf = buf;
12336902eb25Spalle 
12346902eb25Spalle 		sc->sc_tx_prod++;
12356902eb25Spalle 		prod = sc->sc_tx_prod & (sc->sc_vd->vd_nentries - 1);
12366902eb25Spalle 
12376902eb25Spalle 		m_freem(m);
12386902eb25Spalle 	}
12396902eb25Spalle 
12406902eb25Spalle 	membar_producer();
12416902eb25Spalle 
12426902eb25Spalle 	if (start != prod && sc->sc_peer_state != VIO_DP_ACTIVE) {
12436902eb25Spalle 		vnet_send_dring_data(sc, start);
12446902eb25Spalle 		ifp->if_timer = 5;
12456902eb25Spalle 	}
1246b7b2672bSpalle 
12476902eb25Spalle }
12486902eb25Spalle 
12496902eb25Spalle void
vnet_start_desc(struct ifnet * ifp)12506902eb25Spalle vnet_start_desc(struct ifnet *ifp)
12516902eb25Spalle {
12526902eb25Spalle 	struct vnet_softc *sc = ifp->if_softc;
12536902eb25Spalle 	struct ldc_map *map = sc->sc_lm;
12546902eb25Spalle 	struct vnet_desc_msg dm;
12556902eb25Spalle 	struct mbuf *m;
12566902eb25Spalle 	paddr_t pa;
12576902eb25Spalle 	unsigned char *buf;
12586902eb25Spalle 	u_int prod, count;
12596902eb25Spalle 
12606902eb25Spalle 	for (;;) {
12616902eb25Spalle 		count = sc->sc_tx_prod - sc->sc_tx_cons;
12626902eb25Spalle 		if (count >= (sc->sc_vd->vd_nentries - 1) ||
12636902eb25Spalle 		    map->lm_count >= map->lm_nentries) {
12646902eb25Spalle 			return;
12656902eb25Spalle 		}
12666902eb25Spalle 
12676902eb25Spalle 		buf = pool_get(&sc->sc_pool, PR_NOWAIT|PR_ZERO);
12686902eb25Spalle 		if (buf == NULL) {
12696902eb25Spalle 			return;
12706902eb25Spalle 		}
12716902eb25Spalle 
12726902eb25Spalle 		IFQ_DEQUEUE(&ifp->if_snd, m);
12736902eb25Spalle 
12746902eb25Spalle 		if (m == NULL) {
12756902eb25Spalle 			pool_put(&sc->sc_pool, buf);
12766902eb25Spalle 			return;
12776902eb25Spalle 		}
12786902eb25Spalle 
12796902eb25Spalle 		m_copydata(m, 0, m->m_pkthdr.len, buf);
12806902eb25Spalle 
12816902eb25Spalle #if NBPFILTER > 0
12826902eb25Spalle 		/*
12836902eb25Spalle 		 * If BPF is listening on this interface, let it see the
12846902eb25Spalle 		 * packet before we commit it to the wire.
12856902eb25Spalle 		 */
1286fd86cb87Sandvar 		bpf_mtap(ifp, m, BPF_D_OUT);
12876902eb25Spalle #endif
12886902eb25Spalle 
12896902eb25Spalle 		pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa);
12906902eb25Spalle 		KASSERT((pa & ~PAGE_MASK) == (pa & LDC_MTE_RA_MASK));
12916902eb25Spalle 		while (map->lm_slot[map->lm_next].entry != 0) {
12926902eb25Spalle 			map->lm_next++;
12936902eb25Spalle 			map->lm_next &= (map->lm_nentries - 1);
12946902eb25Spalle 		}
12956902eb25Spalle 		map->lm_slot[map->lm_next].entry = (pa & LDC_MTE_RA_MASK);
12966902eb25Spalle 		map->lm_slot[map->lm_next].entry |= LDC_MTE_CPR;
129791d5826aSpalle 		atomic_inc_32(&map->lm_count);
12986902eb25Spalle 
12996902eb25Spalle 		prod = sc->sc_tx_prod & (sc->sc_vd->vd_nentries - 1);
13006902eb25Spalle 		sc->sc_vsd[prod].vsd_map_idx = map->lm_next;
13016902eb25Spalle 		sc->sc_vsd[prod].vsd_buf = buf;
13026902eb25Spalle 
13036902eb25Spalle 		bzero(&dm, sizeof(dm));
13046902eb25Spalle 		dm.tag.type = VIO_TYPE_DATA;
13056902eb25Spalle 		dm.tag.stype = VIO_SUBTYPE_INFO;
13066902eb25Spalle 		dm.tag.stype_env = VIO_DESC_DATA;
13076902eb25Spalle 		dm.tag.sid = sc->sc_local_sid;
13086902eb25Spalle 		dm.seq_no = sc->sc_seq_no++;
13096902eb25Spalle 		dm.desc_handle = sc->sc_tx_prod;
13106902eb25Spalle 		dm.nbytes = MAX(m->m_pkthdr.len, 60);
13116902eb25Spalle 		dm.ncookies = 1;
13126902eb25Spalle 		dm.cookie[0].addr =
13136902eb25Spalle 			map->lm_next << PAGE_SHIFT | (pa & PAGE_MASK);
13146902eb25Spalle 		dm.cookie[0].size = 2048;
13156902eb25Spalle 		vnet_sendmsg(sc, &dm, sizeof(dm));
13166902eb25Spalle 
13176902eb25Spalle 		sc->sc_tx_prod++;
13186902eb25Spalle 		sc->sc_tx_prod &= (sc->sc_vd->vd_nentries - 1);
13196902eb25Spalle 
13206902eb25Spalle 		m_freem(m);
13216902eb25Spalle 	}
13226902eb25Spalle }
13236902eb25Spalle 
13246902eb25Spalle int
vnet_ioctl(struct ifnet * ifp,u_long cmd,void * data)13256902eb25Spalle vnet_ioctl(struct ifnet *ifp, u_long cmd, void* data)
13266902eb25Spalle {
13276902eb25Spalle 	struct vnet_softc *sc = ifp->if_softc;
13286902eb25Spalle 	struct ifreq *ifr = (struct ifreq *)data;
13296902eb25Spalle 	int s, error = 0;
13306902eb25Spalle 
13316902eb25Spalle 	s = splnet();
13326902eb25Spalle 
13336902eb25Spalle 	switch (cmd) {
13346902eb25Spalle 
13356902eb25Spalle 		case SIOCSIFADDR:
13366902eb25Spalle 			ifp->if_flags |= IFF_UP;
13376902eb25Spalle 			/* FALLTHROUGH */
13386902eb25Spalle 		case SIOCSIFFLAGS:
13396902eb25Spalle 			if (ifp->if_flags & IFF_UP) {
13406902eb25Spalle 				if ((ifp->if_flags & IFF_RUNNING) == 0)
13416902eb25Spalle 					vnet_init(ifp);
13426902eb25Spalle 			} else {
13436902eb25Spalle 				if (ifp->if_flags & IFF_RUNNING)
1344f7c20774Spalle 					vnet_stop(ifp, 0);
13456902eb25Spalle 			}
13466902eb25Spalle 		break;
13476902eb25Spalle 
13486902eb25Spalle 		case SIOCGIFMEDIA:
13496902eb25Spalle 		case SIOCSIFMEDIA:
13506902eb25Spalle 			error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
13516902eb25Spalle 			break;
13526902eb25Spalle 
13536902eb25Spalle 		case SIOCADDMULTI:
13546902eb25Spalle 		case SIOCDELMULTI:
13556902eb25Spalle 			/*
13566902eb25Spalle 			 * XXX Removing all multicast addresses and adding
13576902eb25Spalle 			 * most of them back, is somewhat retarded.
13586902eb25Spalle 			 */
13596902eb25Spalle 			vnet_setmulti(sc, 0);
13606902eb25Spalle 			error = ether_ioctl(ifp, cmd, data);
13616902eb25Spalle 			vnet_setmulti(sc, 1);
13626902eb25Spalle 			if (error == ENETRESET)
13636902eb25Spalle 				error = 0;
13646902eb25Spalle 			break;
13656902eb25Spalle 
13666902eb25Spalle 		default:
13676902eb25Spalle 			error = ether_ioctl(ifp, cmd, data);
13686902eb25Spalle 	}
13696902eb25Spalle 
13706902eb25Spalle 	splx(s);
13716902eb25Spalle 
13726902eb25Spalle 	return (error);
13736902eb25Spalle }
13746902eb25Spalle 
13756902eb25Spalle void
vnet_watchdog(struct ifnet * ifp)13766902eb25Spalle vnet_watchdog(struct ifnet *ifp)
13776902eb25Spalle {
1378f7c20774Spalle 
13796902eb25Spalle 	struct vnet_softc *sc = ifp->if_softc;
13806902eb25Spalle 
1381efd62f8cSriastradh 	printf("%s: watchdog timeout\n", device_xname(sc->sc_dv));
13826902eb25Spalle }
13836902eb25Spalle 
13846902eb25Spalle int
vnet_media_change(struct ifnet * ifp)13856902eb25Spalle vnet_media_change(struct ifnet *ifp)
13866902eb25Spalle {
13876902eb25Spalle 	return (0);
13886902eb25Spalle }
13896902eb25Spalle 
13906902eb25Spalle void
vnet_media_status(struct ifnet * ifp,struct ifmediareq * imr)13916902eb25Spalle vnet_media_status(struct ifnet *ifp, struct ifmediareq *imr)
13926902eb25Spalle {
13936902eb25Spalle 	imr->ifm_active = IFM_ETHER | IFM_AUTO;
13946902eb25Spalle 	imr->ifm_status = IFM_AVALID;
13956902eb25Spalle 	if (ifp->if_link_state == LINK_STATE_UP &&
13966902eb25Spalle 	    ifp->if_flags & IFF_UP)
13976902eb25Spalle 		imr->ifm_status |= IFM_ACTIVE;
13986902eb25Spalle }
13996902eb25Spalle 
14006902eb25Spalle void
vnet_link_state(struct vnet_softc * sc)14016902eb25Spalle vnet_link_state(struct vnet_softc *sc)
14026902eb25Spalle {
14036902eb25Spalle 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
14046902eb25Spalle 	int link_state = LINK_STATE_DOWN;
14056902eb25Spalle 
14066902eb25Spalle 	KERNEL_LOCK(1, curlwp);
14076902eb25Spalle 	if (ISSET(sc->sc_vio_state, VIO_RCV_RDX) &&
14086902eb25Spalle 	    ISSET(sc->sc_vio_state, VIO_ACK_RDX))
14096902eb25Spalle 		link_state = LINK_STATE_UP;
14106902eb25Spalle 	if (ifp->if_link_state != link_state) {
14116902eb25Spalle 		if_link_state_change(ifp, link_state);
14126902eb25Spalle 	}
14136902eb25Spalle 	KERNEL_UNLOCK_ONE(curlwp);
14146902eb25Spalle }
14156902eb25Spalle 
14166902eb25Spalle void
vnet_setmulti(struct vnet_softc * sc,int set)14176902eb25Spalle vnet_setmulti(struct vnet_softc *sc, int set)
14186902eb25Spalle {
14196902eb25Spalle 	struct ethercom *ec = &sc->sc_ethercom;
14206902eb25Spalle 	struct ether_multi *enm;
14216902eb25Spalle 	struct ether_multistep step;
14226902eb25Spalle 	struct vnet_mcast_info mi;
14236902eb25Spalle 	int count = 0;
14246902eb25Spalle 
14256902eb25Spalle 	if (!ISSET(sc->sc_vio_state, VIO_RCV_RDX) ||
14266902eb25Spalle 	    !ISSET(sc->sc_vio_state, VIO_ACK_RDX))
14276902eb25Spalle 		return;
14286902eb25Spalle 
14296902eb25Spalle 	bzero(&mi, sizeof(mi));
14306902eb25Spalle 	mi.tag.type = VIO_TYPE_CTRL;
14316902eb25Spalle 	mi.tag.stype = VIO_SUBTYPE_INFO;
14326902eb25Spalle 	mi.tag.stype_env = VNET_MCAST_INFO;
14336902eb25Spalle 	mi.tag.sid = sc->sc_local_sid;
14346902eb25Spalle 	mi.set = set ? 1 : 0;
14356902eb25Spalle 	KERNEL_LOCK(1, curlwp);
14366902eb25Spalle 	ETHER_FIRST_MULTI(step, ec, enm);
14376902eb25Spalle 	while (enm != NULL) {
14386902eb25Spalle 		/* XXX What about multicast ranges? */
14396902eb25Spalle 		bcopy(enm->enm_addrlo, mi.mcast_addr[count], ETHER_ADDR_LEN);
14406902eb25Spalle 		ETHER_NEXT_MULTI(step, enm);
14416902eb25Spalle 
14426902eb25Spalle 		count++;
14436902eb25Spalle 		if (count < VNET_NUM_MCAST)
14446902eb25Spalle 			continue;
14456902eb25Spalle 
14466902eb25Spalle 		mi.count = VNET_NUM_MCAST;
14476902eb25Spalle 		vnet_sendmsg(sc, &mi, sizeof(mi));
14486902eb25Spalle 		count = 0;
14496902eb25Spalle 	}
14506902eb25Spalle 
14516902eb25Spalle 	if (count > 0) {
14526902eb25Spalle 		mi.count = count;
14536902eb25Spalle 		vnet_sendmsg(sc, &mi, sizeof(mi));
14546902eb25Spalle 	}
14556902eb25Spalle 	KERNEL_UNLOCK_ONE(curlwp);
14566902eb25Spalle }
14576902eb25Spalle 
14586902eb25Spalle 
1459f7c20774Spalle int
vnet_init(struct ifnet * ifp)14606902eb25Spalle vnet_init(struct ifnet *ifp)
14616902eb25Spalle {
14626902eb25Spalle 	struct vnet_softc *sc = ifp->if_softc;
14636902eb25Spalle 	struct ldc_conn *lc = &sc->sc_lc;
14646902eb25Spalle 	int err;
14656902eb25Spalle 	vaddr_t va;
14666902eb25Spalle 	paddr_t pa;
14676902eb25Spalle 	sc->sc_lm = ldc_map_alloc(2048);
14686902eb25Spalle 	if (sc->sc_lm == NULL)
1469f7c20774Spalle 		return ENOMEM;
14706902eb25Spalle 
14716902eb25Spalle 	va = (vaddr_t)sc->sc_lm->lm_slot;
14726902eb25Spalle 	pa = 0;
14736902eb25Spalle 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
14746902eb25Spalle 		panic("pmap_extract failed %lx\n", va);
14756902eb25Spalle 	err = hv_ldc_set_map_table(lc->lc_id, pa, 2048);
14766902eb25Spalle 	if (err != H_EOK) {
14776902eb25Spalle 		printf("hv_ldc_set_map_table %d\n", err);
1478f7c20774Spalle 		return EINVAL;
14796902eb25Spalle 	}
14806902eb25Spalle 
14816902eb25Spalle 	sc->sc_vd = vnet_dring_alloc(sc->sc_dmatag, VNET_NUM_SOFT_DESC);
14826902eb25Spalle 	if (sc->sc_vd == NULL)
1483f7c20774Spalle 		return ENOMEM;
14846902eb25Spalle 	sc->sc_vsd = malloc(VNET_NUM_SOFT_DESC * sizeof(*sc->sc_vsd), M_DEVBUF,
14856902eb25Spalle 	    M_NOWAIT|M_ZERO);
14866902eb25Spalle 	if (sc->sc_vsd == NULL)
1487f7c20774Spalle 		return ENOMEM;
14886902eb25Spalle 
1489f7c20774Spalle 	va = (vaddr_t)sc->sc_vd->vd_desc;
1490f7c20774Spalle 	pa = 0;
1491f7c20774Spalle 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
1492f7c20774Spalle 		panic("pmap_extract failed %lx\n", va);
1493f7c20774Spalle 	sc->sc_lm->lm_slot[0].entry = pa;
14946902eb25Spalle 	sc->sc_lm->lm_slot[0].entry &= LDC_MTE_RA_MASK;
14956902eb25Spalle 	sc->sc_lm->lm_slot[0].entry |= LDC_MTE_CPR | LDC_MTE_CPW;
14966902eb25Spalle 	sc->sc_lm->lm_next = 1;
14976902eb25Spalle 	sc->sc_lm->lm_count = 1;
14986902eb25Spalle 
1499f7c20774Spalle 	va = lc->lc_txq->lq_va;
1500f7c20774Spalle 	pa = 0;
1501f7c20774Spalle 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
1502f7c20774Spalle 		panic("pmap_extract failed %lx\n", va);
15036902eb25Spalle 	err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_txq->lq_nentries);
15046902eb25Spalle 	if (err != H_EOK)
15056902eb25Spalle 		printf("hv_ldc_tx_qconf %d\n", err);
15066902eb25Spalle 
1507f7c20774Spalle 	va = (vaddr_t)lc->lc_rxq->lq_va;
1508f7c20774Spalle 	pa = 0;
1509f7c20774Spalle 	if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
1510f7c20774Spalle 	  panic("pmap_extract failed %lx\n", va);
1511f7c20774Spalle 
15126902eb25Spalle 	err = hv_ldc_rx_qconf(lc->lc_id, pa, lc->lc_rxq->lq_nentries);
15136902eb25Spalle 	if (err != H_EOK)
15146902eb25Spalle 		printf("hv_ldc_rx_qconf %d\n", err);
15156902eb25Spalle 
15166902eb25Spalle 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_ENABLED);
15176902eb25Spalle 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_ENABLED);
15186902eb25Spalle 
15196902eb25Spalle 	ldc_send_vers(lc);
15206902eb25Spalle 
15216902eb25Spalle 	ifp->if_flags |= IFF_RUNNING;
15226902eb25Spalle 
1523f7c20774Spalle 	return 0;
15246902eb25Spalle }
15256902eb25Spalle 
15266902eb25Spalle void
vnet_stop(struct ifnet * ifp,int disable)1527f7c20774Spalle vnet_stop(struct ifnet *ifp, int disable)
15286902eb25Spalle 
15296902eb25Spalle {
15306902eb25Spalle 	struct vnet_softc *sc = ifp->if_softc;
15316902eb25Spalle 	struct ldc_conn *lc = &sc->sc_lc;
15326902eb25Spalle 
15336902eb25Spalle 	ifp->if_flags &= ~IFF_RUNNING;
15346902eb25Spalle 	ifp->if_timer = 0;
15356902eb25Spalle 
15366902eb25Spalle 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED);
15376902eb25Spalle 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED);
15386902eb25Spalle 
15396902eb25Spalle #if 0
154091d5826aSpalle openbsd XXX
15416902eb25Spalle 	intr_barrier(sc->sc_tx_ih);
15426902eb25Spalle 	intr_barrier(sc->sc_rx_ih);
15436902eb25Spalle #else
154491d5826aSpalle 	printf("vnet_stop() intr_barrier() not available\n");
15456902eb25Spalle #endif
15466902eb25Spalle 
15476902eb25Spalle 	hv_ldc_tx_qconf(lc->lc_id, 0, 0);
15486902eb25Spalle 	hv_ldc_rx_qconf(lc->lc_id, 0, 0);
15496902eb25Spalle 	lc->lc_tx_seqid = 0;
15506902eb25Spalle 	lc->lc_state = 0;
15516902eb25Spalle 	lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
15526902eb25Spalle 	vnet_ldc_reset(lc);
15536902eb25Spalle 
15546902eb25Spalle 	free(sc->sc_vsd, M_DEVBUF);
15556902eb25Spalle 
15566902eb25Spalle 	vnet_dring_free(sc->sc_dmatag, sc->sc_vd);
15576902eb25Spalle 
15586902eb25Spalle 	hv_ldc_set_map_table(lc->lc_id, 0, 0);
15596902eb25Spalle 	ldc_map_free(sc->sc_lm);
15606902eb25Spalle }
15616902eb25Spalle 
15626902eb25Spalle struct vnet_dring *
vnet_dring_alloc(bus_dma_tag_t t,int nentries)15636902eb25Spalle vnet_dring_alloc(bus_dma_tag_t t, int nentries)
15646902eb25Spalle {
15656902eb25Spalle 	struct vnet_dring *vd;
15666902eb25Spalle 	bus_size_t size;
15676902eb25Spalle 	vaddr_t va;
15686902eb25Spalle 	int i;
15696902eb25Spalle 
15706902eb25Spalle 	vd = kmem_zalloc(sizeof(struct vnet_dring), KM_SLEEP);
15716902eb25Spalle 	if (vd == NULL)
15726902eb25Spalle 		return NULL;
15736902eb25Spalle 
15746902eb25Spalle 	size = roundup(nentries * sizeof(struct vnet_desc), PAGE_SIZE);
15756902eb25Spalle 
15766902eb25Spalle 	va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
15776902eb25Spalle 	vd->vd_desc = (struct vnet_desc *)va;
15786902eb25Spalle 	vd->vd_nentries = nentries;
15796902eb25Spalle 	bzero(vd->vd_desc, nentries * sizeof(struct vnet_desc));
15806902eb25Spalle 	for (i = 0; i < vd->vd_nentries; i++)
15816902eb25Spalle 		vd->vd_desc[i].hdr.dstate = VIO_DESC_FREE;
15826902eb25Spalle 	return (vd);
15836902eb25Spalle 
15846902eb25Spalle 	return (NULL);
15856902eb25Spalle }
15866902eb25Spalle 
15876902eb25Spalle void
vnet_dring_free(bus_dma_tag_t t,struct vnet_dring * vd)15886902eb25Spalle vnet_dring_free(bus_dma_tag_t t, struct vnet_dring *vd)
15896902eb25Spalle {
1590f7c20774Spalle 
15916902eb25Spalle 	bus_size_t size;
15926902eb25Spalle 
15936902eb25Spalle 	size = vd->vd_nentries * sizeof(struct vnet_desc);
15946902eb25Spalle 	size = roundup(size, PAGE_SIZE);
15956902eb25Spalle 
15966902eb25Spalle 	kmem_free(vd->vd_desc, size);
15976902eb25Spalle 	kmem_free(vd, size);
15986902eb25Spalle }
15996902eb25Spalle 
1600