mirror of
https://github.com/ipxe/ipxe
synced 2026-02-14 02:31:26 +03:00
[bofm] Add core BOFM library
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -75,6 +75,7 @@ SRCDIRS += drivers/nvs
|
|||||||
SRCDIRS += drivers/bitbash
|
SRCDIRS += drivers/bitbash
|
||||||
SRCDIRS += drivers/infiniband
|
SRCDIRS += drivers/infiniband
|
||||||
SRCDIRS += interface/pxe interface/efi interface/smbios
|
SRCDIRS += interface/pxe interface/efi interface/smbios
|
||||||
|
SRCDIRS += interface/bofm
|
||||||
SRCDIRS += tests
|
SRCDIRS += tests
|
||||||
SRCDIRS += crypto crypto/axtls crypto/matrixssl
|
SRCDIRS += crypto crypto/axtls crypto/matrixssl
|
||||||
SRCDIRS += hci hci/commands hci/tui
|
SRCDIRS += hci hci/commands hci/tui
|
||||||
|
|||||||
341
src/include/ipxe/bofm.h
Normal file
341
src/include/ipxe/bofm.h
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
#ifndef _IPXE_BOFM_H
|
||||||
|
#define _IPXE_BOFM_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* IBM BladeCenter Open Fabric Manager (BOFM)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <ipxe/list.h>
|
||||||
|
#include <ipxe/pci.h>
|
||||||
|
|
||||||
|
/** 'IBM ' signature
|
||||||
|
*
|
||||||
|
* Present in %edi when the BIOS initialisation entry point is called,
|
||||||
|
* with the BOFM table pointer in %esi.
|
||||||
|
*
|
||||||
|
* Defined in section 4.1.2 of the POST/BIOS BOFM I/O Address
|
||||||
|
* Re-Assignment Architecture document.
|
||||||
|
*/
|
||||||
|
#define IBMs_SIGNATURE ( ( 'I' << 24 ) + ( 'B' << 16 ) + ( 'M' << 8 ) + ' ' )
|
||||||
|
|
||||||
|
/** ' IBM' signature
|
||||||
|
*
|
||||||
|
* Returned in %edi from the BIOS initialisation entry point, with the
|
||||||
|
* return code in %dl.
|
||||||
|
*
|
||||||
|
* Defined in section 4.1.2 of the POST/BIOS BOFM I/O Address
|
||||||
|
* Re-Assignment Architecture document.
|
||||||
|
*/
|
||||||
|
#define sIBM_SIGNATURE ( ( ' ' << 24 ) + ( 'I' << 16 ) + ( 'B' << 8 ) + 'M' )
|
||||||
|
|
||||||
|
/** @defgroup bofmrc BOFM return codes
|
||||||
|
*
|
||||||
|
* Defined in section 4.1.3 of the POST/BIOS BOFM I/O Address
|
||||||
|
* Re-Assignment Architecture document.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Successful */
|
||||||
|
#define BOFM_SUCCESS 0x00
|
||||||
|
|
||||||
|
/** Invalid action string */
|
||||||
|
#define BOFM_ERR_INVALID_ACTION 0x01
|
||||||
|
|
||||||
|
/** Unsupported parameter structure version */
|
||||||
|
#define BOFM_ERR_UNSUPPORTED 0x02
|
||||||
|
|
||||||
|
/** Device error prohibited MAC/WWN update */
|
||||||
|
#define BOFM_ERR_DEVICE_ERROR 0x03
|
||||||
|
|
||||||
|
/** PCI reset required (may be combined with another return code) */
|
||||||
|
#define BOFM_PCI_RESET 0x80
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** Skip option ROM initialisation
|
||||||
|
*
|
||||||
|
* A BOFM BIOS may call the initialisation entry point multiple times;
|
||||||
|
* only the last call should result in actual initialisation.
|
||||||
|
*
|
||||||
|
* This flag is internal to iPXE.
|
||||||
|
*/
|
||||||
|
#define BOFM_SKIP_INIT 0x80000000UL
|
||||||
|
|
||||||
|
/** BOFM table header
|
||||||
|
*
|
||||||
|
* Defined in section 4.1 of the Open Fabric Manager Parameter
|
||||||
|
* Specification document.
|
||||||
|
*/
|
||||||
|
struct bofm_global_header {
|
||||||
|
/** Signature */
|
||||||
|
uint32_t magic;
|
||||||
|
/** Subsignature (action string) */
|
||||||
|
uint32_t action;
|
||||||
|
/** Data structure version */
|
||||||
|
uint8_t version;
|
||||||
|
/** Data structure level */
|
||||||
|
uint8_t level;
|
||||||
|
/** Data structure length */
|
||||||
|
uint16_t length;
|
||||||
|
/** Data structure checksum */
|
||||||
|
uint8_t checksum;
|
||||||
|
/** Data structure profile */
|
||||||
|
char profile[32];
|
||||||
|
/** Data structure global options */
|
||||||
|
uint32_t options;
|
||||||
|
/** Data structure sequence stamp */
|
||||||
|
uint32_t sequence;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** BOFM table header signature
|
||||||
|
*
|
||||||
|
* Defined in section 4.1.2 of the POST/BIOS BOFM I/O Address
|
||||||
|
* Re-Assignment Architecture document.
|
||||||
|
*/
|
||||||
|
#define BOFM_IOAA_MAGIC ( 'I' + ( 'O' << 8 ) + ( 'A' << 16 ) + ( 'A' << 24 ) )
|
||||||
|
|
||||||
|
/** @defgroup bofmaction BOFM header subsignatures (action strings)
|
||||||
|
*
|
||||||
|
* Defined in section 4.1.2 of the POST/BIOS BOFM I/O Address
|
||||||
|
* Re-Assignment Architecture document.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Update MAC/WWN */
|
||||||
|
#define BOFM_ACTION_UPDT ( 'U' + ( 'P' << 8 ) + ( 'D' << 16 ) + ( 'T' << 24 ) )
|
||||||
|
|
||||||
|
/** Restore MAC/WWN to factory default */
|
||||||
|
#define BOFM_ACTION_DFLT ( 'D' + ( 'F' << 8 ) + ( 'L' << 16 ) + ( 'T' << 24 ) )
|
||||||
|
|
||||||
|
/** Harvest MAC/WWN */
|
||||||
|
#define BOFM_ACTION_HVST ( 'H' + ( 'V' << 8 ) + ( 'S' << 16 ) + ( 'T' << 24 ) )
|
||||||
|
|
||||||
|
/** Update MAC/WWN and initialise device */
|
||||||
|
#define BOFM_ACTION_PARM ( 'P' + ( 'A' << 8 ) + ( 'R' << 16 ) + ( 'M' << 24 ) )
|
||||||
|
|
||||||
|
/** Just initialise the device */
|
||||||
|
#define BOFM_ACTION_NONE ( 'N' + ( 'O' << 8 ) + ( 'N' << 16 ) + ( 'E' << 24 ) )
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** BOFM section header
|
||||||
|
*
|
||||||
|
* Defined in section 4.2 of the Open Fabric Manager Parameter
|
||||||
|
* Specification document.
|
||||||
|
*/
|
||||||
|
struct bofm_section_header {
|
||||||
|
/** Signature */
|
||||||
|
uint32_t magic;
|
||||||
|
/** Length */
|
||||||
|
uint16_t length;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** @defgroup bofmsections BOFM section header signatures
|
||||||
|
*
|
||||||
|
* Defined in section 4.2 of the Open Fabric Manager Parameter
|
||||||
|
* Specification document.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** EN start marker */
|
||||||
|
#define BOFM_EN_MAGIC ( ' ' + ( ' ' << 8 ) + ( 'E' << 16 ) + ( 'N' << 24 ) )
|
||||||
|
|
||||||
|
/** End marker */
|
||||||
|
#define BOFM_DONE_MAGIC ( 'D' + ( 'O' << 8 ) + ( 'N' << 16 ) + ( 'E' << 24 ) )
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** BOFM Ethernet parameter entry
|
||||||
|
*
|
||||||
|
* Defined in section 5.1 of the Open Fabric Manager Parameter
|
||||||
|
* Specification document.
|
||||||
|
*/
|
||||||
|
struct bofm_en {
|
||||||
|
/** Options */
|
||||||
|
uint16_t options;
|
||||||
|
/** PCI bus:dev.fn
|
||||||
|
*
|
||||||
|
* Valid only if @c options indicates @c BOFM_EN_MAP_PFA
|
||||||
|
*/
|
||||||
|
uint16_t busdevfn;
|
||||||
|
/** Slot or mezzanine number
|
||||||
|
*
|
||||||
|
* Valid only if @c options indicates @c BOFM_EN_MAP_SLOT_PORT
|
||||||
|
*/
|
||||||
|
uint8_t slot;
|
||||||
|
/** Port number
|
||||||
|
*
|
||||||
|
* Valid only if @c options indicates @c BOFM_EN_MAP_SLOT_PORT
|
||||||
|
*/
|
||||||
|
uint8_t port;
|
||||||
|
/** Multi-port index */
|
||||||
|
uint8_t mport;
|
||||||
|
/** VLAN tag for MAC address A */
|
||||||
|
uint16_t vlan_a;
|
||||||
|
/** MAC address A
|
||||||
|
*
|
||||||
|
* MAC address A is the sole MAC address, or the lower
|
||||||
|
* (inclusive) bound of a range of MAC addresses.
|
||||||
|
*/
|
||||||
|
uint8_t mac_a[6];
|
||||||
|
/** VLAN tag for MAC address B */
|
||||||
|
uint16_t vlan_b;
|
||||||
|
/** MAC address B
|
||||||
|
*
|
||||||
|
* MAC address B is unset, or the upper (inclusive) bound of a
|
||||||
|
* range of MAC addresses
|
||||||
|
*/
|
||||||
|
uint8_t mac_b[6];
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** @defgroup bofmenopts BOFM Ethernet parameter entry options
|
||||||
|
*
|
||||||
|
* Defined in section 5.1 of the Open Fabric Manager Parameter
|
||||||
|
* Specification document.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Port mapping mask */
|
||||||
|
#define BOFM_EN_MAP_MASK 0x0001
|
||||||
|
|
||||||
|
/** Port mapping is by PCI bus:dev.fn */
|
||||||
|
#define BOFM_EN_MAP_PFA 0x0000
|
||||||
|
|
||||||
|
/** Port mapping is by slot/port */
|
||||||
|
#define BOFM_EN_MAP_SLOT_PORT 0x0001
|
||||||
|
|
||||||
|
/** MAC address B is present */
|
||||||
|
#define BOFM_EN_EN_B 0x0002
|
||||||
|
|
||||||
|
/** VLAN tag for MAC address B is present */
|
||||||
|
#define BOFM_EN_VLAN_B 0x0004
|
||||||
|
|
||||||
|
/** MAC address A is present */
|
||||||
|
#define BOFM_EN_EN_A 0x0008
|
||||||
|
|
||||||
|
/** VLAN tag for MAC address A is present */
|
||||||
|
#define BOFM_EN_VLAN_A 0x0010
|
||||||
|
|
||||||
|
/** Entry consumption indicator mask */
|
||||||
|
#define BOFM_EN_CSM_MASK 0x00c0
|
||||||
|
|
||||||
|
/** Entry has not been used */
|
||||||
|
#define BOFM_EN_CSM_UNUSED 0x0000
|
||||||
|
|
||||||
|
/** Entry has been used successfully */
|
||||||
|
#define BOFM_EN_CSM_SUCCESS 0x0040
|
||||||
|
|
||||||
|
/** Entry has been used but failed */
|
||||||
|
#define BOFM_EN_CSM_FAILED 0x0080
|
||||||
|
|
||||||
|
/** Consumed entry change mask */
|
||||||
|
#define BOFM_EN_CHG_MASK 0x0100
|
||||||
|
|
||||||
|
/** Consumed entry is same as previous active entry */
|
||||||
|
#define BOFM_EN_CHG_UNCHANGED 0x0000
|
||||||
|
|
||||||
|
/** Consumed entry is different than previous active entry */
|
||||||
|
#define BOFM_EN_CHG_CHANGED 0x0100
|
||||||
|
|
||||||
|
/** Ignore values - it's harvest time */
|
||||||
|
#define BOFM_EN_USAGE_HARVEST 0x1000
|
||||||
|
|
||||||
|
/** Use entry values for assignment */
|
||||||
|
#define BOFM_EN_USAGE_ENTRY 0x0800
|
||||||
|
|
||||||
|
/** Use factory default values */
|
||||||
|
#define BOFM_EN_USAGE_DEFAULT 0x0400
|
||||||
|
|
||||||
|
/** Harvest complete */
|
||||||
|
#define BOFM_EN_HVST 0x2000
|
||||||
|
|
||||||
|
/** Harvest request mask */
|
||||||
|
#define BOFM_EN_RQ_HVST_MASK 0xc000
|
||||||
|
|
||||||
|
/** Do not harvest */
|
||||||
|
#define BOFM_EN_RQ_HVST_NONE 0x0000
|
||||||
|
|
||||||
|
/** Harvest factory default values */
|
||||||
|
#define BOFM_EN_RQ_HVST_DEFAULT 0x4000
|
||||||
|
|
||||||
|
/** Harvest active values */
|
||||||
|
#define BOFM_EN_RQ_HVST_ACTIVE 0xc000
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/** BOFM magic value debug message format */
|
||||||
|
#define BOFM_MAGIC_FMT "'%c%c%c%c'"
|
||||||
|
|
||||||
|
/** BOFM magic value debug message arguments */
|
||||||
|
#define BOFM_MAGIC_ARGS( magic ) \
|
||||||
|
( ( (magic) >> 0 ) & 0xff ), ( ( (magic) >> 8 ) & 0xff ), \
|
||||||
|
( ( (magic) >> 16 ) & 0xff ), ( ( (magic) >> 24 ) & 0xff )
|
||||||
|
|
||||||
|
/** A BOFM device */
|
||||||
|
struct bofm_device {
|
||||||
|
/** Underlying PCI device */
|
||||||
|
struct pci_device *pci;
|
||||||
|
/** BOFM device operations */
|
||||||
|
struct bofm_operations *op;
|
||||||
|
/** List of BOFM devices */
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** BOFM device operations */
|
||||||
|
struct bofm_operations {
|
||||||
|
/** Harvest Ethernet MAC
|
||||||
|
*
|
||||||
|
* @v bofm BOFM device
|
||||||
|
* @v mport Multi-port index
|
||||||
|
* @v mac MAC to fill in
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int ( * harvest ) ( struct bofm_device *bofm, unsigned int mport,
|
||||||
|
uint8_t *mac );
|
||||||
|
/** Update Ethernet MAC
|
||||||
|
*
|
||||||
|
* @v bofm BOFM device
|
||||||
|
* @v mport Multi-port index
|
||||||
|
* @v mac New MAC
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int ( * update ) ( struct bofm_device *bofm, unsigned int mport,
|
||||||
|
const uint8_t *mac );
|
||||||
|
};
|
||||||
|
|
||||||
|
/** BOFM driver table */
|
||||||
|
#define BOFM_DRIVERS __table ( struct pci_driver, "bofm_drivers" )
|
||||||
|
|
||||||
|
/** Declare a BOFM driver */
|
||||||
|
#define __bofm_driver __table_entry ( BOFM_DRIVERS, 01 )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise BOFM device
|
||||||
|
*
|
||||||
|
* @v bofm BOFM device
|
||||||
|
* @v pci PCI device
|
||||||
|
* @v op BOFM device operations
|
||||||
|
*/
|
||||||
|
static inline __attribute__ (( always_inline )) void
|
||||||
|
bofm_init ( struct bofm_device *bofm, struct pci_device *pci,
|
||||||
|
struct bofm_operations *op ) {
|
||||||
|
bofm->pci = pci;
|
||||||
|
bofm->op = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int bofm_register ( struct bofm_device *bofm );
|
||||||
|
extern void bofm_unregister ( struct bofm_device *bofm );
|
||||||
|
extern int bofm_find_driver ( struct pci_device *pci );
|
||||||
|
extern int bofm ( userptr_t bofmtab, struct pci_device *pci );
|
||||||
|
|
||||||
|
#endif /* _IPXE_BOFM_H */
|
||||||
@@ -236,6 +236,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||||||
#define ERRFILE_fcmgmt_cmd ( ERRFILE_OTHER | 0x001e0000 )
|
#define ERRFILE_fcmgmt_cmd ( ERRFILE_OTHER | 0x001e0000 )
|
||||||
#define ERRFILE_gdbstub_cmd ( ERRFILE_OTHER | 0x001f0000 )
|
#define ERRFILE_gdbstub_cmd ( ERRFILE_OTHER | 0x001f0000 )
|
||||||
#define ERRFILE_sanboot_cmd ( ERRFILE_OTHER | 0x00200000 )
|
#define ERRFILE_sanboot_cmd ( ERRFILE_OTHER | 0x00200000 )
|
||||||
|
#define ERRFILE_bofm ( ERRFILE_OTHER | 0x00210000 )
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|||||||
335
src/interface/bofm/bofm.c
Normal file
335
src/interface/bofm/bofm.c
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or any later version.
|
||||||
|
*
|
||||||
|
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ipxe/uaccess.h>
|
||||||
|
#include <ipxe/list.h>
|
||||||
|
#include <ipxe/ethernet.h>
|
||||||
|
#include <ipxe/bofm.h>
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
*
|
||||||
|
* IBM BladeCenter Open Fabric Manager (BOFM)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** List of BOFM devices */
|
||||||
|
static LIST_HEAD ( bofmdevs );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register BOFM device
|
||||||
|
*
|
||||||
|
* @v bofm BOFM device
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int bofm_register ( struct bofm_device *bofm ) {
|
||||||
|
|
||||||
|
list_add ( &bofm->list, &bofmdevs );
|
||||||
|
DBG ( "BOFM: " PCI_FMT " registered using driver \"%s\"\n",
|
||||||
|
PCI_ARGS ( bofm->pci ), bofm->pci->id->name );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister BOFM device
|
||||||
|
*
|
||||||
|
* @v bofm BOFM device
|
||||||
|
*/
|
||||||
|
void bofm_unregister ( struct bofm_device *bofm ) {
|
||||||
|
|
||||||
|
list_del ( &bofm->list );
|
||||||
|
DBG ( "BOFM: " PCI_FMT " unregistered\n", PCI_ARGS ( bofm->pci ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find BOFM device matching PCI bus:dev.fn address
|
||||||
|
*
|
||||||
|
* @v busdevfn PCI bus:dev.fn address
|
||||||
|
* @ret bofm BOFM device, or NULL
|
||||||
|
*/
|
||||||
|
static struct bofm_device * bofm_find_busdevfn ( unsigned int busdevfn ) {
|
||||||
|
struct bofm_device *bofm;
|
||||||
|
|
||||||
|
list_for_each_entry ( bofm, &bofmdevs, list ) {
|
||||||
|
if ( bofm->pci->busdevfn == busdevfn )
|
||||||
|
return bofm;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find BOFM driver for PCI device
|
||||||
|
*
|
||||||
|
* @v pci PCI device
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int bofm_find_driver ( struct pci_device *pci ) {
|
||||||
|
struct pci_driver *driver;
|
||||||
|
struct pci_device_id *id;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for_each_table_entry ( driver, BOFM_DRIVERS ) {
|
||||||
|
for ( i = 0 ; i < driver->id_count ; i++ ) {
|
||||||
|
id = &driver->ids[i];
|
||||||
|
if ( ( id->vendor == pci->vendor ) &&
|
||||||
|
( id->device == pci->device ) ) {
|
||||||
|
pci_set_driver ( pci, driver, id );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Probe PCI device for BOFM driver
|
||||||
|
*
|
||||||
|
* @v pci PCI device
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int bofm_probe ( struct pci_device *pci ) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Probe device */
|
||||||
|
if ( ( rc = pci_probe ( pci ) ) != 0 ) {
|
||||||
|
DBG ( "BOFM: " PCI_FMT " could not load driver: %s\n",
|
||||||
|
PCI_ARGS ( pci ), strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove PCI device
|
||||||
|
*
|
||||||
|
* @v pci PCI device
|
||||||
|
*/
|
||||||
|
static void bofm_remove ( struct pci_device *pci ) {
|
||||||
|
|
||||||
|
/* Note that the IBM BIOS may re-read the expansion ROM after
|
||||||
|
* the BOFM initialisation call. The BOFM driver must ensure
|
||||||
|
* that the card is left in a state in which expansion ROM
|
||||||
|
* reads will succeed. (For example, if a card contains an
|
||||||
|
* embedded CPU that may issue reads to the same underlying
|
||||||
|
* flash device, and these reads are not locked against reads
|
||||||
|
* via the expansion ROM BAR, then the CPU must be stopped.)
|
||||||
|
*
|
||||||
|
* If this is not done, then occasional corrupted reads from
|
||||||
|
* the expansion ROM will be seen, and the BIOS may complain
|
||||||
|
* about a ROM checksum error.
|
||||||
|
*/
|
||||||
|
pci_remove ( pci );
|
||||||
|
DBG ( "BOFM: " PCI_FMT " removed\n", PCI_ARGS ( pci ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate BOFM table section
|
||||||
|
*
|
||||||
|
* @v bofmtab BOFM table
|
||||||
|
* @v len Length of BOFM table
|
||||||
|
* @v magic Section magic
|
||||||
|
* @v bofmsec BOFM section header to fill in
|
||||||
|
* @ret offset Offset to section, or 0 if not found
|
||||||
|
*/
|
||||||
|
static size_t bofm_locate_section ( userptr_t bofmtab, size_t len,
|
||||||
|
uint32_t magic,
|
||||||
|
struct bofm_section_header *bofmsec ) {
|
||||||
|
size_t offset = sizeof ( struct bofm_global_header );
|
||||||
|
|
||||||
|
while ( offset < len ) {
|
||||||
|
copy_from_user ( bofmsec, bofmtab, offset,
|
||||||
|
sizeof ( *bofmsec ) );
|
||||||
|
if ( bofmsec->magic == magic )
|
||||||
|
return offset;
|
||||||
|
if ( bofmsec->magic == BOFM_DONE_MAGIC )
|
||||||
|
break;
|
||||||
|
offset += ( sizeof ( *bofmsec ) + bofmsec->length );
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process BOFM Ethernet parameter entry
|
||||||
|
*
|
||||||
|
* @v bofm BOFM device
|
||||||
|
* @v en EN parameter entry
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
|
||||||
|
uint8_t mac[6];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Retrieve current MAC address */
|
||||||
|
if ( ( rc = bofm->op->harvest ( bofm, en->mport, mac ) ) != 0 ) {
|
||||||
|
DBG ( "BOFM: " PCI_FMT " port %d could not harvest: %s\n",
|
||||||
|
PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Harvest MAC address if necessary */
|
||||||
|
if ( en->options & BOFM_EN_RQ_HVST_MASK ) {
|
||||||
|
DBG ( "BOFM: " PCI_FMT " port %d harvested MAC %s\n",
|
||||||
|
PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
|
||||||
|
memcpy ( en->mac_a, mac, sizeof ( en->mac_a ) );
|
||||||
|
en->options |= ( BOFM_EN_EN_A | BOFM_EN_HVST );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark as changed if necessary */
|
||||||
|
if ( ( en->options & BOFM_EN_EN_A ) &&
|
||||||
|
( memcmp ( en->mac_a, mac, sizeof ( en->mac_a ) ) != 0 ) ) {
|
||||||
|
DBG ( "BOFM: " PCI_FMT " port %d MAC %s",
|
||||||
|
PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
|
||||||
|
DBG ( " changed to %s\n", eth_ntoa ( en->mac_a ) );
|
||||||
|
en->options |= BOFM_EN_CHG_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply MAC address if necessary */
|
||||||
|
if ( ( en->options & BOFM_EN_EN_A ) &&
|
||||||
|
( en->options & BOFM_EN_USAGE_ENTRY ) &&
|
||||||
|
( ! ( en->options & BOFM_EN_USAGE_HARVEST ) ) ) {
|
||||||
|
DBG ( "BOFM: " PCI_FMT " port %d applied MAC %s\n",
|
||||||
|
PCI_ARGS ( bofm->pci ), en->mport,
|
||||||
|
eth_ntoa ( en->mac_a ) );
|
||||||
|
memcpy ( mac, en->mac_a, sizeof ( mac ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store MAC address */
|
||||||
|
if ( ( rc = bofm->op->update ( bofm, en->mport, mac ) ) != 0 ) {
|
||||||
|
DBG ( "BOFM: " PCI_FMT " port %d could not update: %s\n",
|
||||||
|
PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process BOFM table
|
||||||
|
*
|
||||||
|
* @v bofmtab BOFM table
|
||||||
|
* @v pci PCI device
|
||||||
|
* @ret bofmrc BOFM return status
|
||||||
|
*/
|
||||||
|
int bofm ( userptr_t bofmtab, struct pci_device *pci ) {
|
||||||
|
struct bofm_global_header bofmhdr;
|
||||||
|
struct bofm_section_header bofmsec;
|
||||||
|
struct bofm_en en;
|
||||||
|
struct bofm_device *bofm;
|
||||||
|
size_t en_region_offset;
|
||||||
|
size_t en_offset;
|
||||||
|
int skip;
|
||||||
|
int rc;
|
||||||
|
int bofmrc;
|
||||||
|
|
||||||
|
/* Read BOFM structure */
|
||||||
|
copy_from_user ( &bofmhdr, bofmtab, 0, sizeof ( bofmhdr ) );
|
||||||
|
if ( bofmhdr.magic != BOFM_IOAA_MAGIC ) {
|
||||||
|
DBG ( "BOFM: invalid table signature " BOFM_MAGIC_FMT "\n",
|
||||||
|
BOFM_MAGIC_ARGS ( bofmhdr.magic ) );
|
||||||
|
bofmrc = BOFM_ERR_INVALID_ACTION;
|
||||||
|
goto err_bad_signature;
|
||||||
|
}
|
||||||
|
DBG ( "BOFM: " BOFM_MAGIC_FMT " (profile \"%s\")\n",
|
||||||
|
BOFM_MAGIC_ARGS ( bofmhdr.action ), bofmhdr.profile );
|
||||||
|
|
||||||
|
/* Determine whether or not we should skip normal POST
|
||||||
|
* initialisation.
|
||||||
|
*/
|
||||||
|
switch ( bofmhdr.action ) {
|
||||||
|
case BOFM_ACTION_UPDT:
|
||||||
|
case BOFM_ACTION_DFLT:
|
||||||
|
case BOFM_ACTION_HVST:
|
||||||
|
skip = BOFM_SKIP_INIT;
|
||||||
|
break;
|
||||||
|
case BOFM_ACTION_PARM:
|
||||||
|
case BOFM_ACTION_NONE:
|
||||||
|
skip = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBG ( "BOFM: invalid action " BOFM_MAGIC_FMT "\n",
|
||||||
|
BOFM_MAGIC_ARGS ( bofmhdr.action ) );
|
||||||
|
bofmrc = BOFM_ERR_INVALID_ACTION;
|
||||||
|
goto err_bad_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find BOFM driver */
|
||||||
|
if ( ( rc = bofm_find_driver ( pci ) ) != 0 ) {
|
||||||
|
DBG ( "BOFM: " PCI_FMT " has no driver\n", PCI_ARGS ( pci ) );
|
||||||
|
bofmrc = BOFM_ERR_DEVICE_ERROR;
|
||||||
|
goto err_find_driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Probe driver for PCI device */
|
||||||
|
if ( ( rc = bofm_probe ( pci ) ) != 0 ) {
|
||||||
|
bofmrc = BOFM_ERR_DEVICE_ERROR;
|
||||||
|
goto err_probe;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Locate EN section, if present */
|
||||||
|
en_region_offset = bofm_locate_section ( bofmtab, bofmhdr.length,
|
||||||
|
BOFM_EN_MAGIC, &bofmsec );
|
||||||
|
if ( ! en_region_offset ) {
|
||||||
|
DBG ( "BOFM: No EN section found\n" );
|
||||||
|
bofmrc = ( BOFM_SUCCESS | skip );
|
||||||
|
goto err_no_en_section;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Iterate through EN entries */
|
||||||
|
for ( en_offset = ( en_region_offset + sizeof ( bofmsec ) ) ;
|
||||||
|
en_offset < ( en_region_offset + sizeof ( bofmsec ) +
|
||||||
|
bofmsec.length ) ; en_offset += sizeof ( en ) ) {
|
||||||
|
copy_from_user ( &en, bofmtab, en_offset, sizeof ( en ) );
|
||||||
|
DBG2 ( "BOFM: EN entry found:\n" );
|
||||||
|
DBG2_HDA ( en_offset, &en, sizeof ( en ) );
|
||||||
|
if ( ( en.options & BOFM_EN_MAP_MASK ) != BOFM_EN_MAP_PFA ) {
|
||||||
|
DBG ( "BOFM: slot %d port %d has no PCI mapping\n",
|
||||||
|
en.slot, en.port );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bofm = bofm_find_busdevfn ( en.busdevfn );
|
||||||
|
if ( ! bofm ) {
|
||||||
|
DBG ( "BOFM: " PCI_FMT " ignored\n",
|
||||||
|
PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ),
|
||||||
|
PCI_FUNC ( en.busdevfn ) );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( ( rc = bofm_en ( bofm, &en ) ) == 0 ) {
|
||||||
|
en.options |= BOFM_EN_CSM_SUCCESS;
|
||||||
|
} else {
|
||||||
|
en.options |= BOFM_EN_CSM_FAILED;
|
||||||
|
}
|
||||||
|
DBG2 ( "BOFM: EN entry after processing:\n" );
|
||||||
|
DBG2_HDA ( en_offset, &en, sizeof ( en ) );
|
||||||
|
copy_to_user ( bofmtab, en_offset, &en, sizeof ( en ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
bofmrc = ( BOFM_SUCCESS | skip );
|
||||||
|
|
||||||
|
err_no_en_section:
|
||||||
|
bofm_remove ( pci );
|
||||||
|
err_probe:
|
||||||
|
err_find_driver:
|
||||||
|
err_bad_action:
|
||||||
|
err_bad_signature:
|
||||||
|
return bofmrc;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user