xref: /freebsd/sys/dev/xen/netback/netback.c (revision 2f4afd21257ea1672763722dae9109bbaced5548)
189e0f4d2SKip Macy /*
289e0f4d2SKip Macy  * Copyright (c) 2006, Cisco Systems, Inc.
389e0f4d2SKip Macy  * All rights reserved.
489e0f4d2SKip Macy  *
589e0f4d2SKip Macy  * Redistribution and use in source and binary forms, with or without
689e0f4d2SKip Macy  * modification, are permitted provided that the following conditions
789e0f4d2SKip Macy  * are met:
889e0f4d2SKip Macy  *
989e0f4d2SKip Macy  * 1. Redistributions of source code must retain the above copyright
1089e0f4d2SKip Macy  *    notice, this list of conditions and the following disclaimer.
1189e0f4d2SKip Macy  * 2. Redistributions in binary form must reproduce the above copyright
1289e0f4d2SKip Macy  *    notice, this list of conditions and the following disclaimer in the
1389e0f4d2SKip Macy  *    documentation and/or other materials provided with the distribution.
1489e0f4d2SKip Macy  * 3. Neither the name of Cisco Systems, Inc. nor the names of its contributors
1589e0f4d2SKip Macy  *    may be used to endorse or promote products derived from this software
1689e0f4d2SKip Macy  *    without specific prior written permission.
1789e0f4d2SKip Macy  *
1889e0f4d2SKip Macy  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1989e0f4d2SKip Macy  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2089e0f4d2SKip Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2189e0f4d2SKip Macy  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2289e0f4d2SKip Macy  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2389e0f4d2SKip Macy  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2489e0f4d2SKip Macy  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2589e0f4d2SKip Macy  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2689e0f4d2SKip Macy  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2789e0f4d2SKip Macy  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2889e0f4d2SKip Macy  * POSSIBILITY OF SUCH DAMAGE.
2989e0f4d2SKip Macy  */
3089e0f4d2SKip Macy 
3189e0f4d2SKip Macy #include <sys/cdefs.h>
3289e0f4d2SKip Macy __FBSDID("$FreeBSD$");
332f4afd21SRandall Stewart #include "opt_sctp.h"
3489e0f4d2SKip Macy 
3589e0f4d2SKip Macy #include <sys/param.h>
3689e0f4d2SKip Macy #include <sys/systm.h>
3789e0f4d2SKip Macy #include <sys/sockio.h>
3889e0f4d2SKip Macy #include <sys/mbuf.h>
3989e0f4d2SKip Macy #include <sys/malloc.h>
4089e0f4d2SKip Macy #include <sys/kernel.h>
4189e0f4d2SKip Macy #include <sys/socket.h>
4289e0f4d2SKip Macy #include <sys/queue.h>
4389e0f4d2SKip Macy #include <sys/taskqueue.h>
4489e0f4d2SKip Macy 
4589e0f4d2SKip Macy #include <sys/module.h>
4689e0f4d2SKip Macy #include <sys/bus.h>
4789e0f4d2SKip Macy #include <sys/sysctl.h>
4889e0f4d2SKip Macy 
4989e0f4d2SKip Macy #include <net/if.h>
5089e0f4d2SKip Macy #include <net/if_arp.h>
5189e0f4d2SKip Macy #include <net/if_types.h>
5289e0f4d2SKip Macy #include <net/ethernet.h>
5389e0f4d2SKip Macy #include <net/if_bridgevar.h>
5489e0f4d2SKip Macy 
5589e0f4d2SKip Macy #include <netinet/in_systm.h>
5689e0f4d2SKip Macy #include <netinet/in.h>
5789e0f4d2SKip Macy #include <netinet/in_var.h>
5889e0f4d2SKip Macy #include <netinet/ip.h>
5989e0f4d2SKip Macy #include <netinet/tcp.h>
6089e0f4d2SKip Macy #include <netinet/udp.h>
612f4afd21SRandall Stewart #ifdef SCTP
622f4afd21SRandall Stewart #include <netinet/sctp.h>
632f4afd21SRandall Stewart #include <netinet/sctp_crc32.h>
642f4afd21SRandall Stewart #endif
6589e0f4d2SKip Macy 
6689e0f4d2SKip Macy #include <vm/vm_extern.h>
6789e0f4d2SKip Macy #include <vm/vm_kern.h>
6889e0f4d2SKip Macy 
6989e0f4d2SKip Macy #include <machine/in_cksum.h>
7089e0f4d2SKip Macy #include <machine/xen-os.h>
7189e0f4d2SKip Macy #include <machine/hypervisor.h>
7289e0f4d2SKip Macy #include <machine/hypervisor-ifs.h>
7389e0f4d2SKip Macy #include <machine/xen_intr.h>
7489e0f4d2SKip Macy #include <machine/evtchn.h>
7589e0f4d2SKip Macy #include <machine/xenbus.h>
7689e0f4d2SKip Macy #include <machine/gnttab.h>
7789e0f4d2SKip Macy #include <machine/xen-public/memory.h>
7889e0f4d2SKip Macy #include <dev/xen/xenbus/xenbus_comms.h>
7989e0f4d2SKip Macy 
8089e0f4d2SKip Macy 
8189e0f4d2SKip Macy #ifdef XEN_NETBACK_DEBUG
8289e0f4d2SKip Macy #define DPRINTF(fmt, args...) \
8389e0f4d2SKip Macy     printf("netback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args)
8489e0f4d2SKip Macy #else
8589e0f4d2SKip Macy #define DPRINTF(fmt, args...) ((void)0)
8689e0f4d2SKip Macy #endif
8789e0f4d2SKip Macy 
8889e0f4d2SKip Macy #ifdef XEN_NETBACK_DEBUG_LOTS
8989e0f4d2SKip Macy #define DDPRINTF(fmt, args...) \
9089e0f4d2SKip Macy     printf("netback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args)
9189e0f4d2SKip Macy #define DPRINTF_MBUF(_m) print_mbuf(_m, 0)
9289e0f4d2SKip Macy #define DPRINTF_MBUF_LEN(_m, _len) print_mbuf(_m, _len)
9389e0f4d2SKip Macy #else
9489e0f4d2SKip Macy #define DDPRINTF(fmt, args...) ((void)0)
9589e0f4d2SKip Macy #define DPRINTF_MBUF(_m) ((void)0)
9689e0f4d2SKip Macy #define DPRINTF_MBUF_LEN(_m, _len) ((void)0)
9789e0f4d2SKip Macy #endif
9889e0f4d2SKip Macy 
9989e0f4d2SKip Macy #define WPRINTF(fmt, args...) \
10089e0f4d2SKip Macy     printf("netback (%s:%d): " fmt, __FUNCTION__, __LINE__, ##args)
10189e0f4d2SKip Macy 
10289e0f4d2SKip Macy #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
10389e0f4d2SKip Macy #define BUG_ON PANIC_IF
10489e0f4d2SKip Macy 
10589e0f4d2SKip Macy #define IFNAME(_np) (_np)->ifp->if_xname
10689e0f4d2SKip Macy 
10789e0f4d2SKip Macy #define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
10889e0f4d2SKip Macy #define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
10989e0f4d2SKip Macy 
11089e0f4d2SKip Macy struct ring_ref {
11189e0f4d2SKip Macy 	vm_offset_t va;
11289e0f4d2SKip Macy 	grant_handle_t handle;
11389e0f4d2SKip Macy 	uint64_t bus_addr;
11489e0f4d2SKip Macy };
11589e0f4d2SKip Macy 
11689e0f4d2SKip Macy typedef struct netback_info {
11789e0f4d2SKip Macy 
11889e0f4d2SKip Macy 	/* Schedule lists */
11989e0f4d2SKip Macy 	STAILQ_ENTRY(netback_info) next_tx;
12089e0f4d2SKip Macy 	STAILQ_ENTRY(netback_info) next_rx;
12189e0f4d2SKip Macy 	int on_tx_sched_list;
12289e0f4d2SKip Macy 	int on_rx_sched_list;
12389e0f4d2SKip Macy 
12489e0f4d2SKip Macy 	struct xenbus_device *xdev;
12589e0f4d2SKip Macy 	XenbusState frontend_state;
12689e0f4d2SKip Macy 
12789e0f4d2SKip Macy 	domid_t domid;
12889e0f4d2SKip Macy 	int handle;
12989e0f4d2SKip Macy 	char *bridge;
13089e0f4d2SKip Macy 
13189e0f4d2SKip Macy 	int rings_connected;
13289e0f4d2SKip Macy 	struct ring_ref tx_ring_ref;
13389e0f4d2SKip Macy 	struct ring_ref rx_ring_ref;
13489e0f4d2SKip Macy 	netif_tx_back_ring_t tx;
13589e0f4d2SKip Macy 	netif_rx_back_ring_t rx;
13689e0f4d2SKip Macy 	evtchn_port_t evtchn;
13789e0f4d2SKip Macy 	int irq;
13889e0f4d2SKip Macy 	void *irq_cookie;
13989e0f4d2SKip Macy 
14089e0f4d2SKip Macy 	struct ifnet *ifp;
14189e0f4d2SKip Macy 	int ref_cnt;
14289e0f4d2SKip Macy 
14389e0f4d2SKip Macy 	device_t ndev;
14489e0f4d2SKip Macy 	int attached;
14589e0f4d2SKip Macy } netif_t;
14689e0f4d2SKip Macy 
14789e0f4d2SKip Macy 
14889e0f4d2SKip Macy #define MAX_PENDING_REQS 256
14989e0f4d2SKip Macy #define PKT_PROT_LEN 64
15089e0f4d2SKip Macy 
15189e0f4d2SKip Macy static struct {
15289e0f4d2SKip Macy 	netif_tx_request_t req;
15389e0f4d2SKip Macy 	netif_t *netif;
15489e0f4d2SKip Macy } pending_tx_info[MAX_PENDING_REQS];
15589e0f4d2SKip Macy static uint16_t pending_ring[MAX_PENDING_REQS];
15689e0f4d2SKip Macy typedef unsigned int PEND_RING_IDX;
15789e0f4d2SKip Macy #define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
15889e0f4d2SKip Macy static PEND_RING_IDX pending_prod, pending_cons;
15989e0f4d2SKip Macy #define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
16089e0f4d2SKip Macy 
16189e0f4d2SKip Macy static unsigned long mmap_vstart;
16289e0f4d2SKip Macy #define MMAP_VADDR(_req) (mmap_vstart + ((_req) * PAGE_SIZE))
16389e0f4d2SKip Macy 
16489e0f4d2SKip Macy /* Freed TX mbufs get batched on this ring before return to pending_ring. */
16589e0f4d2SKip Macy static uint16_t dealloc_ring[MAX_PENDING_REQS];
16689e0f4d2SKip Macy static PEND_RING_IDX dealloc_prod, dealloc_cons;
16789e0f4d2SKip Macy 
16889e0f4d2SKip Macy static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1];
16989e0f4d2SKip Macy static mmu_update_t rx_mmu[NET_RX_RING_SIZE];
17089e0f4d2SKip Macy static gnttab_transfer_t grant_rx_op[NET_RX_RING_SIZE];
17189e0f4d2SKip Macy 
17289e0f4d2SKip Macy static grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
17389e0f4d2SKip Macy static gnttab_unmap_grant_ref_t tx_unmap_ops[MAX_PENDING_REQS];
17489e0f4d2SKip Macy static gnttab_map_grant_ref_t tx_map_ops[MAX_PENDING_REQS];
17589e0f4d2SKip Macy 
17689e0f4d2SKip Macy static struct task net_tx_task, net_rx_task;
17789e0f4d2SKip Macy static struct callout rx_task_callout;
17889e0f4d2SKip Macy 
17989e0f4d2SKip Macy static STAILQ_HEAD(netback_tx_sched_list, netback_info) tx_sched_list =
18089e0f4d2SKip Macy 	STAILQ_HEAD_INITIALIZER(tx_sched_list);
18189e0f4d2SKip Macy static STAILQ_HEAD(netback_rx_sched_list, netback_info) rx_sched_list =
18289e0f4d2SKip Macy 	STAILQ_HEAD_INITIALIZER(rx_sched_list);
18389e0f4d2SKip Macy static struct mtx tx_sched_list_lock;
18489e0f4d2SKip Macy static struct mtx rx_sched_list_lock;
18589e0f4d2SKip Macy 
18689e0f4d2SKip Macy static int vif_unit_maker = 0;
18789e0f4d2SKip Macy 
18889e0f4d2SKip Macy /* Protos */
18989e0f4d2SKip Macy static void netback_start(struct ifnet *ifp);
19089e0f4d2SKip Macy static int netback_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
19189e0f4d2SKip Macy static int vif_add_dev(struct xenbus_device *xdev);
19289e0f4d2SKip Macy static void disconnect_rings(netif_t *netif);
19389e0f4d2SKip Macy 
19489e0f4d2SKip Macy #ifdef XEN_NETBACK_DEBUG_LOTS
19589e0f4d2SKip Macy /* Debug code to display the contents of an mbuf */
19689e0f4d2SKip Macy static void
19789e0f4d2SKip Macy print_mbuf(struct mbuf *m, int max)
19889e0f4d2SKip Macy {
19989e0f4d2SKip Macy 	int i, j=0;
20089e0f4d2SKip Macy 	printf("mbuf %08x len = %d", (unsigned int)m, m->m_pkthdr.len);
20189e0f4d2SKip Macy 	for (; m; m = m->m_next) {
20289e0f4d2SKip Macy 		unsigned char *d = m->m_data;
20389e0f4d2SKip Macy 		for (i=0; i < m->m_len; i++) {
20489e0f4d2SKip Macy 			if (max && j == max)
20589e0f4d2SKip Macy 				break;
20689e0f4d2SKip Macy 			if ((j++ % 16) == 0)
20789e0f4d2SKip Macy 				printf("\n%04x:", j);
20889e0f4d2SKip Macy 			printf(" %02x", d[i]);
20989e0f4d2SKip Macy 		}
21089e0f4d2SKip Macy 	}
21189e0f4d2SKip Macy 	printf("\n");
21289e0f4d2SKip Macy }
21389e0f4d2SKip Macy #endif
21489e0f4d2SKip Macy 
21589e0f4d2SKip Macy 
21689e0f4d2SKip Macy #define MAX_MFN_ALLOC 64
21789e0f4d2SKip Macy static unsigned long mfn_list[MAX_MFN_ALLOC];
21889e0f4d2SKip Macy static unsigned int alloc_index = 0;
21989e0f4d2SKip Macy 
22089e0f4d2SKip Macy static unsigned long
22189e0f4d2SKip Macy alloc_mfn(void)
22289e0f4d2SKip Macy {
22389e0f4d2SKip Macy 	unsigned long mfn = 0;
22489e0f4d2SKip Macy 	struct xen_memory_reservation reservation = {
22589e0f4d2SKip Macy 		.extent_start = mfn_list,
22689e0f4d2SKip Macy 		.nr_extents   = MAX_MFN_ALLOC,
22789e0f4d2SKip Macy 		.extent_order = 0,
22889e0f4d2SKip Macy 		.domid        = DOMID_SELF
22989e0f4d2SKip Macy 	};
23089e0f4d2SKip Macy 	if ( unlikely(alloc_index == 0) )
23189e0f4d2SKip Macy 		alloc_index = HYPERVISOR_memory_op(
23289e0f4d2SKip Macy 			XENMEM_increase_reservation, &reservation);
23389e0f4d2SKip Macy 	if ( alloc_index != 0 )
23489e0f4d2SKip Macy 		mfn = mfn_list[--alloc_index];
23589e0f4d2SKip Macy 	return mfn;
23689e0f4d2SKip Macy }
23789e0f4d2SKip Macy 
23889e0f4d2SKip Macy static unsigned long
23989e0f4d2SKip Macy alloc_empty_page_range(unsigned long nr_pages)
24089e0f4d2SKip Macy {
24189e0f4d2SKip Macy 	void *pages;
24289e0f4d2SKip Macy 	int i = 0, j = 0;
24389e0f4d2SKip Macy 	multicall_entry_t mcl[17];
24489e0f4d2SKip Macy 	unsigned long mfn_list[16];
24589e0f4d2SKip Macy 	struct xen_memory_reservation reservation = {
24689e0f4d2SKip Macy 		.extent_start = mfn_list,
24789e0f4d2SKip Macy 		.nr_extents   = 0,
24889e0f4d2SKip Macy 		.address_bits = 0,
24989e0f4d2SKip Macy 		.extent_order = 0,
25089e0f4d2SKip Macy 		.domid        = DOMID_SELF
25189e0f4d2SKip Macy 	};
25289e0f4d2SKip Macy 
25389e0f4d2SKip Macy 	pages = malloc(nr_pages*PAGE_SIZE, M_DEVBUF, M_NOWAIT);
25489e0f4d2SKip Macy 	if (pages == NULL)
25589e0f4d2SKip Macy 		return 0;
25689e0f4d2SKip Macy 
25789e0f4d2SKip Macy 	memset(mcl, 0, sizeof(mcl));
25889e0f4d2SKip Macy 
25989e0f4d2SKip Macy 	while (i < nr_pages) {
26089e0f4d2SKip Macy 		unsigned long va = (unsigned long)pages + (i++ * PAGE_SIZE);
26189e0f4d2SKip Macy 
26289e0f4d2SKip Macy 		mcl[j].op = __HYPERVISOR_update_va_mapping;
26389e0f4d2SKip Macy 		mcl[j].args[0] = va;
26489e0f4d2SKip Macy 
26589e0f4d2SKip Macy 		mfn_list[j++] = vtomach(va) >> PAGE_SHIFT;
26689e0f4d2SKip Macy 
26789e0f4d2SKip Macy 		xen_phys_machine[(vtophys(va) >> PAGE_SHIFT)] = INVALID_P2M_ENTRY;
26889e0f4d2SKip Macy 
26989e0f4d2SKip Macy 		if (j == 16 || i == nr_pages) {
27089e0f4d2SKip Macy 			mcl[j-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_LOCAL;
27189e0f4d2SKip Macy 
27289e0f4d2SKip Macy 			reservation.nr_extents = j;
27389e0f4d2SKip Macy 
27489e0f4d2SKip Macy 			mcl[j].op = __HYPERVISOR_memory_op;
27589e0f4d2SKip Macy 			mcl[j].args[0] = XENMEM_decrease_reservation;
27689e0f4d2SKip Macy 			mcl[j].args[1] =  (unsigned long)&reservation;
27789e0f4d2SKip Macy 
27889e0f4d2SKip Macy 			(void)HYPERVISOR_multicall(mcl, j+1);
27989e0f4d2SKip Macy 
28089e0f4d2SKip Macy 			mcl[j-1].args[MULTI_UVMFLAGS_INDEX] = 0;
28189e0f4d2SKip Macy 			j = 0;
28289e0f4d2SKip Macy 		}
28389e0f4d2SKip Macy 	}
28489e0f4d2SKip Macy 
28589e0f4d2SKip Macy 	return (unsigned long)pages;
28689e0f4d2SKip Macy }
28789e0f4d2SKip Macy 
28889e0f4d2SKip Macy #ifdef XEN_NETBACK_FIXUP_CSUM
28989e0f4d2SKip Macy static void
29089e0f4d2SKip Macy fixup_checksum(struct mbuf *m)
29189e0f4d2SKip Macy {
29289e0f4d2SKip Macy 	struct ether_header *eh = mtod(m, struct ether_header *);
29389e0f4d2SKip Macy 	struct ip *ip = (struct ip *)(eh + 1);
29489e0f4d2SKip Macy 	int iphlen = ip->ip_hl << 2;
29589e0f4d2SKip Macy 	int iplen = ntohs(ip->ip_len);
29689e0f4d2SKip Macy 
29789e0f4d2SKip Macy 	if ((m->m_pkthdr.csum_flags & CSUM_TCP)) {
29889e0f4d2SKip Macy 		struct tcphdr *th = (struct tcphdr *)((caddr_t)ip + iphlen);
29989e0f4d2SKip Macy 		th->th_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
30089e0f4d2SKip Macy 			htons(IPPROTO_TCP + (iplen - iphlen)));
30189e0f4d2SKip Macy 		th->th_sum = in_cksum_skip(m, iplen + sizeof(*eh), sizeof(*eh) + iphlen);
30289e0f4d2SKip Macy 		m->m_pkthdr.csum_flags &= ~CSUM_TCP;
3032f4afd21SRandall Stewart #ifdef SCTP
3042f4afd21SRandall Stewart 	} else if (sw_csum & CSUM_SCTP) {
3052f4afd21SRandall Stewart 		sctp_delayed_cksum(m);
3062f4afd21SRandall Stewart 		sw_csum &= ~CSUM_SCTP;
3072f4afd21SRandall Stewart #endif
30889e0f4d2SKip Macy 	} else {
30989e0f4d2SKip Macy 		u_short csum;
31089e0f4d2SKip Macy 		struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen);
31189e0f4d2SKip Macy 		uh->uh_sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
31289e0f4d2SKip Macy 			htons(IPPROTO_UDP + (iplen - iphlen)));
31389e0f4d2SKip Macy 		if ((csum = in_cksum_skip(m, iplen + sizeof(*eh), sizeof(*eh) + iphlen)) == 0)
31489e0f4d2SKip Macy 			csum = 0xffff;
31589e0f4d2SKip Macy 		uh->uh_sum = csum;
31689e0f4d2SKip Macy 		m->m_pkthdr.csum_flags &= ~CSUM_UDP;
31789e0f4d2SKip Macy 	}
31889e0f4d2SKip Macy }
31989e0f4d2SKip Macy #endif
32089e0f4d2SKip Macy 
32189e0f4d2SKip Macy /* Add the interface to the specified bridge */
32289e0f4d2SKip Macy static int
32389e0f4d2SKip Macy add_to_bridge(struct ifnet *ifp, char *bridge)
32489e0f4d2SKip Macy {
32589e0f4d2SKip Macy 	struct ifdrv ifd;
32689e0f4d2SKip Macy 	struct ifbreq ifb;
32789e0f4d2SKip Macy 	struct ifnet *ifp_bridge = ifunit(bridge);
32889e0f4d2SKip Macy 
32989e0f4d2SKip Macy 	if (!ifp_bridge)
33089e0f4d2SKip Macy 		return ENOENT;
33189e0f4d2SKip Macy 
33289e0f4d2SKip Macy 	bzero(&ifd, sizeof(ifd));
33389e0f4d2SKip Macy 	bzero(&ifb, sizeof(ifb));
33489e0f4d2SKip Macy 
33589e0f4d2SKip Macy 	strcpy(ifb.ifbr_ifsname, ifp->if_xname);
33689e0f4d2SKip Macy 	strcpy(ifd.ifd_name, ifp->if_xname);
33789e0f4d2SKip Macy 	ifd.ifd_cmd = BRDGADD;
33889e0f4d2SKip Macy 	ifd.ifd_len = sizeof(ifb);
33989e0f4d2SKip Macy 	ifd.ifd_data = &ifb;
34089e0f4d2SKip Macy 
34189e0f4d2SKip Macy 	return bridge_ioctl_kern(ifp_bridge, SIOCSDRVSPEC, &ifd);
34289e0f4d2SKip Macy 
34389e0f4d2SKip Macy }
34489e0f4d2SKip Macy 
34589e0f4d2SKip Macy static int
34689e0f4d2SKip Macy netif_create(int handle, struct xenbus_device *xdev, char *bridge)
34789e0f4d2SKip Macy {
34889e0f4d2SKip Macy 	netif_t *netif;
34989e0f4d2SKip Macy 	struct ifnet *ifp;
35089e0f4d2SKip Macy 
35189e0f4d2SKip Macy 	netif = (netif_t *)malloc(sizeof(*netif), M_DEVBUF, M_NOWAIT | M_ZERO);
35289e0f4d2SKip Macy 	if (!netif)
35389e0f4d2SKip Macy 		return ENOMEM;
35489e0f4d2SKip Macy 
35589e0f4d2SKip Macy 	netif->ref_cnt = 1;
35689e0f4d2SKip Macy 	netif->handle = handle;
35789e0f4d2SKip Macy 	netif->domid = xdev->otherend_id;
35889e0f4d2SKip Macy 	netif->xdev = xdev;
35989e0f4d2SKip Macy 	netif->bridge = bridge;
36089e0f4d2SKip Macy 	xdev->data = netif;
36189e0f4d2SKip Macy 
36289e0f4d2SKip Macy 	/* Set up ifnet structure */
36389e0f4d2SKip Macy 	ifp = netif->ifp = if_alloc(IFT_ETHER);
36489e0f4d2SKip Macy 	if (!ifp) {
36589e0f4d2SKip Macy 		if (bridge)
36689e0f4d2SKip Macy 			free(bridge, M_DEVBUF);
36789e0f4d2SKip Macy 		free(netif, M_DEVBUF);
36889e0f4d2SKip Macy 		return ENOMEM;
36989e0f4d2SKip Macy 	}
37089e0f4d2SKip Macy 
37189e0f4d2SKip Macy 	ifp->if_softc = netif;
37289e0f4d2SKip Macy 	if_initname(ifp, "vif",
37389e0f4d2SKip Macy 		atomic_fetchadd_int(&vif_unit_maker, 1) /* ifno */ );
37489e0f4d2SKip Macy 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
37589e0f4d2SKip Macy 	ifp->if_output = ether_output;
37689e0f4d2SKip Macy 	ifp->if_start = netback_start;
37789e0f4d2SKip Macy 	ifp->if_ioctl = netback_ioctl;
37889e0f4d2SKip Macy 	ifp->if_mtu = ETHERMTU;
37989e0f4d2SKip Macy 	ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1;
38089e0f4d2SKip Macy 
38189e0f4d2SKip Macy 	DPRINTF("Created %s for domid=%d handle=%d\n", IFNAME(netif), netif->domid, netif->handle);
38289e0f4d2SKip Macy 
38389e0f4d2SKip Macy 	return 0;
38489e0f4d2SKip Macy }
38589e0f4d2SKip Macy 
38689e0f4d2SKip Macy static void
38789e0f4d2SKip Macy netif_get(netif_t *netif)
38889e0f4d2SKip Macy {
38989e0f4d2SKip Macy 	atomic_add_int(&netif->ref_cnt, 1);
39089e0f4d2SKip Macy }
39189e0f4d2SKip Macy 
39289e0f4d2SKip Macy static void
39389e0f4d2SKip Macy netif_put(netif_t *netif)
39489e0f4d2SKip Macy {
39589e0f4d2SKip Macy 	if (atomic_fetchadd_int(&netif->ref_cnt, -1) == 1) {
39689e0f4d2SKip Macy 		DPRINTF("%s\n", IFNAME(netif));
39789e0f4d2SKip Macy 		disconnect_rings(netif);
39889e0f4d2SKip Macy 		if (netif->ifp) {
39989e0f4d2SKip Macy 			if_free(netif->ifp);
40089e0f4d2SKip Macy 			netif->ifp = NULL;
40189e0f4d2SKip Macy 		}
40289e0f4d2SKip Macy 		if (netif->bridge)
40389e0f4d2SKip Macy 			free(netif->bridge, M_DEVBUF);
40489e0f4d2SKip Macy 		free(netif, M_DEVBUF);
40589e0f4d2SKip Macy 	}
40689e0f4d2SKip Macy }
40789e0f4d2SKip Macy 
40889e0f4d2SKip Macy static int
40989e0f4d2SKip Macy netback_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
41089e0f4d2SKip Macy {
41189e0f4d2SKip Macy 	switch (cmd) {
41289e0f4d2SKip Macy 	case SIOCSIFFLAGS:
41389e0f4d2SKip Macy 	DDPRINTF("%s cmd=SIOCSIFFLAGS flags=%x\n",
41489e0f4d2SKip Macy 			IFNAME((struct netback_info *)ifp->if_softc), ((struct ifreq *)data)->ifr_flags);
41589e0f4d2SKip Macy 		return 0;
41689e0f4d2SKip Macy 	}
41789e0f4d2SKip Macy 
41889e0f4d2SKip Macy 	DDPRINTF("%s cmd=%lx\n", IFNAME((struct netback_info *)ifp->if_softc), cmd);
41989e0f4d2SKip Macy 
42089e0f4d2SKip Macy 	return ether_ioctl(ifp, cmd, data);
42189e0f4d2SKip Macy }
42289e0f4d2SKip Macy 
42389e0f4d2SKip Macy static inline void
42489e0f4d2SKip Macy maybe_schedule_tx_action(void)
42589e0f4d2SKip Macy {
42689e0f4d2SKip Macy 	smp_mb();
42789e0f4d2SKip Macy 	if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) && !STAILQ_EMPTY(&tx_sched_list))
42889e0f4d2SKip Macy 		taskqueue_enqueue(taskqueue_swi, &net_tx_task);
42989e0f4d2SKip Macy }
43089e0f4d2SKip Macy 
43189e0f4d2SKip Macy /* Removes netif from front of list and does not call netif_put() (caller must) */
43289e0f4d2SKip Macy static netif_t *
43389e0f4d2SKip Macy remove_from_tx_schedule_list(void)
43489e0f4d2SKip Macy {
43589e0f4d2SKip Macy 	netif_t *netif;
43689e0f4d2SKip Macy 
43789e0f4d2SKip Macy 	mtx_lock(&tx_sched_list_lock);
43889e0f4d2SKip Macy 
43989e0f4d2SKip Macy 	if ((netif = STAILQ_FIRST(&tx_sched_list))) {
44089e0f4d2SKip Macy 		STAILQ_REMOVE(&tx_sched_list, netif, netback_info, next_tx);
44189e0f4d2SKip Macy 		STAILQ_NEXT(netif, next_tx) = NULL;
44289e0f4d2SKip Macy 		netif->on_tx_sched_list = 0;
44389e0f4d2SKip Macy 	}
44489e0f4d2SKip Macy 
44589e0f4d2SKip Macy 	mtx_unlock(&tx_sched_list_lock);
44689e0f4d2SKip Macy 
44789e0f4d2SKip Macy 	return netif;
44889e0f4d2SKip Macy }
44989e0f4d2SKip Macy 
45089e0f4d2SKip Macy /* Adds netif to end of list and calls netif_get() */
45189e0f4d2SKip Macy static void
45289e0f4d2SKip Macy add_to_tx_schedule_list_tail(netif_t *netif)
45389e0f4d2SKip Macy {
45489e0f4d2SKip Macy 	if (netif->on_tx_sched_list)
45589e0f4d2SKip Macy 		return;
45689e0f4d2SKip Macy 
45789e0f4d2SKip Macy 	mtx_lock(&tx_sched_list_lock);
45889e0f4d2SKip Macy 	if (!netif->on_tx_sched_list && (netif->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
45989e0f4d2SKip Macy 		netif_get(netif);
46089e0f4d2SKip Macy 		STAILQ_INSERT_TAIL(&tx_sched_list, netif, next_tx);
46189e0f4d2SKip Macy 		netif->on_tx_sched_list = 1;
46289e0f4d2SKip Macy 	}
46389e0f4d2SKip Macy 	mtx_unlock(&tx_sched_list_lock);
46489e0f4d2SKip Macy }
46589e0f4d2SKip Macy 
46689e0f4d2SKip Macy /*
46789e0f4d2SKip Macy  * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER:
46889e0f4d2SKip Macy  * If this driver is pipelining transmit requests then we can be very
46989e0f4d2SKip Macy  * aggressive in avoiding new-packet notifications -- frontend only needs to
47089e0f4d2SKip Macy  * send a notification if there are no outstanding unreceived responses.
47189e0f4d2SKip Macy  * If we may be buffer transmit buffers for any reason then we must be rather
47289e0f4d2SKip Macy  * more conservative and treat this as the final check for pending work.
47389e0f4d2SKip Macy  */
47489e0f4d2SKip Macy static void
47589e0f4d2SKip Macy netif_schedule_tx_work(netif_t *netif)
47689e0f4d2SKip Macy {
47789e0f4d2SKip Macy 	int more_to_do;
47889e0f4d2SKip Macy 
47989e0f4d2SKip Macy #ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
48089e0f4d2SKip Macy 	more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx);
48189e0f4d2SKip Macy #else
48289e0f4d2SKip Macy 	RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
48389e0f4d2SKip Macy #endif
48489e0f4d2SKip Macy 
48589e0f4d2SKip Macy 	if (more_to_do) {
48689e0f4d2SKip Macy 		DDPRINTF("Adding %s to tx sched list\n", IFNAME(netif));
48789e0f4d2SKip Macy 		add_to_tx_schedule_list_tail(netif);
48889e0f4d2SKip Macy 		maybe_schedule_tx_action();
48989e0f4d2SKip Macy 	}
49089e0f4d2SKip Macy }
49189e0f4d2SKip Macy 
49289e0f4d2SKip Macy static struct mtx dealloc_lock;
49389e0f4d2SKip Macy MTX_SYSINIT(netback_dealloc, &dealloc_lock, "DEALLOC LOCK", MTX_SPIN | MTX_NOWITNESS);
49489e0f4d2SKip Macy 
49589e0f4d2SKip Macy static void
49689e0f4d2SKip Macy netif_idx_release(uint16_t pending_idx)
49789e0f4d2SKip Macy {
49889e0f4d2SKip Macy 	mtx_lock_spin(&dealloc_lock);
49989e0f4d2SKip Macy 	dealloc_ring[MASK_PEND_IDX(dealloc_prod++)] = pending_idx;
50089e0f4d2SKip Macy 	mtx_unlock_spin(&dealloc_lock);
50189e0f4d2SKip Macy 
50289e0f4d2SKip Macy 	taskqueue_enqueue(taskqueue_swi, &net_tx_task);
50389e0f4d2SKip Macy }
50489e0f4d2SKip Macy 
50589e0f4d2SKip Macy static void
50689e0f4d2SKip Macy make_tx_response(netif_t *netif,
50789e0f4d2SKip Macy 				 uint16_t    id,
50889e0f4d2SKip Macy 				 int8_t      st)
50989e0f4d2SKip Macy {
51089e0f4d2SKip Macy 	RING_IDX i = netif->tx.rsp_prod_pvt;
51189e0f4d2SKip Macy 	netif_tx_response_t *resp;
51289e0f4d2SKip Macy 	int notify;
51389e0f4d2SKip Macy 
51489e0f4d2SKip Macy 	resp = RING_GET_RESPONSE(&netif->tx, i);
51589e0f4d2SKip Macy 	resp->id     = id;
51689e0f4d2SKip Macy 	resp->status = st;
51789e0f4d2SKip Macy 
51889e0f4d2SKip Macy 	netif->tx.rsp_prod_pvt = ++i;
51989e0f4d2SKip Macy 	RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
52089e0f4d2SKip Macy 	if (notify)
52189e0f4d2SKip Macy 		notify_remote_via_irq(netif->irq);
52289e0f4d2SKip Macy 
52389e0f4d2SKip Macy #ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
52489e0f4d2SKip Macy 	if (i == netif->tx.req_cons) {
52589e0f4d2SKip Macy 		int more_to_do;
52689e0f4d2SKip Macy 		RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
52789e0f4d2SKip Macy 		if (more_to_do)
52889e0f4d2SKip Macy 			add_to_tx_schedule_list_tail(netif);
52989e0f4d2SKip Macy 	}
53089e0f4d2SKip Macy #endif
53189e0f4d2SKip Macy }
53289e0f4d2SKip Macy 
53389e0f4d2SKip Macy inline static void
53489e0f4d2SKip Macy net_tx_action_dealloc(void)
53589e0f4d2SKip Macy {
53689e0f4d2SKip Macy 	gnttab_unmap_grant_ref_t *gop;
53789e0f4d2SKip Macy 	uint16_t pending_idx;
53889e0f4d2SKip Macy 	PEND_RING_IDX dc, dp;
53989e0f4d2SKip Macy 	netif_t *netif;
54089e0f4d2SKip Macy 	int ret;
54189e0f4d2SKip Macy 
54289e0f4d2SKip Macy 	dc = dealloc_cons;
54389e0f4d2SKip Macy 	dp = dealloc_prod;
54489e0f4d2SKip Macy 
54589e0f4d2SKip Macy 	/*
54689e0f4d2SKip Macy 	 * Free up any grants we have finished using
54789e0f4d2SKip Macy 	 */
54889e0f4d2SKip Macy 	gop = tx_unmap_ops;
54989e0f4d2SKip Macy 	while (dc != dp) {
55089e0f4d2SKip Macy 		pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
55189e0f4d2SKip Macy 		gop->host_addr    = MMAP_VADDR(pending_idx);
55289e0f4d2SKip Macy 		gop->dev_bus_addr = 0;
55389e0f4d2SKip Macy 		gop->handle       = grant_tx_handle[pending_idx];
55489e0f4d2SKip Macy 		gop++;
55589e0f4d2SKip Macy 	}
55689e0f4d2SKip Macy 	ret = HYPERVISOR_grant_table_op(
55789e0f4d2SKip Macy 		GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops);
55889e0f4d2SKip Macy 	BUG_ON(ret);
55989e0f4d2SKip Macy 
56089e0f4d2SKip Macy 	while (dealloc_cons != dp) {
56189e0f4d2SKip Macy 		pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)];
56289e0f4d2SKip Macy 
56389e0f4d2SKip Macy 		netif = pending_tx_info[pending_idx].netif;
56489e0f4d2SKip Macy 
56589e0f4d2SKip Macy 		make_tx_response(netif, pending_tx_info[pending_idx].req.id,
56689e0f4d2SKip Macy 				 NETIF_RSP_OKAY);
56789e0f4d2SKip Macy 
56889e0f4d2SKip Macy 		pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
56989e0f4d2SKip Macy 
57089e0f4d2SKip Macy 		netif_put(netif);
57189e0f4d2SKip Macy 	}
57289e0f4d2SKip Macy }
57389e0f4d2SKip Macy 
57489e0f4d2SKip Macy static void
57589e0f4d2SKip Macy netif_page_release(void *buf, void *args)
57689e0f4d2SKip Macy {
57789e0f4d2SKip Macy 	uint16_t pending_idx = (unsigned int)args;
57889e0f4d2SKip Macy 
57989e0f4d2SKip Macy 	DDPRINTF("pending_idx=%u\n", pending_idx);
58089e0f4d2SKip Macy 
58189e0f4d2SKip Macy 	KASSERT(pending_idx < MAX_PENDING_REQS, ("%s: bad index %u", __func__, pending_idx));
58289e0f4d2SKip Macy 
58389e0f4d2SKip Macy 	netif_idx_release(pending_idx);
58489e0f4d2SKip Macy }
58589e0f4d2SKip Macy 
58689e0f4d2SKip Macy static void
58789e0f4d2SKip Macy net_tx_action(void *context, int pending)
58889e0f4d2SKip Macy {
58989e0f4d2SKip Macy 	struct mbuf *m;
59089e0f4d2SKip Macy 	netif_t *netif;
59189e0f4d2SKip Macy 	netif_tx_request_t txreq;
59289e0f4d2SKip Macy 	uint16_t pending_idx;
59389e0f4d2SKip Macy 	RING_IDX i;
59489e0f4d2SKip Macy 	gnttab_map_grant_ref_t *mop;
59589e0f4d2SKip Macy 	int ret, work_to_do;
59689e0f4d2SKip Macy 	struct mbuf *txq = NULL, *txq_last = NULL;
59789e0f4d2SKip Macy 
59889e0f4d2SKip Macy 	if (dealloc_cons != dealloc_prod)
59989e0f4d2SKip Macy 		net_tx_action_dealloc();
60089e0f4d2SKip Macy 
60189e0f4d2SKip Macy 	mop = tx_map_ops;
60289e0f4d2SKip Macy 	while ((NR_PENDING_REQS < MAX_PENDING_REQS) && !STAILQ_EMPTY(&tx_sched_list)) {
60389e0f4d2SKip Macy 
60489e0f4d2SKip Macy 		/* Get a netif from the list with work to do. */
60589e0f4d2SKip Macy 		netif = remove_from_tx_schedule_list();
60689e0f4d2SKip Macy 
60789e0f4d2SKip Macy 		DDPRINTF("Processing %s (prod=%u, cons=%u)\n",
60889e0f4d2SKip Macy 				IFNAME(netif), netif->tx.sring->req_prod, netif->tx.req_cons);
60989e0f4d2SKip Macy 
61089e0f4d2SKip Macy 		RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
61189e0f4d2SKip Macy 		if (!work_to_do) {
61289e0f4d2SKip Macy 			netif_put(netif);
61389e0f4d2SKip Macy 			continue;
61489e0f4d2SKip Macy 		}
61589e0f4d2SKip Macy 
61689e0f4d2SKip Macy 		i = netif->tx.req_cons;
61789e0f4d2SKip Macy 		rmb(); /* Ensure that we see the request before we copy it. */
61889e0f4d2SKip Macy 		memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
61989e0f4d2SKip Macy 
62089e0f4d2SKip Macy 		/* If we want credit-based scheduling, coud add it here - WORK */
62189e0f4d2SKip Macy 
62289e0f4d2SKip Macy 		netif->tx.req_cons++;
62389e0f4d2SKip Macy 
62489e0f4d2SKip Macy 		netif_schedule_tx_work(netif);
62589e0f4d2SKip Macy 
62689e0f4d2SKip Macy 		if (unlikely(txreq.size < ETHER_HDR_LEN) ||
62789e0f4d2SKip Macy 		    unlikely(txreq.size > (ETHER_MAX_LEN-ETHER_CRC_LEN))) {
62889e0f4d2SKip Macy 			WPRINTF("Bad packet size: %d\n", txreq.size);
62989e0f4d2SKip Macy 			make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
63089e0f4d2SKip Macy 			netif_put(netif);
63189e0f4d2SKip Macy 			continue;
63289e0f4d2SKip Macy 		}
63389e0f4d2SKip Macy 
63489e0f4d2SKip Macy 		/* No crossing a page as the payload mustn't fragment. */
63589e0f4d2SKip Macy 		if (unlikely((txreq.offset + txreq.size) >= PAGE_SIZE)) {
63689e0f4d2SKip Macy 			WPRINTF("txreq.offset: %x, size: %u, end: %u\n",
63789e0f4d2SKip Macy 				txreq.offset, txreq.size,
63889e0f4d2SKip Macy 				(txreq.offset & PAGE_MASK) + txreq.size);
63989e0f4d2SKip Macy 			make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
64089e0f4d2SKip Macy 			netif_put(netif);
64189e0f4d2SKip Macy 			continue;
64289e0f4d2SKip Macy 		}
64389e0f4d2SKip Macy 
64489e0f4d2SKip Macy 		pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
64589e0f4d2SKip Macy 
64689e0f4d2SKip Macy 		MGETHDR(m, M_DONTWAIT, MT_DATA);
64789e0f4d2SKip Macy 		if (!m) {
64889e0f4d2SKip Macy 			WPRINTF("Failed to allocate mbuf\n");
64989e0f4d2SKip Macy 			make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
65089e0f4d2SKip Macy 			netif_put(netif);
65189e0f4d2SKip Macy 			break;
65289e0f4d2SKip Macy 		}
65389e0f4d2SKip Macy 		m->m_pkthdr.rcvif = netif->ifp;
65489e0f4d2SKip Macy 
65589e0f4d2SKip Macy 		if ((m->m_pkthdr.len = txreq.size) > PKT_PROT_LEN) {
65689e0f4d2SKip Macy 			struct mbuf *n;
65789e0f4d2SKip Macy 			MGET(n, M_DONTWAIT, MT_DATA);
65889e0f4d2SKip Macy 			if (!(m->m_next = n)) {
65989e0f4d2SKip Macy 				m_freem(m);
66089e0f4d2SKip Macy 				WPRINTF("Failed to allocate second mbuf\n");
66189e0f4d2SKip Macy 				make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
66289e0f4d2SKip Macy 				netif_put(netif);
66389e0f4d2SKip Macy 				break;
66489e0f4d2SKip Macy 			}
66589e0f4d2SKip Macy 			n->m_len = txreq.size - PKT_PROT_LEN;
66689e0f4d2SKip Macy 			m->m_len = PKT_PROT_LEN;
66789e0f4d2SKip Macy 		} else
66889e0f4d2SKip Macy 			m->m_len = txreq.size;
66989e0f4d2SKip Macy 
67089e0f4d2SKip Macy 		mop->host_addr = MMAP_VADDR(pending_idx);
67189e0f4d2SKip Macy 		mop->dom       = netif->domid;
67289e0f4d2SKip Macy 		mop->ref       = txreq.gref;
67389e0f4d2SKip Macy 		mop->flags     = GNTMAP_host_map | GNTMAP_readonly;
67489e0f4d2SKip Macy 		mop++;
67589e0f4d2SKip Macy 
67689e0f4d2SKip Macy 		memcpy(&pending_tx_info[pending_idx].req,
67789e0f4d2SKip Macy 		       &txreq, sizeof(txreq));
67889e0f4d2SKip Macy 		pending_tx_info[pending_idx].netif = netif;
67989e0f4d2SKip Macy 		*((uint16_t *)m->m_data) = pending_idx;
68089e0f4d2SKip Macy 
68189e0f4d2SKip Macy 		if (txq_last)
68289e0f4d2SKip Macy 			txq_last->m_nextpkt = m;
68389e0f4d2SKip Macy 		else
68489e0f4d2SKip Macy 			txq = m;
68589e0f4d2SKip Macy 		txq_last = m;
68689e0f4d2SKip Macy 
68789e0f4d2SKip Macy 		pending_cons++;
68889e0f4d2SKip Macy 
68989e0f4d2SKip Macy 		if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
69089e0f4d2SKip Macy 			break;
69189e0f4d2SKip Macy 	}
69289e0f4d2SKip Macy 
69389e0f4d2SKip Macy 	if (!txq)
69489e0f4d2SKip Macy 		return;
69589e0f4d2SKip Macy 
69689e0f4d2SKip Macy 	ret = HYPERVISOR_grant_table_op(
69789e0f4d2SKip Macy 		GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
69889e0f4d2SKip Macy 	BUG_ON(ret);
69989e0f4d2SKip Macy 
70089e0f4d2SKip Macy 	mop = tx_map_ops;
70189e0f4d2SKip Macy 	while ((m = txq) != NULL) {
70289e0f4d2SKip Macy 		caddr_t data;
70389e0f4d2SKip Macy 
70489e0f4d2SKip Macy 		txq = m->m_nextpkt;
70589e0f4d2SKip Macy 		m->m_nextpkt = NULL;
70689e0f4d2SKip Macy 
70789e0f4d2SKip Macy 		pending_idx = *((uint16_t *)m->m_data);
70889e0f4d2SKip Macy 		netif       = pending_tx_info[pending_idx].netif;
70989e0f4d2SKip Macy 		memcpy(&txreq, &pending_tx_info[pending_idx].req, sizeof(txreq));
71089e0f4d2SKip Macy 
71189e0f4d2SKip Macy 		/* Check the remap error code. */
71289e0f4d2SKip Macy 		if (unlikely(mop->status)) {
71389e0f4d2SKip Macy 			WPRINTF("#### netback grant fails\n");
71489e0f4d2SKip Macy 			make_tx_response(netif, txreq.id, NETIF_RSP_ERROR);
71589e0f4d2SKip Macy 			netif_put(netif);
71689e0f4d2SKip Macy 			m_freem(m);
71789e0f4d2SKip Macy 			mop++;
71889e0f4d2SKip Macy 			pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
71989e0f4d2SKip Macy 			continue;
72089e0f4d2SKip Macy 		}
72189e0f4d2SKip Macy 
72289e0f4d2SKip Macy #if 0
72389e0f4d2SKip Macy 		/* Can't do this in FreeBSD since vtophys() returns the pfn */
72489e0f4d2SKip Macy 		/* of the remote domain who loaned us the machine page - DPT */
72589e0f4d2SKip Macy 		xen_phys_machine[(vtophys(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT)] =
72689e0f4d2SKip Macy 			mop->dev_bus_addr >> PAGE_SHIFT;
72789e0f4d2SKip Macy #endif
72889e0f4d2SKip Macy 		grant_tx_handle[pending_idx] = mop->handle;
72989e0f4d2SKip Macy 
73089e0f4d2SKip Macy 		/* Setup data in mbuf (lengths are already set) */
73189e0f4d2SKip Macy 		data = (caddr_t)(MMAP_VADDR(pending_idx)|txreq.offset);
73289e0f4d2SKip Macy 		bcopy(data, m->m_data, m->m_len);
73389e0f4d2SKip Macy 		if (m->m_next) {
73489e0f4d2SKip Macy 			struct mbuf *n = m->m_next;
73589e0f4d2SKip Macy 			MEXTADD(n, MMAP_VADDR(pending_idx), PAGE_SIZE, netif_page_release,
73689e0f4d2SKip Macy 				(void *)(unsigned int)pending_idx, M_RDONLY, EXT_NET_DRV);
73789e0f4d2SKip Macy 			n->m_data = &data[PKT_PROT_LEN];
73889e0f4d2SKip Macy 		} else {
73989e0f4d2SKip Macy 			/* Schedule a response immediately. */
74089e0f4d2SKip Macy 			netif_idx_release(pending_idx);
74189e0f4d2SKip Macy 		}
74289e0f4d2SKip Macy 
74389e0f4d2SKip Macy 		if ((txreq.flags & NETTXF_data_validated)) {
74489e0f4d2SKip Macy 			/* Tell the stack the checksums are okay */
74589e0f4d2SKip Macy 			m->m_pkthdr.csum_flags |=
74689e0f4d2SKip Macy 				(CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
74789e0f4d2SKip Macy 			m->m_pkthdr.csum_data = 0xffff;
74889e0f4d2SKip Macy 		}
74989e0f4d2SKip Macy 
75089e0f4d2SKip Macy 		/* If necessary, inform stack to compute the checksums if it forwards the packet */
75189e0f4d2SKip Macy 		if ((txreq.flags & NETTXF_csum_blank)) {
75289e0f4d2SKip Macy 			struct ether_header *eh = mtod(m, struct ether_header *);
75389e0f4d2SKip Macy 			if (ntohs(eh->ether_type) == ETHERTYPE_IP) {
75489e0f4d2SKip Macy 				struct ip *ip = (struct ip *)&m->m_data[14];
75589e0f4d2SKip Macy 				if (ip->ip_p == IPPROTO_TCP)
75689e0f4d2SKip Macy 					m->m_pkthdr.csum_flags |= CSUM_TCP;
75789e0f4d2SKip Macy 				else if (ip->ip_p == IPPROTO_UDP)
75889e0f4d2SKip Macy 					m->m_pkthdr.csum_flags |= CSUM_UDP;
75989e0f4d2SKip Macy 			}
76089e0f4d2SKip Macy 		}
76189e0f4d2SKip Macy 
76289e0f4d2SKip Macy 		netif->ifp->if_ibytes += m->m_pkthdr.len;
76389e0f4d2SKip Macy 		netif->ifp->if_ipackets++;
76489e0f4d2SKip Macy 
76589e0f4d2SKip Macy 		DDPRINTF("RECV %d bytes from %s (cflags=%x)\n",
76689e0f4d2SKip Macy 			m->m_pkthdr.len, IFNAME(netif), m->m_pkthdr.csum_flags);
76789e0f4d2SKip Macy 		DPRINTF_MBUF_LEN(m, 128);
76889e0f4d2SKip Macy 
76989e0f4d2SKip Macy 		(*netif->ifp->if_input)(netif->ifp, m);
77089e0f4d2SKip Macy 
77189e0f4d2SKip Macy 		mop++;
77289e0f4d2SKip Macy 	}
77389e0f4d2SKip Macy }
77489e0f4d2SKip Macy 
77589e0f4d2SKip Macy /* Handle interrupt from a frontend */
77689e0f4d2SKip Macy static void
77789e0f4d2SKip Macy netback_intr(void *arg)
77889e0f4d2SKip Macy {
77989e0f4d2SKip Macy 	netif_t *netif = arg;
78089e0f4d2SKip Macy 	DDPRINTF("%s\n", IFNAME(netif));
78189e0f4d2SKip Macy 	add_to_tx_schedule_list_tail(netif);
78289e0f4d2SKip Macy 	maybe_schedule_tx_action();
78389e0f4d2SKip Macy }
78489e0f4d2SKip Macy 
78589e0f4d2SKip Macy /* Removes netif from front of list and does not call netif_put() (caller must) */
78689e0f4d2SKip Macy static netif_t *
78789e0f4d2SKip Macy remove_from_rx_schedule_list(void)
78889e0f4d2SKip Macy {
78989e0f4d2SKip Macy 	netif_t *netif;
79089e0f4d2SKip Macy 
79189e0f4d2SKip Macy 	mtx_lock(&rx_sched_list_lock);
79289e0f4d2SKip Macy 
79389e0f4d2SKip Macy 	if ((netif = STAILQ_FIRST(&rx_sched_list))) {
79489e0f4d2SKip Macy 		STAILQ_REMOVE(&rx_sched_list, netif, netback_info, next_rx);
79589e0f4d2SKip Macy 		STAILQ_NEXT(netif, next_rx) = NULL;
79689e0f4d2SKip Macy 		netif->on_rx_sched_list = 0;
79789e0f4d2SKip Macy 	}
79889e0f4d2SKip Macy 
79989e0f4d2SKip Macy 	mtx_unlock(&rx_sched_list_lock);
80089e0f4d2SKip Macy 
80189e0f4d2SKip Macy 	return netif;
80289e0f4d2SKip Macy }
80389e0f4d2SKip Macy 
80489e0f4d2SKip Macy /* Adds netif to end of list and calls netif_get() */
80589e0f4d2SKip Macy static void
80689e0f4d2SKip Macy add_to_rx_schedule_list_tail(netif_t *netif)
80789e0f4d2SKip Macy {
80889e0f4d2SKip Macy 	if (netif->on_rx_sched_list)
80989e0f4d2SKip Macy 		return;
81089e0f4d2SKip Macy 
81189e0f4d2SKip Macy 	mtx_lock(&rx_sched_list_lock);
81289e0f4d2SKip Macy 	if (!netif->on_rx_sched_list && (netif->ifp->if_drv_flags & IFF_DRV_RUNNING)) {
81389e0f4d2SKip Macy 		netif_get(netif);
81489e0f4d2SKip Macy 		STAILQ_INSERT_TAIL(&rx_sched_list, netif, next_rx);
81589e0f4d2SKip Macy 		netif->on_rx_sched_list = 1;
81689e0f4d2SKip Macy 	}
81789e0f4d2SKip Macy 	mtx_unlock(&rx_sched_list_lock);
81889e0f4d2SKip Macy }
81989e0f4d2SKip Macy 
82089e0f4d2SKip Macy static int
82189e0f4d2SKip Macy make_rx_response(netif_t *netif, uint16_t id, int8_t st,
82289e0f4d2SKip Macy 				 uint16_t offset, uint16_t size, uint16_t flags)
82389e0f4d2SKip Macy {
82489e0f4d2SKip Macy 	RING_IDX i = netif->rx.rsp_prod_pvt;
82589e0f4d2SKip Macy 	netif_rx_response_t *resp;
82689e0f4d2SKip Macy 	int notify;
82789e0f4d2SKip Macy 
82889e0f4d2SKip Macy 	resp = RING_GET_RESPONSE(&netif->rx, i);
82989e0f4d2SKip Macy 	resp->offset     = offset;
83089e0f4d2SKip Macy 	resp->flags      = flags;
83189e0f4d2SKip Macy 	resp->id         = id;
83289e0f4d2SKip Macy 	resp->status     = (int16_t)size;
83389e0f4d2SKip Macy 	if (st < 0)
83489e0f4d2SKip Macy 		resp->status = (int16_t)st;
83589e0f4d2SKip Macy 
83689e0f4d2SKip Macy 	DDPRINTF("rx resp(%d): off=%x fl=%x id=%x stat=%d\n",
83789e0f4d2SKip Macy 		i, resp->offset, resp->flags, resp->id, resp->status);
83889e0f4d2SKip Macy 
83989e0f4d2SKip Macy 	netif->rx.rsp_prod_pvt = ++i;
84089e0f4d2SKip Macy 	RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, notify);
84189e0f4d2SKip Macy 
84289e0f4d2SKip Macy 	return notify;
84389e0f4d2SKip Macy }
84489e0f4d2SKip Macy 
84589e0f4d2SKip Macy static int
84689e0f4d2SKip Macy netif_rx(netif_t *netif)
84789e0f4d2SKip Macy {
84889e0f4d2SKip Macy 	struct ifnet *ifp = netif->ifp;
84989e0f4d2SKip Macy 	struct mbuf *m;
85089e0f4d2SKip Macy 	multicall_entry_t *mcl;
85189e0f4d2SKip Macy 	mmu_update_t *mmu;
85289e0f4d2SKip Macy 	gnttab_transfer_t *gop;
85389e0f4d2SKip Macy 	unsigned long vdata, old_mfn, new_mfn;
85489e0f4d2SKip Macy 	struct mbuf *rxq = NULL, *rxq_last = NULL;
85589e0f4d2SKip Macy 	int ret, notify = 0, pkts_dequeued = 0;
85689e0f4d2SKip Macy 
85789e0f4d2SKip Macy 	DDPRINTF("%s\n", IFNAME(netif));
85889e0f4d2SKip Macy 
85989e0f4d2SKip Macy 	mcl = rx_mcl;
86089e0f4d2SKip Macy 	mmu = rx_mmu;
86189e0f4d2SKip Macy 	gop = grant_rx_op;
86289e0f4d2SKip Macy 
86389e0f4d2SKip Macy 	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
86489e0f4d2SKip Macy 
86589e0f4d2SKip Macy 		/* Quit if the target domain has no receive buffers */
86689e0f4d2SKip Macy 		if (netif->rx.req_cons == netif->rx.sring->req_prod)
86789e0f4d2SKip Macy 			break;
86889e0f4d2SKip Macy 
86989e0f4d2SKip Macy 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
87089e0f4d2SKip Macy 		if (m == NULL)
87189e0f4d2SKip Macy 			break;
87289e0f4d2SKip Macy 
87389e0f4d2SKip Macy 		pkts_dequeued++;
87489e0f4d2SKip Macy 
87589e0f4d2SKip Macy 		/* Check if we need to copy the data */
87689e0f4d2SKip Macy 		if (((m->m_flags & (M_RDONLY|M_EXT)) != M_EXT) ||
87789e0f4d2SKip Macy 			(*m->m_ext.ref_cnt > 1) || m->m_next != NULL) {
87889e0f4d2SKip Macy 			struct mbuf *n;
87989e0f4d2SKip Macy 
88089e0f4d2SKip Macy 			DDPRINTF("copying mbuf (fl=%x ext=%x rc=%d n=%x)\n",
88189e0f4d2SKip Macy 				m->m_flags,
88289e0f4d2SKip Macy 				(m->m_flags & M_EXT) ? m->m_ext.ext_type : 0,
88389e0f4d2SKip Macy 				(m->m_flags & M_EXT) ? *m->m_ext.ref_cnt : 0,
88489e0f4d2SKip Macy 				(unsigned int)m->m_next);
88589e0f4d2SKip Macy 
88689e0f4d2SKip Macy 			/* Make copy */
88789e0f4d2SKip Macy 			MGETHDR(n, M_DONTWAIT, MT_DATA);
88889e0f4d2SKip Macy 			if (!n)
88989e0f4d2SKip Macy 				goto drop;
89089e0f4d2SKip Macy 
89189e0f4d2SKip Macy 			MCLGET(n, M_DONTWAIT);
89289e0f4d2SKip Macy 			if (!(n->m_flags & M_EXT)) {
89389e0f4d2SKip Macy 				m_freem(n);
89489e0f4d2SKip Macy 				goto drop;
89589e0f4d2SKip Macy 			}
89689e0f4d2SKip Macy 
89789e0f4d2SKip Macy 			/* Leave space at front and keep current alignment */
89889e0f4d2SKip Macy 			n->m_data += 16 + ((unsigned int)m->m_data & 0x3);
89989e0f4d2SKip Macy 
90089e0f4d2SKip Macy 			if (m->m_pkthdr.len > M_TRAILINGSPACE(n)) {
90189e0f4d2SKip Macy 				WPRINTF("pkt to big %d\n", m->m_pkthdr.len);
90289e0f4d2SKip Macy 				m_freem(n);
90389e0f4d2SKip Macy 				goto drop;
90489e0f4d2SKip Macy 			}
90589e0f4d2SKip Macy 			m_copydata(m, 0, m->m_pkthdr.len, n->m_data);
90689e0f4d2SKip Macy 			n->m_pkthdr.len = n->m_len = m->m_pkthdr.len;
90789e0f4d2SKip Macy 			n->m_pkthdr.csum_flags = (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA);
90889e0f4d2SKip Macy 			m_freem(m);
90989e0f4d2SKip Macy 			m = n;
91089e0f4d2SKip Macy 		}
91189e0f4d2SKip Macy 
91289e0f4d2SKip Macy 		vdata = (unsigned long)m->m_data;
91389e0f4d2SKip Macy 		old_mfn = vtomach(vdata) >> PAGE_SHIFT;
91489e0f4d2SKip Macy 
91589e0f4d2SKip Macy 		if ((new_mfn = alloc_mfn()) == 0)
91689e0f4d2SKip Macy 			goto drop;
91789e0f4d2SKip Macy 
91889e0f4d2SKip Macy #ifdef XEN_NETBACK_FIXUP_CSUM
91989e0f4d2SKip Macy 		/* Check if we need to compute a checksum.  This happens */
92089e0f4d2SKip Macy 		/* when bridging from one domain to another. */
9212f4afd21SRandall Stewart 		if ((m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) ||
9222f4afd21SRandall Stewart 			(m->m_pkthdr.csum_flags & CSUM_SCTP))
92389e0f4d2SKip Macy 			fixup_checksum(m);
92489e0f4d2SKip Macy #endif
92589e0f4d2SKip Macy 
92689e0f4d2SKip Macy 		xen_phys_machine[(vtophys(vdata) >> PAGE_SHIFT)] = new_mfn;
92789e0f4d2SKip Macy 
92889e0f4d2SKip Macy 		mcl->op = __HYPERVISOR_update_va_mapping;
92989e0f4d2SKip Macy 		mcl->args[0] = vdata;
93089e0f4d2SKip Macy 		mcl->args[1] = (new_mfn << PAGE_SHIFT) | PG_V | PG_RW | PG_M | PG_A;
93189e0f4d2SKip Macy 		mcl->args[2] = 0;
93289e0f4d2SKip Macy 		mcl->args[3] = 0;
93389e0f4d2SKip Macy 		mcl++;
93489e0f4d2SKip Macy 
93589e0f4d2SKip Macy 		gop->mfn = old_mfn;
93689e0f4d2SKip Macy 		gop->domid = netif->domid;
93789e0f4d2SKip Macy 		gop->ref = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons)->gref;
93889e0f4d2SKip Macy 		netif->rx.req_cons++;
93989e0f4d2SKip Macy 		gop++;
94089e0f4d2SKip Macy 
94189e0f4d2SKip Macy 		mmu->ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
94289e0f4d2SKip Macy 		mmu->val = vtophys(vdata) >> PAGE_SHIFT;
94389e0f4d2SKip Macy 		mmu++;
94489e0f4d2SKip Macy 
94589e0f4d2SKip Macy 		if (rxq_last)
94689e0f4d2SKip Macy 			rxq_last->m_nextpkt = m;
94789e0f4d2SKip Macy 		else
94889e0f4d2SKip Macy 			rxq = m;
94989e0f4d2SKip Macy 		rxq_last = m;
95089e0f4d2SKip Macy 
95189e0f4d2SKip Macy 		DDPRINTF("XMIT %d bytes to %s\n", m->m_pkthdr.len, IFNAME(netif));
95289e0f4d2SKip Macy 		DPRINTF_MBUF_LEN(m, 128);
95389e0f4d2SKip Macy 
95489e0f4d2SKip Macy 		/* Filled the batch queue? */
95589e0f4d2SKip Macy 		if ((gop - grant_rx_op) == ARRAY_SIZE(grant_rx_op))
95689e0f4d2SKip Macy 			break;
95789e0f4d2SKip Macy 
95889e0f4d2SKip Macy 		continue;
95989e0f4d2SKip Macy 	drop:
96089e0f4d2SKip Macy 		DDPRINTF("dropping pkt\n");
96189e0f4d2SKip Macy 		ifp->if_oerrors++;
96289e0f4d2SKip Macy 		m_freem(m);
96389e0f4d2SKip Macy 	}
96489e0f4d2SKip Macy 
96589e0f4d2SKip Macy 	if (mcl == rx_mcl)
96689e0f4d2SKip Macy 		return pkts_dequeued;
96789e0f4d2SKip Macy 
96889e0f4d2SKip Macy 	mcl->op = __HYPERVISOR_mmu_update;
96989e0f4d2SKip Macy 	mcl->args[0] = (unsigned long)rx_mmu;
97089e0f4d2SKip Macy 	mcl->args[1] = mmu - rx_mmu;
97189e0f4d2SKip Macy 	mcl->args[2] = 0;
97289e0f4d2SKip Macy 	mcl->args[3] = DOMID_SELF;
97389e0f4d2SKip Macy 	mcl++;
97489e0f4d2SKip Macy 
97589e0f4d2SKip Macy 	mcl[-2].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
97689e0f4d2SKip Macy 	ret = HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl);
97789e0f4d2SKip Macy 	BUG_ON(ret != 0);
97889e0f4d2SKip Macy 
97989e0f4d2SKip Macy 	ret = HYPERVISOR_grant_table_op(GNTTABOP_transfer, grant_rx_op, gop - grant_rx_op);
98089e0f4d2SKip Macy 	BUG_ON(ret != 0);
98189e0f4d2SKip Macy 
98289e0f4d2SKip Macy 	mcl = rx_mcl;
98389e0f4d2SKip Macy 	gop = grant_rx_op;
98489e0f4d2SKip Macy 
98589e0f4d2SKip Macy 	while ((m = rxq) != NULL) {
98689e0f4d2SKip Macy 		int8_t status;
98789e0f4d2SKip Macy 		uint16_t id, flags = 0;
98889e0f4d2SKip Macy 
98989e0f4d2SKip Macy 		rxq = m->m_nextpkt;
99089e0f4d2SKip Macy 		m->m_nextpkt = NULL;
99189e0f4d2SKip Macy 
99289e0f4d2SKip Macy 		/* Rederive the machine addresses. */
99389e0f4d2SKip Macy 		new_mfn = mcl->args[1] >> PAGE_SHIFT;
99489e0f4d2SKip Macy 		old_mfn = gop->mfn;
99589e0f4d2SKip Macy 
99689e0f4d2SKip Macy 		ifp->if_obytes += m->m_pkthdr.len;
99789e0f4d2SKip Macy 		ifp->if_opackets++;
99889e0f4d2SKip Macy 
99989e0f4d2SKip Macy 		/* The update_va_mapping() must not fail. */
100089e0f4d2SKip Macy 		BUG_ON(mcl->result != 0);
100189e0f4d2SKip Macy 
100289e0f4d2SKip Macy 		/* Setup flags */
100389e0f4d2SKip Macy 		if ((m->m_pkthdr.csum_flags & CSUM_DELAY_DATA))
100489e0f4d2SKip Macy 			flags |= NETRXF_csum_blank | NETRXF_data_validated;
100589e0f4d2SKip Macy 		else if ((m->m_pkthdr.csum_flags & CSUM_DATA_VALID))
100689e0f4d2SKip Macy 			flags |= NETRXF_data_validated;
100789e0f4d2SKip Macy 
100889e0f4d2SKip Macy 		/* Check the reassignment error code. */
100989e0f4d2SKip Macy 		status = NETIF_RSP_OKAY;
101089e0f4d2SKip Macy 		if (gop->status != 0) {
101189e0f4d2SKip Macy 			DPRINTF("Bad status %d from grant transfer to DOM%u\n",
101289e0f4d2SKip Macy 				gop->status, netif->domid);
101389e0f4d2SKip Macy 			/*
101489e0f4d2SKip Macy 			 * Page no longer belongs to us unless GNTST_bad_page,
101589e0f4d2SKip Macy 			 * but that should be a fatal error anyway.
101689e0f4d2SKip Macy 			 */
101789e0f4d2SKip Macy 			BUG_ON(gop->status == GNTST_bad_page);
101889e0f4d2SKip Macy 			status = NETIF_RSP_ERROR;
101989e0f4d2SKip Macy 		}
102089e0f4d2SKip Macy 		id = RING_GET_REQUEST(&netif->rx, netif->rx.rsp_prod_pvt)->id;
102189e0f4d2SKip Macy 		notify |= make_rx_response(netif, id, status,
102289e0f4d2SKip Macy 					(unsigned long)m->m_data & PAGE_MASK,
102389e0f4d2SKip Macy 					m->m_pkthdr.len, flags);
102489e0f4d2SKip Macy 
102589e0f4d2SKip Macy 		m_freem(m);
102689e0f4d2SKip Macy 		mcl++;
102789e0f4d2SKip Macy 		gop++;
102889e0f4d2SKip Macy 	}
102989e0f4d2SKip Macy 
103089e0f4d2SKip Macy 	if (notify)
103189e0f4d2SKip Macy 		notify_remote_via_irq(netif->irq);
103289e0f4d2SKip Macy 
103389e0f4d2SKip Macy 	return pkts_dequeued;
103489e0f4d2SKip Macy }
103589e0f4d2SKip Macy 
103689e0f4d2SKip Macy static void
103789e0f4d2SKip Macy rx_task_timer(void *arg)
103889e0f4d2SKip Macy {
103989e0f4d2SKip Macy 	DDPRINTF("\n");
104089e0f4d2SKip Macy 	taskqueue_enqueue(taskqueue_swi, &net_rx_task);
104189e0f4d2SKip Macy }
104289e0f4d2SKip Macy 
104389e0f4d2SKip Macy static void
104489e0f4d2SKip Macy net_rx_action(void *context, int pending)
104589e0f4d2SKip Macy {
104689e0f4d2SKip Macy 	netif_t *netif, *last_zero_work = NULL;
104789e0f4d2SKip Macy 
104889e0f4d2SKip Macy 	DDPRINTF("\n");
104989e0f4d2SKip Macy 
105089e0f4d2SKip Macy 	while ((netif = remove_from_rx_schedule_list())) {
105189e0f4d2SKip Macy 		struct ifnet *ifp = netif->ifp;
105289e0f4d2SKip Macy 
105389e0f4d2SKip Macy 		if (netif == last_zero_work) {
105489e0f4d2SKip Macy 			if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
105589e0f4d2SKip Macy 				add_to_rx_schedule_list_tail(netif);
105689e0f4d2SKip Macy 			netif_put(netif);
105789e0f4d2SKip Macy 			if (!STAILQ_EMPTY(&rx_sched_list))
105889e0f4d2SKip Macy 				callout_reset(&rx_task_callout, 1, rx_task_timer, NULL);
105989e0f4d2SKip Macy 			break;
106089e0f4d2SKip Macy 		}
106189e0f4d2SKip Macy 
106289e0f4d2SKip Macy 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) {
106389e0f4d2SKip Macy 			if (netif_rx(netif))
106489e0f4d2SKip Macy 				last_zero_work = NULL;
106589e0f4d2SKip Macy 			else if (!last_zero_work)
106689e0f4d2SKip Macy 				last_zero_work = netif;
106789e0f4d2SKip Macy 			if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
106889e0f4d2SKip Macy 				add_to_rx_schedule_list_tail(netif);
106989e0f4d2SKip Macy 		}
107089e0f4d2SKip Macy 
107189e0f4d2SKip Macy 		netif_put(netif);
107289e0f4d2SKip Macy 	}
107389e0f4d2SKip Macy }
107489e0f4d2SKip Macy 
107589e0f4d2SKip Macy static void
107689e0f4d2SKip Macy netback_start(struct ifnet *ifp)
107789e0f4d2SKip Macy {
107889e0f4d2SKip Macy 	netif_t *netif = (netif_t *)ifp->if_softc;
107989e0f4d2SKip Macy 
108089e0f4d2SKip Macy 	DDPRINTF("%s\n", IFNAME(netif));
108189e0f4d2SKip Macy 
108289e0f4d2SKip Macy 	add_to_rx_schedule_list_tail(netif);
108389e0f4d2SKip Macy 	taskqueue_enqueue(taskqueue_swi, &net_rx_task);
108489e0f4d2SKip Macy }
108589e0f4d2SKip Macy 
108689e0f4d2SKip Macy /* Map a grant ref to a ring */
108789e0f4d2SKip Macy static int
108889e0f4d2SKip Macy map_ring(grant_ref_t ref, domid_t dom, struct ring_ref *ring)
108989e0f4d2SKip Macy {
109089e0f4d2SKip Macy 	struct gnttab_map_grant_ref op;
109189e0f4d2SKip Macy 
109289e0f4d2SKip Macy 	ring->va = kmem_alloc_nofault(kernel_map, PAGE_SIZE);
109389e0f4d2SKip Macy 	if (ring->va == 0)
109489e0f4d2SKip Macy 		return ENOMEM;
109589e0f4d2SKip Macy 
109689e0f4d2SKip Macy 	op.host_addr = ring->va;
109789e0f4d2SKip Macy 	op.flags = GNTMAP_host_map;
109889e0f4d2SKip Macy 	op.ref = ref;
109989e0f4d2SKip Macy 	op.dom = dom;
110089e0f4d2SKip Macy 	HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
110189e0f4d2SKip Macy 	if (op.status) {
110289e0f4d2SKip Macy 		WPRINTF("grant table op err=%d\n", op.status);
110389e0f4d2SKip Macy 		kmem_free(kernel_map, ring->va, PAGE_SIZE);
110489e0f4d2SKip Macy 		ring->va = 0;
110589e0f4d2SKip Macy 		return EACCES;
110689e0f4d2SKip Macy 	}
110789e0f4d2SKip Macy 
110889e0f4d2SKip Macy 	ring->handle = op.handle;
110989e0f4d2SKip Macy 	ring->bus_addr = op.dev_bus_addr;
111089e0f4d2SKip Macy 
111189e0f4d2SKip Macy 	return 0;
111289e0f4d2SKip Macy }
111389e0f4d2SKip Macy 
111489e0f4d2SKip Macy /* Unmap grant ref for a ring */
111589e0f4d2SKip Macy static void
111689e0f4d2SKip Macy unmap_ring(struct ring_ref *ring)
111789e0f4d2SKip Macy {
111889e0f4d2SKip Macy 	struct gnttab_unmap_grant_ref op;
111989e0f4d2SKip Macy 
112089e0f4d2SKip Macy 	op.host_addr = ring->va;
112189e0f4d2SKip Macy 	op.dev_bus_addr = ring->bus_addr;
112289e0f4d2SKip Macy 	op.handle = ring->handle;
112389e0f4d2SKip Macy 	HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
112489e0f4d2SKip Macy 	if (op.status)
112589e0f4d2SKip Macy 		WPRINTF("grant table op err=%d\n", op.status);
112689e0f4d2SKip Macy 
112789e0f4d2SKip Macy 	kmem_free(kernel_map, ring->va, PAGE_SIZE);
112889e0f4d2SKip Macy 	ring->va = 0;
112989e0f4d2SKip Macy }
113089e0f4d2SKip Macy 
113189e0f4d2SKip Macy static int
113289e0f4d2SKip Macy connect_rings(netif_t *netif)
113389e0f4d2SKip Macy {
113489e0f4d2SKip Macy 	struct xenbus_device *xdev = netif->xdev;
113589e0f4d2SKip Macy 	netif_tx_sring_t *txs;
113689e0f4d2SKip Macy 	netif_rx_sring_t *rxs;
113789e0f4d2SKip Macy 	unsigned long tx_ring_ref, rx_ring_ref;
113889e0f4d2SKip Macy 	evtchn_port_t evtchn;
113989e0f4d2SKip Macy 	evtchn_op_t op = { .cmd = EVTCHNOP_bind_interdomain };
114089e0f4d2SKip Macy 	int err;
114189e0f4d2SKip Macy 
114289e0f4d2SKip Macy 	// Grab FE data and map his memory
114389e0f4d2SKip Macy 	err = xenbus_gather(NULL, xdev->otherend,
114489e0f4d2SKip Macy 			"tx-ring-ref", "%lu", &tx_ring_ref,
114589e0f4d2SKip Macy 		    "rx-ring-ref", "%lu", &rx_ring_ref,
114689e0f4d2SKip Macy 		    "event-channel", "%u", &evtchn, NULL);
114789e0f4d2SKip Macy 	if (err) {
114889e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, err,
114989e0f4d2SKip Macy 			"reading %s/ring-ref and event-channel",
115089e0f4d2SKip Macy 			xdev->otherend);
115189e0f4d2SKip Macy 		return err;
115289e0f4d2SKip Macy 	}
115389e0f4d2SKip Macy 
115489e0f4d2SKip Macy 	err = map_ring(tx_ring_ref, netif->domid, &netif->tx_ring_ref);
115589e0f4d2SKip Macy 	if (err) {
115689e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, err, "mapping tx ring");
115789e0f4d2SKip Macy 		return err;
115889e0f4d2SKip Macy 	}
115989e0f4d2SKip Macy 	txs = (netif_tx_sring_t *)netif->tx_ring_ref.va;
116089e0f4d2SKip Macy 	BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
116189e0f4d2SKip Macy 
116289e0f4d2SKip Macy 	err = map_ring(rx_ring_ref, netif->domid, &netif->rx_ring_ref);
116389e0f4d2SKip Macy 	if (err) {
116489e0f4d2SKip Macy 		unmap_ring(&netif->tx_ring_ref);
116589e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, err, "mapping rx ring");
116689e0f4d2SKip Macy 		return err;
116789e0f4d2SKip Macy 	}
116889e0f4d2SKip Macy 	rxs = (netif_rx_sring_t *)netif->rx_ring_ref.va;
116989e0f4d2SKip Macy 	BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
117089e0f4d2SKip Macy 
117189e0f4d2SKip Macy 	op.u.bind_interdomain.remote_dom = netif->domid;
117289e0f4d2SKip Macy 	op.u.bind_interdomain.remote_port = evtchn;
117389e0f4d2SKip Macy 	err = HYPERVISOR_event_channel_op(&op);
117489e0f4d2SKip Macy 	if (err) {
117589e0f4d2SKip Macy 		unmap_ring(&netif->tx_ring_ref);
117689e0f4d2SKip Macy 		unmap_ring(&netif->rx_ring_ref);
117789e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, err, "binding event channel");
117889e0f4d2SKip Macy 		return err;
117989e0f4d2SKip Macy 	}
118089e0f4d2SKip Macy 	netif->evtchn = op.u.bind_interdomain.local_port;
118189e0f4d2SKip Macy 
118289e0f4d2SKip Macy 	/* bind evtchn to irq handler */
118389e0f4d2SKip Macy 	netif->irq =
118489e0f4d2SKip Macy 		bind_evtchn_to_irqhandler(netif->evtchn, "netback",
118589e0f4d2SKip Macy 			netback_intr, netif, INTR_TYPE_NET|INTR_MPSAFE, &netif->irq_cookie);
118689e0f4d2SKip Macy 
118789e0f4d2SKip Macy 	netif->rings_connected = 1;
118889e0f4d2SKip Macy 
118989e0f4d2SKip Macy 	DPRINTF("%s connected! evtchn=%d irq=%d\n",
119089e0f4d2SKip Macy 		IFNAME(netif), netif->evtchn, netif->irq);
119189e0f4d2SKip Macy 
119289e0f4d2SKip Macy 	return 0;
119389e0f4d2SKip Macy }
119489e0f4d2SKip Macy 
119589e0f4d2SKip Macy static void
119689e0f4d2SKip Macy disconnect_rings(netif_t *netif)
119789e0f4d2SKip Macy {
119889e0f4d2SKip Macy 	DPRINTF("\n");
119989e0f4d2SKip Macy 
120089e0f4d2SKip Macy 	if (netif->rings_connected) {
120189e0f4d2SKip Macy 		unbind_from_irqhandler(netif->irq, netif->irq_cookie);
120289e0f4d2SKip Macy 		netif->irq = 0;
120389e0f4d2SKip Macy 		unmap_ring(&netif->tx_ring_ref);
120489e0f4d2SKip Macy 		unmap_ring(&netif->rx_ring_ref);
120589e0f4d2SKip Macy 		netif->rings_connected = 0;
120689e0f4d2SKip Macy 	}
120789e0f4d2SKip Macy }
120889e0f4d2SKip Macy 
120989e0f4d2SKip Macy static void
121089e0f4d2SKip Macy connect(netif_t *netif)
121189e0f4d2SKip Macy {
121289e0f4d2SKip Macy 	if (!netif->xdev ||
121389e0f4d2SKip Macy 		!netif->attached ||
121489e0f4d2SKip Macy 		netif->frontend_state != XenbusStateConnected) {
121589e0f4d2SKip Macy 		return;
121689e0f4d2SKip Macy 	}
121789e0f4d2SKip Macy 
121889e0f4d2SKip Macy 	if (!connect_rings(netif)) {
121989e0f4d2SKip Macy 		xenbus_switch_state(netif->xdev, NULL, XenbusStateConnected);
122089e0f4d2SKip Macy 
122189e0f4d2SKip Macy 		/* Turn on interface */
122289e0f4d2SKip Macy 		netif->ifp->if_drv_flags |= IFF_DRV_RUNNING;
122389e0f4d2SKip Macy 		netif->ifp->if_flags |= IFF_UP;
122489e0f4d2SKip Macy 	}
122589e0f4d2SKip Macy }
122689e0f4d2SKip Macy 
122789e0f4d2SKip Macy static int
122889e0f4d2SKip Macy netback_remove(struct xenbus_device *xdev)
122989e0f4d2SKip Macy {
123089e0f4d2SKip Macy 	netif_t *netif = xdev->data;
123189e0f4d2SKip Macy 	device_t ndev;
123289e0f4d2SKip Macy 
123389e0f4d2SKip Macy 	DPRINTF("remove %s\n", xdev->nodename);
123489e0f4d2SKip Macy 
123589e0f4d2SKip Macy 	if ((ndev = netif->ndev)) {
123689e0f4d2SKip Macy 		netif->ndev = NULL;
123789e0f4d2SKip Macy 		mtx_lock(&Giant);
123889e0f4d2SKip Macy 		device_detach(ndev);
123989e0f4d2SKip Macy 		mtx_unlock(&Giant);
124089e0f4d2SKip Macy 	}
124189e0f4d2SKip Macy 
124289e0f4d2SKip Macy 	xdev->data = NULL;
124389e0f4d2SKip Macy 	netif->xdev = NULL;
124489e0f4d2SKip Macy 	netif_put(netif);
124589e0f4d2SKip Macy 
124689e0f4d2SKip Macy 	return 0;
124789e0f4d2SKip Macy }
124889e0f4d2SKip Macy 
124989e0f4d2SKip Macy /**
125089e0f4d2SKip Macy  * Entry point to this code when a new device is created.  Allocate the basic
125189e0f4d2SKip Macy  * structures and the ring buffers for communication with the frontend.
125289e0f4d2SKip Macy  * Switch to Connected state.
125389e0f4d2SKip Macy  */
125489e0f4d2SKip Macy static int
125589e0f4d2SKip Macy netback_probe(struct xenbus_device *xdev, const struct xenbus_device_id *id)
125689e0f4d2SKip Macy {
125789e0f4d2SKip Macy 	int err;
125889e0f4d2SKip Macy 	long handle;
125989e0f4d2SKip Macy 	char *bridge;
126089e0f4d2SKip Macy 
126189e0f4d2SKip Macy 	DPRINTF("node=%s\n", xdev->nodename);
126289e0f4d2SKip Macy 
126389e0f4d2SKip Macy 	/* Grab the handle */
126489e0f4d2SKip Macy 	err = xenbus_scanf(NULL, xdev->nodename, "handle", "%li", &handle);
126589e0f4d2SKip Macy 	if (err != 1) {
126689e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, err, "reading handle");
126789e0f4d2SKip Macy 		return err;
126889e0f4d2SKip Macy 	}
126989e0f4d2SKip Macy 
127089e0f4d2SKip Macy 	/* Check for bridge */
127189e0f4d2SKip Macy 	bridge = xenbus_read(NULL, xdev->nodename, "bridge", NULL);
127289e0f4d2SKip Macy 	if (IS_ERR(bridge))
127389e0f4d2SKip Macy 		bridge = NULL;
127489e0f4d2SKip Macy 
127589e0f4d2SKip Macy 	err = xenbus_switch_state(xdev, NULL, XenbusStateInitWait);
127689e0f4d2SKip Macy 	if (err) {
127789e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, err, "writing switch state");
127889e0f4d2SKip Macy 		return err;
127989e0f4d2SKip Macy 	}
128089e0f4d2SKip Macy 
128189e0f4d2SKip Macy 	err = netif_create(handle, xdev, bridge);
128289e0f4d2SKip Macy 	if (err) {
128389e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, err, "creating netif");
128489e0f4d2SKip Macy 		return err;
128589e0f4d2SKip Macy 	}
128689e0f4d2SKip Macy 
128789e0f4d2SKip Macy 	err = vif_add_dev(xdev);
128889e0f4d2SKip Macy 	if (err) {
128989e0f4d2SKip Macy 		netif_put((netif_t *)xdev->data);
129089e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, err, "adding vif device");
129189e0f4d2SKip Macy 		return err;
129289e0f4d2SKip Macy 	}
129389e0f4d2SKip Macy 
129489e0f4d2SKip Macy 	return 0;
129589e0f4d2SKip Macy }
129689e0f4d2SKip Macy 
129789e0f4d2SKip Macy /**
129889e0f4d2SKip Macy  * We are reconnecting to the backend, due to a suspend/resume, or a backend
129989e0f4d2SKip Macy  * driver restart.  We tear down our netif structure and recreate it, but
130089e0f4d2SKip Macy  * leave the device-layer structures intact so that this is transparent to the
130189e0f4d2SKip Macy  * rest of the kernel.
130289e0f4d2SKip Macy  */
130389e0f4d2SKip Macy static int netback_resume(struct xenbus_device *xdev)
130489e0f4d2SKip Macy {
130589e0f4d2SKip Macy 	DPRINTF("node=%s\n", xdev->nodename);
130689e0f4d2SKip Macy 	return 0;
130789e0f4d2SKip Macy }
130889e0f4d2SKip Macy 
130989e0f4d2SKip Macy 
131089e0f4d2SKip Macy /**
131189e0f4d2SKip Macy  * Callback received when the frontend's state changes.
131289e0f4d2SKip Macy  */
131389e0f4d2SKip Macy static void frontend_changed(struct xenbus_device *xdev,
131489e0f4d2SKip Macy 							 XenbusState frontend_state)
131589e0f4d2SKip Macy {
131689e0f4d2SKip Macy 	netif_t *netif = xdev->data;
131789e0f4d2SKip Macy 
131889e0f4d2SKip Macy 	DPRINTF("state=%d\n", frontend_state);
131989e0f4d2SKip Macy 
132089e0f4d2SKip Macy 	netif->frontend_state = frontend_state;
132189e0f4d2SKip Macy 
132289e0f4d2SKip Macy 	switch (frontend_state) {
132389e0f4d2SKip Macy 	case XenbusStateInitialising:
132489e0f4d2SKip Macy 	case XenbusStateInitialised:
132589e0f4d2SKip Macy 		break;
132689e0f4d2SKip Macy 	case XenbusStateConnected:
132789e0f4d2SKip Macy 		connect(netif);
132889e0f4d2SKip Macy 		break;
132989e0f4d2SKip Macy 	case XenbusStateClosing:
133089e0f4d2SKip Macy 		xenbus_switch_state(xdev, NULL, XenbusStateClosing);
133189e0f4d2SKip Macy 		break;
133289e0f4d2SKip Macy 	case XenbusStateClosed:
133389e0f4d2SKip Macy 		xenbus_remove_device(xdev);
133489e0f4d2SKip Macy 		break;
133589e0f4d2SKip Macy 	case XenbusStateUnknown:
133689e0f4d2SKip Macy 	case XenbusStateInitWait:
133789e0f4d2SKip Macy 		xenbus_dev_fatal(xdev, EINVAL, "saw state %d at frontend",
133889e0f4d2SKip Macy 						 frontend_state);
133989e0f4d2SKip Macy 		break;
134089e0f4d2SKip Macy 	}
134189e0f4d2SKip Macy }
134289e0f4d2SKip Macy 
134389e0f4d2SKip Macy /* ** Driver registration ** */
134489e0f4d2SKip Macy 
134589e0f4d2SKip Macy static struct xenbus_device_id netback_ids[] = {
134689e0f4d2SKip Macy 	{ "vif" },
134789e0f4d2SKip Macy 	{ "" }
134889e0f4d2SKip Macy };
134989e0f4d2SKip Macy 
135089e0f4d2SKip Macy static struct xenbus_driver netback = {
135189e0f4d2SKip Macy 	.name = "netback",
135289e0f4d2SKip Macy 	.ids = netback_ids,
135389e0f4d2SKip Macy 	.probe = netback_probe,
135489e0f4d2SKip Macy 	.remove = netback_remove,
135589e0f4d2SKip Macy 	.resume= netback_resume,
135689e0f4d2SKip Macy 	.otherend_changed = frontend_changed,
135789e0f4d2SKip Macy };
135889e0f4d2SKip Macy 
135989e0f4d2SKip Macy static void
136089e0f4d2SKip Macy netback_init(void *unused)
136189e0f4d2SKip Macy {
136289e0f4d2SKip Macy 	callout_init(&rx_task_callout, CALLOUT_MPSAFE);
136389e0f4d2SKip Macy 
136489e0f4d2SKip Macy 	mmap_vstart = alloc_empty_page_range(MAX_PENDING_REQS);
136589e0f4d2SKip Macy 	BUG_ON(!mmap_vstart);
136689e0f4d2SKip Macy 
136789e0f4d2SKip Macy 	pending_cons = 0;
136889e0f4d2SKip Macy 	for (pending_prod = 0; pending_prod < MAX_PENDING_REQS; pending_prod++)
136989e0f4d2SKip Macy 		pending_ring[pending_prod] = pending_prod;
137089e0f4d2SKip Macy 
137189e0f4d2SKip Macy 	TASK_INIT(&net_tx_task, 0, net_tx_action, NULL);
137289e0f4d2SKip Macy 	TASK_INIT(&net_rx_task, 0, net_rx_action, NULL);
137389e0f4d2SKip Macy 	mtx_init(&tx_sched_list_lock, "nb_tx_sched_lock", "netback tx sched lock", MTX_DEF);
137489e0f4d2SKip Macy 	mtx_init(&rx_sched_list_lock, "nb_rx_sched_lock", "netback rx sched lock", MTX_DEF);
137589e0f4d2SKip Macy 
137689e0f4d2SKip Macy 	DPRINTF("registering %s\n", netback.name);
137789e0f4d2SKip Macy 
137889e0f4d2SKip Macy 	xenbus_register_backend(&netback);
137989e0f4d2SKip Macy }
138089e0f4d2SKip Macy 
138189e0f4d2SKip Macy SYSINIT(xnbedev, SI_SUB_PSEUDO, SI_ORDER_ANY, netback_init, NULL)
138289e0f4d2SKip Macy 
138389e0f4d2SKip Macy static int
138489e0f4d2SKip Macy vif_add_dev(struct xenbus_device *xdev)
138589e0f4d2SKip Macy {
138689e0f4d2SKip Macy 	netif_t *netif = xdev->data;
138789e0f4d2SKip Macy 	device_t nexus, ndev;
138889e0f4d2SKip Macy 	devclass_t dc;
138989e0f4d2SKip Macy 	int err = 0;
139089e0f4d2SKip Macy 
139189e0f4d2SKip Macy 	mtx_lock(&Giant);
139289e0f4d2SKip Macy 
139389e0f4d2SKip Macy 	/* We will add a vif device as a child of nexus0 (for now) */
139489e0f4d2SKip Macy 	if (!(dc = devclass_find("nexus")) ||
139589e0f4d2SKip Macy 		!(nexus = devclass_get_device(dc, 0))) {
139689e0f4d2SKip Macy 		WPRINTF("could not find nexus0!\n");
139789e0f4d2SKip Macy 		err = ENOENT;
139889e0f4d2SKip Macy 		goto done;
139989e0f4d2SKip Macy 	}
140089e0f4d2SKip Macy 
140189e0f4d2SKip Macy 
140289e0f4d2SKip Macy 	/* Create a newbus device representing the vif */
140389e0f4d2SKip Macy 	ndev = BUS_ADD_CHILD(nexus, 0, "vif", netif->ifp->if_dunit);
140489e0f4d2SKip Macy 	if (!ndev) {
140589e0f4d2SKip Macy 		WPRINTF("could not create newbus device %s!\n", IFNAME(netif));
140689e0f4d2SKip Macy 		err = EFAULT;
140789e0f4d2SKip Macy 		goto done;
140889e0f4d2SKip Macy 	}
140989e0f4d2SKip Macy 
141089e0f4d2SKip Macy 	netif_get(netif);
141189e0f4d2SKip Macy 	device_set_ivars(ndev, netif);
141289e0f4d2SKip Macy 	netif->ndev = ndev;
141389e0f4d2SKip Macy 
141489e0f4d2SKip Macy 	device_probe_and_attach(ndev);
141589e0f4d2SKip Macy 
141689e0f4d2SKip Macy  done:
141789e0f4d2SKip Macy 
141889e0f4d2SKip Macy 	mtx_unlock(&Giant);
141989e0f4d2SKip Macy 
142089e0f4d2SKip Macy 	return err;
142189e0f4d2SKip Macy }
142289e0f4d2SKip Macy 
142389e0f4d2SKip Macy enum {
142489e0f4d2SKip Macy 	VIF_SYSCTL_DOMID,
142589e0f4d2SKip Macy 	VIF_SYSCTL_HANDLE,
142689e0f4d2SKip Macy 	VIF_SYSCTL_TXRING,
142789e0f4d2SKip Macy 	VIF_SYSCTL_RXRING,
142889e0f4d2SKip Macy };
142989e0f4d2SKip Macy 
143089e0f4d2SKip Macy static char *
143189e0f4d2SKip Macy vif_sysctl_ring_info(netif_t *netif, int cmd)
143289e0f4d2SKip Macy {
143389e0f4d2SKip Macy 	char *buf = malloc(256, M_DEVBUF, M_WAITOK);
143489e0f4d2SKip Macy 	if (buf) {
143589e0f4d2SKip Macy 		if (!netif->rings_connected)
143689e0f4d2SKip Macy 			sprintf(buf, "rings not connected\n");
143789e0f4d2SKip Macy 		else if (cmd == VIF_SYSCTL_TXRING) {
143889e0f4d2SKip Macy 			netif_tx_back_ring_t *tx = &netif->tx;
143989e0f4d2SKip Macy 			sprintf(buf, "nr_ents=%x req_cons=%x"
144089e0f4d2SKip Macy 					" req_prod=%x req_event=%x"
144189e0f4d2SKip Macy 					" rsp_prod=%x rsp_event=%x",
144289e0f4d2SKip Macy 					tx->nr_ents, tx->req_cons,
144389e0f4d2SKip Macy 					tx->sring->req_prod, tx->sring->req_event,
144489e0f4d2SKip Macy 					tx->sring->rsp_prod, tx->sring->rsp_event);
144589e0f4d2SKip Macy 		} else {
144689e0f4d2SKip Macy 			netif_rx_back_ring_t *rx = &netif->rx;
144789e0f4d2SKip Macy 			sprintf(buf, "nr_ents=%x req_cons=%x"
144889e0f4d2SKip Macy 					" req_prod=%x req_event=%x"
144989e0f4d2SKip Macy 					" rsp_prod=%x rsp_event=%x",
145089e0f4d2SKip Macy 					rx->nr_ents, rx->req_cons,
145189e0f4d2SKip Macy 					rx->sring->req_prod, rx->sring->req_event,
145289e0f4d2SKip Macy 					rx->sring->rsp_prod, rx->sring->rsp_event);
145389e0f4d2SKip Macy 		}
145489e0f4d2SKip Macy 	}
145589e0f4d2SKip Macy 	return buf;
145689e0f4d2SKip Macy }
145789e0f4d2SKip Macy 
145889e0f4d2SKip Macy static int
145989e0f4d2SKip Macy vif_sysctl_handler(SYSCTL_HANDLER_ARGS)
146089e0f4d2SKip Macy {
146189e0f4d2SKip Macy 	device_t dev = (device_t)arg1;
146289e0f4d2SKip Macy 	netif_t *netif = (netif_t *)device_get_ivars(dev);
146389e0f4d2SKip Macy 	const char *value;
146489e0f4d2SKip Macy 	char *buf = NULL;
146589e0f4d2SKip Macy 	int err;
146689e0f4d2SKip Macy 
146789e0f4d2SKip Macy 	switch (arg2) {
146889e0f4d2SKip Macy 	case VIF_SYSCTL_DOMID:
146989e0f4d2SKip Macy 		return sysctl_handle_int(oidp, NULL, netif->domid, req);
147089e0f4d2SKip Macy 	case VIF_SYSCTL_HANDLE:
147189e0f4d2SKip Macy 		return sysctl_handle_int(oidp, NULL, netif->handle, req);
147289e0f4d2SKip Macy 	case VIF_SYSCTL_TXRING:
147389e0f4d2SKip Macy 	case VIF_SYSCTL_RXRING:
147489e0f4d2SKip Macy 		value = buf = vif_sysctl_ring_info(netif, arg2);
147589e0f4d2SKip Macy 		break;
147689e0f4d2SKip Macy 	default:
147789e0f4d2SKip Macy 		return (EINVAL);
147889e0f4d2SKip Macy 	}
147989e0f4d2SKip Macy 
148089e0f4d2SKip Macy 	err = SYSCTL_OUT(req, value, strlen(value));
148189e0f4d2SKip Macy 	if (buf != NULL)
148289e0f4d2SKip Macy 		free(buf, M_DEVBUF);
148389e0f4d2SKip Macy 
148489e0f4d2SKip Macy 	return err;
148589e0f4d2SKip Macy }
148689e0f4d2SKip Macy 
148789e0f4d2SKip Macy /* Newbus vif device driver probe */
148889e0f4d2SKip Macy static int
148989e0f4d2SKip Macy vif_probe(device_t dev)
149089e0f4d2SKip Macy {
149189e0f4d2SKip Macy 	DDPRINTF("vif%d\n", device_get_unit(dev));
149289e0f4d2SKip Macy 	return 0;
149389e0f4d2SKip Macy }
149489e0f4d2SKip Macy 
149589e0f4d2SKip Macy /* Newbus vif device driver attach */
149689e0f4d2SKip Macy static int
149789e0f4d2SKip Macy vif_attach(device_t dev)
149889e0f4d2SKip Macy {
149989e0f4d2SKip Macy 	netif_t *netif = (netif_t *)device_get_ivars(dev);
150089e0f4d2SKip Macy 	uint8_t mac[ETHER_ADDR_LEN];
150189e0f4d2SKip Macy 
150289e0f4d2SKip Macy 	DDPRINTF("%s\n", IFNAME(netif));
150389e0f4d2SKip Macy 
150489e0f4d2SKip Macy 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
150589e0f4d2SKip Macy 	    OID_AUTO, "domid", CTLTYPE_INT|CTLFLAG_RD,
150689e0f4d2SKip Macy 	    dev, VIF_SYSCTL_DOMID, vif_sysctl_handler, "I",
150789e0f4d2SKip Macy 	    "domid of frontend");
150889e0f4d2SKip Macy 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
150989e0f4d2SKip Macy 	    OID_AUTO, "handle", CTLTYPE_INT|CTLFLAG_RD,
151089e0f4d2SKip Macy 	    dev, VIF_SYSCTL_HANDLE, vif_sysctl_handler, "I",
151189e0f4d2SKip Macy 	    "handle of frontend");
151289e0f4d2SKip Macy #ifdef XEN_NETBACK_DEBUG
151389e0f4d2SKip Macy 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
151489e0f4d2SKip Macy 	    OID_AUTO, "txring", CTLFLAG_RD,
151589e0f4d2SKip Macy 	    dev, VIF_SYSCTL_TXRING, vif_sysctl_handler, "A",
151689e0f4d2SKip Macy 	    "tx ring info");
151789e0f4d2SKip Macy 	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
151889e0f4d2SKip Macy 	    OID_AUTO, "rxring", CTLFLAG_RD,
151989e0f4d2SKip Macy 	    dev, VIF_SYSCTL_RXRING, vif_sysctl_handler, "A",
152089e0f4d2SKip Macy 	    "rx ring info");
152189e0f4d2SKip Macy #endif
152289e0f4d2SKip Macy 
152389e0f4d2SKip Macy 	memset(mac, 0xff, sizeof(mac));
152489e0f4d2SKip Macy 	mac[0] &= ~0x01;
152589e0f4d2SKip Macy 
152689e0f4d2SKip Macy 	ether_ifattach(netif->ifp, mac);
152789e0f4d2SKip Macy 	netif->attached = 1;
152889e0f4d2SKip Macy 
152989e0f4d2SKip Macy 	connect(netif);
153089e0f4d2SKip Macy 
153189e0f4d2SKip Macy 	if (netif->bridge) {
153289e0f4d2SKip Macy 		DPRINTF("Adding %s to bridge %s\n", IFNAME(netif), netif->bridge);
153389e0f4d2SKip Macy 		int err = add_to_bridge(netif->ifp, netif->bridge);
153489e0f4d2SKip Macy 		if (err) {
153589e0f4d2SKip Macy 			WPRINTF("Error adding %s to %s; err=%d\n",
153689e0f4d2SKip Macy 				IFNAME(netif), netif->bridge, err);
153789e0f4d2SKip Macy 		}
153889e0f4d2SKip Macy 	}
153989e0f4d2SKip Macy 
154089e0f4d2SKip Macy 	return bus_generic_attach(dev);
154189e0f4d2SKip Macy }
154289e0f4d2SKip Macy 
154389e0f4d2SKip Macy /* Newbus vif device driver detach */
154489e0f4d2SKip Macy static int
154589e0f4d2SKip Macy vif_detach(device_t dev)
154689e0f4d2SKip Macy {
154789e0f4d2SKip Macy 	netif_t *netif = (netif_t *)device_get_ivars(dev);
154889e0f4d2SKip Macy 	struct ifnet *ifp = netif->ifp;
154989e0f4d2SKip Macy 
155089e0f4d2SKip Macy 	DDPRINTF("%s\n", IFNAME(netif));
155189e0f4d2SKip Macy 
155289e0f4d2SKip Macy 	/* Tell the stack that the interface is no longer active */
155389e0f4d2SKip Macy 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
155489e0f4d2SKip Macy 
155589e0f4d2SKip Macy 	ether_ifdetach(ifp);
155689e0f4d2SKip Macy 
155789e0f4d2SKip Macy 	bus_generic_detach(dev);
155889e0f4d2SKip Macy 
155989e0f4d2SKip Macy 	netif->attached = 0;
156089e0f4d2SKip Macy 
156189e0f4d2SKip Macy 	netif_put(netif);
156289e0f4d2SKip Macy 
156389e0f4d2SKip Macy 	return 0;
156489e0f4d2SKip Macy }
156589e0f4d2SKip Macy 
156689e0f4d2SKip Macy static device_method_t vif_methods[] = {
156789e0f4d2SKip Macy 	/* Device interface */
156889e0f4d2SKip Macy 	DEVMETHOD(device_probe,		vif_probe),
156989e0f4d2SKip Macy 	DEVMETHOD(device_attach, 	vif_attach),
157089e0f4d2SKip Macy 	DEVMETHOD(device_detach,	vif_detach),
157189e0f4d2SKip Macy 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
157289e0f4d2SKip Macy 	DEVMETHOD(device_suspend,	bus_generic_suspend),
157389e0f4d2SKip Macy 	DEVMETHOD(device_resume,	bus_generic_resume),
157489e0f4d2SKip Macy 	{0, 0}
157589e0f4d2SKip Macy };
157689e0f4d2SKip Macy 
157789e0f4d2SKip Macy static devclass_t vif_devclass;
157889e0f4d2SKip Macy 
157989e0f4d2SKip Macy static driver_t vif_driver = {
158089e0f4d2SKip Macy 	"vif",
158189e0f4d2SKip Macy 	vif_methods,
158289e0f4d2SKip Macy 	0,
158389e0f4d2SKip Macy };
158489e0f4d2SKip Macy 
158589e0f4d2SKip Macy DRIVER_MODULE(vif, nexus, vif_driver, vif_devclass, 0, 0);
158689e0f4d2SKip Macy 
158789e0f4d2SKip Macy 
158889e0f4d2SKip Macy /*
158989e0f4d2SKip Macy  * Local variables:
159089e0f4d2SKip Macy  * mode: C
159189e0f4d2SKip Macy  * c-set-style: "BSD"
159289e0f4d2SKip Macy  * c-basic-offset: 4
159389e0f4d2SKip Macy  * tab-width: 4
159489e0f4d2SKip Macy  * indent-tabs-mode: t
159589e0f4d2SKip Macy  * End:
159689e0f4d2SKip Macy  */
1597