Browse Source

Protect ISR against failure to unhook.

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
edc4648c39
2 changed files with 19 additions and 34 deletions
  1. 4
    0
      src/arch/i386/drivers/net/undiisr.S
  2. 15
    34
      src/arch/i386/drivers/net/undinet.c

+ 4
- 0
src/arch/i386/drivers/net/undiisr.S View File

22
 	pushw	%ds
22
 	pushw	%ds
23
 	pushw	%es
23
 	pushw	%es
24
 	pusha
24
 	pusha
25
+
26
+	/* Check that we have an UNDI entry point */
27
+	cmpw	$0, undinet_entry_point
28
+	je	chain
25
 	
29
 	
26
 	/* Issue UNDI API call */
30
 	/* Issue UNDI API call */
27
 	movw	%cs:rm_ds, %ax
31
 	movw	%cs:rm_ds, %ax

+ 15
- 34
src/arch/i386/drivers/net/undinet.c View File

39
 
39
 
40
 /** An UNDI NIC */
40
 /** An UNDI NIC */
41
 struct undi_nic {
41
 struct undi_nic {
42
-	/** Entry point */
43
-	SEGOFF16_t entry;
44
 	/** Assigned IRQ number */
42
 	/** Assigned IRQ number */
45
 	unsigned int irq;
43
 	unsigned int irq;
46
 	/** Currently processing ISR */
44
 	/** Currently processing ISR */
167
 	/* Copy parameter block and entry point */
165
 	/* Copy parameter block and entry point */
168
 	assert ( params_len <= sizeof ( undinet_params ) );
166
 	assert ( params_len <= sizeof ( undinet_params ) );
169
 	memcpy ( &undinet_params, params, params_len );
167
 	memcpy ( &undinet_params, params, params_len );
170
-	undinet_entry_point = undinic->entry;
171
 
168
 
172
 	/* Call real-mode entry point.  This calling convention will
169
 	/* Call real-mode entry point.  This calling convention will
173
 	 * work with both the !PXE and the PXENV+ entry points.
170
 	 * work with both the !PXE and the PXENV+ entry points.
222
 		DBGC ( undinic, "UNDINIC %p parameters at %04x:%04x length "
219
 		DBGC ( undinic, "UNDINIC %p parameters at %04x:%04x length "
223
 		       "%#02x, entry point at %04x:%04x\n", undinic,
220
 		       "%#02x, entry point at %04x:%04x\n", undinic,
224
 		       rm_params.segment, rm_params.offset, params_len,
221
 		       rm_params.segment, rm_params.offset, params_len,
225
-		       undinic->entry.segment, undinic->entry.offset );
222
+		       undinet_entry_point.segment,
223
+		       undinet_entry_point.offset );
226
 		DBGC ( undinic, "UNDINIC %p parameters provided:\n", undinic );
224
 		DBGC ( undinic, "UNDINIC %p parameters provided:\n", undinic );
227
 		DBGC_HDA ( undinic, rm_params, params, params_len );
225
 		DBGC_HDA ( undinic, rm_params, params, params_len );
228
 		DBGC ( undinic, "UNDINIC %p parameters returned:\n", undinic );
226
 		DBGC ( undinic, "UNDINIC %p parameters returned:\n", undinic );
268
  * Hook UNDI interrupt service routine
266
  * Hook UNDI interrupt service routine
269
  *
267
  *
270
  * @v irq		IRQ number
268
  * @v irq		IRQ number
271
- *
272
- * The UNDI ISR specifically does @b not chain to the previous
273
- * interrupt handler.  BIOSes seem to install somewhat perverse
274
- * default interrupt handlers; some do nothing other than an iret (and
275
- * so will cause a screaming interrupt if there really is another
276
- * interrupting device) and some disable the interrupt at the PIC (and
277
- * so will bring our own interrupts to a shuddering halt).
278
  */
269
  */
279
 static void undinet_hook_isr ( unsigned int irq ) {
270
 static void undinet_hook_isr ( unsigned int irq ) {
280
 
271
 
411
  * so instead of doing it the easy way we have to go to all the hassle
402
  * so instead of doing it the easy way we have to go to all the hassle
412
  * of installing a genuine interrupt service routine and dealing with
403
  * of installing a genuine interrupt service routine and dealing with
413
  * the wonderful 8259 Programmable Interrupt Controller.  Joy.
404
  * the wonderful 8259 Programmable Interrupt Controller.  Joy.
405
+ *
406
+ * Addendum (10/07/07).  When doing things such as iSCSI boot, in
407
+ * which we have to co-operate with a running OS, we can't get away
408
+ * with the "ISR-just-increments-a-counter-and-returns" trick at all,
409
+ * because it involves tying up the PIC for far too long, and other
410
+ * interrupt-dependent components (e.g. local disks) start breaking.
411
+ * We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR
412
+ * from within interrupt context in order to deassert the device
413
+ * interrupt, and sends EOI if applicable.
414
  */
414
  */
415
 static void undinet_poll ( struct net_device *netdev ) {
415
 static void undinet_poll ( struct net_device *netdev ) {
416
 	struct undi_nic *undinic = netdev->priv;
416
 	struct undi_nic *undinic = netdev->priv;
425
 		if ( ! undinet_isr_triggered() )
425
 		if ( ! undinet_isr_triggered() )
426
 			return;
426
 			return;
427
 
427
 
428
-#if 0
429
-		/* See if this was our interrupt */
430
-		memset ( &undi_isr, 0, sizeof ( undi_isr ) );
431
-		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
432
-		if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
433
-					   sizeof ( undi_isr ) ) ) != 0 )
434
-			return;
435
-
436
-		/* Send EOI to the PIC.  In an ideal world, we'd do
437
-		 * this only for interrupts which the UNDI stack
438
-		 * reports as "ours".  However, since we don't (can't)
439
-		 * chain to the previous interrupt handler, we have to
440
-		 * acknowledge all interrupts.  See undinet_hook_isr()
441
-		 * for more background.
442
-		 */
443
-		send_eoi ( undinic->irq );
444
-
445
-		/* If this wasn't our interrupt, exit now */
446
-		if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
447
-			return;
448
-#endif
449
-		
450
 		/* Start ISR processing */
428
 		/* Start ISR processing */
451
 		undinic->isr_processing = 1;
429
 		undinic->isr_processing = 1;
452
 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
430
 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
651
 	undi_set_drvdata ( undi, netdev );
629
 	undi_set_drvdata ( undi, netdev );
652
 	netdev->dev = &undi->dev;
630
 	netdev->dev = &undi->dev;
653
 	memset ( undinic, 0, sizeof ( *undinic ) );
631
 	memset ( undinic, 0, sizeof ( *undinic ) );
654
-	undinic->entry = undi->entry;
632
+	undinet_entry_point = undi->entry;
655
 	DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
633
 	DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
656
 
634
 
657
 	/* Hook in UNDI stack */
635
 	/* Hook in UNDI stack */
770
 		       sizeof ( stop_undi ) );
748
 		       sizeof ( stop_undi ) );
771
 	undi->flags &= ~UNDI_FL_STARTED;
749
 	undi->flags &= ~UNDI_FL_STARTED;
772
 
750
 
751
+	/* Clear entry point */
752
+	memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
753
+
773
 	/* Free network device */
754
 	/* Free network device */
774
 	netdev_nullify ( netdev );
755
 	netdev_nullify ( netdev );
775
 	netdev_put ( netdev );
756
 	netdev_put ( netdev );

Loading…
Cancel
Save