netfront.c revision 185473
1181643Skmacy/*
2181643Skmacy *
3181643Skmacy * Copyright (c) 2004-2006 Kip Macy
4181643Skmacy * All rights reserved.
5181643Skmacy *
6181643Skmacy *
7181643Skmacy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
8181643Skmacy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
9181643Skmacy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
10181643Skmacy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
11181643Skmacy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
12181643Skmacy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
13181643Skmacy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
14181643Skmacy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
15181643Skmacy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
16181643Skmacy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17181643Skmacy */
18181643Skmacy
19181643Skmacy
20181643Skmacy#include <sys/cdefs.h>
21181643Skmacy__FBSDID("$FreeBSD: head/sys/dev/xen/netfront/netfront.c 185473 2008-11-30 12:21:46Z dfr $");
22181643Skmacy
23181643Skmacy#include <sys/param.h>
24181643Skmacy#include <sys/systm.h>
25181643Skmacy#include <sys/sockio.h>
26181643Skmacy#include <sys/mbuf.h>
27181643Skmacy#include <sys/malloc.h>
28181643Skmacy#include <sys/kernel.h>
29181643Skmacy#include <sys/socket.h>
30181643Skmacy#include <sys/queue.h>
31181643Skmacy#include <sys/sx.h>
32181643Skmacy
33181643Skmacy#include <net/if.h>
34181643Skmacy#include <net/if_arp.h>
35181643Skmacy#include <net/ethernet.h>
36181643Skmacy#include <net/if_dl.h>
37181643Skmacy#include <net/if_media.h>
38181643Skmacy
39181643Skmacy#include <net/bpf.h>
40181643Skmacy
41181643Skmacy#include <net/if_types.h>
42181643Skmacy#include <net/if.h>
43181643Skmacy
44181643Skmacy#include <netinet/in_systm.h>
45181643Skmacy#include <netinet/in.h>
46181643Skmacy#include <netinet/ip.h>
47181643Skmacy#include <netinet/if_ether.h>
48181643Skmacy
49181643Skmacy#include <vm/vm.h>
50181643Skmacy#include <vm/pmap.h>
51181643Skmacy
52181643Skmacy#include <machine/clock.h>      /* for DELAY */
53181643Skmacy#include <machine/bus.h>
54181643Skmacy#include <machine/resource.h>
55181643Skmacy#include <machine/frame.h>
56181910Skmacy#include <machine/vmparam.h>
57181643Skmacy
58181643Skmacy#include <sys/bus.h>
59181643Skmacy#include <sys/rman.h>
60181643Skmacy
61181643Skmacy#include <machine/intr_machdep.h>
62181643Skmacy
63181643Skmacy#include <machine/xen/xen-os.h>
64181643Skmacy#include <machine/xen/hypervisor.h>
65181643Skmacy#include <machine/xen/xen_intr.h>
66181643Skmacy#include <machine/xen/evtchn.h>
67181643Skmacy#include <machine/xen/xenbus.h>
68181643Skmacy#include <xen/gnttab.h>
69181643Skmacy#include <xen/interface/memory.h>
70181643Skmacy#include <dev/xen/netfront/mbufq.h>
71181643Skmacy#include <machine/xen/features.h>
72181643Skmacy#include <xen/interface/io/netif.h>
73181643Skmacy
74181643Skmacy
75181643Skmacy#define GRANT_INVALID_REF	0
76181643Skmacy
77181643Skmacy#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
78181643Skmacy#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
79181643Skmacy
80181643Skmacy#ifdef CONFIG_XEN
81181643Skmacystatic int MODPARM_rx_copy = 0;
82181643Skmacymodule_param_named(rx_copy, MODPARM_rx_copy, bool, 0);
83181643SkmacyMODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)");
84181643Skmacystatic int MODPARM_rx_flip = 0;
85181643Skmacymodule_param_named(rx_flip, MODPARM_rx_flip, bool, 0);
86181643SkmacyMODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)");
87181643Skmacy#else
88181643Skmacystatic const int MODPARM_rx_copy = 1;
89181643Skmacystatic const int MODPARM_rx_flip = 0;
90181643Skmacy#endif
91181643Skmacy
92181643Skmacy#define RX_COPY_THRESHOLD 256
93181643Skmacy
94181643Skmacy#define net_ratelimit() 0
95181643Skmacy
96181643Skmacystruct netfront_info;
97181643Skmacystruct netfront_rx_info;
98181643Skmacy
99181643Skmacystatic void xn_txeof(struct netfront_info *);
100181643Skmacystatic void xn_rxeof(struct netfront_info *);
101181643Skmacystatic void network_alloc_rx_buffers(struct netfront_info *);
102181643Skmacy
103181643Skmacystatic void xn_tick_locked(struct netfront_info *);
104181643Skmacystatic void xn_tick(void *);
105181643Skmacy
106181643Skmacystatic void xn_intr(void *);
107181643Skmacystatic void xn_start_locked(struct ifnet *);
108181643Skmacystatic void xn_start(struct ifnet *);
109181643Skmacystatic int  xn_ioctl(struct ifnet *, u_long, caddr_t);
110181643Skmacystatic void xn_ifinit_locked(struct netfront_info *);
111181643Skmacystatic void xn_ifinit(void *);
112181643Skmacystatic void xn_stop(struct netfront_info *);
113181643Skmacy#ifdef notyet
114181643Skmacystatic void xn_watchdog(struct ifnet *);
115181643Skmacy#endif
116181643Skmacy
117181643Skmacystatic void show_device(struct netfront_info *sc);
118181643Skmacy#ifdef notyet
119181643Skmacystatic void netfront_closing(struct xenbus_device *dev);
120181643Skmacy#endif
121181643Skmacystatic void netif_free(struct netfront_info *info);
122181643Skmacystatic int netfront_remove(struct xenbus_device *dev);
123181643Skmacy
124181643Skmacystatic int talk_to_backend(struct xenbus_device *dev, struct netfront_info *info);
125181643Skmacystatic int create_netdev(struct xenbus_device *dev, struct ifnet **ifp);
126181643Skmacystatic void netif_disconnect_backend(struct netfront_info *info);
127181643Skmacystatic int setup_device(struct xenbus_device *dev, struct netfront_info *info);
128181643Skmacystatic void end_access(int ref, void *page);
129181643Skmacy
130181643Skmacy/* Xenolinux helper functions */
131181643Skmacystatic int network_connect(struct ifnet *ifp);
132181643Skmacy
133181643Skmacystatic void xn_free_rx_ring(struct netfront_info *);
134181643Skmacy
135181643Skmacystatic void xn_free_tx_ring(struct netfront_info *);
136181643Skmacy
137181643Skmacystatic int xennet_get_responses(struct netfront_info *np,
138181945Skmacy	struct netfront_rx_info *rinfo, RING_IDX rp, struct mbuf **list,
139181643Skmacy	int *pages_flipped_p);
140181643Skmacy
141181643Skmacy#define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT)
142181643Skmacy
143181643Skmacy#define INVALID_P2M_ENTRY (~0UL)
144181643Skmacy
145181643Skmacy/*
146181643Skmacy * Mbuf pointers. We need these to keep track of the virtual addresses
147181643Skmacy * of our mbuf chains since we can only convert from virtual to physical,
148181643Skmacy * not the other way around.  The size must track the free index arrays.
149181643Skmacy */
150181643Skmacystruct xn_chain_data {
151181916Skmacy		struct mbuf		*xn_tx_chain[NET_TX_RING_SIZE+1];
152181945Skmacy		struct mbuf		*xn_rx_chain[NET_RX_RING_SIZE+1];
153181643Skmacy};
154181643Skmacy
155181643Skmacy
156181643Skmacystruct net_device_stats
157181643Skmacy{
158181643Skmacy	u_long	rx_packets;		/* total packets received	*/
159181643Skmacy	u_long	tx_packets;		/* total packets transmitted	*/
160181643Skmacy	u_long	rx_bytes;		/* total bytes received 	*/
161181643Skmacy	u_long	tx_bytes;		/* total bytes transmitted	*/
162181643Skmacy	u_long	rx_errors;		/* bad packets received		*/
163181643Skmacy	u_long	tx_errors;		/* packet transmit problems	*/
164181643Skmacy	u_long	rx_dropped;		/* no space in linux buffers	*/
165181643Skmacy	u_long	tx_dropped;		/* no space available in linux	*/
166181643Skmacy	u_long	multicast;		/* multicast packets received	*/
167181643Skmacy	u_long	collisions;
168181643Skmacy
169181643Skmacy	/* detailed rx_errors: */
170181643Skmacy	u_long	rx_length_errors;
171181643Skmacy	u_long	rx_over_errors;		/* receiver ring buff overflow	*/
172181643Skmacy	u_long	rx_crc_errors;		/* recved pkt with crc error	*/
173181643Skmacy	u_long	rx_frame_errors;	/* recv'd frame alignment error */
174181643Skmacy	u_long	rx_fifo_errors;		/* recv'r fifo overrun		*/
175181643Skmacy	u_long	rx_missed_errors;	/* receiver missed packet	*/
176181643Skmacy
177181643Skmacy	/* detailed tx_errors */
178181643Skmacy	u_long	tx_aborted_errors;
179181643Skmacy	u_long	tx_carrier_errors;
180181643Skmacy	u_long	tx_fifo_errors;
181181643Skmacy	u_long	tx_heartbeat_errors;
182181643Skmacy	u_long	tx_window_errors;
183181643Skmacy
184181643Skmacy	/* for cslip etc */
185181643Skmacy	u_long	rx_compressed;
186181643Skmacy	u_long	tx_compressed;
187181643Skmacy};
188181643Skmacy
189181643Skmacystruct netfront_info {
190181643Skmacy
191181643Skmacy	struct ifnet *xn_ifp;
192181643Skmacy
193181643Skmacy	struct net_device_stats stats;
194181643Skmacy	u_int tx_full;
195181643Skmacy
196181643Skmacy	netif_tx_front_ring_t tx;
197181643Skmacy	netif_rx_front_ring_t rx;
198181643Skmacy
199181643Skmacy	struct mtx   tx_lock;
200181643Skmacy	struct mtx   rx_lock;
201181643Skmacy	struct sx    sc_lock;
202181643Skmacy
203181643Skmacy	u_int handle;
204181643Skmacy	u_int irq;
205181643Skmacy	u_int copying_receiver;
206181643Skmacy	u_int carrier;
207181643Skmacy
208181643Skmacy	/* Receive-ring batched refills. */
209181643Skmacy#define RX_MIN_TARGET 32
210181643Skmacy#define RX_MAX_TARGET NET_RX_RING_SIZE
211181643Skmacy	int rx_min_target, rx_max_target, rx_target;
212181643Skmacy
213181643Skmacy	/*
214181643Skmacy	 * {tx,rx}_skbs store outstanding skbuffs. The first entry in each
215181643Skmacy	 * array is an index into a chain of free entries.
216181643Skmacy	 */
217181643Skmacy
218181643Skmacy	grant_ref_t gref_tx_head;
219181643Skmacy	grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1];
220181643Skmacy	grant_ref_t gref_rx_head;
221181643Skmacy	grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1];
222181643Skmacy
223181643Skmacy#define TX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
224181643Skmacy	struct xenbus_device *xbdev;
225181643Skmacy	int tx_ring_ref;
226181643Skmacy	int rx_ring_ref;
227181643Skmacy	uint8_t mac[ETHER_ADDR_LEN];
228181643Skmacy	struct xn_chain_data	xn_cdata;	/* mbufs */
229181643Skmacy	struct mbuf_head xn_rx_batch;	/* head of the batch queue */
230181643Skmacy
231181643Skmacy	int			xn_if_flags;
232181643Skmacy	struct callout	        xn_stat_ch;
233181643Skmacy
234181643Skmacy	u_long rx_pfn_array[NET_RX_RING_SIZE];
235181643Skmacy	multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1];
236181643Skmacy	mmu_update_t rx_mmu[NET_RX_RING_SIZE];
237181643Skmacy};
238181643Skmacy
239181643Skmacy#define rx_mbufs xn_cdata.xn_rx_chain
240181643Skmacy#define tx_mbufs xn_cdata.xn_tx_chain
241181643Skmacy
242181643Skmacy#define XN_LOCK_INIT(_sc, _name) \
243181643Skmacy        mtx_init(&(_sc)->tx_lock, #_name"_tx", "network transmit lock", MTX_DEF); \
244181643Skmacy        mtx_init(&(_sc)->rx_lock, #_name"_rx", "network receive lock", MTX_DEF);  \
245181643Skmacy        sx_init(&(_sc)->sc_lock, #_name"_rx")
246181643Skmacy
247181643Skmacy#define XN_RX_LOCK(_sc)           mtx_lock(&(_sc)->rx_lock)
248181643Skmacy#define XN_RX_UNLOCK(_sc)         mtx_unlock(&(_sc)->rx_lock)
249181643Skmacy
250181643Skmacy#define XN_TX_LOCK(_sc)           mtx_lock(&(_sc)->tx_lock)
251181643Skmacy#define XN_TX_UNLOCK(_sc)         mtx_unlock(&(_sc)->tx_lock)
252181643Skmacy
253181643Skmacy#define XN_LOCK(_sc)           sx_xlock(&(_sc)->sc_lock);
254181643Skmacy#define XN_UNLOCK(_sc)         sx_xunlock(&(_sc)->sc_lock);
255181643Skmacy
256181643Skmacy#define XN_LOCK_ASSERT(_sc)    sx_assert(&(_sc)->sc_lock, SX_LOCKED);
257181643Skmacy#define XN_RX_LOCK_ASSERT(_sc)    mtx_assert(&(_sc)->rx_lock, MA_OWNED);
258181643Skmacy#define XN_TX_LOCK_ASSERT(_sc)    mtx_assert(&(_sc)->tx_lock, MA_OWNED);
259181643Skmacy#define XN_LOCK_DESTROY(_sc)   mtx_destroy(&(_sc)->rx_lock); \
260181643Skmacy                               mtx_destroy(&(_sc)->tx_lock); \
261181643Skmacy                               sx_destroy(&(_sc)->sc_lock);
262181643Skmacy
263181643Skmacystruct netfront_rx_info {
264181643Skmacy	struct netif_rx_response rx;
265181643Skmacy	struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
266181643Skmacy};
267181643Skmacy
268181643Skmacy#define netfront_carrier_on(netif)	((netif)->carrier = 1)
269181643Skmacy#define netfront_carrier_off(netif)	((netif)->carrier = 0)
270181643Skmacy#define netfront_carrier_ok(netif)	((netif)->carrier)
271181643Skmacy
272181643Skmacy/* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */
273181643Skmacy
274181643Skmacy
275181643Skmacy
276181643Skmacy/*
277181643Skmacy * Access macros for acquiring freeing slots in tx_skbs[].
278181643Skmacy */
279181643Skmacy
280181643Skmacystatic inline void
281181643Skmacyadd_id_to_freelist(struct mbuf **list, unsigned short id)
282181643Skmacy{
283181643Skmacy	list[id] = list[0];
284181643Skmacy	list[0]  = (void *)(u_long)id;
285181643Skmacy}
286181643Skmacy
287181643Skmacystatic inline unsigned short
288181643Skmacyget_id_from_freelist(struct mbuf **list)
289181643Skmacy{
290181643Skmacy	u_int id = (u_int)(u_long)list[0];
291181643Skmacy	list[0] = list[id];
292181643Skmacy	return (id);
293181643Skmacy}
294181643Skmacy
295181643Skmacystatic inline int
296181643Skmacyxennet_rxidx(RING_IDX idx)
297181643Skmacy{
298181643Skmacy	return idx & (NET_RX_RING_SIZE - 1);
299181643Skmacy}
300181643Skmacy
301181643Skmacystatic inline struct mbuf *
302181643Skmacyxennet_get_rx_mbuf(struct netfront_info *np,
303181643Skmacy						RING_IDX ri)
304181643Skmacy{
305181643Skmacy	int i = xennet_rxidx(ri);
306181643Skmacy	struct mbuf *m;
307181643Skmacy
308181643Skmacy	m = np->rx_mbufs[i];
309181643Skmacy	np->rx_mbufs[i] = NULL;
310181643Skmacy	return (m);
311181643Skmacy}
312181643Skmacy
313181643Skmacystatic inline grant_ref_t
314181643Skmacyxennet_get_rx_ref(struct netfront_info *np, RING_IDX ri)
315181643Skmacy{
316181643Skmacy	int i = xennet_rxidx(ri);
317181643Skmacy	grant_ref_t ref = np->grant_rx_ref[i];
318181643Skmacy	np->grant_rx_ref[i] = GRANT_INVALID_REF;
319181643Skmacy	return ref;
320181643Skmacy}
321181643Skmacy
322181643Skmacy#ifdef DEBUG
323181643Skmacy
324181643Skmacy#endif
325181643Skmacy#define IPRINTK(fmt, args...) \
326181643Skmacy    printf("[XEN] " fmt, ##args)
327181643Skmacy#define WPRINTK(fmt, args...) \
328181643Skmacy    printf("[XEN] " fmt, ##args)
329181643Skmacy#define DPRINTK(fmt, args...) \
330181643Skmacy    printf("[XEN] " fmt, ##args)
331181643Skmacy
332181643Skmacy
333181643Skmacystatic __inline struct mbuf*
334181643Skmacymakembuf (struct mbuf *buf)
335181643Skmacy{
336181643Skmacy	struct mbuf *m = NULL;
337181643Skmacy
338181643Skmacy        MGETHDR (m, M_DONTWAIT, MT_DATA);
339181643Skmacy
340181643Skmacy        if (! m)
341181643Skmacy		return 0;
342181643Skmacy
343181643Skmacy		M_MOVE_PKTHDR(m, buf);
344181643Skmacy
345181643Skmacy		m_cljget(m, M_DONTWAIT, MJUMPAGESIZE);
346181643Skmacy        m->m_pkthdr.len = buf->m_pkthdr.len;
347181643Skmacy        m->m_len = buf->m_len;
348181643Skmacy		m_copydata(buf, 0, buf->m_pkthdr.len, mtod(m,caddr_t) );
349181643Skmacy
350181643Skmacy		m->m_ext.ext_arg1 = (caddr_t *)(uintptr_t)(vtophys(mtod(m,caddr_t)) >> PAGE_SHIFT);
351181643Skmacy
352181643Skmacy       	return m;
353181643Skmacy}
354181643Skmacy
355181643Skmacy/**
356181643Skmacy * Read the 'mac' node at the given device's node in the store, and parse that
357181643Skmacy * as colon-separated octets, placing result the given mac array.  mac must be
358181643Skmacy * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h).
359181643Skmacy * Return 0 on success, or errno on error.
360181643Skmacy */
361181643Skmacystatic int
362181643Skmacyxen_net_read_mac(struct xenbus_device *dev, uint8_t mac[])
363181643Skmacy{
364181643Skmacy	char *s;
365181643Skmacy	int i;
366181643Skmacy	char *e;
367181643Skmacy	char *macstr = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
368181643Skmacy	if (IS_ERR(macstr)) {
369181643Skmacy		return PTR_ERR(macstr);
370181643Skmacy	}
371181643Skmacy	s = macstr;
372181643Skmacy	for (i = 0; i < ETHER_ADDR_LEN; i++) {
373181643Skmacy		mac[i] = strtoul(s, &e, 16);
374181643Skmacy		if (s == e || (e[0] != ':' && e[0] != 0)) {
375181643Skmacy			free(macstr, M_DEVBUF);
376181643Skmacy			return ENOENT;
377181643Skmacy		}
378181643Skmacy		s = &e[1];
379181643Skmacy	}
380181643Skmacy	free(macstr, M_DEVBUF);
381181643Skmacy	return 0;
382181643Skmacy}
383181643Skmacy
384181643Skmacy/**
385181643Skmacy * Entry point to this code when a new device is created.  Allocate the basic
386181643Skmacy * structures and the ring buffers for communication with the backend, and
387181643Skmacy * inform the backend of the appropriate details for those.  Switch to
388181643Skmacy * Connected state.
389181643Skmacy */
390181643Skmacystatic int
391181643Skmacynetfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id)
392181643Skmacy{
393181643Skmacy	int err;
394181643Skmacy	struct ifnet *ifp;
395181643Skmacy	struct netfront_info *info;
396181643Skmacy
397181643Skmacy	printf("netfront_probe() \n");
398181643Skmacy
399181643Skmacy	err = create_netdev(dev, &ifp);
400181643Skmacy	if (err) {
401181643Skmacy		xenbus_dev_fatal(dev, err, "creating netdev");
402181643Skmacy		return err;
403181643Skmacy	}
404181643Skmacy
405181643Skmacy	info = ifp->if_softc;
406181643Skmacy	dev->dev_driver_data = info;
407181643Skmacy
408181643Skmacy	return 0;
409181643Skmacy}
410181643Skmacy
411181643Skmacy
412181643Skmacy/**
413181643Skmacy * We are reconnecting to the backend, due to a suspend/resume, or a backend
414181643Skmacy * driver restart.  We tear down our netif structure and recreate it, but
415181643Skmacy * leave the device-layer structures intact so that this is transparent to the
416181643Skmacy * rest of the kernel.
417181643Skmacy */
418181643Skmacystatic int
419181643Skmacynetfront_resume(struct xenbus_device *dev)
420181643Skmacy{
421181643Skmacy	struct netfront_info *info = dev->dev_driver_data;
422181643Skmacy
423181643Skmacy	DPRINTK("%s\n", dev->nodename);
424181643Skmacy
425181643Skmacy	netif_disconnect_backend(info);
426181643Skmacy	return (0);
427181643Skmacy}
428181643Skmacy
429181643Skmacy
430181643Skmacy/* Common code used when first setting up, and when resuming. */
431181643Skmacystatic int
432181643Skmacytalk_to_backend(struct xenbus_device *dev, struct netfront_info *info)
433181643Skmacy{
434181643Skmacy	const char *message;
435181643Skmacy	struct xenbus_transaction xbt;
436181643Skmacy	int err;
437181643Skmacy
438181643Skmacy	err = xen_net_read_mac(dev, info->mac);
439181643Skmacy	if (err) {
440181643Skmacy		xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
441181643Skmacy		goto out;
442181643Skmacy	}
443181643Skmacy
444181643Skmacy	/* Create shared ring, alloc event channel. */
445181643Skmacy	err = setup_device(dev, info);
446181643Skmacy	if (err)
447181643Skmacy		goto out;
448181643Skmacy
449181643Skmacy again:
450181643Skmacy	err = xenbus_transaction_start(&xbt);
451181643Skmacy	if (err) {
452181643Skmacy		xenbus_dev_fatal(dev, err, "starting transaction");
453181643Skmacy		goto destroy_ring;
454181643Skmacy	}
455181643Skmacy	err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u",
456181643Skmacy			    info->tx_ring_ref);
457181643Skmacy	if (err) {
458181643Skmacy		message = "writing tx ring-ref";
459181643Skmacy		goto abort_transaction;
460181643Skmacy	}
461181643Skmacy	err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u",
462181643Skmacy			    info->rx_ring_ref);
463181643Skmacy	if (err) {
464181643Skmacy		message = "writing rx ring-ref";
465181643Skmacy		goto abort_transaction;
466181643Skmacy	}
467181643Skmacy	err = xenbus_printf(xbt, dev->nodename,
468181643Skmacy		"event-channel", "%u", irq_to_evtchn_port(info->irq));
469181643Skmacy	if (err) {
470181643Skmacy		message = "writing event-channel";
471181643Skmacy		goto abort_transaction;
472181643Skmacy	}
473181643Skmacy	err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
474181643Skmacy			    info->copying_receiver);
475181643Skmacy	if (err) {
476181643Skmacy		message = "writing request-rx-copy";
477181643Skmacy		goto abort_transaction;
478181643Skmacy	}
479181643Skmacy	err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
480181643Skmacy	if (err) {
481181643Skmacy		message = "writing feature-rx-notify";
482181643Skmacy		goto abort_transaction;
483181643Skmacy	}
484181643Skmacy	err = xenbus_printf(xbt, dev->nodename, "feature-no-csum-offload", "%d", 1);
485181643Skmacy	if (err) {
486181643Skmacy		message = "writing feature-no-csum-offload";
487181643Skmacy		goto abort_transaction;
488181643Skmacy	}
489181643Skmacy	err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
490181643Skmacy	if (err) {
491181643Skmacy		message = "writing feature-sg";
492181643Skmacy		goto abort_transaction;
493181643Skmacy	}
494181643Skmacy#ifdef HAVE_TSO
495181643Skmacy	err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
496181643Skmacy	if (err) {
497181643Skmacy		message = "writing feature-gso-tcpv4";
498181643Skmacy		goto abort_transaction;
499181643Skmacy	}
500181643Skmacy#endif
501181643Skmacy
502181643Skmacy	err = xenbus_transaction_end(xbt, 0);
503181643Skmacy	if (err) {
504181643Skmacy		if (err == EAGAIN)
505181643Skmacy			goto again;
506181643Skmacy		xenbus_dev_fatal(dev, err, "completing transaction");
507181643Skmacy		goto destroy_ring;
508181643Skmacy	}
509181643Skmacy
510181643Skmacy	return 0;
511181643Skmacy
512181643Skmacy abort_transaction:
513181643Skmacy	xenbus_transaction_end(xbt, 1);
514181643Skmacy	xenbus_dev_fatal(dev, err, "%s", message);
515181643Skmacy destroy_ring:
516181643Skmacy	netif_free(info);
517181643Skmacy out:
518181643Skmacy	return err;
519181643Skmacy}
520181643Skmacy
521181643Skmacy
522181643Skmacystatic int
523181643Skmacysetup_device(struct xenbus_device *dev, struct netfront_info *info)
524181643Skmacy{
525181643Skmacy	netif_tx_sring_t *txs;
526181643Skmacy	netif_rx_sring_t *rxs;
527181643Skmacy	int err;
528181643Skmacy	struct ifnet *ifp;
529181643Skmacy
530181643Skmacy	ifp = info->xn_ifp;
531181643Skmacy
532181643Skmacy	info->tx_ring_ref = GRANT_INVALID_REF;
533181643Skmacy	info->rx_ring_ref = GRANT_INVALID_REF;
534181643Skmacy	info->rx.sring = NULL;
535181643Skmacy	info->tx.sring = NULL;
536181643Skmacy	info->irq = 0;
537181643Skmacy
538181643Skmacy	txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO);
539181643Skmacy	if (!txs) {
540181643Skmacy		err = ENOMEM;
541181643Skmacy		xenbus_dev_fatal(dev, err, "allocating tx ring page");
542181643Skmacy		goto fail;
543181643Skmacy	}
544181643Skmacy	SHARED_RING_INIT(txs);
545181643Skmacy	FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
546181643Skmacy	err = xenbus_grant_ring(dev, virt_to_mfn(txs));
547181643Skmacy	if (err < 0)
548181643Skmacy		goto fail;
549181643Skmacy	info->tx_ring_ref = err;
550181643Skmacy
551181643Skmacy	rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO);
552181643Skmacy	if (!rxs) {
553181643Skmacy		err = ENOMEM;
554181643Skmacy		xenbus_dev_fatal(dev, err, "allocating rx ring page");
555181643Skmacy		goto fail;
556181643Skmacy	}
557181643Skmacy	SHARED_RING_INIT(rxs);
558181643Skmacy	FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
559181643Skmacy
560181643Skmacy	err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
561181643Skmacy	if (err < 0)
562181643Skmacy		goto fail;
563181643Skmacy	info->rx_ring_ref = err;
564181643Skmacy
565181643Skmacy#if 0
566181643Skmacy	network_connect(ifp);
567181643Skmacy#endif
568181643Skmacy	err = bind_listening_port_to_irqhandler(dev->otherend_id,
569181643Skmacy		"xn", xn_intr, info, INTR_TYPE_NET | INTR_MPSAFE, NULL);
570181643Skmacy
571181643Skmacy	if (err <= 0) {
572181643Skmacy		xenbus_dev_fatal(dev, err,
573181643Skmacy				 "bind_evtchn_to_irqhandler failed");
574181643Skmacy		goto fail;
575181643Skmacy	}
576181643Skmacy	info->irq = err;
577181643Skmacy
578181643Skmacy	show_device(info);
579181643Skmacy
580181643Skmacy	return 0;
581181643Skmacy
582181643Skmacy fail:
583181643Skmacy	netif_free(info);
584181643Skmacy	return err;
585181643Skmacy}
586181643Skmacy
587181643Skmacy/**
588181643Skmacy * Callback received when the backend's state changes.
589181643Skmacy */
590181643Skmacystatic void
591181643Skmacybackend_changed(struct xenbus_device *dev,
592181643Skmacy			    XenbusState backend_state)
593181643Skmacy{
594181643Skmacy		struct netfront_info *sc = dev->dev_driver_data;
595181643Skmacy
596181643Skmacy	DPRINTK("\n");
597181643Skmacy
598181643Skmacy	switch (backend_state) {
599181643Skmacy	case XenbusStateInitialising:
600181643Skmacy	case XenbusStateInitialised:
601181643Skmacy	case XenbusStateConnected:
602181643Skmacy	case XenbusStateUnknown:
603181643Skmacy	case XenbusStateClosed:
604183375Skmacy	case XenbusStateReconfigured:
605183375Skmacy	case XenbusStateReconfiguring:
606181643Skmacy			break;
607181643Skmacy	case XenbusStateInitWait:
608181643Skmacy		if (dev->state != XenbusStateInitialising)
609181643Skmacy			break;
610181643Skmacy		if (network_connect(sc->xn_ifp) != 0)
611181643Skmacy			break;
612181643Skmacy		xenbus_switch_state(dev, XenbusStateConnected);
613181643Skmacy#ifdef notyet
614181643Skmacy		(void)send_fake_arp(netdev);
615181643Skmacy#endif
616181643Skmacy		break;	break;
617181643Skmacy	case XenbusStateClosing:
618181643Skmacy			xenbus_frontend_closed(dev);
619181643Skmacy		break;
620181643Skmacy	}
621181643Skmacy}
622181643Skmacy
623181643Skmacystatic void
624181643Skmacyxn_free_rx_ring(struct netfront_info *sc)
625181643Skmacy{
626181643Skmacy#if 0
627181643Skmacy	int i;
628181643Skmacy
629181643Skmacy	for (i = 0; i < NET_RX_RING_SIZE; i++) {
630181643Skmacy		if (sc->xn_cdata.xn_rx_chain[i] != NULL) {
631181643Skmacy			m_freem(sc->xn_cdata.xn_rx_chain[i]);
632181643Skmacy			sc->xn_cdata.xn_rx_chain[i] = NULL;
633181643Skmacy		}
634181643Skmacy	}
635181643Skmacy
636181643Skmacy	sc->rx.rsp_cons = 0;
637181643Skmacy	sc->xn_rx_if->req_prod = 0;
638181643Skmacy	sc->xn_rx_if->event = sc->rx.rsp_cons ;
639181643Skmacy#endif
640181643Skmacy}
641181643Skmacy
642181643Skmacystatic void
643181643Skmacyxn_free_tx_ring(struct netfront_info *sc)
644181643Skmacy{
645181643Skmacy#if 0
646181643Skmacy	int i;
647181643Skmacy
648181643Skmacy	for (i = 0; i < NET_TX_RING_SIZE; i++) {
649181643Skmacy		if (sc->xn_cdata.xn_tx_chain[i] != NULL) {
650181643Skmacy			m_freem(sc->xn_cdata.xn_tx_chain[i]);
651181643Skmacy			sc->xn_cdata.xn_tx_chain[i] = NULL;
652181643Skmacy		}
653181643Skmacy	}
654181643Skmacy
655181643Skmacy	return;
656181643Skmacy#endif
657181643Skmacy}
658181643Skmacy
659181643Skmacystatic inline int
660181643Skmacynetfront_tx_slot_available(struct netfront_info *np)
661181643Skmacy{
662181643Skmacy	return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
663181643Skmacy		(TX_MAX_TARGET - /* MAX_SKB_FRAGS */ 24 - 2));
664181643Skmacy}
665181643Skmacystatic void
666181643Skmacynetif_release_tx_bufs(struct netfront_info *np)
667181643Skmacy{
668181643Skmacy	struct mbuf *m;
669181643Skmacy	int i;
670181643Skmacy
671181643Skmacy	for (i = 1; i <= NET_TX_RING_SIZE; i++) {
672181643Skmacy		m = np->xn_cdata.xn_tx_chain[i];
673181643Skmacy
674181643Skmacy		if (((u_long)m) < KERNBASE)
675181643Skmacy			continue;
676181643Skmacy		gnttab_grant_foreign_access_ref(np->grant_tx_ref[i],
677181643Skmacy		    np->xbdev->otherend_id, virt_to_mfn(mtod(m, vm_offset_t)),
678181643Skmacy		    GNTMAP_readonly);
679181643Skmacy		gnttab_release_grant_reference(&np->gref_tx_head,
680181643Skmacy		    np->grant_tx_ref[i]);
681181643Skmacy		np->grant_tx_ref[i] = GRANT_INVALID_REF;
682181643Skmacy		add_id_to_freelist(np->tx_mbufs, i);
683181643Skmacy		m_freem(m);
684181643Skmacy	}
685181643Skmacy}
686181643Skmacy
687181643Skmacystatic void
688181643Skmacynetwork_alloc_rx_buffers(struct netfront_info *sc)
689181643Skmacy{
690181643Skmacy	unsigned short id;
691181643Skmacy	struct mbuf *m_new;
692181643Skmacy	int i, batch_target, notify;
693181643Skmacy	RING_IDX req_prod;
694181643Skmacy	struct xen_memory_reservation reservation;
695181643Skmacy	grant_ref_t ref;
696181643Skmacy	int nr_flips;
697181643Skmacy	netif_rx_request_t *req;
698181643Skmacy	vm_offset_t vaddr;
699181643Skmacy	u_long pfn;
700181643Skmacy
701181643Skmacy	req_prod = sc->rx.req_prod_pvt;
702181643Skmacy
703181643Skmacy	if (unlikely(sc->carrier == 0))
704181643Skmacy		return;
705181643Skmacy
706181643Skmacy	/*
707181643Skmacy	 * Allocate skbuffs greedily, even though we batch updates to the
708181643Skmacy	 * receive ring. This creates a less bursty demand on the memory
709181643Skmacy	 * allocator, so should reduce the chance of failed allocation
710181643Skmacy	 * requests both for ourself and for other kernel subsystems.
711181643Skmacy	 */
712181643Skmacy	batch_target = sc->rx_target - (req_prod - sc->rx.rsp_cons);
713181643Skmacy	for (i = mbufq_len(&sc->xn_rx_batch); i < batch_target; i++) {
714181643Skmacy		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
715181643Skmacy		if (m_new == NULL)
716181643Skmacy			goto no_mbuf;
717181643Skmacy
718181643Skmacy		m_cljget(m_new, M_DONTWAIT, MJUMPAGESIZE);
719181643Skmacy		if ((m_new->m_flags & M_EXT) == 0) {
720181643Skmacy			m_freem(m_new);
721181643Skmacy
722181643Skmacyno_mbuf:
723181643Skmacy			if (i != 0)
724181643Skmacy				goto refill;
725181643Skmacy			/*
726181643Skmacy			 * XXX set timer
727181643Skmacy			 */
728181643Skmacy			break;
729181643Skmacy		}
730181643Skmacy		m_new->m_len = m_new->m_pkthdr.len = MJUMPAGESIZE;
731181643Skmacy
732181643Skmacy		/* queue the mbufs allocated */
733181643Skmacy		mbufq_tail(&sc->xn_rx_batch, m_new);
734181643Skmacy	}
735181643Skmacy
736181643Skmacy	/* Is the batch large enough to be worthwhile? */
737181643Skmacy	if (i < (sc->rx_target/2)) {
738181643Skmacy		if (req_prod >sc->rx.sring->req_prod)
739181643Skmacy			goto push;
740181643Skmacy		return;
741181643Skmacy	}
742181643Skmacy	/* Adjust floating fill target if we risked running out of buffers. */
743181643Skmacy	if ( ((req_prod - sc->rx.sring->rsp_prod) < (sc->rx_target / 4)) &&
744181643Skmacy	     ((sc->rx_target *= 2) > sc->rx_max_target) )
745181643Skmacy		sc->rx_target = sc->rx_max_target;
746181643Skmacy
747181643Skmacyrefill:
748181643Skmacy	for (nr_flips = i = 0; ; i++) {
749181643Skmacy		if ((m_new = mbufq_dequeue(&sc->xn_rx_batch)) == NULL)
750181643Skmacy			break;
751181643Skmacy
752181643Skmacy		m_new->m_ext.ext_arg1 = (vm_paddr_t *)(uintptr_t)(
753181945Skmacy				vtophys(m_new->m_ext.ext_buf) >> PAGE_SHIFT);
754181643Skmacy
755181643Skmacy		id = xennet_rxidx(req_prod + i);
756181643Skmacy
757181643Skmacy		KASSERT(sc->xn_cdata.xn_rx_chain[id] == NULL,
758181643Skmacy		    ("non-NULL xm_rx_chain"));
759181643Skmacy		sc->xn_cdata.xn_rx_chain[id] = m_new;
760181643Skmacy
761181643Skmacy		ref = gnttab_claim_grant_reference(&sc->gref_rx_head);
762181643Skmacy		KASSERT((short)ref >= 0, ("negative ref"));
763181643Skmacy		sc->grant_rx_ref[id] = ref;
764181643Skmacy
765181643Skmacy		vaddr = mtod(m_new, vm_offset_t);
766181643Skmacy		pfn = vtophys(vaddr) >> PAGE_SHIFT;
767181643Skmacy		req = RING_GET_REQUEST(&sc->rx, req_prod + i);
768181643Skmacy
769181643Skmacy		if (sc->copying_receiver == 0) {
770181643Skmacy			gnttab_grant_foreign_transfer_ref(ref,
771181643Skmacy			    sc->xbdev->otherend_id, pfn);
772181643Skmacy			sc->rx_pfn_array[nr_flips] = PFNTOMFN(pfn);
773181643Skmacy			if (!xen_feature(XENFEAT_auto_translated_physmap)) {
774181643Skmacy				/* Remove this page before passing
775181643Skmacy				 * back to Xen.
776181643Skmacy				 */
777181643Skmacy				set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
778181643Skmacy				MULTI_update_va_mapping(&sc->rx_mcl[i],
779181643Skmacy				    vaddr, 0, 0);
780181643Skmacy			}
781181643Skmacy			nr_flips++;
782181643Skmacy		} else {
783181643Skmacy			gnttab_grant_foreign_access_ref(ref,
784181643Skmacy			    sc->xbdev->otherend_id,
785181643Skmacy			    PFNTOMFN(pfn), 0);
786181643Skmacy		}
787181643Skmacy		req->id = id;
788181643Skmacy		req->gref = ref;
789181643Skmacy
790181643Skmacy		sc->rx_pfn_array[i] =
791181643Skmacy		    vtomach(mtod(m_new,vm_offset_t)) >> PAGE_SHIFT;
792181643Skmacy	}
793181643Skmacy
794181643Skmacy	KASSERT(i, ("no mbufs processed")); /* should have returned earlier */
795181643Skmacy	KASSERT(mbufq_len(&sc->xn_rx_batch) == 0, ("not all mbufs processed"));
796181643Skmacy	/*
797181643Skmacy	 * We may have allocated buffers which have entries outstanding
798181643Skmacy	 * in the page * update queue -- make sure we flush those first!
799181643Skmacy	 */
800181643Skmacy	PT_UPDATES_FLUSH();
801181643Skmacy	if (nr_flips != 0) {
802181643Skmacy#ifdef notyet
803181643Skmacy		/* Tell the ballon driver what is going on. */
804181643Skmacy		balloon_update_driver_allowance(i);
805181643Skmacy#endif
806183375Skmacy		set_xen_guest_handle(reservation.extent_start, sc->rx_pfn_array);
807181643Skmacy		reservation.nr_extents   = i;
808181643Skmacy		reservation.extent_order = 0;
809181643Skmacy		reservation.address_bits = 0;
810181643Skmacy		reservation.domid        = DOMID_SELF;
811181643Skmacy
812181643Skmacy		if (!xen_feature(XENFEAT_auto_translated_physmap)) {
813181643Skmacy
814181643Skmacy			/* After all PTEs have been zapped, flush the TLB. */
815181643Skmacy			sc->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
816181643Skmacy			    UVMF_TLB_FLUSH|UVMF_ALL;
817181643Skmacy
818181643Skmacy			/* Give away a batch of pages. */
819181643Skmacy			sc->rx_mcl[i].op = __HYPERVISOR_memory_op;
820181643Skmacy			sc->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
821181643Skmacy			sc->rx_mcl[i].args[1] =  (u_long)&reservation;
822181643Skmacy			/* Zap PTEs and give away pages in one big multicall. */
823181643Skmacy			(void)HYPERVISOR_multicall(sc->rx_mcl, i+1);
824181643Skmacy
825181643Skmacy			/* Check return status of HYPERVISOR_dom_mem_op(). */
826181643Skmacy			if (unlikely(sc->rx_mcl[i].result != i))
827181643Skmacy				panic("Unable to reduce memory reservation\n");
828181643Skmacy			} else {
829181643Skmacy				if (HYPERVISOR_memory_op(
830181643Skmacy				    XENMEM_decrease_reservation, &reservation)
831181643Skmacy				    != i)
832181643Skmacy					panic("Unable to reduce memory "
833181643Skmacy					    "reservation\n");
834181643Skmacy		}
835181643Skmacy	} else {
836181643Skmacy		wmb();
837181643Skmacy	}
838181643Skmacy
839181643Skmacy	/* Above is a suitable barrier to ensure backend will see requests. */
840181643Skmacy	sc->rx.req_prod_pvt = req_prod + i;
841181643Skmacypush:
842181643Skmacy	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->rx, notify);
843181643Skmacy	if (notify)
844181643Skmacy		notify_remote_via_irq(sc->irq);
845181643Skmacy}
846181643Skmacy
847181643Skmacystatic void
848181643Skmacyxn_rxeof(struct netfront_info *np)
849181643Skmacy{
850181643Skmacy	struct ifnet *ifp;
851181643Skmacy	struct netfront_rx_info rinfo;
852181643Skmacy	struct netif_rx_response *rx = &rinfo.rx;
853181643Skmacy	struct netif_extra_info *extras = rinfo.extras;
854181643Skmacy	RING_IDX i, rp;
855181643Skmacy	multicall_entry_t *mcl;
856181643Skmacy	struct mbuf *m;
857181945Skmacy	struct mbuf_head rxq, errq;
858185473Sdfr	int err, pages_flipped = 0, work_to_do;
859181643Skmacy
860185473Sdfr	do {
861185473Sdfr		XN_RX_LOCK_ASSERT(np);
862185473Sdfr		if (!netfront_carrier_ok(np))
863185473Sdfr			return;
864181643Skmacy
865185473Sdfr		mbufq_init(&errq);
866185473Sdfr		mbufq_init(&rxq);
867181643Skmacy
868185473Sdfr		ifp = np->xn_ifp;
869181643Skmacy
870185473Sdfr		rp = np->rx.sring->rsp_prod;
871185473Sdfr		rmb();	/* Ensure we see queued responses up to 'rp'. */
872181643Skmacy
873185473Sdfr		i = np->rx.rsp_cons;
874185473Sdfr		while ((i != rp)) {
875185473Sdfr			memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
876185473Sdfr			memset(extras, 0, sizeof(rinfo.extras));
877181643Skmacy
878185473Sdfr			m = NULL;
879185473Sdfr			err = xennet_get_responses(np, &rinfo, rp, &m,
880185473Sdfr			    &pages_flipped);
881181643Skmacy
882185473Sdfr			if (unlikely(err)) {
883181945Skmacy				if (m)
884185473Sdfr					mbufq_tail(&errq, m);
885185473Sdfr				np->stats.rx_errors++;
886185473Sdfr				i = np->rx.rsp_cons;
887185473Sdfr				continue;
888185473Sdfr			}
889181643Skmacy
890185473Sdfr			m->m_pkthdr.rcvif = ifp;
891185473Sdfr			if ( rx->flags & NETRXF_data_validated ) {
892185473Sdfr				/* Tell the stack the checksums are okay */
893185473Sdfr				/*
894185473Sdfr				 * XXX this isn't necessarily the case - need to add
895185473Sdfr				 * check
896185473Sdfr				 */
897181643Skmacy
898185473Sdfr				m->m_pkthdr.csum_flags |=
899185473Sdfr					(CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID
900185473Sdfr					    | CSUM_PSEUDO_HDR);
901185473Sdfr				m->m_pkthdr.csum_data = 0xffff;
902185473Sdfr			}
903181643Skmacy
904185473Sdfr			np->stats.rx_packets++;
905185473Sdfr			np->stats.rx_bytes += m->m_pkthdr.len;
906181643Skmacy
907185473Sdfr			mbufq_tail(&rxq, m);
908185473Sdfr			np->rx.rsp_cons = ++i;
909185473Sdfr		}
910181643Skmacy
911185473Sdfr		if (pages_flipped) {
912185473Sdfr			/* Some pages are no longer absent... */
913181643Skmacy#ifdef notyet
914185473Sdfr			balloon_update_driver_allowance(-pages_flipped);
915181643Skmacy#endif
916185473Sdfr			/* Do all the remapping work, and M->P updates, in one big
917185473Sdfr			 * hypercall.
918185473Sdfr			 */
919185473Sdfr			if (!!xen_feature(XENFEAT_auto_translated_physmap)) {
920185473Sdfr				mcl = np->rx_mcl + pages_flipped;
921185473Sdfr				mcl->op = __HYPERVISOR_mmu_update;
922185473Sdfr				mcl->args[0] = (u_long)np->rx_mmu;
923185473Sdfr				mcl->args[1] = pages_flipped;
924185473Sdfr				mcl->args[2] = 0;
925185473Sdfr				mcl->args[3] = DOMID_SELF;
926185473Sdfr				(void)HYPERVISOR_multicall(np->rx_mcl,
927185473Sdfr				    pages_flipped + 1);
928185473Sdfr			}
929181643Skmacy		}
930181643Skmacy
931185473Sdfr		while ((m = mbufq_dequeue(&errq)))
932185473Sdfr			m_freem(m);
933181643Skmacy
934185473Sdfr		/*
935185473Sdfr		 * Process all the mbufs after the remapping is complete.
936185473Sdfr		 * Break the mbuf chain first though.
937185473Sdfr		 */
938185473Sdfr		while ((m = mbufq_dequeue(&rxq)) != NULL) {
939185473Sdfr			ifp->if_ipackets++;
940181643Skmacy
941185473Sdfr			/*
942185473Sdfr			 * Do we really need to drop the rx lock?
943185473Sdfr			 */
944185473Sdfr			XN_RX_UNLOCK(np);
945185473Sdfr			/* Pass it up. */
946185473Sdfr			(*ifp->if_input)(ifp, m);
947185473Sdfr			XN_RX_LOCK(np);
948185473Sdfr		}
949181643Skmacy
950185473Sdfr		np->rx.rsp_cons = i;
951181643Skmacy
952181643Skmacy#if 0
953185473Sdfr		/* If we get a callback with very few responses, reduce fill target. */
954185473Sdfr		/* NB. Note exponential increase, linear decrease. */
955185473Sdfr		if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
956185473Sdfr			((3*np->rx_target) / 4)) && (--np->rx_target < np->rx_min_target))
957185473Sdfr			np->rx_target = np->rx_min_target;
958181643Skmacy#endif
959181643Skmacy
960185473Sdfr		network_alloc_rx_buffers(np);
961181643Skmacy
962185473Sdfr		RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, work_to_do);
963185473Sdfr	} while (work_to_do);
964181643Skmacy}
965181643Skmacy
966181643Skmacystatic void
967181643Skmacyxn_txeof(struct netfront_info *np)
968181643Skmacy{
969181643Skmacy	RING_IDX i, prod;
970181643Skmacy	unsigned short id;
971181643Skmacy	struct ifnet *ifp;
972181643Skmacy	struct mbuf *m;
973181643Skmacy
974181643Skmacy	XN_TX_LOCK_ASSERT(np);
975181643Skmacy
976181643Skmacy	if (!netfront_carrier_ok(np))
977181643Skmacy		return;
978181643Skmacy
979181643Skmacy	ifp = np->xn_ifp;
980181643Skmacy	ifp->if_timer = 0;
981181643Skmacy
982181643Skmacy	do {
983181643Skmacy		prod = np->tx.sring->rsp_prod;
984181643Skmacy		rmb(); /* Ensure we see responses up to 'rp'. */
985181643Skmacy
986181643Skmacy		for (i = np->tx.rsp_cons; i != prod; i++) {
987181643Skmacy			id = RING_GET_RESPONSE(&np->tx, i)->id;
988181643Skmacy			m = np->xn_cdata.xn_tx_chain[id];
989181643Skmacy
990181643Skmacy			ifp->if_opackets++;
991181643Skmacy			KASSERT(m != NULL, ("mbuf not found in xn_tx_chain"));
992181643Skmacy			M_ASSERTVALID(m);
993181643Skmacy			if (unlikely(gnttab_query_foreign_access(
994181643Skmacy			    np->grant_tx_ref[id]) != 0)) {
995181643Skmacy				printf("network_tx_buf_gc: warning "
996181643Skmacy				    "-- grant still in use by backend "
997181643Skmacy				    "domain.\n");
998181643Skmacy				goto out;
999181643Skmacy			}
1000181643Skmacy			gnttab_end_foreign_access_ref(
1001183375Skmacy				np->grant_tx_ref[id]);
1002181643Skmacy			gnttab_release_grant_reference(
1003181643Skmacy				&np->gref_tx_head, np->grant_tx_ref[id]);
1004181643Skmacy			np->grant_tx_ref[id] = GRANT_INVALID_REF;
1005181643Skmacy
1006181643Skmacy			np->xn_cdata.xn_tx_chain[id] = NULL;
1007181643Skmacy			add_id_to_freelist(np->xn_cdata.xn_tx_chain, id);
1008181643Skmacy			m_freem(m);
1009181643Skmacy		}
1010181643Skmacy		np->tx.rsp_cons = prod;
1011181643Skmacy
1012181643Skmacy		/*
1013181643Skmacy		 * Set a new event, then check for race with update of
1014181643Skmacy		 * tx_cons. Note that it is essential to schedule a
1015181643Skmacy		 * callback, no matter how few buffers are pending. Even if
1016181643Skmacy		 * there is space in the transmit ring, higher layers may
1017181643Skmacy		 * be blocked because too much data is outstanding: in such
1018181643Skmacy		 * cases notification from Xen is likely to be the only kick
1019181643Skmacy		 * that we'll get.
1020181643Skmacy		 */
1021181643Skmacy		np->tx.sring->rsp_event =
1022181643Skmacy		    prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
1023181643Skmacy
1024181643Skmacy		mb();
1025181643Skmacy
1026181643Skmacy	} while (prod != np->tx.sring->rsp_prod);
1027181643Skmacy
1028181643Skmacy out:
1029181643Skmacy	if (np->tx_full &&
1030181643Skmacy	    ((np->tx.sring->req_prod - prod) < NET_TX_RING_SIZE)) {
1031181643Skmacy		np->tx_full = 0;
1032181643Skmacy#if 0
1033181643Skmacy		if (np->user_state == UST_OPEN)
1034181643Skmacy			netif_wake_queue(dev);
1035181643Skmacy#endif
1036181643Skmacy	}
1037181643Skmacy
1038181643Skmacy}
1039181643Skmacy
1040181643Skmacystatic void
1041181643Skmacyxn_intr(void *xsc)
1042181643Skmacy{
1043181643Skmacy	struct netfront_info *np = xsc;
1044181643Skmacy	struct ifnet *ifp = np->xn_ifp;
1045181643Skmacy
1046181643Skmacy#if 0
1047181643Skmacy	if (!(np->rx.rsp_cons != np->rx.sring->rsp_prod &&
1048181643Skmacy	    likely(netfront_carrier_ok(np)) &&
1049181643Skmacy	    ifp->if_drv_flags & IFF_DRV_RUNNING))
1050181643Skmacy		return;
1051181643Skmacy#endif
1052181643Skmacy	if (np->tx.rsp_cons != np->tx.sring->rsp_prod) {
1053181643Skmacy		XN_TX_LOCK(np);
1054181643Skmacy		xn_txeof(np);
1055181643Skmacy		XN_TX_UNLOCK(np);
1056181643Skmacy	}
1057181643Skmacy
1058181643Skmacy	XN_RX_LOCK(np);
1059181643Skmacy	xn_rxeof(np);
1060181643Skmacy	XN_RX_UNLOCK(np);
1061181643Skmacy
1062181643Skmacy	if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
1063181643Skmacy	    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1064181643Skmacy		xn_start(ifp);
1065181643Skmacy}
1066181643Skmacy
1067181643Skmacy
1068181643Skmacystatic void
1069181643Skmacyxennet_move_rx_slot(struct netfront_info *np, struct mbuf *m,
1070181643Skmacy	grant_ref_t ref)
1071181643Skmacy{
1072181643Skmacy	int new = xennet_rxidx(np->rx.req_prod_pvt);
1073181643Skmacy
1074181643Skmacy	KASSERT(np->rx_mbufs[new] == NULL, ("rx_mbufs != NULL"));
1075181643Skmacy	np->rx_mbufs[new] = m;
1076181643Skmacy	np->grant_rx_ref[new] = ref;
1077181643Skmacy	RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
1078181643Skmacy	RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
1079181643Skmacy	np->rx.req_prod_pvt++;
1080181643Skmacy}
1081181643Skmacy
1082181643Skmacystatic int
1083181643Skmacyxennet_get_extras(struct netfront_info *np,
1084181643Skmacy    struct netif_extra_info *extras, RING_IDX rp)
1085181643Skmacy{
1086181643Skmacy	struct netif_extra_info *extra;
1087181643Skmacy	RING_IDX cons = np->rx.rsp_cons;
1088181643Skmacy
1089181643Skmacy	int err = 0;
1090181643Skmacy
1091181643Skmacy	do {
1092181643Skmacy		struct mbuf *m;
1093181643Skmacy		grant_ref_t ref;
1094181643Skmacy
1095181643Skmacy		if (unlikely(cons + 1 == rp)) {
1096181643Skmacy#if 0
1097181643Skmacy			if (net_ratelimit())
1098181643Skmacy				WPRINTK("Missing extra info\n");
1099181643Skmacy#endif
1100181643Skmacy			err = -EINVAL;
1101181643Skmacy			break;
1102181643Skmacy		}
1103181643Skmacy
1104181643Skmacy		extra = (struct netif_extra_info *)
1105181643Skmacy		RING_GET_RESPONSE(&np->rx, ++cons);
1106181643Skmacy
1107181643Skmacy		if (unlikely(!extra->type ||
1108181643Skmacy			extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
1109181643Skmacy#if 0
1110181643Skmacy			if (net_ratelimit())
1111181643Skmacy				WPRINTK("Invalid extra type: %d\n",
1112181643Skmacy					extra->type);
1113181643Skmacy#endif
1114181643Skmacy			err = -EINVAL;
1115181643Skmacy		} else {
1116181643Skmacy			memcpy(&extras[extra->type - 1], extra, sizeof(*extra));
1117181643Skmacy		}
1118181643Skmacy
1119181643Skmacy		m = xennet_get_rx_mbuf(np, cons);
1120181643Skmacy		ref = xennet_get_rx_ref(np, cons);
1121181643Skmacy		xennet_move_rx_slot(np, m, ref);
1122181643Skmacy	} while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
1123181643Skmacy
1124181643Skmacy	np->rx.rsp_cons = cons;
1125181643Skmacy	return err;
1126181643Skmacy}
1127181643Skmacy
1128181643Skmacystatic int
1129181643Skmacyxennet_get_responses(struct netfront_info *np,
1130181643Skmacy	struct netfront_rx_info *rinfo, RING_IDX rp,
1131181945Skmacy	struct mbuf  **list,
1132181643Skmacy	int *pages_flipped_p)
1133181643Skmacy{
1134181643Skmacy	int pages_flipped = *pages_flipped_p;
1135181643Skmacy	struct mmu_update *mmu;
1136181643Skmacy	struct multicall_entry *mcl;
1137181643Skmacy	struct netif_rx_response *rx = &rinfo->rx;
1138181643Skmacy	struct netif_extra_info *extras = rinfo->extras;
1139181643Skmacy	RING_IDX cons = np->rx.rsp_cons;
1140181945Skmacy	struct mbuf *m, *m0, *m_prev;
1141181643Skmacy	grant_ref_t ref = xennet_get_rx_ref(np, cons);
1142181945Skmacy	int max = 5 /* MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD) */;
1143181643Skmacy	int frags = 1;
1144181643Skmacy	int err = 0;
1145181643Skmacy	u_long ret;
1146181643Skmacy
1147181945Skmacy	m0 = m = m_prev = xennet_get_rx_mbuf(np, cons);
1148181945Skmacy
1149181945Skmacy
1150181643Skmacy	if (rx->flags & NETRXF_extra_info) {
1151181643Skmacy		err = xennet_get_extras(np, extras, rp);
1152181643Skmacy		cons = np->rx.rsp_cons;
1153181643Skmacy	}
1154181643Skmacy
1155181945Skmacy
1156181945Skmacy	if (m0 != NULL) {
1157181945Skmacy			m0->m_pkthdr.len = 0;
1158181945Skmacy			m0->m_next = NULL;
1159181945Skmacy	}
1160181945Skmacy
1161181643Skmacy	for (;;) {
1162181643Skmacy		u_long mfn;
1163181643Skmacy
1164181945Skmacy#if 0
1165181945Skmacy		printf("rx->status=%hd rx->offset=%hu frags=%u\n",
1166181945Skmacy			rx->status, rx->offset, frags);
1167181945Skmacy#endif
1168181643Skmacy		if (unlikely(rx->status < 0 ||
1169181643Skmacy			rx->offset + rx->status > PAGE_SIZE)) {
1170181643Skmacy#if 0
1171181643Skmacy			if (net_ratelimit())
1172181643Skmacy				WPRINTK("rx->offset: %x, size: %u\n",
1173181643Skmacy					rx->offset, rx->status);
1174181643Skmacy#endif
1175181643Skmacy			xennet_move_rx_slot(np, m, ref);
1176181643Skmacy			err = -EINVAL;
1177181643Skmacy			goto next;
1178181643Skmacy		}
1179181945Skmacy
1180181643Skmacy		/*
1181181643Skmacy		 * This definitely indicates a bug, either in this driver or in
1182181643Skmacy		 * the backend driver. In future this should flag the bad
1183181643Skmacy		 * situation to the system controller to reboot the backed.
1184181643Skmacy		 */
1185181643Skmacy		if (ref == GRANT_INVALID_REF) {
1186181643Skmacy#if 0
1187181643Skmacy			if (net_ratelimit())
1188181643Skmacy				WPRINTK("Bad rx response id %d.\n", rx->id);
1189181643Skmacy#endif
1190181643Skmacy			err = -EINVAL;
1191181643Skmacy			goto next;
1192181643Skmacy		}
1193181643Skmacy
1194181643Skmacy		if (!np->copying_receiver) {
1195181643Skmacy			/* Memory pressure, insufficient buffer
1196181643Skmacy			 * headroom, ...
1197181643Skmacy			 */
1198181643Skmacy			if (!(mfn = gnttab_end_foreign_transfer_ref(ref))) {
1199181643Skmacy				if (net_ratelimit())
1200181643Skmacy					WPRINTK("Unfulfilled rx req "
1201181643Skmacy						"(id=%d, st=%d).\n",
1202181643Skmacy						rx->id, rx->status);
1203181643Skmacy				xennet_move_rx_slot(np, m, ref);
1204181643Skmacy				err = -ENOMEM;
1205181643Skmacy				goto next;
1206181643Skmacy			}
1207181643Skmacy
1208181643Skmacy			if (!xen_feature( XENFEAT_auto_translated_physmap)) {
1209181643Skmacy				/* Remap the page. */
1210181643Skmacy				void *vaddr = mtod(m, void *);
1211181643Skmacy				uint32_t pfn;
1212181643Skmacy
1213181643Skmacy				mcl = np->rx_mcl + pages_flipped;
1214181643Skmacy				mmu = np->rx_mmu + pages_flipped;
1215181643Skmacy
1216181643Skmacy				MULTI_update_va_mapping(mcl, (u_long)vaddr,
1217181916Skmacy				    (((vm_paddr_t)mfn) << PAGE_SHIFT) | PG_RW |
1218181643Skmacy				    PG_V | PG_M | PG_A, 0);
1219181643Skmacy				pfn = (uint32_t)m->m_ext.ext_arg1;
1220181643Skmacy				mmu->ptr = ((vm_paddr_t)mfn << PAGE_SHIFT) |
1221181643Skmacy				    MMU_MACHPHYS_UPDATE;
1222181643Skmacy				mmu->val = pfn;
1223181643Skmacy
1224181643Skmacy				set_phys_to_machine(pfn, mfn);
1225181643Skmacy			}
1226181643Skmacy			pages_flipped++;
1227181643Skmacy		} else {
1228183375Skmacy			ret = gnttab_end_foreign_access_ref(ref);
1229181643Skmacy			KASSERT(ret, ("ret != 0"));
1230181643Skmacy		}
1231181643Skmacy
1232181643Skmacy		gnttab_release_grant_reference(&np->gref_rx_head, ref);
1233181643Skmacy
1234181643Skmacynext:
1235181945Skmacy		if (m != NULL) {
1236181945Skmacy				m->m_len = rx->status;
1237181945Skmacy				m->m_data += rx->offset;
1238181945Skmacy				m0->m_pkthdr.len += rx->status;
1239181945Skmacy		}
1240181945Skmacy
1241181643Skmacy		if (!(rx->flags & NETRXF_more_data))
1242181643Skmacy			break;
1243181643Skmacy
1244181643Skmacy		if (cons + frags == rp) {
1245181643Skmacy			if (net_ratelimit())
1246181643Skmacy				WPRINTK("Need more frags\n");
1247181643Skmacy			err = -ENOENT;
1248181643Skmacy				break;
1249181643Skmacy		}
1250181945Skmacy		m_prev = m;
1251181945Skmacy
1252181643Skmacy		rx = RING_GET_RESPONSE(&np->rx, cons + frags);
1253181643Skmacy		m = xennet_get_rx_mbuf(np, cons + frags);
1254181945Skmacy
1255181945Skmacy		m_prev->m_next = m;
1256181945Skmacy		m->m_next = NULL;
1257181643Skmacy		ref = xennet_get_rx_ref(np, cons + frags);
1258181643Skmacy		frags++;
1259181643Skmacy	}
1260181945Skmacy	*list = m0;
1261181643Skmacy
1262181643Skmacy	if (unlikely(frags > max)) {
1263181643Skmacy		if (net_ratelimit())
1264181643Skmacy			WPRINTK("Too many frags\n");
1265181643Skmacy		err = -E2BIG;
1266181643Skmacy	}
1267181643Skmacy
1268181643Skmacy	if (unlikely(err))
1269181643Skmacy		np->rx.rsp_cons = cons + frags;
1270181643Skmacy
1271181643Skmacy	*pages_flipped_p = pages_flipped;
1272181643Skmacy
1273181643Skmacy	return err;
1274181643Skmacy}
1275181643Skmacy
1276181643Skmacystatic void
1277181643Skmacyxn_tick_locked(struct netfront_info *sc)
1278181643Skmacy{
1279181643Skmacy	XN_RX_LOCK_ASSERT(sc);
1280181643Skmacy	callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc);
1281181643Skmacy
1282181643Skmacy	/* XXX placeholder for printing debug information */
1283181643Skmacy
1284181643Skmacy}
1285181643Skmacy
1286181643Skmacy
1287181643Skmacystatic void
1288181643Skmacyxn_tick(void *xsc)
1289181643Skmacy{
1290181643Skmacy	struct netfront_info *sc;
1291181643Skmacy
1292181643Skmacy	sc = xsc;
1293181643Skmacy	XN_RX_LOCK(sc);
1294181643Skmacy	xn_tick_locked(sc);
1295181643Skmacy	XN_RX_UNLOCK(sc);
1296181643Skmacy
1297181643Skmacy}
1298181643Skmacystatic void
1299181643Skmacyxn_start_locked(struct ifnet *ifp)
1300181643Skmacy{
1301181643Skmacy	unsigned short id;
1302181643Skmacy	struct mbuf *m_head, *new_m;
1303181643Skmacy	struct netfront_info *sc;
1304181643Skmacy	netif_tx_request_t *tx;
1305181643Skmacy	RING_IDX i;
1306181643Skmacy	grant_ref_t ref;
1307181643Skmacy	u_long mfn, tx_bytes;
1308181643Skmacy	int notify;
1309181643Skmacy
1310181643Skmacy	sc = ifp->if_softc;
1311181643Skmacy	tx_bytes = 0;
1312181643Skmacy
1313181643Skmacy	if (!netfront_carrier_ok(sc))
1314181643Skmacy		return;
1315181643Skmacy
1316181643Skmacy	for (i = sc->tx.req_prod_pvt; TRUE; i++) {
1317181643Skmacy		IF_DEQUEUE(&ifp->if_snd, m_head);
1318181643Skmacy		if (m_head == NULL)
1319181643Skmacy			break;
1320181643Skmacy
1321181643Skmacy		if (!netfront_tx_slot_available(sc)) {
1322181643Skmacy			IF_PREPEND(&ifp->if_snd, m_head);
1323181643Skmacy			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1324181643Skmacy			break;
1325181643Skmacy		}
1326181643Skmacy
1327181643Skmacy		id = get_id_from_freelist(sc->xn_cdata.xn_tx_chain);
1328181643Skmacy
1329181643Skmacy		/*
1330181643Skmacy		 * Start packing the mbufs in this chain into
1331181643Skmacy		 * the fragment pointers. Stop when we run out
1332181643Skmacy		 * of fragments or hit the end of the mbuf chain.
1333181643Skmacy		 */
1334181643Skmacy		new_m = makembuf(m_head);
1335181643Skmacy		tx = RING_GET_REQUEST(&sc->tx, i);
1336181643Skmacy		tx->id = id;
1337181643Skmacy		ref = gnttab_claim_grant_reference(&sc->gref_tx_head);
1338181643Skmacy		KASSERT((short)ref >= 0, ("Negative ref"));
1339181643Skmacy		mfn = virt_to_mfn(mtod(new_m, vm_offset_t));
1340181643Skmacy		gnttab_grant_foreign_access_ref(ref, sc->xbdev->otherend_id,
1341181643Skmacy		    mfn, GNTMAP_readonly);
1342181643Skmacy		tx->gref = sc->grant_tx_ref[id] = ref;
1343181643Skmacy		tx->size = new_m->m_pkthdr.len;
1344181643Skmacy#if 0
1345181643Skmacy		tx->flags = (skb->ip_summed == CHECKSUM_HW) ? NETTXF_csum_blank : 0;
1346181643Skmacy#endif
1347181643Skmacy		tx->flags = 0;
1348181643Skmacy		new_m->m_next = NULL;
1349181643Skmacy		new_m->m_nextpkt = NULL;
1350181643Skmacy
1351181643Skmacy		m_freem(m_head);
1352181643Skmacy
1353181643Skmacy		sc->xn_cdata.xn_tx_chain[id] = new_m;
1354181643Skmacy		BPF_MTAP(ifp, new_m);
1355181643Skmacy
1356181643Skmacy		sc->stats.tx_bytes += new_m->m_pkthdr.len;
1357181643Skmacy		sc->stats.tx_packets++;
1358181643Skmacy	}
1359181643Skmacy
1360181643Skmacy	sc->tx.req_prod_pvt = i;
1361181643Skmacy	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->tx, notify);
1362181643Skmacy	if (notify)
1363181643Skmacy		notify_remote_via_irq(sc->irq);
1364181643Skmacy
1365181643Skmacy	xn_txeof(sc);
1366181643Skmacy
1367181643Skmacy	if (RING_FULL(&sc->tx)) {
1368181643Skmacy		sc->tx_full = 1;
1369181643Skmacy#if 0
1370181643Skmacy		netif_stop_queue(dev);
1371181643Skmacy#endif
1372181643Skmacy	}
1373181643Skmacy
1374181643Skmacy	return;
1375181643Skmacy}
1376181643Skmacy
1377181643Skmacystatic void
1378181643Skmacyxn_start(struct ifnet *ifp)
1379181643Skmacy{
1380181643Skmacy	struct netfront_info *sc;
1381181643Skmacy	sc = ifp->if_softc;
1382181643Skmacy	XN_TX_LOCK(sc);
1383181643Skmacy	xn_start_locked(ifp);
1384181643Skmacy	XN_TX_UNLOCK(sc);
1385181643Skmacy}
1386181643Skmacy
1387181643Skmacy/* equivalent of network_open() in Linux */
1388181643Skmacystatic void
1389181643Skmacyxn_ifinit_locked(struct netfront_info *sc)
1390181643Skmacy{
1391181643Skmacy	struct ifnet *ifp;
1392181643Skmacy
1393181643Skmacy	XN_LOCK_ASSERT(sc);
1394181643Skmacy
1395181643Skmacy	ifp = sc->xn_ifp;
1396181643Skmacy
1397181643Skmacy	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1398181643Skmacy		return;
1399181643Skmacy
1400181643Skmacy	xn_stop(sc);
1401181643Skmacy
1402181643Skmacy	network_alloc_rx_buffers(sc);
1403181643Skmacy	sc->rx.sring->rsp_event = sc->rx.rsp_cons + 1;
1404181643Skmacy
1405181643Skmacy	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1406181643Skmacy	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1407181643Skmacy
1408181643Skmacy	callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc);
1409181643Skmacy
1410181643Skmacy}
1411181643Skmacy
1412181643Skmacy
1413181643Skmacystatic void
1414181643Skmacyxn_ifinit(void *xsc)
1415181643Skmacy{
1416181643Skmacy	struct netfront_info *sc = xsc;
1417181643Skmacy
1418181643Skmacy	XN_LOCK(sc);
1419181643Skmacy	xn_ifinit_locked(sc);
1420181643Skmacy	XN_UNLOCK(sc);
1421181643Skmacy
1422181643Skmacy}
1423181643Skmacy
1424181643Skmacy
1425181643Skmacystatic int
1426181643Skmacyxn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1427181643Skmacy{
1428181643Skmacy	struct netfront_info *sc = ifp->if_softc;
1429181643Skmacy	struct ifreq *ifr = (struct ifreq *) data;
1430181643Skmacy	struct ifaddr *ifa = (struct ifaddr *)data;
1431181643Skmacy
1432181643Skmacy	int mask, error = 0;
1433181643Skmacy	switch(cmd) {
1434181643Skmacy	case SIOCSIFADDR:
1435181643Skmacy	case SIOCGIFADDR:
1436181643Skmacy		XN_LOCK(sc);
1437181643Skmacy		if (ifa->ifa_addr->sa_family == AF_INET) {
1438181643Skmacy			ifp->if_flags |= IFF_UP;
1439181643Skmacy			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1440181643Skmacy				xn_ifinit_locked(sc);
1441181643Skmacy			arp_ifinit(ifp, ifa);
1442185473Sdfr			XN_UNLOCK(sc);
1443185473Sdfr		} else {
1444185473Sdfr			XN_UNLOCK(sc);
1445181643Skmacy			error = ether_ioctl(ifp, cmd, data);
1446185473Sdfr		}
1447181643Skmacy		break;
1448181643Skmacy	case SIOCSIFMTU:
1449181643Skmacy		/* XXX can we alter the MTU on a VN ?*/
1450181643Skmacy#ifdef notyet
1451181643Skmacy		if (ifr->ifr_mtu > XN_JUMBO_MTU)
1452181643Skmacy			error = EINVAL;
1453181643Skmacy		else
1454181643Skmacy#endif
1455181643Skmacy		{
1456181643Skmacy			ifp->if_mtu = ifr->ifr_mtu;
1457181643Skmacy			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1458181643Skmacy			xn_ifinit(sc);
1459181643Skmacy		}
1460181643Skmacy		break;
1461181643Skmacy	case SIOCSIFFLAGS:
1462181643Skmacy		XN_LOCK(sc);
1463181643Skmacy		if (ifp->if_flags & IFF_UP) {
1464181643Skmacy			/*
1465181643Skmacy			 * If only the state of the PROMISC flag changed,
1466181643Skmacy			 * then just use the 'set promisc mode' command
1467181643Skmacy			 * instead of reinitializing the entire NIC. Doing
1468181643Skmacy			 * a full re-init means reloading the firmware and
1469181643Skmacy			 * waiting for it to start up, which may take a
1470181643Skmacy			 * second or two.
1471181643Skmacy			 */
1472181643Skmacy#ifdef notyet
1473181643Skmacy			/* No promiscuous mode with Xen */
1474181643Skmacy			if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
1475181643Skmacy			    ifp->if_flags & IFF_PROMISC &&
1476181643Skmacy			    !(sc->xn_if_flags & IFF_PROMISC)) {
1477181643Skmacy				XN_SETBIT(sc, XN_RX_MODE,
1478181643Skmacy					  XN_RXMODE_RX_PROMISC);
1479181643Skmacy			} else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
1480181643Skmacy				   !(ifp->if_flags & IFF_PROMISC) &&
1481181643Skmacy				   sc->xn_if_flags & IFF_PROMISC) {
1482181643Skmacy				XN_CLRBIT(sc, XN_RX_MODE,
1483181643Skmacy					  XN_RXMODE_RX_PROMISC);
1484181643Skmacy			} else
1485181643Skmacy#endif
1486181643Skmacy				xn_ifinit_locked(sc);
1487181643Skmacy		} else {
1488181643Skmacy			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1489181643Skmacy				xn_stop(sc);
1490181643Skmacy			}
1491181643Skmacy		}
1492181643Skmacy		sc->xn_if_flags = ifp->if_flags;
1493181643Skmacy		XN_UNLOCK(sc);
1494181643Skmacy		error = 0;
1495181643Skmacy		break;
1496181643Skmacy	case SIOCSIFCAP:
1497181643Skmacy		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1498181643Skmacy		if (mask & IFCAP_HWCSUM) {
1499181643Skmacy			if (IFCAP_HWCSUM & ifp->if_capenable)
1500181643Skmacy				ifp->if_capenable &= ~IFCAP_HWCSUM;
1501181643Skmacy			else
1502181643Skmacy				ifp->if_capenable |= IFCAP_HWCSUM;
1503181643Skmacy		}
1504181643Skmacy		error = 0;
1505181643Skmacy		break;
1506181643Skmacy	case SIOCADDMULTI:
1507181643Skmacy	case SIOCDELMULTI:
1508181643Skmacy#ifdef notyet
1509181643Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1510181643Skmacy			XN_LOCK(sc);
1511181643Skmacy			xn_setmulti(sc);
1512181643Skmacy			XN_UNLOCK(sc);
1513181643Skmacy			error = 0;
1514181643Skmacy		}
1515181643Skmacy#endif
1516181643Skmacy		/* FALLTHROUGH */
1517181643Skmacy	case SIOCSIFMEDIA:
1518181643Skmacy	case SIOCGIFMEDIA:
1519181643Skmacy		error = EINVAL;
1520181643Skmacy		break;
1521181643Skmacy	default:
1522181643Skmacy		error = ether_ioctl(ifp, cmd, data);
1523181643Skmacy	}
1524181643Skmacy
1525181643Skmacy	return (error);
1526181643Skmacy}
1527181643Skmacy
1528181643Skmacystatic void
1529181643Skmacyxn_stop(struct netfront_info *sc)
1530181643Skmacy{
1531181643Skmacy	struct ifnet *ifp;
1532181643Skmacy
1533181643Skmacy	XN_LOCK_ASSERT(sc);
1534181643Skmacy
1535181643Skmacy	ifp = sc->xn_ifp;
1536181643Skmacy
1537181643Skmacy	callout_stop(&sc->xn_stat_ch);
1538181643Skmacy
1539181643Skmacy	xn_free_rx_ring(sc);
1540181643Skmacy	xn_free_tx_ring(sc);
1541181643Skmacy
1542181643Skmacy	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1543181643Skmacy}
1544181643Skmacy
1545181643Skmacy/* START of Xenolinux helper functions adapted to FreeBSD */
1546181643Skmacystatic int
1547181643Skmacynetwork_connect(struct ifnet *ifp)
1548181643Skmacy{
1549181643Skmacy	struct netfront_info *np;
1550181643Skmacy	int i, requeue_idx, err;
1551181643Skmacy	grant_ref_t ref;
1552181643Skmacy	netif_rx_request_t *req;
1553181643Skmacy	u_int feature_rx_copy, feature_rx_flip;
1554181643Skmacy
1555181643Skmacy	printf("network_connect\n");
1556181643Skmacy
1557181643Skmacy	np = ifp->if_softc;
1558181643Skmacy	err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
1559181643Skmacy			   "feature-rx-copy", "%u", &feature_rx_copy);
1560181643Skmacy	if (err != 1)
1561181643Skmacy		feature_rx_copy = 0;
1562181643Skmacy	err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
1563181643Skmacy			   "feature-rx-flip", "%u", &feature_rx_flip);
1564181643Skmacy	if (err != 1)
1565181643Skmacy		feature_rx_flip = 1;
1566181643Skmacy
1567181643Skmacy	/*
1568181643Skmacy	 * Copy packets on receive path if:
1569181643Skmacy	 *  (a) This was requested by user, and the backend supports it; or
1570181643Skmacy	 *  (b) Flipping was requested, but this is unsupported by the backend.
1571181643Skmacy	 */
1572181643Skmacy	np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) ||
1573181643Skmacy				(MODPARM_rx_flip && !feature_rx_flip));
1574181643Skmacy
1575181643Skmacy	XN_LOCK(np);
1576181643Skmacy	/* Recovery procedure: */
1577181643Skmacy	err = talk_to_backend(np->xbdev, np);
1578181643Skmacy	if (err)
1579181643Skmacy			return (err);
1580181643Skmacy
1581181643Skmacy	/* Step 1: Reinitialise variables. */
1582181643Skmacy	netif_release_tx_bufs(np);
1583181643Skmacy
1584181643Skmacy	/* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
1585181643Skmacy	for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
1586181643Skmacy		struct mbuf *m;
1587181643Skmacy
1588181643Skmacy		if (np->rx_mbufs[i] == NULL)
1589181643Skmacy			continue;
1590181643Skmacy
1591181643Skmacy		m = np->rx_mbufs[requeue_idx] = xennet_get_rx_mbuf(np, i);
1592181643Skmacy		ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
1593181643Skmacy		req = RING_GET_REQUEST(&np->rx, requeue_idx);
1594181643Skmacy
1595181643Skmacy		if (!np->copying_receiver) {
1596181643Skmacy			gnttab_grant_foreign_transfer_ref(ref,
1597181643Skmacy			    np->xbdev->otherend_id,
1598181643Skmacy			    vtophys(mtod(m, vm_offset_t)));
1599181643Skmacy		} else {
1600181643Skmacy			gnttab_grant_foreign_access_ref(ref,
1601181643Skmacy			    np->xbdev->otherend_id,
1602181643Skmacy			    vtophys(mtod(m, vm_offset_t)), 0);
1603181643Skmacy		}
1604181643Skmacy		req->gref = ref;
1605181643Skmacy		req->id   = requeue_idx;
1606181643Skmacy
1607181643Skmacy		requeue_idx++;
1608181643Skmacy	}
1609181643Skmacy
1610181643Skmacy	np->rx.req_prod_pvt = requeue_idx;
1611181643Skmacy
1612181643Skmacy	/* Step 3: All public and private state should now be sane.  Get
1613181643Skmacy	 * ready to start sending and receiving packets and give the driver
1614181643Skmacy	 * domain a kick because we've probably just requeued some
1615181643Skmacy	 * packets.
1616181643Skmacy	 */
1617181643Skmacy	netfront_carrier_on(np);
1618181643Skmacy	notify_remote_via_irq(np->irq);
1619181643Skmacy	XN_TX_LOCK(np);
1620181643Skmacy	xn_txeof(np);
1621181643Skmacy	XN_TX_UNLOCK(np);
1622181643Skmacy	network_alloc_rx_buffers(np);
1623181643Skmacy	XN_UNLOCK(np);
1624181643Skmacy
1625181643Skmacy	return (0);
1626181643Skmacy}
1627181643Skmacy
1628181643Skmacy
1629181643Skmacystatic void
1630181643Skmacyshow_device(struct netfront_info *sc)
1631181643Skmacy{
1632181643Skmacy#ifdef DEBUG
1633181643Skmacy	if (sc) {
1634181643Skmacy		IPRINTK("<vif handle=%u %s(%s) evtchn=%u irq=%u tx=%p rx=%p>\n",
1635181643Skmacy			sc->xn_ifno,
1636181643Skmacy			be_state_name[sc->xn_backend_state],
1637181643Skmacy			sc->xn_user_state ? "open" : "closed",
1638181643Skmacy			sc->xn_evtchn,
1639181643Skmacy			sc->xn_irq,
1640181643Skmacy			sc->xn_tx_if,
1641181643Skmacy			sc->xn_rx_if);
1642181643Skmacy	} else {
1643181643Skmacy		IPRINTK("<vif NULL>\n");
1644181643Skmacy	}
1645181643Skmacy#endif
1646181643Skmacy}
1647181643Skmacy
1648181643Skmacystatic int ifno = 0;
1649181643Skmacy
1650181643Skmacy/** Create a network device.
1651181643Skmacy * @param handle device handle
1652181643Skmacy */
1653181643Skmacystatic int
1654181643Skmacycreate_netdev(struct xenbus_device *dev, struct ifnet **ifpp)
1655181643Skmacy{
1656181643Skmacy	int i;
1657181643Skmacy	struct netfront_info *np;
1658181643Skmacy	int err;
1659181643Skmacy	struct ifnet *ifp;
1660181643Skmacy
1661181643Skmacy	np = (struct netfront_info *)malloc(sizeof(struct netfront_info),
1662181643Skmacy	    M_DEVBUF, M_NOWAIT);
1663181643Skmacy	if (np == NULL)
1664181643Skmacy			return (ENOMEM);
1665181643Skmacy
1666181643Skmacy	memset(np, 0, sizeof(struct netfront_info));
1667181643Skmacy
1668181643Skmacy	np->xbdev         = dev;
1669181643Skmacy
1670181643Skmacy	XN_LOCK_INIT(np, xennetif);
1671181643Skmacy	np->rx_target     = RX_MIN_TARGET;
1672181643Skmacy	np->rx_min_target = RX_MIN_TARGET;
1673181643Skmacy	np->rx_max_target = RX_MAX_TARGET;
1674181643Skmacy
1675181643Skmacy	/* Initialise {tx,rx}_skbs to be a free chain containing every entry. */
1676181643Skmacy	for (i = 0; i <= NET_TX_RING_SIZE; i++) {
1677181643Skmacy		np->tx_mbufs[i] = (void *) ((u_long) i+1);
1678181643Skmacy		np->grant_tx_ref[i] = GRANT_INVALID_REF;
1679181643Skmacy	}
1680181643Skmacy	for (i = 0; i <= NET_RX_RING_SIZE; i++) {
1681181643Skmacy		np->rx_mbufs[i] = NULL;
1682181643Skmacy		np->grant_rx_ref[i] = GRANT_INVALID_REF;
1683181643Skmacy	}
1684181643Skmacy	/* A grant for every tx ring slot */
1685181643Skmacy	if (gnttab_alloc_grant_references(TX_MAX_TARGET,
1686181643Skmacy					  &np->gref_tx_head) < 0) {
1687181643Skmacy		printf("#### netfront can't alloc tx grant refs\n");
1688181643Skmacy		err = ENOMEM;
1689181643Skmacy		goto exit;
1690181643Skmacy	}
1691181643Skmacy	/* A grant for every rx ring slot */
1692181643Skmacy	if (gnttab_alloc_grant_references(RX_MAX_TARGET,
1693181643Skmacy					  &np->gref_rx_head) < 0) {
1694181643Skmacy		printf("#### netfront can't alloc rx grant refs\n");
1695181643Skmacy		gnttab_free_grant_references(np->gref_tx_head);
1696181643Skmacy		err = ENOMEM;
1697181643Skmacy		goto exit;
1698181643Skmacy	}
1699181643Skmacy
1700181643Skmacy	err = xen_net_read_mac(dev, np->mac);
1701181643Skmacy	if (err) {
1702181643Skmacy		xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
1703181643Skmacy		goto out;
1704181643Skmacy	}
1705181643Skmacy
1706181643Skmacy	/* Set up ifnet structure */
1707181643Skmacy	*ifpp = ifp = np->xn_ifp = if_alloc(IFT_ETHER);
1708181643Skmacy    	ifp->if_softc = np;
1709181643Skmacy    	if_initname(ifp, "xn",  ifno++/* ifno */);
1710181643Skmacy    	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
1711181643Skmacy    	ifp->if_ioctl = xn_ioctl;
1712181643Skmacy    	ifp->if_output = ether_output;
1713181643Skmacy    	ifp->if_start = xn_start;
1714181643Skmacy#ifdef notyet
1715181643Skmacy    	ifp->if_watchdog = xn_watchdog;
1716181643Skmacy#endif
1717181643Skmacy    	ifp->if_init = xn_ifinit;
1718181643Skmacy    	ifp->if_mtu = ETHERMTU;
1719181643Skmacy    	ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1;
1720181643Skmacy
1721181643Skmacy#ifdef notyet
1722181643Skmacy    	ifp->if_hwassist = XN_CSUM_FEATURES;
1723181643Skmacy    	ifp->if_capabilities = IFCAP_HWCSUM;
1724181643Skmacy    	ifp->if_capenable = ifp->if_capabilities;
1725181643Skmacy#endif
1726181643Skmacy
1727181643Skmacy    	ether_ifattach(ifp, np->mac);
1728181643Skmacy    	callout_init(&np->xn_stat_ch, CALLOUT_MPSAFE);
1729181643Skmacy	netfront_carrier_off(np);
1730181643Skmacy
1731181643Skmacy	return (0);
1732181643Skmacy
1733181643Skmacyexit:
1734181643Skmacy	gnttab_free_grant_references(np->gref_tx_head);
1735181643Skmacyout:
1736181643Skmacy	panic("do something smart");
1737181643Skmacy
1738181643Skmacy}
1739181643Skmacy
1740181643Skmacy/**
1741181643Skmacy * Handle the change of state of the backend to Closing.  We must delete our
1742181643Skmacy * device-layer structures now, to ensure that writes are flushed through to
1743181643Skmacy * the backend.  Once is this done, we can switch to Closed in
1744181643Skmacy * acknowledgement.
1745181643Skmacy */
1746181643Skmacy#if 0
1747181643Skmacystatic void netfront_closing(struct xenbus_device *dev)
1748181643Skmacy{
1749181643Skmacy#if 0
1750181643Skmacy	struct netfront_info *info = dev->dev_driver_data;
1751181643Skmacy
1752181643Skmacy	DPRINTK("netfront_closing: %s removed\n", dev->nodename);
1753181643Skmacy
1754181643Skmacy	close_netdev(info);
1755181643Skmacy#endif
1756181643Skmacy	xenbus_switch_state(dev, XenbusStateClosed);
1757181643Skmacy}
1758181643Skmacy#endif
1759181643Skmacy
1760181643Skmacystatic int netfront_remove(struct xenbus_device *dev)
1761181643Skmacy{
1762181643Skmacy	struct netfront_info *info = dev->dev_driver_data;
1763181643Skmacy
1764181643Skmacy	DPRINTK("%s\n", dev->nodename);
1765181643Skmacy
1766181643Skmacy	netif_free(info);
1767181643Skmacy	free(info, M_DEVBUF);
1768181643Skmacy
1769181643Skmacy	return 0;
1770181643Skmacy}
1771181643Skmacy
1772181643Skmacy
1773181643Skmacystatic void netif_free(struct netfront_info *info)
1774181643Skmacy{
1775181643Skmacy	netif_disconnect_backend(info);
1776181643Skmacy#if 0
1777181643Skmacy	close_netdev(info);
1778181643Skmacy#endif
1779181643Skmacy}
1780181643Skmacy
1781181643Skmacy
1782181643Skmacy
1783181643Skmacystatic void netif_disconnect_backend(struct netfront_info *info)
1784181643Skmacy{
1785181643Skmacy	xn_stop(info);
1786181643Skmacy	end_access(info->tx_ring_ref, info->tx.sring);
1787181643Skmacy	end_access(info->rx_ring_ref, info->rx.sring);
1788181643Skmacy	info->tx_ring_ref = GRANT_INVALID_REF;
1789181643Skmacy	info->rx_ring_ref = GRANT_INVALID_REF;
1790181643Skmacy	info->tx.sring = NULL;
1791181643Skmacy	info->rx.sring = NULL;
1792181643Skmacy
1793181643Skmacy#if 0
1794181643Skmacy	if (info->irq)
1795181643Skmacy		unbind_from_irqhandler(info->irq, info->netdev);
1796181643Skmacy#else
1797181643Skmacy	panic("FIX ME");
1798181643Skmacy#endif
1799181643Skmacy	info->irq = 0;
1800181643Skmacy}
1801181643Skmacy
1802181643Skmacy
1803181643Skmacystatic void end_access(int ref, void *page)
1804181643Skmacy{
1805181643Skmacy	if (ref != GRANT_INVALID_REF)
1806183375Skmacy		gnttab_end_foreign_access(ref, page);
1807181643Skmacy}
1808181643Skmacy
1809181643Skmacy
1810181643Skmacy/* ** Driver registration ** */
1811181643Skmacy
1812181643Skmacy
1813181643Skmacystatic struct xenbus_device_id netfront_ids[] = {
1814181643Skmacy	{ "vif" },
1815181643Skmacy	{ "" }
1816181643Skmacy};
1817181643Skmacy
1818181643Skmacy
1819181643Skmacystatic struct xenbus_driver netfront = {
1820181643Skmacy	.name = "vif",
1821181643Skmacy	.ids = netfront_ids,
1822181643Skmacy	.probe = netfront_probe,
1823181643Skmacy	.remove = netfront_remove,
1824181643Skmacy	.resume = netfront_resume,
1825181643Skmacy	.otherend_changed = backend_changed,
1826181643Skmacy};
1827181643Skmacy
1828181643Skmacystatic void
1829181643Skmacynetif_init(void *unused)
1830181643Skmacy{
1831181643Skmacy	if (!is_running_on_xen())
1832181643Skmacy		return;
1833181643Skmacy
1834181643Skmacy	if (is_initial_xendomain())
1835181643Skmacy		return;
1836181643Skmacy
1837181643Skmacy	IPRINTK("Initialising virtual ethernet driver.\n");
1838181643Skmacy
1839181643Skmacy	xenbus_register_frontend(&netfront);
1840181643Skmacy}
1841181643Skmacy
1842181910SkmacySYSINIT(xennetif, SI_SUB_PSEUDO, SI_ORDER_SECOND, netif_init, NULL);
1843181643Skmacy
1844181910Skmacy
1845181643Skmacy/*
1846181643Skmacy * Local variables:
1847181643Skmacy * mode: C
1848181643Skmacy * c-set-style: "BSD"
1849181643Skmacy * c-basic-offset: 8
1850181643Skmacy * tab-width: 4
1851181643Skmacy * indent-tabs-mode: t
1852181643Skmacy * End:
1853181643Skmacy */
1854