iPXE
Data Structures | Functions | Variables
pnic.c File Reference
#include <stdint.h>
#include <stdio.h>
#include <ipxe/io.h>
#include <errno.h>
#include <ipxe/pci.h>
#include <ipxe/if_ether.h>
#include <ipxe/ethernet.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include "pnic_api.h"

Go to the source code of this file.

Data Structures

struct  pnic

Functions

 FILE_LICENCE (GPL2_OR_LATER)
static uint16_t pnic_command_quiet (struct pnic *pnic, uint16_t command, const void *input, uint16_t input_length, void *output, uint16_t output_max_length, uint16_t *output_length)
static uint16_t pnic_command (struct pnic *pnic, uint16_t command, const void *input, uint16_t input_length, void *output, uint16_t output_max_length, uint16_t *output_length)
static int pnic_api_check (uint16_t api_version)
static void pnic_poll (struct net_device *netdev)
static int pnic_transmit (struct net_device *netdev, struct io_buffer *iobuf)
static int pnic_open (struct net_device *netdev __unused)
static void pnic_close (struct net_device *netdev __unused)
static void pnic_irq (struct net_device *netdev, int enable)
static void pnic_remove (struct pci_device *pci)
static int pnic_probe (struct pci_device *pci)

Variables

static struct net_device_operations pnic_operations
static struct pci_device_id pnic_nics []
struct pci_driver pnic_driver __pci_driver

Function Documentation

FILE_LICENCE ( GPL2_OR_LATER  )
static uint16_t pnic_command_quiet ( struct pnic pnic,
uint16_t  command,
const void *  input,
uint16_t  input_length,
void *  output,
uint16_t  output_max_length,
uint16_t output_length 
) [static]

Definition at line 55 of file pnic.c.

References insb(), inw(), pnic::ioaddr, NULL, outsb(), outw(), PNIC_REG_CMD, PNIC_REG_DATA, PNIC_REG_LEN, PNIC_REG_STAT, printf(), and status.

Referenced by pnic_command(), and pnic_probe().

                                                               {
        uint16_t status;
        uint16_t _output_length;

        if ( input != NULL ) {
                /* Write input length */
                outw ( input_length, pnic->ioaddr + PNIC_REG_LEN );
                /* Write input data */
                outsb ( pnic->ioaddr + PNIC_REG_DATA, input, input_length );
        }
        /* Write command */
        outw ( command, pnic->ioaddr + PNIC_REG_CMD );
        /* Retrieve status */
        status = inw ( pnic->ioaddr + PNIC_REG_STAT );
        /* Retrieve output length */
        _output_length = inw ( pnic->ioaddr + PNIC_REG_LEN );
        if ( output_length == NULL ) {
                if ( _output_length != output_max_length ) {
                        printf ( "pnic_command %#hx: wrong data length "
                                 "returned (expected %d, got %d)\n", command,
                                 output_max_length, _output_length );
                }
        } else {
                *output_length = _output_length;
        }
        if ( output != NULL ) {
                if ( _output_length > output_max_length ) {
                        printf ( "pnic_command %#hx: output buffer too small "
                                 "(have %d, need %d)\n", command,
                                 output_max_length, _output_length );
                        _output_length = output_max_length;
                }
                /* Retrieve output data */
                insb ( pnic->ioaddr + PNIC_REG_DATA, output, _output_length );
        }
        return status;
}
static uint16_t pnic_command ( struct pnic pnic,
uint16_t  command,
const void *  input,
uint16_t  input_length,
void *  output,
uint16_t  output_max_length,
uint16_t output_length 
) [static]

Definition at line 96 of file pnic.c.

References pnic_command_quiet(), PNIC_STATUS_OK, printf(), and status.

Referenced by pnic_irq(), pnic_poll(), pnic_probe(), pnic_remove(), and pnic_transmit().

                                                         {
        uint16_t status = pnic_command_quiet ( pnic, command,
                                               input, input_length,
                                               output, output_max_length,
                                               output_length );
        if ( status == PNIC_STATUS_OK ) return status;
        printf ( "PNIC command %#hx (len %#hx) failed with status %#hx\n",
                 command, input_length, status );
        return status;
}
static int pnic_api_check ( uint16_t  api_version) [static]

Definition at line 111 of file pnic.c.

References PNIC_API_VERSION, and printf().

Referenced by pnic_probe().

                                                   {
        if ( api_version != PNIC_API_VERSION ) {
                printf ( "Warning: API version mismatch! "
                         "(NIC's is %d.%d, ours is %d.%d)\n",
                         api_version >> 8, api_version & 0xff,
                         PNIC_API_VERSION >> 8, PNIC_API_VERSION & 0xff );
        }
        if ( api_version < PNIC_API_VERSION ) {
                printf ( "** You may need to update your copy of Bochs **\n" );
        }
        return ( api_version == PNIC_API_VERSION );
}
static void pnic_poll ( struct net_device netdev) [static]

Definition at line 127 of file pnic.c.

References alloc_iob(), io_buffer::data, DBG, EIO, ENOMEM, ETH_FRAME_LEN, iob_put, length, netdev_rx(), netdev_rx_err(), NULL, PNIC_CMD_RECV, PNIC_CMD_RECV_QLEN, pnic_command(), PNIC_STATUS_OK, and net_device::priv.

                                                    {
        struct pnic *pnic = netdev->priv;
        struct io_buffer *iobuf;
        uint16_t length;
        uint16_t qlen;

        /* Fetch all available packets */
        while ( 1 ) {
                if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
                                    &qlen, sizeof ( qlen ), NULL )
                     != PNIC_STATUS_OK )
                        return;
                if ( qlen == 0 )
                        return;
                iobuf = alloc_iob ( ETH_FRAME_LEN );
                if ( ! iobuf ) {
                        DBG ( "could not allocate buffer\n" );
                        netdev_rx_err ( netdev, NULL, -ENOMEM );
                        return;
                }
                if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0,
                                    iobuf->data, ETH_FRAME_LEN, &length )
                     != PNIC_STATUS_OK ) {
                        netdev_rx_err ( netdev, iobuf, -EIO );
                        return;
                }
                iob_put ( iobuf, length );
                netdev_rx ( netdev, iobuf );
        }
}
static int pnic_transmit ( struct net_device netdev,
struct io_buffer iobuf 
) [static]

Definition at line 161 of file pnic.c.

References io_buffer::data, ETH_ZLEN, iob_len(), iob_pad(), netdev_tx_complete(), NULL, PNIC_CMD_XMIT, pnic_command(), and net_device::priv.

                                                                                {
        struct pnic *pnic = netdev->priv;

        /* Pad the packet */
        iob_pad ( iobuf, ETH_ZLEN );

        /* Send packet */
        pnic_command ( pnic, PNIC_CMD_XMIT, iobuf->data, iob_len ( iobuf ),
                       NULL, 0, NULL );

        netdev_tx_complete ( netdev, iobuf );
        return 0;
}
static int pnic_open ( struct net_device *netdev  __unused) [static]

Definition at line 178 of file pnic.c.

                                                            {
        /* Nothing to do */
        return 0;
}
static void pnic_close ( struct net_device *netdev  __unused) [static]

Definition at line 186 of file pnic.c.

                                                              {
        /* Nothing to do */
}
static void pnic_irq ( struct net_device netdev,
int  enable 
) [static]

Definition at line 193 of file pnic.c.

References NULL, PNIC_CMD_MASK_IRQ, pnic_command(), and net_device::priv.

                                                               {
        struct pnic *pnic = netdev->priv;
        uint8_t mask = ( enable ? 1 : 0 );
        
        pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &mask, sizeof ( mask ),
                       NULL, 0, NULL );
}
static void pnic_remove ( struct pci_device pci) [static]

Definition at line 215 of file pnic.c.

References netdev, netdev_nullify(), netdev_put(), NULL, pci_get_drvdata(), PNIC_CMD_RESET, pnic_command(), net_device::priv, and unregister_netdev().

                                                   {
        struct net_device *netdev = pci_get_drvdata ( pci );
        struct pnic *pnic = netdev->priv;

        unregister_netdev ( netdev );
        pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
        netdev_nullify ( netdev );
        netdev_put ( netdev );
}
static int pnic_probe ( struct pci_device pci) [static]

Definition at line 228 of file pnic.c.

References adjust_pci_device(), alloc_etherdev(), pci_device::dev, net_device::dev, EIO, ENOMEM, ETH_ALEN, net_device::hw_addr, pnic::ioaddr, pci_device::ioaddr, netdev, netdev_init(), netdev_link_up(), netdev_nullify(), netdev_put(), NULL, pci_set_drvdata(), pnic_api_check(), PNIC_CMD_API_VER, PNIC_CMD_READ_MAC, pnic_command(), pnic_command_quiet(), PNIC_STATUS_OK, printf(), net_device::priv, rc, register_netdev(), and status.

                                                 {
        struct net_device *netdev;
        struct pnic *pnic;
        uint16_t api_version;
        uint16_t status;
        int rc;

        /* Allocate net device */
        netdev = alloc_etherdev ( sizeof ( *pnic ) );
        if ( ! netdev )
                return -ENOMEM;
        netdev_init ( netdev, &pnic_operations );
        pnic = netdev->priv;
        pci_set_drvdata ( pci, netdev );
        netdev->dev = &pci->dev;
        pnic->ioaddr = pci->ioaddr;

        /* Fix up PCI device */
        adjust_pci_device ( pci );
        
        /* API version check */
        status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0,
                                      &api_version,
                                      sizeof ( api_version ), NULL );
        if ( status != PNIC_STATUS_OK ) {
                printf ( "PNIC failed installation check, code %#hx\n",
                         status );
                rc = -EIO;
                goto err;
        }
        pnic_api_check ( api_version );

        /* Get MAC address */
        status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
                                netdev->hw_addr, ETH_ALEN, NULL );

        /* Register network device */
        if ( ( rc = register_netdev ( netdev ) ) != 0 )
                goto err;

        /* Mark as link up; PNIC has no concept of link state */
        netdev_link_up ( netdev );

        return 0;

 err:
        /* Free net device */
        netdev_nullify ( netdev );
        netdev_put ( netdev );
        return rc;
}

Variable Documentation

Initial value:
 {
        .open           = pnic_open,
        .close          = pnic_close,
        .transmit       = pnic_transmit,
        .poll           = pnic_poll,
        .irq            = pnic_irq,
}

Definition at line 204 of file pnic.c.

struct pci_device_id pnic_nics[] [static]
Initial value:
 {

PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ),
}

Definition at line 280 of file pnic.c.

struct pci_driver pnic_driver __pci_driver
Initial value:
 {
        .ids = pnic_nics,
        .id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
        .probe = pnic_probe,
        .remove = pnic_remove,
}

Definition at line 285 of file pnic.c.