xref: /freebsd/sys/dev/xen/netfront/netfront.c (revision da4b0d6eb06d730487d48e15d2d5e10c56266fd9)
18e0ad55aSJoel Dahl /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
489e0f4d2SKip Macy  * Copyright (c) 2004-2006 Kip Macy
596375eacSRoger Pau Monné  * Copyright (c) 2015 Wei Liu <wei.liu2@citrix.com>
689e0f4d2SKip Macy  * All rights reserved.
789e0f4d2SKip Macy  *
88e0ad55aSJoel Dahl  * Redistribution and use in source and binary forms, with or without
98e0ad55aSJoel Dahl  * modification, are permitted provided that the following conditions
108e0ad55aSJoel Dahl  * are met:
118e0ad55aSJoel Dahl  * 1. Redistributions of source code must retain the above copyright
128e0ad55aSJoel Dahl  *    notice, this list of conditions and the following disclaimer.
138e0ad55aSJoel Dahl  * 2. Redistributions in binary form must reproduce the above copyright
148e0ad55aSJoel Dahl  *    notice, this list of conditions and the following disclaimer in the
158e0ad55aSJoel Dahl  *    documentation and/or other materials provided with the distribution.
1689e0f4d2SKip Macy  *
178e0ad55aSJoel Dahl  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
188e0ad55aSJoel Dahl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
198e0ad55aSJoel Dahl  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
208e0ad55aSJoel Dahl  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
218e0ad55aSJoel Dahl  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
228e0ad55aSJoel Dahl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
238e0ad55aSJoel Dahl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
248e0ad55aSJoel Dahl  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
258e0ad55aSJoel Dahl  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
268e0ad55aSJoel Dahl  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
278e0ad55aSJoel Dahl  * SUCH DAMAGE.
2889e0f4d2SKip Macy  */
2989e0f4d2SKip Macy 
3089e0f4d2SKip Macy #include <sys/cdefs.h>
31a0ae8f04SBjoern A. Zeeb #include "opt_inet.h"
32f909bbb4SGleb Smirnoff #include "opt_inet6.h"
33a0ae8f04SBjoern A. Zeeb 
3489e0f4d2SKip Macy #include <sys/param.h>
3589e0f4d2SKip Macy #include <sys/sockio.h>
36c578b6acSGleb Smirnoff #include <sys/limits.h>
3789e0f4d2SKip Macy #include <sys/mbuf.h>
3889e0f4d2SKip Macy #include <sys/malloc.h>
3923dc5621SKip Macy #include <sys/module.h>
4089e0f4d2SKip Macy #include <sys/kernel.h>
4189e0f4d2SKip Macy #include <sys/socket.h>
4212678024SDoug Rabson #include <sys/sysctl.h>
4396375eacSRoger Pau Monné #include <sys/taskqueue.h>
4489e0f4d2SKip Macy 
4589e0f4d2SKip Macy #include <net/if.h>
4677374386SGleb Smirnoff #include <net/if_var.h>
4789e0f4d2SKip Macy #include <net/if_arp.h>
4889e0f4d2SKip Macy #include <net/ethernet.h>
4989e0f4d2SKip Macy #include <net/if_media.h>
5089e0f4d2SKip Macy #include <net/bpf.h>
5189e0f4d2SKip Macy #include <net/if_types.h>
5289e0f4d2SKip Macy 
5389e0f4d2SKip Macy #include <netinet/in.h>
5489e0f4d2SKip Macy #include <netinet/ip.h>
5589e0f4d2SKip Macy #include <netinet/if_ether.h>
5612678024SDoug Rabson #include <netinet/tcp.h>
5712678024SDoug Rabson #include <netinet/tcp_lro.h>
5889e0f4d2SKip Macy 
5989e0f4d2SKip Macy #include <vm/vm.h>
6089e0f4d2SKip Macy #include <vm/pmap.h>
6189e0f4d2SKip Macy 
6289e0f4d2SKip Macy #include <sys/bus.h>
6389e0f4d2SKip Macy 
6476acc41fSJustin T. Gibbs #include <xen/xen-os.h>
653a6d1fcfSKip Macy #include <xen/hypervisor.h>
663a6d1fcfSKip Macy #include <xen/xen_intr.h>
6789e0f4d2SKip Macy #include <xen/gnttab.h>
68ad7dd514SElliott Mitchell #include <contrib/xen/memory.h>
69ad7dd514SElliott Mitchell #include <contrib/xen/io/netif.h>
7023dc5621SKip Macy #include <xen/xenbus/xenbusvar.h>
7189e0f4d2SKip Macy 
72dabb3db7SRoger Pau Monné #include <machine/bus.h>
73dabb3db7SRoger Pau Monné 
7423dc5621SKip Macy #include "xenbus_if.h"
7589e0f4d2SKip Macy 
76578e4bf7SJustin T. Gibbs /* Features supported by all backends.  TSO and LRO can be negotiated */
77578e4bf7SJustin T. Gibbs #define XN_CSUM_FEATURES	(CSUM_TCP | CSUM_UDP)
7812678024SDoug Rabson 
7998018db4SRyan Libby #define NET_TX_RING_SIZE __CONST_RING_SIZE(netif_tx, PAGE_SIZE)
8098018db4SRyan Libby #define NET_RX_RING_SIZE __CONST_RING_SIZE(netif_rx, PAGE_SIZE)
8189e0f4d2SKip Macy 
822568ee67SRoger Pau Monné #define NET_RX_SLOTS_MIN (XEN_NETIF_NR_SLOTS_MIN + 1)
832568ee67SRoger Pau Monné 
8412678024SDoug Rabson /*
8512678024SDoug Rabson  * Should the driver do LRO on the RX end
8612678024SDoug Rabson  *  this can be toggled on the fly, but the
8712678024SDoug Rabson  *  interface must be reset (down/up) for it
8812678024SDoug Rabson  *  to take effect.
8912678024SDoug Rabson  */
9012678024SDoug Rabson static int xn_enable_lro = 1;
9112678024SDoug Rabson TUNABLE_INT("hw.xn.enable_lro", &xn_enable_lro);
9212678024SDoug Rabson 
9396375eacSRoger Pau Monné /*
9496375eacSRoger Pau Monné  * Number of pairs of queues.
9596375eacSRoger Pau Monné  */
9696375eacSRoger Pau Monné static unsigned long xn_num_queues = 4;
9796375eacSRoger Pau Monné TUNABLE_ULONG("hw.xn.num_queues", &xn_num_queues);
9896375eacSRoger Pau Monné 
99931eeffaSKenneth D. Merry /**
100931eeffaSKenneth D. Merry  * \brief The maximum allowed data fragments in a single transmit
101931eeffaSKenneth D. Merry  *        request.
102931eeffaSKenneth D. Merry  *
103931eeffaSKenneth D. Merry  * This limit is imposed by the backend driver.  We assume here that
104931eeffaSKenneth D. Merry  * we are dealing with a Linux driver domain and have set our limit
105931eeffaSKenneth D. Merry  * to mirror the Linux MAX_SKB_FRAGS constant.
106931eeffaSKenneth D. Merry  */
107931eeffaSKenneth D. Merry #define	MAX_TX_REQ_FRAGS (65536 / PAGE_SIZE + 2)
108931eeffaSKenneth D. Merry 
10989e0f4d2SKip Macy #define RX_COPY_THRESHOLD 256
11089e0f4d2SKip Macy 
11189e0f4d2SKip Macy #define net_ratelimit() 0
11289e0f4d2SKip Macy 
11396375eacSRoger Pau Monné struct netfront_rxq;
11496375eacSRoger Pau Monné struct netfront_txq;
11589e0f4d2SKip Macy struct netfront_info;
11689e0f4d2SKip Macy struct netfront_rx_info;
11789e0f4d2SKip Macy 
11896375eacSRoger Pau Monné static void xn_txeof(struct netfront_txq *);
11996375eacSRoger Pau Monné static void xn_rxeof(struct netfront_rxq *);
12096375eacSRoger Pau Monné static void xn_alloc_rx_buffers(struct netfront_rxq *);
1212568ee67SRoger Pau Monné static void xn_alloc_rx_buffers_callout(void *arg);
12289e0f4d2SKip Macy 
12396375eacSRoger Pau Monné static void xn_release_rx_bufs(struct netfront_rxq *);
12496375eacSRoger Pau Monné static void xn_release_tx_bufs(struct netfront_txq *);
12589e0f4d2SKip Macy 
126da695b05SRoger Pau Monné static void xn_rxq_intr(struct netfront_rxq *);
127da695b05SRoger Pau Monné static void xn_txq_intr(struct netfront_txq *);
128da695b05SRoger Pau Monné static void xn_intr(void *);
12996375eacSRoger Pau Monné static int xn_assemble_tx_request(struct netfront_txq *, struct mbuf *);
13002f3b17fSJustin Hibbits static int xn_ioctl(if_t, u_long, caddr_t);
13189e0f4d2SKip Macy static void xn_ifinit_locked(struct netfront_info *);
13289e0f4d2SKip Macy static void xn_ifinit(void *);
13389e0f4d2SKip Macy static void xn_stop(struct netfront_info *);
134578e4bf7SJustin T. Gibbs static void xn_query_features(struct netfront_info *np);
135578e4bf7SJustin T. Gibbs static int xn_configure_features(struct netfront_info *np);
13689e0f4d2SKip Macy static void netif_free(struct netfront_info *info);
13723dc5621SKip Macy static int netfront_detach(device_t dev);
13889e0f4d2SKip Macy 
13996375eacSRoger Pau Monné static int xn_txq_mq_start_locked(struct netfront_txq *, struct mbuf *);
14002f3b17fSJustin Hibbits static int xn_txq_mq_start(if_t, struct mbuf *);
14196375eacSRoger Pau Monné 
14223dc5621SKip Macy static int talk_to_backend(device_t dev, struct netfront_info *info);
14323dc5621SKip Macy static int create_netdev(device_t dev);
14489e0f4d2SKip Macy static void netif_disconnect_backend(struct netfront_info *info);
14596375eacSRoger Pau Monné static int setup_device(device_t dev, struct netfront_info *info,
14696375eacSRoger Pau Monné     unsigned long);
14702f3b17fSJustin Hibbits static int xn_ifmedia_upd(if_t ifp);
14802f3b17fSJustin Hibbits static void xn_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr);
1490e509842SJustin T. Gibbs 
15065671253SRoger Pau Monné static int xn_connect(struct netfront_info *);
15165671253SRoger Pau Monné static void xn_kick_rings(struct netfront_info *);
15289e0f4d2SKip Macy 
15396375eacSRoger Pau Monné static int xn_get_responses(struct netfront_rxq *,
15496375eacSRoger Pau Monné     struct netfront_rx_info *, RING_IDX, RING_IDX *,
15596375eacSRoger Pau Monné     struct mbuf **);
15689e0f4d2SKip Macy 
1573c790178SJohn Baldwin #define virt_to_mfn(x) (vtophys(x) >> PAGE_SHIFT)
15889e0f4d2SKip Macy 
15989e0f4d2SKip Macy #define INVALID_P2M_ENTRY (~0UL)
16096375eacSRoger Pau Monné #define XN_QUEUE_NAME_LEN  8	/* xn{t,r}x_%u, allow for two digits */
16196375eacSRoger Pau Monné struct netfront_rxq {
16296375eacSRoger Pau Monné 	struct netfront_info 	*info;
16396375eacSRoger Pau Monné 	u_int			id;
16496375eacSRoger Pau Monné 	char			name[XN_QUEUE_NAME_LEN];
16596375eacSRoger Pau Monné 	struct mtx		lock;
16696375eacSRoger Pau Monné 
16796375eacSRoger Pau Monné 	int			ring_ref;
16896375eacSRoger Pau Monné 	netif_rx_front_ring_t 	ring;
16996375eacSRoger Pau Monné 	xen_intr_handle_t	xen_intr_handle;
17096375eacSRoger Pau Monné 
17196375eacSRoger Pau Monné 	grant_ref_t 		gref_head;
17236ea5721SOlivier Houchard 	grant_ref_t 		grant_ref[NET_RX_RING_SIZE + 1];
17396375eacSRoger Pau Monné 
17496375eacSRoger Pau Monné 	struct mbuf		*mbufs[NET_RX_RING_SIZE + 1];
17596375eacSRoger Pau Monné 
17696375eacSRoger Pau Monné 	struct lro_ctrl		lro;
17796375eacSRoger Pau Monné 
1782568ee67SRoger Pau Monné 	struct callout		rx_refill;
17996375eacSRoger Pau Monné };
18096375eacSRoger Pau Monné 
18196375eacSRoger Pau Monné struct netfront_txq {
18296375eacSRoger Pau Monné 	struct netfront_info 	*info;
18396375eacSRoger Pau Monné 	u_int 			id;
18496375eacSRoger Pau Monné 	char			name[XN_QUEUE_NAME_LEN];
18596375eacSRoger Pau Monné 	struct mtx		lock;
18696375eacSRoger Pau Monné 
18796375eacSRoger Pau Monné 	int			ring_ref;
18896375eacSRoger Pau Monné 	netif_tx_front_ring_t	ring;
18996375eacSRoger Pau Monné 	xen_intr_handle_t 	xen_intr_handle;
19096375eacSRoger Pau Monné 
19196375eacSRoger Pau Monné 	grant_ref_t		gref_head;
19296375eacSRoger Pau Monné 	grant_ref_t		grant_ref[NET_TX_RING_SIZE + 1];
19396375eacSRoger Pau Monné 
19496375eacSRoger Pau Monné 	struct mbuf		*mbufs[NET_TX_RING_SIZE + 1];
19596375eacSRoger Pau Monné 	int			mbufs_cnt;
19696375eacSRoger Pau Monné 	struct buf_ring		*br;
19796375eacSRoger Pau Monné 
19896375eacSRoger Pau Monné 	struct taskqueue 	*tq;
19996375eacSRoger Pau Monné 	struct task       	defrtask;
20096375eacSRoger Pau Monné 
201dabb3db7SRoger Pau Monné 	bus_dma_segment_t	segs[MAX_TX_REQ_FRAGS];
202dabb3db7SRoger Pau Monné 	struct mbuf_xennet {
203dabb3db7SRoger Pau Monné 		struct m_tag 	tag;
204dabb3db7SRoger Pau Monné 		bus_dma_tag_t	dma_tag;
205dabb3db7SRoger Pau Monné 		bus_dmamap_t	dma_map;
206dabb3db7SRoger Pau Monné 		struct netfront_txq *txq;
207dabb3db7SRoger Pau Monné 		SLIST_ENTRY(mbuf_xennet) next;
208dabb3db7SRoger Pau Monné 		u_int 		count;
209dabb3db7SRoger Pau Monné 	}			xennet_tag[NET_TX_RING_SIZE + 1];
210dabb3db7SRoger Pau Monné 	SLIST_HEAD(, mbuf_xennet) tags;
211dabb3db7SRoger Pau Monné 
21296375eacSRoger Pau Monné 	bool			full;
21396375eacSRoger Pau Monné };
21496375eacSRoger Pau Monné 
21589e0f4d2SKip Macy struct netfront_info {
21602f3b17fSJustin Hibbits 	if_t			xn_ifp;
21789e0f4d2SKip Macy 
218227ca257SKip Macy 	struct mtx   		sc_lock;
21989e0f4d2SKip Macy 
22096375eacSRoger Pau Monné 	u_int  num_queues;
22196375eacSRoger Pau Monné 	struct netfront_rxq 	*rxq;
22296375eacSRoger Pau Monné 	struct netfront_txq 	*txq;
22396375eacSRoger Pau Monné 
22489e0f4d2SKip Macy 	u_int			carrier;
225578e4bf7SJustin T. Gibbs 	u_int			maxfrags;
22689e0f4d2SKip Macy 
22723dc5621SKip Macy 	device_t		xbdev;
22889e0f4d2SKip Macy 	uint8_t			mac[ETHER_ADDR_LEN];
22989e0f4d2SKip Macy 
23089e0f4d2SKip Macy 	int			xn_if_flags;
23189e0f4d2SKip Macy 
2320e509842SJustin T. Gibbs 	struct ifmedia		sc_media;
2336a8e9695SRoger Pau Monné 
234dabb3db7SRoger Pau Monné 	bus_dma_tag_t		dma_tag;
235dabb3db7SRoger Pau Monné 
236c2d12e5eSRoger Pau Monné 	bool			xn_reset;
23789e0f4d2SKip Macy };
23889e0f4d2SKip Macy 
23996375eacSRoger Pau Monné struct netfront_rx_info {
24096375eacSRoger Pau Monné 	struct netif_rx_response rx;
24196375eacSRoger Pau Monné 	struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
24296375eacSRoger Pau Monné };
24389e0f4d2SKip Macy 
24496375eacSRoger Pau Monné #define XN_RX_LOCK(_q)         mtx_lock(&(_q)->lock)
24596375eacSRoger Pau Monné #define XN_RX_UNLOCK(_q)       mtx_unlock(&(_q)->lock)
24689e0f4d2SKip Macy 
24796375eacSRoger Pau Monné #define XN_TX_LOCK(_q)         mtx_lock(&(_q)->lock)
24896375eacSRoger Pau Monné #define XN_TX_TRYLOCK(_q)      mtx_trylock(&(_q)->lock)
24996375eacSRoger Pau Monné #define XN_TX_UNLOCK(_q)       mtx_unlock(&(_q)->lock)
25089e0f4d2SKip Macy 
251227ca257SKip Macy #define XN_LOCK(_sc)           mtx_lock(&(_sc)->sc_lock);
252227ca257SKip Macy #define XN_UNLOCK(_sc)         mtx_unlock(&(_sc)->sc_lock);
25389e0f4d2SKip Macy 
254227ca257SKip Macy #define XN_LOCK_ASSERT(_sc)    mtx_assert(&(_sc)->sc_lock, MA_OWNED);
25596375eacSRoger Pau Monné #define XN_RX_LOCK_ASSERT(_q)  mtx_assert(&(_q)->lock, MA_OWNED);
25696375eacSRoger Pau Monné #define XN_TX_LOCK_ASSERT(_q)  mtx_assert(&(_q)->lock, MA_OWNED);
25789e0f4d2SKip Macy 
25889e0f4d2SKip Macy #define netfront_carrier_on(netif)	((netif)->carrier = 1)
25989e0f4d2SKip Macy #define netfront_carrier_off(netif)	((netif)->carrier = 0)
26089e0f4d2SKip Macy #define netfront_carrier_ok(netif)	((netif)->carrier)
26189e0f4d2SKip Macy 
26289e0f4d2SKip Macy /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */
26389e0f4d2SKip Macy 
26489e0f4d2SKip Macy static inline void
265931eeffaSKenneth D. Merry add_id_to_freelist(struct mbuf **list, uintptr_t id)
26689e0f4d2SKip Macy {
26796375eacSRoger Pau Monné 
268931eeffaSKenneth D. Merry 	KASSERT(id != 0,
269931eeffaSKenneth D. Merry 		("%s: the head item (0) must always be free.", __func__));
27089e0f4d2SKip Macy 	list[id] = list[0];
271931eeffaSKenneth D. Merry 	list[0]  = (struct mbuf *)id;
27289e0f4d2SKip Macy }
27389e0f4d2SKip Macy 
27489e0f4d2SKip Macy static inline unsigned short
27589e0f4d2SKip Macy get_id_from_freelist(struct mbuf **list)
27689e0f4d2SKip Macy {
277931eeffaSKenneth D. Merry 	uintptr_t id;
278931eeffaSKenneth D. Merry 
279931eeffaSKenneth D. Merry 	id = (uintptr_t)list[0];
280931eeffaSKenneth D. Merry 	KASSERT(id != 0,
281931eeffaSKenneth D. Merry 		("%s: the head item (0) must always remain free.", __func__));
28289e0f4d2SKip Macy 	list[0] = list[id];
28389e0f4d2SKip Macy 	return (id);
28489e0f4d2SKip Macy }
28589e0f4d2SKip Macy 
28689e0f4d2SKip Macy static inline int
28796375eacSRoger Pau Monné xn_rxidx(RING_IDX idx)
28889e0f4d2SKip Macy {
28996375eacSRoger Pau Monné 
29089e0f4d2SKip Macy 	return idx & (NET_RX_RING_SIZE - 1);
29189e0f4d2SKip Macy }
29289e0f4d2SKip Macy 
29389e0f4d2SKip Macy static inline struct mbuf *
29496375eacSRoger Pau Monné xn_get_rx_mbuf(struct netfront_rxq *rxq, RING_IDX ri)
29589e0f4d2SKip Macy {
29696375eacSRoger Pau Monné 	int i;
29789e0f4d2SKip Macy 	struct mbuf *m;
29889e0f4d2SKip Macy 
29996375eacSRoger Pau Monné 	i = xn_rxidx(ri);
30096375eacSRoger Pau Monné 	m = rxq->mbufs[i];
30196375eacSRoger Pau Monné 	rxq->mbufs[i] = NULL;
30289e0f4d2SKip Macy 	return (m);
30389e0f4d2SKip Macy }
30489e0f4d2SKip Macy 
30589e0f4d2SKip Macy static inline grant_ref_t
30696375eacSRoger Pau Monné xn_get_rx_ref(struct netfront_rxq *rxq, RING_IDX ri)
30789e0f4d2SKip Macy {
30896375eacSRoger Pau Monné 	int i = xn_rxidx(ri);
30996375eacSRoger Pau Monné 	grant_ref_t ref = rxq->grant_ref[i];
31096375eacSRoger Pau Monné 
311ff662b5cSJustin T. Gibbs 	KASSERT(ref != GRANT_REF_INVALID, ("Invalid grant reference!\n"));
31296375eacSRoger Pau Monné 	rxq->grant_ref[i] = GRANT_REF_INVALID;
31396375eacSRoger Pau Monné 	return (ref);
31489e0f4d2SKip Macy }
31589e0f4d2SKip Macy 
316dabb3db7SRoger Pau Monné #define MTAG_COOKIE 1218492000
317dabb3db7SRoger Pau Monné #define MTAG_XENNET 0
318dabb3db7SRoger Pau Monné 
319dabb3db7SRoger Pau Monné static void mbuf_grab(struct mbuf *m)
320dabb3db7SRoger Pau Monné {
321dabb3db7SRoger Pau Monné 	struct mbuf_xennet *ref;
322dabb3db7SRoger Pau Monné 
323dabb3db7SRoger Pau Monné 	ref = (struct mbuf_xennet *)m_tag_locate(m, MTAG_COOKIE,
324dabb3db7SRoger Pau Monné 	    MTAG_XENNET, NULL);
325dabb3db7SRoger Pau Monné 	KASSERT(ref != NULL, ("Cannot find refcount"));
326dabb3db7SRoger Pau Monné 	ref->count++;
327dabb3db7SRoger Pau Monné }
328dabb3db7SRoger Pau Monné 
329dabb3db7SRoger Pau Monné static void mbuf_release(struct mbuf *m)
330dabb3db7SRoger Pau Monné {
331dabb3db7SRoger Pau Monné 	struct mbuf_xennet *ref;
332dabb3db7SRoger Pau Monné 
333dabb3db7SRoger Pau Monné 	ref = (struct mbuf_xennet *)m_tag_locate(m, MTAG_COOKIE,
334dabb3db7SRoger Pau Monné 	    MTAG_XENNET, NULL);
335dabb3db7SRoger Pau Monné 	KASSERT(ref != NULL, ("Cannot find refcount"));
336dabb3db7SRoger Pau Monné 	KASSERT(ref->count > 0, ("Invalid reference count"));
337dabb3db7SRoger Pau Monné 
338dabb3db7SRoger Pau Monné 	if (--ref->count == 0)
339dabb3db7SRoger Pau Monné 		m_freem(m);
340dabb3db7SRoger Pau Monné }
341dabb3db7SRoger Pau Monné 
342dabb3db7SRoger Pau Monné static void tag_free(struct m_tag *t)
343dabb3db7SRoger Pau Monné {
344dabb3db7SRoger Pau Monné 	struct mbuf_xennet *ref = (struct mbuf_xennet *)t;
345dabb3db7SRoger Pau Monné 
346dabb3db7SRoger Pau Monné 	KASSERT(ref->count == 0, ("Free mbuf tag with pending refcnt"));
347dabb3db7SRoger Pau Monné 	bus_dmamap_sync(ref->dma_tag, ref->dma_map, BUS_DMASYNC_POSTWRITE);
348dabb3db7SRoger Pau Monné 	bus_dmamap_destroy(ref->dma_tag, ref->dma_map);
349dabb3db7SRoger Pau Monné 	SLIST_INSERT_HEAD(&ref->txq->tags, ref, next);
350dabb3db7SRoger Pau Monné }
351dabb3db7SRoger Pau Monné 
35289e0f4d2SKip Macy #define IPRINTK(fmt, args...) \
35389e0f4d2SKip Macy     printf("[XEN] " fmt, ##args)
354227ca257SKip Macy #ifdef INVARIANTS
35589e0f4d2SKip Macy #define WPRINTK(fmt, args...) \
35689e0f4d2SKip Macy     printf("[XEN] " fmt, ##args)
357227ca257SKip Macy #else
358227ca257SKip Macy #define WPRINTK(fmt, args...)
359227ca257SKip Macy #endif
360227ca257SKip Macy #ifdef DEBUG
36189e0f4d2SKip Macy #define DPRINTK(fmt, args...) \
36223dc5621SKip Macy     printf("[XEN] %s: " fmt, __func__, ##args)
36312678024SDoug Rabson #else
36412678024SDoug Rabson #define DPRINTK(fmt, args...)
36512678024SDoug Rabson #endif
36689e0f4d2SKip Macy 
36789e0f4d2SKip Macy /**
36889e0f4d2SKip Macy  * Read the 'mac' node at the given device's node in the store, and parse that
36989e0f4d2SKip Macy  * as colon-separated octets, placing result the given mac array.  mac must be
37089e0f4d2SKip Macy  * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h).
37189e0f4d2SKip Macy  * Return 0 on success, or errno on error.
37289e0f4d2SKip Macy  */
37389e0f4d2SKip Macy static int
37423dc5621SKip Macy xen_net_read_mac(device_t dev, uint8_t mac[])
37589e0f4d2SKip Macy {
3763a6d1fcfSKip Macy 	int error, i;
3773a6d1fcfSKip Macy 	char *s, *e, *macstr;
378ffa06904SJustin T. Gibbs 	const char *path;
3793a6d1fcfSKip Macy 
380ffa06904SJustin T. Gibbs 	path = xenbus_get_node(dev);
381ffa06904SJustin T. Gibbs 	error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr);
382ffa06904SJustin T. Gibbs 	if (error == ENOENT) {
383ffa06904SJustin T. Gibbs 		/*
384ffa06904SJustin T. Gibbs 		 * Deal with missing mac XenStore nodes on devices with
385ffa06904SJustin T. Gibbs 		 * HVM emulation (the 'ioemu' configuration attribute)
386ffa06904SJustin T. Gibbs 		 * enabled.
387ffa06904SJustin T. Gibbs 		 *
388ffa06904SJustin T. Gibbs 		 * The HVM emulator may execute in a stub device model
389ffa06904SJustin T. Gibbs 		 * domain which lacks the permission, only given to Dom0,
390ffa06904SJustin T. Gibbs 		 * to update the guest's XenStore tree.  For this reason,
391ffa06904SJustin T. Gibbs 		 * the HVM emulator doesn't even attempt to write the
392ffa06904SJustin T. Gibbs 		 * front-side mac node, even when operating in Dom0.
393ffa06904SJustin T. Gibbs 		 * However, there should always be a mac listed in the
394ffa06904SJustin T. Gibbs 		 * backend tree.  Fallback to this version if our query
395ffa06904SJustin T. Gibbs 		 * of the front side XenStore location doesn't find
396ffa06904SJustin T. Gibbs 		 * anything.
397ffa06904SJustin T. Gibbs 		 */
398ffa06904SJustin T. Gibbs 		path = xenbus_get_otherend_path(dev);
399ffa06904SJustin T. Gibbs 		error = xs_read(XST_NIL, path, "mac", NULL, (void **) &macstr);
400ffa06904SJustin T. Gibbs 	}
401ffa06904SJustin T. Gibbs 	if (error != 0) {
402ffa06904SJustin T. Gibbs 		xenbus_dev_fatal(dev, error, "parsing %s/mac", path);
4033a6d1fcfSKip Macy 		return (error);
404ffa06904SJustin T. Gibbs 	}
4053a6d1fcfSKip Macy 
40689e0f4d2SKip Macy 	s = macstr;
40789e0f4d2SKip Macy 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
40889e0f4d2SKip Macy 		mac[i] = strtoul(s, &e, 16);
40989e0f4d2SKip Macy 		if (s == e || (e[0] != ':' && e[0] != 0)) {
410ff662b5cSJustin T. Gibbs 			free(macstr, M_XENBUS);
4113a6d1fcfSKip Macy 			return (ENOENT);
41289e0f4d2SKip Macy 		}
41389e0f4d2SKip Macy 		s = &e[1];
41489e0f4d2SKip Macy 	}
415ff662b5cSJustin T. Gibbs 	free(macstr, M_XENBUS);
4163a6d1fcfSKip Macy 	return (0);
41789e0f4d2SKip Macy }
41889e0f4d2SKip Macy 
41989e0f4d2SKip Macy /**
42089e0f4d2SKip Macy  * Entry point to this code when a new device is created.  Allocate the basic
42189e0f4d2SKip Macy  * structures and the ring buffers for communication with the backend, and
42289e0f4d2SKip Macy  * inform the backend of the appropriate details for those.  Switch to
42389e0f4d2SKip Macy  * Connected state.
42489e0f4d2SKip Macy  */
42589e0f4d2SKip Macy static int
42623dc5621SKip Macy netfront_probe(device_t dev)
42723dc5621SKip Macy {
42823dc5621SKip Macy 
4295f700083SJulien Grall 	if (xen_pv_nics_disabled())
430f8f1bb83SRoger Pau Monné 		return (ENXIO);
431f8f1bb83SRoger Pau Monné 
43223dc5621SKip Macy 	if (!strcmp(xenbus_get_type(dev), "vif")) {
43323dc5621SKip Macy 		device_set_desc(dev, "Virtual Network Interface");
43423dc5621SKip Macy 		return (0);
43523dc5621SKip Macy 	}
43623dc5621SKip Macy 
43723dc5621SKip Macy 	return (ENXIO);
43823dc5621SKip Macy }
43923dc5621SKip Macy 
44023dc5621SKip Macy static int
44123dc5621SKip Macy netfront_attach(device_t dev)
44289e0f4d2SKip Macy {
44389e0f4d2SKip Macy 	int err;
44489e0f4d2SKip Macy 
44523dc5621SKip Macy 	err = create_netdev(dev);
44696375eacSRoger Pau Monné 	if (err != 0) {
44789e0f4d2SKip Macy 		xenbus_dev_fatal(dev, err, "creating netdev");
448ffa06904SJustin T. Gibbs 		return (err);
44989e0f4d2SKip Macy 	}
45089e0f4d2SKip Macy 
45112678024SDoug Rabson 	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
45212678024SDoug Rabson 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
453f0188618SHans Petter Selasky 	    OID_AUTO, "enable_lro", CTLFLAG_RW,
45412678024SDoug Rabson 	    &xn_enable_lro, 0, "Large Receive Offload");
45512678024SDoug Rabson 
45696375eacSRoger Pau Monné 	SYSCTL_ADD_ULONG(device_get_sysctl_ctx(dev),
45796375eacSRoger Pau Monné 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
45896375eacSRoger Pau Monné 	    OID_AUTO, "num_queues", CTLFLAG_RD,
45996375eacSRoger Pau Monné 	    &xn_num_queues, "Number of pairs of queues");
46096375eacSRoger Pau Monné 
461ffa06904SJustin T. Gibbs 	return (0);
46289e0f4d2SKip Macy }
46389e0f4d2SKip Macy 
464cf9c09e1SJustin T. Gibbs static int
465cf9c09e1SJustin T. Gibbs netfront_suspend(device_t dev)
466cf9c09e1SJustin T. Gibbs {
46796375eacSRoger Pau Monné 	struct netfront_info *np = device_get_softc(dev);
46896375eacSRoger Pau Monné 	u_int i;
469cf9c09e1SJustin T. Gibbs 
47096375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
47196375eacSRoger Pau Monné 		XN_RX_LOCK(&np->rxq[i]);
47296375eacSRoger Pau Monné 		XN_TX_LOCK(&np->txq[i]);
47396375eacSRoger Pau Monné 	}
47496375eacSRoger Pau Monné 	netfront_carrier_off(np);
47596375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
47696375eacSRoger Pau Monné 		XN_RX_UNLOCK(&np->rxq[i]);
47796375eacSRoger Pau Monné 		XN_TX_UNLOCK(&np->txq[i]);
47896375eacSRoger Pau Monné 	}
479cf9c09e1SJustin T. Gibbs 	return (0);
480cf9c09e1SJustin T. Gibbs }
48189e0f4d2SKip Macy 
48289e0f4d2SKip Macy /**
48389e0f4d2SKip Macy  * We are reconnecting to the backend, due to a suspend/resume, or a backend
48489e0f4d2SKip Macy  * driver restart.  We tear down our netif structure and recreate it, but
48589e0f4d2SKip Macy  * leave the device-layer structures intact so that this is transparent to the
48689e0f4d2SKip Macy  * rest of the kernel.
48789e0f4d2SKip Macy  */
48889e0f4d2SKip Macy static int
48923dc5621SKip Macy netfront_resume(device_t dev)
49089e0f4d2SKip Macy {
49123dc5621SKip Macy 	struct netfront_info *info = device_get_softc(dev);
4928dee0e9bSRoger Pau Monné 	u_int i;
4938dee0e9bSRoger Pau Monné 
4948dee0e9bSRoger Pau Monné 	if (xen_suspend_cancelled) {
4958dee0e9bSRoger Pau Monné 		for (i = 0; i < info->num_queues; i++) {
4968dee0e9bSRoger Pau Monné 			XN_RX_LOCK(&info->rxq[i]);
4978dee0e9bSRoger Pau Monné 			XN_TX_LOCK(&info->txq[i]);
4988dee0e9bSRoger Pau Monné 		}
4998dee0e9bSRoger Pau Monné 		netfront_carrier_on(info);
5008dee0e9bSRoger Pau Monné 		for (i = 0; i < info->num_queues; i++) {
5018dee0e9bSRoger Pau Monné 			XN_RX_UNLOCK(&info->rxq[i]);
5028dee0e9bSRoger Pau Monné 			XN_TX_UNLOCK(&info->txq[i]);
5038dee0e9bSRoger Pau Monné 		}
5048dee0e9bSRoger Pau Monné 		return (0);
5058dee0e9bSRoger Pau Monné 	}
50689e0f4d2SKip Macy 
50789e0f4d2SKip Macy 	netif_disconnect_backend(info);
50889e0f4d2SKip Macy 	return (0);
50989e0f4d2SKip Macy }
51089e0f4d2SKip Macy 
51196375eacSRoger Pau Monné static int
51296375eacSRoger Pau Monné write_queue_xenstore_keys(device_t dev,
51396375eacSRoger Pau Monné     struct netfront_rxq *rxq,
51496375eacSRoger Pau Monné     struct netfront_txq *txq,
51596375eacSRoger Pau Monné     struct xs_transaction *xst, bool hierarchy)
51696375eacSRoger Pau Monné {
51796375eacSRoger Pau Monné 	int err;
51896375eacSRoger Pau Monné 	const char *message;
51996375eacSRoger Pau Monné 	const char *node = xenbus_get_node(dev);
52096375eacSRoger Pau Monné 	char *path;
52196375eacSRoger Pau Monné 	size_t path_size;
52296375eacSRoger Pau Monné 
52396375eacSRoger Pau Monné 	KASSERT(rxq->id == txq->id, ("Mismatch between RX and TX queue ids"));
52496375eacSRoger Pau Monné 	/* Split event channel support is not yet there. */
52596375eacSRoger Pau Monné 	KASSERT(rxq->xen_intr_handle == txq->xen_intr_handle,
52696375eacSRoger Pau Monné 	    ("Split event channels are not supported"));
52796375eacSRoger Pau Monné 
52896375eacSRoger Pau Monné 	if (hierarchy) {
52996375eacSRoger Pau Monné 		path_size = strlen(node) + 10;
53096375eacSRoger Pau Monné 		path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO);
53196375eacSRoger Pau Monné 		snprintf(path, path_size, "%s/queue-%u", node, rxq->id);
53296375eacSRoger Pau Monné 	} else {
53396375eacSRoger Pau Monné 		path_size = strlen(node) + 1;
53496375eacSRoger Pau Monné 		path = malloc(path_size, M_DEVBUF, M_WAITOK|M_ZERO);
53596375eacSRoger Pau Monné 		snprintf(path, path_size, "%s", node);
53696375eacSRoger Pau Monné 	}
53796375eacSRoger Pau Monné 
53896375eacSRoger Pau Monné 	err = xs_printf(*xst, path, "tx-ring-ref","%u", txq->ring_ref);
53996375eacSRoger Pau Monné 	if (err != 0) {
54096375eacSRoger Pau Monné 		message = "writing tx ring-ref";
54196375eacSRoger Pau Monné 		goto error;
54296375eacSRoger Pau Monné 	}
54396375eacSRoger Pau Monné 	err = xs_printf(*xst, path, "rx-ring-ref","%u", rxq->ring_ref);
54496375eacSRoger Pau Monné 	if (err != 0) {
54596375eacSRoger Pau Monné 		message = "writing rx ring-ref";
54696375eacSRoger Pau Monné 		goto error;
54796375eacSRoger Pau Monné 	}
54896375eacSRoger Pau Monné 	err = xs_printf(*xst, path, "event-channel", "%u",
54996375eacSRoger Pau Monné 	    xen_intr_port(rxq->xen_intr_handle));
55096375eacSRoger Pau Monné 	if (err != 0) {
55196375eacSRoger Pau Monné 		message = "writing event-channel";
55296375eacSRoger Pau Monné 		goto error;
55396375eacSRoger Pau Monné 	}
55496375eacSRoger Pau Monné 
55596375eacSRoger Pau Monné 	free(path, M_DEVBUF);
55696375eacSRoger Pau Monné 
55796375eacSRoger Pau Monné 	return (0);
55896375eacSRoger Pau Monné 
55996375eacSRoger Pau Monné error:
56096375eacSRoger Pau Monné 	free(path, M_DEVBUF);
56196375eacSRoger Pau Monné 	xenbus_dev_fatal(dev, err, "%s", message);
56296375eacSRoger Pau Monné 
56396375eacSRoger Pau Monné 	return (err);
56496375eacSRoger Pau Monné }
56596375eacSRoger Pau Monné 
56689e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */
56789e0f4d2SKip Macy static int
56823dc5621SKip Macy talk_to_backend(device_t dev, struct netfront_info *info)
56989e0f4d2SKip Macy {
57089e0f4d2SKip Macy 	const char *message;
571ff662b5cSJustin T. Gibbs 	struct xs_transaction xst;
57223dc5621SKip Macy 	const char *node = xenbus_get_node(dev);
57389e0f4d2SKip Macy 	int err;
57496375eacSRoger Pau Monné 	unsigned long num_queues, max_queues = 0;
57596375eacSRoger Pau Monné 	unsigned int i;
57689e0f4d2SKip Macy 
57789e0f4d2SKip Macy 	err = xen_net_read_mac(dev, info->mac);
57896375eacSRoger Pau Monné 	if (err != 0) {
57923dc5621SKip Macy 		xenbus_dev_fatal(dev, err, "parsing %s/mac", node);
58089e0f4d2SKip Macy 		goto out;
58189e0f4d2SKip Macy 	}
58289e0f4d2SKip Macy 
58396375eacSRoger Pau Monné 	err = xs_scanf(XST_NIL, xenbus_get_otherend_path(info->xbdev),
58496375eacSRoger Pau Monné 	    "multi-queue-max-queues", NULL, "%lu", &max_queues);
58596375eacSRoger Pau Monné 	if (err != 0)
58696375eacSRoger Pau Monné 		max_queues = 1;
58796375eacSRoger Pau Monné 	num_queues = xn_num_queues;
58896375eacSRoger Pau Monné 	if (num_queues > max_queues)
58996375eacSRoger Pau Monné 		num_queues = max_queues;
59096375eacSRoger Pau Monné 
59196375eacSRoger Pau Monné 	err = setup_device(dev, info, num_queues);
59296375eacSRoger Pau Monné 	if (err != 0)
59389e0f4d2SKip Macy 		goto out;
59489e0f4d2SKip Macy 
59589e0f4d2SKip Macy  again:
596ff662b5cSJustin T. Gibbs 	err = xs_transaction_start(&xst);
59796375eacSRoger Pau Monné 	if (err != 0) {
59889e0f4d2SKip Macy 		xenbus_dev_fatal(dev, err, "starting transaction");
59996375eacSRoger Pau Monné 		goto free;
60089e0f4d2SKip Macy 	}
60196375eacSRoger Pau Monné 
60296375eacSRoger Pau Monné 	if (info->num_queues == 1) {
60396375eacSRoger Pau Monné 		err = write_queue_xenstore_keys(dev, &info->rxq[0],
60496375eacSRoger Pau Monné 		    &info->txq[0], &xst, false);
60596375eacSRoger Pau Monné 		if (err != 0)
60696375eacSRoger Pau Monné 			goto abort_transaction_no_def_error;
60796375eacSRoger Pau Monné 	} else {
60896375eacSRoger Pau Monné 		err = xs_printf(xst, node, "multi-queue-num-queues",
60996375eacSRoger Pau Monné 		    "%u", info->num_queues);
61096375eacSRoger Pau Monné 		if (err != 0) {
61196375eacSRoger Pau Monné 			message = "writing multi-queue-num-queues";
61289e0f4d2SKip Macy 			goto abort_transaction;
61389e0f4d2SKip Macy 		}
61496375eacSRoger Pau Monné 
61596375eacSRoger Pau Monné 		for (i = 0; i < info->num_queues; i++) {
61696375eacSRoger Pau Monné 			err = write_queue_xenstore_keys(dev, &info->rxq[i],
61796375eacSRoger Pau Monné 			    &info->txq[i], &xst, true);
61896375eacSRoger Pau Monné 			if (err != 0)
61996375eacSRoger Pau Monné 				goto abort_transaction_no_def_error;
62089e0f4d2SKip Macy 		}
62189e0f4d2SKip Macy 	}
62296375eacSRoger Pau Monné 
623d0f3a8b9SRoger Pau Monné 	err = xs_printf(xst, node, "request-rx-copy", "%u", 1);
62496375eacSRoger Pau Monné 	if (err != 0) {
62589e0f4d2SKip Macy 		message = "writing request-rx-copy";
62689e0f4d2SKip Macy 		goto abort_transaction;
62789e0f4d2SKip Macy 	}
628ff662b5cSJustin T. Gibbs 	err = xs_printf(xst, node, "feature-rx-notify", "%d", 1);
62996375eacSRoger Pau Monné 	if (err != 0) {
63089e0f4d2SKip Macy 		message = "writing feature-rx-notify";
63189e0f4d2SKip Macy 		goto abort_transaction;
63289e0f4d2SKip Macy 	}
633ff662b5cSJustin T. Gibbs 	err = xs_printf(xst, node, "feature-sg", "%d", 1);
63496375eacSRoger Pau Monné 	if (err != 0) {
63589e0f4d2SKip Macy 		message = "writing feature-sg";
63689e0f4d2SKip Macy 		goto abort_transaction;
63789e0f4d2SKip Macy 	}
63802f3b17fSJustin Hibbits 	if ((if_getcapenable(info->xn_ifp) & IFCAP_LRO) != 0) {
639ff662b5cSJustin T. Gibbs 		err = xs_printf(xst, node, "feature-gso-tcpv4", "%d", 1);
64096375eacSRoger Pau Monné 		if (err != 0) {
64189e0f4d2SKip Macy 			message = "writing feature-gso-tcpv4";
64289e0f4d2SKip Macy 			goto abort_transaction;
64389e0f4d2SKip Macy 		}
644c2d12e5eSRoger Pau Monné 	}
64502f3b17fSJustin Hibbits 	if ((if_getcapenable(info->xn_ifp) & IFCAP_RXCSUM) == 0) {
646c2d12e5eSRoger Pau Monné 		err = xs_printf(xst, node, "feature-no-csum-offload", "%d", 1);
647c2d12e5eSRoger Pau Monné 		if (err != 0) {
648c2d12e5eSRoger Pau Monné 			message = "writing feature-no-csum-offload";
649c2d12e5eSRoger Pau Monné 			goto abort_transaction;
650c2d12e5eSRoger Pau Monné 		}
651c2d12e5eSRoger Pau Monné 	}
65289e0f4d2SKip Macy 
653ff662b5cSJustin T. Gibbs 	err = xs_transaction_end(xst, 0);
65496375eacSRoger Pau Monné 	if (err != 0) {
65589e0f4d2SKip Macy 		if (err == EAGAIN)
65689e0f4d2SKip Macy 			goto again;
65789e0f4d2SKip Macy 		xenbus_dev_fatal(dev, err, "completing transaction");
65896375eacSRoger Pau Monné 		goto free;
65989e0f4d2SKip Macy 	}
66089e0f4d2SKip Macy 
66189e0f4d2SKip Macy 	return 0;
66289e0f4d2SKip Macy 
66389e0f4d2SKip Macy  abort_transaction:
66489e0f4d2SKip Macy 	xenbus_dev_fatal(dev, err, "%s", message);
66596375eacSRoger Pau Monné  abort_transaction_no_def_error:
66696375eacSRoger Pau Monné 	xs_transaction_end(xst, 1);
66796375eacSRoger Pau Monné  free:
66889e0f4d2SKip Macy 	netif_free(info);
66989e0f4d2SKip Macy  out:
67096375eacSRoger Pau Monné 	return (err);
67196375eacSRoger Pau Monné }
67296375eacSRoger Pau Monné 
67396375eacSRoger Pau Monné static void
674da695b05SRoger Pau Monné xn_rxq_intr(struct netfront_rxq *rxq)
67596375eacSRoger Pau Monné {
67696375eacSRoger Pau Monné 
67796375eacSRoger Pau Monné 	XN_RX_LOCK(rxq);
67896375eacSRoger Pau Monné 	xn_rxeof(rxq);
67996375eacSRoger Pau Monné 	XN_RX_UNLOCK(rxq);
68096375eacSRoger Pau Monné }
68196375eacSRoger Pau Monné 
68296375eacSRoger Pau Monné static void
68396375eacSRoger Pau Monné xn_txq_start(struct netfront_txq *txq)
68496375eacSRoger Pau Monné {
68596375eacSRoger Pau Monné 	struct netfront_info *np = txq->info;
68602f3b17fSJustin Hibbits 	if_t ifp = np->xn_ifp;
68796375eacSRoger Pau Monné 
68896375eacSRoger Pau Monné 	XN_TX_LOCK_ASSERT(txq);
68996375eacSRoger Pau Monné 	if (!drbr_empty(ifp, txq->br))
69096375eacSRoger Pau Monné 		xn_txq_mq_start_locked(txq, NULL);
69196375eacSRoger Pau Monné }
69296375eacSRoger Pau Monné 
69396375eacSRoger Pau Monné static void
694da695b05SRoger Pau Monné xn_txq_intr(struct netfront_txq *txq)
69596375eacSRoger Pau Monné {
69696375eacSRoger Pau Monné 
69796375eacSRoger Pau Monné 	XN_TX_LOCK(txq);
69896375eacSRoger Pau Monné 	if (RING_HAS_UNCONSUMED_RESPONSES(&txq->ring))
69996375eacSRoger Pau Monné 		xn_txeof(txq);
70096375eacSRoger Pau Monné 	xn_txq_start(txq);
70196375eacSRoger Pau Monné 	XN_TX_UNLOCK(txq);
70296375eacSRoger Pau Monné }
70396375eacSRoger Pau Monné 
70496375eacSRoger Pau Monné static void
70596375eacSRoger Pau Monné xn_txq_tq_deferred(void *xtxq, int pending)
70696375eacSRoger Pau Monné {
70796375eacSRoger Pau Monné 	struct netfront_txq *txq = xtxq;
70896375eacSRoger Pau Monné 
70996375eacSRoger Pau Monné 	XN_TX_LOCK(txq);
71096375eacSRoger Pau Monné 	xn_txq_start(txq);
71196375eacSRoger Pau Monné 	XN_TX_UNLOCK(txq);
71296375eacSRoger Pau Monné }
71396375eacSRoger Pau Monné 
71496375eacSRoger Pau Monné static void
71596375eacSRoger Pau Monné disconnect_rxq(struct netfront_rxq *rxq)
71696375eacSRoger Pau Monné {
71796375eacSRoger Pau Monné 
71896375eacSRoger Pau Monné 	xn_release_rx_bufs(rxq);
71996375eacSRoger Pau Monné 	gnttab_free_grant_references(rxq->gref_head);
720d039b070SRoger Pau Monné 	gnttab_end_foreign_access(rxq->ring_ref, NULL);
72196375eacSRoger Pau Monné 	/*
72296375eacSRoger Pau Monné 	 * No split event channel support at the moment, handle will
72396375eacSRoger Pau Monné 	 * be unbound in tx. So no need to call xen_intr_unbind here,
72496375eacSRoger Pau Monné 	 * but we do want to reset the handler to 0.
72596375eacSRoger Pau Monné 	 */
72696375eacSRoger Pau Monné 	rxq->xen_intr_handle = 0;
72796375eacSRoger Pau Monné }
72896375eacSRoger Pau Monné 
72996375eacSRoger Pau Monné static void
73096375eacSRoger Pau Monné destroy_rxq(struct netfront_rxq *rxq)
73196375eacSRoger Pau Monné {
73296375eacSRoger Pau Monné 
7332568ee67SRoger Pau Monné 	callout_drain(&rxq->rx_refill);
73496375eacSRoger Pau Monné 	free(rxq->ring.sring, M_DEVBUF);
73596375eacSRoger Pau Monné }
73696375eacSRoger Pau Monné 
73796375eacSRoger Pau Monné static void
73896375eacSRoger Pau Monné destroy_rxqs(struct netfront_info *np)
73996375eacSRoger Pau Monné {
74096375eacSRoger Pau Monné 	int i;
74196375eacSRoger Pau Monné 
74296375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++)
74396375eacSRoger Pau Monné 		destroy_rxq(&np->rxq[i]);
74496375eacSRoger Pau Monné 
74596375eacSRoger Pau Monné 	free(np->rxq, M_DEVBUF);
74696375eacSRoger Pau Monné 	np->rxq = NULL;
74789e0f4d2SKip Macy }
74889e0f4d2SKip Macy 
74989e0f4d2SKip Macy static int
75096375eacSRoger Pau Monné setup_rxqs(device_t dev, struct netfront_info *info,
75196375eacSRoger Pau Monné 	   unsigned long num_queues)
75289e0f4d2SKip Macy {
75396375eacSRoger Pau Monné 	int q, i;
7543a6d1fcfSKip Macy 	int error;
75596375eacSRoger Pau Monné 	netif_rx_sring_t *rxs;
75696375eacSRoger Pau Monné 	struct netfront_rxq *rxq;
75789e0f4d2SKip Macy 
75896375eacSRoger Pau Monné 	info->rxq = malloc(sizeof(struct netfront_rxq) * num_queues,
75996375eacSRoger Pau Monné 	    M_DEVBUF, M_WAITOK|M_ZERO);
76089e0f4d2SKip Macy 
76196375eacSRoger Pau Monné 	for (q = 0; q < num_queues; q++) {
76296375eacSRoger Pau Monné 		rxq = &info->rxq[q];
76396375eacSRoger Pau Monné 
76496375eacSRoger Pau Monné 		rxq->id = q;
76596375eacSRoger Pau Monné 		rxq->info = info;
76696375eacSRoger Pau Monné 		rxq->ring_ref = GRANT_REF_INVALID;
76796375eacSRoger Pau Monné 		rxq->ring.sring = NULL;
76896375eacSRoger Pau Monné 		snprintf(rxq->name, XN_QUEUE_NAME_LEN, "xnrx_%u", q);
76996375eacSRoger Pau Monné 		mtx_init(&rxq->lock, rxq->name, "netfront receive lock",
77096375eacSRoger Pau Monné 		    MTX_DEF);
77196375eacSRoger Pau Monné 
77296375eacSRoger Pau Monné 		for (i = 0; i <= NET_RX_RING_SIZE; i++) {
77396375eacSRoger Pau Monné 			rxq->mbufs[i] = NULL;
77496375eacSRoger Pau Monné 			rxq->grant_ref[i] = GRANT_REF_INVALID;
77596375eacSRoger Pau Monné 		}
77696375eacSRoger Pau Monné 
77796375eacSRoger Pau Monné 		/* Start resources allocation */
77896375eacSRoger Pau Monné 
7792568ee67SRoger Pau Monné 		if (gnttab_alloc_grant_references(NET_RX_RING_SIZE,
78096375eacSRoger Pau Monné 		    &rxq->gref_head) != 0) {
78196375eacSRoger Pau Monné 			device_printf(dev, "allocating rx gref");
7823a6d1fcfSKip Macy 			error = ENOMEM;
78389e0f4d2SKip Macy 			goto fail;
78489e0f4d2SKip Macy 		}
78589e0f4d2SKip Macy 
78696375eacSRoger Pau Monné 		rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF,
78796375eacSRoger Pau Monné 		    M_WAITOK|M_ZERO);
78889e0f4d2SKip Macy 		SHARED_RING_INIT(rxs);
78996375eacSRoger Pau Monné 		FRONT_RING_INIT(&rxq->ring, rxs, PAGE_SIZE);
79089e0f4d2SKip Macy 
79196375eacSRoger Pau Monné 		error = xenbus_grant_ring(dev, virt_to_mfn(rxs),
79296375eacSRoger Pau Monné 		    &rxq->ring_ref);
79396375eacSRoger Pau Monné 		if (error != 0) {
79496375eacSRoger Pau Monné 			device_printf(dev, "granting rx ring page");
79596375eacSRoger Pau Monné 			goto fail_grant_ring;
79696375eacSRoger Pau Monné 		}
79789e0f4d2SKip Macy 
7982568ee67SRoger Pau Monné 		callout_init(&rxq->rx_refill, 1);
79989e0f4d2SKip Macy 	}
80089e0f4d2SKip Macy 
8013a6d1fcfSKip Macy 	return (0);
80289e0f4d2SKip Macy 
80396375eacSRoger Pau Monné fail_grant_ring:
80496375eacSRoger Pau Monné 	gnttab_free_grant_references(rxq->gref_head);
80596375eacSRoger Pau Monné 	free(rxq->ring.sring, M_DEVBUF);
80689e0f4d2SKip Macy fail:
80796375eacSRoger Pau Monné 	for (; q >= 0; q--) {
80896375eacSRoger Pau Monné 		disconnect_rxq(&info->rxq[q]);
80996375eacSRoger Pau Monné 		destroy_rxq(&info->rxq[q]);
81096375eacSRoger Pau Monné 	}
81196375eacSRoger Pau Monné 
81296375eacSRoger Pau Monné 	free(info->rxq, M_DEVBUF);
81396375eacSRoger Pau Monné 	return (error);
81496375eacSRoger Pau Monné }
81596375eacSRoger Pau Monné 
81696375eacSRoger Pau Monné static void
81796375eacSRoger Pau Monné disconnect_txq(struct netfront_txq *txq)
81896375eacSRoger Pau Monné {
81996375eacSRoger Pau Monné 
82096375eacSRoger Pau Monné 	xn_release_tx_bufs(txq);
82196375eacSRoger Pau Monné 	gnttab_free_grant_references(txq->gref_head);
822d039b070SRoger Pau Monné 	gnttab_end_foreign_access(txq->ring_ref, NULL);
82396375eacSRoger Pau Monné 	xen_intr_unbind(&txq->xen_intr_handle);
82496375eacSRoger Pau Monné }
82596375eacSRoger Pau Monné 
82696375eacSRoger Pau Monné static void
82796375eacSRoger Pau Monné destroy_txq(struct netfront_txq *txq)
82896375eacSRoger Pau Monné {
829dabb3db7SRoger Pau Monné 	unsigned int i;
83096375eacSRoger Pau Monné 
83196375eacSRoger Pau Monné 	free(txq->ring.sring, M_DEVBUF);
83296375eacSRoger Pau Monné 	buf_ring_free(txq->br, M_DEVBUF);
83396375eacSRoger Pau Monné 	taskqueue_drain_all(txq->tq);
83496375eacSRoger Pau Monné 	taskqueue_free(txq->tq);
835dabb3db7SRoger Pau Monné 
836dabb3db7SRoger Pau Monné 	for (i = 0; i <= NET_TX_RING_SIZE; i++) {
837dabb3db7SRoger Pau Monné 		bus_dmamap_destroy(txq->info->dma_tag,
838dabb3db7SRoger Pau Monné 		    txq->xennet_tag[i].dma_map);
839dabb3db7SRoger Pau Monné 		txq->xennet_tag[i].dma_map = NULL;
840dabb3db7SRoger Pau Monné 	}
84196375eacSRoger Pau Monné }
84296375eacSRoger Pau Monné 
84396375eacSRoger Pau Monné static void
84496375eacSRoger Pau Monné destroy_txqs(struct netfront_info *np)
84596375eacSRoger Pau Monné {
84696375eacSRoger Pau Monné 	int i;
84796375eacSRoger Pau Monné 
84896375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++)
84996375eacSRoger Pau Monné 		destroy_txq(&np->txq[i]);
85096375eacSRoger Pau Monné 
85196375eacSRoger Pau Monné 	free(np->txq, M_DEVBUF);
85296375eacSRoger Pau Monné 	np->txq = NULL;
85396375eacSRoger Pau Monné }
85496375eacSRoger Pau Monné 
85596375eacSRoger Pau Monné static int
85696375eacSRoger Pau Monné setup_txqs(device_t dev, struct netfront_info *info,
85796375eacSRoger Pau Monné 	   unsigned long num_queues)
85896375eacSRoger Pau Monné {
85996375eacSRoger Pau Monné 	int q, i;
86096375eacSRoger Pau Monné 	int error;
86196375eacSRoger Pau Monné 	netif_tx_sring_t *txs;
86296375eacSRoger Pau Monné 	struct netfront_txq *txq;
86396375eacSRoger Pau Monné 
86496375eacSRoger Pau Monné 	info->txq = malloc(sizeof(struct netfront_txq) * num_queues,
86596375eacSRoger Pau Monné 	    M_DEVBUF, M_WAITOK|M_ZERO);
86696375eacSRoger Pau Monné 
86796375eacSRoger Pau Monné 	for (q = 0; q < num_queues; q++) {
86896375eacSRoger Pau Monné 		txq = &info->txq[q];
86996375eacSRoger Pau Monné 
87096375eacSRoger Pau Monné 		txq->id = q;
87196375eacSRoger Pau Monné 		txq->info = info;
87296375eacSRoger Pau Monné 
87396375eacSRoger Pau Monné 		txq->ring_ref = GRANT_REF_INVALID;
87496375eacSRoger Pau Monné 		txq->ring.sring = NULL;
87596375eacSRoger Pau Monné 
87696375eacSRoger Pau Monné 		snprintf(txq->name, XN_QUEUE_NAME_LEN, "xntx_%u", q);
87796375eacSRoger Pau Monné 
87896375eacSRoger Pau Monné 		mtx_init(&txq->lock, txq->name, "netfront transmit lock",
87996375eacSRoger Pau Monné 		    MTX_DEF);
880dabb3db7SRoger Pau Monné 		SLIST_INIT(&txq->tags);
88196375eacSRoger Pau Monné 
88296375eacSRoger Pau Monné 		for (i = 0; i <= NET_TX_RING_SIZE; i++) {
88396375eacSRoger Pau Monné 			txq->mbufs[i] = (void *) ((u_long) i+1);
88496375eacSRoger Pau Monné 			txq->grant_ref[i] = GRANT_REF_INVALID;
885dabb3db7SRoger Pau Monné 			txq->xennet_tag[i].txq = txq;
886dabb3db7SRoger Pau Monné 			txq->xennet_tag[i].dma_tag = info->dma_tag;
887dabb3db7SRoger Pau Monné 			error = bus_dmamap_create(info->dma_tag, 0,
888dabb3db7SRoger Pau Monné 			    &txq->xennet_tag[i].dma_map);
889dabb3db7SRoger Pau Monné 			if (error != 0) {
890dabb3db7SRoger Pau Monné 				device_printf(dev,
891dabb3db7SRoger Pau Monné 				    "failed to allocate dma map\n");
892dabb3db7SRoger Pau Monné 				goto fail;
893dabb3db7SRoger Pau Monné 			}
894dabb3db7SRoger Pau Monné 			m_tag_setup(&txq->xennet_tag[i].tag,
895dabb3db7SRoger Pau Monné 			    MTAG_COOKIE, MTAG_XENNET,
896dabb3db7SRoger Pau Monné 			    sizeof(txq->xennet_tag[i]) -
897dabb3db7SRoger Pau Monné 			    sizeof(txq->xennet_tag[i].tag));
898dabb3db7SRoger Pau Monné 			txq->xennet_tag[i].tag.m_tag_free = &tag_free;
899dabb3db7SRoger Pau Monné 			SLIST_INSERT_HEAD(&txq->tags, &txq->xennet_tag[i],
900dabb3db7SRoger Pau Monné 			    next);
90196375eacSRoger Pau Monné 		}
90296375eacSRoger Pau Monné 		txq->mbufs[NET_TX_RING_SIZE] = (void *)0;
90396375eacSRoger Pau Monné 
90496375eacSRoger Pau Monné 		/* Start resources allocation. */
90596375eacSRoger Pau Monné 
90696375eacSRoger Pau Monné 		if (gnttab_alloc_grant_references(NET_TX_RING_SIZE,
90796375eacSRoger Pau Monné 		    &txq->gref_head) != 0) {
90896375eacSRoger Pau Monné 			device_printf(dev, "failed to allocate tx grant refs\n");
90996375eacSRoger Pau Monné 			error = ENOMEM;
91096375eacSRoger Pau Monné 			goto fail;
91196375eacSRoger Pau Monné 		}
91296375eacSRoger Pau Monné 
91396375eacSRoger Pau Monné 		txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF,
91496375eacSRoger Pau Monné 		    M_WAITOK|M_ZERO);
91596375eacSRoger Pau Monné 		SHARED_RING_INIT(txs);
91696375eacSRoger Pau Monné 		FRONT_RING_INIT(&txq->ring, txs, PAGE_SIZE);
91796375eacSRoger Pau Monné 
91896375eacSRoger Pau Monné 		error = xenbus_grant_ring(dev, virt_to_mfn(txs),
91996375eacSRoger Pau Monné 		    &txq->ring_ref);
92096375eacSRoger Pau Monné 		if (error != 0) {
92196375eacSRoger Pau Monné 			device_printf(dev, "failed to grant tx ring\n");
92296375eacSRoger Pau Monné 			goto fail_grant_ring;
92396375eacSRoger Pau Monné 		}
92496375eacSRoger Pau Monné 
92596375eacSRoger Pau Monné 		txq->br = buf_ring_alloc(NET_TX_RING_SIZE, M_DEVBUF,
92696375eacSRoger Pau Monné 		    M_WAITOK, &txq->lock);
92796375eacSRoger Pau Monné 		TASK_INIT(&txq->defrtask, 0, xn_txq_tq_deferred, txq);
92896375eacSRoger Pau Monné 
929da695b05SRoger Pau Monné 		txq->tq = taskqueue_create(txq->name, M_WAITOK,
93096375eacSRoger Pau Monné 		    taskqueue_thread_enqueue, &txq->tq);
93196375eacSRoger Pau Monné 
93296375eacSRoger Pau Monné 		error = taskqueue_start_threads(&txq->tq, 1, PI_NET,
93396375eacSRoger Pau Monné 		    "%s txq %d", device_get_nameunit(dev), txq->id);
93496375eacSRoger Pau Monné 		if (error != 0) {
93596375eacSRoger Pau Monné 			device_printf(dev, "failed to start tx taskq %d\n",
93696375eacSRoger Pau Monné 			    txq->id);
93796375eacSRoger Pau Monné 			goto fail_start_thread;
93896375eacSRoger Pau Monné 		}
93996375eacSRoger Pau Monné 
94096375eacSRoger Pau Monné 		error = xen_intr_alloc_and_bind_local_port(dev,
941da695b05SRoger Pau Monné 		    xenbus_get_otherend_id(dev), /* filter */ NULL, xn_intr,
942da695b05SRoger Pau Monné 		    &info->txq[q], INTR_TYPE_NET | INTR_MPSAFE | INTR_ENTROPY,
94396375eacSRoger Pau Monné 		    &txq->xen_intr_handle);
94496375eacSRoger Pau Monné 
94596375eacSRoger Pau Monné 		if (error != 0) {
94696375eacSRoger Pau Monné 			device_printf(dev, "xen_intr_alloc_and_bind_local_port failed\n");
94796375eacSRoger Pau Monné 			goto fail_bind_port;
94896375eacSRoger Pau Monné 		}
94996375eacSRoger Pau Monné 	}
95096375eacSRoger Pau Monné 
95196375eacSRoger Pau Monné 	return (0);
95296375eacSRoger Pau Monné 
95396375eacSRoger Pau Monné fail_bind_port:
95496375eacSRoger Pau Monné 	taskqueue_drain_all(txq->tq);
95596375eacSRoger Pau Monné fail_start_thread:
95696375eacSRoger Pau Monné 	buf_ring_free(txq->br, M_DEVBUF);
95796375eacSRoger Pau Monné 	taskqueue_free(txq->tq);
958d039b070SRoger Pau Monné 	gnttab_end_foreign_access(txq->ring_ref, NULL);
95996375eacSRoger Pau Monné fail_grant_ring:
96096375eacSRoger Pau Monné 	gnttab_free_grant_references(txq->gref_head);
96196375eacSRoger Pau Monné 	free(txq->ring.sring, M_DEVBUF);
96296375eacSRoger Pau Monné fail:
96396375eacSRoger Pau Monné 	for (; q >= 0; q--) {
96496375eacSRoger Pau Monné 		disconnect_txq(&info->txq[q]);
96596375eacSRoger Pau Monné 		destroy_txq(&info->txq[q]);
96696375eacSRoger Pau Monné 	}
96796375eacSRoger Pau Monné 
96896375eacSRoger Pau Monné 	free(info->txq, M_DEVBUF);
96996375eacSRoger Pau Monné 	return (error);
97096375eacSRoger Pau Monné }
97196375eacSRoger Pau Monné 
97296375eacSRoger Pau Monné static int
97396375eacSRoger Pau Monné setup_device(device_t dev, struct netfront_info *info,
97496375eacSRoger Pau Monné     unsigned long num_queues)
97596375eacSRoger Pau Monné {
97696375eacSRoger Pau Monné 	int error;
97796375eacSRoger Pau Monné 	int q;
97896375eacSRoger Pau Monné 
97996375eacSRoger Pau Monné 	if (info->txq)
98096375eacSRoger Pau Monné 		destroy_txqs(info);
98196375eacSRoger Pau Monné 
98296375eacSRoger Pau Monné 	if (info->rxq)
98396375eacSRoger Pau Monné 		destroy_rxqs(info);
98496375eacSRoger Pau Monné 
98596375eacSRoger Pau Monné 	info->num_queues = 0;
98696375eacSRoger Pau Monné 
98796375eacSRoger Pau Monné 	error = setup_rxqs(dev, info, num_queues);
98896375eacSRoger Pau Monné 	if (error != 0)
98996375eacSRoger Pau Monné 		goto out;
99096375eacSRoger Pau Monné 	error = setup_txqs(dev, info, num_queues);
99196375eacSRoger Pau Monné 	if (error != 0)
99296375eacSRoger Pau Monné 		goto out;
99396375eacSRoger Pau Monné 
99496375eacSRoger Pau Monné 	info->num_queues = num_queues;
99596375eacSRoger Pau Monné 
99696375eacSRoger Pau Monné 	/* No split event channel at the moment. */
99796375eacSRoger Pau Monné 	for (q = 0; q < num_queues; q++)
99896375eacSRoger Pau Monné 		info->rxq[q].xen_intr_handle = info->txq[q].xen_intr_handle;
99996375eacSRoger Pau Monné 
100096375eacSRoger Pau Monné 	return (0);
100196375eacSRoger Pau Monné 
100296375eacSRoger Pau Monné out:
100396375eacSRoger Pau Monné 	KASSERT(error != 0, ("Error path taken without providing an error code"));
10043a6d1fcfSKip Macy 	return (error);
100589e0f4d2SKip Macy }
100689e0f4d2SKip Macy 
1007a0ae8f04SBjoern A. Zeeb #ifdef INET
100802f3b17fSJustin Hibbits static u_int
100902f3b17fSJustin Hibbits netfront_addr_cb(void *arg, struct ifaddr *a, u_int count)
101002f3b17fSJustin Hibbits {
101102f3b17fSJustin Hibbits 	arp_ifinit((if_t)arg, a);
101202f3b17fSJustin Hibbits 	return (1);
101302f3b17fSJustin Hibbits }
101489e0f4d2SKip Macy /**
101512678024SDoug Rabson  * If this interface has an ipv4 address, send an arp for it. This
101612678024SDoug Rabson  * helps to get the network going again after migrating hosts.
101712678024SDoug Rabson  */
101812678024SDoug Rabson static void
101912678024SDoug Rabson netfront_send_fake_arp(device_t dev, struct netfront_info *info)
102012678024SDoug Rabson {
102102f3b17fSJustin Hibbits 	if_t ifp;
102212678024SDoug Rabson 
102312678024SDoug Rabson 	ifp = info->xn_ifp;
102402f3b17fSJustin Hibbits 	if_foreach_addr_type(ifp, AF_INET, netfront_addr_cb, ifp);
102512678024SDoug Rabson }
1026a0ae8f04SBjoern A. Zeeb #endif
102712678024SDoug Rabson 
102812678024SDoug Rabson /**
102989e0f4d2SKip Macy  * Callback received when the backend's state changes.
103089e0f4d2SKip Macy  */
1031283d6f72SJustin T. Gibbs static void
103223dc5621SKip Macy netfront_backend_changed(device_t dev, XenbusState newstate)
103389e0f4d2SKip Macy {
103423dc5621SKip Macy 	struct netfront_info *sc = device_get_softc(dev);
103589e0f4d2SKip Macy 
103623dc5621SKip Macy 	DPRINTK("newstate=%d\n", newstate);
103789e0f4d2SKip Macy 
103802f3b17fSJustin Hibbits 	CURVNET_SET(if_getvnet(sc->xn_ifp));
1039903eaa68SKristof Provost 
104023dc5621SKip Macy 	switch (newstate) {
104189e0f4d2SKip Macy 	case XenbusStateInitialising:
104289e0f4d2SKip Macy 	case XenbusStateInitialised:
104389e0f4d2SKip Macy 	case XenbusStateUnknown:
1044920ba15bSKip Macy 	case XenbusStateReconfigured:
1045920ba15bSKip Macy 	case XenbusStateReconfiguring:
104689e0f4d2SKip Macy 		break;
104789e0f4d2SKip Macy 	case XenbusStateInitWait:
104823dc5621SKip Macy 		if (xenbus_get_state(dev) != XenbusStateInitialising)
104989e0f4d2SKip Macy 			break;
105096375eacSRoger Pau Monné 		if (xn_connect(sc) != 0)
105189e0f4d2SKip Macy 			break;
105265671253SRoger Pau Monné 		/* Switch to connected state before kicking the rings. */
105365671253SRoger Pau Monné 		xenbus_set_state(sc->xbdev, XenbusStateConnected);
105465671253SRoger Pau Monné 		xn_kick_rings(sc);
105523dc5621SKip Macy 		break;
105689e0f4d2SKip Macy 	case XenbusStateClosing:
105723dc5621SKip Macy 		xenbus_set_state(dev, XenbusStateClosed);
105889e0f4d2SKip Macy 		break;
1059c2d12e5eSRoger Pau Monné 	case XenbusStateClosed:
1060c2d12e5eSRoger Pau Monné 		if (sc->xn_reset) {
1061c2d12e5eSRoger Pau Monné 			netif_disconnect_backend(sc);
1062c2d12e5eSRoger Pau Monné 			xenbus_set_state(dev, XenbusStateInitialising);
1063c2d12e5eSRoger Pau Monné 			sc->xn_reset = false;
1064c2d12e5eSRoger Pau Monné 		}
1065c2d12e5eSRoger Pau Monné 		break;
1066dbf82bdeSRoger Pau Monné 	case XenbusStateConnected:
1067dbf82bdeSRoger Pau Monné #ifdef INET
1068dbf82bdeSRoger Pau Monné 		netfront_send_fake_arp(dev, sc);
1069dbf82bdeSRoger Pau Monné #endif
1070dbf82bdeSRoger Pau Monné 		break;
107189e0f4d2SKip Macy 	}
1072903eaa68SKristof Provost 
1073903eaa68SKristof Provost 	CURVNET_RESTORE();
107489e0f4d2SKip Macy }
107589e0f4d2SKip Macy 
1076931eeffaSKenneth D. Merry /**
1077931eeffaSKenneth D. Merry  * \brief Verify that there is sufficient space in the Tx ring
1078931eeffaSKenneth D. Merry  *        buffer for a maximally sized request to be enqueued.
1079c099cafaSAdrian Chadd  *
1080931eeffaSKenneth D. Merry  * A transmit request requires a transmit descriptor for each packet
1081931eeffaSKenneth D. Merry  * fragment, plus up to 2 entries for "options" (e.g. TSO).
1082c099cafaSAdrian Chadd  */
108389e0f4d2SKip Macy static inline int
108496375eacSRoger Pau Monné xn_tx_slot_available(struct netfront_txq *txq)
108589e0f4d2SKip Macy {
108696375eacSRoger Pau Monné 
108796375eacSRoger Pau Monné 	return (RING_FREE_REQUESTS(&txq->ring) > (MAX_TX_REQ_FRAGS + 2));
108889e0f4d2SKip Macy }
1089931eeffaSKenneth D. Merry 
109089e0f4d2SKip Macy static void
109196375eacSRoger Pau Monné xn_release_tx_bufs(struct netfront_txq *txq)
109289e0f4d2SKip Macy {
109389e0f4d2SKip Macy 	int i;
109489e0f4d2SKip Macy 
109589e0f4d2SKip Macy 	for (i = 1; i <= NET_TX_RING_SIZE; i++) {
1096931eeffaSKenneth D. Merry 		struct mbuf *m;
109789e0f4d2SKip Macy 
109896375eacSRoger Pau Monné 		m = txq->mbufs[i];
1099931eeffaSKenneth D. Merry 
1100931eeffaSKenneth D. Merry 		/*
1101931eeffaSKenneth D. Merry 		 * We assume that no kernel addresses are
1102931eeffaSKenneth D. Merry 		 * less than NET_TX_RING_SIZE.  Any entry
1103931eeffaSKenneth D. Merry 		 * in the table that is below this number
1104931eeffaSKenneth D. Merry 		 * must be an index from free-list tracking.
1105931eeffaSKenneth D. Merry 		 */
1106931eeffaSKenneth D. Merry 		if (((uintptr_t)m) <= NET_TX_RING_SIZE)
110789e0f4d2SKip Macy 			continue;
110896375eacSRoger Pau Monné 		gnttab_end_foreign_access_ref(txq->grant_ref[i]);
110996375eacSRoger Pau Monné 		gnttab_release_grant_reference(&txq->gref_head,
111096375eacSRoger Pau Monné 		    txq->grant_ref[i]);
111196375eacSRoger Pau Monné 		txq->grant_ref[i] = GRANT_REF_INVALID;
111296375eacSRoger Pau Monné 		add_id_to_freelist(txq->mbufs, i);
111396375eacSRoger Pau Monné 		txq->mbufs_cnt--;
111496375eacSRoger Pau Monné 		if (txq->mbufs_cnt < 0) {
11156f9767acSMarius Strobl 			panic("%s: tx_chain_cnt must be >= 0", __func__);
1116a4ec37f5SAdrian Chadd 		}
1117dabb3db7SRoger Pau Monné 		mbuf_release(m);
111889e0f4d2SKip Macy 	}
111989e0f4d2SKip Macy }
112089e0f4d2SKip Macy 
11212568ee67SRoger Pau Monné static struct mbuf *
11222568ee67SRoger Pau Monné xn_alloc_one_rx_buffer(struct netfront_rxq *rxq)
11232568ee67SRoger Pau Monné {
11242568ee67SRoger Pau Monné 	struct mbuf *m;
11252568ee67SRoger Pau Monné 
11262568ee67SRoger Pau Monné 	m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
11272568ee67SRoger Pau Monné 	if (m == NULL)
11282568ee67SRoger Pau Monné 		return NULL;
11292568ee67SRoger Pau Monné 	m->m_len = m->m_pkthdr.len = MJUMPAGESIZE;
11302568ee67SRoger Pau Monné 
11312568ee67SRoger Pau Monné 	return (m);
11322568ee67SRoger Pau Monné }
11332568ee67SRoger Pau Monné 
113489e0f4d2SKip Macy static void
113596375eacSRoger Pau Monné xn_alloc_rx_buffers(struct netfront_rxq *rxq)
113689e0f4d2SKip Macy {
113789e0f4d2SKip Macy 	RING_IDX req_prod;
11382568ee67SRoger Pau Monné 	int notify;
11392568ee67SRoger Pau Monné 
11402568ee67SRoger Pau Monné 	XN_RX_LOCK_ASSERT(rxq);
11412568ee67SRoger Pau Monné 
11422568ee67SRoger Pau Monné 	if (__predict_false(rxq->info->carrier == 0))
11432568ee67SRoger Pau Monné 		return;
11442568ee67SRoger Pau Monné 
11452568ee67SRoger Pau Monné 	for (req_prod = rxq->ring.req_prod_pvt;
11462568ee67SRoger Pau Monné 	     req_prod - rxq->ring.rsp_cons < NET_RX_RING_SIZE;
11472568ee67SRoger Pau Monné 	     req_prod++) {
11482568ee67SRoger Pau Monné 		struct mbuf *m;
11492568ee67SRoger Pau Monné 		unsigned short id;
115089e0f4d2SKip Macy 		grant_ref_t ref;
11512568ee67SRoger Pau Monné 		struct netif_rx_request *req;
11522568ee67SRoger Pau Monné 		unsigned long pfn;
115389e0f4d2SKip Macy 
11542568ee67SRoger Pau Monné 		m = xn_alloc_one_rx_buffer(rxq);
11552568ee67SRoger Pau Monné 		if (m == NULL)
115689e0f4d2SKip Macy 			break;
115789e0f4d2SKip Macy 
11582568ee67SRoger Pau Monné 		id = xn_rxidx(req_prod);
115989e0f4d2SKip Macy 
116096375eacSRoger Pau Monné 		KASSERT(rxq->mbufs[id] == NULL, ("non-NULL xn_rx_chain"));
11612568ee67SRoger Pau Monné 		rxq->mbufs[id] = m;
116289e0f4d2SKip Macy 
116396375eacSRoger Pau Monné 		ref = gnttab_claim_grant_reference(&rxq->gref_head);
1164ff662b5cSJustin T. Gibbs 		KASSERT(ref != GNTTAB_LIST_END,
1165ff662b5cSJustin T. Gibbs 		    ("reserved grant references exhuasted"));
116696375eacSRoger Pau Monné 		rxq->grant_ref[id] = ref;
116789e0f4d2SKip Macy 
11682568ee67SRoger Pau Monné 		pfn = atop(vtophys(mtod(m, vm_offset_t)));
11692568ee67SRoger Pau Monné 		req = RING_GET_REQUEST(&rxq->ring, req_prod);
117089e0f4d2SKip Macy 
11712568ee67SRoger Pau Monné 		gnttab_grant_foreign_access_ref(ref,
11722568ee67SRoger Pau Monné 		    xenbus_get_otherend_id(rxq->info->xbdev), pfn, 0);
117389e0f4d2SKip Macy 		req->id = id;
117489e0f4d2SKip Macy 		req->gref = ref;
117589e0f4d2SKip Macy 	}
117689e0f4d2SKip Macy 
11772568ee67SRoger Pau Monné 	rxq->ring.req_prod_pvt = req_prod;
117889e0f4d2SKip Macy 
11792568ee67SRoger Pau Monné 	/* Not enough requests? Try again later. */
11802568ee67SRoger Pau Monné 	if (req_prod - rxq->ring.rsp_cons < NET_RX_SLOTS_MIN) {
1181bf7b50dbSRoger Pau Monné 		callout_reset_curcpu(&rxq->rx_refill, hz/10,
1182bf7b50dbSRoger Pau Monné 		    xn_alloc_rx_buffers_callout, rxq);
11832568ee67SRoger Pau Monné 		return;
11842568ee67SRoger Pau Monné 	}
11852568ee67SRoger Pau Monné 
11862568ee67SRoger Pau Monné 	wmb();		/* barrier so backend seens requests */
11872568ee67SRoger Pau Monné 
118896375eacSRoger Pau Monné 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&rxq->ring, notify);
118989e0f4d2SKip Macy 	if (notify)
119096375eacSRoger Pau Monné 		xen_intr_signal(rxq->xen_intr_handle);
119189e0f4d2SKip Macy }
119289e0f4d2SKip Macy 
11932568ee67SRoger Pau Monné static void xn_alloc_rx_buffers_callout(void *arg)
11942568ee67SRoger Pau Monné {
11952568ee67SRoger Pau Monné 	struct netfront_rxq *rxq;
11962568ee67SRoger Pau Monné 
11972568ee67SRoger Pau Monné 	rxq = (struct netfront_rxq *)arg;
11982568ee67SRoger Pau Monné 	XN_RX_LOCK(rxq);
11992568ee67SRoger Pau Monné 	xn_alloc_rx_buffers(rxq);
12002568ee67SRoger Pau Monné 	XN_RX_UNLOCK(rxq);
12012568ee67SRoger Pau Monné }
12022568ee67SRoger Pau Monné 
120389e0f4d2SKip Macy static void
120496375eacSRoger Pau Monné xn_release_rx_bufs(struct netfront_rxq *rxq)
120596375eacSRoger Pau Monné {
120696375eacSRoger Pau Monné 	int i,  ref;
120796375eacSRoger Pau Monné 	struct mbuf *m;
120896375eacSRoger Pau Monné 
120996375eacSRoger Pau Monné 	for (i = 0; i < NET_RX_RING_SIZE; i++) {
121096375eacSRoger Pau Monné 		m = rxq->mbufs[i];
121196375eacSRoger Pau Monné 
121296375eacSRoger Pau Monné 		if (m == NULL)
121396375eacSRoger Pau Monné 			continue;
121496375eacSRoger Pau Monné 
121596375eacSRoger Pau Monné 		ref = rxq->grant_ref[i];
121696375eacSRoger Pau Monné 		if (ref == GRANT_REF_INVALID)
121796375eacSRoger Pau Monné 			continue;
121896375eacSRoger Pau Monné 
121996375eacSRoger Pau Monné 		gnttab_end_foreign_access_ref(ref);
122096375eacSRoger Pau Monné 		gnttab_release_grant_reference(&rxq->gref_head, ref);
122196375eacSRoger Pau Monné 		rxq->mbufs[i] = NULL;
122296375eacSRoger Pau Monné 		rxq->grant_ref[i] = GRANT_REF_INVALID;
122396375eacSRoger Pau Monné 		m_freem(m);
122496375eacSRoger Pau Monné 	}
122596375eacSRoger Pau Monné }
122696375eacSRoger Pau Monné 
122796375eacSRoger Pau Monné static void
122896375eacSRoger Pau Monné xn_rxeof(struct netfront_rxq *rxq)
122989e0f4d2SKip Macy {
123002f3b17fSJustin Hibbits 	if_t ifp;
123196375eacSRoger Pau Monné 	struct netfront_info *np = rxq->info;
12323778878dSRoger Pau Monné #if (defined(INET) || defined(INET6))
123396375eacSRoger Pau Monné 	struct lro_ctrl *lro = &rxq->lro;
12343778878dSRoger Pau Monné #endif
123589e0f4d2SKip Macy 	struct netfront_rx_info rinfo;
123689e0f4d2SKip Macy 	struct netif_rx_response *rx = &rinfo.rx;
123789e0f4d2SKip Macy 	struct netif_extra_info *extras = rinfo.extras;
123889e0f4d2SKip Macy 	RING_IDX i, rp;
123989e0f4d2SKip Macy 	struct mbuf *m;
124096375eacSRoger Pau Monné 	struct mbufq mbufq_rxq, mbufq_errq;
1241d0f3a8b9SRoger Pau Monné 	int err, work_to_do;
124289e0f4d2SKip Macy 
124396375eacSRoger Pau Monné 	XN_RX_LOCK_ASSERT(rxq);
1244bf319173SRoger Pau Monné 
124589e0f4d2SKip Macy 	if (!netfront_carrier_ok(np))
124689e0f4d2SKip Macy 		return;
124789e0f4d2SKip Macy 
1248c578b6acSGleb Smirnoff 	/* XXX: there should be some sane limit. */
124996375eacSRoger Pau Monné 	mbufq_init(&mbufq_errq, INT_MAX);
125096375eacSRoger Pau Monné 	mbufq_init(&mbufq_rxq, INT_MAX);
125189e0f4d2SKip Macy 
125289e0f4d2SKip Macy 	ifp = np->xn_ifp;
125389e0f4d2SKip Macy 
1254bf319173SRoger Pau Monné 	do {
125596375eacSRoger Pau Monné 		rp = rxq->ring.sring->rsp_prod;
125689e0f4d2SKip Macy 		rmb();	/* Ensure we see queued responses up to 'rp'. */
125789e0f4d2SKip Macy 
125896375eacSRoger Pau Monné 		i = rxq->ring.rsp_cons;
125989e0f4d2SKip Macy 		while ((i != rp)) {
126096375eacSRoger Pau Monné 			memcpy(rx, RING_GET_RESPONSE(&rxq->ring, i), sizeof(*rx));
126189e0f4d2SKip Macy 			memset(extras, 0, sizeof(rinfo.extras));
126289e0f4d2SKip Macy 
126383b92f6eSKip Macy 			m = NULL;
126496375eacSRoger Pau Monné 			err = xn_get_responses(rxq, &rinfo, rp, &i, &m);
126589e0f4d2SKip Macy 
126676acc41fSJustin T. Gibbs 			if (__predict_false(err)) {
126783b92f6eSKip Macy 				if (m)
126896375eacSRoger Pau Monné 					(void )mbufq_enqueue(&mbufq_errq, m);
1269b2fd6999SRoger Pau Monné 				if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
127089e0f4d2SKip Macy 				continue;
127189e0f4d2SKip Macy 			}
127289e0f4d2SKip Macy 
127389e0f4d2SKip Macy 			m->m_pkthdr.rcvif = ifp;
127489e0f4d2SKip Macy 			if (rx->flags & NETRXF_data_validated) {
127589e0f4d2SKip Macy 				/*
1276a81683c3SRoger Pau Monné 				 * According to mbuf(9) the correct way to tell
1277a81683c3SRoger Pau Monné 				 * the stack that the checksum of an inbound
1278a81683c3SRoger Pau Monné 				 * packet is correct, without it actually being
1279a81683c3SRoger Pau Monné 				 * present (because the underlying interface
1280a81683c3SRoger Pau Monné 				 * doesn't provide it), is to set the
1281a81683c3SRoger Pau Monné 				 * CSUM_DATA_VALID and CSUM_PSEUDO_HDR flags,
1282a81683c3SRoger Pau Monné 				 * and the csum_data field to 0xffff.
128389e0f4d2SKip Macy 				 */
1284a81683c3SRoger Pau Monné 				m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID
128589e0f4d2SKip Macy 				    | CSUM_PSEUDO_HDR);
128689e0f4d2SKip Macy 				m->m_pkthdr.csum_data = 0xffff;
128789e0f4d2SKip Macy 			}
1288d9a66b6dSRoger Pau Monné 			if ((rx->flags & NETRXF_extra_info) != 0 &&
1289d9a66b6dSRoger Pau Monné 			    (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type ==
1290d9a66b6dSRoger Pau Monné 			    XEN_NETIF_EXTRA_TYPE_GSO)) {
1291d9a66b6dSRoger Pau Monné 				m->m_pkthdr.tso_segsz =
1292d9a66b6dSRoger Pau Monné 				extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].u.gso.size;
1293d9a66b6dSRoger Pau Monné 				m->m_pkthdr.csum_flags |= CSUM_TSO;
1294d9a66b6dSRoger Pau Monné 			}
129589e0f4d2SKip Macy 
129696375eacSRoger Pau Monné 			(void )mbufq_enqueue(&mbufq_rxq, m);
129789e0f4d2SKip Macy 		}
129889e0f4d2SKip Macy 
1299bf319173SRoger Pau Monné 		rxq->ring.rsp_cons = i;
130089e0f4d2SKip Macy 
1301bf319173SRoger Pau Monné 		xn_alloc_rx_buffers(rxq);
1302bf319173SRoger Pau Monné 
1303bf319173SRoger Pau Monné 		RING_FINAL_CHECK_FOR_RESPONSES(&rxq->ring, work_to_do);
1304bf319173SRoger Pau Monné 	} while (work_to_do);
1305bf319173SRoger Pau Monné 
1306bf319173SRoger Pau Monné 	mbufq_drain(&mbufq_errq);
130789e0f4d2SKip Macy 	/*
130889e0f4d2SKip Macy 	 * Process all the mbufs after the remapping is complete.
130989e0f4d2SKip Macy 	 * Break the mbuf chain first though.
131089e0f4d2SKip Macy 	 */
131196375eacSRoger Pau Monné 	while ((m = mbufq_dequeue(&mbufq_rxq)) != NULL) {
1312c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
131308c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6))
131412678024SDoug Rabson 		/* Use LRO if possible */
131502f3b17fSJustin Hibbits 		if ((if_getcapenable(ifp) & IFCAP_LRO) == 0 ||
131612678024SDoug Rabson 		    lro->lro_cnt == 0 || tcp_lro_rx(lro, m, 0)) {
131712678024SDoug Rabson 			/*
131812678024SDoug Rabson 			 * If LRO fails, pass up to the stack
131912678024SDoug Rabson 			 * directly.
132012678024SDoug Rabson 			 */
132102f3b17fSJustin Hibbits 			if_input(ifp, m);
132212678024SDoug Rabson 		}
132312678024SDoug Rabson #else
132402f3b17fSJustin Hibbits 		if_input(ifp, m);
132512678024SDoug Rabson #endif
132689e0f4d2SKip Macy 	}
132789e0f4d2SKip Macy 
132808c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6))
132912678024SDoug Rabson 	/*
133012678024SDoug Rabson 	 * Flush any outstanding LRO work
133112678024SDoug Rabson 	 */
13326dd38b87SSepherosa Ziehau 	tcp_lro_flush_all(lro);
133312678024SDoug Rabson #endif
133489e0f4d2SKip Macy }
133589e0f4d2SKip Macy 
133689e0f4d2SKip Macy static void
133796375eacSRoger Pau Monné xn_txeof(struct netfront_txq *txq)
133889e0f4d2SKip Macy {
133989e0f4d2SKip Macy 	RING_IDX i, prod;
134089e0f4d2SKip Macy 	unsigned short id;
134102f3b17fSJustin Hibbits 	if_t ifp;
134212678024SDoug Rabson 	netif_tx_response_t *txr;
134389e0f4d2SKip Macy 	struct mbuf *m;
134496375eacSRoger Pau Monné 	struct netfront_info *np = txq->info;
134589e0f4d2SKip Macy 
134696375eacSRoger Pau Monné 	XN_TX_LOCK_ASSERT(txq);
134789e0f4d2SKip Macy 
134889e0f4d2SKip Macy 	if (!netfront_carrier_ok(np))
134989e0f4d2SKip Macy 		return;
135089e0f4d2SKip Macy 
135189e0f4d2SKip Macy 	ifp = np->xn_ifp;
135289e0f4d2SKip Macy 
135389e0f4d2SKip Macy 	do {
135496375eacSRoger Pau Monné 		prod = txq->ring.sring->rsp_prod;
135589e0f4d2SKip Macy 		rmb(); /* Ensure we see responses up to 'rp'. */
135689e0f4d2SKip Macy 
135796375eacSRoger Pau Monné 		for (i = txq->ring.rsp_cons; i != prod; i++) {
135896375eacSRoger Pau Monné 			txr = RING_GET_RESPONSE(&txq->ring, i);
135912678024SDoug Rabson 			if (txr->status == NETIF_RSP_NULL)
136012678024SDoug Rabson 				continue;
136112678024SDoug Rabson 
1362931eeffaSKenneth D. Merry 			if (txr->status != NETIF_RSP_OKAY) {
1363931eeffaSKenneth D. Merry 				printf("%s: WARNING: response is %d!\n",
1364931eeffaSKenneth D. Merry 				       __func__, txr->status);
1365931eeffaSKenneth D. Merry 			}
136612678024SDoug Rabson 			id = txr->id;
136796375eacSRoger Pau Monné 			m = txq->mbufs[id];
136896375eacSRoger Pau Monné 			KASSERT(m != NULL, ("mbuf not found in chain"));
1369931eeffaSKenneth D. Merry 			KASSERT((uintptr_t)m > NET_TX_RING_SIZE,
1370931eeffaSKenneth D. Merry 				("mbuf already on the free list, but we're "
1371931eeffaSKenneth D. Merry 				"trying to free it again!"));
13722d8fae98SAdrian Chadd 			M_ASSERTVALID(m);
137389e0f4d2SKip Macy 
137476acc41fSJustin T. Gibbs 			if (__predict_false(gnttab_query_foreign_access(
137596375eacSRoger Pau Monné 			    txq->grant_ref[id]) != 0)) {
13766f9767acSMarius Strobl 				panic("%s: grant id %u still in use by the "
13776f9767acSMarius Strobl 				    "backend", __func__, id);
137889e0f4d2SKip Macy 			}
137996375eacSRoger Pau Monné 			gnttab_end_foreign_access_ref(txq->grant_ref[id]);
138089e0f4d2SKip Macy 			gnttab_release_grant_reference(
138196375eacSRoger Pau Monné 				&txq->gref_head, txq->grant_ref[id]);
138296375eacSRoger Pau Monné 			txq->grant_ref[id] = GRANT_REF_INVALID;
138389e0f4d2SKip Macy 
138496375eacSRoger Pau Monné 			txq->mbufs[id] = NULL;
138596375eacSRoger Pau Monné 			add_id_to_freelist(txq->mbufs, id);
138696375eacSRoger Pau Monné 			txq->mbufs_cnt--;
1387dabb3db7SRoger Pau Monné 			mbuf_release(m);
138896375eacSRoger Pau Monné 			/* Only mark the txq active if we've freed up at least one slot to try */
138902f3b17fSJustin Hibbits 			if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
139089e0f4d2SKip Macy 		}
139196375eacSRoger Pau Monné 		txq->ring.rsp_cons = prod;
139289e0f4d2SKip Macy 
139389e0f4d2SKip Macy 		/*
139489e0f4d2SKip Macy 		 * Set a new event, then check for race with update of
139589e0f4d2SKip Macy 		 * tx_cons. Note that it is essential to schedule a
139689e0f4d2SKip Macy 		 * callback, no matter how few buffers are pending. Even if
139789e0f4d2SKip Macy 		 * there is space in the transmit ring, higher layers may
139889e0f4d2SKip Macy 		 * be blocked because too much data is outstanding: in such
139989e0f4d2SKip Macy 		 * cases notification from Xen is likely to be the only kick
140089e0f4d2SKip Macy 		 * that we'll get.
140189e0f4d2SKip Macy 		 */
140296375eacSRoger Pau Monné 		txq->ring.sring->rsp_event =
140396375eacSRoger Pau Monné 		    prod + ((txq->ring.sring->req_prod - prod) >> 1) + 1;
140489e0f4d2SKip Macy 
140589e0f4d2SKip Macy 		mb();
140696375eacSRoger Pau Monné 	} while (prod != txq->ring.sring->rsp_prod);
140789e0f4d2SKip Macy 
140896375eacSRoger Pau Monné 	if (txq->full &&
140996375eacSRoger Pau Monné 	    ((txq->ring.sring->req_prod - prod) < NET_TX_RING_SIZE)) {
141096375eacSRoger Pau Monné 		txq->full = false;
1411da695b05SRoger Pau Monné 		xn_txq_start(txq);
141289e0f4d2SKip Macy 	}
141389e0f4d2SKip Macy }
141489e0f4d2SKip Macy 
141589e0f4d2SKip Macy static void
141696375eacSRoger Pau Monné xn_intr(void *xsc)
141796375eacSRoger Pau Monné {
141896375eacSRoger Pau Monné 	struct netfront_txq *txq = xsc;
141996375eacSRoger Pau Monné 	struct netfront_info *np = txq->info;
142096375eacSRoger Pau Monné 	struct netfront_rxq *rxq = &np->rxq[txq->id];
142196375eacSRoger Pau Monné 
142296375eacSRoger Pau Monné 	/* kick both tx and rx */
142396375eacSRoger Pau Monné 	xn_rxq_intr(rxq);
142496375eacSRoger Pau Monné 	xn_txq_intr(txq);
142596375eacSRoger Pau Monné }
142696375eacSRoger Pau Monné 
142796375eacSRoger Pau Monné static void
142896375eacSRoger Pau Monné xn_move_rx_slot(struct netfront_rxq *rxq, struct mbuf *m,
142996375eacSRoger Pau Monné     grant_ref_t ref)
143096375eacSRoger Pau Monné {
143196375eacSRoger Pau Monné 	int new = xn_rxidx(rxq->ring.req_prod_pvt);
143296375eacSRoger Pau Monné 
143396375eacSRoger Pau Monné 	KASSERT(rxq->mbufs[new] == NULL, ("mbufs != NULL"));
143496375eacSRoger Pau Monné 	rxq->mbufs[new] = m;
143596375eacSRoger Pau Monné 	rxq->grant_ref[new] = ref;
143696375eacSRoger Pau Monné 	RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->id = new;
143796375eacSRoger Pau Monné 	RING_GET_REQUEST(&rxq->ring, rxq->ring.req_prod_pvt)->gref = ref;
143896375eacSRoger Pau Monné 	rxq->ring.req_prod_pvt++;
143996375eacSRoger Pau Monné }
144096375eacSRoger Pau Monné 
144196375eacSRoger Pau Monné static int
144296375eacSRoger Pau Monné xn_get_extras(struct netfront_rxq *rxq,
1443931eeffaSKenneth D. Merry     struct netif_extra_info *extras, RING_IDX rp, RING_IDX *cons)
144489e0f4d2SKip Macy {
144589e0f4d2SKip Macy 	struct netif_extra_info *extra;
144689e0f4d2SKip Macy 
144789e0f4d2SKip Macy 	int err = 0;
144889e0f4d2SKip Macy 
144989e0f4d2SKip Macy 	do {
145089e0f4d2SKip Macy 		struct mbuf *m;
145189e0f4d2SKip Macy 		grant_ref_t ref;
145289e0f4d2SKip Macy 
145376acc41fSJustin T. Gibbs 		if (__predict_false(*cons + 1 == rp)) {
1454931eeffaSKenneth D. Merry 			err = EINVAL;
145589e0f4d2SKip Macy 			break;
145689e0f4d2SKip Macy 		}
145789e0f4d2SKip Macy 
145889e0f4d2SKip Macy 		extra = (struct netif_extra_info *)
145996375eacSRoger Pau Monné 		RING_GET_RESPONSE(&rxq->ring, ++(*cons));
146089e0f4d2SKip Macy 
146176acc41fSJustin T. Gibbs 		if (__predict_false(!extra->type ||
146289e0f4d2SKip Macy 			extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
1463931eeffaSKenneth D. Merry 			err = EINVAL;
146489e0f4d2SKip Macy 		} else {
146589e0f4d2SKip Macy 			memcpy(&extras[extra->type - 1], extra, sizeof(*extra));
146689e0f4d2SKip Macy 		}
146789e0f4d2SKip Macy 
146896375eacSRoger Pau Monné 		m = xn_get_rx_mbuf(rxq, *cons);
146996375eacSRoger Pau Monné 		ref = xn_get_rx_ref(rxq,  *cons);
147096375eacSRoger Pau Monné 		xn_move_rx_slot(rxq, m, ref);
147189e0f4d2SKip Macy 	} while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
147289e0f4d2SKip Macy 
147389e0f4d2SKip Macy 	return err;
147489e0f4d2SKip Macy }
147589e0f4d2SKip Macy 
147689e0f4d2SKip Macy static int
147796375eacSRoger Pau Monné xn_get_responses(struct netfront_rxq *rxq,
1478931eeffaSKenneth D. Merry     struct netfront_rx_info *rinfo, RING_IDX rp, RING_IDX *cons,
1479d0f3a8b9SRoger Pau Monné     struct mbuf  **list)
148089e0f4d2SKip Macy {
148189e0f4d2SKip Macy 	struct netif_rx_response *rx = &rinfo->rx;
148289e0f4d2SKip Macy 	struct netif_extra_info *extras = rinfo->extras;
148383b92f6eSKip Macy 	struct mbuf *m, *m0, *m_prev;
148496375eacSRoger Pau Monné 	grant_ref_t ref = xn_get_rx_ref(rxq, *cons);
148589e0f4d2SKip Macy 	int frags = 1;
148689e0f4d2SKip Macy 	int err = 0;
1487e7236a7dSMateusz Guzik 	u_long ret __diagused;
148889e0f4d2SKip Macy 
148996375eacSRoger Pau Monné 	m0 = m = m_prev = xn_get_rx_mbuf(rxq, *cons);
149083b92f6eSKip Macy 
149189e0f4d2SKip Macy 	if (rx->flags & NETRXF_extra_info) {
149296375eacSRoger Pau Monné 		err = xn_get_extras(rxq, extras, rp, cons);
149389e0f4d2SKip Macy 	}
149489e0f4d2SKip Macy 
149583b92f6eSKip Macy 	if (m0 != NULL) {
149683b92f6eSKip Macy 		m0->m_pkthdr.len = 0;
149783b92f6eSKip Macy 		m0->m_next = NULL;
149883b92f6eSKip Macy 	}
149983b92f6eSKip Macy 
150089e0f4d2SKip Macy 	for (;;) {
150183b92f6eSKip Macy #if 0
1502227ca257SKip Macy 		DPRINTK("rx->status=%hd rx->offset=%hu frags=%u\n",
150383b92f6eSKip Macy 			rx->status, rx->offset, frags);
150483b92f6eSKip Macy #endif
150576acc41fSJustin T. Gibbs 		if (__predict_false(rx->status < 0 ||
150689e0f4d2SKip Macy 			rx->offset + rx->status > PAGE_SIZE)) {
150796375eacSRoger Pau Monné 			xn_move_rx_slot(rxq, m, ref);
1508931eeffaSKenneth D. Merry 			if (m0 == m)
1509931eeffaSKenneth D. Merry 				m0 = NULL;
1510931eeffaSKenneth D. Merry 			m = NULL;
1511931eeffaSKenneth D. Merry 			err = EINVAL;
1512931eeffaSKenneth D. Merry 			goto next_skip_queue;
151389e0f4d2SKip Macy 		}
151489e0f4d2SKip Macy 
151589e0f4d2SKip Macy 		/*
151689e0f4d2SKip Macy 		 * This definitely indicates a bug, either in this driver or in
151789e0f4d2SKip Macy 		 * the backend driver. In future this should flag the bad
151889e0f4d2SKip Macy 		 * situation to the system controller to reboot the backed.
151989e0f4d2SKip Macy 		 */
1520ff662b5cSJustin T. Gibbs 		if (ref == GRANT_REF_INVALID) {
1521ff662b5cSJustin T. Gibbs 			printf("%s: Bad rx response id %d.\n", __func__, rx->id);
1522931eeffaSKenneth D. Merry 			err = EINVAL;
152389e0f4d2SKip Macy 			goto next;
152489e0f4d2SKip Macy 		}
152589e0f4d2SKip Macy 
1526920ba15bSKip Macy 		ret = gnttab_end_foreign_access_ref(ref);
1527d0f3a8b9SRoger Pau Monné 		KASSERT(ret, ("Unable to end access to grant references"));
152889e0f4d2SKip Macy 
152996375eacSRoger Pau Monné 		gnttab_release_grant_reference(&rxq->gref_head, ref);
153089e0f4d2SKip Macy 
153189e0f4d2SKip Macy next:
15323a539122SAdrian Chadd 		if (m == NULL)
15333a539122SAdrian Chadd 			break;
15343a539122SAdrian Chadd 
153583b92f6eSKip Macy 		m->m_len = rx->status;
153683b92f6eSKip Macy 		m->m_data += rx->offset;
153783b92f6eSKip Macy 		m0->m_pkthdr.len += rx->status;
153883b92f6eSKip Macy 
1539931eeffaSKenneth D. Merry next_skip_queue:
154089e0f4d2SKip Macy 		if (!(rx->flags & NETRXF_more_data))
154189e0f4d2SKip Macy 			break;
154289e0f4d2SKip Macy 
1543931eeffaSKenneth D. Merry 		if (*cons + frags == rp) {
154489e0f4d2SKip Macy 			if (net_ratelimit())
154589e0f4d2SKip Macy 				WPRINTK("Need more frags\n");
1546931eeffaSKenneth D. Merry 			err = ENOENT;
1547931eeffaSKenneth D. Merry 			printf("%s: cons %u frags %u rp %u, not enough frags\n",
1548931eeffaSKenneth D. Merry 			       __func__, *cons, frags, rp);
154989e0f4d2SKip Macy 			break;
155089e0f4d2SKip Macy 		}
1551931eeffaSKenneth D. Merry 		/*
1552931eeffaSKenneth D. Merry 		 * Note that m can be NULL, if rx->status < 0 or if
1553931eeffaSKenneth D. Merry 		 * rx->offset + rx->status > PAGE_SIZE above.
1554931eeffaSKenneth D. Merry 		 */
155583b92f6eSKip Macy 		m_prev = m;
155689e0f4d2SKip Macy 
155796375eacSRoger Pau Monné 		rx = RING_GET_RESPONSE(&rxq->ring, *cons + frags);
155896375eacSRoger Pau Monné 		m = xn_get_rx_mbuf(rxq, *cons + frags);
155983b92f6eSKip Macy 
1560931eeffaSKenneth D. Merry 		/*
1561931eeffaSKenneth D. Merry 		 * m_prev == NULL can happen if rx->status < 0 or if
1562931eeffaSKenneth D. Merry 		 * rx->offset + * rx->status > PAGE_SIZE above.
1563931eeffaSKenneth D. Merry 		 */
1564931eeffaSKenneth D. Merry 		if (m_prev != NULL)
156583b92f6eSKip Macy 			m_prev->m_next = m;
1566931eeffaSKenneth D. Merry 
1567931eeffaSKenneth D. Merry 		/*
1568931eeffaSKenneth D. Merry 		 * m0 can be NULL if rx->status < 0 or if * rx->offset +
1569931eeffaSKenneth D. Merry 		 * rx->status > PAGE_SIZE above.
1570931eeffaSKenneth D. Merry 		 */
1571931eeffaSKenneth D. Merry 		if (m0 == NULL)
1572931eeffaSKenneth D. Merry 			m0 = m;
157383b92f6eSKip Macy 		m->m_next = NULL;
157496375eacSRoger Pau Monné 		ref = xn_get_rx_ref(rxq, *cons + frags);
157589e0f4d2SKip Macy 		frags++;
157689e0f4d2SKip Macy 	}
157783b92f6eSKip Macy 	*list = m0;
1578931eeffaSKenneth D. Merry 	*cons += frags;
157989e0f4d2SKip Macy 
15808577146eSJustin T. Gibbs 	return (err);
158189e0f4d2SKip Macy }
158289e0f4d2SKip Macy 
1583931eeffaSKenneth D. Merry /**
1584931eeffaSKenneth D. Merry  * Given an mbuf chain, make sure we have enough room and then push
1585931eeffaSKenneth D. Merry  * it onto the transmit ring.
1586931eeffaSKenneth D. Merry  */
1587931eeffaSKenneth D. Merry static int
158896375eacSRoger Pau Monné xn_assemble_tx_request(struct netfront_txq *txq, struct mbuf *m_head)
1589931eeffaSKenneth D. Merry {
159096375eacSRoger Pau Monné 	struct netfront_info *np = txq->info;
159102f3b17fSJustin Hibbits 	if_t ifp = np->xn_ifp;
1592dabb3db7SRoger Pau Monné 	int otherend_id, error, nfrags;
1593dabb3db7SRoger Pau Monné 	bus_dma_segment_t *segs = txq->segs;
1594dabb3db7SRoger Pau Monné 	struct mbuf_xennet *tag;
1595dabb3db7SRoger Pau Monné 	bus_dmamap_t map;
1596dabb3db7SRoger Pau Monné 	unsigned int i;
1597931eeffaSKenneth D. Merry 
1598dabb3db7SRoger Pau Monné 	KASSERT(!SLIST_EMPTY(&txq->tags), ("no tags available"));
1599dabb3db7SRoger Pau Monné 	tag = SLIST_FIRST(&txq->tags);
1600dabb3db7SRoger Pau Monné 	SLIST_REMOVE_HEAD(&txq->tags, next);
1601dabb3db7SRoger Pau Monné 	KASSERT(tag->count == 0, ("tag already in-use"));
1602dabb3db7SRoger Pau Monné 	map = tag->dma_map;
1603dabb3db7SRoger Pau Monné 	error = bus_dmamap_load_mbuf_sg(np->dma_tag, map, m_head, segs,
1604dabb3db7SRoger Pau Monné 	    &nfrags, 0);
1605dabb3db7SRoger Pau Monné 	if (error == EFBIG || nfrags > np->maxfrags) {
1606dabb3db7SRoger Pau Monné 		struct mbuf *m;
1607931eeffaSKenneth D. Merry 
1608dabb3db7SRoger Pau Monné 		bus_dmamap_unload(np->dma_tag, map);
1609c6499eccSGleb Smirnoff 		m = m_defrag(m_head, M_NOWAIT);
161012678024SDoug Rabson 		if (!m) {
1611931eeffaSKenneth D. Merry 			/*
1612931eeffaSKenneth D. Merry 			 * Defrag failed, so free the mbuf and
1613931eeffaSKenneth D. Merry 			 * therefore drop the packet.
1614931eeffaSKenneth D. Merry 			 */
1615dabb3db7SRoger Pau Monné 			SLIST_INSERT_HEAD(&txq->tags, tag, next);
161612678024SDoug Rabson 			m_freem(m_head);
1617931eeffaSKenneth D. Merry 			return (EMSGSIZE);
161812678024SDoug Rabson 		}
161912678024SDoug Rabson 		m_head = m;
1620dabb3db7SRoger Pau Monné 		error = bus_dmamap_load_mbuf_sg(np->dma_tag, map, m_head, segs,
1621dabb3db7SRoger Pau Monné 		    &nfrags, 0);
1622dabb3db7SRoger Pau Monné 		if (error != 0 || nfrags > np->maxfrags) {
1623dabb3db7SRoger Pau Monné 			bus_dmamap_unload(np->dma_tag, map);
1624dabb3db7SRoger Pau Monné 			SLIST_INSERT_HEAD(&txq->tags, tag, next);
1625dabb3db7SRoger Pau Monné 			m_freem(m_head);
1626dabb3db7SRoger Pau Monné 			return (error ?: EFBIG);
1627dabb3db7SRoger Pau Monné 		}
1628dabb3db7SRoger Pau Monné 	} else if (error != 0) {
1629dabb3db7SRoger Pau Monné 		SLIST_INSERT_HEAD(&txq->tags, tag, next);
1630dabb3db7SRoger Pau Monné 		m_freem(m_head);
1631dabb3db7SRoger Pau Monné 		return (error);
163212678024SDoug Rabson 	}
163389e0f4d2SKip Macy 
1634931eeffaSKenneth D. Merry 	/**
1635931eeffaSKenneth D. Merry 	 * The FreeBSD TCP stack, with TSO enabled, can produce a chain
1636931eeffaSKenneth D. Merry 	 * of mbufs longer than Linux can handle.  Make sure we don't
1637931eeffaSKenneth D. Merry 	 * pass a too-long chain over to the other side by dropping the
1638931eeffaSKenneth D. Merry 	 * packet.  It doesn't look like there is currently a way to
1639931eeffaSKenneth D. Merry 	 * tell the TCP stack to generate a shorter chain of packets.
16403fb28bbbSAdrian Chadd 	 */
1641931eeffaSKenneth D. Merry 	if (nfrags > MAX_TX_REQ_FRAGS) {
1642ff662b5cSJustin T. Gibbs #ifdef DEBUG
1643ff662b5cSJustin T. Gibbs 		printf("%s: nfrags %d > MAX_TX_REQ_FRAGS %d, netback "
1644ff662b5cSJustin T. Gibbs 		       "won't be able to handle it, dropping\n",
1645ff662b5cSJustin T. Gibbs 		       __func__, nfrags, MAX_TX_REQ_FRAGS);
1646ff662b5cSJustin T. Gibbs #endif
1647dabb3db7SRoger Pau Monné 		SLIST_INSERT_HEAD(&txq->tags, tag, next);
1648dabb3db7SRoger Pau Monné 		bus_dmamap_unload(np->dma_tag, map);
1649931eeffaSKenneth D. Merry 		m_freem(m_head);
1650931eeffaSKenneth D. Merry 		return (EMSGSIZE);
1651a4ec37f5SAdrian Chadd 	}
1652a4ec37f5SAdrian Chadd 
16533fb28bbbSAdrian Chadd 	/*
1654931eeffaSKenneth D. Merry 	 * This check should be redundant.  We've already verified that we
1655931eeffaSKenneth D. Merry 	 * have enough slots in the ring to handle a packet of maximum
1656931eeffaSKenneth D. Merry 	 * size, and that our packet is less than the maximum size.  Keep
1657931eeffaSKenneth D. Merry 	 * it in here as an assert for now just to make certain that
165896375eacSRoger Pau Monné 	 * chain_cnt is accurate.
16593fb28bbbSAdrian Chadd 	 */
166096375eacSRoger Pau Monné 	KASSERT((txq->mbufs_cnt + nfrags) <= NET_TX_RING_SIZE,
166196375eacSRoger Pau Monné 		("%s: chain_cnt (%d) + nfrags (%d) > NET_TX_RING_SIZE "
166296375eacSRoger Pau Monné 		 "(%d)!", __func__, (int) txq->mbufs_cnt,
1663931eeffaSKenneth D. Merry                     (int) nfrags, (int) NET_TX_RING_SIZE));
1664a4ec37f5SAdrian Chadd 
166589e0f4d2SKip Macy 	/*
166689e0f4d2SKip Macy 	 * Start packing the mbufs in this chain into
166789e0f4d2SKip Macy 	 * the fragment pointers. Stop when we run out
166889e0f4d2SKip Macy 	 * of fragments or hit the end of the mbuf chain.
166989e0f4d2SKip Macy 	 */
167096375eacSRoger Pau Monné 	otherend_id = xenbus_get_otherend_id(np->xbdev);
1671dabb3db7SRoger Pau Monné 	m_tag_prepend(m_head, &tag->tag);
1672dabb3db7SRoger Pau Monné 	for (i = 0; i < nfrags; i++) {
1673931eeffaSKenneth D. Merry 		netif_tx_request_t *tx;
1674931eeffaSKenneth D. Merry 		uintptr_t id;
1675931eeffaSKenneth D. Merry 		grant_ref_t ref;
1676931eeffaSKenneth D. Merry 		u_long mfn; /* XXX Wrong type? */
1677931eeffaSKenneth D. Merry 
167896375eacSRoger Pau Monné 		tx = RING_GET_REQUEST(&txq->ring, txq->ring.req_prod_pvt);
167996375eacSRoger Pau Monné 		id = get_id_from_freelist(txq->mbufs);
1680a4ec37f5SAdrian Chadd 		if (id == 0)
16816f9767acSMarius Strobl 			panic("%s: was allocated the freelist head!\n",
16826f9767acSMarius Strobl 			    __func__);
168396375eacSRoger Pau Monné 		txq->mbufs_cnt++;
168496375eacSRoger Pau Monné 		if (txq->mbufs_cnt > NET_TX_RING_SIZE)
16856f9767acSMarius Strobl 			panic("%s: tx_chain_cnt must be <= NET_TX_RING_SIZE\n",
16866f9767acSMarius Strobl 			    __func__);
1687dabb3db7SRoger Pau Monné 		mbuf_grab(m_head);
1688dabb3db7SRoger Pau Monné 		txq->mbufs[id] = m_head;
168989e0f4d2SKip Macy 		tx->id = id;
169096375eacSRoger Pau Monné 		ref = gnttab_claim_grant_reference(&txq->gref_head);
169189e0f4d2SKip Macy 		KASSERT((short)ref >= 0, ("Negative ref"));
1692dabb3db7SRoger Pau Monné 		mfn = atop(segs[i].ds_addr);
169323dc5621SKip Macy 		gnttab_grant_foreign_access_ref(ref, otherend_id,
169489e0f4d2SKip Macy 		    mfn, GNTMAP_readonly);
169596375eacSRoger Pau Monné 		tx->gref = txq->grant_ref[id] = ref;
1696dabb3db7SRoger Pau Monné 		tx->offset = segs[i].ds_addr & PAGE_MASK;
1697dabb3db7SRoger Pau Monné 		KASSERT(tx->offset + segs[i].ds_len <= PAGE_SIZE,
1698dabb3db7SRoger Pau Monné 		    ("mbuf segment crosses a page boundary"));
169989e0f4d2SKip Macy 		tx->flags = 0;
1700dabb3db7SRoger Pau Monné 		if (i == 0) {
170112678024SDoug Rabson 			/*
170212678024SDoug Rabson 			 * The first fragment has the entire packet
170312678024SDoug Rabson 			 * size, subsequent fragments have just the
170412678024SDoug Rabson 			 * fragment size. The backend works out the
170512678024SDoug Rabson 			 * true size of the first fragment by
170612678024SDoug Rabson 			 * subtracting the sizes of the other
170712678024SDoug Rabson 			 * fragments.
170812678024SDoug Rabson 			 */
1709dabb3db7SRoger Pau Monné 			tx->size = m_head->m_pkthdr.len;
171089e0f4d2SKip Macy 
171112678024SDoug Rabson 			/*
1712931eeffaSKenneth D. Merry 			 * The first fragment contains the checksum flags
1713931eeffaSKenneth D. Merry 			 * and is optionally followed by extra data for
1714931eeffaSKenneth D. Merry 			 * TSO etc.
1715931eeffaSKenneth D. Merry 			 */
1716931eeffaSKenneth D. Merry 			/**
1717931eeffaSKenneth D. Merry 			 * CSUM_TSO requires checksum offloading.
1718931eeffaSKenneth D. Merry 			 * Some versions of FreeBSD fail to
1719931eeffaSKenneth D. Merry 			 * set CSUM_TCP in the CSUM_TSO case,
1720931eeffaSKenneth D. Merry 			 * so we have to test for CSUM_TSO
1721931eeffaSKenneth D. Merry 			 * explicitly.
172212678024SDoug Rabson 			 */
1723dabb3db7SRoger Pau Monné 			if (m_head->m_pkthdr.csum_flags
1724931eeffaSKenneth D. Merry 			    & (CSUM_DELAY_DATA | CSUM_TSO)) {
172512678024SDoug Rabson 				tx->flags |= (NETTXF_csum_blank
172612678024SDoug Rabson 				    | NETTXF_data_validated);
172712678024SDoug Rabson 			}
1728dabb3db7SRoger Pau Monné 			if (m_head->m_pkthdr.csum_flags & CSUM_TSO) {
172912678024SDoug Rabson 				struct netif_extra_info *gso =
173012678024SDoug Rabson 					(struct netif_extra_info *)
173196375eacSRoger Pau Monné 					RING_GET_REQUEST(&txq->ring,
173296375eacSRoger Pau Monné 							 ++txq->ring.req_prod_pvt);
173389e0f4d2SKip Macy 
173412678024SDoug Rabson 				tx->flags |= NETTXF_extra_info;
173589e0f4d2SKip Macy 
1736dabb3db7SRoger Pau Monné 				gso->u.gso.size = m_head->m_pkthdr.tso_segsz;
173712678024SDoug Rabson 				gso->u.gso.type =
173812678024SDoug Rabson 					XEN_NETIF_GSO_TYPE_TCPV4;
173912678024SDoug Rabson 				gso->u.gso.pad = 0;
174012678024SDoug Rabson 				gso->u.gso.features = 0;
174112678024SDoug Rabson 
174212678024SDoug Rabson 				gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
174312678024SDoug Rabson 				gso->flags = 0;
174412678024SDoug Rabson 			}
174512678024SDoug Rabson 		} else {
1746dabb3db7SRoger Pau Monné 			tx->size = segs[i].ds_len;
174712678024SDoug Rabson 		}
1748dabb3db7SRoger Pau Monné 		if (i != nfrags - 1)
174912678024SDoug Rabson 			tx->flags |= NETTXF_more_data;
175012678024SDoug Rabson 
175196375eacSRoger Pau Monné 		txq->ring.req_prod_pvt++;
1752931eeffaSKenneth D. Merry 	}
1753dabb3db7SRoger Pau Monné 	bus_dmamap_sync(np->dma_tag, map, BUS_DMASYNC_PREWRITE);
175412678024SDoug Rabson 	BPF_MTAP(ifp, m_head);
175512678024SDoug Rabson 
1756b2fd6999SRoger Pau Monné 	if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1757b2fd6999SRoger Pau Monné 	if_inc_counter(ifp, IFCOUNTER_OBYTES, m_head->m_pkthdr.len);
1758b2fd6999SRoger Pau Monné 	if (m_head->m_flags & M_MCAST)
1759b2fd6999SRoger Pau Monné 		if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
176096375eacSRoger Pau Monné 
1761b2fd6999SRoger Pau Monné 	xn_txeof(txq);
1762931eeffaSKenneth D. Merry 
1763931eeffaSKenneth D. Merry 	return (0);
176489e0f4d2SKip Macy }
176589e0f4d2SKip Macy 
176689e0f4d2SKip Macy /* equivalent of network_open() in Linux */
176789e0f4d2SKip Macy static void
176896375eacSRoger Pau Monné xn_ifinit_locked(struct netfront_info *np)
176989e0f4d2SKip Macy {
177002f3b17fSJustin Hibbits 	if_t ifp;
177196375eacSRoger Pau Monné 	int i;
177296375eacSRoger Pau Monné 	struct netfront_rxq *rxq;
177389e0f4d2SKip Macy 
177496375eacSRoger Pau Monné 	XN_LOCK_ASSERT(np);
177589e0f4d2SKip Macy 
177696375eacSRoger Pau Monné 	ifp = np->xn_ifp;
177789e0f4d2SKip Macy 
177802f3b17fSJustin Hibbits 	if (if_getdrvflags(ifp) & IFF_DRV_RUNNING || !netfront_carrier_ok(np))
177989e0f4d2SKip Macy 		return;
178089e0f4d2SKip Macy 
178196375eacSRoger Pau Monné 	xn_stop(np);
178289e0f4d2SKip Macy 
178396375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
178496375eacSRoger Pau Monné 		rxq = &np->rxq[i];
17852568ee67SRoger Pau Monné 		XN_RX_LOCK(rxq);
178696375eacSRoger Pau Monné 		xn_alloc_rx_buffers(rxq);
178796375eacSRoger Pau Monné 		rxq->ring.sring->rsp_event = rxq->ring.rsp_cons + 1;
17882568ee67SRoger Pau Monné 		if (RING_HAS_UNCONSUMED_RESPONSES(&rxq->ring))
1789da695b05SRoger Pau Monné 			xn_rxeof(rxq);
17902568ee67SRoger Pau Monné 		XN_RX_UNLOCK(rxq);
179196375eacSRoger Pau Monné 	}
179289e0f4d2SKip Macy 
179302f3b17fSJustin Hibbits 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
179402f3b17fSJustin Hibbits 	if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
17950e509842SJustin T. Gibbs 	if_link_state_change(ifp, LINK_STATE_UP);
179689e0f4d2SKip Macy }
179789e0f4d2SKip Macy 
179889e0f4d2SKip Macy static void
179989e0f4d2SKip Macy xn_ifinit(void *xsc)
180089e0f4d2SKip Macy {
180189e0f4d2SKip Macy 	struct netfront_info *sc = xsc;
180289e0f4d2SKip Macy 
180389e0f4d2SKip Macy 	XN_LOCK(sc);
180489e0f4d2SKip Macy 	xn_ifinit_locked(sc);
180589e0f4d2SKip Macy 	XN_UNLOCK(sc);
180689e0f4d2SKip Macy }
180789e0f4d2SKip Macy 
180889e0f4d2SKip Macy static int
180902f3b17fSJustin Hibbits xn_ioctl(if_t ifp, u_long cmd, caddr_t data)
181089e0f4d2SKip Macy {
181102f3b17fSJustin Hibbits 	struct netfront_info *sc = if_getsoftc(ifp);
181289e0f4d2SKip Macy 	struct ifreq *ifr = (struct ifreq *) data;
1813c2d12e5eSRoger Pau Monné 	device_t dev;
1814a0ae8f04SBjoern A. Zeeb #ifdef INET
181589e0f4d2SKip Macy 	struct ifaddr *ifa = (struct ifaddr *)data;
1816a0ae8f04SBjoern A. Zeeb #endif
18173c9d5940SRoger Pau Monné 	int mask, error = 0, reinit;
1818c2d12e5eSRoger Pau Monné 
1819c2d12e5eSRoger Pau Monné 	dev = sc->xbdev;
1820c2d12e5eSRoger Pau Monné 
182189e0f4d2SKip Macy 	switch(cmd) {
182289e0f4d2SKip Macy 	case SIOCSIFADDR:
1823a0ae8f04SBjoern A. Zeeb #ifdef INET
182489e0f4d2SKip Macy 		XN_LOCK(sc);
182589e0f4d2SKip Macy 		if (ifa->ifa_addr->sa_family == AF_INET) {
182602f3b17fSJustin Hibbits 			if_setflagbits(ifp, IFF_UP, 0);
182702f3b17fSJustin Hibbits 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
182889e0f4d2SKip Macy 				xn_ifinit_locked(sc);
182989e0f4d2SKip Macy 			arp_ifinit(ifp, ifa);
183089e0f4d2SKip Macy 			XN_UNLOCK(sc);
183149906218SDoug Rabson 		} else {
183249906218SDoug Rabson 			XN_UNLOCK(sc);
1833a0ae8f04SBjoern A. Zeeb #endif
183449906218SDoug Rabson 			error = ether_ioctl(ifp, cmd, data);
1835a0ae8f04SBjoern A. Zeeb #ifdef INET
183649906218SDoug Rabson 		}
1837a0ae8f04SBjoern A. Zeeb #endif
183889e0f4d2SKip Macy 		break;
183989e0f4d2SKip Macy 	case SIOCSIFMTU:
184002f3b17fSJustin Hibbits 		if (if_getmtu(ifp) == ifr->ifr_mtu)
1841c74415edSColin Percival 			break;
1842c74415edSColin Percival 
184302f3b17fSJustin Hibbits 		if_setmtu(ifp, ifr->ifr_mtu);
184402f3b17fSJustin Hibbits 		if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
184589e0f4d2SKip Macy 		xn_ifinit(sc);
184689e0f4d2SKip Macy 		break;
184789e0f4d2SKip Macy 	case SIOCSIFFLAGS:
184889e0f4d2SKip Macy 		XN_LOCK(sc);
184902f3b17fSJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
185089e0f4d2SKip Macy 			/*
185189e0f4d2SKip Macy 			 * If only the state of the PROMISC flag changed,
185289e0f4d2SKip Macy 			 * then just use the 'set promisc mode' command
185389e0f4d2SKip Macy 			 * instead of reinitializing the entire NIC. Doing
185489e0f4d2SKip Macy 			 * a full re-init means reloading the firmware and
185589e0f4d2SKip Macy 			 * waiting for it to start up, which may take a
185689e0f4d2SKip Macy 			 * second or two.
185789e0f4d2SKip Macy 			 */
185889e0f4d2SKip Macy 			xn_ifinit_locked(sc);
185989e0f4d2SKip Macy 		} else {
186002f3b17fSJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
186189e0f4d2SKip Macy 				xn_stop(sc);
186289e0f4d2SKip Macy 			}
186389e0f4d2SKip Macy 		}
186402f3b17fSJustin Hibbits 		sc->xn_if_flags = if_getflags(ifp);
186589e0f4d2SKip Macy 		XN_UNLOCK(sc);
186689e0f4d2SKip Macy 		break;
186789e0f4d2SKip Macy 	case SIOCSIFCAP:
186802f3b17fSJustin Hibbits 		mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
18693c9d5940SRoger Pau Monné 		reinit = 0;
18703c9d5940SRoger Pau Monné 
187112678024SDoug Rabson 		if (mask & IFCAP_TXCSUM) {
187202f3b17fSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM);
187302f3b17fSJustin Hibbits 			if_togglehwassist(ifp, XN_CSUM_FEATURES);
187412678024SDoug Rabson 		}
187512678024SDoug Rabson 		if (mask & IFCAP_TSO4) {
187602f3b17fSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO4);
187702f3b17fSJustin Hibbits 			if_togglehwassist(ifp, CSUM_TSO);
187812678024SDoug Rabson 		}
187912678024SDoug Rabson 
18803c9d5940SRoger Pau Monné 		if (mask & (IFCAP_RXCSUM | IFCAP_LRO)) {
18813c9d5940SRoger Pau Monné 			/* These Rx features require us to renegotiate. */
18823c9d5940SRoger Pau Monné 			reinit = 1;
18833c9d5940SRoger Pau Monné 
18843c9d5940SRoger Pau Monné 			if (mask & IFCAP_RXCSUM)
188502f3b17fSJustin Hibbits 				if_togglecapenable(ifp, IFCAP_RXCSUM);
18863c9d5940SRoger Pau Monné 			if (mask & IFCAP_LRO)
188702f3b17fSJustin Hibbits 				if_togglecapenable(ifp, IFCAP_LRO);
188812678024SDoug Rabson 		}
18893c9d5940SRoger Pau Monné 
18903c9d5940SRoger Pau Monné 		if (reinit == 0)
18913c9d5940SRoger Pau Monné 			break;
18923c9d5940SRoger Pau Monné 
1893c2d12e5eSRoger Pau Monné 		/*
1894c2d12e5eSRoger Pau Monné 		 * We must reset the interface so the backend picks up the
1895c2d12e5eSRoger Pau Monné 		 * new features.
1896c2d12e5eSRoger Pau Monné 		 */
18973c9d5940SRoger Pau Monné 		device_printf(sc->xbdev,
18983c9d5940SRoger Pau Monné 		    "performing interface reset due to feature change\n");
1899c2d12e5eSRoger Pau Monné 		XN_LOCK(sc);
1900c2d12e5eSRoger Pau Monné 		netfront_carrier_off(sc);
1901c2d12e5eSRoger Pau Monné 		sc->xn_reset = true;
1902c2d12e5eSRoger Pau Monné 		/*
1903c2d12e5eSRoger Pau Monné 		 * NB: the pending packet queue is not flushed, since
1904c2d12e5eSRoger Pau Monné 		 * the interface should still support the old options.
1905c2d12e5eSRoger Pau Monné 		 */
1906c2d12e5eSRoger Pau Monné 		XN_UNLOCK(sc);
1907c2d12e5eSRoger Pau Monné 		/*
1908c2d12e5eSRoger Pau Monné 		 * Delete the xenstore nodes that export features.
1909c2d12e5eSRoger Pau Monné 		 *
1910c2d12e5eSRoger Pau Monné 		 * NB: There's a xenbus state called
1911c2d12e5eSRoger Pau Monné 		 * "XenbusStateReconfiguring", which is what we should set
1912c2d12e5eSRoger Pau Monné 		 * here. Sadly none of the backends know how to handle it,
1913c2d12e5eSRoger Pau Monné 		 * and simply disconnect from the frontend, so we will just
1914c2d12e5eSRoger Pau Monné 		 * switch back to XenbusStateInitialising in order to force
1915c2d12e5eSRoger Pau Monné 		 * a reconnection.
1916c2d12e5eSRoger Pau Monné 		 */
1917c2d12e5eSRoger Pau Monné 		xs_rm(XST_NIL, xenbus_get_node(dev), "feature-gso-tcpv4");
1918c2d12e5eSRoger Pau Monné 		xs_rm(XST_NIL, xenbus_get_node(dev), "feature-no-csum-offload");
1919c2d12e5eSRoger Pau Monné 		xenbus_set_state(dev, XenbusStateClosing);
19203c9d5940SRoger Pau Monné 
19213c9d5940SRoger Pau Monné 		/*
19223c9d5940SRoger Pau Monné 		 * Wait for the frontend to reconnect before returning
19233c9d5940SRoger Pau Monné 		 * from the ioctl. 30s should be more than enough for any
19243c9d5940SRoger Pau Monné 		 * sane backend to reconnect.
19253c9d5940SRoger Pau Monné 		 */
19263c9d5940SRoger Pau Monné 		error = tsleep(sc, 0, "xn_rst", 30*hz);
192789e0f4d2SKip Macy 		break;
192889e0f4d2SKip Macy 	case SIOCADDMULTI:
192989e0f4d2SKip Macy 	case SIOCDELMULTI:
1930ce8df48bSSimon J. Gerraty 		break;
193189e0f4d2SKip Macy 	case SIOCSIFMEDIA:
193289e0f4d2SKip Macy 	case SIOCGIFMEDIA:
19330e509842SJustin T. Gibbs 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
193489e0f4d2SKip Macy 		break;
193589e0f4d2SKip Macy 	default:
193689e0f4d2SKip Macy 		error = ether_ioctl(ifp, cmd, data);
193789e0f4d2SKip Macy 	}
193889e0f4d2SKip Macy 
193989e0f4d2SKip Macy 	return (error);
194089e0f4d2SKip Macy }
194189e0f4d2SKip Macy 
194289e0f4d2SKip Macy static void
194389e0f4d2SKip Macy xn_stop(struct netfront_info *sc)
194489e0f4d2SKip Macy {
194502f3b17fSJustin Hibbits 	if_t ifp;
194689e0f4d2SKip Macy 
194789e0f4d2SKip Macy 	XN_LOCK_ASSERT(sc);
194889e0f4d2SKip Macy 
194989e0f4d2SKip Macy 	ifp = sc->xn_ifp;
195089e0f4d2SKip Macy 
195102f3b17fSJustin Hibbits 	if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
19520e509842SJustin T. Gibbs 	if_link_state_change(ifp, LINK_STATE_DOWN);
195389e0f4d2SKip Macy }
195489e0f4d2SKip Macy 
195596375eacSRoger Pau Monné static void
195696375eacSRoger Pau Monné xn_rebuild_rx_bufs(struct netfront_rxq *rxq)
195789e0f4d2SKip Macy {
195896375eacSRoger Pau Monné 	int requeue_idx, i;
195989e0f4d2SKip Macy 	grant_ref_t ref;
196089e0f4d2SKip Macy 	netif_rx_request_t *req;
196189e0f4d2SKip Macy 
196289e0f4d2SKip Macy 	for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
196389e0f4d2SKip Macy 		struct mbuf *m;
19643a6d1fcfSKip Macy 		u_long pfn;
196589e0f4d2SKip Macy 
196696375eacSRoger Pau Monné 		if (rxq->mbufs[i] == NULL)
196789e0f4d2SKip Macy 			continue;
196889e0f4d2SKip Macy 
196996375eacSRoger Pau Monné 		m = rxq->mbufs[requeue_idx] = xn_get_rx_mbuf(rxq, i);
197096375eacSRoger Pau Monné 		ref = rxq->grant_ref[requeue_idx] = xn_get_rx_ref(rxq, i);
1971931eeffaSKenneth D. Merry 
197296375eacSRoger Pau Monné 		req = RING_GET_REQUEST(&rxq->ring, requeue_idx);
19733a6d1fcfSKip Macy 		pfn = vtophys(mtod(m, vm_offset_t)) >> PAGE_SHIFT;
197489e0f4d2SKip Macy 
197589e0f4d2SKip Macy 		gnttab_grant_foreign_access_ref(ref,
197696375eacSRoger Pau Monné 		    xenbus_get_otherend_id(rxq->info->xbdev),
1977ed95805eSJohn Baldwin 		    pfn, 0);
1978d0f3a8b9SRoger Pau Monné 
197989e0f4d2SKip Macy 		req->gref = ref;
198089e0f4d2SKip Macy 		req->id   = requeue_idx;
198189e0f4d2SKip Macy 
198289e0f4d2SKip Macy 		requeue_idx++;
198389e0f4d2SKip Macy 	}
198489e0f4d2SKip Macy 
198596375eacSRoger Pau Monné 	rxq->ring.req_prod_pvt = requeue_idx;
198696375eacSRoger Pau Monné }
198789e0f4d2SKip Macy 
198896375eacSRoger Pau Monné /* START of Xenolinux helper functions adapted to FreeBSD */
198965671253SRoger Pau Monné static int
199096375eacSRoger Pau Monné xn_connect(struct netfront_info *np)
199196375eacSRoger Pau Monné {
199296375eacSRoger Pau Monné 	int i, error;
199396375eacSRoger Pau Monné 	u_int feature_rx_copy;
199496375eacSRoger Pau Monné 	struct netfront_rxq *rxq;
199596375eacSRoger Pau Monné 	struct netfront_txq *txq;
199696375eacSRoger Pau Monné 
199796375eacSRoger Pau Monné 	error = xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev),
199896375eacSRoger Pau Monné 	    "feature-rx-copy", NULL, "%u", &feature_rx_copy);
199996375eacSRoger Pau Monné 	if (error != 0)
200096375eacSRoger Pau Monné 		feature_rx_copy = 0;
200196375eacSRoger Pau Monné 
200296375eacSRoger Pau Monné 	/* We only support rx copy. */
200396375eacSRoger Pau Monné 	if (!feature_rx_copy)
200496375eacSRoger Pau Monné 		return (EPROTONOSUPPORT);
200596375eacSRoger Pau Monné 
200696375eacSRoger Pau Monné 	/* Recovery procedure: */
200796375eacSRoger Pau Monné 	error = talk_to_backend(np->xbdev, np);
200896375eacSRoger Pau Monné 	if (error != 0)
200996375eacSRoger Pau Monné 		return (error);
201096375eacSRoger Pau Monné 
201196375eacSRoger Pau Monné 	/* Step 1: Reinitialise variables. */
201296375eacSRoger Pau Monné 	xn_query_features(np);
201396375eacSRoger Pau Monné 	xn_configure_features(np);
201496375eacSRoger Pau Monné 
201596375eacSRoger Pau Monné 	/* Step 2: Release TX buffer */
201696375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
201796375eacSRoger Pau Monné 		txq = &np->txq[i];
201896375eacSRoger Pau Monné 		xn_release_tx_bufs(txq);
201996375eacSRoger Pau Monné 	}
202096375eacSRoger Pau Monné 
202196375eacSRoger Pau Monné 	/* Step 3: Rebuild the RX buffer freelist and the RX ring itself. */
202296375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
202396375eacSRoger Pau Monné 		rxq = &np->rxq[i];
202496375eacSRoger Pau Monné 		xn_rebuild_rx_bufs(rxq);
202596375eacSRoger Pau Monné 	}
202696375eacSRoger Pau Monné 
202796375eacSRoger Pau Monné 	/* Step 4: All public and private state should now be sane.  Get
202889e0f4d2SKip Macy 	 * ready to start sending and receiving packets and give the driver
202989e0f4d2SKip Macy 	 * domain a kick because we've probably just requeued some
203089e0f4d2SKip Macy 	 * packets.
203189e0f4d2SKip Macy 	 */
203289e0f4d2SKip Macy 	netfront_carrier_on(np);
20333c9d5940SRoger Pau Monné 	wakeup(np);
203465671253SRoger Pau Monné 
203565671253SRoger Pau Monné 	return (0);
203665671253SRoger Pau Monné }
203765671253SRoger Pau Monné 
203865671253SRoger Pau Monné static void
203965671253SRoger Pau Monné xn_kick_rings(struct netfront_info *np)
204065671253SRoger Pau Monné {
204165671253SRoger Pau Monné 	struct netfront_rxq *rxq;
204265671253SRoger Pau Monné 	struct netfront_txq *txq;
204365671253SRoger Pau Monné 	int i;
204465671253SRoger Pau Monné 
204596375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
204696375eacSRoger Pau Monné 		txq = &np->txq[i];
204765671253SRoger Pau Monné 		rxq = &np->rxq[i];
204896375eacSRoger Pau Monné 		xen_intr_signal(txq->xen_intr_handle);
204996375eacSRoger Pau Monné 		XN_TX_LOCK(txq);
205096375eacSRoger Pau Monné 		xn_txeof(txq);
205196375eacSRoger Pau Monné 		XN_TX_UNLOCK(txq);
20522568ee67SRoger Pau Monné 		XN_RX_LOCK(rxq);
205396375eacSRoger Pau Monné 		xn_alloc_rx_buffers(rxq);
20542568ee67SRoger Pau Monné 		XN_RX_UNLOCK(rxq);
205596375eacSRoger Pau Monné 	}
205689e0f4d2SKip Macy }
205789e0f4d2SKip Macy 
205889e0f4d2SKip Macy static void
2059578e4bf7SJustin T. Gibbs xn_query_features(struct netfront_info *np)
2060578e4bf7SJustin T. Gibbs {
2061578e4bf7SJustin T. Gibbs 	int val;
2062578e4bf7SJustin T. Gibbs 
2063578e4bf7SJustin T. Gibbs 	device_printf(np->xbdev, "backend features:");
2064578e4bf7SJustin T. Gibbs 
2065578e4bf7SJustin T. Gibbs 	if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev),
2066107cfbb7SRoger Pau Monné 		"feature-sg", NULL, "%d", &val) != 0)
2067578e4bf7SJustin T. Gibbs 		val = 0;
2068578e4bf7SJustin T. Gibbs 
2069578e4bf7SJustin T. Gibbs 	np->maxfrags = 1;
2070578e4bf7SJustin T. Gibbs 	if (val) {
2071578e4bf7SJustin T. Gibbs 		np->maxfrags = MAX_TX_REQ_FRAGS;
2072578e4bf7SJustin T. Gibbs 		printf(" feature-sg");
2073578e4bf7SJustin T. Gibbs 	}
2074578e4bf7SJustin T. Gibbs 
2075578e4bf7SJustin T. Gibbs 	if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev),
2076107cfbb7SRoger Pau Monné 		"feature-gso-tcpv4", NULL, "%d", &val) != 0)
2077578e4bf7SJustin T. Gibbs 		val = 0;
2078578e4bf7SJustin T. Gibbs 
207902f3b17fSJustin Hibbits 	if_setcapabilitiesbit(np->xn_ifp, 0, IFCAP_TSO4 | IFCAP_LRO);
2080578e4bf7SJustin T. Gibbs 	if (val) {
208102f3b17fSJustin Hibbits 		if_setcapabilitiesbit(np->xn_ifp, IFCAP_TSO4 | IFCAP_LRO, 0);
2082578e4bf7SJustin T. Gibbs 		printf(" feature-gso-tcp4");
2083578e4bf7SJustin T. Gibbs 	}
2084578e4bf7SJustin T. Gibbs 
2085c2d12e5eSRoger Pau Monné 	/*
2086c2d12e5eSRoger Pau Monné 	 * HW CSUM offload is assumed to be available unless
2087c2d12e5eSRoger Pau Monné 	 * feature-no-csum-offload is set in xenstore.
2088c2d12e5eSRoger Pau Monné 	 */
2089c2d12e5eSRoger Pau Monné 	if (xs_scanf(XST_NIL, xenbus_get_otherend_path(np->xbdev),
2090c2d12e5eSRoger Pau Monné 		"feature-no-csum-offload", NULL, "%d", &val) != 0)
2091c2d12e5eSRoger Pau Monné 		val = 0;
2092c2d12e5eSRoger Pau Monné 
209302f3b17fSJustin Hibbits 	if_setcapabilitiesbit(np->xn_ifp, IFCAP_HWCSUM, 0);
2094c2d12e5eSRoger Pau Monné 	if (val) {
209502f3b17fSJustin Hibbits 		if_setcapabilitiesbit(np->xn_ifp, 0, IFCAP_HWCSUM);
2096c2d12e5eSRoger Pau Monné 		printf(" feature-no-csum-offload");
2097c2d12e5eSRoger Pau Monné 	}
2098c2d12e5eSRoger Pau Monné 
2099578e4bf7SJustin T. Gibbs 	printf("\n");
2100578e4bf7SJustin T. Gibbs }
2101578e4bf7SJustin T. Gibbs 
2102cf9c09e1SJustin T. Gibbs static int
2103578e4bf7SJustin T. Gibbs xn_configure_features(struct netfront_info *np)
2104cf9c09e1SJustin T. Gibbs {
21056a8e9695SRoger Pau Monné 	int err, cap_enabled;
210696375eacSRoger Pau Monné #if (defined(INET) || defined(INET6))
210796375eacSRoger Pau Monné 	int i;
210896375eacSRoger Pau Monné #endif
210902f3b17fSJustin Hibbits 	if_t ifp;
2110cf9c09e1SJustin T. Gibbs 
2111c2d12e5eSRoger Pau Monné 	ifp = np->xn_ifp;
2112cf9c09e1SJustin T. Gibbs 	err = 0;
21136a8e9695SRoger Pau Monné 
211402f3b17fSJustin Hibbits 	if ((if_getcapenable(ifp) & if_getcapabilities(ifp)) == if_getcapenable(ifp)) {
21156a8e9695SRoger Pau Monné 		/* Current options are available, no need to do anything. */
21166a8e9695SRoger Pau Monné 		return (0);
21176a8e9695SRoger Pau Monné 	}
21186a8e9695SRoger Pau Monné 
21196a8e9695SRoger Pau Monné 	/* Try to preserve as many options as possible. */
212002f3b17fSJustin Hibbits 	cap_enabled = if_getcapenable(ifp);
212102f3b17fSJustin Hibbits 	if_setcapenable(ifp, 0);
212202f3b17fSJustin Hibbits 	if_sethwassist(ifp, 0);
21236a8e9695SRoger Pau Monné 
212408c9c2e0SRoger Pau Monné #if (defined(INET) || defined(INET6))
2125c2d12e5eSRoger Pau Monné 	if ((cap_enabled & IFCAP_LRO) != 0)
212696375eacSRoger Pau Monné 		for (i = 0; i < np->num_queues; i++)
212796375eacSRoger Pau Monné 			tcp_lro_free(&np->rxq[i].lro);
2128c2d12e5eSRoger Pau Monné 	if (xn_enable_lro &&
212902f3b17fSJustin Hibbits 	    (if_getcapabilities(ifp) & cap_enabled & IFCAP_LRO) != 0) {
213002f3b17fSJustin Hibbits 	    	if_setcapenablebit(ifp, IFCAP_LRO, 0);
213196375eacSRoger Pau Monné 		for (i = 0; i < np->num_queues; i++) {
213296375eacSRoger Pau Monné 			err = tcp_lro_init(&np->rxq[i].lro);
213396375eacSRoger Pau Monné 			if (err != 0) {
2134c2d12e5eSRoger Pau Monné 				device_printf(np->xbdev,
2135c2d12e5eSRoger Pau Monné 				    "LRO initialization failed\n");
213602f3b17fSJustin Hibbits 				if_setcapenablebit(ifp, 0, IFCAP_LRO);
2137c2d12e5eSRoger Pau Monné 				break;
2138c2d12e5eSRoger Pau Monné 			}
2139c2d12e5eSRoger Pau Monné 			np->rxq[i].lro.ifp = ifp;
2140cf9c09e1SJustin T. Gibbs 		}
2141cf9c09e1SJustin T. Gibbs 	}
214202f3b17fSJustin Hibbits 	if ((if_getcapabilities(ifp) & cap_enabled & IFCAP_TSO4) != 0) {
214302f3b17fSJustin Hibbits 		if_setcapenablebit(ifp, IFCAP_TSO4, 0);
214402f3b17fSJustin Hibbits 		if_sethwassistbits(ifp, CSUM_TSO, 0);
2145578e4bf7SJustin T. Gibbs 	}
2146cf9c09e1SJustin T. Gibbs #endif
214702f3b17fSJustin Hibbits 	if ((if_getcapabilities(ifp) & cap_enabled & IFCAP_TXCSUM) != 0) {
214802f3b17fSJustin Hibbits 		if_setcapenablebit(ifp, IFCAP_TXCSUM, 0);
214902f3b17fSJustin Hibbits 		if_sethwassistbits(ifp, XN_CSUM_FEATURES, 0);
2150c2d12e5eSRoger Pau Monné 	}
215102f3b17fSJustin Hibbits 	if ((if_getcapabilities(ifp) & cap_enabled & IFCAP_RXCSUM) != 0)
215202f3b17fSJustin Hibbits 		if_setcapenablebit(ifp, IFCAP_RXCSUM, 0);
2153c2d12e5eSRoger Pau Monné 
2154cf9c09e1SJustin T. Gibbs 	return (err);
2155cf9c09e1SJustin T. Gibbs }
2156cf9c09e1SJustin T. Gibbs 
215796375eacSRoger Pau Monné static int
215896375eacSRoger Pau Monné xn_txq_mq_start_locked(struct netfront_txq *txq, struct mbuf *m)
215996375eacSRoger Pau Monné {
216096375eacSRoger Pau Monné 	struct netfront_info *np;
216102f3b17fSJustin Hibbits 	if_t ifp;
216296375eacSRoger Pau Monné 	struct buf_ring *br;
216396375eacSRoger Pau Monné 	int error, notify;
216496375eacSRoger Pau Monné 
216596375eacSRoger Pau Monné 	np = txq->info;
216696375eacSRoger Pau Monné 	br = txq->br;
216796375eacSRoger Pau Monné 	ifp = np->xn_ifp;
216896375eacSRoger Pau Monné 	error = 0;
216996375eacSRoger Pau Monné 
217096375eacSRoger Pau Monné 	XN_TX_LOCK_ASSERT(txq);
217196375eacSRoger Pau Monné 
217202f3b17fSJustin Hibbits 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0 ||
217396375eacSRoger Pau Monné 	    !netfront_carrier_ok(np)) {
217496375eacSRoger Pau Monné 		if (m != NULL)
217596375eacSRoger Pau Monné 			error = drbr_enqueue(ifp, br, m);
217696375eacSRoger Pau Monné 		return (error);
217796375eacSRoger Pau Monné 	}
217896375eacSRoger Pau Monné 
217996375eacSRoger Pau Monné 	if (m != NULL) {
218096375eacSRoger Pau Monné 		error = drbr_enqueue(ifp, br, m);
218196375eacSRoger Pau Monné 		if (error != 0)
218296375eacSRoger Pau Monné 			return (error);
218396375eacSRoger Pau Monné 	}
218496375eacSRoger Pau Monné 
218596375eacSRoger Pau Monné 	while ((m = drbr_peek(ifp, br)) != NULL) {
218696375eacSRoger Pau Monné 		if (!xn_tx_slot_available(txq)) {
218796375eacSRoger Pau Monné 			drbr_putback(ifp, br, m);
218896375eacSRoger Pau Monné 			break;
218996375eacSRoger Pau Monné 		}
219096375eacSRoger Pau Monné 
219196375eacSRoger Pau Monné 		error = xn_assemble_tx_request(txq, m);
219296375eacSRoger Pau Monné 		/* xn_assemble_tx_request always consumes the mbuf*/
219396375eacSRoger Pau Monné 		if (error != 0) {
219496375eacSRoger Pau Monné 			drbr_advance(ifp, br);
219596375eacSRoger Pau Monné 			break;
219696375eacSRoger Pau Monné 		}
219796375eacSRoger Pau Monné 
219896375eacSRoger Pau Monné 		RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&txq->ring, notify);
219996375eacSRoger Pau Monné 		if (notify)
220096375eacSRoger Pau Monné 			xen_intr_signal(txq->xen_intr_handle);
220196375eacSRoger Pau Monné 
220296375eacSRoger Pau Monné 		drbr_advance(ifp, br);
220396375eacSRoger Pau Monné 	}
220496375eacSRoger Pau Monné 
220596375eacSRoger Pau Monné 	if (RING_FULL(&txq->ring))
220696375eacSRoger Pau Monné 		txq->full = true;
220796375eacSRoger Pau Monné 
220896375eacSRoger Pau Monné 	return (0);
220996375eacSRoger Pau Monné }
221096375eacSRoger Pau Monné 
221196375eacSRoger Pau Monné static int
221202f3b17fSJustin Hibbits xn_txq_mq_start(if_t ifp, struct mbuf *m)
221396375eacSRoger Pau Monné {
221496375eacSRoger Pau Monné 	struct netfront_info *np;
221596375eacSRoger Pau Monné 	struct netfront_txq *txq;
221696375eacSRoger Pau Monné 	int i, npairs, error;
221796375eacSRoger Pau Monné 
221802f3b17fSJustin Hibbits 	np = if_getsoftc(ifp);
221996375eacSRoger Pau Monné 	npairs = np->num_queues;
222096375eacSRoger Pau Monné 
2221339690b5SRoger Pau Monné 	if (!netfront_carrier_ok(np))
2222339690b5SRoger Pau Monné 		return (ENOBUFS);
2223339690b5SRoger Pau Monné 
2224c21b47d8SRoger Pau Monné 	KASSERT(npairs != 0, ("called with 0 available queues"));
2225c21b47d8SRoger Pau Monné 
222696375eacSRoger Pau Monné 	/* check if flowid is set */
222796375eacSRoger Pau Monné 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
222896375eacSRoger Pau Monné 		i = m->m_pkthdr.flowid % npairs;
222996375eacSRoger Pau Monné 	else
223096375eacSRoger Pau Monné 		i = curcpu % npairs;
223196375eacSRoger Pau Monné 
223296375eacSRoger Pau Monné 	txq = &np->txq[i];
223396375eacSRoger Pau Monné 
223496375eacSRoger Pau Monné 	if (XN_TX_TRYLOCK(txq) != 0) {
223596375eacSRoger Pau Monné 		error = xn_txq_mq_start_locked(txq, m);
223696375eacSRoger Pau Monné 		XN_TX_UNLOCK(txq);
223796375eacSRoger Pau Monné 	} else {
223896375eacSRoger Pau Monné 		error = drbr_enqueue(ifp, txq->br, m);
223996375eacSRoger Pau Monné 		taskqueue_enqueue(txq->tq, &txq->defrtask);
224096375eacSRoger Pau Monné 	}
224196375eacSRoger Pau Monné 
224296375eacSRoger Pau Monné 	return (error);
224396375eacSRoger Pau Monné }
224496375eacSRoger Pau Monné 
224596375eacSRoger Pau Monné static void
224602f3b17fSJustin Hibbits xn_qflush(if_t ifp)
224796375eacSRoger Pau Monné {
224896375eacSRoger Pau Monné 	struct netfront_info *np;
224996375eacSRoger Pau Monné 	struct netfront_txq *txq;
225096375eacSRoger Pau Monné 	struct mbuf *m;
225196375eacSRoger Pau Monné 	int i;
225296375eacSRoger Pau Monné 
225302f3b17fSJustin Hibbits 	np = if_getsoftc(ifp);
225496375eacSRoger Pau Monné 
225596375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
225696375eacSRoger Pau Monné 		txq = &np->txq[i];
225796375eacSRoger Pau Monné 
225896375eacSRoger Pau Monné 		XN_TX_LOCK(txq);
225996375eacSRoger Pau Monné 		while ((m = buf_ring_dequeue_sc(txq->br)) != NULL)
226096375eacSRoger Pau Monné 			m_freem(m);
226196375eacSRoger Pau Monné 		XN_TX_UNLOCK(txq);
226296375eacSRoger Pau Monné 	}
226396375eacSRoger Pau Monné 
226496375eacSRoger Pau Monné 	if_qflush(ifp);
226596375eacSRoger Pau Monné }
226696375eacSRoger Pau Monné 
226776acc41fSJustin T. Gibbs /**
226876acc41fSJustin T. Gibbs  * Create a network device.
226976acc41fSJustin T. Gibbs  * @param dev  Newbus device representing this virtual NIC.
227089e0f4d2SKip Macy  */
227123dc5621SKip Macy int
227223dc5621SKip Macy create_netdev(device_t dev)
227389e0f4d2SKip Macy {
227489e0f4d2SKip Macy 	struct netfront_info *np;
2275*da4b0d6eSDoug Rabson 	int err, cap_enabled;
227602f3b17fSJustin Hibbits 	if_t ifp;
227789e0f4d2SKip Macy 
227823dc5621SKip Macy 	np = device_get_softc(dev);
227989e0f4d2SKip Macy 
228089e0f4d2SKip Macy 	np->xbdev         = dev;
228189e0f4d2SKip Macy 
2282177e3f13SRoger Pau Monné 	mtx_init(&np->sc_lock, "xnsc", "netfront softc lock", MTX_DEF);
22830e509842SJustin T. Gibbs 
22840e509842SJustin T. Gibbs 	ifmedia_init(&np->sc_media, 0, xn_ifmedia_upd, xn_ifmedia_sts);
22850e509842SJustin T. Gibbs 	ifmedia_add(&np->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
22860e509842SJustin T. Gibbs 	ifmedia_set(&np->sc_media, IFM_ETHER|IFM_MANUAL);
22870e509842SJustin T. Gibbs 
228889e0f4d2SKip Macy 	err = xen_net_read_mac(dev, np->mac);
228996375eacSRoger Pau Monné 	if (err != 0)
22901a2928b7SRoger Pau Monné 		goto error;
229189e0f4d2SKip Macy 
229289e0f4d2SKip Macy 	/* Set up ifnet structure */
229323dc5621SKip Macy 	ifp = np->xn_ifp = if_alloc(IFT_ETHER);
229402f3b17fSJustin Hibbits 	if_setsoftc(ifp, np);
229523dc5621SKip Macy 	if_initname(ifp, "xn",  device_get_unit(dev));
229602f3b17fSJustin Hibbits 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
229702f3b17fSJustin Hibbits 	if_setioctlfn(ifp, xn_ioctl);
229896375eacSRoger Pau Monné 
229902f3b17fSJustin Hibbits 	if_settransmitfn(ifp, xn_txq_mq_start);
230002f3b17fSJustin Hibbits 	if_setqflushfn(ifp, xn_qflush);
230196375eacSRoger Pau Monné 
230202f3b17fSJustin Hibbits 	if_setinitfn(ifp, xn_ifinit);
230389e0f4d2SKip Macy 
230402f3b17fSJustin Hibbits 	if_sethwassist(ifp, XN_CSUM_FEATURES);
2305c2d12e5eSRoger Pau Monné 	/* Enable all supported features at device creation. */
230602f3b17fSJustin Hibbits 	if_setcapabilities(ifp, IFCAP_HWCSUM|IFCAP_TSO4|IFCAP_LRO);
2307*da4b0d6eSDoug Rabson 	cap_enabled = if_getcapabilities(ifp);
2308*da4b0d6eSDoug Rabson 	if (!xn_enable_lro) {
2309*da4b0d6eSDoug Rabson 		cap_enabled &= ~IFCAP_LRO;
2310*da4b0d6eSDoug Rabson 	}
2311*da4b0d6eSDoug Rabson 	if_setcapenable(ifp, cap_enabled);
231202f3b17fSJustin Hibbits 
231302f3b17fSJustin Hibbits 	if_sethwtsomax(ifp, 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
231402f3b17fSJustin Hibbits 	if_sethwtsomaxsegcount(ifp, MAX_TX_REQ_FRAGS);
231502f3b17fSJustin Hibbits 	if_sethwtsomaxsegsize(ifp, PAGE_SIZE);
231689e0f4d2SKip Macy 
231789e0f4d2SKip Macy 	ether_ifattach(ifp, np->mac);
231889e0f4d2SKip Macy 	netfront_carrier_off(np);
231989e0f4d2SKip Macy 
2320dabb3db7SRoger Pau Monné 	err = bus_dma_tag_create(
2321dabb3db7SRoger Pau Monné 	    bus_get_dma_tag(dev),		/* parent */
2322dabb3db7SRoger Pau Monné 	    1, PAGE_SIZE,			/* algnmnt, boundary */
2323dabb3db7SRoger Pau Monné 	    BUS_SPACE_MAXADDR,			/* lowaddr */
2324dabb3db7SRoger Pau Monné 	    BUS_SPACE_MAXADDR,			/* highaddr */
2325dabb3db7SRoger Pau Monné 	    NULL, NULL,				/* filter, filterarg */
2326dabb3db7SRoger Pau Monné 	    PAGE_SIZE * MAX_TX_REQ_FRAGS,	/* max request size */
2327dabb3db7SRoger Pau Monné 	    MAX_TX_REQ_FRAGS,			/* max segments */
2328dabb3db7SRoger Pau Monné 	    PAGE_SIZE,				/* maxsegsize */
2329dabb3db7SRoger Pau Monné 	    BUS_DMA_ALLOCNOW,			/* flags */
2330dabb3db7SRoger Pau Monné 	    NULL, NULL,				/* lockfunc, lockarg */
2331dabb3db7SRoger Pau Monné 	    &np->dma_tag);
2332dabb3db7SRoger Pau Monné 
2333dabb3db7SRoger Pau Monné 	return (err);
233489e0f4d2SKip Macy 
23351a2928b7SRoger Pau Monné error:
23361a2928b7SRoger Pau Monné 	KASSERT(err != 0, ("Error path with no error code specified"));
2337ffa06904SJustin T. Gibbs 	return (err);
233889e0f4d2SKip Macy }
233989e0f4d2SKip Macy 
23400e509842SJustin T. Gibbs static int
23410e509842SJustin T. Gibbs netfront_detach(device_t dev)
234289e0f4d2SKip Macy {
234323dc5621SKip Macy 	struct netfront_info *info = device_get_softc(dev);
234489e0f4d2SKip Macy 
234523dc5621SKip Macy 	DPRINTK("%s\n", xenbus_get_node(dev));
234689e0f4d2SKip Macy 
234789e0f4d2SKip Macy 	netif_free(info);
234889e0f4d2SKip Macy 
234989e0f4d2SKip Macy 	return 0;
235089e0f4d2SKip Macy }
235189e0f4d2SKip Macy 
23520e509842SJustin T. Gibbs static void
235396375eacSRoger Pau Monné netif_free(struct netfront_info *np)
235489e0f4d2SKip Macy {
235596375eacSRoger Pau Monné 
235696375eacSRoger Pau Monné 	XN_LOCK(np);
235796375eacSRoger Pau Monné 	xn_stop(np);
235896375eacSRoger Pau Monné 	XN_UNLOCK(np);
235996375eacSRoger Pau Monné 	netif_disconnect_backend(np);
2360c21b47d8SRoger Pau Monné 	ether_ifdetach(np->xn_ifp);
236196375eacSRoger Pau Monné 	free(np->rxq, M_DEVBUF);
236296375eacSRoger Pau Monné 	free(np->txq, M_DEVBUF);
236396375eacSRoger Pau Monné 	if_free(np->xn_ifp);
236496375eacSRoger Pau Monné 	np->xn_ifp = NULL;
236596375eacSRoger Pau Monné 	ifmedia_removeall(&np->sc_media);
2366dabb3db7SRoger Pau Monné 	bus_dma_tag_destroy(np->dma_tag);
236789e0f4d2SKip Macy }
236889e0f4d2SKip Macy 
23690e509842SJustin T. Gibbs static void
237096375eacSRoger Pau Monné netif_disconnect_backend(struct netfront_info *np)
237189e0f4d2SKip Macy {
237296375eacSRoger Pau Monné 	u_int i;
23733a6d1fcfSKip Macy 
237496375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
237596375eacSRoger Pau Monné 		XN_RX_LOCK(&np->rxq[i]);
237696375eacSRoger Pau Monné 		XN_TX_LOCK(&np->txq[i]);
237796375eacSRoger Pau Monné 	}
237896375eacSRoger Pau Monné 	netfront_carrier_off(np);
237996375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
238096375eacSRoger Pau Monné 		XN_RX_UNLOCK(&np->rxq[i]);
238196375eacSRoger Pau Monné 		XN_TX_UNLOCK(&np->txq[i]);
238289e0f4d2SKip Macy 	}
238389e0f4d2SKip Macy 
238496375eacSRoger Pau Monné 	for (i = 0; i < np->num_queues; i++) {
238596375eacSRoger Pau Monné 		disconnect_rxq(&np->rxq[i]);
238696375eacSRoger Pau Monné 		disconnect_txq(&np->txq[i]);
2387cf9c09e1SJustin T. Gibbs 	}
238889e0f4d2SKip Macy }
238989e0f4d2SKip Macy 
23900e509842SJustin T. Gibbs static int
239102f3b17fSJustin Hibbits xn_ifmedia_upd(if_t ifp)
23920e509842SJustin T. Gibbs {
239396375eacSRoger Pau Monné 
23940e509842SJustin T. Gibbs 	return (0);
23950e509842SJustin T. Gibbs }
23960e509842SJustin T. Gibbs 
23970e509842SJustin T. Gibbs static void
239802f3b17fSJustin Hibbits xn_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
23990e509842SJustin T. Gibbs {
240096375eacSRoger Pau Monné 
24010e509842SJustin T. Gibbs 	ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE;
24020e509842SJustin T. Gibbs 	ifmr->ifm_active = IFM_ETHER|IFM_MANUAL;
24030e509842SJustin T. Gibbs }
24040e509842SJustin T. Gibbs 
240589e0f4d2SKip Macy /* ** Driver registration ** */
240623dc5621SKip Macy static device_method_t netfront_methods[] = {
240723dc5621SKip Macy 	/* Device interface */
240823dc5621SKip Macy 	DEVMETHOD(device_probe,         netfront_probe),
240923dc5621SKip Macy 	DEVMETHOD(device_attach,        netfront_attach),
241023dc5621SKip Macy 	DEVMETHOD(device_detach,        netfront_detach),
241123dc5621SKip Macy 	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
2412cf9c09e1SJustin T. Gibbs 	DEVMETHOD(device_suspend,       netfront_suspend),
241323dc5621SKip Macy 	DEVMETHOD(device_resume,        netfront_resume),
241489e0f4d2SKip Macy 
241523dc5621SKip Macy 	/* Xenbus interface */
2416ff662b5cSJustin T. Gibbs 	DEVMETHOD(xenbus_otherend_changed, netfront_backend_changed),
241789e0f4d2SKip Macy 
24186f9767acSMarius Strobl 	DEVMETHOD_END
241989e0f4d2SKip Macy };
242089e0f4d2SKip Macy 
242123dc5621SKip Macy static driver_t netfront_driver = {
242223dc5621SKip Macy 	"xn",
242323dc5621SKip Macy 	netfront_methods,
242423dc5621SKip Macy 	sizeof(struct netfront_info),
242589e0f4d2SKip Macy };
242689e0f4d2SKip Macy 
2427f929eb1eSJohn Baldwin DRIVER_MODULE(xe, xenbusb_front, netfront_driver, NULL, NULL);
2428