ソースを参照

Remember to enable/disable the interrupt at the PIC.

Handle failures in undi_open() properly.
tags/v0.9.3
Michael Brown 18年前
コミット
23cb837951
1個のファイルの変更27行の追加13行の削除
  1. 27
    13
      src/arch/i386/drivers/net/undi.c

+ 27
- 13
src/arch/i386/drivers/net/undi.c ファイルの表示

@@ -32,6 +32,8 @@
32 32
  *
33 33
  */
34 34
 
35
+static void undi_close ( struct net_device *netdev );
36
+
35 37
 /*****************************************************************************
36 38
  *
37 39
  * UNDI interrupt service routine
@@ -47,28 +49,33 @@
47 49
  */
48 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 55
 /** IRQ trigger count */
55
-static volatile uint16_t __text16 ( trigger_count );
56
+static volatile uint16_t __text16 ( trigger_count ) = 0;
56 57
 #define trigger_count __use_text16 ( trigger_count )
57 58
 
58 59
 /**
59 60
  * Hook UNDI interrupt service routine
60 61
  *
61 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 71
 static void undi_hook_isr ( unsigned int irq ) {
64 72
 	__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
65 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 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,7 +86,7 @@ static void undi_hook_isr ( unsigned int irq ) {
79 86
  */
80 87
 static void undi_unhook_isr ( unsigned int irq ) {
81 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,7 +95,7 @@ static void undi_unhook_isr ( unsigned int irq ) {
88 95
  * @ret triggered	ISR has been triggered since last check
89 96
  */
90 97
 static int undi_isr_triggered ( void ) {
91
-	static unsigned int last_trigger_count;
98
+	static unsigned int last_trigger_count = 0;
92 99
 	unsigned int this_trigger_count;
93 100
 
94 101
 	/* Read trigger_count.  Do this only once; it is volatile */
@@ -285,8 +292,9 @@ static int undi_open ( struct net_device *netdev ) {
285 292
 	struct s_PXENV_UNDI_OPEN open;
286 293
 	int rc;
287 294
 
288
-	/* Hook interrupt service routine */
295
+	/* Hook interrupt service routine and enable interrupt */
289 296
 	undi_hook_isr ( pxe->irq );
297
+	enable_irq ( pxe->irq );
290 298
 
291 299
 	/* Set station address.  Required for some PXE stacks; will
292 300
 	 * spuriously fail on others.  Ignore failures.  We only ever
@@ -307,10 +315,14 @@ static int undi_open ( struct net_device *netdev ) {
307 315
 	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_OPEN, &open,
308 316
 			       sizeof ( open ) ) ) != 0 ) {
309 317
 		DBG ( "UNDI_OPEN failed: %s\n", strerror ( rc ) );
310
-		return rc;
318
+		goto err;
311 319
 	}
312 320
 
313 321
 	return 0;
322
+
323
+ err:
324
+	undi_close ( netdev );
325
+	return rc;
314 326
 }
315 327
 
316 328
 /**
@@ -329,7 +341,8 @@ static void undi_close ( struct net_device *netdev ) {
329 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 346
 	undi_unhook_isr ( pxe->irq );
334 347
 }
335 348
 
@@ -369,6 +382,7 @@ int undi_probe ( struct pxe_device *pxe ) {
369 382
 
370 383
  err:
371 384
 	free_netdev ( netdev );
385
+	pxe_set_drvdata ( pxe, NULL );
372 386
 	return rc;
373 387
 }
374 388
 

読み込み中…
キャンセル
保存