123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
-
-
- 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>
-
-
-
-
- static LIST_HEAD ( bofmdevs );
-
-
- 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;
- }
-
-
- void bofm_unregister ( struct bofm_device *bofm ) {
-
- list_del ( &bofm->list );
- DBG ( "BOFM: " PCI_FMT " unregistered\n", PCI_ARGS ( bofm->pci ) );
- }
-
-
- 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;
- }
-
-
- 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;
- }
-
-
- static int bofm_probe ( struct pci_device *pci ) {
- int rc;
-
-
- 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;
- }
-
-
- static void bofm_remove ( struct pci_device *pci ) {
-
-
-
- pci_remove ( pci );
- DBG ( "BOFM: " PCI_FMT " removed\n", PCI_ARGS ( pci ) );
- }
-
-
- 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;
- }
-
-
- static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
- uint8_t mac[6];
- int rc;
-
-
- 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;
- }
-
-
- 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 );
- }
-
-
- 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;
- }
-
-
- 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 ) );
- }
-
-
- 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;
- }
-
-
- 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;
-
-
- 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 );
-
-
-
- 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;
- }
-
-
- 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;
- }
-
-
- if ( ( rc = bofm_probe ( pci ) ) != 0 ) {
- bofmrc = BOFM_ERR_DEVICE_ERROR;
- goto err_probe;
- }
-
-
- 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;
- }
-
-
- 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 + 1 ) );
- 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;
- }
|