diff options
author | Michael Brown | 2011-02-10 14:47:38 +0100 |
---|---|---|
committer | Michael Brown | 2011-03-03 00:58:43 +0100 |
commit | 5597d52c21377872387866e8cf9ee351b7a41a01 (patch) | |
tree | 8805382ac5267e7aff87bd5a3df613802ec54b48 /src | |
parent | [autoboot] Allow a SAN boot as a fallback if a filename boot returns (diff) | |
download | ipxe-5597d52c21377872387866e8cf9ee351b7a41a01.tar.gz ipxe-5597d52c21377872387866e8cf9ee351b7a41a01.tar.xz ipxe-5597d52c21377872387866e8cf9ee351b7a41a01.zip |
[bofm] Add core BOFM library
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 1 | ||||
-rw-r--r-- | src/include/ipxe/bofm.h | 341 | ||||
-rw-r--r-- | src/include/ipxe/errfile.h | 1 | ||||
-rw-r--r-- | src/interface/bofm/bofm.c | 335 |
4 files changed, 678 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile index 1a878ef8..8b691a71 100644 --- a/src/Makefile +++ b/src/Makefile @@ -75,6 +75,7 @@ SRCDIRS += drivers/nvs SRCDIRS += drivers/bitbash SRCDIRS += drivers/infiniband SRCDIRS += interface/pxe interface/efi interface/smbios +SRCDIRS += interface/bofm SRCDIRS += tests SRCDIRS += crypto crypto/axtls crypto/matrixssl SRCDIRS += hci hci/commands hci/tui diff --git a/src/include/ipxe/bofm.h b/src/include/ipxe/bofm.h new file mode 100644 index 00000000..2fe1e908 --- /dev/null +++ b/src/include/ipxe/bofm.h @@ -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 */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 24d5b310..01de5600 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -236,6 +236,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_fcmgmt_cmd ( ERRFILE_OTHER | 0x001e0000 ) #define ERRFILE_gdbstub_cmd ( ERRFILE_OTHER | 0x001f0000 ) #define ERRFILE_sanboot_cmd ( ERRFILE_OTHER | 0x00200000 ) +#define ERRFILE_bofm ( ERRFILE_OTHER | 0x00210000 ) /** @} */ diff --git a/src/interface/bofm/bofm.c b/src/interface/bofm/bofm.c new file mode 100644 index 00000000..dfa76d32 --- /dev/null +++ b/src/interface/bofm/bofm.c @@ -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; +} |