1 /************************************************************************** 2 Etherboot - BOOTP/TFTP Bootstrap Program 3 UNDI NIC driver for Etherboot 4 5 This file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk> 6 of Fen Systems Ltd. (http://www.fensystems.co.uk/). All rights 7 reserved. 8 9 $Id: undi.c,v 1.8 2003/10/25 13:54:53 mcb30 Exp $ 10 ***************************************************************************/ 11 12 /* 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License as 15 * published by the Free Software Foundation; either version 2, or (at 16 * your option) any later version. 17 */ 18 19 /* to get some global routines like printf */ 20 #include "etherboot.h" 21 /* to get the interface to the body of the program */ 22 #include "nic.h" 23 /* to get the PCI support functions, if this is a PCI NIC */ 24 #include "pci.h" 25 /* UNDI and PXE defines. Includes pxe.h. */ 26 #include "undi.h" 27 /* 8259 PIC defines */ 28 #include "pic8259.h" 29 30 /* NIC specific static variables go here */ 31 static undi_t undi = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, 32 NULL, NULL, 0, NULL, 0, NULL, 33 0, 0, 0, 0, 34 { 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, NULL }, 35 IRQ_NONE }; 36 static undi_base_mem_data_t undi_base_mem_data; 37 38 #define UNDI_HEAP (void *)(512 << 10) 39 40 /* Function prototypes */ 41 int allocate_base_mem_data ( void ); 42 int free_base_mem_data ( void ); 43 int eb_pxenv_undi_shutdown ( void ); 44 int eb_pxenv_stop_undi ( void ); 45 int undi_unload_base_code ( void ); 46 int undi_full_shutdown ( void ); 47 48 /************************************************************************** 49 * Utility functions 50 **************************************************************************/ 51 52 /* Checksum a block. 53 */ 54 55 uint8_t checksum ( void *block, size_t size ) { 56 uint8_t sum = 0; 57 uint16_t i = 0; 58 for ( i = 0; i < size; i++ ) { 59 sum += ( ( uint8_t * ) block )[i]; 60 } 61 return sum; 62 } 63 64 /* Print the status of a !PXE structure 65 */ 66 67 void pxe_dump ( void ) { 68 #ifdef TRACE_UNDI 69 printf ( "API %hx:%hx St %hx:%hx UD %hx:%hx UC %hx:%hx " 70 "BD %hx:%hx BC %hx:%hx\n", 71 undi.pxe->EntryPointSP.segment, undi.pxe->EntryPointSP.offset, 72 undi.pxe->Stack.Seg_Addr, undi.pxe->Stack.Seg_Size, 73 undi.pxe->UNDIData.Seg_Addr, undi.pxe->UNDIData.Seg_Size, 74 undi.pxe->UNDICode.Seg_Addr, undi.pxe->UNDICode.Seg_Size, 75 undi.pxe->BC_Data.Seg_Addr, undi.pxe->BC_Data.Seg_Size, 76 undi.pxe->BC_Code.Seg_Addr, undi.pxe->BC_Code.Seg_Size ); 77 #endif 78 } 79 80 /* Allocate/free space for structures that must reside in base memory 81 */ 82 83 int allocate_base_mem_data ( void ) { 84 /* In GRUB, anything is in base address, so we do not need 85 * allocate anything */ 86 undi.base_mem_data = &undi_base_mem_data; 87 memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) ); 88 undi.undi_call_info = &undi.base_mem_data->undi_call_info; 89 undi.pxs = &undi.base_mem_data->pxs; 90 undi.xmit_data = &undi.base_mem_data->xmit_data; 91 undi.xmit_buffer = undi.base_mem_data->xmit_buffer; 92 #if 0 /* Etherboot Code */ 93 /* Allocate space in base memory. 94 * Initialise pointers to base memory structures. 95 */ 96 if ( undi.base_mem_data == NULL ) { 97 undi.base_mem_data = 98 allot_base_memory ( sizeof(undi_base_mem_data_t) + 99 TRIVIAL_IRQ_HANDLER_SIZE ); 100 if ( undi.base_mem_data == NULL ) { 101 printf ( "Failed to allocate base memory\n" ); 102 free_base_mem_data(); 103 return 0; 104 } 105 memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) ); 106 undi.undi_call_info = &undi.base_mem_data->undi_call_info; 107 undi.pxs = &undi.base_mem_data->pxs; 108 undi.xmit_data = &undi.base_mem_data->xmit_data; 109 undi.xmit_buffer = undi.base_mem_data->xmit_buffer; 110 copy_trivial_irq_handler ( undi.base_mem_data->irq_handler, 111 TRIVIAL_IRQ_HANDLER_SIZE ); 112 } 113 #endif /* Etherboot Code */ 114 return 1; 115 } 116 117 int free_base_mem_data ( void ) { 118 /* Just pretend to free something :-) */ 119 undi.base_mem_data = NULL; 120 undi.undi_call_info = NULL; 121 undi.pxs = NULL; 122 undi.xmit_data = NULL; 123 undi.xmit_buffer = NULL; 124 #if 0 /* Etherboot Code */ 125 if ( undi.base_mem_data != NULL ) { 126 forget_base_memory ( undi.base_mem_data, 127 sizeof(undi_base_mem_data_t) + 128 TRIVIAL_IRQ_HANDLER_SIZE ); 129 undi.base_mem_data = NULL; 130 undi.undi_call_info = NULL; 131 undi.pxs = NULL; 132 undi.xmit_data = NULL; 133 undi.xmit_buffer = NULL; 134 copy_trivial_irq_handler ( NULL, 0 ); 135 } 136 #endif /* Etherboot Code */ 137 return 1; 138 } 139 140 void assemble_firing_squad ( firing_squad_lineup_t *lineup, 141 void *start, size_t size, 142 firing_squad_shoot_t shoot ) { 143 int target; 144 int index; 145 int bit; 146 int start_kb = virt_to_phys(start) >> 10; 147 int end_kb = ( virt_to_phys(start+size) + (1<<10) - 1 ) >> 10; 148 149 for ( target = start_kb; target <= end_kb; target++ ) { 150 index = FIRING_SQUAD_TARGET_INDEX ( target ); 151 bit = FIRING_SQUAD_TARGET_BIT ( target ); 152 lineup->targets[index] = ( shoot << bit ) | 153 ( lineup->targets[index] & ~( 1 << bit ) ); 154 } 155 } 156 157 void shoot_targets ( firing_squad_lineup_t *lineup ) { 158 int shoot_this_target = 0; 159 int shoot_last_target = 0; 160 int start_target = 0; 161 int target; 162 163 for ( target = 0; target <= 640; target++ ) { 164 shoot_this_target = ( target == 640 ? 0 : 165 ( 1 << FIRING_SQUAD_TARGET_BIT(target) ) & 166 lineup->targets[FIRING_SQUAD_TARGET_INDEX(target)] ); 167 if ( shoot_this_target && !shoot_last_target ) { 168 start_target = target; 169 } else if ( shoot_last_target && !shoot_this_target ) { 170 size_t range_size = ( target - start_target ) << 10; 171 forget_base_memory ( phys_to_virt( start_target<<10 ), 172 range_size ); 173 } 174 shoot_last_target = shoot_this_target; 175 } 176 } 177 178 /* Debug macros 179 */ 180 181 #ifdef TRACE_UNDI 182 #define DBG(...) printf ( __VA_ARGS__ ) 183 #else 184 #define DBG(...) 185 #endif 186 187 #define UNDI_STATUS(pxs) ( (pxs)->Status == PXENV_EXIT_SUCCESS ? \ 188 "SUCCESS" : \ 189 ( (pxs)->Status == PXENV_EXIT_FAILURE ? \ 190 "FAILURE" : "UNKNOWN" ) ) 191 192 /************************************************************************** 193 * Base memory scanning functions 194 **************************************************************************/ 195 196 /* Locate the $PnP structure indicating a PnP BIOS. 197 */ 198 199 int hunt_pnp_bios ( void ) { 200 uint32_t off = 0x10000; 201 202 DBG ( "Hunting for PnP BIOS..." ); 203 while ( off > 0 ) { 204 off -= 16; 205 undi.pnp_bios = (pnp_bios_t *) phys_to_virt ( 0xf0000 + off ); 206 if ( undi.pnp_bios->signature == PNP_BIOS_SIGNATURE ) { 207 DBG ( "found $PnP at f000:%hx...", off ); 208 if ( checksum(undi.pnp_bios,sizeof(pnp_bios_t)) !=0) { 209 DBG ( "invalid checksum\n..." ); 210 continue; 211 } 212 DBG ( "ok\n" ); 213 return 1; 214 } 215 } 216 DBG ( "none found\n" ); 217 undi.pnp_bios = NULL; 218 return 0; 219 } 220 221 /* Locate the !PXE structure indicating a loaded UNDI driver. 222 */ 223 224 int hunt_pixie ( void ) { 225 static uint32_t ptr = 0; 226 pxe_t *pxe = NULL; 227 228 DBG ( "Hunting for pixies..." ); 229 if ( ptr == 0 ) ptr = 0xa0000; 230 while ( ptr > 0x10000 ) { 231 ptr -= 16; 232 pxe = (pxe_t *) phys_to_virt ( ptr ); 233 if ( memcmp ( pxe->Signature, "!PXE", 4 ) == 0 ) { 234 DBG ( "found !PXE at %x...", ptr ); 235 if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) { 236 DBG ( "invalid checksum\n..." ); 237 continue; 238 } 239 if ( ptr < get_free_base_memory() ) { 240 DBG ( "in free base memory!\n\n" 241 "WARNING: a valid !PXE structure was " 242 "found in an area of memory marked " 243 "as free!\n\n" ); 244 undi.pxe = pxe; 245 pxe_dump(); 246 undi.pxe = NULL; 247 DBG ( "\nIgnoring and continuing, but this " 248 "may cause problems later!\n\n" ); 249 continue; 250 } 251 DBG ( "ok\n" ); 252 undi.pxe = pxe; 253 pxe_dump(); 254 DBG ( "Resetting pixie...\n" ); 255 undi_unload_base_code(); 256 eb_pxenv_stop_undi(); 257 pxe_dump(); 258 return 1; 259 } 260 } 261 DBG ( "none found\n" ); 262 ptr = 0; 263 return 0; 264 } 265 266 /* Locate PCI PnP ROMs. 267 */ 268 269 int hunt_rom ( void ) { 270 static uint32_t ptr = 0; 271 272 DBG ( "Hunting for ROMs..." ); 273 if ( ptr == 0 ) ptr = 0x100000; 274 while ( ptr > 0x0c0000 ) { 275 ptr -= 0x800; 276 undi.rom = ( rom_t * ) phys_to_virt ( ptr ); 277 if ( undi.rom->signature == ROM_SIGNATURE ) { 278 pcir_header_t *pcir_header = NULL; 279 pnp_header_t *pnp_header = NULL; 280 281 DBG ( "found 55AA at %x...", ptr ); 282 if ( undi.rom->pcir_off == 0 ) { 283 DBG ( "not a PCI ROM\n..." ); 284 continue; 285 } 286 pcir_header = (pcir_header_t*)( ( void * ) undi.rom + 287 undi.rom->pcir_off ); 288 if ( pcir_header->signature != PCIR_SIGNATURE ) { 289 DBG ( "invalid PCI signature\n..." ); 290 continue; 291 } 292 DBG ( "PCI:%hx:%hx...", pcir_header->vendor_id, 293 pcir_header->device_id ); 294 if ( ( pcir_header->vendor_id != undi.pci.vendor ) || 295 ( pcir_header->device_id != undi.pci.dev_id ) ) { 296 DBG ( "not me (%hx:%hx)\n...", 297 undi.pci.vendor, 298 undi.pci.dev_id ); 299 continue; 300 } 301 if ( undi.rom->pnp_off == 0 ) { 302 DBG ( "not a PnP ROM\n..." ); 303 continue; 304 } 305 pnp_header = (pnp_header_t*)( ( void * ) undi.rom + 306 undi.rom->pnp_off ); 307 if ( pnp_header->signature != PNP_SIGNATURE ) { 308 DBG ( "invalid $PnP signature\n..." ); 309 continue; 310 } 311 if ( checksum(pnp_header,sizeof(pnp_header_t)) != 0 ) { 312 DBG ( "invalid PnP checksum\n..." ); 313 continue; 314 } 315 DBG ( "ok\n"); 316 printf ("ROM %s by %s\n", 317 pnp_header->product_str_off==0 ? "(unknown)" : 318 (void*)undi.rom+pnp_header->product_str_off, 319 pnp_header->manuf_str_off==0 ? "(unknown)" : 320 (void*)undi.rom+pnp_header->manuf_str_off ); 321 return 1; 322 } 323 } 324 DBG ( "none found\n" ); 325 ptr = 0; 326 undi.rom = NULL; 327 return 0; 328 } 329 330 /* Locate ROMs containing UNDI drivers. 331 */ 332 333 int hunt_undi_rom ( void ) { 334 while ( hunt_rom() ) { 335 if ( undi.rom->undi_rom_id_off == 0 ) { 336 DBG ( "Not a PXE ROM\n" ); 337 continue; 338 } 339 undi.undi_rom_id = (undi_rom_id_t *) 340 ( (void *)undi.rom + undi.rom->undi_rom_id_off ); 341 if ( undi.undi_rom_id->signature != UNDI_SIGNATURE ) { 342 DBG ( "Invalid UNDI signature\n" ); 343 continue; 344 } 345 printf ( "Revision %d.%d.%d", 346 undi.undi_rom_id->undi_rev[2], 347 undi.undi_rom_id->undi_rev[1], 348 undi.undi_rom_id->undi_rev[0] ); 349 return 1; 350 } 351 return 0; 352 } 353 354 /************************************************************************** 355 * Low-level UNDI API call wrappers 356 **************************************************************************/ 357 358 /* Make a real-mode UNDI API call to the UNDI routine at 359 * routine_seg:routine_off, passing in three uint16 parameters on the 360 * real-mode stack. 361 * Calls the assembler wrapper routine __undi_call. 362 */ 363 364 static inline PXENV_EXIT_t _undi_call ( uint16_t routine_seg, 365 uint16_t routine_off, uint16_t st0, 366 uint16_t st1, uint16_t st2 ) { 367 PXENV_EXIT_t ret = PXENV_EXIT_FAILURE; 368 369 undi.undi_call_info->routine.segment = routine_seg; 370 undi.undi_call_info->routine.offset = routine_off; 371 undi.undi_call_info->stack[0] = st0; 372 undi.undi_call_info->stack[1] = st1; 373 undi.undi_call_info->stack[2] = st2; 374 ret = __undi_call ( SEGMENT( undi.undi_call_info ), 375 OFFSET( undi.undi_call_info ) ); 376 377 /* UNDI API calls may rudely change the status of A20 and not 378 * bother to restore it afterwards. Intel is known to be 379 * guilty of this. 380 * 381 * Note that we will return to this point even if A20 gets 382 * screwed up by the UNDI driver, because Etherboot always 383 * resides in an even megabyte of RAM. 384 */ 385 gateA20_set(); 386 387 return ret; 388 } 389 390 /* Make a real-mode call to the UNDI loader routine at 391 * routine_seg:routine_off, passing in the seg:off address of a 392 * pxenv_structure on the real-mode stack. 393 */ 394 395 int undi_call_loader ( void ) { 396 PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE; 397 398 pxenv_exit = _undi_call ( SEGMENT( undi.rom ), 399 undi.undi_rom_id->undi_loader_off, 400 OFFSET( undi.pxs ), 401 SEGMENT( undi.pxs ), 402 0 /* Unused for UNDI loader API */ ); 403 /* Return 1 for success, to be consistent with other routines */ 404 if ( pxenv_exit == PXENV_EXIT_SUCCESS ) return 1; 405 DBG ( "UNDI loader call failed with status %#hx\n", 406 undi.pxs->Status ); 407 return 0; 408 } 409 410 /* Make a real-mode UNDI API call, passing in the opcode and the 411 * seg:off address of a pxenv_structure on the real-mode stack. 412 * 413 * Two versions: undi_call() will automatically report any failure 414 * codes, undi_call_silent() will not. 415 */ 416 417 int undi_call_silent ( uint16_t opcode ) { 418 PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE; 419 420 pxenv_exit = _undi_call ( undi.pxe->EntryPointSP.segment, 421 undi.pxe->EntryPointSP.offset, 422 opcode, 423 OFFSET( undi.pxs ), 424 SEGMENT( undi.pxs ) ); 425 /* Return 1 for success, to be consistent with other routines */ 426 return pxenv_exit == PXENV_EXIT_SUCCESS ? 1 : 0; 427 } 428 429 int undi_call ( uint16_t opcode ) { 430 if ( undi_call_silent ( opcode ) ) return 1; 431 DBG ( "UNDI API call %#hx failed with status %#hx\n", 432 opcode, undi.pxs->Status ); 433 return 0; 434 } 435 436 /************************************************************************** 437 * High-level UNDI API call wrappers 438 **************************************************************************/ 439 440 /* Install the UNDI driver from a located UNDI ROM. 441 */ 442 443 int undi_loader ( void ) { 444 pxe_t *pxe = NULL; 445 446 /* AX contains PCI bus:devfn (PCI specification) */ 447 undi.pxs->loader.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn; 448 /* BX and DX set to 0xffff for non-ISAPnP devices 449 * (BIOS boot specification) 450 */ 451 undi.pxs->loader.bx = 0xffff; 452 undi.pxs->loader.dx = 0xffff; 453 /* ES:DI points to PnP BIOS' $PnP structure 454 * (BIOS boot specification) 455 */ 456 undi.pxs->loader.es = 0xf000; 457 undi.pxs->loader.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000; 458 459 /* Allocate space for UNDI driver's code and data segments */ 460 undi.driver_code_size = undi.undi_rom_id->code_size; 461 undi.driver_code = UNDI_HEAP; 462 if ( undi.driver_code == NULL ) { 463 printf ( "Could not allocate %d bytes for UNDI code segment\n", 464 undi.driver_code_size ); 465 return 0; 466 } 467 undi.pxs->loader.undi_cs = SEGMENT( undi.driver_code ); 468 469 undi.driver_data_size = undi.undi_rom_id->data_size; 470 undi.driver_data = (void *)((((unsigned long)UNDI_HEAP + undi.undi_rom_id->code_size) | (1024 -1)) + 1); 471 if ( undi.driver_data == NULL ) { 472 printf ( "Could not allocate %d bytes for UNDI code segment\n", 473 undi.driver_data_size ); 474 return 0; 475 } 476 undi.pxs->loader.undi_ds = SEGMENT( undi.driver_data ); 477 478 DBG ( "Installing UNDI driver code to %hx:0000, data at %hx:0000\n", 479 undi.pxs->loader.undi_cs, undi.pxs->loader.undi_ds ); 480 481 /* Do the API call to install the loader */ 482 if ( ! undi_call_loader () ) return 0; 483 484 pxe = VIRTUAL( undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off ); 485 DBG ( "UNDI driver created a pixie at %hx:%hx...", 486 undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off ); 487 if ( memcmp ( pxe->Signature, "!PXE", 4 ) != 0 ) { 488 DBG ( "invalid signature\n" ); 489 return 0; 490 } 491 if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) { 492 DBG ( "invalid checksum\n" ); 493 return 0; 494 } 495 DBG ( "ok\n" ); 496 undi.pxe = pxe; 497 pxe_dump(); 498 return 1; 499 } 500 501 /* Start the UNDI driver. 502 */ 503 504 int eb_pxenv_start_undi ( void ) { 505 int success = 0; 506 507 /* AX contains PCI bus:devfn (PCI specification) */ 508 undi.pxs->start_undi.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn; 509 /* BX and DX set to 0xffff for non-ISAPnP devices 510 * (BIOS boot specification) 511 */ 512 undi.pxs->start_undi.bx = 0xffff; 513 undi.pxs->start_undi.dx = 0xffff; 514 /* ES:DI points to PnP BIOS' $PnP structure 515 * (BIOS boot specification) 516 */ 517 undi.pxs->start_undi.es = 0xf000; 518 undi.pxs->start_undi.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000; 519 520 DBG ( "PXENV_START_UNDI => AX=%hx BX=%hx DX=%hx ES:DI=%hx:%hx\n", 521 undi.pxs->start_undi.ax, 522 undi.pxs->start_undi.bx, undi.pxs->start_undi.dx, 523 undi.pxs->start_undi.es, undi.pxs->start_undi.di ); 524 success = undi_call ( PXENV_START_UNDI ); 525 DBG ( "PXENV_START_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 526 if ( success ) undi.prestarted = 1; 527 return success; 528 } 529 530 int eb_pxenv_undi_startup ( void ) { 531 int success = 0; 532 533 DBG ( "PXENV_UNDI_STARTUP => (void)\n" ); 534 success = undi_call ( PXENV_UNDI_STARTUP ); 535 DBG ( "PXENV_UNDI_STARTUP <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 536 if ( success ) undi.started = 1; 537 return success; 538 } 539 540 int eb_pxenv_undi_cleanup ( void ) { 541 int success = 0; 542 543 DBG ( "PXENV_UNDI_CLEANUP => (void)\n" ); 544 success = undi_call ( PXENV_UNDI_CLEANUP ); 545 DBG ( "PXENV_UNDI_CLEANUP <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 546 return success; 547 } 548 549 int eb_pxenv_undi_initialize ( void ) { 550 int success = 0; 551 552 undi.pxs->undi_initialize.ProtocolIni = 0; 553 memset ( &undi.pxs->undi_initialize.reserved, 0, 554 sizeof ( undi.pxs->undi_initialize.reserved ) ); 555 DBG ( "PXENV_UNDI_INITIALIZE => ProtocolIni=%x\n" ); 556 success = undi_call ( PXENV_UNDI_INITIALIZE ); 557 DBG ( "PXENV_UNDI_INITIALIZE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 558 if ( success ) undi.initialized = 1; 559 return success; 560 } 561 562 int eb_pxenv_undi_shutdown ( void ) { 563 int success = 0; 564 565 DBG ( "PXENV_UNDI_SHUTDOWN => (void)\n" ); 566 success = undi_call ( PXENV_UNDI_SHUTDOWN ); 567 DBG ( "PXENV_UNDI_SHUTDOWN <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 568 if ( success ) { 569 undi.initialized = 0; 570 undi.started = 0; 571 } 572 return success; 573 } 574 575 int eb_pxenv_undi_open ( void ) { 576 int success = 0; 577 578 undi.pxs->undi_open.OpenFlag = 0; 579 undi.pxs->undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST; 580 581 /* Multicast support not yet implemented */ 582 undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount = 0; 583 DBG ( "PXENV_UNDI_OPEN => OpenFlag=%hx PktFilter=%hx " 584 "MCastAddrCount=%hx\n", 585 undi.pxs->undi_open.OpenFlag, undi.pxs->undi_open.PktFilter, 586 undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount ); 587 success = undi_call ( PXENV_UNDI_OPEN ); 588 DBG ( "PXENV_UNDI_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 589 if ( success ) undi.opened = 1; 590 return success; 591 } 592 593 int eb_pxenv_undi_close ( void ) { 594 int success = 0; 595 596 DBG ( "PXENV_UNDI_CLOSE => (void)\n" ); 597 success = undi_call ( PXENV_UNDI_CLOSE ); 598 DBG ( "PXENV_UNDI_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 599 if ( success ) undi.opened = 0; 600 return success; 601 } 602 603 int eb_pxenv_undi_transmit_packet ( void ) { 604 int success = 0; 605 static const uint8_t broadcast[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; 606 607 /* XMitFlag selects unicast / broadcast */ 608 if ( memcmp ( undi.xmit_data->destaddr, broadcast, 609 sizeof(broadcast) ) == 0 ) { 610 undi.pxs->undi_transmit.XmitFlag = XMT_BROADCAST; 611 } else { 612 undi.pxs->undi_transmit.XmitFlag = XMT_DESTADDR; 613 } 614 615 /* Zero reserved dwords */ 616 undi.pxs->undi_transmit.Reserved[0] = 0; 617 undi.pxs->undi_transmit.Reserved[1] = 0; 618 619 /* Segment:offset pointer to DestAddr in base memory */ 620 undi.pxs->undi_transmit.DestAddr.segment = 621 SEGMENT( undi.xmit_data->destaddr ); 622 undi.pxs->undi_transmit.DestAddr.offset = 623 OFFSET( undi.xmit_data->destaddr ); 624 625 /* Segment:offset pointer to TBD in base memory */ 626 undi.pxs->undi_transmit.TBD.segment = SEGMENT( &undi.xmit_data->tbd ); 627 undi.pxs->undi_transmit.TBD.offset = OFFSET( &undi.xmit_data->tbd ); 628 629 /* Use only the "immediate" part of the TBD */ 630 undi.xmit_data->tbd.DataBlkCount = 0; 631 632 DBG ( "PXENV_UNDI_TRANSMIT_PACKET => Protocol=%hx XmitFlag=%hx ...\n" 633 "... DestAddr=%hx:%hx TBD=%hx:%hx ...\n", 634 undi.pxs->undi_transmit.Protocol, 635 undi.pxs->undi_transmit.XmitFlag, 636 undi.pxs->undi_transmit.DestAddr.segment, 637 undi.pxs->undi_transmit.DestAddr.offset, 638 undi.pxs->undi_transmit.TBD.segment, 639 undi.pxs->undi_transmit.TBD.offset ); 640 DBG ( "... TBD { ImmedLength=%hx Xmit=%hx:%hx DataBlkCount=%hx }\n", 641 undi.xmit_data->tbd.ImmedLength, 642 undi.xmit_data->tbd.Xmit.segment, 643 undi.xmit_data->tbd.Xmit.offset, 644 undi.xmit_data->tbd.DataBlkCount ); 645 success = undi_call ( PXENV_UNDI_TRANSMIT ); 646 DBG ( "PXENV_UNDI_TRANSMIT_PACKET <= Status=%s\n", 647 UNDI_STATUS(undi.pxs) ); 648 return success; 649 } 650 651 int eb_pxenv_undi_set_station_address ( void ) { 652 /* This will spuriously fail on some cards. Ignore failures. 653 * We only ever use it to set the MAC address to the card's 654 * permanent value anyway, so it's a useless call (although we 655 * make it because PXE spec says we should). 656 */ 657 DBG ( "PXENV_UNDI_SET_STATION_ADDRESS => " 658 "StationAddress=%!\n", 659 undi.pxs->undi_set_station_address.StationAddress ); 660 undi_call_silent ( PXENV_UNDI_SET_STATION_ADDRESS ); 661 DBG ( "PXENV_UNDI_SET_STATION_ADDRESS <= Status=%s\n", 662 UNDI_STATUS(undi.pxs) ); 663 return 1; 664 } 665 666 int eb_pxenv_undi_get_information ( void ) { 667 int success = 0; 668 memset ( undi.pxs, 0, sizeof ( undi.pxs ) ); 669 DBG ( "PXENV_UNDI_GET_INFORMATION => (void)\n" ); 670 success = undi_call ( PXENV_UNDI_GET_INFORMATION ); 671 DBG ( "PXENV_UNDI_GET_INFORMATION <= Status=%s " 672 "BaseIO=%hx IntNumber=%hx ...\n" 673 "... MaxTranUnit=%hx HwType=%hx HwAddrlen=%hx ...\n" 674 "... CurrentNodeAddress=%! PermNodeAddress=%! ...\n" 675 "... ROMAddress=%hx RxBufCt=%hx TxBufCt=%hx\n", 676 UNDI_STATUS(undi.pxs), 677 undi.pxs->undi_get_information.BaseIo, 678 undi.pxs->undi_get_information.IntNumber, 679 undi.pxs->undi_get_information.MaxTranUnit, 680 undi.pxs->undi_get_information.HwType, 681 undi.pxs->undi_get_information.HwAddrLen, 682 undi.pxs->undi_get_information.CurrentNodeAddress, 683 undi.pxs->undi_get_information.PermNodeAddress, 684 undi.pxs->undi_get_information.ROMAddress, 685 undi.pxs->undi_get_information.RxBufCt, 686 undi.pxs->undi_get_information.TxBufCt ); 687 return success; 688 } 689 690 int eb_pxenv_undi_get_iface_info ( void ) { 691 int success = 0; 692 693 DBG ( "PXENV_UNDI_GET_IFACE_INFO => (void)\n" ); 694 success = undi_call ( PXENV_UNDI_GET_IFACE_INFO ); 695 DBG ( "PXENV_UNDI_GET_IFACE_INFO <= Status=%s IfaceType=%s ...\n" 696 "... LinkSpeed=%x ServiceFlags=%x\n", 697 UNDI_STATUS(undi.pxs), 698 undi.pxs->undi_get_iface_info.IfaceType, 699 undi.pxs->undi_get_iface_info.LinkSpeed, 700 undi.pxs->undi_get_iface_info.ServiceFlags ); 701 return success; 702 } 703 704 int eb_pxenv_undi_isr ( void ) { 705 int success = 0; 706 707 DBG ( "PXENV_UNDI_ISR => FuncFlag=%hx\n", 708 undi.pxs->undi_isr.FuncFlag ); 709 success = undi_call ( PXENV_UNDI_ISR ); 710 DBG ( "PXENV_UNDI_ISR <= Status=%s FuncFlag=%hx BufferLength=%hx ...\n" 711 "... FrameLength=%hx FrameHeaderLength=%hx Frame=%hx:%hx " 712 "ProtType=%hhx ...\n... PktType=%hhx\n", 713 UNDI_STATUS(undi.pxs), undi.pxs->undi_isr.FuncFlag, 714 undi.pxs->undi_isr.BufferLength, 715 undi.pxs->undi_isr.FrameLength, 716 undi.pxs->undi_isr.FrameHeaderLength, 717 undi.pxs->undi_isr.Frame.segment, 718 undi.pxs->undi_isr.Frame.offset, 719 undi.pxs->undi_isr.ProtType, 720 undi.pxs->undi_isr.PktType ); 721 return success; 722 } 723 724 int eb_pxenv_stop_undi ( void ) { 725 int success = 0; 726 727 DBG ( "PXENV_STOP_UNDI => (void)\n" ); 728 success = undi_call ( PXENV_STOP_UNDI ); 729 DBG ( "PXENV_STOP_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 730 if ( success ) undi.prestarted = 0; 731 return success; 732 } 733 734 int eb_pxenv_unload_stack ( void ) { 735 int success = 0; 736 737 memset ( undi.pxs, 0, sizeof ( undi.pxs ) ); 738 DBG ( "PXENV_UNLOAD_STACK => (void)\n" ); 739 success = undi_call_silent ( PXENV_UNLOAD_STACK ); 740 DBG ( "PXENV_UNLOAD_STACK <= Status=%s ...\n... (%s)\n", 741 UNDI_STATUS(undi.pxs), 742 ( undi.pxs->Status == PXENV_STATUS_SUCCESS ? 743 "base-code is ready to be removed" : 744 ( undi.pxs->Status == PXENV_STATUS_FAILURE ? 745 "the size of free base memory has been changed" : 746 ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ? 747 "the NIC interrupt vector has been changed" : 748 "UNEXPECTED STATUS CODE" ) ) ) ); 749 return success; 750 } 751 752 int eb_pxenv_stop_base ( void ) { 753 int success = 0; 754 755 DBG ( "PXENV_STOP_BASE => (void)\n" ); 756 success = undi_call ( PXENV_STOP_BASE ); 757 DBG ( "PXENV_STOP_BASE <= Status=%s\n", UNDI_STATUS(undi.pxs) ); 758 return success; 759 } 760 761 /* Unload UNDI base code (if any present) and free memory. 762 */ 763 int undi_unload_base_code ( void ) { 764 /* In GRUB, we do not allocate anything, but we still can call 765 * to free the base space */ 766 void *bc_code = VIRTUAL( undi.pxe->BC_Code.Seg_Addr, 0 ); 767 size_t bc_code_size = undi.pxe->BC_Code.Seg_Size; 768 void *bc_data = VIRTUAL( undi.pxe->BC_Data.Seg_Addr, 0 ); 769 size_t bc_data_size = undi.pxe->BC_Data.Seg_Size; 770 void *bc_stck = VIRTUAL( undi.pxe->Stack.Seg_Addr, 0 ); 771 size_t bc_stck_size = undi.pxe->Stack.Seg_Size; 772 firing_squad_lineup_t lineup; 773 774 /* Don't unload if there is no base code present */ 775 if ( undi.pxe->BC_Code.Seg_Addr == 0 ) return 1; 776 777 /* Since we never start the base code, the only time we should 778 * reach this is if we were loaded via PXE. There are many 779 * different and conflicting versions of the "correct" way to 780 * unload the PXE base code, several of which appear within 781 * the PXE specification itself. This one seems to work for 782 * our purposes. 783 */ 784 eb_pxenv_stop_base(); 785 //eb_pxenv_unload_stack(); 786 /* if ( ( undi.pxs->unload_stack.Status != PXENV_STATUS_SUCCESS ) && 787 ( undi.pxs->unload_stack.Status != PXENV_STATUS_FAILURE ) ) { 788 printf ( "Could not free memory allocated to PXE base code: " 789 "possible memory leak\n" ); 790 return 0; 791 }*/ 792 /* Free data structures. Forget what the PXE specification 793 * says about how to calculate the new size of base memory; 794 * basemem.c takes care of all that for us. Note that we also 795 * have to free the stack (even though PXE spec doesn't say 796 * anything about it) because nothing else is going to do so. 797 * 798 * Structures will almost certainly not be kB-aligned and 799 * there's a reasonable chance that the UNDI code or data 800 * portions will lie in the same kB as the base code. Since 801 * forget_base_memory works only in 1kB increments, this means 802 * we have to do some arcane trickery. 803 */ 804 memset ( &lineup, 0, sizeof(lineup) ); 805 if ( SEGMENT(bc_code) != 0 ) 806 assemble_firing_squad( &lineup, bc_code, bc_code_size, SHOOT ); 807 if ( SEGMENT(bc_data) != 0 ) 808 assemble_firing_squad( &lineup, bc_data, bc_data_size, SHOOT ); 809 if ( SEGMENT(bc_stck) != 0 ) 810 assemble_firing_squad( &lineup, bc_stck, bc_stck_size, SHOOT ); 811 /* Don't shoot any bits of the UNDI driver code or data */ 812 assemble_firing_squad ( &lineup, 813 VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 0), 814 undi.pxe->UNDICode.Seg_Size, DONTSHOOT ); 815 assemble_firing_squad ( &lineup, 816 VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 0), 817 undi.pxe->UNDIData.Seg_Size, DONTSHOOT ); 818 //shoot_targets ( &lineup ); 819 //undi.pxe->BC_Code.Seg_Addr = 0; 820 //undi.pxe->BC_Data.Seg_Addr = 0; 821 //undi.pxe->Stack.Seg_Addr = 0; 822 823 /* Free and reallocate our own base memory data structures, to 824 * allow the freed base-code blocks to be fully released. 825 */ 826 free_base_mem_data(); 827 if ( ! allocate_base_mem_data() ) { 828 printf ( "FATAL: memory unaccountably lost\n" ); 829 while ( 1 ) {}; 830 } 831 832 return 1; 833 } 834 835 /* UNDI full initialization 836 * 837 * This calls all the various UNDI initialization routines in sequence. 838 */ 839 840 int undi_full_startup ( void ) { 841 if ( ! eb_pxenv_start_undi() ) return 0; 842 if ( ! eb_pxenv_undi_startup() ) return 0; 843 if ( ! eb_pxenv_undi_initialize() ) return 0; 844 if ( ! eb_pxenv_undi_get_information() ) return 0; 845 undi.irq = undi.pxs->undi_get_information.IntNumber; 846 if ( ! install_undi_irq_handler ( undi.irq, undi.pxe->EntryPointSP ) ) { 847 undi.irq = IRQ_NONE; 848 return 0; 849 } 850 memmove ( &undi.pxs->undi_set_station_address.StationAddress, 851 &undi.pxs->undi_get_information.PermNodeAddress, 852 sizeof (undi.pxs->undi_set_station_address.StationAddress) ); 853 if ( ! eb_pxenv_undi_set_station_address() ) return 0; 854 if ( ! eb_pxenv_undi_open() ) return 0; 855 /* install_undi_irq_handler leaves irq disabled */ 856 enable_irq ( undi.irq ); 857 return 1; 858 } 859 860 /* UNDI full shutdown 861 * 862 * This calls all the various UNDI shutdown routines in sequence and 863 * also frees any memory that it can. 864 */ 865 866 int undi_full_shutdown ( void ) { 867 if ( undi.pxe != NULL ) { 868 /* In case we didn't allocate the driver's memory in the first 869 * place, try to grab the code and data segments and sizes 870 * from the !PXE structure. 871 */ 872 if ( undi.driver_code == NULL ) { 873 undi.driver_code = VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 874 0 ); 875 undi.driver_code_size = undi.pxe->UNDICode.Seg_Size; 876 } 877 if ( undi.driver_data == NULL ) { 878 undi.driver_data = VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 879 0 ); 880 undi.driver_data_size = undi.pxe->UNDIData.Seg_Size; 881 } 882 883 /* Ignore errors and continue in the hope of shutting 884 * down anyway 885 */ 886 if ( undi.opened ) eb_pxenv_undi_close(); 887 if ( undi.started ) { 888 eb_pxenv_undi_cleanup(); 889 /* We may get spurious UNDI API errors at this 890 * point. If startup() succeeded but 891 * initialize() failed then according to the 892 * spec, we should call shutdown(). However, 893 * some NICS will fail with a status code 894 * 0x006a (INVALID_STATE). 895 */ 896 eb_pxenv_undi_shutdown(); 897 } 898 if ( undi.irq != IRQ_NONE ) { 899 remove_undi_irq_handler ( undi.irq ); 900 undi.irq = IRQ_NONE; 901 } 902 undi_unload_base_code(); 903 if ( undi.prestarted ) { 904 eb_pxenv_stop_undi(); 905 /* Success OR Failure indicates that memory 906 * can be freed. Any other status code means 907 * that it can't. 908 */ 909 if (( undi.pxs->Status == PXENV_STATUS_KEEP_UNDI ) || 910 ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ) ) { 911 printf ("Could not free memory allocated to " 912 "UNDI driver: possible memory leak\n"); 913 return 0; 914 } 915 } 916 } 917 /* Free memory allocated to UNDI driver */ 918 if ( undi.driver_code != NULL ) { 919 /* Clear contents in order to eliminate !PXE and PXENV 920 * signatures to prevent spurious detection via base 921 * memory scan. 922 */ 923 memset ( undi.driver_code, 0, undi.driver_code_size ); 924 /* forget_base_memory ( undi.driver_code, undi.driver_code_size ); */ 925 undi.driver_code = NULL; 926 undi.driver_code_size = 0; 927 } 928 if ( undi.driver_data != NULL ) { 929 /* forget_base_memory ( undi.driver_data, undi.driver_data_size ); */ 930 undi.driver_data = NULL; 931 undi.driver_data_size = 0; 932 } 933 /* !PXE structure now gone; memory freed */ 934 undi.pxe = NULL; 935 return 1; 936 } 937 938 /************************************************************************** 939 POLL - Wait for a frame 940 ***************************************************************************/ 941 static int undi_poll(struct nic *nic, int retrieve) 942 { 943 /* Fun, fun, fun. UNDI drivers don't use polling; they use 944 * interrupts. We therefore cheat and pretend that an 945 * interrupt has occurred every time undi_poll() is called. 946 * This isn't too much of a hack; PCI devices share IRQs and 947 * so the first thing that a proper ISR should do is call 948 * PXENV_UNDI_ISR to determine whether or not the UNDI NIC 949 * generated the interrupt; there is no harm done by spurious 950 * calls to PXENV_UNDI_ISR. Similarly, we wouldn't be 951 * handling them any more rapidly than the usual rate of 952 * undi_poll() being called even if we did implement a full 953 * ISR. So it should work. Ha! 954 * 955 * Addendum (21/10/03). Some cards don't play nicely with 956 * this trick, so instead of doing it the easy way we have to 957 * go to all the hassle of installing a genuine interrupt 958 * service routine and dealing with the wonderful 8259 959 * Programmable Interrupt Controller. Joy. 960 * 961 * (02/01/2005). A real UNDI ISR is now implemented in, 962 * following Figure 3-4 in PXE spec 2.0. The interrupt 963 * handler, undi_irq_handler, issues PXENV_UNDI_ISR_IN_START. 964 * If the interrupt is ours, the handler sends EOI and bumps the 965 * undi_irq_trigger_count. This polled routine is equivalent 966 * to the "driver strategy routine". 967 * 968 * Another issue is that upper layer await_*() does not handle 969 * coalesced packets. The UNDI implementation on broadcom chips 970 * appear to combine interrupts. If we loop through GET_NEXT, 971 * we may hand up coalesced packets, resulting in drops, and 972 * severe time delay. As a temperary hack, we return as soon as 973 * we get something, remembering where we were (IN_PROCESS 974 * or GET_NEXT). This assume packets are never broken up. 975 * XXX Need to fix upper layer to handle coalesced data. 976 */ 977 978 static int undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 979 980 /* See if a hardware interrupt has occurred since the last poll(). 981 */ 982 switch ( undi_opcode ) { 983 case PXENV_UNDI_ISR_IN_PROCESS: 984 if ( ! undi_irq_triggered ( undi.irq ) ) 985 return 0; 986 default: 987 break; 988 } 989 990 /* We have an interrupt or there is something left from 991 * last poll. Either way, we need to call UNDI ISR. 992 */ 993 nic->packetlen = 0; 994 undi.pxs->undi_isr.FuncFlag = undi_opcode; 995 /* there is no good way to handle this error */ 996 if ( ! eb_pxenv_undi_isr() ) { 997 printf ("undi isr call failed: opcode = %d\n", undi_opcode); 998 return 0; 999 } 1000 switch ( undi.pxs->undi_isr.FuncFlag ) { 1001 case PXENV_UNDI_ISR_OUT_DONE: 1002 /* Set opcode back to IN_PROCESS and wait for next intr */ 1003 undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 1004 return 0; 1005 case PXENV_UNDI_ISR_OUT_TRANSMIT: 1006 /* We really don't care about transmission complete 1007 * interrupts. Move on to next frame. 1008 */ 1009 undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 1010 return 0; 1011 case PXENV_UNDI_ISR_OUT_BUSY: 1012 /* This should never happen. 1013 */ 1014 undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 1015 printf ( "UNDI ISR thinks it's being re-entered!\n" 1016 "Aborting receive\n" ); 1017 return 0; 1018 case PXENV_UNDI_ISR_OUT_RECEIVE: 1019 /* Copy data to receive buffer and move on to next frame */ 1020 undi_opcode = PXENV_UNDI_ISR_IN_GET_NEXT; 1021 memcpy ( nic->packet + nic->packetlen, 1022 VIRTUAL( undi.pxs->undi_isr.Frame.segment, 1023 undi.pxs->undi_isr.Frame.offset ), 1024 undi.pxs->undi_isr.BufferLength ); 1025 nic->packetlen += undi.pxs->undi_isr.BufferLength; 1026 break; 1027 default: 1028 undi_opcode = PXENV_UNDI_ISR_IN_PROCESS; 1029 printf ( "UNDI ISR returned bizzare status code %d\n", 1030 undi.pxs->undi_isr.FuncFlag ); 1031 } 1032 1033 return nic->packetlen > 0 ? 1 : 0; 1034 } 1035 1036 /************************************************************************** 1037 TRANSMIT - Transmit a frame 1038 ***************************************************************************/ 1039 static void undi_transmit( 1040 struct nic *nic, 1041 const char *d, /* Destination */ 1042 unsigned int t, /* Type */ 1043 unsigned int s, /* size */ 1044 const char *p) /* Packet */ 1045 { 1046 /* Inhibit compiler warning about unused parameter nic */ 1047 if ( nic == NULL ) {}; 1048 1049 /* Copy destination to buffer in base memory */ 1050 memcpy ( undi.xmit_data->destaddr, d, sizeof(MAC_ADDR) ); 1051 1052 /* Translate packet type to UNDI packet type */ 1053 switch ( t ) { 1054 case IP : undi.pxs->undi_transmit.Protocol = P_IP; break; 1055 case ARP: undi.pxs->undi_transmit.Protocol = P_ARP; break; 1056 case RARP: undi.pxs->undi_transmit.Protocol = P_RARP; break; 1057 default: undi.pxs->undi_transmit.Protocol = P_UNKNOWN; break; 1058 } 1059 1060 /* Store packet length in TBD */ 1061 undi.xmit_data->tbd.ImmedLength = s; 1062 1063 /* Check to see if data to be transmitted is currently in base 1064 * memory. If not, allocate temporary storage in base memory 1065 * and copy it there. 1066 */ 1067 if ( SEGMENT( p ) <= 0xffff ) { 1068 undi.xmit_data->tbd.Xmit.segment = SEGMENT( p ); 1069 undi.xmit_data->tbd.Xmit.offset = OFFSET( p ); 1070 } else { 1071 memcpy ( undi.xmit_buffer, p, s ); 1072 undi.xmit_data->tbd.Xmit.segment = SEGMENT( undi.xmit_buffer ); 1073 undi.xmit_data->tbd.Xmit.offset = OFFSET( undi.xmit_buffer ); 1074 } 1075 1076 eb_pxenv_undi_transmit_packet(); 1077 } 1078 1079 /************************************************************************** 1080 DISABLE - Turn off ethernet interface 1081 ***************************************************************************/ 1082 static void undi_disable(struct dev *dev) 1083 { 1084 /* Inhibit compiler warning about unused parameter dev */ 1085 if ( dev == NULL ) {}; 1086 undi_full_shutdown(); 1087 free_base_mem_data(); 1088 } 1089 1090 /************************************************************************** 1091 PROBE - Look for an adapter, this routine's visible to the outside 1092 ***************************************************************************/ 1093 1094 /* Locate an UNDI driver by first scanning through base memory for an 1095 * installed driver and then by scanning for UNDI ROMs and attempting 1096 * to install their drivers. 1097 */ 1098 1099 int hunt_pixies_and_undi_roms ( void ) { 1100 static uint8_t hunt_type = HUNT_FOR_PIXIES; 1101 1102 if ( hunt_type == HUNT_FOR_PIXIES ) { 1103 if ( hunt_pixie() ) { 1104 return 1; 1105 } 1106 } 1107 hunt_type = HUNT_FOR_UNDI_ROMS; 1108 while ( hunt_undi_rom() ) { 1109 if ( undi_loader() ) { 1110 return 1; 1111 } 1112 undi_full_shutdown(); /* Free any allocated memory */ 1113 } 1114 hunt_type = HUNT_FOR_PIXIES; 1115 return 0; 1116 } 1117 1118 /* The actual Etherboot probe routine. 1119 */ 1120 1121 static int undi_probe(struct dev *dev, struct pci_device *pci) 1122 { 1123 struct nic *nic = (struct nic *)dev; 1124 1125 /* Zero out global undi structure */ 1126 memset ( &undi, 0, sizeof(undi) ); 1127 1128 /* Store PCI parameters; we will need them to initialize the UNDI 1129 * driver later. 1130 */ 1131 memcpy ( &undi.pci, pci, sizeof(undi.pci) ); 1132 1133 /* Find the BIOS' $PnP structure */ 1134 if ( ! hunt_pnp_bios() ) { 1135 printf ( "No PnP BIOS found; aborting\n" ); 1136 return 0; 1137 } 1138 1139 /* Allocate base memory data structures */ 1140 if ( ! allocate_base_mem_data() ) return 0; 1141 1142 /* Search thoroughly for UNDI drivers */ 1143 for ( ; hunt_pixies_and_undi_roms(); undi_full_shutdown() ) { 1144 /* Try to initialise UNDI driver */ 1145 DBG ( "Initializing UNDI driver. Please wait...\n" ); 1146 if ( ! undi_full_startup() ) { 1147 if ( undi.pxs->Status == 1148 PXENV_STATUS_UNDI_MEDIATEST_FAILED ) { 1149 DBG ( "Cable not connected (code %#hx)\n", 1150 PXENV_STATUS_UNDI_MEDIATEST_FAILED ); 1151 } 1152 continue; 1153 } 1154 /* Basic information: MAC, IO addr, IRQ */ 1155 if ( ! eb_pxenv_undi_get_information() ) continue; 1156 DBG ( "Initialized UNDI NIC with IO %#hx, IRQ %d, MAC %!\n", 1157 undi.pxs->undi_get_information.BaseIo, 1158 undi.pxs->undi_get_information.IntNumber, 1159 undi.pxs->undi_get_information.CurrentNodeAddress ); 1160 /* Fill out MAC address in nic structure */ 1161 memcpy ( nic->node_addr, 1162 undi.pxs->undi_get_information.CurrentNodeAddress, 1163 ETH_ALEN ); 1164 /* More diagnostic information including link speed */ 1165 if ( ! eb_pxenv_undi_get_iface_info() ) continue; 1166 printf ( " NDIS type %s interface at %d Mbps\n", 1167 undi.pxs->undi_get_iface_info.IfaceType, 1168 undi.pxs->undi_get_iface_info.LinkSpeed / 1000000 ); 1169 DBG ("UNDI Stack at %#hx:%#hx",UNDI_STACK_SEG, UNDI_STACK_OFF); 1170 dev->disable = undi_disable; 1171 nic->poll = undi_poll; 1172 nic->transmit = undi_transmit; 1173 return 1; 1174 } 1175 undi_disable ( dev ); /* To free base memory structures */ 1176 return 0; 1177 } 1178 1179 /* UNDI driver states that it is suitable for any PCI NIC (i.e. any 1180 * PCI device of class PCI_CLASS_NETWORK_ETHERNET). If there are any 1181 * obscure UNDI NICs that have the incorrect PCI class, add them to 1182 * this list. 1183 */ 1184 static struct pci_id undi_nics[] = { 1185 /* PCI_ROM(0x0000, 0x0000, "undi", "UNDI adaptor"), */ 1186 }; 1187 1188 struct pci_driver undi_driver = { 1189 .type = NIC_DRIVER, 1190 .name = "UNDI", 1191 .probe = undi_probe, 1192 .ids = undi_nics, 1193 .id_count = sizeof(undi_nics)/sizeof(undi_nics[0]), 1194 .class = PCI_CLASS_NETWORK_ETHERNET, 1195 }; 1196