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