1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336 |
- /************************************************* -*- linux-c -*-
- * Myricom 10Gb Network Interface Card Software
- * Copyright 2009, Myricom, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- ****************************************************************/
-
- FILE_LICENCE ( GPL2_ONLY );
-
- /*
- * Author: Glenn Brown <glenn@myri.com>
- */
-
- /*
- * General Theory of Operation
- *
- * This is a minimal Myricom 10 gigabit Ethernet driver for network
- * boot.
- *
- * Initialization
- *
- * myri10ge_pci_probe() is called by iPXE during initialization.
- * Minimal NIC initialization is performed to minimize resources
- * consumed when the driver is resident but unused.
- *
- * Network Boot
- *
- * myri10ge_net_open() is called by iPXE before attempting to network
- * boot from the card. Packet buffers are allocated and the NIC
- * interface is initialized.
- *
- * Transmit
- *
- * myri10ge_net_transmit() enqueues frames for transmission by writing
- * discriptors to the NIC's tx ring. For simplicity and to avoid
- * copies, we always have the NIC DMA up the packet. The sent I/O
- * buffer is released once the NIC signals myri10ge_interrupt_handler()
- * that the send has completed.
- *
- * Receive
- *
- * Receives are posted to the NIC's receive ring. The NIC fills a
- * DMAable receive_completion ring with completion notifications.
- * myri10ge_net_poll() polls for these receive notifications, posts
- * replacement receive buffers to the NIC, and passes received frames
- * to netdev_rx().
- *
- * NonVolatile Storage
- *
- * This driver supports NonVolatile Storage (nvs) in the NIC EEPROM.
- * If the last EEPROM block is not otherwise filled, we tell
- * iPXE it may store NonVolatile Options (nvo) there.
- */
-
- /*
- * Debugging levels:
- * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(),
- * TX overflow, corrupted packets, ...
- * - DBG2() is for successful events, like packet received,
- * packet transmitted, and other general notifications.
- * - DBGP() prints the name of each called function on entry
- */
-
- #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"
-
- /****************************************************************
- * Forward declarations
- ****************************************************************/
-
- /* PCI driver entry points */
-
- static int myri10ge_pci_probe ( struct pci_device* );
- static void myri10ge_pci_remove ( struct pci_device* );
-
- /* Network device operations */
-
- 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* );
-
- /****************************************************************
- * Constants
- ****************************************************************/
-
- /* Maximum ring indices, used to wrap ring indices. These must be 2**N-1. */
-
- #define MYRI10GE_TRANSMIT_WRAP 1U
- #define MYRI10GE_RECEIVE_WRAP 7U
- #define MYRI10GE_RECEIVE_COMPLETION_WRAP 31U
-
- /****************************************************************
- * Driver internal data types.
- ****************************************************************/
-
- /* Structure holding all DMA buffers for a NIC, which we will
- allocated as contiguous read/write DMAable memory when the NIC is
- initialized. */
-
- struct myri10ge_dma_buffers
- {
- /* The NIC DMAs receive completion notifications into this ring */
-
- mcp_slot_t receive_completion[1+MYRI10GE_RECEIVE_COMPLETION_WRAP];
-
- /* Interrupt details are DMAd here before interrupting. */
-
- mcp_irq_data_t irq_data; /* 64B */
-
- /* NIC command completion status is DMAd here. */
-
- mcp_cmd_response_t command_response; /* 8B */
- };
-
- struct myri10ge_private
- {
- /* Interrupt support */
-
- uint32 *irq_claim; /* in NIC SRAM */
- uint32 *irq_deassert; /* in NIC SRAM */
-
- /* DMA buffers. */
-
- struct myri10ge_dma_buffers *dma;
-
- /*
- * Transmit state.
- *
- * The counts here are uint32 for easy comparison with
- * priv->dma->irq_data.send_done_count and with each other.
- */
-
- mcp_kreq_ether_send_t *transmit_ring; /* in NIC SRAM */
- uint32 transmit_ring_wrap;
- uint32 transmits_posted;
- uint32 transmits_done;
- struct io_buffer *transmit_iob[1 + MYRI10GE_TRANSMIT_WRAP];
-
- /*
- * Receive state.
- */
-
- mcp_kreq_ether_recv_t *receive_post_ring; /* in NIC SRAM */
- unsigned int receive_post_ring_wrap;
- unsigned int receives_posted;
- unsigned int receives_done;
- struct io_buffer *receive_iob[1 + MYRI10GE_RECEIVE_WRAP];
-
- /* Address for writing commands to the firmware.
- BEWARE: the value must be written 32 bits at a time. */
-
- mcp_cmd_t *command;
-
- /*
- * Nonvolatile Storage for configuration options.
- */
-
- struct nvs_device nvs;
- struct nvo_block nvo;
- unsigned int nvo_registered;
-
- /* Cached PCI capability locations. */
-
- uint8 pci_cap_vs;
- };
-
- /****************************************************************
- * Driver internal functions.
- ****************************************************************/
-
- /* Print ring status when debugging. Use this only after a printed
- value changes. */
-
- #define DBG2_RINGS( priv ) \
- DBG2 ( "tx %x/%x rx %x/%x in %s() \n", \
- ( priv ) ->transmits_done, ( priv ) -> transmits_posted, \
- ( priv ) ->receives_done, ( priv ) -> receives_posted, \
- __FUNCTION__ )
-
- /*
- * Return a pointer to the driver private data for a network device.
- *
- * @v netdev Network device created by this driver.
- * @ret priv The corresponding driver private data.
- */
- static inline struct myri10ge_private *myri10ge_priv ( struct net_device *nd )
- {
- /* 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 );
- }
-
- /*
- * Convert a Myri10ge driver private data pointer to a netdev pointer.
- *
- * @v p Myri10ge device private data.
- * @ret r The corresponding network device.
- */
- static inline struct net_device *myri10ge_netdev ( struct myri10ge_private *p )
- {
- return ( ( struct net_device * ) p ) - 1;
- }
-
- /*
- * Convert a network device pointer to a PCI device pointer.
- *
- * @v netdev A Network Device.
- * @ret r The corresponding PCI device.
- */
- static inline struct pci_device *myri10ge_pcidev ( struct net_device *netdev )
- {
- return container_of (netdev->dev, struct pci_device, dev);
- }
-
- /*
- * Pass a receive buffer to the NIC to be filled.
- *
- * @v priv The network device to receive the buffer.
- * @v iob The I/O buffer to fill.
- *
- * Receive buffers are filled in FIFO order.
- */
- static void myri10ge_post_receive ( struct myri10ge_private *priv,
- struct io_buffer *iob )
- {
- 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;
- }
-
- /*
- * Execute a command on the NIC.
- *
- * @v priv NIC to perform the command.
- * @v cmd The command to perform.
- * @v data I/O copy buffer for parameters/results
- * @ret rc 0 on success, else an error code.
- */
- static int myri10ge_command ( struct myri10ge_private *priv,
- uint32 cmd,
- uint32 data[3] )
- {
- 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;
- }
-
- /*
- * Handle any pending interrupt.
- *
- * @v netdev Device being polled for interrupts.
- *
- * This is called periodically to let the driver check for interrupts.
- */
- static void myri10ge_interrupt_handler ( struct net_device *netdev )
- {
- 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();
- }
-
- /* Constants for reading the STRING_SPECS via the Myricom
- Vendor Specific PCI configuration space capability. */
-
- #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
-
- /*
- * Read MAC address from its 'string specs' via the vendor-specific
- * capability. (This capability allows NIC SRAM and ROM to be read
- * before it is mapped.)
- *
- * @v pci The device.
- * @v vs Offset of the PCI Vendor-Specific Capability.
- * @v mac Buffer to store the MAC address.
- * @ret rc Returns 0 on success, else an error code.
- */
- static int mac_address_from_string_specs ( struct pci_device *pci,
- unsigned int vs,
- uint8 mac[ETH_ALEN] )
- {
- 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;
- }
-
- /****************************************************************
- * NonVolatile Storage support
- ****************************************************************/
-
- /*
- * Fill a buffer with data read from nonvolatile storage.
- *
- * @v nvs The NonVolatile Storage device to be read.
- * @v addr The first NonVolatile Storage address to be read.
- * @v _buf Pointer to the data buffer to be filled.
- * @v len The number of bytes to copy.
- * @ret rc 0 on success, else nonzero.
- */
- static int myri10ge_nvs_read ( struct nvs_device *nvs,
- unsigned int addr,
- void *_buf,
- size_t len )
- {
- 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;
- }
-
- /*
- * Write a buffer into nonvolatile storage.
- *
- * @v nvs The NonVolatile Storage device to be written.
- * @v address The NonVolatile Storage address to be written.
- * @v _buf Pointer to the data to be written.
- * @v len Length of the buffer to be written.
- * @ret rc 0 on success, else nonzero.
- */
- static int myri10ge_nvs_write ( struct nvs_device *nvs,
- unsigned int addr,
- const void *_buf,
- size_t len )
- {
- 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;
- }
-
- /*
- * Initialize NonVolatile storage support for a device.
- *
- * @v priv Device private data for the device.
- * @ret rc 0 on success, else an error code.
- */
-
- static int myri10ge_nv_init ( struct myri10ge_private *priv )
- {
- 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 )
- {
- /* Simply return if nonvolatile access is not supported. */
-
- if ( 0 == priv->nvo_registered )
- return;
-
- unregister_nvo ( &priv->nvo );
- }
-
- /****************************************************************
- * iPXE PCI Device Driver API functions
- ****************************************************************/
-
- /*
- * Initialize the PCI device.
- *
- * @v pci The device's associated pci_device structure.
- * @v id The PCI device + vendor id.
- * @ret rc Returns zero if successfully initialized.
- *
- * This function is called very early on, while iPXE is initializing.
- * This is a iPXE PCI Device Driver API function.
- */
- static int myri10ge_pci_probe ( struct pci_device *pci )
- {
- 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;
- }
-
- /*
- * Remove a device from the PCI device list.
- *
- * @v pci PCI device to remove.
- *
- * This is a PCI Device Driver API function.
- */
- static void myri10ge_pci_remove ( struct pci_device *pci )
- {
- 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 );
- }
-
- /****************************************************************
- * iPXE Network Device Driver Operations
- ****************************************************************/
-
- /*
- * Close a network device.
- *
- * @v netdev Device to close.
- *
- * This is a iPXE Network Device Driver API function.
- */
- static void myri10ge_net_close ( struct net_device *netdev )
- {
- 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 );
- }
-
- /*
- * Enable or disable IRQ masking.
- *
- * @v netdev Device to control.
- * @v enable Zero to mask off IRQ, non-zero to enable IRQ.
- *
- * This is a iPXE Network Driver API function.
- */
- static void myri10ge_net_irq ( struct net_device *netdev, int enable )
- {
- 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 );
- }
-
- /*
- * Opens a network device.
- *
- * @v netdev Device to be opened.
- * @ret rc Non-zero if failed to open.
- *
- * This enables tx and rx on the device.
- * This is a iPXE Network Device Driver API function.
- */
- static int myri10ge_net_open ( struct net_device *netdev )
- {
- 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 );
- }
-
- /*
- * This function allows a driver to process events during operation.
- *
- * @v netdev Device being polled.
- *
- * This is called periodically by iPXE to let the driver check the status of
- * transmitted packets and to allow the driver to check for received packets.
- * This is a iPXE Network Device Driver API function.
- */
- static void myri10ge_net_poll ( struct net_device *netdev )
- {
- 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 );
- }
- }
-
- /*
- * This transmits a packet.
- *
- * @v netdev Device to transmit from.
- * @v iobuf Data to transmit.
- * @ret rc Non-zero if failed to transmit.
- *
- * This is a iPXE Network Driver API function.
- */
- static int myri10ge_net_transmit ( struct net_device *netdev,
- struct io_buffer *iobuf )
- {
- 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 pci_device_id myri10ge_nics[] = {
- /* Each of these macros must be a single line to satisfy a script. */
- PCI_ROM ( 0x14c1, 0x0008, "myri10ge", "Myricom 10Gb Ethernet Adapter", 0 ) ,
- };
-
- struct pci_driver myri10ge_driver __pci_driver = {
- .ids = myri10ge_nics,
- .id_count = ( sizeof ( myri10ge_nics ) / sizeof ( myri10ge_nics[0] ) ) ,
- .probe = myri10ge_pci_probe,
- .remove = myri10ge_pci_remove
- };
-
- /*
- * Local variables:
- * c-basic-offset: 8
- * c-indent-level: 8
- * tab-width: 8
- * End:
- */
|