mirror of
https://github.com/xcat2/xNBA.git
synced 2024-12-14 07:11:32 +00:00
Add the concept of a fragment list for non-volatile stored options.
This commit is contained in:
parent
f944737045
commit
cc9bcb99a0
129
src/core/nvo.c
129
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 );
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user