gPXE fellows: The attached patch set does the following, in 4 distinct patches: * Adds a PCI_CAP_ID_VS definition to pci.h. * Adds jump-scrolling to the settings_ui, since gPXE now has more settings that can fit on screen. * Adds setting-deletion support to the settings UI. * Adds nonvolatile option support to the myri10ge driver.
The attached .gif shows the appearance of the modified settings UI,with "..." to suggest scrolling and with "Ctrl-D" instructions. The patches have been tested with diskless DHCP-less iSCSI boot over a myri10ge NIC.
Would someone please sponsor this patch set? Thank you, --Glenn Brown
>From 49fa1ab0f33157ef0115738d83228c427a97067a Mon Sep 17 00:00:00 2001 From: Glenn Brown <gl...@myri.com> Date: Mon, 14 Jun 2010 16:30:00 -0700 Subject: [PATCH 1/4] [pci] Define Vendor Specific capability ID. Add a PCI_CAP_ID_VS definition for the PCI standard "Vendor Specific" capability ID. Signed-off-by: Glenn Brown <gl...@myri.com> --- src/include/gpxe/pci.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/src/include/gpxe/pci.h b/src/include/gpxe/pci.h index 8bcf1e0..d8c693d 100644 --- a/src/include/gpxe/pci.h +++ b/src/include/gpxe/pci.h @@ -159,6 +159,7 @@ FILE_LICENCE ( GPL2_ONLY ); #define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ +#define PCI_CAP_ID_VS 0x09 /* Vendor Specific */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ -- 1.7.0.4 >From 0e67712cc5ae36a3e9058233eb7e58c87a1f6593 Mon Sep 17 00:00:00 2001 From: Glenn Brown <gl...@myri.com> Date: Sun, 20 Jun 2010 22:46:37 -0700 Subject: [PATCH 2/4] [settings_ui] Jump scroll. Implement jump scrolling with "..." displayed where the settings list continues off-screen, because there are now too many settings to fit on screen in the "config ..." text user interface. Signed-off-by: Glenn Brown <gl...@myri.com> --- src/hci/tui/settings_ui.c | 115 ++++++++++++++++++++++++++++++--------------- 1 files changed, 77 insertions(+), 38 deletions(-) diff --git a/src/hci/tui/settings_ui.c b/src/hci/tui/settings_ui.c index 74ce6af..61ea3e4 100644 --- a/src/hci/tui/settings_ui.c +++ b/src/hci/tui/settings_ui.c @@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define TITLE_ROW 1 #define SETTINGS_LIST_ROW 3 #define SETTINGS_LIST_COL 1 +#define SETTINGS_LIST_ROWS 16 #define INFO_ROW 20 #define ALERT_ROW 20 #define INSTRUCTION_ROW 22 @@ -65,6 +66,8 @@ struct setting_row { struct setting_widget { /** Settings block */ struct settings *settings; + /** Index of the first visible setting, for scrolling. */ + unsigned int first_visible; /** Configuration setting */ struct setting *setting; /** Screen row */ @@ -84,15 +87,13 @@ struct setting_widget { static void load_setting ( struct setting_widget *widget ) __nonnull; static int save_setting ( struct setting_widget *widget ) __nonnull; -static void init_setting ( struct setting_widget *widget, - struct settings *settings, - struct setting *setting, - unsigned int row, unsigned int col ) __nonnull; +static void init_widget ( struct setting_widget *widget, + struct settings *settings ) __nonnull; static void draw_setting ( struct setting_widget *widget ) __nonnull; static int edit_setting ( struct setting_widget *widget, int key ) __nonnull; -static void init_setting_index ( struct setting_widget *widget, - struct settings *settings, - unsigned int index ) __nonnull; +static void select_setting ( struct setting_widget *widget, + unsigned int index ) __nonnull; +static void reveal ( struct setting_widget *widget, unsigned int n) __nonnull; static void vmsg ( unsigned int row, const char *fmt, va_list args ) __nonnull; static void msg ( unsigned int row, const char *fmt, ... ) __nonnull; static void valert ( const char *fmt, va_list args ) __nonnull; @@ -135,28 +136,17 @@ static int save_setting ( struct setting_widget *widget ) { } /** - * Initialise setting widget + * Initialise the scrolling setting widget, drawing initial display. * * @v widget Setting widget * @v settings Settings block - * @v setting Configuration setting - * @v row Screen row - * @v col Screen column */ -static void init_setting ( struct setting_widget *widget, - struct settings *settings, - struct setting *setting, - unsigned int row, unsigned int col ) { - - /* Initialise widget structure */ +static void init_widget ( struct setting_widget *widget, + struct settings *settings ) { memset ( widget, 0, sizeof ( *widget ) ); widget->settings = settings; - widget->setting = setting; - widget->row = row; - widget->col = col; - - /* Read current setting value */ - load_setting ( widget ); + widget->first_visible = SETTINGS_LIST_ROWS; + reveal ( widget, 0 ); } /** @@ -212,19 +202,25 @@ static int edit_setting ( struct setting_widget *widget, int key ) { } /** - * Initialise setting widget by index + * Select a setting for display updates, by index. * * @v widget Setting widget * @v settings Settings block * @v index Index of setting with settings list */ -static void init_setting_index ( struct setting_widget *widget, - struct settings *settings, - unsigned int index ) { +static void select_setting ( struct setting_widget *widget, + unsigned int index ) { struct setting *all_settings = table_start ( SETTINGS ); + unsigned int skip = offsetof ( struct setting_widget, setting ); + + /* Reset the widget, preserving static state. */ + memset ( ( char * ) widget + skip, 0, sizeof ( *widget ) - skip ); + widget->setting = &all_settings[index]; + widget->row = SETTINGS_LIST_ROW + index - widget->first_visible; + widget->col = SETTINGS_LIST_COL; - init_setting ( widget, settings, &all_settings[index], - ( SETTINGS_LIST_ROW + index ), SETTINGS_LIST_COL ); + /* Read current setting value */ + load_setting ( widget ); } /** @@ -334,22 +330,65 @@ static void draw_instruction_row ( int editing ) { } } +/** + * Reveal a setting by index: Scroll the setting list to reveal the + * specified setting. + * + * @widget The main loop's display widget. + * @n The index of the setting to reveal. + */ +static void reveal ( struct setting_widget *widget, unsigned int n) +{ + unsigned int i; + + /* Simply return if setting N is already on-screen. */ + if ( n - widget->first_visible < SETTINGS_LIST_ROWS ) + return; + + /* Jump scroll to make the specified setting visible. */ + while ( widget->first_visible < n ) + widget->first_visible += SETTINGS_LIST_ROWS; + while ( widget->first_visible > n ) + widget->first_visible -= SETTINGS_LIST_ROWS; + + /* Draw elipses before and/or after the settings list to + represent any invisible settings. */ + mvaddstr ( SETTINGS_LIST_ROW - 1, + SETTINGS_LIST_COL + 1, + widget->first_visible > 0 ? "..." : " " ); + mvaddstr ( SETTINGS_LIST_ROW + SETTINGS_LIST_ROWS, + SETTINGS_LIST_COL + 1, + ( widget->first_visible + SETTINGS_LIST_ROWS < NUM_SETTINGS + ? "..." + : " " ) ); + + /* Draw visible settings. */ + for ( i = 0; i < SETTINGS_LIST_ROWS; i++ ) { + if ( widget->first_visible + i < NUM_SETTINGS ) { + select_setting ( widget, widget->first_visible + i ); + draw_setting ( widget ); + } else { + clearmsg ( SETTINGS_LIST_ROW + i ); + } + } + + /* Set the widget to the current row, which will be redrawn + appropriately by the main loop. */ + select_setting ( widget, n ); +} + static int main_loop ( struct settings *settings ) { struct setting_widget widget; unsigned int current = 0; unsigned int next; - int i; int key; int rc; /* Print initial screen content */ draw_title_row(); color_set ( CPAIR_NORMAL, NULL ); - for ( i = ( NUM_SETTINGS - 1 ) ; i >= 0 ; i-- ) { - init_setting_index ( &widget, settings, i ); - draw_setting ( &widget ); - } - + init_widget ( &widget, settings ); + while ( 1 ) { /* Redraw information and instruction rows */ draw_info_row ( widget.setting ); @@ -385,11 +424,11 @@ static int main_loop ( struct settings *settings ) { switch ( key ) { case KEY_DOWN: if ( next < ( NUM_SETTINGS - 1 ) ) - next++; + reveal ( &widget, ++next ); break; case KEY_UP: if ( next > 0 ) - next--; + reveal ( &widget, --next ) ; break; case CTRL_X: return 0; @@ -399,7 +438,7 @@ static int main_loop ( struct settings *settings ) { } if ( next != current ) { draw_setting ( &widget ); - init_setting_index ( &widget, settings, next ); + select_setting ( &widget, next ); current = next; } } -- 1.7.0.4 >From dbdf24ef2d3db34db08460402137bcbe4e58e37d Mon Sep 17 00:00:00 2001 From: Glenn Brown <gl...@myri.com> Date: Sun, 20 Jun 2010 22:52:07 -0700 Subject: [PATCH 3/4] [settings_ui] Add setting deletion (Ctrl-D) interface Make Ctrl-D delete a settings, because the Text User Interface (tui) previously provided no way to delete a setting. Also, update the on-screen instructions to describe the new feature. Deleting settings is especially important for settings stored in precious nonvolatile storate. Signed-off-by: Glenn Brown <gl...@myri.com> --- src/hci/tui/settings_ui.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/src/hci/tui/settings_ui.c b/src/hci/tui/settings_ui.c index 61ea3e4..1915e58 100644 --- a/src/hci/tui/settings_ui.c +++ b/src/hci/tui/settings_ui.c @@ -326,6 +326,7 @@ static void draw_instruction_row ( int editing ) { "Ctrl-C - discard changes" ); } else { msg ( INSTRUCTION_ROW, + "Ctrl-D - delete setting" INSTRUCTION_PAD "Ctrl-X - exit configuration utility" ); } } @@ -430,6 +431,12 @@ static int main_loop ( struct settings *settings ) { if ( next > 0 ) reveal ( &widget, --next ) ; break; + case CTRL_D: + delete_setting ( widget.settings, + widget.setting ); + select_setting ( &widget, next ); + draw_setting ( &widget ); + break; case CTRL_X: return 0; default: -- 1.7.0.4 >From a6697dbc0ab262addd2e9fe57e9820b70b557230 Mon Sep 17 00:00:00 2001 From: Glenn Brown <gl...@myri.com> Date: Sun, 20 Jun 2010 22:57:41 -0700 Subject: [PATCH 4/4] [myri10ge] Add NonVolatile Option (nvo) support Add NonVolatile Option (nvo) and NonVolatile Storage (nvs) support to the myri10ge driver using the EEPROM read/write mechanism provided by the NIC's Vendor Specific PCI capability. The myri10ge NIC is capabile of storing 64KB or more of nonvolatile options, but this patch advertises only 512 bytes of nvo storage because gPXE malloc's a buffer matching the total size we advertise. 512 is plenty without wasting malloc'd memory. (The 2 other drivers currently supporting nvo advertise 256 bytes or less.) Signed-off-by: Glenn Brown <gl...@myri.com> --- src/drivers/net/myri10ge.c | 325 ++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 314 insertions(+), 11 deletions(-) diff --git a/src/drivers/net/myri10ge.c b/src/drivers/net/myri10ge.c index 353158b..99bc272 100644 --- a/src/drivers/net/myri10ge.c +++ b/src/drivers/net/myri10ge.c @@ -55,6 +55,12 @@ FILE_LICENCE ( GPL2_ONLY ); * 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 + * gPXE it may store NonVolatile Options (nvo) there. */ /* @@ -75,6 +81,8 @@ FILE_LICENCE ( GPL2_ONLY ); #include <gpxe/iobuf.h> #include <gpxe/malloc.h> #include <gpxe/netdevice.h> +#include <gpxe/nvo.h> +#include <gpxe/nvs.h> #include <gpxe/pci.h> #include <gpxe/timer.h> @@ -169,6 +177,18 @@ struct myri10ge_private 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_fragment nvo_fragment[2]; + struct nvo_block nvo; + + /* Cached PCI capability locations. */ + + uint8 pci_cap_vs; }; /**************************************************************** @@ -199,6 +219,28 @@ static inline struct myri10ge_private *myri10ge_priv ( struct net_device *nd ) } /* + * 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. @@ -381,12 +423,16 @@ static void myri10ge_interrupt_handler ( struct net_device *netdev ) /* 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 @@ -394,28 +440,21 @@ static void myri10ge_interrupt_handler ( struct net_device *netdev ) * 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, - uint8 mac[ETH_ALEN] ) + unsigned int vs, + uint8 mac[ETH_ALEN] ) { char string_specs[256]; char *ptr, *limit; char *to = string_specs; uint32 addr; uint32 len; - unsigned int vs; int mac_set = 0; - /* Find the "vendor specific" capability. */ - - vs = pci_find_capability ( pci, 9 ); - if ( vs == 0 ) { - DBG ( "no VS\n" ); - return -ENOTSUP; - } - /* Locate the String specs in LANai SRAM. */ pci_write_config_byte ( pci, VS_MODE, VS_MODE_LOCATE ); @@ -427,6 +466,7 @@ static int mac_address_from_string_specs ( struct pci_device *pci, /* 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; } @@ -484,6 +524,247 @@ static int mac_address_from_string_specs ( struct pci_device *pci, } /**************************************************************** + * 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 = bswap_32 ( hdr.eeprom_len ); + hdr.eeprom_segment_len = bswap_32 ( hdr.eeprom_segment_len ); + hdr.mcp2_offset = bswap_32 ( hdr.mcp2_offset ); + hdr.version = bswap_32 ( hdr.version ); + DBG2 ( "eelen:%xh seglen:%xh m...@%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 = bswap_32 ( 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; + } + + /* Initilize 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; + + /* Build the NonVolatile storage fragment list. We would like + to use the whole last EEPROM block for this, but we must + reduce the block size lest malloc fail in + src/core/nvo.o. */ + + priv->nvo_fragment[0].address = nvo_fragment_pos; + priv->nvo_fragment[0].len = 0x200; + + /* Register the NonVolatile Options storage. */ + + nvo_init ( &priv->nvo, + &priv->nvs, + priv->nvo_fragment, + & myri10ge_netdev (priv) -> refcnt ); + rc = register_nvo ( &priv->nvo, + netdev_settings ( myri10ge_netdev ( priv ) ) ); + if ( rc ) { + DBG ("register_nvo failed"); + priv->nvo_fragment[0].len = 0; + return rc; + } + + 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_fragment[0].len ) + return; + + unregister_nvo ( &priv->nvo ); +} + +/**************************************************************** * gPXE PCI Device Driver API functions ****************************************************************/ @@ -532,9 +813,20 @@ static int myri10ge_pci_probe ( struct pci_device *pci, myri10ge_net_irq ( netdev, 0 ); + /* Find the PCI Vendor-Specific capability. */ + + priv->pci_cap_vs = pci_find_capability ( pci , PCI_CAP_ID_VS ); + 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, netdev->hw_addr ); + 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; @@ -554,10 +846,20 @@ static int myri10ge_pci_probe ( struct pci_device *pci, 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 ); @@ -580,6 +882,7 @@ static void myri10ge_pci_remove ( struct pci_device *pci ) 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 ); -- 1.7.0.4
<<attachment: gpxe_config.gif>>
_______________________________________________ gPXE mailing list gPXE@etherboot.org http://etherboot.org/mailman/listinfo/gpxe