iPXE
Data Structures | Defines | Functions | Variables
myri10ge.c File Reference
#include <stdint.h>
#include <byteswap.h>
#include <errno.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <ipxe/iobuf.h>
#include <ipxe/malloc.h>
#include <ipxe/netdevice.h>
#include <ipxe/nvo.h>
#include <ipxe/nvs.h>
#include <ipxe/pci.h>
#include <ipxe/timer.h>
#include "myri10ge_mcp.h"

Go to the source code of this file.

Data Structures

struct  myri10ge_dma_buffers
struct  myri10ge_private

Defines

#define MYRI10GE_TRANSMIT_WRAP   1U
#define MYRI10GE_RECEIVE_WRAP   7U
#define MYRI10GE_RECEIVE_COMPLETION_WRAP   31U
#define DBG2_RINGS(priv)
#define VS_EEPROM_READ_ADDR   ( vs + 0x04 )
#define VS_EEPROM_READ_DATA   ( vs + 0x08 )
#define VS_EEPROM_WRITE   ( vs + 0x0C )
#define VS_ADDR   ( vs + 0x18 )
#define VS_DATA   ( vs + 0x14 )
#define VS_MODE   ( vs + 0x10 )
#define VS_MODE_READ32   0x3
#define VS_MODE_LOCATE   0x8
#define VS_LOCATE_STRING_SPECS   0x3
#define VS_MODE_EEPROM_STREAM_WRITE   0xB
#define TRY(prefix, base, suffix)

Functions

 FILE_LICENCE (GPL2_ONLY)
static int myri10ge_pci_probe (struct pci_device *)
static void myri10ge_pci_remove (struct pci_device *)
static void myri10ge_net_close (struct net_device *)
static void myri10ge_net_irq (struct net_device *, int enable)
static int myri10ge_net_open (struct net_device *)
static void myri10ge_net_poll (struct net_device *)
static int myri10ge_net_transmit (struct net_device *, struct io_buffer *)
static struct myri10ge_privatemyri10ge_priv (struct net_device *nd)
static struct net_devicemyri10ge_netdev (struct myri10ge_private *p)
static struct pci_devicemyri10ge_pcidev (struct net_device *netdev)
static void myri10ge_post_receive (struct myri10ge_private *priv, struct io_buffer *iob)
static int myri10ge_command (struct myri10ge_private *priv, uint32 cmd, uint32 data[3])
static void myri10ge_interrupt_handler (struct net_device *netdev)
static int mac_address_from_string_specs (struct pci_device *pci, unsigned int vs, uint8 mac[ETH_ALEN])
static int myri10ge_nvs_read (struct nvs_device *nvs, unsigned int addr, void *_buf, size_t len)
static int myri10ge_nvs_write (struct nvs_device *nvs, unsigned int addr, const void *_buf, size_t len)
static int myri10ge_nv_init (struct myri10ge_private *priv)
void myri10ge_nv_fini (struct myri10ge_private *priv)

Variables

static struct pci_device_id myri10ge_nics []
struct pci_driver myri10ge_driver __pci_driver

Define Documentation

#define MYRI10GE_TRANSMIT_WRAP   1U

Definition at line 115 of file myri10ge.c.

Referenced by myri10ge_interrupt_handler(), and myri10ge_net_transmit().

#define MYRI10GE_RECEIVE_WRAP   7U

Definition at line 117 of file myri10ge.c.

Referenced by myri10ge_net_poll().

#define DBG2_RINGS (   priv)
Value:
DBG2 ( "tx %x/%x rx %x/%x in %s() \n",                          \
               ( priv ) ->transmits_done, ( priv ) -> transmits_posted, \
               ( priv ) ->receives_done, ( priv ) -> receives_posted,   \
               __FUNCTION__ )

Definition at line 201 of file myri10ge.c.

Referenced by myri10ge_net_close(), myri10ge_net_open(), myri10ge_net_poll(), and myri10ge_net_transmit().

#define VS_EEPROM_READ_ADDR   ( vs + 0x04 )

Definition at line 426 of file myri10ge.c.

Referenced by myri10ge_nvs_read(), and myri10ge_nvs_write().

#define VS_EEPROM_READ_DATA   ( vs + 0x08 )

Definition at line 427 of file myri10ge.c.

Referenced by myri10ge_nvs_read(), and myri10ge_nvs_write().

#define VS_EEPROM_WRITE   ( vs + 0x0C )

Definition at line 428 of file myri10ge.c.

Referenced by myri10ge_nvs_write().

#define VS_ADDR   ( vs + 0x18 )

Definition at line 429 of file myri10ge.c.

Referenced by mac_address_from_string_specs(), and myri10ge_nvs_write().

#define VS_DATA   ( vs + 0x14 )

Definition at line 430 of file myri10ge.c.

Referenced by mac_address_from_string_specs(), and myri10ge_nvs_write().

#define VS_MODE   ( vs + 0x10 )

Definition at line 431 of file myri10ge.c.

Referenced by mac_address_from_string_specs(), and myri10ge_nvs_write().

#define VS_MODE_READ32   0x3

Definition at line 432 of file myri10ge.c.

Referenced by mac_address_from_string_specs().

#define VS_MODE_LOCATE   0x8

Definition at line 433 of file myri10ge.c.

Referenced by mac_address_from_string_specs().

#define VS_LOCATE_STRING_SPECS   0x3

Definition at line 434 of file myri10ge.c.

Referenced by mac_address_from_string_specs().

#define VS_MODE_EEPROM_STREAM_WRITE   0xB

Definition at line 435 of file myri10ge.c.

Referenced by myri10ge_nvs_write().

#define TRY (   prefix,
  base,
  suffix 
)
Value:
do {            \
                rc = myri10ge_command ( priv,           \
                                        MXGEFW_         \
                                        ## prefix       \
                                        ## base         \
                                        ## suffix,      \
                                        data );         \
                if ( rc ) {                             \
                        dbg = #base;                    \
                        goto abort_with_dma;            \
                }                                       \
        } while ( 0 )

Referenced by myri10ge_net_open().


Function Documentation

FILE_LICENCE ( GPL2_ONLY  )
static int myri10ge_pci_probe ( struct pci_device pci) [static]

Definition at line 774 of file myri10ge.c.

References adjust_pci_device(), alloc_etherdev(), DBG, DBGP, pci_device::dev, net_device::dev, ENOMEM, ENOTSUP, net_device::hw_addr, mac_address_from_string_specs(), myri10ge_net_close(), myri10ge_net_irq(), myri10ge_net_open(), myri10ge_net_poll(), myri10ge_net_transmit(), myri10ge_nv_init(), myri10ge_priv(), netdev, netdev_init(), netdev_nullify(), netdev_put(), net_device_operations::open, PCI_CAP_ID_VNDR, myri10ge_private::pci_cap_vs, pci_find_capability(), pci_set_drvdata(), priv, rc, register_netdev(), strerror(), and unregister_netdev().

{
        static struct net_device_operations myri10ge_operations = {
                .open     = myri10ge_net_open,
                .close    = myri10ge_net_close,
                .transmit = myri10ge_net_transmit,
                .poll     = myri10ge_net_poll,
                .irq      = myri10ge_net_irq
        };

        const char *dbg;
        int rc;
        struct net_device *netdev;
        struct myri10ge_private *priv;

        DBGP ( "myri10ge_pci_probe: " );

        netdev = alloc_etherdev ( sizeof ( *priv ) );
        if ( !netdev ) {
                rc = -ENOMEM;
                dbg = "alloc_etherdev";
                goto abort_with_nothing;
        }

        netdev_init ( netdev, &myri10ge_operations );
        priv = myri10ge_priv ( netdev );

        pci_set_drvdata ( pci, netdev );
        netdev->dev = &pci->dev;

        /* Make sure interrupts are disabled. */

        myri10ge_net_irq ( netdev, 0 );

        /* Find the PCI Vendor-Specific capability. */

        priv->pci_cap_vs = pci_find_capability ( pci , PCI_CAP_ID_VNDR );
        if ( 0 == priv->pci_cap_vs ) {
                rc = -ENOTSUP;
                dbg = "no_vs";
                goto abort_with_netdev_init;
        }

        /* Read the NIC HW address. */

        rc = mac_address_from_string_specs ( pci,
                                             priv->pci_cap_vs,
                                             netdev->hw_addr );
        if ( rc ) {
                dbg = "mac_from_ss";
                goto abort_with_netdev_init;
        }
        DBGP ( "mac " );

        /* Enable bus master, etc. */

        adjust_pci_device ( pci );
        DBGP ( "pci " );

        /* Register the initialized network device. */

        rc = register_netdev ( netdev );
        if ( rc ) {
                dbg = "register_netdev";
                goto abort_with_netdev_init;
        }

        /* Initialize NonVolatile Storage support. */

        rc = myri10ge_nv_init ( priv );
        if ( rc ) {
                dbg = "myri10ge_nv_init";
                goto abort_with_registered_netdev;
        }

        DBGP ( "done\n" );

        return 0;

abort_with_registered_netdev:
        unregister_netdev ( netdev );
abort_with_netdev_init:
        netdev_nullify ( netdev );
        netdev_put ( netdev );
abort_with_nothing:
        DBG ( "%s:%s\n", dbg, strerror ( rc ) );
        return rc;
}
static void myri10ge_pci_remove ( struct pci_device pci) [static]

Definition at line 870 of file myri10ge.c.

References DBGP, myri10ge_nv_fini(), myri10ge_priv(), netdev, netdev_nullify(), netdev_put(), pci_get_drvdata(), and unregister_netdev().

{
        struct net_device       *netdev;

        DBGP ( "myri10ge_pci_remove\n" );
        netdev = pci_get_drvdata ( pci );

        myri10ge_nv_fini ( myri10ge_priv ( netdev ) );
        unregister_netdev ( netdev );
        netdev_nullify ( netdev );
        netdev_put ( netdev );
}
static void myri10ge_net_close ( struct net_device netdev) [static]

Definition at line 894 of file myri10ge.c.

References data, DBG2_RINGS, DBGP, myri10ge_private::dma, free_dma(), free_iob(), memset(), myri10ge_command(), myri10ge_net_irq(), myri10ge_priv(), MYRI10GE_RECEIVE_WRAP, priv, myri10ge_private::receive_iob, myri10ge_private::receives_done, and myri10ge_private::receives_posted.

Referenced by myri10ge_pci_probe().

{
        struct myri10ge_private *priv;
        uint32                   data[3];

        DBGP ( "myri10ge_net_close\n" );
        priv = myri10ge_priv ( netdev );

        /* disable interrupts */

        myri10ge_net_irq ( netdev, 0 );

        /* Reset the NIC interface, so we won't get any more events from
           the NIC. */

        myri10ge_command ( priv, MXGEFW_CMD_RESET, data );

        /* Free receive buffers that were never filled. */

        while ( priv->receives_done != priv->receives_posted ) {
                free_iob ( priv->receive_iob[priv->receives_done
                                             & MYRI10GE_RECEIVE_WRAP] );
                ++priv->receives_done;
        }

        /* Release DMAable memory. */

        free_dma ( priv->dma, sizeof ( *priv->dma ) );

        /* Erase all state from the open. */

        memset ( priv, 0, sizeof ( *priv ) );

        DBG2_RINGS ( priv );
}
static void myri10ge_net_irq ( struct net_device netdev,
int  enable 
) [static]

Definition at line 938 of file myri10ge.c.

References DBGP, net_device::dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE, pci_read_config_word(), pci_write_config_word(), and val.

Referenced by myri10ge_net_close(), myri10ge_net_open(), and myri10ge_pci_probe().

{
        struct pci_device       *pci_dev;
        uint16                   val;

        DBGP ( "myri10ge_net_irq\n" );
        pci_dev = ( struct pci_device * ) netdev->dev;

        /* Adjust the Interrupt Disable bit in the Command register of the
           PCI Device. */

        pci_read_config_word ( pci_dev, PCI_COMMAND, &val );
        if ( enable )
                val &= ~PCI_COMMAND_INTX_DISABLE;
        else
                val |= PCI_COMMAND_INTX_DISABLE;
        pci_write_config_word ( pci_dev, PCI_COMMAND, val );
}
static int myri10ge_net_open ( struct net_device netdev) [static]

Definition at line 966 of file myri10ge.c.

References alloc_iob(), myri10ge_private::command, data, DBG, DBG2_RINGS, DBGP, net_device::dev, myri10ge_private::dma, ENOMEM, EPROTO, ETH_FRAME_LEN, free_dma(), free_iob(), iob_reserve, myri10ge_private::irq_claim, myri10ge_dma_buffers::irq_data, myri10ge_private::irq_deassert, net_device::ll_addr, MAC_ADDRESS, malloc_dma(), pci_device::membase, memset(), myri10ge_net_irq(), myri10ge_post_receive(), myri10ge_priv(), MYRI10GE_RECEIVE_WRAP, phys_to_virt(), priv, rc, myri10ge_dma_buffers::receive_completion, myri10ge_private::receive_iob, myri10ge_private::receive_post_ring, myri10ge_private::receive_post_ring_wrap, myri10ge_private::receives_posted, RESET, strerror(), myri10ge_private::transmit_ring, myri10ge_private::transmit_ring_wrap, TRY, and virt_to_bus().

Referenced by myri10ge_pci_probe().

{
        const char              *dbg;   /* printed upon error return */
        int                      rc;
        struct io_buffer        *iob;
        struct myri10ge_private *priv;
        uint32                   data[3];
        struct pci_device       *pci_dev;
        void                    *membase;

        DBGP ( "myri10ge_net_open\n" );
        priv    = myri10ge_priv ( netdev );
        pci_dev = ( struct pci_device * ) netdev->dev;
        membase = phys_to_virt ( pci_dev->membase );

        /* Compute address for passing commands to the firmware. */

        priv->command = membase + MXGEFW_ETH_CMD;

        /* Ensure interrupts are disabled. */

        myri10ge_net_irq ( netdev, 0 );

        /* Allocate cleared DMAable buffers. */

        priv->dma = malloc_dma ( sizeof ( *priv->dma ) , 128 );
        if ( !priv->dma ) {
                rc = -ENOMEM;
                dbg = "DMA";
                goto abort_with_nothing;
        }
        memset ( priv->dma, 0, sizeof ( *priv->dma ) );

        /* Simplify following code. */

#define TRY( prefix, base, suffix ) do {                \
                rc = myri10ge_command ( priv,           \
                                        MXGEFW_         \
                                        ## prefix       \
                                        ## base         \
                                        ## suffix,      \
                                        data );         \
                if ( rc ) {                             \
                        dbg = #base;                    \
                        goto abort_with_dma;            \
                }                                       \
        } while ( 0 )

        /* Send a reset command to the card to see if it is alive,
           and to reset its queue state. */

        TRY ( CMD_, RESET , );

        /* Set the interrupt queue size. */

        data[0] = ( (uint32_t)( sizeof ( priv->dma->receive_completion ) )
                    | MXGEFW_CMD_SET_INTRQ_SIZE_FLAG_NO_STRICT_SIZE_CHECK );
        TRY ( CMD_SET_ , INTRQ_SIZE , );

        /* Set the interrupt queue DMA address. */

        data[0] = virt_to_bus ( &priv->dma->receive_completion );
        data[1] = 0;
        TRY ( CMD_SET_, INTRQ_DMA, );

        /* Get the NIC interrupt claim address. */

        TRY ( CMD_GET_, IRQ_ACK, _OFFSET );
        priv->irq_claim = membase + data[0];

        /* Get the NIC interrupt assert address. */

        TRY ( CMD_GET_, IRQ_DEASSERT, _OFFSET );
        priv->irq_deassert = membase + data[0];

        /* Disable interrupt coalescing, which is inappropriate for the
           minimal buffering we provide. */

        TRY ( CMD_GET_, INTR_COAL, _DELAY_OFFSET );
        * ( ( uint32 * ) ( membase + data[0] ) ) = 0;

        /* Set the NIC mac address. */

        data[0] = ( netdev->ll_addr[0] << 24
                    | netdev->ll_addr[1] << 16
                    | netdev->ll_addr[2] << 8
                    | netdev->ll_addr[3] );
        data[1] = ( ( netdev->ll_addr[4] << 8 )
                     | netdev->ll_addr[5] );
        TRY ( SET_ , MAC_ADDRESS , );

        /* Enable multicast receives, because some iPXE clients don't work
           without multicast. . */

        TRY ( ENABLE_ , ALLMULTI , );

        /* Disable Ethernet flow control, so the NIC cannot deadlock the
           network under any circumstances. */

        TRY ( DISABLE_ , FLOW , _CONTROL );

        /* Compute transmit ring sizes. */

        data[0] = 0;            /* slice 0 */
        TRY ( CMD_GET_, SEND_RING, _SIZE );
        priv->transmit_ring_wrap
                = data[0] / sizeof ( mcp_kreq_ether_send_t ) - 1;
        if ( priv->transmit_ring_wrap
             & ( priv->transmit_ring_wrap + 1 ) ) {
                rc = -EPROTO;
                dbg = "TX_RING";
                goto abort_with_dma;
        }

        /* Compute receive ring sizes. */

        data[0] = 0;            /* slice 0 */
        TRY ( CMD_GET_ , RX_RING , _SIZE );
        priv->receive_post_ring_wrap = data[0] / sizeof ( mcp_dma_addr_t ) - 1;
        if ( priv->receive_post_ring_wrap
             & ( priv->receive_post_ring_wrap + 1 ) ) {
                rc = -EPROTO;
                dbg = "RX_RING";
                goto abort_with_dma;
        }

        /* Get NIC transmit ring address. */

        data[0] = 0;            /* slice 0. */
        TRY ( CMD_GET_, SEND, _OFFSET );
        priv->transmit_ring = membase + data[0];

        /* Get the NIC receive ring address. */

        data[0] = 0;            /* slice 0. */
        TRY ( CMD_GET_, SMALL_RX, _OFFSET );
        priv->receive_post_ring = membase + data[0];

        /* Set the Nic MTU. */

        data[0] = ETH_FRAME_LEN;
        TRY ( CMD_SET_, MTU, );

        /* Tell the NIC our buffer sizes. ( We use only small buffers, so we
           set both buffer sizes to the same value, which will force all
           received frames to use small buffers. ) */

        data[0] = MXGEFW_PAD + ETH_FRAME_LEN;
        TRY ( CMD_SET_, SMALL_BUFFER, _SIZE );
        data[0] = MXGEFW_PAD + ETH_FRAME_LEN;
        TRY ( CMD_SET_, BIG_BUFFER, _SIZE );

        /* Tell firmware where to DMA IRQ data */

        data[0] = virt_to_bus ( &priv->dma->irq_data );
        data[1] = 0;
        data[2] = sizeof ( priv->dma->irq_data );
        TRY ( CMD_SET_, STATS_DMA_V2, );

        /* Post receives. */

        while ( priv->receives_posted <= MYRI10GE_RECEIVE_WRAP ) {

                /* Reserve 2 extra bytes at the start of packets, since
                   the firmware always skips the first 2 bytes of the buffer
                   so TCP headers will be aligned. */

                iob = alloc_iob ( MXGEFW_PAD + ETH_FRAME_LEN );
                if ( !iob ) {
                        rc = -ENOMEM;
                        dbg = "alloc_iob";
                        goto abort_with_receives_posted;
                }
                iob_reserve ( iob, MXGEFW_PAD );
                myri10ge_post_receive ( priv, iob );
        }

        /* Bring up the link. */

        TRY ( CMD_, ETHERNET_UP, );

        DBG2_RINGS ( priv );
        return 0;

abort_with_receives_posted:
        while ( priv->receives_posted-- )
                free_iob ( priv->receive_iob[priv->receives_posted] );
abort_with_dma:
        /* Because the link is not up, we don't have to reset the NIC here. */
        free_dma ( priv->dma, sizeof ( *priv->dma ) );
abort_with_nothing:
        /* Erase all signs of the failed open. */
        memset ( priv, 0, sizeof ( *priv ) );
        DBG ( "%s: %s\n", dbg, strerror ( rc ) );
        return ( rc );
}
static void myri10ge_net_poll ( struct net_device netdev) [static]

Definition at line 1172 of file myri10ge.c.

References alloc_iob(), DBG, DBG2_RINGS, DBGP, myri10ge_private::dma, ETH_FRAME_LEN, iob_put, iob_reserve, length, myri10ge_interrupt_handler(), myri10ge_post_receive(), myri10ge_priv(), MYRI10GE_RECEIVE_COMPLETION_WRAP, MYRI10GE_RECEIVE_WRAP, netdev_rx(), ntohs, priv, myri10ge_dma_buffers::receive_completion, myri10ge_private::receive_iob, myri10ge_private::receives_done, myri10ge_private::receives_posted, and wmb.

Referenced by myri10ge_pci_probe().

{
        struct io_buffer                *iob;
        struct io_buffer                *replacement;
        struct myri10ge_dma_buffers     *dma;
        struct myri10ge_private         *priv;
        unsigned int                     length;
        unsigned int                     orig_receives_posted;

        DBGP ( "myri10ge_net_poll\n" );
        priv = myri10ge_priv ( netdev );
        dma  = priv->dma;

        /* Process any pending interrupt. */

        myri10ge_interrupt_handler ( netdev );

        /* Pass up received frames, but limit ourselves to receives posted
           before this function was called, so we cannot livelock if
           receives are arriving faster than we process them. */

        orig_receives_posted = priv->receives_posted;
        while ( priv->receives_done != orig_receives_posted ) {

                /* Stop if there is no pending receive. */

                length = ntohs ( dma->receive_completion
                                 [priv->receives_done
                                  & MYRI10GE_RECEIVE_COMPLETION_WRAP]
                                 .length );
                if ( length == 0 )
                        break;

                /* Allocate a replacement buffer.  If none is available,
                   stop passing up packets until a buffer is available.

                   Reserve 2 extra bytes at the start of packets, since
                   the firmware always skips the first 2 bytes of the buffer
                   so TCP headers will be aligned. */

                replacement = alloc_iob ( MXGEFW_PAD + ETH_FRAME_LEN );
                if ( !replacement ) {
                        DBG ( "NO RX BUF\n" );
                        break;
                }
                iob_reserve ( replacement, MXGEFW_PAD );

                /* Pass up the received frame. */

                iob = priv->receive_iob[priv->receives_done
                                        & MYRI10GE_RECEIVE_WRAP];
                iob_put ( iob, length );
                netdev_rx ( netdev, iob );

                /* We have consumed the packet, so clear the receive
                   notification. */

                dma->receive_completion [priv->receives_done
                                         & MYRI10GE_RECEIVE_COMPLETION_WRAP]
                        .length = 0;
                wmb();

                /* Replace the passed-up I/O buffer. */

                myri10ge_post_receive ( priv, replacement );
                ++priv->receives_done;
                DBG2_RINGS ( priv );
        }
}
static int myri10ge_net_transmit ( struct net_device netdev,
struct io_buffer iobuf 
) [static]

Definition at line 1251 of file myri10ge.c.

References io_buffer::data, DBG, DBG2, DBG2_HD, DBG2_RINGS, DBGP, ENOBUFS, ETH_ZLEN, htonl, iob_len(), iob_pad(), len, myri10ge_priv(), MYRI10GE_TRANSMIT_WRAP, priv, myri10ge_private::transmit_iob, myri10ge_private::transmit_ring, myri10ge_private::transmit_ring_wrap, myri10ge_private::transmits_done, myri10ge_private::transmits_posted, virt_to_bus(), and wmb.

Referenced by myri10ge_pci_probe().

{
        mcp_kreq_ether_send_t   *kreq;
        size_t                   len;
        struct myri10ge_private *priv;
        uint32                   transmits_posted;

        DBGP ( "myri10ge_net_transmit\n" );
        priv = myri10ge_priv ( netdev );

        /* Confirm space in the send ring. */

        transmits_posted = priv->transmits_posted;
        if ( transmits_posted - priv->transmits_done
             > MYRI10GE_TRANSMIT_WRAP ) {
                DBG ( "TX ring full\n" );
                return -ENOBUFS;
        }

        DBG2 ( "TX %p+%zd ", iobuf->data, iob_len ( iobuf ) );
        DBG2_HD ( iobuf->data, 14 );

        /* Record the packet being transmitted, so we can later report
           send completion. */

        priv->transmit_iob[transmits_posted & MYRI10GE_TRANSMIT_WRAP] = iobuf;

        /* Copy and pad undersized frames, because the NIC does not pad,
           and we would rather copy small frames than do a gather. */

        len = iob_len ( iobuf );
        if ( len < ETH_ZLEN ) {
                iob_pad ( iobuf, ETH_ZLEN );
                len = ETH_ZLEN;
        }

        /* Enqueue the packet by writing a descriptor to the NIC.
           This is a bit tricky because the HW requires 32-bit writes,
           but the structure has smaller fields. */

        kreq = &priv->transmit_ring[transmits_posted
                                    & priv->transmit_ring_wrap];
        kreq->addr_high = 0;
        kreq->addr_low = htonl ( virt_to_bus ( iobuf->data ) );
        ( ( uint32 * ) kreq ) [2] = htonl (
                0x0000 << 16     /* pseudo_header_offset */
                | ( len & 0xFFFF ) /* length */
                );
        wmb();
        ( ( uint32 * ) kreq ) [3] = htonl (
                0x00 << 24      /* pad */
                | 0x01 << 16    /* rdma_count */
                | 0x00 << 8     /* cksum_offset */
                | ( MXGEFW_FLAGS_SMALL
                    | MXGEFW_FLAGS_FIRST
                    | MXGEFW_FLAGS_NO_TSO ) /* flags */
                );
        wmb();

        /* Mark the slot as consumed and return. */

        priv->transmits_posted = ++transmits_posted;
        DBG2_RINGS ( priv );
        return 0;
}
static struct myri10ge_private* myri10ge_priv ( struct net_device nd) [static, read]

Definition at line 213 of file myri10ge.c.

Referenced by myri10ge_interrupt_handler(), myri10ge_net_close(), myri10ge_net_open(), myri10ge_net_poll(), myri10ge_net_transmit(), myri10ge_pci_probe(), and myri10ge_pci_remove().

{
        /* Our private data always follows the network device in memory,
           since we use alloc_netdev() to allocate the storage. */

        return ( struct myri10ge_private * ) ( nd + 1 );
}
static struct net_device* myri10ge_netdev ( struct myri10ge_private p) [static, read]

Definition at line 227 of file myri10ge.c.

Referenced by myri10ge_nv_init(), myri10ge_nvs_read(), and myri10ge_nvs_write().

{
        return ( ( struct net_device * ) p ) - 1;
}
static struct pci_device* myri10ge_pcidev ( struct net_device netdev) [static, read]

Definition at line 238 of file myri10ge.c.

References container_of, pci_device::dev, and net_device::dev.

Referenced by myri10ge_nvs_read(), and myri10ge_nvs_write().

{
        return container_of (netdev->dev, struct pci_device, dev);
}
static void myri10ge_post_receive ( struct myri10ge_private priv,
struct io_buffer iob 
) [static]

Definition at line 251 of file myri10ge.c.

References io_buffer::data, htonl, MYRI10GE_RECEIVE_WRAP, myri10ge_private::receive_iob, myri10ge_private::receive_post_ring, myri10ge_private::receive_post_ring_wrap, myri10ge_private::receives_posted, request, virt_to_bus(), and wmb.

Referenced by myri10ge_net_open(), and myri10ge_net_poll().

{
        unsigned int             receives_posted;
        mcp_kreq_ether_recv_t   *request;

        /* Record the posted I/O buffer, to be passed to netdev_rx() on
           receive. */

        receives_posted = priv->receives_posted;
        priv->receive_iob[receives_posted & MYRI10GE_RECEIVE_WRAP] = iob;

        /* Post the receive. */

        request = &priv->receive_post_ring[receives_posted
                                           & priv->receive_post_ring_wrap];
        request->addr_high = 0;
        wmb();
        request->addr_low = htonl ( virt_to_bus ( iob->data ) );
        priv->receives_posted = ++receives_posted;
}
static int myri10ge_command ( struct myri10ge_private priv,
uint32  cmd,
uint32  data[3] 
) [static]

Definition at line 281 of file myri10ge.c.

References command, myri10ge_private::command, myri10ge_dma_buffers::command_response, DBG, DBGP, myri10ge_private::dma, EIO, ETIMEDOUT, htonl, ntohl, rmb, udelay(), virt_to_bus(), and wmb.

Referenced by myri10ge_net_close().

{
        int                              i;
        mcp_cmd_t                       *command;
        uint32                           result;
        unsigned int                     slept_ms;
        volatile mcp_cmd_response_t     *response;

        DBGP ( "myri10ge_command ( ,%d, ) \n", cmd );
        command = priv->command;
        response = &priv->dma->command_response;

        /* Mark the command as incomplete. */

        response->result = 0xFFFFFFFF;

        /* Pass the command to the NIC. */

        command->cmd                = htonl ( cmd );
        command->data0              = htonl ( data[0] );
        command->data1              = htonl ( data[1] );
        command->data2              = htonl ( data[2] );
        command->response_addr.high = 0;
        command->response_addr.low
                = htonl ( virt_to_bus ( &priv->dma->command_response ) );
        for ( i=0; i<9; i++ )
                command->pad[i] = 0;
        wmb();
        command->pad[9] = 0;

        /* Wait up to 2 seconds for a response. */

        for ( slept_ms=0; slept_ms<2000; slept_ms++ ) {
                result = response->result;
                if ( result == 0 ) {
                        data[0] = ntohl ( response->data );
                        return 0;
                } else if ( result != 0xFFFFFFFF ) {
                        DBG ( "cmd%d:0x%x\n",
                              cmd,
                              ntohl ( response->result ) );
                        return -EIO;
                }
                udelay ( 1000 );
                rmb();
        }
        DBG ( "cmd%d:timed out\n", cmd );
        return -ETIMEDOUT;
}
static void myri10ge_interrupt_handler ( struct net_device netdev) [static]

Definition at line 340 of file myri10ge.c.

References DBG2, myri10ge_private::dma, htonl, myri10ge_private::irq_claim, myri10ge_dma_buffers::irq_data, myri10ge_private::irq_deassert, mb(), myri10ge_priv(), MYRI10GE_TRANSMIT_WRAP, netdev_link_down(), netdev_link_up(), netdev_tx_complete(), ntohl, priv, rmb, myri10ge_private::transmit_iob, myri10ge_private::transmits_done, valid, and wmb.

Referenced by myri10ge_net_poll().

{
        struct myri10ge_private *priv;
        mcp_irq_data_t          *irq_data;
        uint8                    valid;

        priv = myri10ge_priv ( netdev );
        irq_data = &priv->dma->irq_data;

        /* Return if there was no interrupt. */

        rmb();
        valid = irq_data->valid;
        if ( !valid )
                return;
        DBG2 ( "irq " );

        /* Tell the NIC to deassert the interrupt and clear
           irq_data->valid.*/

        *priv->irq_deassert = 0;        /* any value is OK. */
        mb();

        /* Handle any new receives. */

        if ( valid & 1 ) {

                /* Pass the receive interrupt token back to the NIC. */

                DBG2 ( "rx " );
                *priv->irq_claim = htonl ( 3 );
                wmb();
        }

        /* Handle any sent packet by freeing its I/O buffer, now that
           we know it has been DMAd. */

        if ( valid & 2 ) {
                unsigned int nic_done_count;

                DBG2 ( "snt " );
                nic_done_count = ntohl ( priv->dma->irq_data.send_done_count );
                while ( priv->transmits_done != nic_done_count ) {
                        struct io_buffer *iob;

                        iob = priv->transmit_iob [priv->transmits_done
                                                  & MYRI10GE_TRANSMIT_WRAP];
                        DBG2 ( "%p ", iob );
                        netdev_tx_complete ( netdev, iob );
                        ++priv->transmits_done;
                }
        }

        /* Record any statistics update. */

        if ( irq_data->stats_updated ) {

                /* Update the link status. */

                DBG2 ( "stats " );
                if ( ntohl ( irq_data->link_up ) == MXGEFW_LINK_UP )
                        netdev_link_up ( netdev );
                else
                        netdev_link_down ( netdev );

                /* Ignore all error counters from the NIC. */
        }

        /* Wait for the interrupt to be deasserted, as indicated by
           irq_data->valid, which is set by the NIC after the deassert. */

        DBG2 ( "wait " );
        do {
                mb();
        } while ( irq_data->valid );

        /* Claim the interrupt to enable future interrupt generation. */

        DBG2 ( "claim\n" );
        * ( priv->irq_claim + 1 ) = htonl ( 3 );
        mb();
}
static int mac_address_from_string_specs ( struct pci_device pci,
unsigned int  vs,
uint8  mac[ETH_ALEN] 
) [static]

Definition at line 447 of file myri10ge.c.

References addr, DBG, DBG2, ENOTSUP, len, limit, mac, memcmp(), memcpy(), ntohl, pci_read_config_dword(), pci_write_config_byte(), pci_write_config_dword(), strtoul(), VS_ADDR, VS_DATA, VS_LOCATE_STRING_SPECS, VS_MODE, VS_MODE_LOCATE, and VS_MODE_READ32.

Referenced by myri10ge_pci_probe().

{
        char string_specs[256];
        char *ptr, *limit;
        char *to = string_specs;
        uint32 addr;
        uint32 len;
        int mac_set = 0;

        /* Locate the String specs in LANai SRAM. */

        pci_write_config_byte ( pci, VS_MODE, VS_MODE_LOCATE );
        pci_write_config_dword ( pci, VS_ADDR, VS_LOCATE_STRING_SPECS );
        pci_read_config_dword ( pci, VS_ADDR, &addr );
        pci_read_config_dword ( pci, VS_DATA, &len );
        DBG2 ( "ss@%x,%x\n", addr, len );

        /* Copy in the string specs.  Use 32-bit reads for performance. */

        if ( len > sizeof ( string_specs ) || ( len & 3 ) ) {
                pci_write_config_byte ( pci, VS_MODE, 0 );
                DBG ( "SS too big\n" );
                return -ENOTSUP;
        }

        pci_write_config_byte ( pci, VS_MODE, VS_MODE_READ32 );
        while ( len >= 4 ) {
                uint32 tmp;

                pci_write_config_byte ( pci, VS_ADDR, addr );
                pci_read_config_dword ( pci, VS_DATA, &tmp );
                tmp = ntohl ( tmp );
                memcpy ( to, &tmp, 4 );
                to += 4;
                addr += 4;
                len -= 4;
        }
        pci_write_config_byte ( pci, VS_MODE, 0 );

        /* Parse the string specs. */

        DBG2 ( "STRING_SPECS:\n" );
        ptr = string_specs;
        limit = string_specs + sizeof ( string_specs );
        while ( *ptr != '\0' && ptr < limit ) {
                DBG2 ( "%s\n", ptr );
                if ( memcmp ( ptr, "MAC=", 4 ) == 0 ) {
                        unsigned int i;

                        ptr += 4;
                        for ( i=0; i<6; i++ ) {
                                if ( ( ptr + 2 ) > limit ) {
                                        DBG ( "bad MAC addr\n" );
                                        return -ENOTSUP;
                                }
                                mac[i] = strtoul ( ptr, &ptr, 16 );
                                ptr += 1;
                        }
                        mac_set = 1;
                }
                else
                        while ( ptr < limit && *ptr++ );
        }

        /* Verify we parsed all we need. */

        if ( !mac_set ) {
                DBG ( "no MAC addr\n" );
                return -ENOTSUP;
        }

        DBG2 ( "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );

        return 0;
}
static int myri10ge_nvs_read ( struct nvs_device nvs,
unsigned int  addr,
void *  _buf,
size_t  len 
) [static]

Definition at line 539 of file myri10ge.c.

References container_of, data, DBGP, DBGP_HDA, len, myri10ge_netdev(), myri10ge_pcidev(), myri10ge_private::pci_cap_vs, pci_read_config_dword(), pci_write_config_byte(), priv, VS_EEPROM_READ_ADDR, and VS_EEPROM_READ_DATA.

Referenced by myri10ge_nv_init().

{
        struct myri10ge_private *priv =
                container_of (nvs, struct myri10ge_private, nvs);
        struct pci_device *pci = myri10ge_pcidev ( myri10ge_netdev ( priv ) );
        unsigned int vs = priv->pci_cap_vs;
        unsigned char *buf = (unsigned char *) _buf;
        unsigned int data;
        unsigned int i, j;

        DBGP ( "myri10ge_nvs_read\n" );

        /* Issue the first read address. */

        pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 3, addr>>16 );
        pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 2, addr>>8 );
        pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );
        addr++;

        /* Issue all the reads, and harvest the results every 4th issue. */

        for ( i=0; i<len; ++i,addr++ ) {

                /* Issue the next read address, updating only the
                   bytes that need updating.  We always update the
                   LSB, which triggers the read. */

                if ( ( addr & 0xff ) == 0 ) {
                        if ( ( addr & 0xffff ) == 0 ) {
                                pci_write_config_byte ( pci,
                                                        VS_EEPROM_READ_ADDR + 3,
                                                        addr >> 16 );
                        }
                        pci_write_config_byte ( pci,
                                                VS_EEPROM_READ_ADDR + 2,
                                                addr >> 8 );
                }
                pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );

                /* If 4 data bytes are available, read them with a single read. */

                if ( ( i & 3 ) == 3 ) {
                        pci_read_config_dword ( pci,
                                                VS_EEPROM_READ_DATA,
                                                &data );
                        for ( j=0; j<4; j++ ) {
                                buf[i-j] = data;
                                data >>= 8;
                        }
                }
        }

        /* Harvest any remaining results. */

        if ( ( i & 3 ) != 0 ) {
                pci_read_config_dword ( pci, VS_EEPROM_READ_DATA, &data );
                for ( j=1; j<=(i&3); j++ ) {
                        buf[i-j] = data;
                        data >>= 8;
                }
        }

        DBGP_HDA ( addr - len, _buf, len );
        return 0;
}
static int myri10ge_nvs_write ( struct nvs_device nvs,
unsigned int  addr,
const void *  _buf,
size_t  len 
) [static]

Definition at line 617 of file myri10ge.c.

References container_of, DBGP, DBGP_HDA, len, myri10ge_netdev(), myri10ge_pcidev(), myri10ge_private::pci_cap_vs, pci_read_config_byte(), pci_write_config_byte(), pci_write_config_dword(), priv, VS_ADDR, VS_DATA, VS_EEPROM_READ_ADDR, VS_EEPROM_READ_DATA, VS_EEPROM_WRITE, VS_MODE, and VS_MODE_EEPROM_STREAM_WRITE.

Referenced by myri10ge_nv_init().

{
        struct myri10ge_private *priv =
                container_of (nvs, struct myri10ge_private, nvs);
        struct pci_device *pci = myri10ge_pcidev ( myri10ge_netdev ( priv ) );
        unsigned int vs = priv->pci_cap_vs;
        const unsigned char *buf = (const unsigned char *)_buf;
        unsigned int i;
        uint8 verify;

        DBGP ( "nvs_write " );
        DBGP_HDA ( addr, _buf, len );

        /* Start erase of the NonVolatile Options block. */

        DBGP ( "erasing " );
        pci_write_config_dword ( pci, VS_EEPROM_WRITE, ( addr << 8 ) | 0xff );

        /* Wait for erase to complete. */

        DBGP ( "waiting " );
        pci_read_config_byte ( pci, VS_EEPROM_READ_DATA, &verify );
        while ( verify != 0xff ) {
                pci_write_config_byte ( pci, VS_EEPROM_READ_ADDR + 1, addr );
                pci_read_config_byte ( pci, VS_EEPROM_READ_DATA, &verify );
        }

        /* Write the data one byte at a time. */

        DBGP ( "writing " );
        pci_write_config_byte ( pci, VS_MODE, VS_MODE_EEPROM_STREAM_WRITE );
        pci_write_config_dword ( pci, VS_ADDR, addr );
        for (i=0; i<len; i++, addr++)
                pci_write_config_byte ( pci, VS_DATA, buf[i] );
        pci_write_config_dword ( pci, VS_ADDR, 0xffffffff );
        pci_write_config_byte ( pci, VS_MODE, 0 );

        DBGP ( "done\n" );
        return 0;
}
static int myri10ge_nv_init ( struct myri10ge_private priv) [static]

Definition at line 668 of file myri10ge.c.

References nvs_device::block_size, DBG, DBG2, DBGP, hdr, myri10ge_netdev(), myri10ge_nvs_read(), myri10ge_nvs_write(), netdev_settings(), ntohl, NULL, myri10ge_private::nvo, nvo_init(), myri10ge_private::nvo_registered, myri10ge_private::nvs, rc, nvs_device::read, register_nvo(), nvs_device::size, version, nvs_device::word_len_log2, and nvs_device::write.

Referenced by myri10ge_pci_probe().

{
        int rc;
        struct myri10ge_eeprom_header
        {
                uint8 __jump[8];
                uint32 eeprom_len;
                uint32 eeprom_segment_len;
                uint32 mcp1_offset;
                uint32 mcp2_offset;
                uint32 version;
        } hdr;
        uint32 mcp2_len;
        unsigned int nvo_fragment_pos;

        DBGP ( "myri10ge_nv_init\n" );

        /* Read the EEPROM header, and byteswap the fields we will use.
           This is safe even though priv->nvs is not yet initialized. */

        rc = myri10ge_nvs_read ( &priv->nvs, 0, &hdr, sizeof ( hdr ) );
        if ( rc ) {
                DBG ( "EEPROM header unreadable\n" );
                return rc;
        }
        hdr.eeprom_len         = ntohl ( hdr.eeprom_len );
        hdr.eeprom_segment_len = ntohl ( hdr.eeprom_segment_len );
        hdr.mcp2_offset        = ntohl ( hdr.mcp2_offset );
        hdr.version            = ntohl ( hdr.version );
        DBG2 ( "eelen:%xh seglen:%xh mcp2@%xh ver%d\n", hdr.eeprom_len,
               hdr.eeprom_segment_len, hdr.mcp2_offset, hdr.version );

        /* If the firmware does not support EEPROM writes, simply return. */

        if ( hdr.version < 1 ) {
                DBG ( "No EEPROM write support\n" );
                return 0;
        }

        /* Read the length of MCP2. */

        rc = myri10ge_nvs_read ( &priv->nvs, hdr.mcp2_offset, &mcp2_len, 4 );
        mcp2_len = ntohl ( mcp2_len );
        DBG2 ( "mcp2len:%xh\n", mcp2_len );

        /* Determine the position of the NonVolatile Options fragment and
           simply return if it overlaps other data. */

        nvo_fragment_pos = hdr.eeprom_len -  hdr.eeprom_segment_len;
        if ( hdr.mcp2_offset + mcp2_len > nvo_fragment_pos ) {
                DBG ( "EEPROM full\n" );
                return 0;
        }

        /* Initialize NonVolatile Storage state. */

        priv->nvs.word_len_log2 = 0;
        priv->nvs.size          = hdr.eeprom_len;
        priv->nvs.block_size    = hdr.eeprom_segment_len;
        priv->nvs.read          = myri10ge_nvs_read;
        priv->nvs.write         = myri10ge_nvs_write;

        /* Register the NonVolatile Options storage. */

        nvo_init ( &priv->nvo,
                   &priv->nvs,
                   nvo_fragment_pos, 0x200,
                   NULL,
                   & myri10ge_netdev (priv) -> refcnt );
        rc = register_nvo ( &priv->nvo,
                            netdev_settings ( myri10ge_netdev ( priv ) ) );
        if ( rc ) {
                DBG ("register_nvo failed");
                return rc;
        }

        priv->nvo_registered = 1;
        DBG2 ( "NVO supported\n" );
        return 0;
}
void myri10ge_nv_fini ( struct myri10ge_private priv)

Definition at line 750 of file myri10ge.c.

References myri10ge_private::nvo, myri10ge_private::nvo_registered, and unregister_nvo().

Referenced by myri10ge_pci_remove().

{
        /* Simply return if nonvolatile access is not supported. */

        if ( 0 == priv->nvo_registered )
                return;

        unregister_nvo ( &priv->nvo );
}

Variable Documentation

struct pci_device_id myri10ge_nics[] [static]
Initial value:
 {
        
        PCI_ROM ( 0x14c1, 0x0008, "myri10ge", "Myricom 10Gb Ethernet Adapter", 0 ) ,
}

Definition at line 1318 of file myri10ge.c.

struct pci_driver myri10ge_driver __pci_driver
Initial value:
 {
        .ids      = myri10ge_nics,
        .id_count = ( sizeof ( myri10ge_nics ) / sizeof ( myri10ge_nics[0] ) ) ,
        .probe    = myri10ge_pci_probe,
        .remove   = myri10ge_pci_remove
}

Definition at line 1323 of file myri10ge.c.