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 17 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,6 +21,7 @@
21 21
 #include <realmode.h>
22 22
 #include <pic8259.h>
23 23
 #include <biosint.h>
24
+#include <pnpbios.h>
24 25
 #include <gpxe/pkbuff.h>
25 26
 #include <gpxe/netdevice.h>
26 27
 #include <gpxe/if_ether.h>
@@ -32,8 +33,202 @@
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 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 234
  * UNDI interrupt service routine
@@ -50,10 +245,10 @@ static void undi_close ( struct net_device *netdev );
50 245
 extern void undi_isr ( void );
51 246
 
52 247
 /** Dummy chain vector */
53
-static struct segoff undi_isr_dummy_chain;
248
+static struct segoff prev_handler[ IRQ_MAX + 1 ];
54 249
 
55 250
 /** IRQ trigger count */
56
-static volatile uint16_t __text16 ( trigger_count ) = 0;
251
+static volatile uint8_t __text16 ( trigger_count ) = 0;
57 252
 #define trigger_count __use_text16 ( trigger_count )
58 253
 
59 254
 /**
@@ -69,13 +264,16 @@ static volatile uint16_t __text16 ( trigger_count ) = 0;
69 264
  * so will bring our own interrupts to a shuddering halt).
70 265
  */
71 266
 static void undi_hook_isr ( unsigned int irq ) {
267
+
268
+	assert ( irq <= IRQ_MAX );
269
+
72 270
 	__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
73
-					     "incl %%cs:%c0\n\t"
271
+					     "incb %%cs:%c0\n\t"
74 272
 					     "iret\n\t" )
75 273
 			       : : "p" ( & __from_text16 ( trigger_count ) ) );
76 274
 
77 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,8 +283,11 @@ static void undi_hook_isr ( unsigned int irq ) {
85 283
  * @v irq		IRQ number
86 284
  */
87 285
 static void undi_unhook_isr ( unsigned int irq ) {
286
+
287
+	assert ( irq <= IRQ_MAX );
288
+
88 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,7 +343,7 @@ static struct s_PXENV_UNDI_TBD __data16 ( undi_tbd );
142 343
  * @ret rc		Return status code
143 344
  */
144 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 347
 	struct s_PXENV_UNDI_TRANSMIT undi_transmit;
147 348
 	size_t len = pkb_len ( pkb );
148 349
 	int rc;
@@ -168,10 +369,8 @@ static int undi_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
168 369
 		= ( ( unsigned ) & __from_data16 ( undi_pkb ) );
169 370
 
170 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 375
 	/* Free packet buffer and return */
177 376
 	free_pkb ( pkb );
@@ -200,7 +399,7 @@ static int undi_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
200 399
  * the wonderful 8259 Programmable Interrupt Controller.  Joy.
201 400
  */
202 401
 static void undi_poll ( struct net_device *netdev ) {
203
-	struct pxe_device *pxe = netdev->priv;
402
+	struct undi_nic *undi = netdev->priv;
204 403
 	struct s_PXENV_UNDI_ISR undi_isr;
205 404
 	struct pk_buff *pkb = NULL;
206 405
 	size_t len;
@@ -214,26 +413,21 @@ static void undi_poll ( struct net_device *netdev ) {
214 413
 	/* See if this was our interrupt */
215 414
 	memset ( &undi_isr, 0, sizeof ( undi_isr ) );
216 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 418
 		return;
221
-	}
222 419
 	if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
223 420
 		return;
224 421
 
225 422
 	/* Send EOI */
226
-	send_eoi ( pxe->irq );
423
+	send_eoi ( undi->irq );
227 424
 
228 425
 	/* Run through the ISR loop */
229 426
 	undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
230 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 430
 			break;
236
-		}
237 431
 		switch ( undi_isr.FuncFlag ) {
238 432
 		case PXENV_UNDI_ISR_OUT_TRANSMIT:
239 433
 			/* We don't care about transmit completions */
@@ -245,12 +439,14 @@ static void undi_poll ( struct net_device *netdev ) {
245 439
 			if ( ! pkb )
246 440
 				pkb = alloc_pkb ( len );
247 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 445
 				break;
251 446
 			}
252 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 450
 				frag_len = pkb_available ( pkb );
255 451
 			}
256 452
 			copy_from_real ( pkb_put ( pkb, frag_len ),
@@ -266,8 +462,8 @@ static void undi_poll ( struct net_device *netdev ) {
266 462
 			goto done;
267 463
 		default:
268 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 467
 			goto done;
272 468
 		}
273 469
 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
@@ -275,7 +471,7 @@ static void undi_poll ( struct net_device *netdev ) {
275 471
 
276 472
  done:
277 473
 	if ( pkb ) {
278
-		DBG ( "UNDI returned incomplete packet\n" );
474
+		DBGC ( undi, "UNDI %p returned incomplete packet\n", undi );
279 475
 		netdev_rx ( netdev, pkb );
280 476
 	}
281 477
 }
@@ -287,14 +483,14 @@ static void undi_poll ( struct net_device *netdev ) {
287 483
  * @ret rc		Return status code
288 484
  */
289 485
 static int undi_open ( struct net_device *netdev ) {
290
-	struct pxe_device *pxe = netdev->priv;
486
+	struct undi_nic *undi = netdev->priv;
291 487
 	struct s_PXENV_UNDI_SET_STATION_ADDRESS set_address;
292 488
 	struct s_PXENV_UNDI_OPEN open;
293 489
 	int rc;
294 490
 
295 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 495
 	/* Set station address.  Required for some PXE stacks; will
300 496
 	 * spuriously fail on others.  Ignore failures.  We only ever
@@ -303,20 +499,15 @@ static int undi_open ( struct net_device *netdev ) {
303 499
 	 */
304 500
 	memcpy ( set_address.StationAddress, netdev->ll_addr,
305 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 505
 	/* Open NIC */
313 506
 	memset ( &open, 0, sizeof ( open ) );
314 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 510
 		goto err;
319
-	}
320 511
 
321 512
 	return 0;
322 513
 
@@ -331,19 +522,15 @@ static int undi_open ( struct net_device *netdev ) {
331 522
  * @v netdev		Net device
332 523
  */
333 524
 static void undi_close ( struct net_device *netdev ) {
334
-	struct pxe_device *pxe = netdev->priv;
525
+	struct undi_nic *undi = netdev->priv;
335 526
 	struct s_PXENV_UNDI_CLOSE close;
336
-	int rc;
337 527
 
338 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 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,19 +541,59 @@ static void undi_close ( struct net_device *netdev ) {
354 541
  */
355 542
 int undi_probe ( struct pxe_device *pxe ) {
356 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 552
 	int rc;
358 553
 
359 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 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 598
 	/* Point to NIC specific routines */
372 599
 	netdev->open	 = undi_open;
@@ -376,11 +603,26 @@ int undi_probe ( struct pxe_device *pxe ) {
376 603
 
377 604
 	/* Register network device */
378 605
 	if ( ( rc = register_netdev ( netdev ) ) != 0 )
379
-		goto err;
606
+		goto err_register;
380 607
 
381 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 626
 	free_netdev ( netdev );
385 627
 	pxe_set_drvdata ( pxe, NULL );
386 628
 	return rc;
@@ -393,7 +635,31 @@ int undi_probe ( struct pxe_device *pxe ) {
393 635
  */
394 636
 void undi_remove ( struct pxe_device *pxe ) {
395 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 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 659
 	free_netdev ( netdev );
399 660
 }
661
+
662
+
663
+
664
+
665
+REQUIRE_OBJECT ( pxebus );

Loading…
Cancel
Save