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