189e0f4d2SKip Macy /* 289e0f4d2SKip Macy * 389e0f4d2SKip Macy * Copyright (c) 2004-2006 Kip Macy 489e0f4d2SKip Macy * All rights reserved. 589e0f4d2SKip Macy * 689e0f4d2SKip Macy * 789e0f4d2SKip Macy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 889e0f4d2SKip Macy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 989e0f4d2SKip Macy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1089e0f4d2SKip Macy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1189e0f4d2SKip Macy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1289e0f4d2SKip Macy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1389e0f4d2SKip Macy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1489e0f4d2SKip Macy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1589e0f4d2SKip Macy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 1689e0f4d2SKip Macy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1789e0f4d2SKip Macy */ 1889e0f4d2SKip Macy 1989e0f4d2SKip Macy 2089e0f4d2SKip Macy #include <sys/cdefs.h> 2189e0f4d2SKip Macy __FBSDID("$FreeBSD$"); 2289e0f4d2SKip Macy 2389e0f4d2SKip Macy #include <sys/param.h> 2489e0f4d2SKip Macy #include <sys/systm.h> 2589e0f4d2SKip Macy #include <sys/sockio.h> 2689e0f4d2SKip Macy #include <sys/mbuf.h> 2789e0f4d2SKip Macy #include <sys/malloc.h> 2889e0f4d2SKip Macy #include <sys/kernel.h> 2989e0f4d2SKip Macy #include <sys/socket.h> 3089e0f4d2SKip Macy #include <sys/queue.h> 3189e0f4d2SKip Macy #include <sys/sx.h> 3289e0f4d2SKip Macy 3389e0f4d2SKip Macy #include <net/if.h> 3489e0f4d2SKip Macy #include <net/if_arp.h> 3589e0f4d2SKip Macy #include <net/ethernet.h> 3689e0f4d2SKip Macy #include <net/if_dl.h> 3789e0f4d2SKip Macy #include <net/if_media.h> 3889e0f4d2SKip Macy 3989e0f4d2SKip Macy #include <net/bpf.h> 4089e0f4d2SKip Macy 4189e0f4d2SKip Macy #include <net/if_types.h> 4289e0f4d2SKip Macy #include <net/if.h> 4389e0f4d2SKip Macy 4489e0f4d2SKip Macy #include <netinet/in_systm.h> 4589e0f4d2SKip Macy #include <netinet/in.h> 4689e0f4d2SKip Macy #include <netinet/ip.h> 4789e0f4d2SKip Macy #include <netinet/if_ether.h> 4889e0f4d2SKip Macy 4989e0f4d2SKip Macy #include <vm/vm.h> 5089e0f4d2SKip Macy #include <vm/pmap.h> 5189e0f4d2SKip Macy 5289e0f4d2SKip Macy #include <machine/clock.h> /* for DELAY */ 5389e0f4d2SKip Macy #include <machine/bus.h> 5489e0f4d2SKip Macy #include <machine/resource.h> 5589e0f4d2SKip Macy #include <machine/frame.h> 56980c7178SKip Macy #include <machine/vmparam.h> 5789e0f4d2SKip Macy 5889e0f4d2SKip Macy #include <sys/bus.h> 5989e0f4d2SKip Macy #include <sys/rman.h> 6089e0f4d2SKip Macy 6189e0f4d2SKip Macy #include <machine/intr_machdep.h> 6289e0f4d2SKip Macy 6389e0f4d2SKip Macy #include <machine/xen/xen-os.h> 6489e0f4d2SKip Macy #include <machine/xen/hypervisor.h> 6589e0f4d2SKip Macy #include <machine/xen/xen_intr.h> 6689e0f4d2SKip Macy #include <machine/xen/evtchn.h> 6789e0f4d2SKip Macy #include <machine/xen/xenbus.h> 6889e0f4d2SKip Macy #include <xen/gnttab.h> 6989e0f4d2SKip Macy #include <xen/interface/memory.h> 7089e0f4d2SKip Macy #include <dev/xen/netfront/mbufq.h> 7189e0f4d2SKip Macy #include <machine/xen/features.h> 7289e0f4d2SKip Macy #include <xen/interface/io/netif.h> 7389e0f4d2SKip Macy 7489e0f4d2SKip Macy 7589e0f4d2SKip Macy #define GRANT_INVALID_REF 0 7689e0f4d2SKip Macy 7789e0f4d2SKip Macy #define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE) 7889e0f4d2SKip Macy #define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE) 7989e0f4d2SKip Macy 8089e0f4d2SKip Macy #ifdef CONFIG_XEN 8189e0f4d2SKip Macy static int MODPARM_rx_copy = 0; 8289e0f4d2SKip Macy module_param_named(rx_copy, MODPARM_rx_copy, bool, 0); 8389e0f4d2SKip Macy MODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)"); 8489e0f4d2SKip Macy static int MODPARM_rx_flip = 0; 8589e0f4d2SKip Macy module_param_named(rx_flip, MODPARM_rx_flip, bool, 0); 8689e0f4d2SKip Macy MODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)"); 8789e0f4d2SKip Macy #else 8889e0f4d2SKip Macy static const int MODPARM_rx_copy = 1; 8989e0f4d2SKip Macy static const int MODPARM_rx_flip = 0; 9089e0f4d2SKip Macy #endif 9189e0f4d2SKip Macy 9289e0f4d2SKip Macy #define RX_COPY_THRESHOLD 256 9389e0f4d2SKip Macy 9489e0f4d2SKip Macy #define net_ratelimit() 0 9589e0f4d2SKip Macy 9689e0f4d2SKip Macy struct netfront_info; 9789e0f4d2SKip Macy struct netfront_rx_info; 9889e0f4d2SKip Macy 9989e0f4d2SKip Macy static void xn_txeof(struct netfront_info *); 10089e0f4d2SKip Macy static void xn_rxeof(struct netfront_info *); 10189e0f4d2SKip Macy static void network_alloc_rx_buffers(struct netfront_info *); 10289e0f4d2SKip Macy 10389e0f4d2SKip Macy static void xn_tick_locked(struct netfront_info *); 10489e0f4d2SKip Macy static void xn_tick(void *); 10589e0f4d2SKip Macy 10689e0f4d2SKip Macy static void xn_intr(void *); 10789e0f4d2SKip Macy static void xn_start_locked(struct ifnet *); 10889e0f4d2SKip Macy static void xn_start(struct ifnet *); 10989e0f4d2SKip Macy static int xn_ioctl(struct ifnet *, u_long, caddr_t); 11089e0f4d2SKip Macy static void xn_ifinit_locked(struct netfront_info *); 11189e0f4d2SKip Macy static void xn_ifinit(void *); 11289e0f4d2SKip Macy static void xn_stop(struct netfront_info *); 11389e0f4d2SKip Macy #ifdef notyet 11489e0f4d2SKip Macy static void xn_watchdog(struct ifnet *); 11589e0f4d2SKip Macy #endif 11689e0f4d2SKip Macy 11789e0f4d2SKip Macy static void show_device(struct netfront_info *sc); 11889e0f4d2SKip Macy #ifdef notyet 11989e0f4d2SKip Macy static void netfront_closing(struct xenbus_device *dev); 12089e0f4d2SKip Macy #endif 12189e0f4d2SKip Macy static void netif_free(struct netfront_info *info); 12289e0f4d2SKip Macy static int netfront_remove(struct xenbus_device *dev); 12389e0f4d2SKip Macy 12489e0f4d2SKip Macy static int talk_to_backend(struct xenbus_device *dev, struct netfront_info *info); 12589e0f4d2SKip Macy static int create_netdev(struct xenbus_device *dev, struct ifnet **ifp); 12689e0f4d2SKip Macy static void netif_disconnect_backend(struct netfront_info *info); 12789e0f4d2SKip Macy static int setup_device(struct xenbus_device *dev, struct netfront_info *info); 12889e0f4d2SKip Macy static void end_access(int ref, void *page); 12989e0f4d2SKip Macy 13089e0f4d2SKip Macy /* Xenolinux helper functions */ 13189e0f4d2SKip Macy static int network_connect(struct ifnet *ifp); 13289e0f4d2SKip Macy 13389e0f4d2SKip Macy static void xn_free_rx_ring(struct netfront_info *); 13489e0f4d2SKip Macy 13589e0f4d2SKip Macy static void xn_free_tx_ring(struct netfront_info *); 13689e0f4d2SKip Macy 13789e0f4d2SKip Macy static int xennet_get_responses(struct netfront_info *np, 13889e0f4d2SKip Macy struct netfront_rx_info *rinfo, RING_IDX rp, struct mbuf_head *list, 13989e0f4d2SKip Macy int *pages_flipped_p); 14089e0f4d2SKip Macy 14189e0f4d2SKip Macy #define virt_to_mfn(x) (vtomach(x) >> PAGE_SHIFT) 14289e0f4d2SKip Macy 14389e0f4d2SKip Macy #define INVALID_P2M_ENTRY (~0UL) 14489e0f4d2SKip Macy 14589e0f4d2SKip Macy /* 14689e0f4d2SKip Macy * Mbuf pointers. We need these to keep track of the virtual addresses 14789e0f4d2SKip Macy * of our mbuf chains since we can only convert from virtual to physical, 14889e0f4d2SKip Macy * not the other way around. The size must track the free index arrays. 14989e0f4d2SKip Macy */ 15089e0f4d2SKip Macy struct xn_chain_data { 15189e0f4d2SKip Macy struct mbuf *xn_tx_chain[NET_TX_RING_SIZE+1]; 15289e0f4d2SKip Macy struct mbuf *xn_rx_chain[NET_RX_RING_SIZE+1]; 15389e0f4d2SKip Macy }; 15489e0f4d2SKip Macy 15589e0f4d2SKip Macy 15689e0f4d2SKip Macy struct net_device_stats 15789e0f4d2SKip Macy { 15889e0f4d2SKip Macy u_long rx_packets; /* total packets received */ 15989e0f4d2SKip Macy u_long tx_packets; /* total packets transmitted */ 16089e0f4d2SKip Macy u_long rx_bytes; /* total bytes received */ 16189e0f4d2SKip Macy u_long tx_bytes; /* total bytes transmitted */ 16289e0f4d2SKip Macy u_long rx_errors; /* bad packets received */ 16389e0f4d2SKip Macy u_long tx_errors; /* packet transmit problems */ 16489e0f4d2SKip Macy u_long rx_dropped; /* no space in linux buffers */ 16589e0f4d2SKip Macy u_long tx_dropped; /* no space available in linux */ 16689e0f4d2SKip Macy u_long multicast; /* multicast packets received */ 16789e0f4d2SKip Macy u_long collisions; 16889e0f4d2SKip Macy 16989e0f4d2SKip Macy /* detailed rx_errors: */ 17089e0f4d2SKip Macy u_long rx_length_errors; 17189e0f4d2SKip Macy u_long rx_over_errors; /* receiver ring buff overflow */ 17289e0f4d2SKip Macy u_long rx_crc_errors; /* recved pkt with crc error */ 17389e0f4d2SKip Macy u_long rx_frame_errors; /* recv'd frame alignment error */ 17489e0f4d2SKip Macy u_long rx_fifo_errors; /* recv'r fifo overrun */ 17589e0f4d2SKip Macy u_long rx_missed_errors; /* receiver missed packet */ 17689e0f4d2SKip Macy 17789e0f4d2SKip Macy /* detailed tx_errors */ 17889e0f4d2SKip Macy u_long tx_aborted_errors; 17989e0f4d2SKip Macy u_long tx_carrier_errors; 18089e0f4d2SKip Macy u_long tx_fifo_errors; 18189e0f4d2SKip Macy u_long tx_heartbeat_errors; 18289e0f4d2SKip Macy u_long tx_window_errors; 18389e0f4d2SKip Macy 18489e0f4d2SKip Macy /* for cslip etc */ 18589e0f4d2SKip Macy u_long rx_compressed; 18689e0f4d2SKip Macy u_long tx_compressed; 18789e0f4d2SKip Macy }; 18889e0f4d2SKip Macy 18989e0f4d2SKip Macy struct netfront_info { 19089e0f4d2SKip Macy 19189e0f4d2SKip Macy struct ifnet *xn_ifp; 19289e0f4d2SKip Macy 19389e0f4d2SKip Macy struct net_device_stats stats; 19489e0f4d2SKip Macy u_int tx_full; 19589e0f4d2SKip Macy 19689e0f4d2SKip Macy netif_tx_front_ring_t tx; 19789e0f4d2SKip Macy netif_rx_front_ring_t rx; 19889e0f4d2SKip Macy 19989e0f4d2SKip Macy struct mtx tx_lock; 20089e0f4d2SKip Macy struct mtx rx_lock; 20189e0f4d2SKip Macy struct sx sc_lock; 20289e0f4d2SKip Macy 20389e0f4d2SKip Macy u_int handle; 20489e0f4d2SKip Macy u_int irq; 20589e0f4d2SKip Macy u_int copying_receiver; 20689e0f4d2SKip Macy u_int carrier; 20789e0f4d2SKip Macy 20889e0f4d2SKip Macy /* Receive-ring batched refills. */ 20989e0f4d2SKip Macy #define RX_MIN_TARGET 32 21089e0f4d2SKip Macy #define RX_MAX_TARGET NET_RX_RING_SIZE 21189e0f4d2SKip Macy int rx_min_target, rx_max_target, rx_target; 21289e0f4d2SKip Macy 21389e0f4d2SKip Macy /* 21489e0f4d2SKip Macy * {tx,rx}_skbs store outstanding skbuffs. The first entry in each 21589e0f4d2SKip Macy * array is an index into a chain of free entries. 21689e0f4d2SKip Macy */ 21789e0f4d2SKip Macy 21889e0f4d2SKip Macy grant_ref_t gref_tx_head; 21989e0f4d2SKip Macy grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1]; 22089e0f4d2SKip Macy grant_ref_t gref_rx_head; 22189e0f4d2SKip Macy grant_ref_t grant_rx_ref[NET_TX_RING_SIZE + 1]; 22289e0f4d2SKip Macy 22389e0f4d2SKip Macy #define TX_MAX_TARGET min(NET_RX_RING_SIZE, 256) 22489e0f4d2SKip Macy struct xenbus_device *xbdev; 22589e0f4d2SKip Macy int tx_ring_ref; 22689e0f4d2SKip Macy int rx_ring_ref; 22789e0f4d2SKip Macy uint8_t mac[ETHER_ADDR_LEN]; 22889e0f4d2SKip Macy struct xn_chain_data xn_cdata; /* mbufs */ 22989e0f4d2SKip Macy struct mbuf_head xn_rx_batch; /* head of the batch queue */ 23089e0f4d2SKip Macy 23189e0f4d2SKip Macy int xn_if_flags; 23289e0f4d2SKip Macy struct callout xn_stat_ch; 23389e0f4d2SKip Macy 23489e0f4d2SKip Macy u_long rx_pfn_array[NET_RX_RING_SIZE]; 23589e0f4d2SKip Macy multicall_entry_t rx_mcl[NET_RX_RING_SIZE+1]; 23689e0f4d2SKip Macy mmu_update_t rx_mmu[NET_RX_RING_SIZE]; 23789e0f4d2SKip Macy }; 23889e0f4d2SKip Macy 23989e0f4d2SKip Macy #define rx_mbufs xn_cdata.xn_rx_chain 24089e0f4d2SKip Macy #define tx_mbufs xn_cdata.xn_tx_chain 24189e0f4d2SKip Macy 24289e0f4d2SKip Macy #define XN_LOCK_INIT(_sc, _name) \ 24389e0f4d2SKip Macy mtx_init(&(_sc)->tx_lock, #_name"_tx", "network transmit lock", MTX_DEF); \ 24489e0f4d2SKip Macy mtx_init(&(_sc)->rx_lock, #_name"_rx", "network receive lock", MTX_DEF); \ 24589e0f4d2SKip Macy sx_init(&(_sc)->sc_lock, #_name"_rx") 24689e0f4d2SKip Macy 24789e0f4d2SKip Macy #define XN_RX_LOCK(_sc) mtx_lock(&(_sc)->rx_lock) 24889e0f4d2SKip Macy #define XN_RX_UNLOCK(_sc) mtx_unlock(&(_sc)->rx_lock) 24989e0f4d2SKip Macy 25089e0f4d2SKip Macy #define XN_TX_LOCK(_sc) mtx_lock(&(_sc)->tx_lock) 25189e0f4d2SKip Macy #define XN_TX_UNLOCK(_sc) mtx_unlock(&(_sc)->tx_lock) 25289e0f4d2SKip Macy 25389e0f4d2SKip Macy #define XN_LOCK(_sc) sx_xlock(&(_sc)->sc_lock); 25489e0f4d2SKip Macy #define XN_UNLOCK(_sc) sx_xunlock(&(_sc)->sc_lock); 25589e0f4d2SKip Macy 25689e0f4d2SKip Macy #define XN_LOCK_ASSERT(_sc) sx_assert(&(_sc)->sc_lock, SX_LOCKED); 25789e0f4d2SKip Macy #define XN_RX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rx_lock, MA_OWNED); 25889e0f4d2SKip Macy #define XN_TX_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->tx_lock, MA_OWNED); 25989e0f4d2SKip Macy #define XN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rx_lock); \ 26089e0f4d2SKip Macy mtx_destroy(&(_sc)->tx_lock); \ 26189e0f4d2SKip Macy sx_destroy(&(_sc)->sc_lock); 26289e0f4d2SKip Macy 26389e0f4d2SKip Macy struct netfront_rx_info { 26489e0f4d2SKip Macy struct netif_rx_response rx; 26589e0f4d2SKip Macy struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1]; 26689e0f4d2SKip Macy }; 26789e0f4d2SKip Macy 26889e0f4d2SKip Macy #define netfront_carrier_on(netif) ((netif)->carrier = 1) 26989e0f4d2SKip Macy #define netfront_carrier_off(netif) ((netif)->carrier = 0) 27089e0f4d2SKip Macy #define netfront_carrier_ok(netif) ((netif)->carrier) 27189e0f4d2SKip Macy 27289e0f4d2SKip Macy /* Access macros for acquiring freeing slots in xn_free_{tx,rx}_idxs[]. */ 27389e0f4d2SKip Macy 27489e0f4d2SKip Macy 27589e0f4d2SKip Macy 27689e0f4d2SKip Macy /* 27789e0f4d2SKip Macy * Access macros for acquiring freeing slots in tx_skbs[]. 27889e0f4d2SKip Macy */ 27989e0f4d2SKip Macy 28089e0f4d2SKip Macy static inline void 28189e0f4d2SKip Macy add_id_to_freelist(struct mbuf **list, unsigned short id) 28289e0f4d2SKip Macy { 28389e0f4d2SKip Macy list[id] = list[0]; 28489e0f4d2SKip Macy list[0] = (void *)(u_long)id; 28589e0f4d2SKip Macy } 28689e0f4d2SKip Macy 28789e0f4d2SKip Macy static inline unsigned short 28889e0f4d2SKip Macy get_id_from_freelist(struct mbuf **list) 28989e0f4d2SKip Macy { 29089e0f4d2SKip Macy u_int id = (u_int)(u_long)list[0]; 29189e0f4d2SKip Macy list[0] = list[id]; 29289e0f4d2SKip Macy return (id); 29389e0f4d2SKip Macy } 29489e0f4d2SKip Macy 29589e0f4d2SKip Macy static inline int 29689e0f4d2SKip Macy xennet_rxidx(RING_IDX idx) 29789e0f4d2SKip Macy { 29889e0f4d2SKip Macy return idx & (NET_RX_RING_SIZE - 1); 29989e0f4d2SKip Macy } 30089e0f4d2SKip Macy 30189e0f4d2SKip Macy static inline struct mbuf * 30289e0f4d2SKip Macy xennet_get_rx_mbuf(struct netfront_info *np, 30389e0f4d2SKip Macy RING_IDX ri) 30489e0f4d2SKip Macy { 30589e0f4d2SKip Macy int i = xennet_rxidx(ri); 30689e0f4d2SKip Macy struct mbuf *m; 30789e0f4d2SKip Macy 30889e0f4d2SKip Macy m = np->rx_mbufs[i]; 30989e0f4d2SKip Macy np->rx_mbufs[i] = NULL; 31089e0f4d2SKip Macy return (m); 31189e0f4d2SKip Macy } 31289e0f4d2SKip Macy 31389e0f4d2SKip Macy static inline grant_ref_t 31489e0f4d2SKip Macy xennet_get_rx_ref(struct netfront_info *np, RING_IDX ri) 31589e0f4d2SKip Macy { 31689e0f4d2SKip Macy int i = xennet_rxidx(ri); 31789e0f4d2SKip Macy grant_ref_t ref = np->grant_rx_ref[i]; 31889e0f4d2SKip Macy np->grant_rx_ref[i] = GRANT_INVALID_REF; 31989e0f4d2SKip Macy return ref; 32089e0f4d2SKip Macy } 32189e0f4d2SKip Macy 32289e0f4d2SKip Macy #ifdef DEBUG 32389e0f4d2SKip Macy 32489e0f4d2SKip Macy #endif 32589e0f4d2SKip Macy #define IPRINTK(fmt, args...) \ 32689e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 32789e0f4d2SKip Macy #define WPRINTK(fmt, args...) \ 32889e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 32989e0f4d2SKip Macy #define DPRINTK(fmt, args...) \ 33089e0f4d2SKip Macy printf("[XEN] " fmt, ##args) 33189e0f4d2SKip Macy 33289e0f4d2SKip Macy 33389e0f4d2SKip Macy static __inline struct mbuf* 33489e0f4d2SKip Macy makembuf (struct mbuf *buf) 33589e0f4d2SKip Macy { 33689e0f4d2SKip Macy struct mbuf *m = NULL; 33789e0f4d2SKip Macy 33889e0f4d2SKip Macy MGETHDR (m, M_DONTWAIT, MT_DATA); 33989e0f4d2SKip Macy 34089e0f4d2SKip Macy if (! m) 34189e0f4d2SKip Macy return 0; 34289e0f4d2SKip Macy 34389e0f4d2SKip Macy M_MOVE_PKTHDR(m, buf); 34489e0f4d2SKip Macy 34589e0f4d2SKip Macy m_cljget(m, M_DONTWAIT, MJUMPAGESIZE); 34689e0f4d2SKip Macy m->m_pkthdr.len = buf->m_pkthdr.len; 34789e0f4d2SKip Macy m->m_len = buf->m_len; 34889e0f4d2SKip Macy m_copydata(buf, 0, buf->m_pkthdr.len, mtod(m,caddr_t) ); 34989e0f4d2SKip Macy 35089e0f4d2SKip Macy m->m_ext.ext_arg1 = (caddr_t *)(uintptr_t)(vtophys(mtod(m,caddr_t)) >> PAGE_SHIFT); 35189e0f4d2SKip Macy 35289e0f4d2SKip Macy return m; 35389e0f4d2SKip Macy } 35489e0f4d2SKip Macy 35589e0f4d2SKip Macy /** 35689e0f4d2SKip Macy * Read the 'mac' node at the given device's node in the store, and parse that 35789e0f4d2SKip Macy * as colon-separated octets, placing result the given mac array. mac must be 35889e0f4d2SKip Macy * a preallocated array of length ETH_ALEN (as declared in linux/if_ether.h). 35989e0f4d2SKip Macy * Return 0 on success, or errno on error. 36089e0f4d2SKip Macy */ 36189e0f4d2SKip Macy static int 36289e0f4d2SKip Macy xen_net_read_mac(struct xenbus_device *dev, uint8_t mac[]) 36389e0f4d2SKip Macy { 36489e0f4d2SKip Macy char *s; 36589e0f4d2SKip Macy int i; 36689e0f4d2SKip Macy char *e; 36789e0f4d2SKip Macy char *macstr = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL); 36889e0f4d2SKip Macy if (IS_ERR(macstr)) { 36989e0f4d2SKip Macy return PTR_ERR(macstr); 37089e0f4d2SKip Macy } 37189e0f4d2SKip Macy s = macstr; 37289e0f4d2SKip Macy for (i = 0; i < ETHER_ADDR_LEN; i++) { 37389e0f4d2SKip Macy mac[i] = strtoul(s, &e, 16); 37489e0f4d2SKip Macy if (s == e || (e[0] != ':' && e[0] != 0)) { 37589e0f4d2SKip Macy free(macstr, M_DEVBUF); 37689e0f4d2SKip Macy return ENOENT; 37789e0f4d2SKip Macy } 37889e0f4d2SKip Macy s = &e[1]; 37989e0f4d2SKip Macy } 38089e0f4d2SKip Macy free(macstr, M_DEVBUF); 38189e0f4d2SKip Macy return 0; 38289e0f4d2SKip Macy } 38389e0f4d2SKip Macy 38489e0f4d2SKip Macy /** 38589e0f4d2SKip Macy * Entry point to this code when a new device is created. Allocate the basic 38689e0f4d2SKip Macy * structures and the ring buffers for communication with the backend, and 38789e0f4d2SKip Macy * inform the backend of the appropriate details for those. Switch to 38889e0f4d2SKip Macy * Connected state. 38989e0f4d2SKip Macy */ 39089e0f4d2SKip Macy static int 39189e0f4d2SKip Macy netfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) 39289e0f4d2SKip Macy { 39389e0f4d2SKip Macy int err; 39489e0f4d2SKip Macy struct ifnet *ifp; 39589e0f4d2SKip Macy struct netfront_info *info; 39689e0f4d2SKip Macy 39789e0f4d2SKip Macy printf("netfront_probe() \n"); 39889e0f4d2SKip Macy 39989e0f4d2SKip Macy err = create_netdev(dev, &ifp); 40089e0f4d2SKip Macy if (err) { 40189e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "creating netdev"); 40289e0f4d2SKip Macy return err; 40389e0f4d2SKip Macy } 40489e0f4d2SKip Macy 40589e0f4d2SKip Macy info = ifp->if_softc; 40689e0f4d2SKip Macy dev->dev_driver_data = info; 40789e0f4d2SKip Macy 40889e0f4d2SKip Macy 40989e0f4d2SKip Macy return 0; 41089e0f4d2SKip Macy } 41189e0f4d2SKip Macy 41289e0f4d2SKip Macy 41389e0f4d2SKip Macy /** 41489e0f4d2SKip Macy * We are reconnecting to the backend, due to a suspend/resume, or a backend 41589e0f4d2SKip Macy * driver restart. We tear down our netif structure and recreate it, but 41689e0f4d2SKip Macy * leave the device-layer structures intact so that this is transparent to the 41789e0f4d2SKip Macy * rest of the kernel. 41889e0f4d2SKip Macy */ 41989e0f4d2SKip Macy static int 42089e0f4d2SKip Macy netfront_resume(struct xenbus_device *dev) 42189e0f4d2SKip Macy { 42289e0f4d2SKip Macy struct netfront_info *info = dev->dev_driver_data; 42389e0f4d2SKip Macy 42489e0f4d2SKip Macy DPRINTK("%s\n", dev->nodename); 42589e0f4d2SKip Macy 42689e0f4d2SKip Macy netif_disconnect_backend(info); 42789e0f4d2SKip Macy return (0); 42889e0f4d2SKip Macy } 42989e0f4d2SKip Macy 43089e0f4d2SKip Macy 43189e0f4d2SKip Macy /* Common code used when first setting up, and when resuming. */ 43289e0f4d2SKip Macy static int 43389e0f4d2SKip Macy talk_to_backend(struct xenbus_device *dev, struct netfront_info *info) 43489e0f4d2SKip Macy { 43589e0f4d2SKip Macy const char *message; 43689e0f4d2SKip Macy struct xenbus_transaction xbt; 43789e0f4d2SKip Macy int err; 43889e0f4d2SKip Macy 43989e0f4d2SKip Macy err = xen_net_read_mac(dev, info->mac); 44089e0f4d2SKip Macy if (err) { 44189e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); 44289e0f4d2SKip Macy goto out; 44389e0f4d2SKip Macy } 44489e0f4d2SKip Macy 44589e0f4d2SKip Macy /* Create shared ring, alloc event channel. */ 44689e0f4d2SKip Macy err = setup_device(dev, info); 44789e0f4d2SKip Macy if (err) 44889e0f4d2SKip Macy goto out; 44989e0f4d2SKip Macy 45089e0f4d2SKip Macy again: 45189e0f4d2SKip Macy err = xenbus_transaction_start(&xbt); 45289e0f4d2SKip Macy if (err) { 45389e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "starting transaction"); 45489e0f4d2SKip Macy goto destroy_ring; 45589e0f4d2SKip Macy } 45689e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u", 45789e0f4d2SKip Macy info->tx_ring_ref); 45889e0f4d2SKip Macy if (err) { 45989e0f4d2SKip Macy message = "writing tx ring-ref"; 46089e0f4d2SKip Macy goto abort_transaction; 46189e0f4d2SKip Macy } 46289e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u", 46389e0f4d2SKip Macy info->rx_ring_ref); 46489e0f4d2SKip Macy if (err) { 46589e0f4d2SKip Macy message = "writing rx ring-ref"; 46689e0f4d2SKip Macy goto abort_transaction; 46789e0f4d2SKip Macy } 46889e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, 46989e0f4d2SKip Macy "event-channel", "%u", irq_to_evtchn_port(info->irq)); 47089e0f4d2SKip Macy if (err) { 47189e0f4d2SKip Macy message = "writing event-channel"; 47289e0f4d2SKip Macy goto abort_transaction; 47389e0f4d2SKip Macy } 47489e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u", 47589e0f4d2SKip Macy info->copying_receiver); 47689e0f4d2SKip Macy if (err) { 47789e0f4d2SKip Macy message = "writing request-rx-copy"; 47889e0f4d2SKip Macy goto abort_transaction; 47989e0f4d2SKip Macy } 48089e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1); 48189e0f4d2SKip Macy if (err) { 48289e0f4d2SKip Macy message = "writing feature-rx-notify"; 48389e0f4d2SKip Macy goto abort_transaction; 48489e0f4d2SKip Macy } 48589e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, "feature-no-csum-offload", "%d", 1); 48689e0f4d2SKip Macy if (err) { 48789e0f4d2SKip Macy message = "writing feature-no-csum-offload"; 48889e0f4d2SKip Macy goto abort_transaction; 48989e0f4d2SKip Macy } 49089e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1); 49189e0f4d2SKip Macy if (err) { 49289e0f4d2SKip Macy message = "writing feature-sg"; 49389e0f4d2SKip Macy goto abort_transaction; 49489e0f4d2SKip Macy } 49589e0f4d2SKip Macy #ifdef HAVE_TSO 49689e0f4d2SKip Macy err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1); 49789e0f4d2SKip Macy if (err) { 49889e0f4d2SKip Macy message = "writing feature-gso-tcpv4"; 49989e0f4d2SKip Macy goto abort_transaction; 50089e0f4d2SKip Macy } 50189e0f4d2SKip Macy #endif 50289e0f4d2SKip Macy 50389e0f4d2SKip Macy err = xenbus_transaction_end(xbt, 0); 50489e0f4d2SKip Macy if (err) { 50589e0f4d2SKip Macy if (err == EAGAIN) 50689e0f4d2SKip Macy goto again; 50789e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "completing transaction"); 50889e0f4d2SKip Macy goto destroy_ring; 50989e0f4d2SKip Macy } 51089e0f4d2SKip Macy 51189e0f4d2SKip Macy return 0; 51289e0f4d2SKip Macy 51389e0f4d2SKip Macy abort_transaction: 51489e0f4d2SKip Macy xenbus_transaction_end(xbt, 1); 51589e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "%s", message); 51689e0f4d2SKip Macy destroy_ring: 51789e0f4d2SKip Macy netif_free(info); 51889e0f4d2SKip Macy out: 51989e0f4d2SKip Macy return err; 52089e0f4d2SKip Macy } 52189e0f4d2SKip Macy 52289e0f4d2SKip Macy 52389e0f4d2SKip Macy static int 52489e0f4d2SKip Macy setup_device(struct xenbus_device *dev, struct netfront_info *info) 52589e0f4d2SKip Macy { 52689e0f4d2SKip Macy netif_tx_sring_t *txs; 52789e0f4d2SKip Macy netif_rx_sring_t *rxs; 52889e0f4d2SKip Macy int err; 52989e0f4d2SKip Macy struct ifnet *ifp; 53089e0f4d2SKip Macy 53189e0f4d2SKip Macy ifp = info->xn_ifp; 53289e0f4d2SKip Macy 53389e0f4d2SKip Macy info->tx_ring_ref = GRANT_INVALID_REF; 53489e0f4d2SKip Macy info->rx_ring_ref = GRANT_INVALID_REF; 53589e0f4d2SKip Macy info->rx.sring = NULL; 53689e0f4d2SKip Macy info->tx.sring = NULL; 53789e0f4d2SKip Macy info->irq = 0; 53889e0f4d2SKip Macy 53989e0f4d2SKip Macy txs = (netif_tx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 54089e0f4d2SKip Macy if (!txs) { 54189e0f4d2SKip Macy err = ENOMEM; 54289e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "allocating tx ring page"); 54389e0f4d2SKip Macy goto fail; 54489e0f4d2SKip Macy } 54589e0f4d2SKip Macy SHARED_RING_INIT(txs); 54689e0f4d2SKip Macy FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE); 54789e0f4d2SKip Macy err = xenbus_grant_ring(dev, virt_to_mfn(txs)); 54889e0f4d2SKip Macy if (err < 0) 54989e0f4d2SKip Macy goto fail; 55089e0f4d2SKip Macy info->tx_ring_ref = err; 55189e0f4d2SKip Macy 55289e0f4d2SKip Macy rxs = (netif_rx_sring_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT|M_ZERO); 55389e0f4d2SKip Macy if (!rxs) { 55489e0f4d2SKip Macy err = ENOMEM; 55589e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "allocating rx ring page"); 55689e0f4d2SKip Macy goto fail; 55789e0f4d2SKip Macy } 55889e0f4d2SKip Macy SHARED_RING_INIT(rxs); 55989e0f4d2SKip Macy FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE); 56089e0f4d2SKip Macy 56189e0f4d2SKip Macy err = xenbus_grant_ring(dev, virt_to_mfn(rxs)); 56289e0f4d2SKip Macy if (err < 0) 56389e0f4d2SKip Macy goto fail; 56489e0f4d2SKip Macy info->rx_ring_ref = err; 56589e0f4d2SKip Macy 56689e0f4d2SKip Macy #if 0 56789e0f4d2SKip Macy network_connect(ifp); 56889e0f4d2SKip Macy #endif 56989e0f4d2SKip Macy err = bind_listening_port_to_irqhandler(dev->otherend_id, 57089e0f4d2SKip Macy "xn", xn_intr, info, INTR_TYPE_NET | INTR_MPSAFE, NULL); 57189e0f4d2SKip Macy 57289e0f4d2SKip Macy if (err <= 0) { 57389e0f4d2SKip Macy xenbus_dev_fatal(dev, err, 57489e0f4d2SKip Macy "bind_evtchn_to_irqhandler failed"); 57589e0f4d2SKip Macy goto fail; 57689e0f4d2SKip Macy } 57789e0f4d2SKip Macy info->irq = err; 57889e0f4d2SKip Macy 57989e0f4d2SKip Macy show_device(info); 58089e0f4d2SKip Macy 58189e0f4d2SKip Macy return 0; 58289e0f4d2SKip Macy 58389e0f4d2SKip Macy fail: 58489e0f4d2SKip Macy netif_free(info); 58589e0f4d2SKip Macy return err; 58689e0f4d2SKip Macy } 58789e0f4d2SKip Macy 58889e0f4d2SKip Macy /** 58989e0f4d2SKip Macy * Callback received when the backend's state changes. 59089e0f4d2SKip Macy */ 59189e0f4d2SKip Macy static void 59289e0f4d2SKip Macy backend_changed(struct xenbus_device *dev, 59389e0f4d2SKip Macy XenbusState backend_state) 59489e0f4d2SKip Macy { 59589e0f4d2SKip Macy struct netfront_info *sc = dev->dev_driver_data; 59689e0f4d2SKip Macy 59789e0f4d2SKip Macy DPRINTK("\n"); 59889e0f4d2SKip Macy 59989e0f4d2SKip Macy switch (backend_state) { 60089e0f4d2SKip Macy case XenbusStateInitialising: 60189e0f4d2SKip Macy case XenbusStateInitialised: 60289e0f4d2SKip Macy case XenbusStateConnected: 60389e0f4d2SKip Macy case XenbusStateUnknown: 60489e0f4d2SKip Macy case XenbusStateClosed: 60589e0f4d2SKip Macy break; 60689e0f4d2SKip Macy case XenbusStateInitWait: 60789e0f4d2SKip Macy if (dev->state != XenbusStateInitialising) 60889e0f4d2SKip Macy break; 60989e0f4d2SKip Macy if (network_connect(sc->xn_ifp) != 0) 61089e0f4d2SKip Macy break; 61189e0f4d2SKip Macy xenbus_switch_state(dev, XenbusStateConnected); 61289e0f4d2SKip Macy #ifdef notyet 61389e0f4d2SKip Macy (void)send_fake_arp(netdev); 61489e0f4d2SKip Macy #endif 61589e0f4d2SKip Macy break; break; 61689e0f4d2SKip Macy case XenbusStateClosing: 61789e0f4d2SKip Macy xenbus_frontend_closed(dev); 61889e0f4d2SKip Macy break; 61989e0f4d2SKip Macy } 62089e0f4d2SKip Macy } 62189e0f4d2SKip Macy 62289e0f4d2SKip Macy static void 62389e0f4d2SKip Macy xn_free_rx_ring(struct netfront_info *sc) 62489e0f4d2SKip Macy { 62589e0f4d2SKip Macy #if 0 62689e0f4d2SKip Macy int i; 62789e0f4d2SKip Macy 62889e0f4d2SKip Macy for (i = 0; i < NET_RX_RING_SIZE; i++) { 62989e0f4d2SKip Macy if (sc->xn_cdata.xn_rx_chain[i] != NULL) { 63089e0f4d2SKip Macy m_freem(sc->xn_cdata.xn_rx_chain[i]); 63189e0f4d2SKip Macy sc->xn_cdata.xn_rx_chain[i] = NULL; 63289e0f4d2SKip Macy } 63389e0f4d2SKip Macy } 63489e0f4d2SKip Macy 63589e0f4d2SKip Macy sc->rx.rsp_cons = 0; 63689e0f4d2SKip Macy sc->xn_rx_if->req_prod = 0; 63789e0f4d2SKip Macy sc->xn_rx_if->event = sc->rx.rsp_cons ; 63889e0f4d2SKip Macy #endif 63989e0f4d2SKip Macy } 64089e0f4d2SKip Macy 64189e0f4d2SKip Macy static void 64289e0f4d2SKip Macy xn_free_tx_ring(struct netfront_info *sc) 64389e0f4d2SKip Macy { 64489e0f4d2SKip Macy #if 0 64589e0f4d2SKip Macy int i; 64689e0f4d2SKip Macy 64789e0f4d2SKip Macy for (i = 0; i < NET_TX_RING_SIZE; i++) { 64889e0f4d2SKip Macy if (sc->xn_cdata.xn_tx_chain[i] != NULL) { 64989e0f4d2SKip Macy m_freem(sc->xn_cdata.xn_tx_chain[i]); 65089e0f4d2SKip Macy sc->xn_cdata.xn_tx_chain[i] = NULL; 65189e0f4d2SKip Macy } 65289e0f4d2SKip Macy } 65389e0f4d2SKip Macy 65489e0f4d2SKip Macy return; 65589e0f4d2SKip Macy #endif 65689e0f4d2SKip Macy } 65789e0f4d2SKip Macy 65889e0f4d2SKip Macy static inline int 65989e0f4d2SKip Macy netfront_tx_slot_available(struct netfront_info *np) 66089e0f4d2SKip Macy { 66189e0f4d2SKip Macy return ((np->tx.req_prod_pvt - np->tx.rsp_cons) < 66289e0f4d2SKip Macy (TX_MAX_TARGET - /* MAX_SKB_FRAGS */ 24 - 2)); 66389e0f4d2SKip Macy } 66489e0f4d2SKip Macy static void 66589e0f4d2SKip Macy netif_release_tx_bufs(struct netfront_info *np) 66689e0f4d2SKip Macy { 66789e0f4d2SKip Macy struct mbuf *m; 66889e0f4d2SKip Macy int i; 66989e0f4d2SKip Macy 67089e0f4d2SKip Macy for (i = 1; i <= NET_TX_RING_SIZE; i++) { 67189e0f4d2SKip Macy m = np->xn_cdata.xn_tx_chain[i]; 67289e0f4d2SKip Macy 67389e0f4d2SKip Macy if (((u_long)m) < KERNBASE) 67489e0f4d2SKip Macy continue; 67589e0f4d2SKip Macy gnttab_grant_foreign_access_ref(np->grant_tx_ref[i], 67689e0f4d2SKip Macy np->xbdev->otherend_id, virt_to_mfn(mtod(m, vm_offset_t)), 67789e0f4d2SKip Macy GNTMAP_readonly); 67889e0f4d2SKip Macy gnttab_release_grant_reference(&np->gref_tx_head, 67989e0f4d2SKip Macy np->grant_tx_ref[i]); 68089e0f4d2SKip Macy np->grant_tx_ref[i] = GRANT_INVALID_REF; 68189e0f4d2SKip Macy add_id_to_freelist(np->tx_mbufs, i); 68289e0f4d2SKip Macy m_freem(m); 68389e0f4d2SKip Macy } 68489e0f4d2SKip Macy } 68589e0f4d2SKip Macy 68689e0f4d2SKip Macy static void 68789e0f4d2SKip Macy network_alloc_rx_buffers(struct netfront_info *sc) 68889e0f4d2SKip Macy { 68989e0f4d2SKip Macy unsigned short id; 69089e0f4d2SKip Macy struct mbuf *m_new; 69189e0f4d2SKip Macy int i, batch_target, notify; 69289e0f4d2SKip Macy RING_IDX req_prod; 69389e0f4d2SKip Macy struct xen_memory_reservation reservation; 69489e0f4d2SKip Macy grant_ref_t ref; 69589e0f4d2SKip Macy int nr_flips; 69689e0f4d2SKip Macy netif_rx_request_t *req; 69789e0f4d2SKip Macy vm_offset_t vaddr; 69889e0f4d2SKip Macy u_long pfn; 69989e0f4d2SKip Macy 70089e0f4d2SKip Macy req_prod = sc->rx.req_prod_pvt; 70189e0f4d2SKip Macy 70289e0f4d2SKip Macy if (unlikely(sc->carrier == 0)) 70389e0f4d2SKip Macy return; 70489e0f4d2SKip Macy 70589e0f4d2SKip Macy /* 70689e0f4d2SKip Macy * Allocate skbuffs greedily, even though we batch updates to the 70789e0f4d2SKip Macy * receive ring. This creates a less bursty demand on the memory 70889e0f4d2SKip Macy * allocator, so should reduce the chance of failed allocation 70989e0f4d2SKip Macy * requests both for ourself and for other kernel subsystems. 71089e0f4d2SKip Macy */ 71189e0f4d2SKip Macy batch_target = sc->rx_target - (req_prod - sc->rx.rsp_cons); 71289e0f4d2SKip Macy for (i = mbufq_len(&sc->xn_rx_batch); i < batch_target; i++) { 71389e0f4d2SKip Macy MGETHDR(m_new, M_DONTWAIT, MT_DATA); 71489e0f4d2SKip Macy if (m_new == NULL) 71589e0f4d2SKip Macy goto no_mbuf; 71689e0f4d2SKip Macy 71789e0f4d2SKip Macy m_cljget(m_new, M_DONTWAIT, MJUMPAGESIZE); 71889e0f4d2SKip Macy if ((m_new->m_flags & M_EXT) == 0) { 71989e0f4d2SKip Macy m_freem(m_new); 72089e0f4d2SKip Macy 72189e0f4d2SKip Macy no_mbuf: 72289e0f4d2SKip Macy if (i != 0) 72389e0f4d2SKip Macy goto refill; 72489e0f4d2SKip Macy /* 72589e0f4d2SKip Macy * XXX set timer 72689e0f4d2SKip Macy */ 72789e0f4d2SKip Macy break; 72889e0f4d2SKip Macy } 72989e0f4d2SKip Macy m_new->m_len = m_new->m_pkthdr.len = MJUMPAGESIZE; 73089e0f4d2SKip Macy 73189e0f4d2SKip Macy /* queue the mbufs allocated */ 73289e0f4d2SKip Macy mbufq_tail(&sc->xn_rx_batch, m_new); 73389e0f4d2SKip Macy } 73489e0f4d2SKip Macy 73589e0f4d2SKip Macy /* Is the batch large enough to be worthwhile? */ 73689e0f4d2SKip Macy if (i < (sc->rx_target/2)) { 73789e0f4d2SKip Macy if (req_prod >sc->rx.sring->req_prod) 73889e0f4d2SKip Macy goto push; 73989e0f4d2SKip Macy return; 74089e0f4d2SKip Macy } 74189e0f4d2SKip Macy /* Adjust floating fill target if we risked running out of buffers. */ 74289e0f4d2SKip Macy if ( ((req_prod - sc->rx.sring->rsp_prod) < (sc->rx_target / 4)) && 74389e0f4d2SKip Macy ((sc->rx_target *= 2) > sc->rx_max_target) ) 74489e0f4d2SKip Macy sc->rx_target = sc->rx_max_target; 74589e0f4d2SKip Macy 74689e0f4d2SKip Macy refill: 74789e0f4d2SKip Macy for (nr_flips = i = 0; ; i++) { 74889e0f4d2SKip Macy if ((m_new = mbufq_dequeue(&sc->xn_rx_batch)) == NULL) 74989e0f4d2SKip Macy break; 75089e0f4d2SKip Macy 75189e0f4d2SKip Macy m_new->m_ext.ext_arg1 = (vm_paddr_t *)(uintptr_t)( 75289e0f4d2SKip Macy vtophys(m_new->m_ext.ext_buf) >> PAGE_SHIFT); 75389e0f4d2SKip Macy 75489e0f4d2SKip Macy id = xennet_rxidx(req_prod + i); 75589e0f4d2SKip Macy 75689e0f4d2SKip Macy KASSERT(sc->xn_cdata.xn_rx_chain[id] == NULL, 75789e0f4d2SKip Macy ("non-NULL xm_rx_chain")); 75889e0f4d2SKip Macy sc->xn_cdata.xn_rx_chain[id] = m_new; 75989e0f4d2SKip Macy 76089e0f4d2SKip Macy ref = gnttab_claim_grant_reference(&sc->gref_rx_head); 76189e0f4d2SKip Macy KASSERT((short)ref >= 0, ("negative ref")); 76289e0f4d2SKip Macy sc->grant_rx_ref[id] = ref; 76389e0f4d2SKip Macy 76489e0f4d2SKip Macy vaddr = mtod(m_new, vm_offset_t); 76589e0f4d2SKip Macy pfn = vtophys(vaddr) >> PAGE_SHIFT; 76689e0f4d2SKip Macy req = RING_GET_REQUEST(&sc->rx, req_prod + i); 76789e0f4d2SKip Macy 76889e0f4d2SKip Macy if (sc->copying_receiver == 0) { 76989e0f4d2SKip Macy gnttab_grant_foreign_transfer_ref(ref, 77089e0f4d2SKip Macy sc->xbdev->otherend_id, pfn); 77189e0f4d2SKip Macy sc->rx_pfn_array[nr_flips] = PFNTOMFN(pfn); 77289e0f4d2SKip Macy if (!xen_feature(XENFEAT_auto_translated_physmap)) { 77389e0f4d2SKip Macy /* Remove this page before passing 77489e0f4d2SKip Macy * back to Xen. 77589e0f4d2SKip Macy */ 77689e0f4d2SKip Macy set_phys_to_machine(pfn, INVALID_P2M_ENTRY); 77789e0f4d2SKip Macy MULTI_update_va_mapping(&sc->rx_mcl[i], 77889e0f4d2SKip Macy vaddr, 0, 0); 77989e0f4d2SKip Macy } 78089e0f4d2SKip Macy nr_flips++; 78189e0f4d2SKip Macy } else { 78289e0f4d2SKip Macy gnttab_grant_foreign_access_ref(ref, 78389e0f4d2SKip Macy sc->xbdev->otherend_id, 78489e0f4d2SKip Macy PFNTOMFN(pfn), 0); 78589e0f4d2SKip Macy } 78689e0f4d2SKip Macy req->id = id; 78789e0f4d2SKip Macy req->gref = ref; 78889e0f4d2SKip Macy 78989e0f4d2SKip Macy sc->rx_pfn_array[i] = 79089e0f4d2SKip Macy vtomach(mtod(m_new,vm_offset_t)) >> PAGE_SHIFT; 79189e0f4d2SKip Macy } 79289e0f4d2SKip Macy 79389e0f4d2SKip Macy KASSERT(i, ("no mbufs processed")); /* should have returned earlier */ 79489e0f4d2SKip Macy KASSERT(mbufq_len(&sc->xn_rx_batch) == 0, ("not all mbufs processed")); 79589e0f4d2SKip Macy /* 79689e0f4d2SKip Macy * We may have allocated buffers which have entries outstanding 79789e0f4d2SKip Macy * in the page * update queue -- make sure we flush those first! 79889e0f4d2SKip Macy */ 79989e0f4d2SKip Macy PT_UPDATES_FLUSH(); 80089e0f4d2SKip Macy if (nr_flips != 0) { 80189e0f4d2SKip Macy #ifdef notyet 80289e0f4d2SKip Macy /* Tell the ballon driver what is going on. */ 80389e0f4d2SKip Macy balloon_update_driver_allowance(i); 80489e0f4d2SKip Macy #endif 80589e0f4d2SKip Macy set_xen_guest_handle(reservation.extent_start,sc->rx_pfn_array); 80689e0f4d2SKip Macy reservation.nr_extents = i; 80789e0f4d2SKip Macy reservation.extent_order = 0; 80889e0f4d2SKip Macy reservation.address_bits = 0; 80989e0f4d2SKip Macy reservation.domid = DOMID_SELF; 81089e0f4d2SKip Macy 81189e0f4d2SKip Macy if (!xen_feature(XENFEAT_auto_translated_physmap)) { 81289e0f4d2SKip Macy 81389e0f4d2SKip Macy /* After all PTEs have been zapped, flush the TLB. */ 81489e0f4d2SKip Macy sc->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] = 81589e0f4d2SKip Macy UVMF_TLB_FLUSH|UVMF_ALL; 81689e0f4d2SKip Macy 81789e0f4d2SKip Macy /* Give away a batch of pages. */ 81889e0f4d2SKip Macy sc->rx_mcl[i].op = __HYPERVISOR_memory_op; 81989e0f4d2SKip Macy sc->rx_mcl[i].args[0] = XENMEM_decrease_reservation; 82089e0f4d2SKip Macy sc->rx_mcl[i].args[1] = (u_long)&reservation; 82189e0f4d2SKip Macy /* Zap PTEs and give away pages in one big multicall. */ 82289e0f4d2SKip Macy (void)HYPERVISOR_multicall(sc->rx_mcl, i+1); 82389e0f4d2SKip Macy 82489e0f4d2SKip Macy /* Check return status of HYPERVISOR_dom_mem_op(). */ 82589e0f4d2SKip Macy if (unlikely(sc->rx_mcl[i].result != i)) 82689e0f4d2SKip Macy panic("Unable to reduce memory reservation\n"); 82789e0f4d2SKip Macy } else { 82889e0f4d2SKip Macy if (HYPERVISOR_memory_op( 82989e0f4d2SKip Macy XENMEM_decrease_reservation, &reservation) 83089e0f4d2SKip Macy != i) 83189e0f4d2SKip Macy panic("Unable to reduce memory " 83289e0f4d2SKip Macy "reservation\n"); 83389e0f4d2SKip Macy } 83489e0f4d2SKip Macy } else { 83589e0f4d2SKip Macy wmb(); 83689e0f4d2SKip Macy } 83789e0f4d2SKip Macy 83889e0f4d2SKip Macy /* Above is a suitable barrier to ensure backend will see requests. */ 83989e0f4d2SKip Macy sc->rx.req_prod_pvt = req_prod + i; 84089e0f4d2SKip Macy push: 84189e0f4d2SKip Macy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->rx, notify); 84289e0f4d2SKip Macy if (notify) 84389e0f4d2SKip Macy notify_remote_via_irq(sc->irq); 84489e0f4d2SKip Macy } 84589e0f4d2SKip Macy 84689e0f4d2SKip Macy static void 84789e0f4d2SKip Macy xn_rxeof(struct netfront_info *np) 84889e0f4d2SKip Macy { 84989e0f4d2SKip Macy struct ifnet *ifp; 85089e0f4d2SKip Macy struct netfront_rx_info rinfo; 85189e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo.rx; 85289e0f4d2SKip Macy struct netif_extra_info *extras = rinfo.extras; 85389e0f4d2SKip Macy RING_IDX i, rp; 85489e0f4d2SKip Macy multicall_entry_t *mcl; 85589e0f4d2SKip Macy struct mbuf *m; 85689e0f4d2SKip Macy struct mbuf_head rxq, errq, tmpq; 85789e0f4d2SKip Macy int err, pages_flipped = 0; 85889e0f4d2SKip Macy 85989e0f4d2SKip Macy XN_RX_LOCK_ASSERT(np); 86089e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 86189e0f4d2SKip Macy return; 86289e0f4d2SKip Macy 86389e0f4d2SKip Macy mbufq_init(&tmpq); 86489e0f4d2SKip Macy mbufq_init(&errq); 86589e0f4d2SKip Macy mbufq_init(&rxq); 86689e0f4d2SKip Macy 86789e0f4d2SKip Macy ifp = np->xn_ifp; 86889e0f4d2SKip Macy 86989e0f4d2SKip Macy rp = np->rx.sring->rsp_prod; 87089e0f4d2SKip Macy rmb(); /* Ensure we see queued responses up to 'rp'. */ 87189e0f4d2SKip Macy 87289e0f4d2SKip Macy i = np->rx.rsp_cons; 87389e0f4d2SKip Macy while ((i != rp)) { 87489e0f4d2SKip Macy memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx)); 87589e0f4d2SKip Macy memset(extras, 0, sizeof(rinfo.extras)); 87689e0f4d2SKip Macy 87789e0f4d2SKip Macy err = xennet_get_responses(np, &rinfo, rp, &tmpq, 87889e0f4d2SKip Macy &pages_flipped); 87989e0f4d2SKip Macy 88089e0f4d2SKip Macy if (unlikely(err)) { 88189e0f4d2SKip Macy while ((m = mbufq_dequeue(&tmpq))) 88289e0f4d2SKip Macy mbufq_tail(&errq, m); 88389e0f4d2SKip Macy np->stats.rx_errors++; 88489e0f4d2SKip Macy i = np->rx.rsp_cons; 88589e0f4d2SKip Macy continue; 88689e0f4d2SKip Macy } 88789e0f4d2SKip Macy 88889e0f4d2SKip Macy m = mbufq_dequeue(&tmpq); 88989e0f4d2SKip Macy 89089e0f4d2SKip Macy m->m_data += rx->offset;/* (rx->addr & PAGE_MASK); */ 89189e0f4d2SKip Macy m->m_pkthdr.len = m->m_len = rx->status; 89289e0f4d2SKip Macy m->m_pkthdr.rcvif = ifp; 89389e0f4d2SKip Macy 89489e0f4d2SKip Macy if ( rx->flags & NETRXF_data_validated ) { 89589e0f4d2SKip Macy /* Tell the stack the checksums are okay */ 89689e0f4d2SKip Macy /* 89789e0f4d2SKip Macy * XXX this isn't necessarily the case - need to add 89889e0f4d2SKip Macy * check 89989e0f4d2SKip Macy */ 90089e0f4d2SKip Macy 90189e0f4d2SKip Macy m->m_pkthdr.csum_flags |= 90289e0f4d2SKip Macy (CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID 90389e0f4d2SKip Macy | CSUM_PSEUDO_HDR); 90489e0f4d2SKip Macy m->m_pkthdr.csum_data = 0xffff; 90589e0f4d2SKip Macy } 90689e0f4d2SKip Macy 90789e0f4d2SKip Macy np->stats.rx_packets++; 90889e0f4d2SKip Macy np->stats.rx_bytes += rx->status; 90989e0f4d2SKip Macy 91089e0f4d2SKip Macy mbufq_tail(&rxq, m); 91189e0f4d2SKip Macy np->rx.rsp_cons = ++i; 91289e0f4d2SKip Macy } 91389e0f4d2SKip Macy 91489e0f4d2SKip Macy if (pages_flipped) { 91589e0f4d2SKip Macy /* Some pages are no longer absent... */ 91689e0f4d2SKip Macy #ifdef notyet 91789e0f4d2SKip Macy balloon_update_driver_allowance(-pages_flipped); 91889e0f4d2SKip Macy #endif 91989e0f4d2SKip Macy /* Do all the remapping work, and M->P updates, in one big 92089e0f4d2SKip Macy * hypercall. 92189e0f4d2SKip Macy */ 92289e0f4d2SKip Macy if (!!xen_feature(XENFEAT_auto_translated_physmap)) { 92389e0f4d2SKip Macy mcl = np->rx_mcl + pages_flipped; 92489e0f4d2SKip Macy mcl->op = __HYPERVISOR_mmu_update; 92589e0f4d2SKip Macy mcl->args[0] = (u_long)np->rx_mmu; 92689e0f4d2SKip Macy mcl->args[1] = pages_flipped; 92789e0f4d2SKip Macy mcl->args[2] = 0; 92889e0f4d2SKip Macy mcl->args[3] = DOMID_SELF; 92989e0f4d2SKip Macy (void)HYPERVISOR_multicall(np->rx_mcl, 93089e0f4d2SKip Macy pages_flipped + 1); 93189e0f4d2SKip Macy } 93289e0f4d2SKip Macy } 93389e0f4d2SKip Macy 93489e0f4d2SKip Macy while ((m = mbufq_dequeue(&errq))) 93589e0f4d2SKip Macy m_freem(m); 93689e0f4d2SKip Macy 93789e0f4d2SKip Macy /* 93889e0f4d2SKip Macy * Process all the mbufs after the remapping is complete. 93989e0f4d2SKip Macy * Break the mbuf chain first though. 94089e0f4d2SKip Macy */ 94189e0f4d2SKip Macy while ((m = mbufq_dequeue(&rxq)) != NULL) { 94289e0f4d2SKip Macy ifp->if_ipackets++; 94389e0f4d2SKip Macy 94489e0f4d2SKip Macy /* 94589e0f4d2SKip Macy * Do we really need to drop the rx lock? 94689e0f4d2SKip Macy */ 94789e0f4d2SKip Macy XN_RX_UNLOCK(np); 94889e0f4d2SKip Macy /* Pass it up. */ 94989e0f4d2SKip Macy (*ifp->if_input)(ifp, m); 95089e0f4d2SKip Macy XN_RX_LOCK(np); 95189e0f4d2SKip Macy } 95289e0f4d2SKip Macy 95389e0f4d2SKip Macy np->rx.rsp_cons = i; 95489e0f4d2SKip Macy 95589e0f4d2SKip Macy #if 0 95689e0f4d2SKip Macy /* If we get a callback with very few responses, reduce fill target. */ 95789e0f4d2SKip Macy /* NB. Note exponential increase, linear decrease. */ 95889e0f4d2SKip Macy if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) > 95989e0f4d2SKip Macy ((3*np->rx_target) / 4)) && (--np->rx_target < np->rx_min_target)) 96089e0f4d2SKip Macy np->rx_target = np->rx_min_target; 96189e0f4d2SKip Macy #endif 96289e0f4d2SKip Macy 96389e0f4d2SKip Macy network_alloc_rx_buffers(np); 96489e0f4d2SKip Macy 96589e0f4d2SKip Macy np->rx.sring->rsp_event = i + 1; 96689e0f4d2SKip Macy } 96789e0f4d2SKip Macy 96889e0f4d2SKip Macy static void 96989e0f4d2SKip Macy xn_txeof(struct netfront_info *np) 97089e0f4d2SKip Macy { 97189e0f4d2SKip Macy RING_IDX i, prod; 97289e0f4d2SKip Macy unsigned short id; 97389e0f4d2SKip Macy struct ifnet *ifp; 97489e0f4d2SKip Macy struct mbuf *m; 97589e0f4d2SKip Macy 97689e0f4d2SKip Macy XN_TX_LOCK_ASSERT(np); 97789e0f4d2SKip Macy 97889e0f4d2SKip Macy if (!netfront_carrier_ok(np)) 97989e0f4d2SKip Macy return; 98089e0f4d2SKip Macy 98189e0f4d2SKip Macy ifp = np->xn_ifp; 98289e0f4d2SKip Macy ifp->if_timer = 0; 98389e0f4d2SKip Macy 98489e0f4d2SKip Macy do { 98589e0f4d2SKip Macy prod = np->tx.sring->rsp_prod; 98689e0f4d2SKip Macy rmb(); /* Ensure we see responses up to 'rp'. */ 98789e0f4d2SKip Macy 98889e0f4d2SKip Macy for (i = np->tx.rsp_cons; i != prod; i++) { 98989e0f4d2SKip Macy id = RING_GET_RESPONSE(&np->tx, i)->id; 99089e0f4d2SKip Macy m = np->xn_cdata.xn_tx_chain[id]; 99189e0f4d2SKip Macy 99289e0f4d2SKip Macy ifp->if_opackets++; 99389e0f4d2SKip Macy KASSERT(m != NULL, ("mbuf not found in xn_tx_chain")); 99489e0f4d2SKip Macy M_ASSERTVALID(m); 99589e0f4d2SKip Macy if (unlikely(gnttab_query_foreign_access( 99689e0f4d2SKip Macy np->grant_tx_ref[id]) != 0)) { 99789e0f4d2SKip Macy printf("network_tx_buf_gc: warning " 99889e0f4d2SKip Macy "-- grant still in use by backend " 99989e0f4d2SKip Macy "domain.\n"); 100089e0f4d2SKip Macy goto out; 100189e0f4d2SKip Macy } 100289e0f4d2SKip Macy gnttab_end_foreign_access_ref( 100389e0f4d2SKip Macy np->grant_tx_ref[id], GNTMAP_readonly); 100489e0f4d2SKip Macy gnttab_release_grant_reference( 100589e0f4d2SKip Macy &np->gref_tx_head, np->grant_tx_ref[id]); 100689e0f4d2SKip Macy np->grant_tx_ref[id] = GRANT_INVALID_REF; 100789e0f4d2SKip Macy 100889e0f4d2SKip Macy np->xn_cdata.xn_tx_chain[id] = NULL; 100989e0f4d2SKip Macy add_id_to_freelist(np->xn_cdata.xn_tx_chain, id); 101089e0f4d2SKip Macy m_freem(m); 101189e0f4d2SKip Macy } 101289e0f4d2SKip Macy np->tx.rsp_cons = prod; 101389e0f4d2SKip Macy 101489e0f4d2SKip Macy /* 101589e0f4d2SKip Macy * Set a new event, then check for race with update of 101689e0f4d2SKip Macy * tx_cons. Note that it is essential to schedule a 101789e0f4d2SKip Macy * callback, no matter how few buffers are pending. Even if 101889e0f4d2SKip Macy * there is space in the transmit ring, higher layers may 101989e0f4d2SKip Macy * be blocked because too much data is outstanding: in such 102089e0f4d2SKip Macy * cases notification from Xen is likely to be the only kick 102189e0f4d2SKip Macy * that we'll get. 102289e0f4d2SKip Macy */ 102389e0f4d2SKip Macy np->tx.sring->rsp_event = 102489e0f4d2SKip Macy prod + ((np->tx.sring->req_prod - prod) >> 1) + 1; 102589e0f4d2SKip Macy 102689e0f4d2SKip Macy mb(); 102789e0f4d2SKip Macy 102889e0f4d2SKip Macy } while (prod != np->tx.sring->rsp_prod); 102989e0f4d2SKip Macy 103089e0f4d2SKip Macy out: 103189e0f4d2SKip Macy if (np->tx_full && 103289e0f4d2SKip Macy ((np->tx.sring->req_prod - prod) < NET_TX_RING_SIZE)) { 103389e0f4d2SKip Macy np->tx_full = 0; 103489e0f4d2SKip Macy #if 0 103589e0f4d2SKip Macy if (np->user_state == UST_OPEN) 103689e0f4d2SKip Macy netif_wake_queue(dev); 103789e0f4d2SKip Macy #endif 103889e0f4d2SKip Macy } 103989e0f4d2SKip Macy 104089e0f4d2SKip Macy } 104189e0f4d2SKip Macy 104289e0f4d2SKip Macy static void 104389e0f4d2SKip Macy xn_intr(void *xsc) 104489e0f4d2SKip Macy { 104589e0f4d2SKip Macy struct netfront_info *np = xsc; 104689e0f4d2SKip Macy struct ifnet *ifp = np->xn_ifp; 104789e0f4d2SKip Macy 104889e0f4d2SKip Macy #if 0 104989e0f4d2SKip Macy if (!(np->rx.rsp_cons != np->rx.sring->rsp_prod && 105089e0f4d2SKip Macy likely(netfront_carrier_ok(np)) && 105189e0f4d2SKip Macy ifp->if_drv_flags & IFF_DRV_RUNNING)) 105289e0f4d2SKip Macy return; 105389e0f4d2SKip Macy #endif 105489e0f4d2SKip Macy if (np->tx.rsp_cons != np->tx.sring->rsp_prod) { 105589e0f4d2SKip Macy XN_TX_LOCK(np); 105689e0f4d2SKip Macy xn_txeof(np); 105789e0f4d2SKip Macy XN_TX_UNLOCK(np); 105889e0f4d2SKip Macy } 105989e0f4d2SKip Macy 106089e0f4d2SKip Macy XN_RX_LOCK(np); 106189e0f4d2SKip Macy xn_rxeof(np); 106289e0f4d2SKip Macy XN_RX_UNLOCK(np); 106389e0f4d2SKip Macy 106489e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING && 106589e0f4d2SKip Macy !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 106689e0f4d2SKip Macy xn_start(ifp); 106789e0f4d2SKip Macy } 106889e0f4d2SKip Macy 106989e0f4d2SKip Macy 107089e0f4d2SKip Macy static void 107189e0f4d2SKip Macy xennet_move_rx_slot(struct netfront_info *np, struct mbuf *m, 107289e0f4d2SKip Macy grant_ref_t ref) 107389e0f4d2SKip Macy { 107489e0f4d2SKip Macy int new = xennet_rxidx(np->rx.req_prod_pvt); 107589e0f4d2SKip Macy 107689e0f4d2SKip Macy KASSERT(np->rx_mbufs[new] == NULL, ("rx_mbufs != NULL")); 107789e0f4d2SKip Macy np->rx_mbufs[new] = m; 107889e0f4d2SKip Macy np->grant_rx_ref[new] = ref; 107989e0f4d2SKip Macy RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new; 108089e0f4d2SKip Macy RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref; 108189e0f4d2SKip Macy np->rx.req_prod_pvt++; 108289e0f4d2SKip Macy } 108389e0f4d2SKip Macy 108489e0f4d2SKip Macy static int 108589e0f4d2SKip Macy xennet_get_extras(struct netfront_info *np, 108689e0f4d2SKip Macy struct netif_extra_info *extras, RING_IDX rp) 108789e0f4d2SKip Macy { 108889e0f4d2SKip Macy struct netif_extra_info *extra; 108989e0f4d2SKip Macy RING_IDX cons = np->rx.rsp_cons; 109089e0f4d2SKip Macy 109189e0f4d2SKip Macy int err = 0; 109289e0f4d2SKip Macy 109389e0f4d2SKip Macy do { 109489e0f4d2SKip Macy struct mbuf *m; 109589e0f4d2SKip Macy grant_ref_t ref; 109689e0f4d2SKip Macy 109789e0f4d2SKip Macy if (unlikely(cons + 1 == rp)) { 109889e0f4d2SKip Macy #if 0 109989e0f4d2SKip Macy if (net_ratelimit()) 110089e0f4d2SKip Macy WPRINTK("Missing extra info\n"); 110189e0f4d2SKip Macy #endif 110289e0f4d2SKip Macy err = -EINVAL; 110389e0f4d2SKip Macy break; 110489e0f4d2SKip Macy } 110589e0f4d2SKip Macy 110689e0f4d2SKip Macy extra = (struct netif_extra_info *) 110789e0f4d2SKip Macy RING_GET_RESPONSE(&np->rx, ++cons); 110889e0f4d2SKip Macy 110989e0f4d2SKip Macy if (unlikely(!extra->type || 111089e0f4d2SKip Macy extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) { 111189e0f4d2SKip Macy #if 0 111289e0f4d2SKip Macy if (net_ratelimit()) 111389e0f4d2SKip Macy WPRINTK("Invalid extra type: %d\n", 111489e0f4d2SKip Macy extra->type); 111589e0f4d2SKip Macy #endif 111689e0f4d2SKip Macy err = -EINVAL; 111789e0f4d2SKip Macy } else { 111889e0f4d2SKip Macy memcpy(&extras[extra->type - 1], extra, sizeof(*extra)); 111989e0f4d2SKip Macy } 112089e0f4d2SKip Macy 112189e0f4d2SKip Macy m = xennet_get_rx_mbuf(np, cons); 112289e0f4d2SKip Macy ref = xennet_get_rx_ref(np, cons); 112389e0f4d2SKip Macy xennet_move_rx_slot(np, m, ref); 112489e0f4d2SKip Macy } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE); 112589e0f4d2SKip Macy 112689e0f4d2SKip Macy np->rx.rsp_cons = cons; 112789e0f4d2SKip Macy return err; 112889e0f4d2SKip Macy } 112989e0f4d2SKip Macy 113089e0f4d2SKip Macy static int 113189e0f4d2SKip Macy xennet_get_responses(struct netfront_info *np, 113289e0f4d2SKip Macy struct netfront_rx_info *rinfo, RING_IDX rp, 113389e0f4d2SKip Macy struct mbuf_head *list, 113489e0f4d2SKip Macy int *pages_flipped_p) 113589e0f4d2SKip Macy { 113689e0f4d2SKip Macy int pages_flipped = *pages_flipped_p; 113789e0f4d2SKip Macy struct mmu_update *mmu; 113889e0f4d2SKip Macy struct multicall_entry *mcl; 113989e0f4d2SKip Macy struct netif_rx_response *rx = &rinfo->rx; 114089e0f4d2SKip Macy struct netif_extra_info *extras = rinfo->extras; 114189e0f4d2SKip Macy RING_IDX cons = np->rx.rsp_cons; 114289e0f4d2SKip Macy struct mbuf *m = xennet_get_rx_mbuf(np, cons); 114389e0f4d2SKip Macy grant_ref_t ref = xennet_get_rx_ref(np, cons); 114489e0f4d2SKip Macy int max = 24 /* MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD) */; 114589e0f4d2SKip Macy int frags = 1; 114689e0f4d2SKip Macy int err = 0; 114789e0f4d2SKip Macy u_long ret; 114889e0f4d2SKip Macy 114989e0f4d2SKip Macy if (rx->flags & NETRXF_extra_info) { 115089e0f4d2SKip Macy err = xennet_get_extras(np, extras, rp); 115189e0f4d2SKip Macy cons = np->rx.rsp_cons; 115289e0f4d2SKip Macy } 115389e0f4d2SKip Macy 115489e0f4d2SKip Macy for (;;) { 115589e0f4d2SKip Macy u_long mfn; 115689e0f4d2SKip Macy 115789e0f4d2SKip Macy if (unlikely(rx->status < 0 || 115889e0f4d2SKip Macy rx->offset + rx->status > PAGE_SIZE)) { 115989e0f4d2SKip Macy #if 0 116089e0f4d2SKip Macy if (net_ratelimit()) 116189e0f4d2SKip Macy WPRINTK("rx->offset: %x, size: %u\n", 116289e0f4d2SKip Macy rx->offset, rx->status); 116389e0f4d2SKip Macy #endif 116489e0f4d2SKip Macy xennet_move_rx_slot(np, m, ref); 116589e0f4d2SKip Macy err = -EINVAL; 116689e0f4d2SKip Macy goto next; 116789e0f4d2SKip Macy } 116889e0f4d2SKip Macy 116989e0f4d2SKip Macy /* 117089e0f4d2SKip Macy * This definitely indicates a bug, either in this driver or in 117189e0f4d2SKip Macy * the backend driver. In future this should flag the bad 117289e0f4d2SKip Macy * situation to the system controller to reboot the backed. 117389e0f4d2SKip Macy */ 117489e0f4d2SKip Macy if (ref == GRANT_INVALID_REF) { 117589e0f4d2SKip Macy #if 0 117689e0f4d2SKip Macy if (net_ratelimit()) 117789e0f4d2SKip Macy WPRINTK("Bad rx response id %d.\n", rx->id); 117889e0f4d2SKip Macy #endif 117989e0f4d2SKip Macy err = -EINVAL; 118089e0f4d2SKip Macy goto next; 118189e0f4d2SKip Macy } 118289e0f4d2SKip Macy 118389e0f4d2SKip Macy if (!np->copying_receiver) { 118489e0f4d2SKip Macy /* Memory pressure, insufficient buffer 118589e0f4d2SKip Macy * headroom, ... 118689e0f4d2SKip Macy */ 118789e0f4d2SKip Macy if (!(mfn = gnttab_end_foreign_transfer_ref(ref))) { 118889e0f4d2SKip Macy if (net_ratelimit()) 118989e0f4d2SKip Macy WPRINTK("Unfulfilled rx req " 119089e0f4d2SKip Macy "(id=%d, st=%d).\n", 119189e0f4d2SKip Macy rx->id, rx->status); 119289e0f4d2SKip Macy xennet_move_rx_slot(np, m, ref); 119389e0f4d2SKip Macy err = -ENOMEM; 119489e0f4d2SKip Macy goto next; 119589e0f4d2SKip Macy } 119689e0f4d2SKip Macy 119789e0f4d2SKip Macy if (!xen_feature( XENFEAT_auto_translated_physmap)) { 119889e0f4d2SKip Macy /* Remap the page. */ 119989e0f4d2SKip Macy void *vaddr = mtod(m, void *); 120089e0f4d2SKip Macy uint32_t pfn; 120189e0f4d2SKip Macy 120289e0f4d2SKip Macy mcl = np->rx_mcl + pages_flipped; 120389e0f4d2SKip Macy mmu = np->rx_mmu + pages_flipped; 120489e0f4d2SKip Macy 120589e0f4d2SKip Macy MULTI_update_va_mapping(mcl, (u_long)vaddr, 120689e0f4d2SKip Macy (mfn << PAGE_SHIFT) | PG_RW | 120789e0f4d2SKip Macy PG_V | PG_M | PG_A, 0); 120889e0f4d2SKip Macy pfn = (uint32_t)m->m_ext.ext_arg1; 120989e0f4d2SKip Macy mmu->ptr = ((vm_paddr_t)mfn << PAGE_SHIFT) | 121089e0f4d2SKip Macy MMU_MACHPHYS_UPDATE; 121189e0f4d2SKip Macy mmu->val = pfn; 121289e0f4d2SKip Macy 121389e0f4d2SKip Macy set_phys_to_machine(pfn, mfn); 121489e0f4d2SKip Macy } 121589e0f4d2SKip Macy pages_flipped++; 121689e0f4d2SKip Macy } else { 121789e0f4d2SKip Macy ret = gnttab_end_foreign_access_ref(ref, 0); 121889e0f4d2SKip Macy KASSERT(ret, ("ret != 0")); 121989e0f4d2SKip Macy } 122089e0f4d2SKip Macy 122189e0f4d2SKip Macy gnttab_release_grant_reference(&np->gref_rx_head, ref); 122289e0f4d2SKip Macy mbufq_tail(list, m); 122389e0f4d2SKip Macy 122489e0f4d2SKip Macy next: 122589e0f4d2SKip Macy if (!(rx->flags & NETRXF_more_data)) 122689e0f4d2SKip Macy break; 122789e0f4d2SKip Macy 122889e0f4d2SKip Macy if (cons + frags == rp) { 122989e0f4d2SKip Macy if (net_ratelimit()) 123089e0f4d2SKip Macy WPRINTK("Need more frags\n"); 123189e0f4d2SKip Macy err = -ENOENT; 123289e0f4d2SKip Macy break; 123389e0f4d2SKip Macy } 123489e0f4d2SKip Macy 123589e0f4d2SKip Macy rx = RING_GET_RESPONSE(&np->rx, cons + frags); 123689e0f4d2SKip Macy m = xennet_get_rx_mbuf(np, cons + frags); 123789e0f4d2SKip Macy ref = xennet_get_rx_ref(np, cons + frags); 123889e0f4d2SKip Macy frags++; 123989e0f4d2SKip Macy } 124089e0f4d2SKip Macy 124189e0f4d2SKip Macy if (unlikely(frags > max)) { 124289e0f4d2SKip Macy if (net_ratelimit()) 124389e0f4d2SKip Macy WPRINTK("Too many frags\n"); 124489e0f4d2SKip Macy err = -E2BIG; 124589e0f4d2SKip Macy } 124689e0f4d2SKip Macy 124789e0f4d2SKip Macy if (unlikely(err)) 124889e0f4d2SKip Macy np->rx.rsp_cons = cons + frags; 124989e0f4d2SKip Macy 125089e0f4d2SKip Macy *pages_flipped_p = pages_flipped; 125189e0f4d2SKip Macy 125289e0f4d2SKip Macy return err; 125389e0f4d2SKip Macy } 125489e0f4d2SKip Macy 125589e0f4d2SKip Macy static void 125689e0f4d2SKip Macy xn_tick_locked(struct netfront_info *sc) 125789e0f4d2SKip Macy { 125889e0f4d2SKip Macy XN_RX_LOCK_ASSERT(sc); 125989e0f4d2SKip Macy callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); 126089e0f4d2SKip Macy 126189e0f4d2SKip Macy /* XXX placeholder for printing debug information */ 126289e0f4d2SKip Macy 126389e0f4d2SKip Macy } 126489e0f4d2SKip Macy 126589e0f4d2SKip Macy 126689e0f4d2SKip Macy static void 126789e0f4d2SKip Macy xn_tick(void *xsc) 126889e0f4d2SKip Macy { 126989e0f4d2SKip Macy struct netfront_info *sc; 127089e0f4d2SKip Macy 127189e0f4d2SKip Macy sc = xsc; 127289e0f4d2SKip Macy XN_RX_LOCK(sc); 127389e0f4d2SKip Macy xn_tick_locked(sc); 127489e0f4d2SKip Macy XN_RX_UNLOCK(sc); 127589e0f4d2SKip Macy 127689e0f4d2SKip Macy } 127789e0f4d2SKip Macy static void 127889e0f4d2SKip Macy xn_start_locked(struct ifnet *ifp) 127989e0f4d2SKip Macy { 128089e0f4d2SKip Macy unsigned short id; 128189e0f4d2SKip Macy struct mbuf *m_head, *new_m; 128289e0f4d2SKip Macy struct netfront_info *sc; 128389e0f4d2SKip Macy netif_tx_request_t *tx; 128489e0f4d2SKip Macy RING_IDX i; 128589e0f4d2SKip Macy grant_ref_t ref; 128689e0f4d2SKip Macy u_long mfn, tx_bytes; 128789e0f4d2SKip Macy int notify; 128889e0f4d2SKip Macy 128989e0f4d2SKip Macy sc = ifp->if_softc; 129089e0f4d2SKip Macy tx_bytes = 0; 129189e0f4d2SKip Macy 129289e0f4d2SKip Macy if (!netfront_carrier_ok(sc)) 129389e0f4d2SKip Macy return; 129489e0f4d2SKip Macy 129589e0f4d2SKip Macy for (i = sc->tx.req_prod_pvt; TRUE; i++) { 129689e0f4d2SKip Macy IF_DEQUEUE(&ifp->if_snd, m_head); 129789e0f4d2SKip Macy if (m_head == NULL) 129889e0f4d2SKip Macy break; 129989e0f4d2SKip Macy 130089e0f4d2SKip Macy if (!netfront_tx_slot_available(sc)) { 130189e0f4d2SKip Macy IF_PREPEND(&ifp->if_snd, m_head); 130289e0f4d2SKip Macy ifp->if_drv_flags |= IFF_DRV_OACTIVE; 130389e0f4d2SKip Macy break; 130489e0f4d2SKip Macy } 130589e0f4d2SKip Macy 130689e0f4d2SKip Macy id = get_id_from_freelist(sc->xn_cdata.xn_tx_chain); 130789e0f4d2SKip Macy 130889e0f4d2SKip Macy /* 130989e0f4d2SKip Macy * Start packing the mbufs in this chain into 131089e0f4d2SKip Macy * the fragment pointers. Stop when we run out 131189e0f4d2SKip Macy * of fragments or hit the end of the mbuf chain. 131289e0f4d2SKip Macy */ 131389e0f4d2SKip Macy new_m = makembuf(m_head); 131489e0f4d2SKip Macy tx = RING_GET_REQUEST(&sc->tx, i); 131589e0f4d2SKip Macy tx->id = id; 131689e0f4d2SKip Macy ref = gnttab_claim_grant_reference(&sc->gref_tx_head); 131789e0f4d2SKip Macy KASSERT((short)ref >= 0, ("Negative ref")); 131889e0f4d2SKip Macy mfn = virt_to_mfn(mtod(new_m, vm_offset_t)); 131989e0f4d2SKip Macy gnttab_grant_foreign_access_ref(ref, sc->xbdev->otherend_id, 132089e0f4d2SKip Macy mfn, GNTMAP_readonly); 132189e0f4d2SKip Macy tx->gref = sc->grant_tx_ref[id] = ref; 132289e0f4d2SKip Macy tx->size = new_m->m_pkthdr.len; 132389e0f4d2SKip Macy #if 0 132489e0f4d2SKip Macy tx->flags = (skb->ip_summed == CHECKSUM_HW) ? NETTXF_csum_blank : 0; 132589e0f4d2SKip Macy #endif 132689e0f4d2SKip Macy tx->flags = 0; 132789e0f4d2SKip Macy new_m->m_next = NULL; 132889e0f4d2SKip Macy new_m->m_nextpkt = NULL; 132989e0f4d2SKip Macy 133089e0f4d2SKip Macy m_freem(m_head); 133189e0f4d2SKip Macy 133289e0f4d2SKip Macy sc->xn_cdata.xn_tx_chain[id] = new_m; 133389e0f4d2SKip Macy BPF_MTAP(ifp, new_m); 133489e0f4d2SKip Macy 133589e0f4d2SKip Macy sc->stats.tx_bytes += new_m->m_pkthdr.len; 133689e0f4d2SKip Macy sc->stats.tx_packets++; 133789e0f4d2SKip Macy } 133889e0f4d2SKip Macy 133989e0f4d2SKip Macy sc->tx.req_prod_pvt = i; 134089e0f4d2SKip Macy RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->tx, notify); 134189e0f4d2SKip Macy if (notify) 134289e0f4d2SKip Macy notify_remote_via_irq(sc->irq); 134389e0f4d2SKip Macy 134489e0f4d2SKip Macy xn_txeof(sc); 134589e0f4d2SKip Macy 134689e0f4d2SKip Macy if (RING_FULL(&sc->tx)) { 134789e0f4d2SKip Macy sc->tx_full = 1; 134889e0f4d2SKip Macy #if 0 134989e0f4d2SKip Macy netif_stop_queue(dev); 135089e0f4d2SKip Macy #endif 135189e0f4d2SKip Macy } 135289e0f4d2SKip Macy 135389e0f4d2SKip Macy return; 135489e0f4d2SKip Macy } 135589e0f4d2SKip Macy 135689e0f4d2SKip Macy static void 135789e0f4d2SKip Macy xn_start(struct ifnet *ifp) 135889e0f4d2SKip Macy { 135989e0f4d2SKip Macy struct netfront_info *sc; 136089e0f4d2SKip Macy sc = ifp->if_softc; 136189e0f4d2SKip Macy XN_TX_LOCK(sc); 136289e0f4d2SKip Macy xn_start_locked(ifp); 136389e0f4d2SKip Macy XN_TX_UNLOCK(sc); 136489e0f4d2SKip Macy } 136589e0f4d2SKip Macy 136689e0f4d2SKip Macy /* equivalent of network_open() in Linux */ 136789e0f4d2SKip Macy static void 136889e0f4d2SKip Macy xn_ifinit_locked(struct netfront_info *sc) 136989e0f4d2SKip Macy { 137089e0f4d2SKip Macy struct ifnet *ifp; 137189e0f4d2SKip Macy 137289e0f4d2SKip Macy XN_LOCK_ASSERT(sc); 137389e0f4d2SKip Macy 137489e0f4d2SKip Macy ifp = sc->xn_ifp; 137589e0f4d2SKip Macy 137689e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) 137789e0f4d2SKip Macy return; 137889e0f4d2SKip Macy 137989e0f4d2SKip Macy xn_stop(sc); 138089e0f4d2SKip Macy 138189e0f4d2SKip Macy network_alloc_rx_buffers(sc); 138289e0f4d2SKip Macy sc->rx.sring->rsp_event = sc->rx.rsp_cons + 1; 138389e0f4d2SKip Macy 138489e0f4d2SKip Macy ifp->if_drv_flags |= IFF_DRV_RUNNING; 138589e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 138689e0f4d2SKip Macy 138789e0f4d2SKip Macy callout_reset(&sc->xn_stat_ch, hz, xn_tick, sc); 138889e0f4d2SKip Macy 138989e0f4d2SKip Macy } 139089e0f4d2SKip Macy 139189e0f4d2SKip Macy 139289e0f4d2SKip Macy static void 139389e0f4d2SKip Macy xn_ifinit(void *xsc) 139489e0f4d2SKip Macy { 139589e0f4d2SKip Macy struct netfront_info *sc = xsc; 139689e0f4d2SKip Macy 139789e0f4d2SKip Macy XN_LOCK(sc); 139889e0f4d2SKip Macy xn_ifinit_locked(sc); 139989e0f4d2SKip Macy XN_UNLOCK(sc); 140089e0f4d2SKip Macy 140189e0f4d2SKip Macy } 140289e0f4d2SKip Macy 140389e0f4d2SKip Macy 140489e0f4d2SKip Macy static int 140589e0f4d2SKip Macy xn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 140689e0f4d2SKip Macy { 140789e0f4d2SKip Macy struct netfront_info *sc = ifp->if_softc; 140889e0f4d2SKip Macy struct ifreq *ifr = (struct ifreq *) data; 140989e0f4d2SKip Macy struct ifaddr *ifa = (struct ifaddr *)data; 141089e0f4d2SKip Macy 141189e0f4d2SKip Macy int mask, error = 0; 141289e0f4d2SKip Macy switch(cmd) { 141389e0f4d2SKip Macy case SIOCSIFADDR: 141489e0f4d2SKip Macy case SIOCGIFADDR: 141589e0f4d2SKip Macy XN_LOCK(sc); 141689e0f4d2SKip Macy if (ifa->ifa_addr->sa_family == AF_INET) { 141789e0f4d2SKip Macy ifp->if_flags |= IFF_UP; 141889e0f4d2SKip Macy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 141989e0f4d2SKip Macy xn_ifinit_locked(sc); 142089e0f4d2SKip Macy arp_ifinit(ifp, ifa); 142189e0f4d2SKip Macy } else 142289e0f4d2SKip Macy error = ether_ioctl(ifp, cmd, data); 142389e0f4d2SKip Macy XN_UNLOCK(sc); 142489e0f4d2SKip Macy break; 142589e0f4d2SKip Macy case SIOCSIFMTU: 142689e0f4d2SKip Macy /* XXX can we alter the MTU on a VN ?*/ 142789e0f4d2SKip Macy #ifdef notyet 142889e0f4d2SKip Macy if (ifr->ifr_mtu > XN_JUMBO_MTU) 142989e0f4d2SKip Macy error = EINVAL; 143089e0f4d2SKip Macy else 143189e0f4d2SKip Macy #endif 143289e0f4d2SKip Macy { 143389e0f4d2SKip Macy ifp->if_mtu = ifr->ifr_mtu; 143489e0f4d2SKip Macy ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 143589e0f4d2SKip Macy xn_ifinit(sc); 143689e0f4d2SKip Macy } 143789e0f4d2SKip Macy break; 143889e0f4d2SKip Macy case SIOCSIFFLAGS: 143989e0f4d2SKip Macy XN_LOCK(sc); 144089e0f4d2SKip Macy if (ifp->if_flags & IFF_UP) { 144189e0f4d2SKip Macy /* 144289e0f4d2SKip Macy * If only the state of the PROMISC flag changed, 144389e0f4d2SKip Macy * then just use the 'set promisc mode' command 144489e0f4d2SKip Macy * instead of reinitializing the entire NIC. Doing 144589e0f4d2SKip Macy * a full re-init means reloading the firmware and 144689e0f4d2SKip Macy * waiting for it to start up, which may take a 144789e0f4d2SKip Macy * second or two. 144889e0f4d2SKip Macy */ 144989e0f4d2SKip Macy #ifdef notyet 145089e0f4d2SKip Macy /* No promiscuous mode with Xen */ 145189e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING && 145289e0f4d2SKip Macy ifp->if_flags & IFF_PROMISC && 145389e0f4d2SKip Macy !(sc->xn_if_flags & IFF_PROMISC)) { 145489e0f4d2SKip Macy XN_SETBIT(sc, XN_RX_MODE, 145589e0f4d2SKip Macy XN_RXMODE_RX_PROMISC); 145689e0f4d2SKip Macy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 145789e0f4d2SKip Macy !(ifp->if_flags & IFF_PROMISC) && 145889e0f4d2SKip Macy sc->xn_if_flags & IFF_PROMISC) { 145989e0f4d2SKip Macy XN_CLRBIT(sc, XN_RX_MODE, 146089e0f4d2SKip Macy XN_RXMODE_RX_PROMISC); 146189e0f4d2SKip Macy } else 146289e0f4d2SKip Macy #endif 146389e0f4d2SKip Macy xn_ifinit_locked(sc); 146489e0f4d2SKip Macy } else { 146589e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 146689e0f4d2SKip Macy xn_stop(sc); 146789e0f4d2SKip Macy } 146889e0f4d2SKip Macy } 146989e0f4d2SKip Macy sc->xn_if_flags = ifp->if_flags; 147089e0f4d2SKip Macy XN_UNLOCK(sc); 147189e0f4d2SKip Macy error = 0; 147289e0f4d2SKip Macy break; 147389e0f4d2SKip Macy case SIOCSIFCAP: 147489e0f4d2SKip Macy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 147589e0f4d2SKip Macy if (mask & IFCAP_HWCSUM) { 147689e0f4d2SKip Macy if (IFCAP_HWCSUM & ifp->if_capenable) 147789e0f4d2SKip Macy ifp->if_capenable &= ~IFCAP_HWCSUM; 147889e0f4d2SKip Macy else 147989e0f4d2SKip Macy ifp->if_capenable |= IFCAP_HWCSUM; 148089e0f4d2SKip Macy } 148189e0f4d2SKip Macy error = 0; 148289e0f4d2SKip Macy break; 148389e0f4d2SKip Macy case SIOCADDMULTI: 148489e0f4d2SKip Macy case SIOCDELMULTI: 148589e0f4d2SKip Macy #ifdef notyet 148689e0f4d2SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 148789e0f4d2SKip Macy XN_LOCK(sc); 148889e0f4d2SKip Macy xn_setmulti(sc); 148989e0f4d2SKip Macy XN_UNLOCK(sc); 149089e0f4d2SKip Macy error = 0; 149189e0f4d2SKip Macy } 149289e0f4d2SKip Macy #endif 149389e0f4d2SKip Macy /* FALLTHROUGH */ 149489e0f4d2SKip Macy case SIOCSIFMEDIA: 149589e0f4d2SKip Macy case SIOCGIFMEDIA: 149689e0f4d2SKip Macy error = EINVAL; 149789e0f4d2SKip Macy break; 149889e0f4d2SKip Macy default: 149989e0f4d2SKip Macy error = ether_ioctl(ifp, cmd, data); 150089e0f4d2SKip Macy } 150189e0f4d2SKip Macy 150289e0f4d2SKip Macy return (error); 150389e0f4d2SKip Macy } 150489e0f4d2SKip Macy 150589e0f4d2SKip Macy static void 150689e0f4d2SKip Macy xn_stop(struct netfront_info *sc) 150789e0f4d2SKip Macy { 150889e0f4d2SKip Macy struct ifnet *ifp; 150989e0f4d2SKip Macy 151089e0f4d2SKip Macy XN_LOCK_ASSERT(sc); 151189e0f4d2SKip Macy 151289e0f4d2SKip Macy ifp = sc->xn_ifp; 151389e0f4d2SKip Macy 151489e0f4d2SKip Macy callout_stop(&sc->xn_stat_ch); 151589e0f4d2SKip Macy 151689e0f4d2SKip Macy xn_free_rx_ring(sc); 151789e0f4d2SKip Macy xn_free_tx_ring(sc); 151889e0f4d2SKip Macy 151989e0f4d2SKip Macy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 152089e0f4d2SKip Macy } 152189e0f4d2SKip Macy 152289e0f4d2SKip Macy /* START of Xenolinux helper functions adapted to FreeBSD */ 152389e0f4d2SKip Macy static int 152489e0f4d2SKip Macy network_connect(struct ifnet *ifp) 152589e0f4d2SKip Macy { 152689e0f4d2SKip Macy struct netfront_info *np; 152789e0f4d2SKip Macy int i, requeue_idx, err; 152889e0f4d2SKip Macy grant_ref_t ref; 152989e0f4d2SKip Macy netif_rx_request_t *req; 153089e0f4d2SKip Macy u_int feature_rx_copy, feature_rx_flip; 153189e0f4d2SKip Macy 153289e0f4d2SKip Macy printf("network_connect\n"); 153389e0f4d2SKip Macy 153489e0f4d2SKip Macy np = ifp->if_softc; 153589e0f4d2SKip Macy err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, 153689e0f4d2SKip Macy "feature-rx-copy", "%u", &feature_rx_copy); 153789e0f4d2SKip Macy if (err != 1) 153889e0f4d2SKip Macy feature_rx_copy = 0; 153989e0f4d2SKip Macy err = xenbus_scanf(XBT_NIL, np->xbdev->otherend, 154089e0f4d2SKip Macy "feature-rx-flip", "%u", &feature_rx_flip); 154189e0f4d2SKip Macy if (err != 1) 154289e0f4d2SKip Macy feature_rx_flip = 1; 154389e0f4d2SKip Macy 154489e0f4d2SKip Macy /* 154589e0f4d2SKip Macy * Copy packets on receive path if: 154689e0f4d2SKip Macy * (a) This was requested by user, and the backend supports it; or 154789e0f4d2SKip Macy * (b) Flipping was requested, but this is unsupported by the backend. 154889e0f4d2SKip Macy */ 154989e0f4d2SKip Macy np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) || 155089e0f4d2SKip Macy (MODPARM_rx_flip && !feature_rx_flip)); 155189e0f4d2SKip Macy 155289e0f4d2SKip Macy XN_LOCK(np); 155389e0f4d2SKip Macy /* Recovery procedure: */ 155489e0f4d2SKip Macy err = talk_to_backend(np->xbdev, np); 155589e0f4d2SKip Macy if (err) 155689e0f4d2SKip Macy return (err); 155789e0f4d2SKip Macy 155889e0f4d2SKip Macy /* Step 1: Reinitialise variables. */ 155989e0f4d2SKip Macy netif_release_tx_bufs(np); 156089e0f4d2SKip Macy 156189e0f4d2SKip Macy /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */ 156289e0f4d2SKip Macy for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) { 156389e0f4d2SKip Macy struct mbuf *m; 156489e0f4d2SKip Macy 156589e0f4d2SKip Macy if (np->rx_mbufs[i] == NULL) 156689e0f4d2SKip Macy continue; 156789e0f4d2SKip Macy 156889e0f4d2SKip Macy m = np->rx_mbufs[requeue_idx] = xennet_get_rx_mbuf(np, i); 156989e0f4d2SKip Macy ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i); 157089e0f4d2SKip Macy req = RING_GET_REQUEST(&np->rx, requeue_idx); 157189e0f4d2SKip Macy 157289e0f4d2SKip Macy if (!np->copying_receiver) { 157389e0f4d2SKip Macy gnttab_grant_foreign_transfer_ref(ref, 157489e0f4d2SKip Macy np->xbdev->otherend_id, 157589e0f4d2SKip Macy vtophys(mtod(m, vm_offset_t))); 157689e0f4d2SKip Macy } else { 157789e0f4d2SKip Macy gnttab_grant_foreign_access_ref(ref, 157889e0f4d2SKip Macy np->xbdev->otherend_id, 157989e0f4d2SKip Macy vtophys(mtod(m, vm_offset_t)), 0); 158089e0f4d2SKip Macy } 158189e0f4d2SKip Macy req->gref = ref; 158289e0f4d2SKip Macy req->id = requeue_idx; 158389e0f4d2SKip Macy 158489e0f4d2SKip Macy requeue_idx++; 158589e0f4d2SKip Macy } 158689e0f4d2SKip Macy 158789e0f4d2SKip Macy np->rx.req_prod_pvt = requeue_idx; 158889e0f4d2SKip Macy 158989e0f4d2SKip Macy /* Step 3: All public and private state should now be sane. Get 159089e0f4d2SKip Macy * ready to start sending and receiving packets and give the driver 159189e0f4d2SKip Macy * domain a kick because we've probably just requeued some 159289e0f4d2SKip Macy * packets. 159389e0f4d2SKip Macy */ 159489e0f4d2SKip Macy netfront_carrier_on(np); 159589e0f4d2SKip Macy notify_remote_via_irq(np->irq); 159689e0f4d2SKip Macy XN_TX_LOCK(np); 159789e0f4d2SKip Macy xn_txeof(np); 159889e0f4d2SKip Macy XN_TX_UNLOCK(np); 159989e0f4d2SKip Macy network_alloc_rx_buffers(np); 160089e0f4d2SKip Macy XN_UNLOCK(np); 160189e0f4d2SKip Macy 160289e0f4d2SKip Macy return (0); 160389e0f4d2SKip Macy } 160489e0f4d2SKip Macy 160589e0f4d2SKip Macy 160689e0f4d2SKip Macy static void 160789e0f4d2SKip Macy show_device(struct netfront_info *sc) 160889e0f4d2SKip Macy { 160989e0f4d2SKip Macy #ifdef DEBUG 161089e0f4d2SKip Macy if (sc) { 161189e0f4d2SKip Macy IPRINTK("<vif handle=%u %s(%s) evtchn=%u irq=%u tx=%p rx=%p>\n", 161289e0f4d2SKip Macy sc->xn_ifno, 161389e0f4d2SKip Macy be_state_name[sc->xn_backend_state], 161489e0f4d2SKip Macy sc->xn_user_state ? "open" : "closed", 161589e0f4d2SKip Macy sc->xn_evtchn, 161689e0f4d2SKip Macy sc->xn_irq, 161789e0f4d2SKip Macy sc->xn_tx_if, 161889e0f4d2SKip Macy sc->xn_rx_if); 161989e0f4d2SKip Macy } else { 162089e0f4d2SKip Macy IPRINTK("<vif NULL>\n"); 162189e0f4d2SKip Macy } 162289e0f4d2SKip Macy #endif 162389e0f4d2SKip Macy } 162489e0f4d2SKip Macy 162589e0f4d2SKip Macy static int ifno = 0; 162689e0f4d2SKip Macy 162789e0f4d2SKip Macy /** Create a network device. 162889e0f4d2SKip Macy * @param handle device handle 162989e0f4d2SKip Macy */ 163089e0f4d2SKip Macy static int 163189e0f4d2SKip Macy create_netdev(struct xenbus_device *dev, struct ifnet **ifpp) 163289e0f4d2SKip Macy { 163389e0f4d2SKip Macy int i; 163489e0f4d2SKip Macy struct netfront_info *np; 163589e0f4d2SKip Macy int err; 163689e0f4d2SKip Macy struct ifnet *ifp; 163789e0f4d2SKip Macy 163889e0f4d2SKip Macy np = (struct netfront_info *)malloc(sizeof(struct netfront_info), 163989e0f4d2SKip Macy M_DEVBUF, M_NOWAIT); 164089e0f4d2SKip Macy if (np == NULL) 164189e0f4d2SKip Macy return (ENOMEM); 164289e0f4d2SKip Macy 164389e0f4d2SKip Macy memset(np, 0, sizeof(struct netfront_info)); 164489e0f4d2SKip Macy 164589e0f4d2SKip Macy np->xbdev = dev; 164689e0f4d2SKip Macy 164789e0f4d2SKip Macy XN_LOCK_INIT(np, xennetif); 164889e0f4d2SKip Macy np->rx_target = RX_MIN_TARGET; 164989e0f4d2SKip Macy np->rx_min_target = RX_MIN_TARGET; 165089e0f4d2SKip Macy np->rx_max_target = RX_MAX_TARGET; 165189e0f4d2SKip Macy 165289e0f4d2SKip Macy /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ 165389e0f4d2SKip Macy for (i = 0; i <= NET_TX_RING_SIZE; i++) { 165489e0f4d2SKip Macy np->tx_mbufs[i] = (void *) ((u_long) i+1); 165589e0f4d2SKip Macy np->grant_tx_ref[i] = GRANT_INVALID_REF; 165689e0f4d2SKip Macy } 165789e0f4d2SKip Macy for (i = 0; i <= NET_RX_RING_SIZE; i++) { 165889e0f4d2SKip Macy np->rx_mbufs[i] = NULL; 165989e0f4d2SKip Macy np->grant_rx_ref[i] = GRANT_INVALID_REF; 166089e0f4d2SKip Macy } 166189e0f4d2SKip Macy /* A grant for every tx ring slot */ 166289e0f4d2SKip Macy if (gnttab_alloc_grant_references(TX_MAX_TARGET, 166389e0f4d2SKip Macy &np->gref_tx_head) < 0) { 166489e0f4d2SKip Macy printf("#### netfront can't alloc tx grant refs\n"); 166589e0f4d2SKip Macy err = ENOMEM; 166689e0f4d2SKip Macy goto exit; 166789e0f4d2SKip Macy } 166889e0f4d2SKip Macy /* A grant for every rx ring slot */ 166989e0f4d2SKip Macy if (gnttab_alloc_grant_references(RX_MAX_TARGET, 167089e0f4d2SKip Macy &np->gref_rx_head) < 0) { 167189e0f4d2SKip Macy printf("#### netfront can't alloc rx grant refs\n"); 167289e0f4d2SKip Macy gnttab_free_grant_references(np->gref_tx_head); 167389e0f4d2SKip Macy err = ENOMEM; 167489e0f4d2SKip Macy goto exit; 167589e0f4d2SKip Macy } 167689e0f4d2SKip Macy 167789e0f4d2SKip Macy err = xen_net_read_mac(dev, np->mac); 167889e0f4d2SKip Macy if (err) { 167989e0f4d2SKip Macy xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); 168089e0f4d2SKip Macy goto out; 168189e0f4d2SKip Macy } 168289e0f4d2SKip Macy 168389e0f4d2SKip Macy /* Set up ifnet structure */ 168489e0f4d2SKip Macy *ifpp = ifp = np->xn_ifp = if_alloc(IFT_ETHER); 168589e0f4d2SKip Macy ifp->if_softc = np; 168689e0f4d2SKip Macy if_initname(ifp, "xn", ifno++/* ifno */); 168789e0f4d2SKip Macy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 168889e0f4d2SKip Macy ifp->if_ioctl = xn_ioctl; 168989e0f4d2SKip Macy ifp->if_output = ether_output; 169089e0f4d2SKip Macy ifp->if_start = xn_start; 169189e0f4d2SKip Macy #ifdef notyet 169289e0f4d2SKip Macy ifp->if_watchdog = xn_watchdog; 169389e0f4d2SKip Macy #endif 169489e0f4d2SKip Macy ifp->if_init = xn_ifinit; 169589e0f4d2SKip Macy ifp->if_mtu = ETHERMTU; 169689e0f4d2SKip Macy ifp->if_snd.ifq_maxlen = NET_TX_RING_SIZE - 1; 169789e0f4d2SKip Macy 169889e0f4d2SKip Macy #ifdef notyet 169989e0f4d2SKip Macy ifp->if_hwassist = XN_CSUM_FEATURES; 170089e0f4d2SKip Macy ifp->if_capabilities = IFCAP_HWCSUM; 170189e0f4d2SKip Macy ifp->if_capenable = ifp->if_capabilities; 170289e0f4d2SKip Macy #endif 170389e0f4d2SKip Macy 170489e0f4d2SKip Macy ether_ifattach(ifp, np->mac); 170589e0f4d2SKip Macy callout_init(&np->xn_stat_ch, CALLOUT_MPSAFE); 170689e0f4d2SKip Macy netfront_carrier_off(np); 170789e0f4d2SKip Macy 170889e0f4d2SKip Macy return (0); 170989e0f4d2SKip Macy 171089e0f4d2SKip Macy exit: 171189e0f4d2SKip Macy gnttab_free_grant_references(np->gref_tx_head); 171289e0f4d2SKip Macy out: 171389e0f4d2SKip Macy panic("do something smart"); 171489e0f4d2SKip Macy 171589e0f4d2SKip Macy } 171689e0f4d2SKip Macy 171789e0f4d2SKip Macy /** 171889e0f4d2SKip Macy * Handle the change of state of the backend to Closing. We must delete our 171989e0f4d2SKip Macy * device-layer structures now, to ensure that writes are flushed through to 172089e0f4d2SKip Macy * the backend. Once is this done, we can switch to Closed in 172189e0f4d2SKip Macy * acknowledgement. 172289e0f4d2SKip Macy */ 172389e0f4d2SKip Macy #if 0 172489e0f4d2SKip Macy static void netfront_closing(struct xenbus_device *dev) 172589e0f4d2SKip Macy { 172689e0f4d2SKip Macy #if 0 172789e0f4d2SKip Macy struct netfront_info *info = dev->dev_driver_data; 172889e0f4d2SKip Macy 172989e0f4d2SKip Macy DPRINTK("netfront_closing: %s removed\n", dev->nodename); 173089e0f4d2SKip Macy 173189e0f4d2SKip Macy close_netdev(info); 173289e0f4d2SKip Macy #endif 173389e0f4d2SKip Macy xenbus_switch_state(dev, XenbusStateClosed); 173489e0f4d2SKip Macy } 173589e0f4d2SKip Macy #endif 173689e0f4d2SKip Macy 173789e0f4d2SKip Macy static int netfront_remove(struct xenbus_device *dev) 173889e0f4d2SKip Macy { 173989e0f4d2SKip Macy struct netfront_info *info = dev->dev_driver_data; 174089e0f4d2SKip Macy 174189e0f4d2SKip Macy DPRINTK("%s\n", dev->nodename); 174289e0f4d2SKip Macy 174389e0f4d2SKip Macy netif_free(info); 174489e0f4d2SKip Macy free(info, M_DEVBUF); 174589e0f4d2SKip Macy 174689e0f4d2SKip Macy return 0; 174789e0f4d2SKip Macy } 174889e0f4d2SKip Macy 174989e0f4d2SKip Macy 175089e0f4d2SKip Macy static void netif_free(struct netfront_info *info) 175189e0f4d2SKip Macy { 175289e0f4d2SKip Macy netif_disconnect_backend(info); 175389e0f4d2SKip Macy #if 0 175489e0f4d2SKip Macy close_netdev(info); 175589e0f4d2SKip Macy #endif 175689e0f4d2SKip Macy } 175789e0f4d2SKip Macy 175889e0f4d2SKip Macy 175989e0f4d2SKip Macy 176089e0f4d2SKip Macy static void netif_disconnect_backend(struct netfront_info *info) 176189e0f4d2SKip Macy { 176289e0f4d2SKip Macy xn_stop(info); 176389e0f4d2SKip Macy end_access(info->tx_ring_ref, info->tx.sring); 176489e0f4d2SKip Macy end_access(info->rx_ring_ref, info->rx.sring); 176589e0f4d2SKip Macy info->tx_ring_ref = GRANT_INVALID_REF; 176689e0f4d2SKip Macy info->rx_ring_ref = GRANT_INVALID_REF; 176789e0f4d2SKip Macy info->tx.sring = NULL; 176889e0f4d2SKip Macy info->rx.sring = NULL; 176989e0f4d2SKip Macy 177089e0f4d2SKip Macy #if 0 177189e0f4d2SKip Macy if (info->irq) 177289e0f4d2SKip Macy unbind_from_irqhandler(info->irq, info->netdev); 177389e0f4d2SKip Macy #else 177489e0f4d2SKip Macy panic("FIX ME"); 177589e0f4d2SKip Macy #endif 177689e0f4d2SKip Macy info->irq = 0; 177789e0f4d2SKip Macy } 177889e0f4d2SKip Macy 177989e0f4d2SKip Macy 178089e0f4d2SKip Macy static void end_access(int ref, void *page) 178189e0f4d2SKip Macy { 178289e0f4d2SKip Macy if (ref != GRANT_INVALID_REF) 178389e0f4d2SKip Macy gnttab_end_foreign_access(ref, 0, page); 178489e0f4d2SKip Macy } 178589e0f4d2SKip Macy 178689e0f4d2SKip Macy 178789e0f4d2SKip Macy /* ** Driver registration ** */ 178889e0f4d2SKip Macy 178989e0f4d2SKip Macy 179089e0f4d2SKip Macy static struct xenbus_device_id netfront_ids[] = { 179189e0f4d2SKip Macy { "vif" }, 179289e0f4d2SKip Macy { "" } 179389e0f4d2SKip Macy }; 179489e0f4d2SKip Macy 179589e0f4d2SKip Macy 179689e0f4d2SKip Macy static struct xenbus_driver netfront = { 179789e0f4d2SKip Macy .name = "vif", 179889e0f4d2SKip Macy .ids = netfront_ids, 179989e0f4d2SKip Macy .probe = netfront_probe, 180089e0f4d2SKip Macy .remove = netfront_remove, 180189e0f4d2SKip Macy .resume = netfront_resume, 180289e0f4d2SKip Macy .otherend_changed = backend_changed, 180389e0f4d2SKip Macy }; 180489e0f4d2SKip Macy 180589e0f4d2SKip Macy static void 180689e0f4d2SKip Macy netif_init(void *unused) 180789e0f4d2SKip Macy { 180889e0f4d2SKip Macy if (!is_running_on_xen()) 180989e0f4d2SKip Macy return; 181089e0f4d2SKip Macy 181189e0f4d2SKip Macy if (is_initial_xendomain()) 181289e0f4d2SKip Macy return; 181389e0f4d2SKip Macy 181489e0f4d2SKip Macy IPRINTK("Initialising virtual ethernet driver.\n"); 181589e0f4d2SKip Macy 181689e0f4d2SKip Macy xenbus_register_frontend(&netfront); 181789e0f4d2SKip Macy } 181889e0f4d2SKip Macy 1819980c7178SKip Macy SYSINIT(xennetif, SI_SUB_PSEUDO, SI_ORDER_SECOND, netif_init, NULL); 1820980c7178SKip Macy 182189e0f4d2SKip Macy 182289e0f4d2SKip Macy /* 182389e0f4d2SKip Macy * Local variables: 182489e0f4d2SKip Macy * mode: C 182589e0f4d2SKip Macy * c-set-style: "BSD" 182689e0f4d2SKip Macy * c-basic-offset: 8 182789e0f4d2SKip Macy * tab-width: 4 182889e0f4d2SKip Macy * indent-tabs-mode: t 182989e0f4d2SKip Macy * End: 183089e0f4d2SKip Macy */ 1831