iPXE
Functions | Variables
netvsc.c File Reference

Hyper-V network virtual service client. More...

#include <errno.h>
#include <unistd.h>
#include <byteswap.h>
#include <ipxe/umalloc.h>
#include <ipxe/rndis.h>
#include <ipxe/vmbus.h>
#include "netvsc.h"

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static int netvsc_control (struct netvsc_device *netvsc, unsigned int xrid, const void *data, size_t len)
 Send control message and wait for completion.
static int netvsc_completed (struct netvsc_device *netvsc __unused, const void *data __unused, size_t len __unused)
 Handle generic completion.
static int netvsc_initialise (struct netvsc_device *netvsc)
 Initialise communication.
static int netvsc_initialised (struct netvsc_device *netvsc, const void *data, size_t len)
 Handle initialisation completion.
static int netvsc_ndis_version (struct netvsc_device *netvsc)
 Set NDIS version.
static int netvsc_establish_buffer (struct netvsc_device *netvsc, struct netvsc_buffer *buffer)
 Establish data buffer.
static int netvsc_rx_established_buffer (struct netvsc_device *netvsc, const void *data, size_t len)
 Handle establish receive data buffer completion.
static int netvsc_revoke_buffer (struct netvsc_device *netvsc, struct netvsc_buffer *buffer)
 Revoke data buffer.
static int netvsc_recv_control (struct vmbus_device *vmdev, uint64_t xid, const void *data, size_t len)
 Handle received control packet.
static int netvsc_recv_data (struct vmbus_device *vmdev, uint64_t xid, const void *data, size_t len, struct list_head *list)
 Handle received data packet.
static int netvsc_recv_completion (struct vmbus_device *vmdev, uint64_t xid, const void *data, size_t len)
 Handle received completion packet.
static int netvsc_recv_cancellation (struct vmbus_device *vmdev, uint64_t xid)
 Handle received cancellation packet.
static void netvsc_poll (struct rndis_device *rndis)
 Poll for completed and received packets.
static int netvsc_transmit (struct rndis_device *rndis, struct io_buffer *iobuf)
 Transmit packet.
static void netvsc_cancel_transmit (struct netvsc_device *netvsc, struct io_buffer *iobuf, unsigned int tx_id)
 Cancel transmission.
static int netvsc_create_ring (struct netvsc_device *netvsc __unused, struct netvsc_ring *ring)
 Create descriptor ring.
static void netvsc_destroy_ring (struct netvsc_device *netvsc, struct netvsc_ring *ring, void(*discard)(struct netvsc_device *, struct io_buffer *, unsigned int))
 Destroy descriptor ring.
static int netvsc_buffer_copy (struct vmbus_xfer_pages *pages, void *data, size_t offset, size_t len)
 Copy data from data buffer.
static int netvsc_create_buffer (struct netvsc_device *netvsc, struct netvsc_buffer *buffer)
 Create data buffer.
static void netvsc_destroy_buffer (struct netvsc_device *netvsc, struct netvsc_buffer *buffer)
 Destroy data buffer.
static int netvsc_open (struct rndis_device *rndis)
 Open device.
static void netvsc_close (struct rndis_device *rndis)
 Close device.
static int netvsc_probe (struct vmbus_device *vmdev)
 Probe device.
static int netvsc_reset (struct vmbus_device *vmdev)
 Reset device.
static void netvsc_remove (struct vmbus_device *vmdev)
 Remove device.

Variables

static struct
vmbus_channel_operations 
netvsc_channel_operations
 VMBus channel operations.
static struct
vmbus_xfer_pages_operations 
netvsc_xfer_pages_operations
 Transfer page set operations.
static struct rndis_operations netvsc_operations
 RNDIS operations.
struct vmbus_driver netvsc_driver __vmbus_driver
 NetVSC driver.

Detailed Description

Hyper-V network virtual service client.

The network virtual service client (NetVSC) connects to the network virtual service provider (NetVSP) via the Hyper-V virtual machine bus (VMBus). It provides a transport layer for RNDIS packets.

Definition in file netvsc.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static int netvsc_control ( struct netvsc_device *  netvsc,
unsigned int  xrid,
const void *  data,
size_t  len 
) [static]

Send control message and wait for completion.

Parameters:
netvscNetVSC device
xridRelative transaction ID
dataData
lenLength of data
Return values:
rcReturn status code

Definition at line 52 of file netvsc.c.

References DBGC, ETIMEDOUT, mdelay(), NETVSC_BASE_XID, NETVSC_MAX_WAIT_MS, rc, strerror(), vmbus_dump_channel(), vmbus_poll(), and vmbus_send_control().

Referenced by netvsc_establish_buffer(), netvsc_initialise(), netvsc_ndis_version(), and netvsc_revoke_buffer().

                                                           {
        uint64_t xid = ( NETVSC_BASE_XID + xrid );
        unsigned int i;
        int rc;

        /* Send control message */
        if ( ( rc = vmbus_send_control ( netvsc->vmdev, xid, data, len ) ) !=0){
                DBGC ( netvsc, "NETVSC %s could not send control message: %s\n",
                       netvsc->name, strerror ( rc ) );
                return rc;
        }

        /* Record transaction ID */
        netvsc->wait_xrid = xrid;

        /* Wait for operation to complete */
        for ( i = 0 ; i < NETVSC_MAX_WAIT_MS ; i++ ) {

                /* Check for completion */
                if ( ! netvsc->wait_xrid )
                        return netvsc->wait_rc;

                /* Poll VMBus device */
                vmbus_poll ( netvsc->vmdev );

                /* Delay for 1ms */
                mdelay ( 1 );
        }

        DBGC ( netvsc, "NETVSC %s timed out waiting for XRID %d\n",
               netvsc->name, xrid );
        vmbus_dump_channel ( netvsc->vmdev );
        return -ETIMEDOUT;
}
static int netvsc_completed ( struct netvsc_device *netvsc  __unused,
const void *data  __unused,
size_t len  __unused 
) [static]

Handle generic completion.

Parameters:
netvscNetVSC device
dataData
lenLength of data
Return values:
rcReturn status code

Definition at line 96 of file netvsc.c.

Referenced by netvsc_recv_completion().

                                                                               {
        return 0;
}
static int netvsc_initialise ( struct netvsc_device *  netvsc) [static]

Initialise communication.

Parameters:
netvscNetVSC device
Return values:
rcReturn status code

Definition at line 107 of file netvsc.c.

References cpu_to_le32, DBGC, netvsc_init_message::header, netvsc_init_message::max, memset(), netvsc_init_message::min, netvsc_control(), NETVSC_INIT_MSG, NETVSC_INIT_XRID, NETVSC_VERSION_1, rc, strerror(), and netvsc_header::type.

Referenced by netvsc_open().

                                                              {
        struct netvsc_init_message msg;
        int rc;

        /* Construct message */
        memset ( &msg, 0, sizeof ( msg ) );
        msg.header.type = cpu_to_le32 ( NETVSC_INIT_MSG );
        msg.min = cpu_to_le32 ( NETVSC_VERSION_1 );
        msg.max = cpu_to_le32 ( NETVSC_VERSION_1 );

        /* Send message and wait for completion */
        if ( ( rc = netvsc_control ( netvsc, NETVSC_INIT_XRID, &msg,
                                     sizeof ( msg ) ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not initialise: %s\n",
                       netvsc->name, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int netvsc_initialised ( struct netvsc_device *  netvsc,
const void *  data,
size_t  len 
) [static]

Handle initialisation completion.

Parameters:
netvscNetVSC device
dataData
lenLength of data
Return values:
rcReturn status code

Definition at line 137 of file netvsc.c.

References cpu_to_le32, data, DBGC, EINVAL, EPROTO, netvsc_init_completion::header, le32_to_cpu, NETVSC_INIT_CMPLT, NETVSC_OK, netvsc_init_completion::status, and netvsc_header::type.

Referenced by netvsc_recv_completion().

                                  {
        const struct netvsc_init_completion *cmplt = data;

        /* Check completion */
        if ( len < sizeof ( *cmplt ) ) {
                DBGC ( netvsc, "NETVSC %s underlength initialisation "
                       "completion (%zd bytes)\n", netvsc->name, len );
                return -EINVAL;
        }
        if ( cmplt->header.type != cpu_to_le32 ( NETVSC_INIT_CMPLT ) ) {
                DBGC ( netvsc, "NETVSC %s unexpected initialisation completion "
                       "type %d\n", netvsc->name,
                       le32_to_cpu ( cmplt->header.type ) );
                return -EPROTO;
        }
        if ( cmplt->status != cpu_to_le32 ( NETVSC_OK ) ) {
                DBGC ( netvsc, "NETVSC %s initialisation failure status %d\n",
                       netvsc->name, le32_to_cpu ( cmplt->status ) );
                return -EPROTO;
        }

        return 0;
}
static int netvsc_ndis_version ( struct netvsc_device *  netvsc) [static]

Set NDIS version.

Parameters:
netvscNetVSC device
Return values:
rcReturn status code

Definition at line 168 of file netvsc.c.

References cpu_to_le32, DBGC, netvsc_ndis_version_message::header, netvsc_ndis_version_message::major, memset(), netvsc_ndis_version_message::minor, netvsc_control(), NETVSC_NDIS_MAJOR, NETVSC_NDIS_MINOR, NETVSC_NDIS_VERSION_MSG, NETVSC_NDIS_VERSION_XRID, rc, strerror(), and netvsc_header::type.

Referenced by netvsc_open().

                                                                {
        struct netvsc_ndis_version_message msg;
        int rc;

        /* Construct message */
        memset ( &msg, 0, sizeof ( msg ) );
        msg.header.type = cpu_to_le32 ( NETVSC_NDIS_VERSION_MSG );
        msg.major = cpu_to_le32 ( NETVSC_NDIS_MAJOR );
        msg.minor = cpu_to_le32 ( NETVSC_NDIS_MINOR );

        /* Send message and wait for completion */
        if ( ( rc = netvsc_control ( netvsc, NETVSC_NDIS_VERSION_XRID,
                                     &msg, sizeof ( msg ) ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not set NDIS version: %s\n",
                       netvsc->name, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int netvsc_establish_buffer ( struct netvsc_device *  netvsc,
struct netvsc_buffer *  buffer 
) [static]

Establish data buffer.

Parameters:
netvscNetVSC device
bufferData buffer
Return values:
rcReturn status code

Definition at line 196 of file netvsc.c.

References cpu_to_le32, DBGC, netvsc_establish_buffer_message::gpadl, netvsc_establish_buffer_message::header, memset(), netvsc_control(), netvsc_establish_buffer_message::pageset, rc, strerror(), and netvsc_header::type.

Referenced by netvsc_open().

                                                                    {
        struct netvsc_establish_buffer_message msg;
        int rc;

        /* Construct message */
        memset ( &msg, 0, sizeof ( msg ) );
        msg.header.type = cpu_to_le32 ( buffer->establish_type );
        msg.gpadl = cpu_to_le32 ( buffer->gpadl );
        msg.pageset = buffer->pages.pageset; /* Already protocol-endian */

        /* Send message and wait for completion */
        if ( ( rc = netvsc_control ( netvsc, buffer->establish_xrid, &msg,
                                     sizeof ( msg ) ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not establish buffer: %s\n",
                       netvsc->name, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int netvsc_rx_established_buffer ( struct netvsc_device *  netvsc,
const void *  data,
size_t  len 
) [static]

Handle establish receive data buffer completion.

Parameters:
netvscNetVSC device
dataData
lenLength of data
Return values:
rcReturn status code

Definition at line 226 of file netvsc.c.

References cpu_to_le32, data, DBGC, EINVAL, EPROTO, netvsc_rx_establish_buffer_completion::header, le32_to_cpu, NETVSC_OK, NETVSC_RX_ESTABLISH_CMPLT, netvsc_rx_establish_buffer_completion::status, and netvsc_header::type.

Referenced by netvsc_recv_completion().

                                                                         {
        const struct netvsc_rx_establish_buffer_completion *cmplt = data;

        /* Check completion */
        if ( len < sizeof ( *cmplt ) ) {
                DBGC ( netvsc, "NETVSC %s underlength buffer completion (%zd "
                       "bytes)\n", netvsc->name, len );
                return -EINVAL;
        }
        if ( cmplt->header.type != cpu_to_le32 ( NETVSC_RX_ESTABLISH_CMPLT ) ) {
                DBGC ( netvsc, "NETVSC %s unexpected buffer completion type "
                       "%d\n", netvsc->name, le32_to_cpu ( cmplt->header.type));
                return -EPROTO;
        }
        if ( cmplt->status != cpu_to_le32 ( NETVSC_OK ) ) {
                DBGC ( netvsc, "NETVSC %s buffer failure status %d\n",
                       netvsc->name, le32_to_cpu ( cmplt->status ) );
                return -EPROTO;
        }

        return 0;
}
static int netvsc_revoke_buffer ( struct netvsc_device *  netvsc,
struct netvsc_buffer *  buffer 
) [static]

Revoke data buffer.

Parameters:
netvscNetVSC device
bufferData buffer
Return values:
rcReturn status code

Definition at line 257 of file netvsc.c.

References cpu_to_le32, DBGC, netvsc_revoke_buffer_message::header, memset(), netvsc_control(), netvsc_revoke_buffer_message::pageset, rc, strerror(), and netvsc_header::type.

Referenced by netvsc_close(), and netvsc_open().

                                                                 {
        struct netvsc_revoke_buffer_message msg;
        int rc;

        /* If the buffer's GPADL is obsolete (i.e. was created before
         * the most recent Hyper-V reset), then we will never receive
         * a response to the revoke message.  Since the GPADL is
         * already destroyed as far as the hypervisor is concerned, no
         * further action is required.
         */
        if ( netvsc_is_obsolete ( netvsc ) )
                return 0;

        /* Construct message */
        memset ( &msg, 0, sizeof ( msg ) );
        msg.header.type = cpu_to_le32 ( buffer->revoke_type );
        msg.pageset = buffer->pages.pageset; /* Already protocol-endian */

        /* Send message and wait for completion */
        if ( ( rc = netvsc_control ( netvsc, buffer->revoke_xrid,
                                     &msg, sizeof ( msg ) ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not revoke buffer: %s\n",
                       netvsc->name, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static int netvsc_recv_control ( struct vmbus_device vmdev,
uint64_t  xid,
const void *  data,
size_t  len 
) [static]

Handle received control packet.

Parameters:
vmdevVMBus device
xidTransaction ID
dataData
lenLength of data
Return values:
rcReturn status code

Definition at line 296 of file netvsc.c.

References DBGC, DBGC_HDA, ENOTSUP, rndis_device::priv, and vmbus_get_drvdata().

                                                                {
        struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
        struct netvsc_device *netvsc = rndis->priv;

        DBGC ( netvsc, "NETVSC %s received unsupported control packet "
               "(%08llx):\n", netvsc->name, xid );
        DBGC_HDA ( netvsc, 0, data, len );
        return -ENOTSUP;
}
static int netvsc_recv_data ( struct vmbus_device vmdev,
uint64_t  xid,
const void *  data,
size_t  len,
struct list_head list 
) [static]

Handle received data packet.

Parameters:
vmdevVMBus device
xidTransaction ID
dataData
lenLength of data
listList of I/O buffers
Return values:
rcReturn status code

Definition at line 317 of file netvsc.c.

References cpu_to_le32, data, DBGC, EINVAL, free_iob(), netvsc_rndis_message::header, iob_disown, le32_to_cpu, io_buffer::list, list_del, list_for_each_entry_safe, msg(), NETVSC_RNDIS_MSG, NULL, rndis_device::priv, rc, rndis_rx(), strerror(), netvsc_header::type, vmbus_get_drvdata(), and vmbus_send_completion().

                                                       {
        struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
        struct netvsc_device *netvsc = rndis->priv;
        const struct netvsc_rndis_message *msg = data;
        struct io_buffer *iobuf;
        struct io_buffer *tmp;
        int rc;

        /* Sanity check */
        if ( len < sizeof ( *msg ) ) {
                DBGC ( netvsc, "NETVSC %s received underlength RNDIS packet "
                       "(%zd bytes)\n", netvsc->name, len );
                rc = -EINVAL;
                goto err_sanity;
        }
        if ( msg->header.type != cpu_to_le32 ( NETVSC_RNDIS_MSG ) ) {
                DBGC ( netvsc, "NETVSC %s received unexpected RNDIS packet "
                       "type %d\n", netvsc->name,
                       le32_to_cpu ( msg->header.type ) );
                rc = -EINVAL;
                goto err_sanity;
        }

        /* Send completion back to host */
        if ( ( rc = vmbus_send_completion ( vmdev, xid, NULL, 0 ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not send completion: %s\n",
                       netvsc->name, strerror ( rc ) );
                goto err_completion;
        }

        /* Hand off to RNDIS */
        list_for_each_entry_safe ( iobuf, tmp, list, list ) {
                list_del ( &iobuf->list );
                rndis_rx ( rndis, iob_disown ( iobuf ) );
        }

        return 0;

 err_completion:
 err_sanity:
        list_for_each_entry_safe ( iobuf, tmp, list, list ) {
                list_del ( &iobuf->list );
                free_iob ( iobuf );
        }
        return rc;
}
static int netvsc_recv_completion ( struct vmbus_device vmdev,
uint64_t  xid,
const void *  data,
size_t  len 
) [static]

Handle received completion packet.

Parameters:
vmdevVMBus device
xidTransaction ID
dataData
lenLength of data
Return values:
rcReturn status code

Definition at line 375 of file netvsc.c.

References completion, data, DBGC, EPIPE, len, NETVSC_BASE_XID, netvsc_completed(), NETVSC_INIT_XRID, netvsc_initialised(), NETVSC_RX_ESTABLISH_XRID, netvsc_rx_established_buffer(), NETVSC_TX_BASE_XRID, NETVSC_TX_NUM_DESC, NULL, rndis_device::priv, rc, rndis_tx_complete(), and vmbus_get_drvdata().

                                                                   {
        struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
        struct netvsc_device *netvsc = rndis->priv;
        struct io_buffer *iobuf;
        int ( * completion ) ( struct netvsc_device *netvsc,
                               const void *data, size_t len );
        unsigned int xrid = ( xid - NETVSC_BASE_XID );
        unsigned int tx_id;
        int rc;

        /* Handle transmit completion, if applicable */
        tx_id = ( xrid - NETVSC_TX_BASE_XRID );
        if ( ( tx_id < NETVSC_TX_NUM_DESC ) &&
             ( ( iobuf = netvsc->tx.iobufs[tx_id] ) != NULL ) ) {

                /* Free buffer ID */
                netvsc->tx.iobufs[tx_id] = NULL;
                netvsc->tx.ids[ ( netvsc->tx.id_cons++ ) &
                                ( netvsc->tx.count - 1 ) ] = tx_id;

                /* Hand back to RNDIS */
                rndis_tx_complete ( rndis, iobuf );
                return 0;
        }

        /* Otherwise determine completion handler */
        if ( xrid == NETVSC_INIT_XRID ) {
                completion = netvsc_initialised;
        } else if ( xrid == NETVSC_RX_ESTABLISH_XRID ) {
                completion = netvsc_rx_established_buffer;
        } else if ( ( netvsc->wait_xrid != 0 ) &&
                    ( xrid == netvsc->wait_xrid ) ) {
                completion = netvsc_completed;
        } else {
                DBGC ( netvsc, "NETVSC %s received unexpected completion "
                       "(%08llx)\n", netvsc->name, xid );
                return -EPIPE;
        }

        /* Hand off to completion handler */
        rc = completion ( netvsc, data, len );

        /* Record completion handler result if applicable */
        if ( xrid == netvsc->wait_xrid ) {
                netvsc->wait_xrid = 0;
                netvsc->wait_rc = rc;
        }

        return rc;
}
static int netvsc_recv_cancellation ( struct vmbus_device vmdev,
uint64_t  xid 
) [static]

Handle received cancellation packet.

Parameters:
vmdevVMBus device
xidTransaction ID
Return values:
rcReturn status code

Definition at line 434 of file netvsc.c.

References DBGC, ENOTSUP, rndis_device::priv, and vmbus_get_drvdata().

                                                     {
        struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
        struct netvsc_device *netvsc = rndis->priv;

        DBGC ( netvsc, "NETVSC %s received unsupported cancellation packet "
               "(%08llx):\n", netvsc->name, xid );
        return -ENOTSUP;
}
static void netvsc_poll ( struct rndis_device rndis) [static]

Poll for completed and received packets.

Parameters:
rndisRNDIS device

Definition at line 457 of file netvsc.c.

References rndis_device::priv, vmbus_has_data(), and vmbus_poll().

                                                       {
        struct netvsc_device *netvsc = rndis->priv;
        struct vmbus_device *vmdev = netvsc->vmdev;

        /* Poll VMBus device */
        while ( vmbus_has_data ( vmdev ) )
                vmbus_poll ( vmdev );
}
static int netvsc_transmit ( struct rndis_device rndis,
struct io_buffer iobuf 
) [static]

Transmit packet.

Parameters:
rndisRNDIS device
iobufI/O buffer
Return values:
rcReturn status code

If this method returns success then the RNDIS device must eventually report completion via rndis_tx_complete().

Definition at line 476 of file netvsc.c.

References assert, netvsc_rndis_message::buffer, netvsc_rndis_message::channel, cpu_to_le32, io_buffer::data, DBGC, EPIPE, header, netvsc_rndis_message::header, iob_len(), le32_to_cpu, rndis_header::len, memset(), NETVSC_BASE_XID, NETVSC_RNDIS_CONTROL, NETVSC_RNDIS_DATA, NETVSC_RNDIS_MSG, NETVSC_RNDIS_NO_BUFFER, NETVSC_TX_BASE_XRID, NULL, rndis_device::priv, rc, RNDIS_PACKET_MSG, rndis_tx_defer(), strerror(), rndis_header::type, netvsc_header::type, and vmbus_send_data().

                                                       {
        struct netvsc_device *netvsc = rndis->priv;
        struct rndis_header *header = iobuf->data;
        struct netvsc_rndis_message msg;
        unsigned int tx_id;
        unsigned int xrid;
        uint64_t xid;
        int rc;

        /* If the device is obsolete (i.e. was opened before the most
         * recent Hyper-V reset), then we will never receive transmit
         * completions.  Fail transmissions immediately to minimise
         * the delay in closing and reopening the device.
         */
        if ( netvsc_is_obsolete ( netvsc ) )
                return -EPIPE;

        /* Sanity check */
        assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
        assert ( iob_len ( iobuf ) == le32_to_cpu ( header->len ) );

        /* Check that we have space in the transmit ring */
        if ( netvsc_ring_is_full ( &netvsc->tx ) )
                return rndis_tx_defer ( rndis, iobuf );

        /* Allocate buffer ID and calculate transaction ID */
        tx_id = netvsc->tx.ids[ netvsc->tx.id_prod & ( netvsc->tx.count - 1 ) ];
        assert ( netvsc->tx.iobufs[tx_id] == NULL );
        xrid = ( NETVSC_TX_BASE_XRID + tx_id );
        xid = ( NETVSC_BASE_XID + xrid );

        /* Construct message */
        memset ( &msg, 0, sizeof ( msg ) );
        msg.header.type = cpu_to_le32 ( NETVSC_RNDIS_MSG );
        msg.channel = ( ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) ?
                        NETVSC_RNDIS_DATA : NETVSC_RNDIS_CONTROL );
        msg.buffer = cpu_to_le32 ( NETVSC_RNDIS_NO_BUFFER );

        /* Send message */
        if ( ( rc = vmbus_send_data ( netvsc->vmdev, xid, &msg, sizeof ( msg ),
                                      iobuf ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not send RNDIS message: %s\n",
                       netvsc->name, strerror ( rc ) );
                return rc;
        }

        /* Store I/O buffer and consume buffer ID */
        netvsc->tx.iobufs[tx_id] = iobuf;
        netvsc->tx.id_prod++;

        return 0;
}
static void netvsc_cancel_transmit ( struct netvsc_device *  netvsc,
struct io_buffer iobuf,
unsigned int  tx_id 
) [static]

Cancel transmission.

Parameters:
netvscNetVSC device
iobufI/O buffer
tx_idTransmission ID

Definition at line 537 of file netvsc.c.

References DBGC, ECANCELED, NETVSC_BASE_XID, NETVSC_TX_BASE_XRID, rndis_tx_complete_err(), and vmbus_send_cancellation().

Referenced by netvsc_close().

                                                          {
        unsigned int xrid;
        uint64_t xid;

        /* Send cancellation */
        xrid = ( NETVSC_TX_BASE_XRID + tx_id );
        xid = ( NETVSC_BASE_XID + xrid );
        DBGC ( netvsc, "NETVSC %s cancelling transmission %#x\n",
               netvsc->name, tx_id );
        vmbus_send_cancellation ( netvsc->vmdev, xid );

        /* Report back to RNDIS */
        rndis_tx_complete_err ( netvsc->rndis, iobuf, -ECANCELED );
}
static int netvsc_create_ring ( struct netvsc_device *netvsc  __unused,
struct netvsc_ring ring 
) [static]

Create descriptor ring.

Parameters:
netvscNetVSC device
ringDescriptor ring
Return values:
rcReturn status code

Definition at line 561 of file netvsc.c.

References assert, netvsc_ring::count, netvsc_ring::id_cons, netvsc_ring::id_prod, netvsc_ring::ids, netvsc_ring::iobufs, and NULL.

Referenced by netvsc_open().

                                                           {
        unsigned int i;

        /* 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;

        return 0;
}
static void netvsc_destroy_ring ( struct netvsc_device *  netvsc,
struct netvsc_ring ring,
void(*)(struct netvsc_device *, struct io_buffer *, unsigned int)  discard 
) [static]

Destroy descriptor ring.

Parameters:
netvscNetVSC device
ringDescriptor ring
discardMethod used to discard outstanding buffer, or NULL

Definition at line 583 of file netvsc.c.

References assert, netvsc_ring::count, netvsc_ring::id_cons, netvsc_ring::ids, netvsc_ring::iobufs, and NULL.

Referenced by netvsc_close(), and netvsc_open().

                                                                        {
        struct io_buffer *iobuf;
        unsigned int i;

        /* Flush any outstanding buffers */
        for ( i = 0 ; i < ring->count ; i++ ) {
                iobuf = ring->iobufs[i];
                if ( ! iobuf )
                        continue;
                ring->iobufs[i] = NULL;
                ring->ids[ ( ring->id_cons++ ) & ( ring->count - 1 ) ] = i;
                if ( discard )
                        discard ( netvsc, iobuf, i );
        }

        /* Sanity check */
        assert ( netvsc_ring_is_empty ( ring ) );
}
static int netvsc_buffer_copy ( struct vmbus_xfer_pages pages,
void *  data,
size_t  offset,
size_t  len 
) [static]

Copy data from data buffer.

Parameters:
pagesTransfer page set
dataData buffer
offsetOffset within page set
lenLength within page set
Return values:
rcReturn status code

Definition at line 615 of file netvsc.c.

References buffer, container_of, copy_from_user(), and ERANGE.

                                                            {
        struct netvsc_buffer *buffer =
                container_of ( pages, struct netvsc_buffer, pages );

        /* Sanity check */
        if ( ( offset > buffer->len ) || ( len > ( buffer->len - offset ) ) )
                return -ERANGE;

        /* Copy data from buffer */
        copy_from_user ( data, buffer->data, offset, len );

        return 0;
}
static int netvsc_create_buffer ( struct netvsc_device *  netvsc,
struct netvsc_buffer *  buffer 
) [static]

Create data buffer.

Parameters:
netvscNetVSC device
bufferData buffer
Return values:
rcReturn status code

Definition at line 642 of file netvsc.c.

References arbelprm_rc_send_wqe::data, DBGC, ENOMEM, gpadl, vmbus_device::pages, rc, strerror(), ufree(), umalloc(), vmbus_establish_gpadl(), vmbus_gpadl_teardown(), vmbus_register_pages(), and vmbus_unregister_pages().

Referenced by netvsc_open().

                                                                 {
        struct vmbus_device *vmdev = netvsc->vmdev;
        int gpadl;
        int rc;

        /* Allocate receive buffer */
        buffer->data = umalloc ( buffer->len );
        if ( ! buffer->data ) {
                DBGC ( netvsc, "NETVSC %s could not allocate %zd-byte buffer\n",
                       netvsc->name, buffer->len );
                rc = -ENOMEM;
                goto err_alloc;
        }

        /* Establish GPA descriptor list */
        gpadl = vmbus_establish_gpadl ( vmdev, buffer->data, buffer->len );
        if ( gpadl < 0 ) {
                rc = gpadl;
                DBGC ( netvsc, "NETVSC %s could not establish GPADL: %s\n",
                       netvsc->name, strerror ( rc ) );
                goto err_establish_gpadl;
        }
        buffer->gpadl = gpadl;

        /* Register transfer page set */
        if ( ( rc = vmbus_register_pages ( vmdev, &buffer->pages ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not register transfer pages: "
                       "%s\n", netvsc->name, strerror ( rc ) );
                goto err_register_pages;
        }

        return 0;

        vmbus_unregister_pages ( vmdev, &buffer->pages );
 err_register_pages:
        vmbus_gpadl_teardown ( vmdev, gpadl );
 err_establish_gpadl:
        ufree ( buffer->data );
 err_alloc:
        return rc;
}
static void netvsc_destroy_buffer ( struct netvsc_device *  netvsc,
struct netvsc_buffer *  buffer 
) [static]

Destroy data buffer.

Parameters:
netvscNetVSC device
bufferData buffer

Definition at line 691 of file netvsc.c.

References DBGC, vmbus_device::gpadl, vmbus_device::pages, rc, strerror(), ufree(), and vmbus_unregister_pages().

Referenced by netvsc_close(), and netvsc_open().

                                                                   {
        struct vmbus_device *vmdev = netvsc->vmdev;
        int rc;

        /* Unregister transfer pages */
        vmbus_unregister_pages ( vmdev, &buffer->pages );

        /* Tear down GPA descriptor list */
        if ( ( rc = vmbus_gpadl_teardown ( vmdev, buffer->gpadl ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not tear down GPADL: %s\n",
                       netvsc->name, strerror ( rc ) );
                /* Death is imminent.  The host may well continue to
                 * write to the data buffer.  The best we can do is
                 * leak memory for now and hope that the host doesn't
                 * write to this region after we load an OS.
                 */
                return;
        }

        /* Free buffer */
        ufree ( buffer->data );
}
static int netvsc_open ( struct rndis_device rndis) [static]

Open device.

Parameters:
rndisRNDIS device
Return values:
rcReturn status code

Definition at line 721 of file netvsc.c.

References DBGC, netvsc_create_buffer(), netvsc_create_ring(), netvsc_destroy_buffer(), netvsc_destroy_ring(), netvsc_establish_buffer(), netvsc_initialise(), NETVSC_MTU, netvsc_ndis_version(), netvsc_revoke_buffer(), NULL, PAGE_SIZE, rndis_device::priv, rc, strerror(), vmbus_close(), and vmbus_open().

                                                      {
        struct netvsc_device *netvsc = rndis->priv;
        int rc;

        /* Initialise receive buffer */
        if ( ( rc = netvsc_create_buffer ( netvsc, &netvsc->rx ) ) != 0 )
                goto err_create_rx;

        /* Open channel */
        if ( ( rc = vmbus_open ( netvsc->vmdev, &netvsc_channel_operations,
                                 PAGE_SIZE, PAGE_SIZE, NETVSC_MTU ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not open VMBus: %s\n",
                       netvsc->name, strerror ( rc ) );
                goto err_vmbus_open;
        }

        /* Initialise communication with NetVSP */
        if ( ( rc = netvsc_initialise ( netvsc ) ) != 0 )
                goto err_initialise;
        if ( ( rc = netvsc_ndis_version ( netvsc ) ) != 0 )
                goto err_ndis_version;

        /* Initialise transmit ring */
        if ( ( rc = netvsc_create_ring ( netvsc, &netvsc->tx ) ) != 0 )
                goto err_create_tx;

        /* Establish receive buffer */
        if ( ( rc = netvsc_establish_buffer ( netvsc, &netvsc->rx ) ) != 0 )
                goto err_establish_rx;

        return 0;

        netvsc_revoke_buffer ( netvsc, &netvsc->rx );
 err_establish_rx:
        netvsc_destroy_ring ( netvsc, &netvsc->tx, NULL );
 err_create_tx:
 err_ndis_version:
 err_initialise:
        vmbus_close ( netvsc->vmdev );
 err_vmbus_open:
        netvsc_destroy_buffer ( netvsc, &netvsc->rx );
 err_create_rx:
        return rc;
}
static void netvsc_close ( struct rndis_device rndis) [static]

Close device.

Parameters:
rndisRNDIS device

Definition at line 771 of file netvsc.c.

References netvsc_cancel_transmit(), netvsc_destroy_buffer(), netvsc_destroy_ring(), netvsc_revoke_buffer(), rndis_device::priv, and vmbus_close().

                                                        {
        struct netvsc_device *netvsc = rndis->priv;

        /* Revoke receive buffer */
        netvsc_revoke_buffer ( netvsc, &netvsc->rx );

        /* Destroy transmit ring */
        netvsc_destroy_ring ( netvsc, &netvsc->tx, netvsc_cancel_transmit );

        /* Close channel */
        vmbus_close ( netvsc->vmdev );

        /* Destroy receive buffer */
        netvsc_destroy_buffer ( netvsc, &netvsc->rx );
}
static int netvsc_probe ( struct vmbus_device vmdev) [static]

Probe device.

Parameters:
vmdevVMBus device
Return values:
rcReturn status code

Definition at line 801 of file netvsc.c.

References alloc_rndis(), DBGC, net_device::dev, vmbus_device::dev, ENOMEM, free_rndis(), device::name, rndis_device::name, rndis_device::netdev, NETVSC_RX_BUF_LEN, NETVSC_RX_BUF_PAGESET, NETVSC_RX_ESTABLISH_MSG, NETVSC_RX_ESTABLISH_XRID, NETVSC_RX_REVOKE_MSG, NETVSC_RX_REVOKE_XRID, NETVSC_TX_NUM_DESC, rndis_device::priv, rc, register_rndis(), rndis_init(), strerror(), unregister_rndis(), and vmbus_set_drvdata().

                                                       {
        struct netvsc_device *netvsc;
        struct rndis_device *rndis;
        int rc;

        /* Allocate and initialise structure */
        rndis = alloc_rndis ( sizeof ( *netvsc ) );
        if ( ! rndis ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        rndis_init ( rndis, &netvsc_operations );
        rndis->netdev->dev = &vmdev->dev;
        netvsc = rndis->priv;
        netvsc->vmdev = vmdev;
        netvsc->rndis = rndis;
        netvsc->name = vmdev->dev.name;
        netvsc_init_ring ( &netvsc->tx, NETVSC_TX_NUM_DESC,
                           netvsc->tx_iobufs, netvsc->tx_ids );
        netvsc_init_buffer ( &netvsc->rx, NETVSC_RX_BUF_PAGESET,
                             &netvsc_xfer_pages_operations,
                             NETVSC_RX_ESTABLISH_MSG, NETVSC_RX_ESTABLISH_XRID,
                             NETVSC_RX_REVOKE_MSG, NETVSC_RX_REVOKE_XRID,
                             NETVSC_RX_BUF_LEN );
        vmbus_set_drvdata ( vmdev, rndis );

        /* Register RNDIS device */
        if ( ( rc = register_rndis ( rndis ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not register: %s\n",
                       netvsc->name, strerror ( rc ) );
                goto err_register;
        }

        return 0;

        unregister_rndis ( rndis );
 err_register:
        free_rndis ( rndis );
 err_alloc:
        return rc;
}
static int netvsc_reset ( struct vmbus_device vmdev) [static]

Reset device.

Parameters:
vmdevVMBus device
Return values:
rcReturn status code

Definition at line 849 of file netvsc.c.

References DBGC, netdev, rndis_device::netdev, netdev_close(), netdev_is_open(), netdev_open(), rndis_device::priv, rc, strerror(), and vmbus_get_drvdata().

                                                       {
        struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
        struct netvsc_device *netvsc = rndis->priv;
        struct net_device *netdev = rndis->netdev;
        int rc;

        /* A closed device holds no NetVSC (or RNDIS) state, so there
         * is nothing to reset.
         */
        if ( ! netdev_is_open ( netdev ) )
                return 0;

        /* Close and reopen device to reset any stale state */
        netdev_close ( netdev );
        if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
                DBGC ( netvsc, "NETVSC %s could not reopen: %s\n",
                       netvsc->name, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static void netvsc_remove ( struct vmbus_device vmdev) [static]

Remove device.

Parameters:
vmdevVMBus device

Definition at line 877 of file netvsc.c.

References free_rndis(), unregister_rndis(), and vmbus_get_drvdata().

                                                         {
        struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );

        /* Unregister RNDIS device */
        unregister_rndis ( rndis );

        /* Free RNDIS device */
        free_rndis ( rndis );
}

Variable Documentation

Initial value:
 {
        .recv_control = netvsc_recv_control,
        .recv_data = netvsc_recv_data,
        .recv_completion = netvsc_recv_completion,
        .recv_cancellation = netvsc_recv_cancellation,
}

VMBus channel operations.

Definition at line 445 of file netvsc.c.

Initial value:
 {
        .copy = netvsc_buffer_copy,
}

Transfer page set operations.

Definition at line 631 of file netvsc.c.

Initial value:
 {
        .open = netvsc_open,
        .close = netvsc_close,
        .transmit = netvsc_transmit,
        .poll = netvsc_poll,
}

RNDIS operations.

Definition at line 788 of file netvsc.c.

struct vmbus_driver netvsc_driver __vmbus_driver
Initial value:
 {
        .name = "netvsc",
        .type = VMBUS_TYPE ( 0xf8615163, 0xdf3e, 0x46c5, 0x913f,
                             0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e ),
        .probe = netvsc_probe,
        .reset = netvsc_reset,
        .remove = netvsc_remove,
}

NetVSC driver.

Definition at line 888 of file netvsc.c.