Browse Source

Move START_UNDI, UNDI_STARTUP, UNDI_INITIALIZE and

UNDI_GET_INFORMATION calls into drivers/net/undi.c.  undi_probe() now
gets given a pxe_device representing a PXE stack that has been loaded
into memory but not initialised in any way.
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
85a41b25fe
1 changed files with 324 additions and 58 deletions
  1. 324
    58
      src/arch/i386/drivers/net/undi.c

+ 324
- 58
src/arch/i386/drivers/net/undi.c View File

21
 #include <realmode.h>
21
 #include <realmode.h>
22
 #include <pic8259.h>
22
 #include <pic8259.h>
23
 #include <biosint.h>
23
 #include <biosint.h>
24
+#include <pnpbios.h>
24
 #include <gpxe/pkbuff.h>
25
 #include <gpxe/pkbuff.h>
25
 #include <gpxe/netdevice.h>
26
 #include <gpxe/netdevice.h>
26
 #include <gpxe/if_ether.h>
27
 #include <gpxe/if_ether.h>
32
  *
33
  *
33
  */
34
  */
34
 
35
 
36
+/** An UNDI NIC */
37
+struct undi_nic {
38
+	/** Entry point */
39
+	SEGOFF16_t entry;
40
+	/** Assigned IRQ number */
41
+	unsigned int irq;
42
+};
43
+
35
 static void undi_close ( struct net_device *netdev );
44
 static void undi_close ( struct net_device *netdev );
36
 
45
 
46
+/*****************************************************************************
47
+ *
48
+ * UNDI API call
49
+ *
50
+ *****************************************************************************
51
+ */
52
+
53
+/**
54
+ * Name UNDI API call
55
+ *
56
+ * @v function		API call number
57
+ * @ret name		API call name
58
+ */
59
+static inline __attribute__ (( always_inline )) const char *
60
+undi_function_name ( unsigned int function ) {
61
+	switch ( function ) {
62
+	case PXENV_UNLOAD_STACK:
63
+		return "PXENV_UNLOAD_STACK";
64
+	case PXENV_GET_CACHED_INFO:
65
+		return "PXENV_GET_CACHED_INFO";
66
+	case PXENV_RESTART_TFTP:
67
+		return "PXENV_RESTART_TFTP";
68
+	case PXENV_START_UNDI:
69
+		return "PXENV_START_UNDI";
70
+	case PXENV_STOP_UNDI:
71
+		return "PXENV_STOP_UNDI";
72
+	case PXENV_START_BASE:
73
+		return "PXENV_START_BASE";
74
+	case PXENV_STOP_BASE:
75
+		return "PXENV_STOP_BASE";
76
+	case PXENV_TFTP_OPEN:
77
+		return "PXENV_TFTP_OPEN";
78
+	case PXENV_TFTP_CLOSE:
79
+		return "PXENV_TFTP_CLOSE";
80
+	case PXENV_TFTP_READ:
81
+		return "PXENV_TFTP_READ";
82
+	case PXENV_TFTP_READ_FILE:
83
+		return "PXENV_TFTP_READ_FILE";
84
+	case PXENV_TFTP_GET_FSIZE:
85
+		return "PXENV_TFTP_GET_FSIZE";
86
+	case PXENV_UDP_OPEN:
87
+		return "PXENV_UDP_OPEN";
88
+	case PXENV_UDP_CLOSE:
89
+		return "PXENV_UDP_CLOSE";
90
+	case PXENV_UDP_WRITE:
91
+		return "PXENV_UDP_WRITE";
92
+	case PXENV_UDP_READ:
93
+		return "PXENV_UDP_READ";
94
+	case PXENV_UNDI_STARTUP:
95
+		return "PXENV_UNDI_STARTUP";
96
+	case PXENV_UNDI_CLEANUP:
97
+		return "PXENV_UNDI_CLEANUP";
98
+	case PXENV_UNDI_INITIALIZE:
99
+		return "PXENV_UNDI_INITIALIZE";
100
+	case PXENV_UNDI_RESET_ADAPTER:
101
+		return "PXENV_UNDI_RESET_ADAPTER";
102
+	case PXENV_UNDI_SHUTDOWN:
103
+		return "PXENV_UNDI_SHUTDOWN";
104
+	case PXENV_UNDI_OPEN:
105
+		return "PXENV_UNDI_OPEN";
106
+	case PXENV_UNDI_CLOSE:
107
+		return "PXENV_UNDI_CLOSE";
108
+	case PXENV_UNDI_TRANSMIT:
109
+		return "PXENV_UNDI_TRANSMIT";
110
+	case PXENV_UNDI_SET_MCAST_ADDRESS:
111
+		return "PXENV_UNDI_SET_MCAST_ADDRESS";
112
+	case PXENV_UNDI_SET_STATION_ADDRESS:
113
+		return "PXENV_UNDI_SET_STATION_ADDRESS";
114
+	case PXENV_UNDI_SET_PACKET_FILTER:
115
+		return "PXENV_UNDI_SET_PACKET_FILTER";
116
+	case PXENV_UNDI_GET_INFORMATION:
117
+		return "PXENV_UNDI_GET_INFORMATION";
118
+	case PXENV_UNDI_GET_STATISTICS:
119
+		return "PXENV_UNDI_GET_STATISTICS";
120
+	case PXENV_UNDI_CLEAR_STATISTICS:
121
+		return "PXENV_UNDI_CLEAR_STATISTICS";
122
+	case PXENV_UNDI_INITIATE_DIAGS:
123
+		return "PXENV_UNDI_INITIATE_DIAGS";
124
+	case PXENV_UNDI_FORCE_INTERRUPT:
125
+		return "PXENV_UNDI_FORCE_INTERRUPT";
126
+	case PXENV_UNDI_GET_MCAST_ADDRESS:
127
+		return "PXENV_UNDI_GET_MCAST_ADDRESS";
128
+	case PXENV_UNDI_GET_NIC_TYPE:
129
+		return "PXENV_UNDI_GET_NIC_TYPE";
130
+	case PXENV_UNDI_GET_IFACE_INFO:
131
+		return "PXENV_UNDI_GET_IFACE_INFO";
132
+	/*
133
+	 * Duplicate case value; this is a bug in the PXE specification.
134
+	 *
135
+	 *	case PXENV_UNDI_GET_STATE:
136
+	 *		return "PXENV_UNDI_GET_STATE";
137
+	 */
138
+	case PXENV_UNDI_ISR:
139
+		return "PXENV_UNDI_ISR";
140
+	default:
141
+		return "UNKNOWN API CALL";
142
+	}
143
+}
144
+
145
+/**
146
+ * UNDI parameter block
147
+ *
148
+ * Used as the paramter block for all UNDI API calls.  Resides in base
149
+ * memory.
150
+ */
151
+static union u_PXENV_ANY __data16 ( undi_params );
152
+#define undi_params __use_data16 ( undi_params )
153
+
154
+/** UNDI entry point
155
+ *
156
+ * Used as the indirection vector for all UNDI API calls.  Resides in
157
+ * base memory.
158
+ */
159
+static SEGOFF16_t __data16 ( undi_entry_point );
160
+#define undi_entry_point __use_data16 ( undi_entry_point )
161
+
162
+/**
163
+ * Issue UNDI API call
164
+ *
165
+ * @v undi		UNDI NIC
166
+ * @v function		API call number
167
+ * @v params		UNDI parameter block
168
+ * @v params_len	Length of UNDI parameter block
169
+ * @ret rc		Return status code
170
+ */
171
+static int undi_call ( struct undi_nic *undi, unsigned int function,
172
+		       void *params, size_t params_len ) {
173
+	union u_PXENV_ANY *pxenv_any = params;
174
+	PXENV_EXIT_t exit;
175
+	int discard_b, discard_D;
176
+	int rc;
177
+
178
+	/* Copy parameter block and entry point */
179
+	assert ( params_len <= sizeof ( undi_params ) );
180
+	memcpy ( &undi_params, params, params_len );
181
+	undi_entry_point = undi->entry;
182
+
183
+	/* Call real-mode entry point.  This calling convention will
184
+	 * work with both the !PXE and the PXENV+ entry points.
185
+	 */
186
+	__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
187
+					   "pushw %%di\n\t"
188
+					   "pushw %%bx\n\t"
189
+					   "lcall *%c3\n\t"
190
+					   "addw $6, %%sp\n\t" )
191
+			       : "=a" ( exit ), "=b" ( discard_b ),
192
+			         "=D" ( discard_D )
193
+			       : "p" ( & __from_data16 ( undi_entry_point ) ),
194
+			         "b" ( function ),
195
+			         "D" ( & __from_data16 ( undi_params ) )
196
+			       : "ecx", "edx", "esi", "ebp" );
197
+
198
+	/* UNDI API calls may rudely change the status of A20 and not
199
+	 * bother to restore it afterwards.  Intel is known to be
200
+	 * guilty of this.
201
+	 *
202
+	 * Note that we will return to this point even if A20 gets
203
+	 * screwed up by the UNDI driver, because Etherboot always
204
+	 * resides in an even megabyte of RAM.
205
+	 */	
206
+	gateA20_set();
207
+
208
+	/* Copy parameter block back */
209
+	memcpy ( params, &undi_params, params_len );
210
+
211
+	/* Determine return status code based on PXENV_EXIT and
212
+	 * PXENV_STATUS
213
+	 */
214
+	if ( exit == PXENV_EXIT_SUCCESS ) {
215
+		rc = 0;
216
+	} else {
217
+		rc = -pxenv_any->Status;
218
+		/* Paranoia; don't return success for the combination
219
+		 * of PXENV_EXIT_FAILURE but PXENV_STATUS_SUCCESS
220
+		 */
221
+		if ( rc == 0 )
222
+			rc = -EIO;
223
+	}
224
+
225
+	if ( rc != 0 ) {
226
+		DBGC ( undi, "UNDI %p %s failed: %s\n", undi,
227
+		       undi_function_name ( function ), strerror ( rc ) );
228
+	}
229
+	return rc;
230
+}
231
+
37
 /*****************************************************************************
232
 /*****************************************************************************
38
  *
233
  *
39
  * UNDI interrupt service routine
234
  * UNDI interrupt service routine
50
 extern void undi_isr ( void );
245
 extern void undi_isr ( void );
51
 
246
 
52
 /** Dummy chain vector */
247
 /** Dummy chain vector */
53
-static struct segoff undi_isr_dummy_chain;
248
+static struct segoff prev_handler[ IRQ_MAX + 1 ];
54
 
249
 
55
 /** IRQ trigger count */
250
 /** IRQ trigger count */
56
-static volatile uint16_t __text16 ( trigger_count ) = 0;
251
+static volatile uint8_t __text16 ( trigger_count ) = 0;
57
 #define trigger_count __use_text16 ( trigger_count )
252
 #define trigger_count __use_text16 ( trigger_count )
58
 
253
 
59
 /**
254
 /**
69
  * so will bring our own interrupts to a shuddering halt).
264
  * so will bring our own interrupts to a shuddering halt).
70
  */
265
  */
71
 static void undi_hook_isr ( unsigned int irq ) {
266
 static void undi_hook_isr ( unsigned int irq ) {
267
+
268
+	assert ( irq <= IRQ_MAX );
269
+
72
 	__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
270
 	__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
73
-					     "incl %%cs:%c0\n\t"
271
+					     "incb %%cs:%c0\n\t"
74
 					     "iret\n\t" )
272
 					     "iret\n\t" )
75
 			       : : "p" ( & __from_text16 ( trigger_count ) ) );
273
 			       : : "p" ( & __from_text16 ( trigger_count ) ) );
76
 
274
 
77
 	hook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
275
 	hook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
78
-			      &undi_isr_dummy_chain );
276
+			      &prev_handler[irq] );
79
 
277
 
80
 }
278
 }
81
 
279
 
85
  * @v irq		IRQ number
283
  * @v irq		IRQ number
86
  */
284
  */
87
 static void undi_unhook_isr ( unsigned int irq ) {
285
 static void undi_unhook_isr ( unsigned int irq ) {
286
+
287
+	assert ( irq <= IRQ_MAX );
288
+
88
 	unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
289
 	unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
89
-				&undi_isr_dummy_chain );
290
+				&prev_handler[irq] );
90
 }
291
 }
91
 
292
 
92
 /**
293
 /**
142
  * @ret rc		Return status code
343
  * @ret rc		Return status code
143
  */
344
  */
144
 static int undi_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
345
 static int undi_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
145
-	struct pxe_device *pxe = netdev->priv;
346
+	struct undi_nic *undi = netdev->priv;
146
 	struct s_PXENV_UNDI_TRANSMIT undi_transmit;
347
 	struct s_PXENV_UNDI_TRANSMIT undi_transmit;
147
 	size_t len = pkb_len ( pkb );
348
 	size_t len = pkb_len ( pkb );
148
 	int rc;
349
 	int rc;
168
 		= ( ( unsigned ) & __from_data16 ( undi_pkb ) );
369
 		= ( ( unsigned ) & __from_data16 ( undi_pkb ) );
169
 
370
 
170
 	/* Issue PXE API call */
371
 	/* Issue PXE API call */
171
-	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_TRANSMIT, &undi_transmit,
172
-			       sizeof ( undi_transmit ) ) ) != 0 ) {
173
-		DBG ( "UNDI_TRANSMIT failed: %s\n", strerror ( rc ) );
174
-	}
372
+	rc = undi_call ( undi, PXENV_UNDI_TRANSMIT, &undi_transmit,
373
+			 sizeof ( undi_transmit ) );
175
 
374
 
176
 	/* Free packet buffer and return */
375
 	/* Free packet buffer and return */
177
 	free_pkb ( pkb );
376
 	free_pkb ( pkb );
200
  * the wonderful 8259 Programmable Interrupt Controller.  Joy.
399
  * the wonderful 8259 Programmable Interrupt Controller.  Joy.
201
  */
400
  */
202
 static void undi_poll ( struct net_device *netdev ) {
401
 static void undi_poll ( struct net_device *netdev ) {
203
-	struct pxe_device *pxe = netdev->priv;
402
+	struct undi_nic *undi = netdev->priv;
204
 	struct s_PXENV_UNDI_ISR undi_isr;
403
 	struct s_PXENV_UNDI_ISR undi_isr;
205
 	struct pk_buff *pkb = NULL;
404
 	struct pk_buff *pkb = NULL;
206
 	size_t len;
405
 	size_t len;
214
 	/* See if this was our interrupt */
413
 	/* See if this was our interrupt */
215
 	memset ( &undi_isr, 0, sizeof ( undi_isr ) );
414
 	memset ( &undi_isr, 0, sizeof ( undi_isr ) );
216
 	undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
415
 	undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
217
-	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_ISR, &undi_isr,
218
-			       sizeof ( undi_isr ) ) ) != 0 ) {
219
-		DBG ( "UNDI_ISR (START) failed: %s\n", strerror ( rc ) );
416
+	if ( ( rc = undi_call ( undi, PXENV_UNDI_ISR, &undi_isr,
417
+				sizeof ( undi_isr ) ) ) != 0 )
220
 		return;
418
 		return;
221
-	}
222
 	if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
419
 	if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
223
 		return;
420
 		return;
224
 
421
 
225
 	/* Send EOI */
422
 	/* Send EOI */
226
-	send_eoi ( pxe->irq );
423
+	send_eoi ( undi->irq );
227
 
424
 
228
 	/* Run through the ISR loop */
425
 	/* Run through the ISR loop */
229
 	undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
426
 	undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
230
 	while ( 1 ) {
427
 	while ( 1 ) {
231
-		if ( ( rc = pxe_call ( pxe, PXENV_UNDI_ISR, &undi_isr,
232
-				       sizeof ( undi_isr ) ) ) != 0 ) {
233
-			DBG ( "UNDI_ISR (PROCESS/GET_NEXT) failed: %s\n",
234
-			      strerror ( rc ) );
428
+		if ( ( rc = undi_call ( undi, PXENV_UNDI_ISR, &undi_isr,
429
+					sizeof ( undi_isr ) ) ) != 0 )
235
 			break;
430
 			break;
236
-		}
237
 		switch ( undi_isr.FuncFlag ) {
431
 		switch ( undi_isr.FuncFlag ) {
238
 		case PXENV_UNDI_ISR_OUT_TRANSMIT:
432
 		case PXENV_UNDI_ISR_OUT_TRANSMIT:
239
 			/* We don't care about transmit completions */
433
 			/* We don't care about transmit completions */
245
 			if ( ! pkb )
439
 			if ( ! pkb )
246
 				pkb = alloc_pkb ( len );
440
 				pkb = alloc_pkb ( len );
247
 			if ( ! pkb ) {
441
 			if ( ! pkb ) {
248
-				DBG ( "UNDI could not allocate %zd bytes for "
249
-				      "receive buffer\n", len );
442
+				DBGC ( undi, "UNDI %p could not allocate %zd "
443
+				       "bytes for receive buffer\n",
444
+				       undi, len );
250
 				break;
445
 				break;
251
 			}
446
 			}
252
 			if ( frag_len > pkb_available ( pkb ) ) {
447
 			if ( frag_len > pkb_available ( pkb ) ) {
253
-				DBG ( "UNDI fragment too large\n" );
448
+				DBGC ( undi, "UNDI %p fragment too large\n",
449
+				       undi );
254
 				frag_len = pkb_available ( pkb );
450
 				frag_len = pkb_available ( pkb );
255
 			}
451
 			}
256
 			copy_from_real ( pkb_put ( pkb, frag_len ),
452
 			copy_from_real ( pkb_put ( pkb, frag_len ),
266
 			goto done;
462
 			goto done;
267
 		default:
463
 		default:
268
 			/* Should never happen */
464
 			/* Should never happen */
269
-			DBG ( "UNDI ISR returned invalid FuncFlag %04x\n",
270
-			      undi_isr.FuncFlag );
465
+			DBGC ( undi, "UNDI %p ISR returned invalid FuncFlag "
466
+			       "%04x\n", undi, undi_isr.FuncFlag );
271
 			goto done;
467
 			goto done;
272
 		}
468
 		}
273
 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
469
 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
275
 
471
 
276
  done:
472
  done:
277
 	if ( pkb ) {
473
 	if ( pkb ) {
278
-		DBG ( "UNDI returned incomplete packet\n" );
474
+		DBGC ( undi, "UNDI %p returned incomplete packet\n", undi );
279
 		netdev_rx ( netdev, pkb );
475
 		netdev_rx ( netdev, pkb );
280
 	}
476
 	}
281
 }
477
 }
287
  * @ret rc		Return status code
483
  * @ret rc		Return status code
288
  */
484
  */
289
 static int undi_open ( struct net_device *netdev ) {
485
 static int undi_open ( struct net_device *netdev ) {
290
-	struct pxe_device *pxe = netdev->priv;
486
+	struct undi_nic *undi = netdev->priv;
291
 	struct s_PXENV_UNDI_SET_STATION_ADDRESS set_address;
487
 	struct s_PXENV_UNDI_SET_STATION_ADDRESS set_address;
292
 	struct s_PXENV_UNDI_OPEN open;
488
 	struct s_PXENV_UNDI_OPEN open;
293
 	int rc;
489
 	int rc;
294
 
490
 
295
 	/* Hook interrupt service routine and enable interrupt */
491
 	/* Hook interrupt service routine and enable interrupt */
296
-	undi_hook_isr ( pxe->irq );
297
-	enable_irq ( pxe->irq );
492
+	undi_hook_isr ( undi->irq );
493
+	enable_irq ( undi->irq );
298
 
494
 
299
 	/* Set station address.  Required for some PXE stacks; will
495
 	/* Set station address.  Required for some PXE stacks; will
300
 	 * spuriously fail on others.  Ignore failures.  We only ever
496
 	 * spuriously fail on others.  Ignore failures.  We only ever
303
 	 */
499
 	 */
304
 	memcpy ( set_address.StationAddress, netdev->ll_addr,
500
 	memcpy ( set_address.StationAddress, netdev->ll_addr,
305
 		 sizeof ( set_address.StationAddress ) );
501
 		 sizeof ( set_address.StationAddress ) );
306
-	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_SET_STATION_ADDRESS,
307
-			       &set_address, sizeof ( set_address ) ) ) != 0 ){
308
-		DBG ( "UNDI_SET_STATION_ADDRESS failed: %s\n",
309
-		      strerror ( rc ) );
310
-	}
502
+	undi_call ( undi, PXENV_UNDI_SET_STATION_ADDRESS,
503
+		    &set_address, sizeof ( set_address ) );
311
 
504
 
312
 	/* Open NIC */
505
 	/* Open NIC */
313
 	memset ( &open, 0, sizeof ( open ) );
506
 	memset ( &open, 0, sizeof ( open ) );
314
 	open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST );
507
 	open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST );
315
-	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_OPEN, &open,
316
-			       sizeof ( open ) ) ) != 0 ) {
317
-		DBG ( "UNDI_OPEN failed: %s\n", strerror ( rc ) );
508
+	if ( ( rc = undi_call ( undi, PXENV_UNDI_OPEN, &open,
509
+				sizeof ( open ) ) ) != 0 )
318
 		goto err;
510
 		goto err;
319
-	}
320
 
511
 
321
 	return 0;
512
 	return 0;
322
 
513
 
331
  * @v netdev		Net device
522
  * @v netdev		Net device
332
  */
523
  */
333
 static void undi_close ( struct net_device *netdev ) {
524
 static void undi_close ( struct net_device *netdev ) {
334
-	struct pxe_device *pxe = netdev->priv;
525
+	struct undi_nic *undi = netdev->priv;
335
 	struct s_PXENV_UNDI_CLOSE close;
526
 	struct s_PXENV_UNDI_CLOSE close;
336
-	int rc;
337
 
527
 
338
 	/* Close NIC */
528
 	/* Close NIC */
339
-	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_CLOSE, &close,
340
-			       sizeof ( close ) ) ) != 0 ) {
341
-		DBG ( "UNDI_CLOSE failed: %s\n", strerror ( rc ) );
342
-	}
529
+	undi_call ( undi, PXENV_UNDI_CLOSE, &close, sizeof ( close ) );
343
 
530
 
344
 	/* Disable interrupt and unhook ISR */
531
 	/* Disable interrupt and unhook ISR */
345
-	disable_irq ( pxe->irq );
346
-	undi_unhook_isr ( pxe->irq );
532
+	disable_irq ( undi->irq );
533
+	undi_unhook_isr ( undi->irq );
347
 }
534
 }
348
 
535
 
349
 /**
536
 /**
354
  */
541
  */
355
 int undi_probe ( struct pxe_device *pxe ) {
542
 int undi_probe ( struct pxe_device *pxe ) {
356
 	struct net_device *netdev;
543
 	struct net_device *netdev;
544
+	struct undi_nic *undi;
545
+	struct s_PXENV_START_UNDI start_undi;
546
+	struct s_PXENV_UNDI_STARTUP undi_startup;
547
+	struct s_PXENV_UNDI_INITIALIZE undi_initialize;
548
+	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
549
+	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
550
+	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
551
+	struct s_PXENV_STOP_UNDI stop_undi;
357
 	int rc;
552
 	int rc;
358
 
553
 
359
 	/* Allocate net device */
554
 	/* Allocate net device */
360
-	netdev = alloc_etherdev ( 0 );
361
-	if ( ! netdev ) {
362
-		rc = -ENOMEM;
363
-		goto err;
364
-	}
365
-	netdev->priv = pxe;
555
+	netdev = alloc_etherdev ( sizeof ( *undi ) );
556
+	if ( ! netdev )
557
+		return -ENOMEM;
558
+	undi = netdev->priv;
366
 	pxe_set_drvdata ( pxe, netdev );
559
 	pxe_set_drvdata ( pxe, netdev );
367
-
368
-	/* Fill in NIC information */
369
-	memcpy ( netdev->ll_addr, pxe->hwaddr, ETH_ALEN );
560
+	memset ( undi, 0, sizeof ( *undi ) );
561
+	undi->entry = pxe->entry;
562
+
563
+	/* Hook in UNDI stack */
564
+	memset ( &start_undi, 0, sizeof ( start_undi ) );
565
+	start_undi.AX = pxe->pci_busdevfn;
566
+	start_undi.BX = pxe->isapnp_csn;
567
+	start_undi.DX = pxe->isapnp_read_port;
568
+	start_undi.ES = BIOS_SEG;
569
+	start_undi.DI = find_pnp_bios();
570
+	if ( ( rc = undi_call ( undi, PXENV_START_UNDI, &start_undi,
571
+				sizeof ( start_undi ) ) ) != 0 )
572
+		goto err_start_undi;
573
+
574
+	/* Bring up UNDI stack */
575
+	memset ( &undi_startup, 0, sizeof ( undi_startup ) );
576
+	if ( ( rc = undi_call ( undi, PXENV_UNDI_STARTUP, &undi_startup,
577
+				sizeof ( undi_startup ) ) ) != 0 )
578
+		goto err_undi_startup;
579
+	memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
580
+	if ( ( rc = undi_call ( undi, PXENV_UNDI_INITIALIZE, &undi_initialize,
581
+				sizeof ( undi_initialize ) ) ) != 0 )
582
+		goto err_undi_initialize;
583
+
584
+	/* Get device information */
585
+	memset ( &undi_info, 0, sizeof ( undi_info ) );
586
+	if ( ( rc = undi_call ( undi, PXENV_UNDI_GET_INFORMATION, &undi_info,
587
+				sizeof ( undi_info ) ) ) != 0 )
588
+		goto err_undi_get_information;
589
+	memcpy ( netdev->ll_addr, undi_info.PermNodeAddress, ETH_ALEN );
590
+	undi->irq = undi_info.IntNumber;
591
+	if ( undi->irq > IRQ_MAX ) {
592
+		DBGC ( undi, "UNDI %p invalid IRQ %d\n", undi, undi->irq );
593
+		goto err_bad_irq;
594
+	}
595
+	DBGC ( undi, "UNDI %p (%s) using IRQ %d\n",
596
+	       undi, eth_ntoa ( netdev->ll_addr ), undi->irq );
370
 
597
 
371
 	/* Point to NIC specific routines */
598
 	/* Point to NIC specific routines */
372
 	netdev->open	 = undi_open;
599
 	netdev->open	 = undi_open;
376
 
603
 
377
 	/* Register network device */
604
 	/* Register network device */
378
 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
605
 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
379
-		goto err;
606
+		goto err_register;
380
 
607
 
381
 	return 0;
608
 	return 0;
382
 
609
 
383
- err:
610
+ err_register:
611
+ err_bad_irq:
612
+ err_undi_get_information:
613
+ err_undi_initialize:
614
+	/* Shut down UNDI stack */
615
+	memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
616
+	undi_call ( undi, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
617
+		    sizeof ( undi_shutdown ) );
618
+	memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
619
+	undi_call ( undi, PXENV_UNDI_CLEANUP, &undi_cleanup,
620
+		    sizeof ( undi_cleanup ) );
621
+ err_undi_startup:
622
+	/* Unhook UNDI stack */
623
+	memset ( &stop_undi, 0, sizeof ( stop_undi ) );
624
+	undi_call ( undi, PXENV_STOP_UNDI, &stop_undi, sizeof ( stop_undi ) );
625
+ err_start_undi:
384
 	free_netdev ( netdev );
626
 	free_netdev ( netdev );
385
 	pxe_set_drvdata ( pxe, NULL );
627
 	pxe_set_drvdata ( pxe, NULL );
386
 	return rc;
628
 	return rc;
393
  */
635
  */
394
 void undi_remove ( struct pxe_device *pxe ) {
636
 void undi_remove ( struct pxe_device *pxe ) {
395
 	struct net_device *netdev = pxe_get_drvdata ( pxe );
637
 	struct net_device *netdev = pxe_get_drvdata ( pxe );
638
+	struct undi_nic *undi = netdev->priv;
639
+	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
640
+	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
641
+	struct s_PXENV_STOP_UNDI stop_undi;
396
 
642
 
643
+	/* Unregister net device */
397
 	unregister_netdev ( netdev );
644
 	unregister_netdev ( netdev );
645
+
646
+	/* Shut down UNDI stack */
647
+	memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
648
+	undi_call ( undi, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
649
+		    sizeof ( undi_shutdown ) );
650
+	memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
651
+	undi_call ( undi, PXENV_UNDI_CLEANUP, &undi_cleanup,
652
+		    sizeof ( undi_cleanup ) );
653
+
654
+	/* Unhook UNDI stack */
655
+	memset ( &stop_undi, 0, sizeof ( stop_undi ) );
656
+	undi_call ( undi, PXENV_STOP_UNDI, &stop_undi, sizeof ( stop_undi ) );
657
+
658
+	/* Free network device */
398
 	free_netdev ( netdev );
659
 	free_netdev ( netdev );
399
 }
660
 }
661
+
662
+
663
+
664
+
665
+REQUIRE_OBJECT ( pxebus );

Loading…
Cancel
Save