Browse Source

Remember to enable/disable the interrupt at the PIC.

Handle failures in undi_open() properly.
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
23cb837951
1 changed files with 27 additions and 13 deletions
  1. 27
    13
      src/arch/i386/drivers/net/undi.c

+ 27
- 13
src/arch/i386/drivers/net/undi.c View File

32
  *
32
  *
33
  */
33
  */
34
 
34
 
35
+static void undi_close ( struct net_device *netdev );
36
+
35
 /*****************************************************************************
37
 /*****************************************************************************
36
  *
38
  *
37
  * UNDI interrupt service routine
39
  * UNDI interrupt service routine
47
  */
49
  */
48
 extern void undi_isr ( void );
50
 extern void undi_isr ( void );
49
 
51
 
50
-/** Vector for chaining to other interrupts handlers */
51
-static struct segoff __text16 ( undi_isr_chain );
52
-#define undi_isr_chain __use_text16 ( undi_isr_chain )
52
+/** Dummy chain vector */
53
+static struct segoff undi_isr_dummy_chain;
53
 
54
 
54
 /** IRQ trigger count */
55
 /** IRQ trigger count */
55
-static volatile uint16_t __text16 ( trigger_count );
56
+static volatile uint16_t __text16 ( trigger_count ) = 0;
56
 #define trigger_count __use_text16 ( trigger_count )
57
 #define trigger_count __use_text16 ( trigger_count )
57
 
58
 
58
 /**
59
 /**
59
  * Hook UNDI interrupt service routine
60
  * Hook UNDI interrupt service routine
60
  *
61
  *
61
  * @v irq		IRQ number
62
  * @v irq		IRQ number
63
+ *
64
+ * The UNDI ISR specifically does @b not chain to the previous
65
+ * interrupt handler.  BIOSes seem to install somewhat perverse
66
+ * default interrupt handlers; some do nothing other than an iret (and
67
+ * so will cause a screaming interrupt if there really is another
68
+ * interrupting device) and some disable the interrupt at the PIC (and
69
+ * so will bring our own interrupts to a shuddering halt).
62
  */
70
  */
63
 static void undi_hook_isr ( unsigned int irq ) {
71
 static void undi_hook_isr ( unsigned int irq ) {
64
 	__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
72
 	__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
65
 					     "incl %%cs:%c0\n\t"
73
 					     "incl %%cs:%c0\n\t"
66
-					     "ljmp *%%cs:%c1\n\t" )
67
-			       : : "p" ( & __from_text16 ( trigger_count ) ),
68
-			           "p" ( & __from_text16 ( undi_isr_chain ) ));
74
+					     "iret\n\t" )
75
+			       : : "p" ( & __from_text16 ( trigger_count ) ) );
69
 
76
 
70
 	hook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
77
 	hook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
71
-			      &undi_isr_chain );
78
+			      &undi_isr_dummy_chain );
72
 
79
 
73
 }
80
 }
74
 
81
 
79
  */
86
  */
80
 static void undi_unhook_isr ( unsigned int irq ) {
87
 static void undi_unhook_isr ( unsigned int irq ) {
81
 	unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
88
 	unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
82
-				&undi_isr_chain );
89
+				&undi_isr_dummy_chain );
83
 }
90
 }
84
 
91
 
85
 /**
92
 /**
88
  * @ret triggered	ISR has been triggered since last check
95
  * @ret triggered	ISR has been triggered since last check
89
  */
96
  */
90
 static int undi_isr_triggered ( void ) {
97
 static int undi_isr_triggered ( void ) {
91
-	static unsigned int last_trigger_count;
98
+	static unsigned int last_trigger_count = 0;
92
 	unsigned int this_trigger_count;
99
 	unsigned int this_trigger_count;
93
 
100
 
94
 	/* Read trigger_count.  Do this only once; it is volatile */
101
 	/* Read trigger_count.  Do this only once; it is volatile */
285
 	struct s_PXENV_UNDI_OPEN open;
292
 	struct s_PXENV_UNDI_OPEN open;
286
 	int rc;
293
 	int rc;
287
 
294
 
288
-	/* Hook interrupt service routine */
295
+	/* Hook interrupt service routine and enable interrupt */
289
 	undi_hook_isr ( pxe->irq );
296
 	undi_hook_isr ( pxe->irq );
297
+	enable_irq ( pxe->irq );
290
 
298
 
291
 	/* Set station address.  Required for some PXE stacks; will
299
 	/* Set station address.  Required for some PXE stacks; will
292
 	 * spuriously fail on others.  Ignore failures.  We only ever
300
 	 * spuriously fail on others.  Ignore failures.  We only ever
307
 	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_OPEN, &open,
315
 	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_OPEN, &open,
308
 			       sizeof ( open ) ) ) != 0 ) {
316
 			       sizeof ( open ) ) ) != 0 ) {
309
 		DBG ( "UNDI_OPEN failed: %s\n", strerror ( rc ) );
317
 		DBG ( "UNDI_OPEN failed: %s\n", strerror ( rc ) );
310
-		return rc;
318
+		goto err;
311
 	}
319
 	}
312
 
320
 
313
 	return 0;
321
 	return 0;
322
+
323
+ err:
324
+	undi_close ( netdev );
325
+	return rc;
314
 }
326
 }
315
 
327
 
316
 /**
328
 /**
329
 		DBG ( "UNDI_CLOSE failed: %s\n", strerror ( rc ) );
341
 		DBG ( "UNDI_CLOSE failed: %s\n", strerror ( rc ) );
330
 	}
342
 	}
331
 
343
 
332
-	/* Unhook ISR */
344
+	/* Disable interrupt and unhook ISR */
345
+	disable_irq ( pxe->irq );
333
 	undi_unhook_isr ( pxe->irq );
346
 	undi_unhook_isr ( pxe->irq );
334
 }
347
 }
335
 
348
 
369
 
382
 
370
  err:
383
  err:
371
 	free_netdev ( netdev );
384
 	free_netdev ( netdev );
385
+	pxe_set_drvdata ( pxe, NULL );
372
 	return rc;
386
 	return rc;
373
 }
387
 }
374
 
388
 

Loading…
Cancel
Save