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