summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brown2006-12-04 22:46:13 +0100
committerMichael Brown2006-12-04 22:46:13 +0100
commitcc9bcb99a0ac2460dbe8286731e65812fa4ef870 (patch)
treeb2beaafcde77c3502ed7a61dbd139c94455d2e92 /src
parentFixed two logic errors that were cancelling each other out. (diff)
downloadipxe-cc9bcb99a0ac2460dbe8286731e65812fa4ef870.tar.gz
ipxe-cc9bcb99a0ac2460dbe8286731e65812fa4ef870.tar.xz
ipxe-cc9bcb99a0ac2460dbe8286731e65812fa4ef870.zip
Add the concept of a fragment list for non-volatile stored options.
Diffstat (limited to 'src')
-rw-r--r--src/core/nvo.c129
-rw-r--r--src/drivers/net/etherfabric.c17
-rw-r--r--src/include/gpxe/nvo.h28
3 files changed, 135 insertions, 39 deletions
diff --git a/src/core/nvo.c b/src/core/nvo.c
index 9bd92526..a130329f 100644
--- a/src/core/nvo.c
+++ b/src/core/nvo.c
@@ -28,79 +28,146 @@
*
*/
-static size_t nvo_options_len ( struct nvs_options *nvo ) {
+/**
+ * Calculate total length of non-volatile stored options
+ *
+ * @v nvo Non-volatile options block
+ * @ret total_len Total length of all fragments
+ */
+static size_t nvo_total_len ( struct nvo_block *nvo ) {
+ struct nvo_fragment *fragment = nvo->fragments;
+ size_t total_len = 0;
+
+ for ( ; fragment->len ; fragment++ ) {
+ total_len += fragment->len;
+ }
+
+ return total_len;
+}
+
+/**
+ * Read non-volatile stored options from non-volatile storage device
+ *
+ * @v nvo Non-volatile options block
+ * @ret rc Return status code
+ */
+static int nvo_read ( struct nvo_block *nvo ) {
+ struct nvo_fragment *fragment = nvo->fragments;
+ void *data = nvo->options->data;
+ int rc;
+
+ for ( ; fragment->len ; fragment++ ) {
+ if ( ( rc = nvs_read ( nvo->nvs, fragment->address,
+ data, fragment->len ) ) != 0 ) {
+ DBG ( "NVO %p could not read %zd bytes at %#04x\n",
+ nvo, fragment->len, fragment->address );
+ return rc;
+ }
+ data += fragment->len;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse stored options
+ *
+ * @v nvo Non-volatile options block
+ * @v total_len Total length of options data
+ *
+ * Verifies that the options data is valid, and configures the DHCP
+ * options block. If the data is not valid, it is replaced with an
+ * empty options block.
+ */
+static void nvo_init_dhcp ( struct nvo_block *nvo, size_t total_len ) {
+ struct dhcp_option_block *options = nvo->options;
struct dhcp_option *option;
uint8_t sum;
unsigned int i;
- size_t len;
- for ( sum = 0, i = 0 ; i < nvo->nvs->size ; i++ ) {
- sum += * ( ( uint8_t * ) ( nvo->options->data + i ) );
+ /* Steal one byte for the checksum */
+ options->max_len = ( total_len - 1 );
+
+ /* Verify checksum over whole block */
+ for ( sum = 0, i = 0 ; i < total_len ; i++ ) {
+ sum += * ( ( uint8_t * ) ( options->data + i ) );
}
if ( sum != 0 ) {
DBG ( "NVO %p has bad checksum %02x; assuming empty\n",
nvo, sum );
- return 0;
+ goto empty;
}
- option = nvo->options->data;
+ /* Check that we don't just have a block full of zeroes */
+ option = options->data;
if ( option->tag == DHCP_PAD ) {
DBG ( "NVO %p has bad start; assuming empty\n", nvo );
- return 0;
+ goto empty;
}
- option = find_dhcp_option ( nvo->options, DHCP_END );
+ /* Search for the DHCP_END tag */
+ options->len = options->max_len;
+ option = find_dhcp_option ( options, DHCP_END );
if ( ! option ) {
DBG ( "NVO %p has no end tag; assuming empty\n", nvo );
- return 0;
+ goto empty;
}
- len = ( ( void * ) option - nvo->options->data + 1 );
+ /* Set correct length of DHCP options */
+ options->len = ( ( void * ) option - options->data + 1 );
DBG ( "NVO %p contains %zd bytes of options (maximum %zd)\n",
- nvo, len, nvo->nvs->size );
+ nvo, options->len, options->max_len );
+ return;
- return len;
+ empty:
+ /* No options found; initialise an empty options block */
+ option = options->data;
+ option->tag = DHCP_END;
+ options->len = 1;
+ return;
}
-int nvo_register ( struct nvs_options *nvo ) {
- struct dhcp_option *option;
+/**
+ * Register non-volatile stored options
+ *
+ * @v nvo Non-volatile options block
+ * @ret rc Return status code
+ */
+int nvo_register ( struct nvo_block *nvo ) {
+ size_t total_len;
int rc;
- nvo->options = alloc_dhcp_options ( nvo->nvs->size );
+ /* Allocate memory for options and read in from NVS */
+ total_len = nvo_total_len ( nvo );
+ nvo->options = alloc_dhcp_options ( total_len );
if ( ! nvo->options ) {
DBG ( "NVO %p could not allocate %zd bytes\n",
- nvo, nvo->nvs->size );
+ nvo, total_len );
rc = -ENOMEM;
goto err;
}
- if ( ( rc = nvo->nvs->read ( nvo->nvs, 0, nvo->options->data,
- nvo->nvs->size ) ) != 0 ) {
- DBG ( "NVO %p could not read [0,%zd)\n",
- nvo, nvo->nvs->size );
+ if ( ( rc = nvo_read ( nvo ) ) != 0 )
goto err;
- }
-
- nvo->options->len = nvo->options->max_len;
- nvo->options->len = nvo_options_len ( nvo );
- if ( ! nvo->options->len ) {
- option = nvo->options->data;
- option->tag = DHCP_END;
- nvo->options->len = 1;
- }
+ /* Verify and register options */
+ nvo_init_dhcp ( nvo, total_len );
register_dhcp_options ( nvo->options );
return 0;
err:
-
free_dhcp_options ( nvo->options );
nvo->options = NULL;
return rc;
}
-void nvo_unregister ( struct nvs_options *nvo ) {
+/**
+ * Unregister non-volatile stored options
+ *
+ * @v nvo Non-volatile options block
+ */
+void nvo_unregister ( struct nvo_block *nvo ) {
if ( nvo->options ) {
unregister_dhcp_options ( nvo->options );
free_dhcp_options ( nvo->options );
diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c
index 17897666..b6ffc70c 100644
--- a/src/drivers/net/etherfabric.c
+++ b/src/drivers/net/etherfabric.c
@@ -23,6 +23,7 @@
#include <gpxe/bitbash.h>
#include <gpxe/i2c.h>
#include <gpxe/spi.h>
+#include <gpxe/nvo.h>
#include "timer.h"
#define dma_addr_t unsigned long
#include "etherfabric.h"
@@ -217,6 +218,9 @@ struct efab_nic {
struct spi_bus spi;
struct spi_device falcon_flash;
struct spi_device falcon_eeprom;
+
+ /** Non-volatile options */
+ struct nvo_block nvo;
};
/**************************************************************************
@@ -2304,6 +2308,11 @@ static void falcon_init_spi ( struct efab_nic *efab ) {
/** Offset of MAC address within EEPROM or Flash */
#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) )
+static struct nvo_fragment falcon_eeprom_fragments[] = {
+ { 0, 0x100 },
+ { 0, 0 }
+};
+
/**
* Read MAC address from EEPROM
*
@@ -2972,12 +2981,10 @@ static int falcon_init_nic ( struct efab_nic *efab ) {
/* Register non-volatile storage */
if ( efab->has_eeprom ) {
- /*
- efab->nvs.op = &falcon_nvs_operations;
- efab->nvs.len = 0x100;
- if ( nvs_register ( &efab->nvs ) != 0 )
+ efab->nvo.nvs = &efab->falcon_eeprom.nvs;
+ efab->nvo.fragments = falcon_eeprom_fragments;
+ if ( nvo_register ( &efab->nvo ) != 0 )
return 0;
- */
}
return 1;
diff --git a/src/include/gpxe/nvo.h b/src/include/gpxe/nvo.h
index b51431aa..f766508c 100644
--- a/src/include/gpxe/nvo.h
+++ b/src/include/gpxe/nvo.h
@@ -7,15 +7,37 @@
*
*/
+#include <stdint.h>
+
struct nvs_device;
struct dhcp_option_block;
-struct nvs_options {
+/**
+ * A fragment of a non-volatile storage device used for stored options
+ */
+struct nvo_fragment {
+ /** Starting address of fragment within NVS device */
+ unsigned int address;
+ /** Length of fragment */
+ size_t len;
+};
+
+/**
+ * A block of non-volatile stored options
+ */
+struct nvo_block {
+ /** Underlying non-volatile storage device */
struct nvs_device *nvs;
+ /** List of option-containing fragments
+ *
+ * The list is terminated by a fragment with a length of zero.
+ */
+ struct nvo_fragment *fragments;
+ /** DHCP options block */
struct dhcp_option_block *options;
};
-extern int nvo_register ( struct nvs_options *nvo );
-extern void nvo_unregister ( struct nvs_options *nvo );
+extern int nvo_register ( struct nvo_block *nvo );
+extern void nvo_unregister ( struct nvo_block *nvo );
#endif /* _GPXE_NVO_H */