iPXE
Defines | Functions | Variables
exanic.c File Reference

Exablaze ExaNIC driver. More...

#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <ipxe/iobuf.h>
#include <ipxe/malloc.h>
#include <ipxe/umalloc.h>
#include <ipxe/pci.h>
#include "exanic.h"

Go to the source code of this file.

Defines

#define EIO_ABORTED   __einfo_error ( EINFO_EIO_ABORTED )
#define EINFO_EIO_ABORTED   __einfo_uniqify ( EINFO_EIO, 0x01, "Frame aborted" )
#define EIO_CORRUPT   __einfo_error ( EINFO_EIO_CORRUPT )
#define EINFO_EIO_CORRUPT   __einfo_uniqify ( EINFO_EIO, 0x02, "CRC incorrect" )
#define EIO_HWOVFL   __einfo_error ( EINFO_EIO_HWOVFL )
#define EINFO_EIO_HWOVFL   __einfo_uniqify ( EINFO_EIO, 0x03, "Hardware overflow" )
#define EIO_STATUS(status)

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void exanic_write_base (physaddr_t addr, void *reg)
 Write DMA base address register.
static void exanic_clear_base (void *reg)
 Clear DMA base address register.
static void exanic_reset (struct exanic *exanic)
 Reset hardware.
static int exanic_i2c_read_bit (struct bit_basher *basher, unsigned int bit_id)
 Read I2C line status.
static void exanic_i2c_write_bit (struct bit_basher *basher, unsigned int bit_id, unsigned long data)
 Write I2C line status.
static int exanic_try_init_eeprom (struct exanic *exanic, struct exanic_i2c_config *i2cfg)
 Initialise EEPROM.
static int exanic_init_eeprom (struct exanic *exanic)
 Initialise EEPROM.
static int exanic_fetch_mac (struct exanic *exanic)
 Fetch base MAC address.
static void exanic_check_link (struct net_device *netdev)
 Check link state.
static void exanic_expired (struct retry_timer *timer, int over __unused)
 Check link state periodically.
static int exanic_open (struct net_device *netdev)
 Open network device.
static void exanic_close (struct net_device *netdev)
 Close network device.
static int exanic_transmit (struct net_device *netdev, struct io_buffer *iobuf)
 Transmit packet.
static void exanic_poll_tx (struct net_device *netdev)
 Poll for completed packets.
static void exanic_poll_rx (struct net_device *netdev)
 Poll for received packets.
static void exanic_poll (struct net_device *netdev)
 Poll for completed and received packets.
static int exanic_probe_port (struct exanic *exanic, struct device *dev, unsigned int index)
 Probe port.
static void exanic_remove_port (struct exanic *exanic, unsigned int index)
 Probe port.
static int exanic_probe (struct pci_device *pci)
 Probe PCI device.
static void exanic_remove (struct pci_device *pci)
 Remove PCI device.

Variables

static struct bit_basher_operations exanic_i2c_basher_ops
 I2C bit-bashing interface operations.
static struct exanic_i2c_config exanic_i2cfgs []
 Possible I2C bus configurations.
static struct net_device_operations exanic_operations
 ExaNIC network device operations.
static struct pci_device_id exanic_ids []
 ExaNIC PCI device IDs.
struct pci_driver exanic_driver __pci_driver
 ExaNIC PCI driver.

Detailed Description

Exablaze ExaNIC driver.

Definition in file exanic.c.


Define Documentation

Definition at line 48 of file exanic.c.

#define EINFO_EIO_ABORTED   __einfo_uniqify ( EINFO_EIO, 0x01, "Frame aborted" )

Definition at line 49 of file exanic.c.

Definition at line 51 of file exanic.c.

#define EINFO_EIO_CORRUPT   __einfo_uniqify ( EINFO_EIO, 0x02, "CRC incorrect" )

Definition at line 52 of file exanic.c.

Definition at line 54 of file exanic.c.

#define EINFO_EIO_HWOVFL   __einfo_uniqify ( EINFO_EIO, 0x03, "Hardware overflow" )

Definition at line 55 of file exanic.c.

#define EIO_STATUS (   status)
Value:

Definition at line 57 of file exanic.c.

Referenced by exanic_poll_rx().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void exanic_write_base ( physaddr_t  addr,
void *  reg 
) [static]

Write DMA base address register.

Parameters:
addrDMA base address
regRegister

Definition at line 67 of file exanic.c.

References addr, EXANIC_DMA_32_BIT, and writel().

Referenced by exanic_open(), and exanic_probe().

                                                             {
        uint32_t lo;
        uint32_t hi;

        /* Write high and low registers, setting flags as appropriate */
        lo = addr;
        if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) {
                /* 64-bit build; may be a 32-bit or 64-bit address */
                hi = ( ( ( uint64_t ) addr ) >> 32 );
                if ( ! hi )
                        lo |= EXANIC_DMA_32_BIT;
        } else {
                /* 32-bit build; always a 32-bit address */
                hi = 0;
                lo |= EXANIC_DMA_32_BIT;
        }
        writel ( hi, ( reg + 0 ) );
        writel ( lo, ( reg + 4 ) );
}
static void exanic_clear_base ( void *  reg) [inline, static]

Clear DMA base address register.

Parameters:
regRegister

Definition at line 92 of file exanic.c.

References writel().

Referenced by exanic_close(), and exanic_reset().

                                                   {

        /* Clear both high and low registers */
        writel ( 0, ( reg + 0 ) );
        writel ( 0, ( reg + 4 ) );
}
static void exanic_reset ( struct exanic exanic) [static]

Reset hardware.

Parameters:
exanicExaNIC device

Definition at line 111 of file exanic.c.

References exanic_clear_base(), EXANIC_MAX_PORTS, EXANIC_PORT_ENABLE, EXANIC_PORT_IRQ, EXANIC_PORT_REGS, EXANIC_PORT_RX_BASE, EXANIC_TXF_BASE, exanic::regs, and writel().

Referenced by exanic_probe(), and exanic_remove().

                                                   {
        void *port_regs;
        unsigned int i;

        /* Disable all possible ports */
        for ( i = 0 ; i < EXANIC_MAX_PORTS ; i++ ) {
                port_regs = ( exanic->regs + EXANIC_PORT_REGS ( i ) );
                writel ( 0, ( port_regs + EXANIC_PORT_ENABLE ) );
                writel ( 0, ( port_regs + EXANIC_PORT_IRQ ) );
                exanic_clear_base ( port_regs + EXANIC_PORT_RX_BASE );
        }

        /* Disable transmit feedback */
        exanic_clear_base ( exanic->regs + EXANIC_TXF_BASE );
}
static int exanic_i2c_read_bit ( struct bit_basher basher,
unsigned int  bit_id 
) [static]

Read I2C line status.

Parameters:
basherBit-bashing interface
bit_idBit number
Return values:
zeroInput is a logic 0
non-zeroInput is a logic 1

Definition at line 142 of file exanic.c.

References assert, container_of, DBG_DISABLE, DBG_ENABLE, DBGLVL_IO, EXANIC_I2C, exanic_i2c_config::getsda, I2C_BIT_SDA, exanic::i2cfg, readl(), and exanic::regs.

                                                       {
        struct exanic *exanic =
                container_of ( basher, struct exanic, basher.basher );
        unsigned int shift;
        uint32_t i2c;

        /* Identify bit */
        assert ( bit_id == I2C_BIT_SDA );
        shift = exanic->i2cfg.getsda;

        /* Read I2C register */
        DBG_DISABLE ( DBGLVL_IO );
        i2c = readl ( exanic->regs + EXANIC_I2C );
        DBG_ENABLE ( DBGLVL_IO );
        return ( ( i2c >> shift ) & 1 );
}
static void exanic_i2c_write_bit ( struct bit_basher basher,
unsigned int  bit_id,
unsigned long  data 
) [static]

Write I2C line status.

Parameters:
basherBit-bashing interface
bit_idBit number
dataValue to write

Definition at line 167 of file exanic.c.

References assert, container_of, DBG_DISABLE, DBG_ENABLE, DBGLVL_IO, EXANIC_I2C, I2C_BIT_SCL, I2C_BIT_SDA, exanic::i2cfg, readl(), exanic::regs, exanic_i2c_config::setscl, exanic_i2c_config::setsda, and writel().

                                                                             {
        struct exanic *exanic =
                container_of ( basher, struct exanic, basher.basher );
        unsigned int shift;
        uint32_t mask;
        uint32_t i2c;

        /* Identify shift */
        assert ( ( bit_id == I2C_BIT_SCL ) || ( bit_id == I2C_BIT_SDA ) );
        shift = ( ( bit_id == I2C_BIT_SCL ) ?
                  exanic->i2cfg.setscl : exanic->i2cfg.setsda );
        mask = ( 1UL << shift );

        /* Modify I2C register */
        DBG_DISABLE ( DBGLVL_IO );
        i2c = readl ( exanic->regs + EXANIC_I2C );
        i2c &= ~mask;
        if ( ! data )
                i2c |= mask;
        writel ( i2c, ( exanic->regs + EXANIC_I2C ) );
        DBG_ENABLE ( DBGLVL_IO );
}
static int exanic_try_init_eeprom ( struct exanic exanic,
struct exanic_i2c_config i2cfg 
) [static]

Initialise EEPROM.

Parameters:
exanicExaNIC device
i2cfgI2C bus configuration
Return values:
rcReturn status code

Definition at line 212 of file exanic.c.

References exanic::basher, DBGC, DBGC2, exanic::eeprom, EXANIC_EEPROM_ADDRESS, exanic_i2c_config::getsda, i2c_bit_basher::i2c, i2c_check_presence(), exanic::i2cfg, init_i2c_bit_basher(), init_i2c_eeprom(), memcpy(), rc, exanic_i2c_config::setscl, and exanic_i2c_config::setsda.

Referenced by exanic_init_eeprom().

                                                                      {
        int rc;

        /* Configure I2C bus */
        memcpy ( &exanic->i2cfg, i2cfg, sizeof ( exanic->i2cfg ) );

        /* Initialise I2C bus */
        if ( ( rc = init_i2c_bit_basher ( &exanic->basher,
                                          &exanic_i2c_basher_ops ) ) != 0 ) {
                DBGC2 ( exanic, "EXANIC %p found no I2C bus via %d/%d/%d\n",
                        exanic, exanic->i2cfg.setscl,
                        exanic->i2cfg.setsda, exanic->i2cfg.getsda );
                return rc;
        }

        /* Check for EEPROM presence */
        init_i2c_eeprom ( &exanic->eeprom, EXANIC_EEPROM_ADDRESS );
        if ( ( rc = i2c_check_presence ( &exanic->basher.i2c,
                                         &exanic->eeprom ) ) != 0 ) {
                DBGC2 ( exanic, "EXANIC %p found no EEPROM via %d/%d/%d\n",
                        exanic, exanic->i2cfg.setscl,
                        exanic->i2cfg.setsda, exanic->i2cfg.getsda );
                return rc;
        }

        DBGC ( exanic, "EXANIC %p found EEPROM via %d/%d/%d\n",
               exanic, exanic->i2cfg.setscl,
               exanic->i2cfg.setsda, exanic->i2cfg.getsda );
        return 0;
}
static int exanic_init_eeprom ( struct exanic exanic) [static]

Initialise EEPROM.

Parameters:
exanicExaNIC device
Return values:
rcReturn status code

Definition at line 250 of file exanic.c.

References DBGC, ENODEV, exanic_i2cfgs, exanic_try_init_eeprom(), and rc.

Referenced by exanic_fetch_mac().

                                                        {
        struct exanic_i2c_config *i2cfg;
        unsigned int i;
        int rc;

        /* Try all possible bus configurations */
        for ( i = 0 ; i < ( sizeof ( exanic_i2cfgs ) /
                            sizeof ( exanic_i2cfgs[0] ) ) ; i++ ) {
                i2cfg = &exanic_i2cfgs[i];
                if ( ( rc = exanic_try_init_eeprom ( exanic, i2cfg ) ) == 0 )
                        return 0;
        }

        DBGC ( exanic, "EXANIC %p found no EEPROM\n", exanic );
        return -ENODEV;
}
static int exanic_fetch_mac ( struct exanic exanic) [static]

Fetch base MAC address.

Parameters:
exanicExaNIC device
Return values:
rcReturn status code

Definition at line 273 of file exanic.c.

References exanic::basher, DBGC, exanic::eeprom, exanic_init_eeprom(), i2c_bit_basher::i2c, exanic::mac, rc, i2c_interface::read, and strerror().

Referenced by exanic_probe().

                                                      {
        struct i2c_interface *i2c = &exanic->basher.i2c;
        int rc;

        /* Initialise EEPROM */
        if ( ( rc = exanic_init_eeprom ( exanic ) ) != 0 )
                return rc;

        /* Fetch base MAC address */
        if ( ( rc = i2c->read ( i2c, &exanic->eeprom, 0, exanic->mac,
                                sizeof ( exanic->mac ) ) ) != 0 ) {
                DBGC ( exanic, "EXANIC %p could not read MAC address: %s\n",
                       exanic, strerror ( rc ) );
                return rc;
        }

        return 0;
}
static void exanic_check_link ( struct net_device netdev) [static]

Check link state.

Parameters:
netdevNetwork device

Definition at line 304 of file exanic.c.

References DBGC, EXANIC_PORT_SPEED, EXANIC_PORT_STATUS, EXANIC_PORT_STATUS_LINK, net_device::name, netdev_link_down(), netdev_link_up(), port, net_device::priv, readl(), exanic_port::regs, speed, status, and exanic_port::status.

Referenced by exanic_expired(), and exanic_probe_port().

                                                            {
        struct exanic_port *port = netdev->priv;
        uint32_t status;
        uint32_t speed;

        /* Report port status changes */
        status = readl ( port->regs + EXANIC_PORT_STATUS );
        speed = readl ( port->regs + EXANIC_PORT_SPEED );
        if ( status != port->status ) {
                DBGC ( port, "EXANIC %s port status %#08x speed %dMbps\n",
                       netdev->name, status, speed );
                if ( status & EXANIC_PORT_STATUS_LINK ) {
                        netdev_link_up ( netdev );
                } else {
                        netdev_link_down ( netdev );
                }
                port->status = status;
        }
}
static void exanic_expired ( struct retry_timer timer,
int over  __unused 
) [static]

Check link state periodically.

Parameters:
retryLink state check timer
overFailure indicator

Definition at line 330 of file exanic.c.

References assert, container_of, DBGC, EXANIC_CAPS_SPEED_MASK, exanic_check_link(), EXANIC_LINK_INTERVAL, EXANIC_PORT_SPEED, ffs, index, net_device::name, netdev, exanic_port::netdev, netdev_link_ok(), port, exanic_port::regs, exanic_port::speed, exanic_port::speeds, start_timer_fixed(), and writel().

Referenced by exanic_probe_port().

                                                                            {
        struct exanic_port *port =
                container_of ( timer, struct exanic_port, timer );
        struct net_device *netdev = port->netdev;
        static const uint32_t speeds[] = {
                100, 1000, 10000, 40000, 100000,
        };
        unsigned int index;

        /* Restart timer */
        start_timer_fixed ( timer, EXANIC_LINK_INTERVAL );

        /* Check link state */
        exanic_check_link ( netdev );

        /* Do nothing further if link is already up */
        if ( netdev_link_ok ( netdev ) )
                return;

        /* Do nothing further unless we have a valid list of supported speeds */
        if ( ! port->speeds )
                return;

        /* Autonegotiation is not supported; try manually selecting
         * the next supported link speed.
         */
        do {
                if ( ! port->speed )
                        port->speed = ( 8 * sizeof ( port->speeds ) );
                port->speed--;
        } while ( ! ( ( 1UL << port->speed ) & port->speeds ) );
        index = ( port->speed - ( ffs ( EXANIC_CAPS_SPEED_MASK ) - 1 ) );
        assert ( index < ( sizeof ( speeds ) / sizeof ( speeds[0] ) ) );

        /* Attempt the selected speed */
        DBGC ( netdev, "EXANIC %s attempting %dMbps\n",
               netdev->name, speeds[index] );
        writel ( speeds[index], ( port->regs + EXANIC_PORT_SPEED ) );
}
static int exanic_open ( struct net_device netdev) [static]

Open network device.

Parameters:
netdevNetwork device
Return values:
rcReturn status code

Definition at line 383 of file exanic.c.

References exanic_port::default_speed, exanic_tx_chunk::desc, EXANIC_LINK_INTERVAL, EXANIC_PORT_ENABLE, EXANIC_PORT_ENABLE_ENABLED, EXANIC_PORT_FLAGS, EXANIC_PORT_FLAGS_PROMISC, EXANIC_PORT_RX_BASE, EXANIC_PORT_SPEED, EXANIC_RX_LEN, EXANIC_TYPE_RAW, exanic_write_base(), exanic_tx_descriptor::flags, memset_user(), exanic_tx_chunk::pad, phys_to_bus(), port, net_device::priv, exanic_port::regs, exanic_port::rx, exanic_port::rx_cons, exanic_port::speed, start_timer_fixed(), exanic_port::status, exanic_port::timer, tx, exanic_port::tx, exanic_port::tx_cons, exanic_port::tx_count, exanic_port::tx_prod, exanic_port::txf, exanic_tx_descriptor::txf_slot, exanic_port::txf_slot, exanic_tx_descriptor::type, user_to_phys(), wmb, writeb(), writel(), and writew().

                                                     {
        struct exanic_port *port = netdev->priv;
        struct exanic_tx_chunk *tx;
        unsigned int i;

        /* Reset transmit region contents */
        for ( i = 0 ; i < port->tx_count ; i++ ) {
                tx = ( port->tx + ( i * sizeof ( *tx ) ) );
                writew ( port->txf_slot, &tx->desc.txf_slot );
                writeb ( EXANIC_TYPE_RAW, &tx->desc.type );
                writeb ( 0, &tx->desc.flags );
                writew ( 0, &tx->pad );
        }

        /* Reset receive region contents */
        memset_user ( port->rx, 0, 0xff, EXANIC_RX_LEN );

        /* Reset transmit feedback region */
        *(port->txf) = 0;

        /* Reset counters */
        port->tx_prod = 0;
        port->tx_cons = 0;
        port->rx_cons = 0;

        /* Map receive region */
        exanic_write_base ( phys_to_bus ( user_to_phys ( port->rx, 0 ) ),
                            ( port->regs + EXANIC_PORT_RX_BASE ) );

        /* Enable promiscuous mode */
        writel ( EXANIC_PORT_FLAGS_PROMISC,
                 ( port->regs + EXANIC_PORT_FLAGS ) );

        /* Reset to default speed and clear cached status */
        writel ( port->default_speed, ( port->regs + EXANIC_PORT_SPEED ) );
        port->speed = 0;
        port->status = 0;

        /* Enable port */
        wmb();
        writel ( EXANIC_PORT_ENABLE_ENABLED,
                 ( port->regs + EXANIC_PORT_ENABLE ) );

        /* Start link state timer */
        start_timer_fixed ( &port->timer, EXANIC_LINK_INTERVAL );

        return 0;
}
static void exanic_close ( struct net_device netdev) [static]

Close network device.

Parameters:
netdevNetwork device

Definition at line 437 of file exanic.c.

References ECANCELED, exanic_clear_base(), EXANIC_PORT_ENABLE, EXANIC_PORT_RX_BASE, netdev_rx_err(), NULL, port, net_device::priv, exanic_port::regs, exanic_port::rx_iobuf, stop_timer(), exanic_port::timer, wmb, and writel().

                                                       {
        struct exanic_port *port = netdev->priv;

        /* Stop link state timer */
        stop_timer ( &port->timer );

        /* Disable port */
        writel ( 0, ( port->regs + EXANIC_PORT_ENABLE ) );
        wmb();

        /* Clear receive region */
        exanic_clear_base ( port->regs + EXANIC_PORT_RX_BASE );

        /* Discard any in-progress receive */
        if ( port->rx_iobuf ) {
                netdev_rx_err ( netdev, port->rx_iobuf, -ECANCELED );
                port->rx_iobuf = NULL;
        }
}
static int exanic_transmit ( struct net_device netdev,
struct io_buffer iobuf 
) [static]

Transmit packet.

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

Definition at line 464 of file exanic.c.

References io_buffer::data, exanic_tx_chunk::data, data, DBGC, DBGC2, exanic_tx_chunk::desc, ENOBUFS, ENOTSUP, EXANIC_PORT_TX_COMMAND, iob_len(), exanic_tx_descriptor::len, len, net_device::name, offset, offsetof, exanic_tx_chunk::pad, port, net_device::priv, exanic_port::regs, src, tx, exanic_port::tx, exanic_port::tx_cons, exanic_port::tx_count, exanic_port::tx_offset, exanic_port::tx_prod, exanic_tx_descriptor::txf_id, wmb, writeb(), writel(), and writew().

                                                       {
        struct exanic_port *port = netdev->priv;
        struct exanic_tx_chunk *tx;
        unsigned int tx_fill;
        unsigned int tx_index;
        size_t offset;
        size_t len;
        uint8_t *src;
        uint8_t *dst;

        /* Sanity check */
        len = iob_len ( iobuf );
        if ( len > sizeof ( tx->data ) ) {
                DBGC ( port, "EXANIC %s transmit too large\n", netdev->name );
                return -ENOTSUP;
        }

        /* Get next transmit descriptor */
        tx_fill = ( port->tx_prod - port->tx_cons );
        if ( tx_fill >= port->tx_count ) {
                DBGC ( port, "EXANIC %s out of transmit descriptors\n",
                       netdev->name );
                return -ENOBUFS;
        }
        tx_index = ( port->tx_prod & ( port->tx_count - 1 ) );
        offset = ( tx_index * sizeof ( *tx ) );
        tx = ( port->tx + offset );
        DBGC2 ( port, "EXANIC %s TX %04x at [%05zx,%05zx)\n",
                netdev->name, port->tx_prod, ( port->tx_offset + offset ),
                ( port->tx_offset + offset +
                  offsetof ( typeof ( *tx ), data ) + len ) );
        port->tx_prod++;

        /* Populate transmit descriptor */
        writew ( port->tx_prod, &tx->desc.txf_id );
        writew ( ( sizeof ( tx->pad ) + len ), &tx->desc.len );

        /* Copy data to transmit region.  There is no DMA on the
         * transmit data path.
         */
        src = iobuf->data;
        dst = tx->data;
        while ( len-- )
                writeb ( *(src++), dst++ );

        /* Send transmit command */
        wmb();
        writel ( ( port->tx_offset + offset ),
                 ( port->regs + EXANIC_PORT_TX_COMMAND ) );

        return 0;
}
static void exanic_poll_tx ( struct net_device netdev) [static]

Poll for completed packets.

Parameters:
netdevNetwork device

Definition at line 523 of file exanic.c.

References DBGC2, net_device::name, netdev_tx_complete_next(), port, net_device::priv, exanic_port::tx_cons, and exanic_port::txf.

Referenced by exanic_poll().

                                                         {
        struct exanic_port *port = netdev->priv;

        /* Report any completed packets */
        while ( port->tx_cons != *(port->txf) ) {
                DBGC2 ( port, "EXANIC %s TX %04x complete\n",
                        netdev->name, port->tx_cons );
                netdev_tx_complete_next ( netdev );
                port->tx_cons++;
        }
}
static void exanic_poll_rx ( struct net_device netdev) [static]

Poll for received packets.

Parameters:
netdevNetwork device

Definition at line 540 of file exanic.c.

References alloc_iob(), copy_from_user(), exanic_rx_chunk::data, data, DBGC, DBGC2, EIO_STATUS, ENOBUFS, ERANGE, EXANIC_MAX_RX_LEN, EXANIC_RX_LEN, EXANIC_STATUS_ERROR_MASK, exanic_rx_descriptor::generation, iob_put, iob_tailroom(), iob_unput, exanic_rx_descriptor::len, len, net_device::name, netdev_rx(), netdev_rx_err(), NULL, offset, offsetof, port, net_device::priv, rmb, rx, exanic_port::rx, exanic_port::rx_cons, exanic_port::rx_iobuf, exanic_port::rx_rc, exanic_rx_descriptor::status, and strerror().

Referenced by exanic_poll().

                                                         {
        struct exanic_port *port = netdev->priv;
        struct exanic_rx_chunk *rx;
        struct exanic_rx_descriptor desc;
        uint8_t current;
        uint8_t previous;
        size_t offset;
        size_t len;

        for ( ; ; port->rx_cons++ ) {

                /* Fetch descriptor */
                offset = ( ( port->rx_cons * sizeof ( *rx ) ) % EXANIC_RX_LEN );
                copy_from_user ( &desc, port->rx,
                                 ( offset + offsetof ( typeof ( *rx ), desc ) ),
                                 sizeof ( desc ) );

                /* Calculate generation */
                current = ( port->rx_cons / ( EXANIC_RX_LEN / sizeof ( *rx ) ));
                previous = ( current - 1 );

                /* Do nothing if no chunk is ready */
                if ( desc.generation == previous )
                        break;

                /* Allocate I/O buffer if needed */
                if ( ! port->rx_iobuf ) {
                        port->rx_iobuf = alloc_iob ( EXANIC_MAX_RX_LEN );
                        if ( ! port->rx_iobuf ) {
                                /* Wait for next poll */
                                break;
                        }
                        port->rx_rc = 0;
                }

                /* Calculate chunk length */
                len = ( desc.len ? desc.len : sizeof ( rx->data ) );

                /* Append data to I/O buffer */
                if ( len <= iob_tailroom ( port->rx_iobuf ) ) {
                        copy_from_user ( iob_put ( port->rx_iobuf, len ),
                                         port->rx,
                                         ( offset + offsetof ( typeof ( *rx ),
                                                               data ) ), len );
                } else {
                        DBGC ( port, "EXANIC %s RX too large\n",
                               netdev->name );
                        port->rx_rc = -ERANGE;
                }

                /* Check for overrun */
                rmb();
                copy_from_user ( &desc.generation, port->rx,
                                 ( offset + offsetof ( typeof ( *rx ),
                                                       desc.generation ) ),
                                 sizeof ( desc.generation ) );
                if ( desc.generation != current ) {
                        DBGC ( port, "EXANIC %s RX overrun\n", netdev->name );
                        port->rx_rc = -ENOBUFS;
                        continue;
                }

                /* Wait for end of packet */
                if ( ! desc.len )
                        continue;

                /* Check for receive errors */
                if ( desc.status & EXANIC_STATUS_ERROR_MASK ) {
                        port->rx_rc = -EIO_STATUS ( desc.status );
                        DBGC ( port, "EXANIC %s RX %04x error: %s\n",
                               netdev->name, port->rx_cons,
                               strerror ( port->rx_rc ) );
                } else {
                        DBGC2 ( port, "EXANIC %s RX %04x\n",
                                netdev->name, port->rx_cons );
                }

                /* Hand off to network stack */
                if ( port->rx_rc ) {
                        netdev_rx_err ( netdev, port->rx_iobuf, port->rx_rc );
                } else {
                        iob_unput ( port->rx_iobuf, 4 /* strip CRC */ );
                        netdev_rx ( netdev, port->rx_iobuf );
                }
                port->rx_iobuf = NULL;
        }
}
static void exanic_poll ( struct net_device netdev) [static]

Poll for completed and received packets.

Parameters:
netdevNetwork device

Definition at line 633 of file exanic.c.

References exanic_poll_rx(), and exanic_poll_tx().

                                                      {

        /* Poll for completed packets */
        exanic_poll_tx ( netdev );

        /* Poll for received packets */
        exanic_poll_rx ( netdev );
}
static int exanic_probe_port ( struct exanic exanic,
struct device dev,
unsigned int  index 
) [static]

Probe port.

Parameters:
exanicExaNIC device
devParent device
indexPort number
Return values:
rcReturn status code

Definition at line 665 of file exanic.c.

References alloc_etherdev(), assert, exanic::caps, DBGC, exanic_port::default_speed, net_device::dev, ENOMEM, ETH_ALEN, EXANIC_CAPS_SPEED_MASK, exanic_check_link(), exanic_expired(), EXANIC_MAX_TX_LEN, EXANIC_PORT_REGS, EXANIC_PORT_SPEED, EXANIC_PORT_STATUS, EXANIC_PORT_STATUS_ABSENT, EXANIC_PORT_TX_LEN, EXANIC_PORT_TX_OFFSET, EXANIC_RX_LEN, EXANIC_TXF_SLOT, net_device::hw_addr, index, exanic::mac, memcpy(), memset(), net_device::name, netdev, exanic_port::netdev, netdev_init(), netdev_nullify(), netdev_put(), exanic::port, port, net_device::priv, rc, readl(), net_device::refcnt, register_netdev(), exanic_port::regs, exanic::regs, exanic_port::rx, exanic_port::speeds, status, exanic_port::timer, exanic_port::tx, exanic::tx, exanic_port::tx_count, exanic_port::tx_offset, exanic_port::txf, exanic::txf, exanic_port::txf_slot, ufree(), umalloc(), unregister_netdev(), and user_to_phys().

Referenced by exanic_probe().

                                                    {
        struct net_device *netdev;
        struct exanic_port *port;
        void *port_regs;
        uint32_t status;
        size_t tx_len;
        int rc;

        /* Do nothing if port is not physically present */
        port_regs = ( exanic->regs + EXANIC_PORT_REGS ( index ) );
        status = readl ( port_regs + EXANIC_PORT_STATUS );
        tx_len = readl ( port_regs + EXANIC_PORT_TX_LEN );
        if ( ( status & EXANIC_PORT_STATUS_ABSENT ) || ( tx_len == 0 ) ) {
                rc = 0;
                goto absent;
        }

        /* Allocate network device */
        netdev = alloc_etherdev ( sizeof ( *port ) );
        if ( ! netdev ) {
                rc = -ENOMEM;
                goto err_alloc_netdev;
        }
        netdev_init ( netdev, &exanic_operations );
        netdev->dev = dev;
        port = netdev->priv;
        memset ( port, 0, sizeof ( *port ) );
        exanic->port[index] = port;
        port->netdev = netdev;
        port->regs = port_regs;
        timer_init ( &port->timer, exanic_expired, &netdev->refcnt );

        /* Identify transmit region */
        port->tx_offset = readl ( port->regs + EXANIC_PORT_TX_OFFSET );
        if ( tx_len > EXANIC_MAX_TX_LEN )
                tx_len = EXANIC_MAX_TX_LEN;
        assert ( ! ( tx_len & ( tx_len - 1 ) ) );
        port->tx = ( exanic->tx + port->tx_offset );
        port->tx_count = ( tx_len / sizeof ( struct exanic_tx_chunk ) );

        /* Identify transmit feedback region */
        port->txf_slot = EXANIC_TXF_SLOT ( index );
        port->txf = ( exanic->txf +
                      ( port->txf_slot * sizeof ( *(port->txf) ) ) );

        /* Allocate receive region (via umalloc()) */
        port->rx = umalloc ( EXANIC_RX_LEN );
        if ( ! port->rx ) {
                rc = -ENOMEM;
                goto err_alloc_rx;
        }

        /* Set MAC address */
        memcpy ( netdev->hw_addr, exanic->mac, ETH_ALEN );
        netdev->hw_addr[ ETH_ALEN - 1 ] += index;

        /* Record default link speed and supported speeds */
        port->default_speed = readl ( port->regs + EXANIC_PORT_SPEED );
        port->speeds = ( exanic->caps & EXANIC_CAPS_SPEED_MASK );

        /* Register network device */
        if ( ( rc = register_netdev ( netdev ) ) != 0 )
                goto err_register_netdev;
        DBGC ( port, "EXANIC %s port %d TX [%#05zx,%#05zx) TXF %#02x RX "
               "[%#lx,%#lx)\n", netdev->name, index, port->tx_offset,
               ( port->tx_offset + tx_len ), port->txf_slot,
               user_to_phys ( port->rx, 0 ),
               user_to_phys ( port->rx, EXANIC_RX_LEN ) );

        /* Set initial link state */
        exanic_check_link ( netdev );

        return 0;

        unregister_netdev ( netdev );
 err_register_netdev:
        ufree ( port->rx );
 err_alloc_rx:
        netdev_nullify ( netdev );
        netdev_put ( netdev );
 err_alloc_netdev:
 absent:
        return rc;
}
static void exanic_remove_port ( struct exanic exanic,
unsigned int  index 
) [static]

Probe port.

Parameters:
exanicExaNIC device
indexPort number

Definition at line 757 of file exanic.c.

References index, exanic_port::netdev, netdev_nullify(), netdev_put(), exanic::port, port, exanic_port::rx, ufree(), and unregister_netdev().

Referenced by exanic_probe(), and exanic_remove().

                                                                             {
        struct exanic_port *port;

        /* Do nothing if port is not physically present */
        port = exanic->port[index];
        if ( ! port )
                return;

        /* Unregister network device */
        unregister_netdev ( port->netdev );

        /* Free receive region */
        ufree ( port->rx );

        /* Free network device */
        netdev_nullify ( port->netdev );
        netdev_put ( port->netdev );
}
static int exanic_probe ( struct pci_device pci) [static]

Probe PCI device.

Parameters:
pciPCI device
Return values:
rcReturn status code

Definition at line 782 of file exanic.c.

References adjust_pci_device(), exanic::caps, DBGC, pci_device::dev, ENODEV, ENOMEM, eth_ntoa(), EXANIC_ALIGN, EXANIC_CAPS, exanic_fetch_mac(), EXANIC_MAX_PORTS, EXANIC_POWER, EXANIC_POWER_ON, exanic_probe_port(), EXANIC_REGS_BAR, EXANIC_REGS_LEN, exanic_remove_port(), exanic_reset(), EXANIC_TX_BAR, EXANIC_TXF_BASE, EXANIC_TXF_LEN, exanic_write_base(), free, free_dma(), ioremap(), iounmap(), exanic::mac, malloc_dma(), memset(), pci_bar_size(), pci_bar_start(), pci_set_drvdata(), rc, readl(), exanic::regs, exanic::tx, exanic::txf, virt_to_bus(), writel(), and zalloc().

                                                   {
        struct exanic *exanic;
        unsigned long regs_bar_start;
        unsigned long tx_bar_start;
        size_t tx_bar_len;
        int i;
        int rc;

        /* Allocate and initialise structure */
        exanic = zalloc ( sizeof ( *exanic ) );
        if ( ! exanic ) {
                rc = -ENOMEM;
                goto err_alloc;
        }
        pci_set_drvdata ( pci, exanic );

        /* Fix up PCI device */
        adjust_pci_device ( pci );

        /* Map registers */
        regs_bar_start = pci_bar_start ( pci, EXANIC_REGS_BAR );
        exanic->regs = ioremap ( regs_bar_start, EXANIC_REGS_LEN );
        if ( ! exanic->regs ) {
                rc = -ENODEV;
                goto err_ioremap_regs;
        }

        /* Reset device */
        exanic_reset ( exanic );

        /* Read capabilities */
        exanic->caps = readl ( exanic->regs + EXANIC_CAPS );

        /* Power up PHYs */
        writel ( EXANIC_POWER_ON, ( exanic->regs + EXANIC_POWER ) );

        /* Fetch base MAC address */
        if ( ( rc = exanic_fetch_mac ( exanic ) ) != 0 )
                goto err_fetch_mac;
        DBGC ( exanic, "EXANIC %p capabilities %#08x base MAC %s\n",
               exanic, exanic->caps, eth_ntoa ( exanic->mac ) );

        /* Map transmit region */
        tx_bar_start = pci_bar_start ( pci, EXANIC_TX_BAR );
        tx_bar_len = pci_bar_size ( pci, EXANIC_TX_BAR );
        exanic->tx = ioremap ( tx_bar_start, tx_bar_len );
        if ( ! exanic->tx ) {
                rc = -ENODEV;
                goto err_ioremap_tx;
        }

        /* Allocate transmit feedback region (shared between all ports) */
        exanic->txf = malloc_dma ( EXANIC_TXF_LEN, EXANIC_ALIGN );
        if ( ! exanic->txf ) {
                rc = -ENOMEM;
                goto err_alloc_txf;
        }
        memset ( exanic->txf, 0, EXANIC_TXF_LEN );
        exanic_write_base ( virt_to_bus ( exanic->txf ),
                            ( exanic->regs + EXANIC_TXF_BASE ) );

        /* Allocate and initialise per-port network devices */
        for ( i = 0 ; i < EXANIC_MAX_PORTS ; i++ ) {
                if ( ( rc = exanic_probe_port ( exanic, &pci->dev, i ) ) != 0 )
                        goto err_probe_port;
        }

        return 0;

        i = EXANIC_MAX_PORTS;
 err_probe_port:
        for ( i-- ; i >= 0 ; i-- )
                exanic_remove_port ( exanic, i );
        exanic_reset ( exanic );
        free_dma ( exanic->txf, EXANIC_TXF_LEN );
 err_alloc_txf:
        iounmap ( exanic->tx );
 err_ioremap_tx:
        iounmap ( exanic->regs );
 err_fetch_mac:
 err_ioremap_regs:
        free ( exanic );
 err_alloc:
        return rc;
}
static void exanic_remove ( struct pci_device pci) [static]

Remove PCI device.

Parameters:
pciPCI device

Definition at line 873 of file exanic.c.

References EXANIC_MAX_PORTS, exanic_remove_port(), exanic_reset(), EXANIC_TXF_LEN, free, free_dma(), iounmap(), pci_get_drvdata(), exanic::regs, exanic::tx, and exanic::txf.

                                                     {
        struct exanic *exanic = pci_get_drvdata ( pci );
        unsigned int i;

        /* Remove all ports */
        for ( i = 0 ; i < EXANIC_MAX_PORTS ; i++ )
                exanic_remove_port ( exanic, i );

        /* Reset device */
        exanic_reset ( exanic );

        /* Free transmit feedback region */
        free_dma ( exanic->txf, EXANIC_TXF_LEN );

        /* Unmap transmit region */
        iounmap ( exanic->tx );

        /* Unmap registers */
        iounmap ( exanic->regs );

        /* Free device */
        free ( exanic );
}

Variable Documentation

Initial value:
 {
        .read = exanic_i2c_read_bit,
        .write = exanic_i2c_write_bit,
}

I2C bit-bashing interface operations.

Definition at line 192 of file exanic.c.

struct exanic_i2c_config exanic_i2cfgs[] [static]
Initial value:
 {
        
        { .setscl = 7, .setsda = 4, .getsda = 12 },
        
        { .setscl = 7, .setsda = 5, .getsda = 13 },
}

Possible I2C bus configurations.

Definition at line 198 of file exanic.c.

Referenced by exanic_init_eeprom().

Initial value:
 {
        .open           = exanic_open,
        .close          = exanic_close,
        .transmit       = exanic_transmit,
        .poll           = exanic_poll,
}

ExaNIC network device operations.

Definition at line 643 of file exanic.c.

struct pci_device_id exanic_ids[] [static]
Initial value:
 {
        PCI_ROM ( 0x10ee, 0x2b00, "exanic-old", "ExaNIC (old)", 0 ),
        PCI_ROM ( 0x1ce4, 0x0001, "exanic-x4", "ExaNIC X4", 0 ),
        PCI_ROM ( 0x1ce4, 0x0002, "exanic-x2", "ExaNIC X2", 0 ),
        PCI_ROM ( 0x1ce4, 0x0003, "exanic-x10", "ExaNIC X10", 0 ),
        PCI_ROM ( 0x1ce4, 0x0004, "exanic-x10gm", "ExaNIC X10 GM", 0 ),
        PCI_ROM ( 0x1ce4, 0x0005, "exanic-x40", "ExaNIC X40", 0 ),
        PCI_ROM ( 0x1ce4, 0x0006, "exanic-x10hpt", "ExaNIC X10 HPT", 0 ),
        PCI_ROM ( 0x1ce4, 0x0007, "exanic-x40g", "ExaNIC X40", 0 ),
}

ExaNIC PCI device IDs.

Definition at line 898 of file exanic.c.

struct pci_driver exanic_driver __pci_driver
Initial value:
 {
        .ids = exanic_ids,
        .id_count = ( sizeof ( exanic_ids ) / sizeof ( exanic_ids[0] ) ),
        .probe = exanic_probe,
        .remove = exanic_remove,
}

ExaNIC PCI driver.

Definition at line 910 of file exanic.c.