summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/drivers/net/netfront.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/net/netfront.c')
-rw-r--r--qemu/roms/ipxe/src/drivers/net/netfront.c952
1 files changed, 0 insertions, 952 deletions
diff --git a/qemu/roms/ipxe/src/drivers/net/netfront.c b/qemu/roms/ipxe/src/drivers/net/netfront.c
deleted file mode 100644
index 2f4bbf2a0..000000000
--- a/qemu/roms/ipxe/src/drivers/net/netfront.c
+++ /dev/null
@@ -1,952 +0,0 @@
-/*
- * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * You can also choose to distribute this program under the terms of
- * the Unmodified Binary Distribution Licence (as given in the file
- * COPYING.UBDL), provided that you have satisfied its requirements.
- */
-
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <ipxe/netdevice.h>
-#include <ipxe/ethernet.h>
-#include <ipxe/if_ether.h>
-#include <ipxe/malloc.h>
-#include <ipxe/base16.h>
-#include <ipxe/xen.h>
-#include <ipxe/xenstore.h>
-#include <ipxe/xenbus.h>
-#include <ipxe/xengrant.h>
-#include <ipxe/xenevent.h>
-#include "netfront.h"
-
-/** @file
- *
- * Xen netfront driver
- *
- */
-
-/* Disambiguate the various error causes */
-#define EIO_NETIF_RSP_ERROR \
- __einfo_error ( EINFO_EIO_NETIF_RSP_ERROR )
-#define EINFO_EIO_NETIF_RSP_ERROR \
- __einfo_uniqify ( EINFO_EIO, -NETIF_RSP_ERROR, \
- "Unspecified network error" )
-#define EIO_NETIF_RSP_DROPPED \
- __einfo_error ( EINFO_EIO_NETIF_RSP_DROPPED )
-#define EINFO_EIO_NETIF_RSP_DROPPED \
- __einfo_uniqify ( EINFO_EIO, -NETIF_RSP_DROPPED, \
- "Packet dropped" )
-#define EIO_NETIF_RSP( status ) \
- EUNIQ ( EINFO_EIO, -(status), \
- EIO_NETIF_RSP_ERROR, EIO_NETIF_RSP_DROPPED )
-
-/******************************************************************************
- *
- * XenStore interface
- *
- ******************************************************************************
- */
-
-/**
- * Reset device
- *
- * @v netfront Netfront device
- * @ret rc Return status code
- */
-static int netfront_reset ( struct netfront_nic *netfront ) {
- struct xen_device *xendev = netfront->xendev;
- int state;
- int rc;
-
- /* Get current backend state */
- if ( ( state = xenbus_backend_state ( xendev ) ) < 0 ) {
- rc = state;
- DBGC ( netfront, "NETFRONT %s could not read backend state: "
- "%s\n", xendev->key, strerror ( rc ) );
- return rc;
- }
-
- /* If the backend is not already in InitWait, then mark
- * frontend as Closed to shut down the backend.
- */
- if ( state != XenbusStateInitWait ) {
-
- /* Set state to Closed */
- xenbus_set_state ( xendev, XenbusStateClosed );
-
- /* Wait for backend to reach Closed */
- if ( ( rc = xenbus_backend_wait ( xendev,
- XenbusStateClosed ) ) != 0 ) {
- DBGC ( netfront, "NETFRONT %s backend did not reach "
- "Closed: %s\n", xendev->key, strerror ( rc ) );
- return rc;
- }
- }
-
- /* Reset state to Initialising */
- xenbus_set_state ( xendev, XenbusStateInitialising );
-
- /* Wait for backend to reach InitWait */
- if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateInitWait ) ) != 0){
- DBGC ( netfront, "NETFRONT %s backend did not reach InitWait: "
- "%s\n", xendev->key, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-}
-
-/**
- * Fetch MAC address
- *
- * @v netfront Netfront device
- * @v hw_addr Hardware address to fill in
- * @ret rc Return status code
- */
-static int netfront_read_mac ( struct netfront_nic *netfront, void *hw_addr ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- char *mac;
- int len;
- int rc;
-
- /* Fetch MAC address */
- if ( ( rc = xenstore_read ( xen, &mac, xendev->key, "mac", NULL ) )!=0){
- DBGC ( netfront, "NETFRONT %s could not read MAC address: %s\n",
- xendev->key, strerror ( rc ) );
- goto err_xenstore_read;
- }
- DBGC2 ( netfront, "NETFRONT %s has MAC address \"%s\"\n",
- xendev->key, mac );
-
- /* Decode MAC address */
- len = hex_decode ( ':', mac, hw_addr, ETH_ALEN );
- if ( len < 0 ) {
- rc = len;
- DBGC ( netfront, "NETFRONT %s could not decode MAC address "
- "\"%s\": %s\n", xendev->key, mac, strerror ( rc ) );
- goto err_decode;
- }
-
- /* Success */
- rc = 0;
-
- err_decode:
- free ( mac );
- err_xenstore_read:
- return rc;
-}
-
-/**
- * Write XenStore numeric value
- *
- * @v netfront Netfront device
- * @v subkey Subkey
- * @v num Numeric value
- * @ret rc Return status code
- */
-static int netfront_write_num ( struct netfront_nic *netfront,
- const char *subkey, unsigned long num ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- int rc;
-
- /* Write value */
- if ( ( rc = xenstore_write_num ( xen, num, xendev->key, subkey,
- NULL ) ) != 0 ) {
- DBGC ( netfront, "NETFRONT %s could not set %s=\"%ld\": %s\n",
- xendev->key, subkey, num, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-}
-
-/**
- * Write XenStore flag value
- *
- * @v netfront Netfront device
- * @v subkey Subkey
- * @v num Numeric value
- * @ret rc Return status code
- */
-static int netfront_write_flag ( struct netfront_nic *netfront,
- const char *subkey ) {
-
- return netfront_write_num ( netfront, subkey, 1 );
-}
-
-/**
- * Delete XenStore value
- *
- * @v netfront Netfront device
- * @v subkey Subkey
- * @ret rc Return status code
- */
-static int netfront_rm ( struct netfront_nic *netfront, const char *subkey ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- int rc;
-
- /* Remove value */
- if ( ( rc = xenstore_rm ( xen, xendev->key, subkey, NULL ) ) != 0 ) {
- DBGC ( netfront, "NETFRONT %s could not delete %s: %s\n",
- xendev->key, subkey, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * Events
- *
- ******************************************************************************
- */
-
-/**
- * Create event channel
- *
- * @v netfront Netfront device
- * @ret rc Return status code
- */
-static int netfront_create_event ( struct netfront_nic *netfront ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- struct evtchn_alloc_unbound alloc_unbound;
- struct evtchn_close close;
- int xenrc;
- int rc;
-
- /* Allocate event */
- alloc_unbound.dom = DOMID_SELF;
- alloc_unbound.remote_dom = xendev->backend_id;
- if ( ( xenrc = xenevent_alloc_unbound ( xen, &alloc_unbound ) ) != 0 ) {
- rc = -EXEN ( xenrc );
- DBGC ( netfront, "NETFRONT %s could not allocate event: %s\n",
- xendev->key, strerror ( rc ) );
- goto err_alloc_unbound;
- }
- netfront->event.port = alloc_unbound.port;
-
- /* Publish event channel */
- if ( ( rc = netfront_write_num ( netfront, "event-channel",
- netfront->event.port ) ) != 0 )
- goto err_write_num;
-
- DBGC ( netfront, "NETFRONT %s event-channel=\"%d\"\n",
- xendev->key, netfront->event.port );
- return 0;
-
- netfront_rm ( netfront, "event-channel" );
- err_write_num:
- close.port = netfront->event.port;
- xenevent_close ( xen, &close );
- err_alloc_unbound:
- return rc;
-}
-
-/**
- * Send event
- *
- * @v netfront Netfront device
- * @ret rc Return status code
- */
-static inline __attribute__ (( always_inline )) int
-netfront_send_event ( struct netfront_nic *netfront ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- int xenrc;
- int rc;
-
- /* Send event */
- if ( ( xenrc = xenevent_send ( xen, &netfront->event ) ) != 0 ) {
- rc = -EXEN ( xenrc );
- DBGC ( netfront, "NETFRONT %s could not send event: %s\n",
- xendev->key, strerror ( rc ) );
- return rc;
- }
-
- return 0;
-}
-
-/**
- * Destroy event channel
- *
- * @v netfront Netfront device
- */
-static void netfront_destroy_event ( struct netfront_nic *netfront ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- struct evtchn_close close;
-
- /* Unpublish event channel */
- netfront_rm ( netfront, "event-channel" );
-
- /* Close event channel */
- close.port = netfront->event.port;
- xenevent_close ( xen, &close );
-}
-
-/******************************************************************************
- *
- * Descriptor rings
- *
- ******************************************************************************
- */
-
-/**
- * Create descriptor ring
- *
- * @v netfront Netfront device
- * @v ring Descriptor ring
- * @ret rc Return status code
- */
-static int netfront_create_ring ( struct netfront_nic *netfront,
- struct netfront_ring *ring ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- unsigned int i;
- int rc;
-
- /* Initialise buffer ID ring */
- for ( i = 0 ; i < ring->count ; i++ ) {
- ring->ids[i] = i;
- assert ( ring->iobufs[i] == NULL );
- }
- ring->id_prod = 0;
- ring->id_cons = 0;
-
- /* Allocate and initialise shared ring */
- ring->sring.raw = malloc_dma ( PAGE_SIZE, PAGE_SIZE );
- if ( ! ring->sring.raw ) {
- rc = -ENOMEM;
- goto err_alloc;
- }
-
- /* Grant access to shared ring */
- if ( ( rc = xengrant_permit_access ( xen, ring->ref, xendev->backend_id,
- 0, ring->sring.raw ) ) != 0 ) {
- DBGC ( netfront, "NETFRONT %s could not permit access to "
- "%#08lx: %s\n", xendev->key,
- virt_to_phys ( ring->sring.raw ), strerror ( rc ) );
- goto err_permit_access;
- }
-
- /* Publish shared ring reference */
- if ( ( rc = netfront_write_num ( netfront, ring->ref_key,
- ring->ref ) ) != 0 )
- goto err_write_num;
-
- DBGC ( netfront, "NETFRONT %s %s=\"%d\" [%08lx,%08lx)\n",
- xendev->key, ring->ref_key, ring->ref,
- virt_to_phys ( ring->sring.raw ),
- ( virt_to_phys ( ring->sring.raw ) + PAGE_SIZE ) );
- return 0;
-
- netfront_rm ( netfront, ring->ref_key );
- err_write_num:
- xengrant_invalidate ( xen, ring->ref );
- err_permit_access:
- free_dma ( ring->sring.raw, PAGE_SIZE );
- err_alloc:
- return rc;
-}
-
-/**
- * Add buffer to descriptor ring
- *
- * @v netfront Netfront device
- * @v ring Descriptor ring
- * @v iobuf I/O buffer
- * @v id Buffer ID to fill in
- * @v ref Grant reference to fill in
- * @ret rc Return status code
- *
- * The caller is responsible for ensuring that there is space in the
- * ring.
- */
-static int netfront_push ( struct netfront_nic *netfront,
- struct netfront_ring *ring, struct io_buffer *iobuf,
- uint16_t *id, grant_ref_t *ref ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- unsigned int next_id;
- unsigned int next_ref;
- int rc;
-
- /* Sanity check */
- assert ( ! netfront_ring_is_full ( ring ) );
-
- /* Allocate buffer ID */
- next_id = ring->ids[ ring->id_prod & ( ring->count - 1 ) ];
- next_ref = ring->refs[next_id];
-
- /* Grant access to I/O buffer page. I/O buffers are naturally
- * aligned, so we never need to worry about crossing a page
- * boundary.
- */
- if ( ( rc = xengrant_permit_access ( xen, next_ref, xendev->backend_id,
- 0, iobuf->data ) ) != 0 ) {
- DBGC ( netfront, "NETFRONT %s could not permit access to "
- "%#08lx: %s\n", xendev->key,
- virt_to_phys ( iobuf->data ), strerror ( rc ) );
- return rc;
- }
-
- /* Store I/O buffer */
- assert ( ring->iobufs[next_id] == NULL );
- ring->iobufs[next_id] = iobuf;
-
- /* Consume buffer ID */
- ring->id_prod++;
-
- /* Return buffer ID and grant reference */
- *id = next_id;
- *ref = next_ref;
-
- return 0;
-}
-
-/**
- * Remove buffer from descriptor ring
- *
- * @v netfront Netfront device
- * @v ring Descriptor ring
- * @v id Buffer ID
- * @ret iobuf I/O buffer
- */
-static struct io_buffer * netfront_pull ( struct netfront_nic *netfront,
- struct netfront_ring *ring,
- unsigned int id ) {
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- struct io_buffer *iobuf;
-
- /* Sanity check */
- assert ( id < ring->count );
-
- /* Revoke access from I/O buffer page */
- xengrant_invalidate ( xen, ring->refs[id] );
-
- /* Retrieve I/O buffer */
- iobuf = ring->iobufs[id];
- assert ( iobuf != NULL );
- ring->iobufs[id] = NULL;
-
- /* Free buffer ID */
- ring->ids[ ( ring->id_cons++ ) & ( ring->count - 1 ) ] = id;
-
- return iobuf;
-}
-
-/**
- * Destroy descriptor ring
- *
- * @v netfront Netfront device
- * @v ring Descriptor ring
- * @v discard Method used to discard outstanding buffer, or NULL
- */
-static void netfront_destroy_ring ( struct netfront_nic *netfront,
- struct netfront_ring *ring,
- void ( * discard ) ( struct io_buffer * ) ){
- struct xen_device *xendev = netfront->xendev;
- struct xen_hypervisor *xen = xendev->xen;
- struct io_buffer *iobuf;
- unsigned int id;
-
- /* Flush any outstanding buffers */
- while ( ! netfront_ring_is_empty ( ring ) ) {
- id = ring->ids[ ring->id_cons & ( ring->count - 1 ) ];
- iobuf = netfront_pull ( netfront, ring, id );
- if ( discard )
- discard ( iobuf );
- }
-
- /* Unpublish shared ring reference */
- netfront_rm ( netfront, ring->ref_key );
-
- /* Revoke access from shared ring */
- xengrant_invalidate ( xen, ring->ref );
-
- /* Free page */
- free_dma ( ring->sring.raw, PAGE_SIZE );
- ring->sring.raw = NULL;
-}
-
-/******************************************************************************
- *
- * Network device interface
- *
- ******************************************************************************
- */
-
-/**
- * Refill receive descriptor ring
- *
- * @v netdev Network device
- */
-static void netfront_refill_rx ( struct net_device *netdev ) {
- struct netfront_nic *netfront = netdev->priv;
- struct xen_device *xendev = netfront->xendev;
- struct io_buffer *iobuf;
- struct netif_rx_request *request;
- int notify;
- int rc;
-
- /* Do nothing if ring is already full */
- if ( netfront_ring_is_full ( &netfront->rx ) )
- return;
-
- /* Refill ring */
- do {
-
- /* Allocate I/O buffer */
- iobuf = alloc_iob ( PAGE_SIZE );
- if ( ! iobuf ) {
- /* Wait for next refill */
- break;
- }
-
- /* Add to descriptor ring */
- request = RING_GET_REQUEST ( &netfront->rx_fring,
- netfront->rx_fring.req_prod_pvt );
- if ( ( rc = netfront_push ( netfront, &netfront->rx,
- iobuf, &request->id,
- &request->gref ) ) != 0 ) {
- netdev_rx_err ( netdev, iobuf, rc );
- break;
- }
- DBGC2 ( netfront, "NETFRONT %s RX id %d ref %d is %#08lx+%zx\n",
- xendev->key, request->id, request->gref,
- virt_to_phys ( iobuf->data ), iob_tailroom ( iobuf ) );
-
- /* Move to next descriptor */
- netfront->rx_fring.req_prod_pvt++;
-
- } while ( ! netfront_ring_is_full ( &netfront->rx ) );
-
- /* Push new descriptors and notify backend if applicable */
- RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->rx_fring, notify );
- if ( notify )
- netfront_send_event ( netfront );
-}
-
-/**
- * Open network device
- *
- * @v netdev Network device
- * @ret rc Return status code
- */
-static int netfront_open ( struct net_device *netdev ) {
- struct netfront_nic *netfront = netdev->priv;
- struct xen_device *xendev = netfront->xendev;
- int rc;
-
- /* Ensure device is in a suitable initial state */
- if ( ( rc = netfront_reset ( netfront ) ) != 0 )
- goto err_reset;
-
- /* Create transmit descriptor ring */
- if ( ( rc = netfront_create_ring ( netfront, &netfront->tx ) ) != 0 )
- goto err_create_tx;
- SHARED_RING_INIT ( netfront->tx_sring );
- FRONT_RING_INIT ( &netfront->tx_fring, netfront->tx_sring, PAGE_SIZE );
- assert ( RING_SIZE ( &netfront->tx_fring ) >= netfront->tx.count );
-
- /* Create receive descriptor ring */
- if ( ( rc = netfront_create_ring ( netfront, &netfront->rx ) ) != 0 )
- goto err_create_rx;
- SHARED_RING_INIT ( netfront->rx_sring );
- FRONT_RING_INIT ( &netfront->rx_fring, netfront->rx_sring, PAGE_SIZE );
- assert ( RING_SIZE ( &netfront->rx_fring ) >= netfront->rx.count );
-
- /* Create event channel */
- if ( ( rc = netfront_create_event ( netfront ) ) != 0 )
- goto err_create_event;
-
- /* "Request" the rx-copy feature. Current versions of
- * xen_netback.ko will fail silently if this parameter is not
- * present.
- */
- if ( ( rc = netfront_write_flag ( netfront, "request-rx-copy" ) ) != 0 )
- goto err_request_rx_copy;
-
- /* Disable checksum offload, since we will always do the work anyway */
- if ( ( rc = netfront_write_flag ( netfront,
- "feature-no-csum-offload" ) ) != 0 )
- goto err_feature_no_csum_offload;
-
- /* Inform backend that we will send notifications for RX requests */
- if ( ( rc = netfront_write_flag ( netfront,
- "feature-rx-notify" ) ) != 0 )
- goto err_feature_rx_notify;
-
- /* Set state to Connected */
- if ( ( rc = xenbus_set_state ( xendev, XenbusStateConnected ) ) != 0 ) {
- DBGC ( netfront, "NETFRONT %s could not set state=\"%d\": %s\n",
- xendev->key, XenbusStateConnected, strerror ( rc ) );
- goto err_set_state;
- }
-
- /* Wait for backend to connect */
- if ( ( rc = xenbus_backend_wait ( xendev, XenbusStateConnected ) ) !=0){
- DBGC ( netfront, "NETFRONT %s could not connect to backend: "
- "%s\n", xendev->key, strerror ( rc ) );
- goto err_backend_wait;
- }
-
- /* Refill receive descriptor ring */
- netfront_refill_rx ( netdev );
-
- /* Set link up */
- netdev_link_up ( netdev );
-
- return 0;
-
- err_backend_wait:
- netfront_reset ( netfront );
- err_set_state:
- netfront_rm ( netfront, "feature-rx-notify" );
- err_feature_rx_notify:
- netfront_rm ( netfront, "feature-no-csum-offload" );
- err_feature_no_csum_offload:
- netfront_rm ( netfront, "request-rx-copy" );
- err_request_rx_copy:
- netfront_destroy_event ( netfront );
- err_create_event:
- netfront_destroy_ring ( netfront, &netfront->rx, NULL );
- err_create_rx:
- netfront_destroy_ring ( netfront, &netfront->tx, NULL );
- err_create_tx:
- err_reset:
- return rc;
-}
-
-/**
- * Close network device
- *
- * @v netdev Network device
- */
-static void netfront_close ( struct net_device *netdev ) {
- struct netfront_nic *netfront = netdev->priv;
- struct xen_device *xendev = netfront->xendev;
- int rc;
-
- /* Reset devic, thereby ensuring that grant references are no
- * longer in use, etc.
- */
- if ( ( rc = netfront_reset ( netfront ) ) != 0 ) {
- DBGC ( netfront, "NETFRONT %s could not disconnect from "
- "backend: %s\n", xendev->key, strerror ( rc ) );
- /* Things will probably go _very_ badly wrong if this
- * happens, since it means the backend may still write
- * to the outstanding RX buffers that we are about to
- * free. The best we can do is report the error via
- * the link status, but there's a good chance the
- * machine will crash soon.
- */
- netdev_link_err ( netdev, rc );
- } else {
- netdev_link_down ( netdev );
- }
-
- /* Delete flags */
- netfront_rm ( netfront, "feature-rx-notify" );
- netfront_rm ( netfront, "feature-no-csum-offload" );
- netfront_rm ( netfront, "request-rx-copy" );
-
- /* Destroy event channel */
- netfront_destroy_event ( netfront );
-
- /* Destroy receive descriptor ring, freeing any outstanding
- * I/O buffers.
- */
- netfront_destroy_ring ( netfront, &netfront->rx, free_iob );
-
- /* Destroy transmit descriptor ring. Leave any outstanding
- * I/O buffers to be freed by netdev_tx_flush().
- */
- netfront_destroy_ring ( netfront, &netfront->tx, NULL );
-}
-
-/**
- * Transmit packet
- *
- * @v netdev Network device
- * @v iobuf I/O buffer
- * @ret rc Return status code
- */
-static int netfront_transmit ( struct net_device *netdev,
- struct io_buffer *iobuf ) {
- struct netfront_nic *netfront = netdev->priv;
- struct xen_device *xendev = netfront->xendev;
- struct netif_tx_request *request;
- int notify;
- int rc;
-
- /* Check that we have space in the ring */
- if ( netfront_ring_is_full ( &netfront->tx ) ) {
- DBGC ( netfront, "NETFRONT %s out of transmit descriptors\n",
- xendev->key );
- return -ENOBUFS;
- }
-
- /* Add to descriptor ring */
- request = RING_GET_REQUEST ( &netfront->tx_fring,
- netfront->tx_fring.req_prod_pvt );
- if ( ( rc = netfront_push ( netfront, &netfront->tx, iobuf,
- &request->id, &request->gref ) ) != 0 ) {
- return rc;
- }
- request->offset = ( virt_to_phys ( iobuf->data ) & ( PAGE_SIZE - 1 ) );
- request->flags = NETTXF_data_validated;
- request->size = iob_len ( iobuf );
- DBGC2 ( netfront, "NETFRONT %s TX id %d ref %d is %#08lx+%zx\n",
- xendev->key, request->id, request->gref,
- virt_to_phys ( iobuf->data ), iob_len ( iobuf ) );
-
- /* Consume descriptor */
- netfront->tx_fring.req_prod_pvt++;
-
- /* Push new descriptor and notify backend if applicable */
- RING_PUSH_REQUESTS_AND_CHECK_NOTIFY ( &netfront->tx_fring, notify );
- if ( notify )
- netfront_send_event ( netfront );
-
- return 0;
-}
-
-/**
- * Poll for completed packets
- *
- * @v netdev Network device
- */
-static void netfront_poll_tx ( struct net_device *netdev ) {
- struct netfront_nic *netfront = netdev->priv;
- struct xen_device *xendev = netfront->xendev;
- struct netif_tx_response *response;
- struct io_buffer *iobuf;
- unsigned int status;
- int rc;
-
- /* Consume any unconsumed responses */
- while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->tx_fring ) ) {
-
- /* Get next response */
- response = RING_GET_RESPONSE ( &netfront->tx_fring,
- netfront->tx_fring.rsp_cons++ );
-
- /* Retrieve from descriptor ring */
- iobuf = netfront_pull ( netfront, &netfront->tx, response->id );
- status = response->status;
- if ( status == NETIF_RSP_OKAY ) {
- DBGC2 ( netfront, "NETFRONT %s TX id %d complete\n",
- xendev->key, response->id );
- netdev_tx_complete ( netdev, iobuf );
- } else {
- rc = -EIO_NETIF_RSP ( status );
- DBGC2 ( netfront, "NETFRONT %s TX id %d error %d: %s\n",
- xendev->key, response->id, status,
- strerror ( rc ) );
- netdev_tx_complete_err ( netdev, iobuf, rc );
- }
- }
-}
-
-/**
- * Poll for received packets
- *
- * @v netdev Network device
- */
-static void netfront_poll_rx ( struct net_device *netdev ) {
- struct netfront_nic *netfront = netdev->priv;
- struct xen_device *xendev = netfront->xendev;
- struct netif_rx_response *response;
- struct io_buffer *iobuf;
- int status;
- size_t len;
- int rc;
-
- /* Consume any unconsumed responses */
- while ( RING_HAS_UNCONSUMED_RESPONSES ( &netfront->rx_fring ) ) {
-
- /* Get next response */
- response = RING_GET_RESPONSE ( &netfront->rx_fring,
- netfront->rx_fring.rsp_cons++ );
-
- /* Retrieve from descriptor ring */
- iobuf = netfront_pull ( netfront, &netfront->rx, response->id );
- status = response->status;
- if ( status >= 0 ) {
- len = status;
- iob_reserve ( iobuf, response->offset );
- iob_put ( iobuf, len );
- DBGC2 ( netfront, "NETFRONT %s RX id %d complete "
- "%#08lx+%zx\n", xendev->key, response->id,
- virt_to_phys ( iobuf->data ), len );
- netdev_rx ( netdev, iobuf );
- } else {
- rc = -EIO_NETIF_RSP ( status );
- DBGC2 ( netfront, "NETFRONT %s RX id %d error %d: %s\n",
- xendev->key, response->id, status,
- strerror ( rc ) );
- netdev_rx_err ( netdev, iobuf, rc );
- }
- }
-}
-
-/**
- * Poll for completed and received packets
- *
- * @v netdev Network device
- */
-static void netfront_poll ( struct net_device *netdev ) {
-
- /* Poll for TX completions */
- netfront_poll_tx ( netdev );
-
- /* Poll for RX completions */
- netfront_poll_rx ( netdev );
-
- /* Refill RX descriptor ring */
- netfront_refill_rx ( netdev );
-}
-
-/** Network device operations */
-static struct net_device_operations netfront_operations = {
- .open = netfront_open,
- .close = netfront_close,
- .transmit = netfront_transmit,
- .poll = netfront_poll,
-};
-
-/******************************************************************************
- *
- * Xen device bus interface
- *
- ******************************************************************************
- */
-
-/**
- * Probe Xen device
- *
- * @v xendev Xen device
- * @ret rc Return status code
- */
-static int netfront_probe ( struct xen_device *xendev ) {
- struct xen_hypervisor *xen = xendev->xen;
- struct net_device *netdev;
- struct netfront_nic *netfront;
- int rc;
-
- /* Allocate and initialise structure */
- netdev = alloc_etherdev ( sizeof ( *netfront ) );
- if ( ! netdev ) {
- rc = -ENOMEM;
- goto err_alloc;
- }
- netdev_init ( netdev, &netfront_operations );
- netdev->dev = &xendev->dev;
- netfront = netdev->priv;
- netfront->xendev = xendev;
- DBGC ( netfront, "NETFRONT %s backend=\"%s\" in domain %ld\n",
- xendev->key, xendev->backend, xendev->backend_id );
-
- /* Allocate grant references and initialise descriptor rings */
- if ( ( rc = xengrant_alloc ( xen, netfront->refs,
- NETFRONT_REF_COUNT ) ) != 0 ) {
- DBGC ( netfront, "NETFRONT %s could not allocate grant "
- "references: %s\n", xendev->key, strerror ( rc ) );
- goto err_grant_alloc;
- }
- netfront_init_ring ( &netfront->tx, "tx-ring-ref",
- netfront->refs[NETFRONT_REF_TX_RING],
- NETFRONT_NUM_TX_DESC, netfront->tx_iobufs,
- &netfront->refs[NETFRONT_REF_TX_BASE],
- netfront->tx_ids );
- netfront_init_ring ( &netfront->rx, "rx-ring-ref",
- netfront->refs[NETFRONT_REF_RX_RING],
- NETFRONT_NUM_RX_DESC, netfront->rx_iobufs,
- &netfront->refs[NETFRONT_REF_RX_BASE],
- netfront->rx_ids );
-
- /* Fetch MAC address */
- if ( ( rc = netfront_read_mac ( netfront, netdev->hw_addr ) ) != 0 )
- goto err_read_mac;
-
- /* Reset device. Ignore failures; allow the device to be
- * registered so that reset errors can be observed by the user
- * when attempting to open the device.
- */
- netfront_reset ( netfront );
-
- /* Register network device */
- if ( ( rc = register_netdev ( netdev ) ) != 0 )
- goto err_register_netdev;
-
- /* Set initial link state */
- netdev_link_down ( netdev );
-
- xen_set_drvdata ( xendev, netdev );
- return 0;
-
- unregister_netdev ( netdev );
- err_register_netdev:
- err_read_mac:
- xengrant_free ( xen, netfront->refs, NETFRONT_REF_COUNT );
- err_grant_alloc:
- netdev_nullify ( netdev );
- netdev_put ( netdev );
- err_alloc:
- return rc;
-}
-
-/**
- * Remove Xen device
- *
- * @v xendev Xen device
- */
-static void netfront_remove ( struct xen_device *xendev ) {
- struct net_device *netdev = xen_get_drvdata ( xendev );
- struct netfront_nic *netfront = netdev->priv;
- struct xen_hypervisor *xen = xendev->xen;
-
- /* Unregister network device */
- unregister_netdev ( netdev );
-
- /* Free resources */
- xengrant_free ( xen, netfront->refs, NETFRONT_REF_COUNT );
-
- /* Free network device */
- netdev_nullify ( netdev );
- netdev_put ( netdev );
-}
-
-/** Xen netfront driver */
-struct xen_driver netfront_driver __xen_driver = {
- .name = "netfront",
- .type = "vif",
- .probe = netfront_probe,
- .remove = netfront_remove,
-};