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