Browse Source

[undi] Cope with devices that erroneously claim not to use interrupts

Some PXE stacks advertise that interrupts are not supported, despite
requiring the use of interrupts.  Attempt to cope with such cards
without breaking others by always hooking the interrupt, and using the
"interrupts supported" flag only to decide whether or not to wait for
an interrupt before calling PXENV_UNDI_ISR_IN_PROCESS.

The possible combinations are therefore:

1. Card generates interrupts and claims to support interrupts

   iPXE will call PXENV_UNDI_ISR_IN_PROCESS only after an interrupt
   has been observed.  (This is required to avoid lockups in some PXE
   stacks, which spuriously sulk if called before an interrupt has
   been generated.)

   Such a card should work correctly.

2. Card does not generate interrupts and does not claim to support
   interrupts

   iPXE will call PXENV_UNDI_ISR_IN_PROCESS indiscriminately, matching
   the observed behaviour of at least one other PXE NBP (winBoot/i).

   Such a card should work correctly.

3. Card generates interrupts but claims not to support interrupts

   iPXE will call PXENV_UNDI_ISR_IN_PROCESS indiscriminately.  An
   interrupt will still result in a call to PXENV_UNDI_ISR_IN_START.

   Such a card may work correctly.

4. Card does not generate interrupts but claims to support interrupts

   Such a card will not work at all.

Reported-by: Jerry Cheng <jaspers.cheng@msa.hinet.net>
Tested-by: Jerry Cheng <jaspers.cheng@msa.hinet.net>
Reported-by: Mauricio Silveira <mauricio@livreti.com.br>
Tested-by: Mauricio Silveira <mauricio@livreti.com.br>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
b6ca3aa01f
1 changed files with 28 additions and 21 deletions
  1. 28
    21
      src/arch/i386/drivers/net/undinet.c

+ 28
- 21
src/arch/i386/drivers/net/undinet.c View File

253
 	int rc;
253
 	int rc;
254
 
254
 
255
 	if ( ! undinic->isr_processing ) {
255
 	if ( ! undinic->isr_processing ) {
256
-		/* If interrupts are supported, then do nothing unless
257
-		 * the ISR has been triggered.
256
+		/* Allow interrupt to occur.  Do this even if
257
+		 * interrupts are not known to be supported, since
258
+		 * some cards erroneously report that they do not
259
+		 * support interrupts.
258
 		 */
260
 		 */
259
-		if ( undinic->irq_supported && ( ! undinet_isr_triggered() ) ){
261
+		if ( ! undinet_isr_triggered() ) {
260
 			/* Allow interrupt to occur */
262
 			/* Allow interrupt to occur */
261
 			__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
263
 			__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
262
 							   "nop\n\t"
264
 							   "nop\n\t"
263
 							   "nop\n\t"
265
 							   "nop\n\t"
264
 							   "cli\n\t" ) : : );
266
 							   "cli\n\t" ) : : );
265
-			return;
267
+
268
+			/* If interrupts are known to be supported,
269
+			 * then do nothing on this poll; wait for the
270
+			 * interrupt to be triggered.
271
+			 */
272
+			if ( undinic->irq_supported )
273
+				return;
266
 		}
274
 		}
267
 
275
 
268
 		/* Start ISR processing */
276
 		/* Start ISR processing */
361
 	struct s_PXENV_UNDI_OPEN undi_open;
369
 	struct s_PXENV_UNDI_OPEN undi_open;
362
 	int rc;
370
 	int rc;
363
 
371
 
364
-	/* Hook interrupt service routine and enable interrupt if supported */
365
-	if ( undinic->irq_supported ) {
372
+	/* Hook interrupt service routine and enable interrupt if applicable */
373
+	if ( undinic->irq ) {
366
 		undinet_hook_isr ( undinic->irq );
374
 		undinet_hook_isr ( undinic->irq );
367
 		enable_irq ( undinic->irq );
375
 		enable_irq ( undinic->irq );
368
 		send_eoi ( undinic->irq );
376
 		send_eoi ( undinic->irq );
431
 	pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
439
 	pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
432
 			 &undi_close, sizeof ( undi_close ) );
440
 			 &undi_close, sizeof ( undi_close ) );
433
 
441
 
434
-	/* Disable interrupt and unhook ISR if supported */
435
-	if ( undinic->irq_supported ) {
442
+	/* Disable interrupt and unhook ISR if applicable */
443
+	if ( undinic->irq ) {
436
 		disable_irq ( undinic->irq );
444
 		disable_irq ( undinic->irq );
437
 		undinet_unhook_isr ( undinic->irq );
445
 		undinet_unhook_isr ( undinic->irq );
438
 	}
446
 	}
532
 		goto err_undi_get_information;
540
 		goto err_undi_get_information;
533
 	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
541
 	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
534
 	undinic->irq = undi_info.IntNumber;
542
 	undinic->irq = undi_info.IntNumber;
535
-	DBGC ( undinic, "UNDINIC %p has MAC address %s\n",
536
-	       undinic, eth_ntoa ( netdev->hw_addr ) );
543
+	if ( undinic->irq > IRQ_MAX ) {
544
+		DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
545
+		       undinic, undinic->irq );
546
+		rc = -EINVAL;
547
+		goto err_bad_irq;
548
+	}
549
+	DBGC ( undinic, "UNDINIC %p has MAC address %s and IRQ %d\n",
550
+	       undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
537
 
551
 
538
 	/* Get interface information */
552
 	/* Get interface information */
539
 	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
553
 	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
544
 	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
558
 	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
545
 	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
559
 	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
546
 	       undi_iface.ServiceFlags );
560
 	       undi_iface.ServiceFlags );
547
-	if ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) {
548
-		if ( undinic->irq > IRQ_MAX ) {
549
-			DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
550
-			       undinic, undinic->irq );
551
-			rc = -EINVAL;
552
-			goto err_bad_irq;
553
-		}
561
+	if ( undi_iface.ServiceFlags & SUPPORTED_IRQ )
554
 		undinic->irq_supported = 1;
562
 		undinic->irq_supported = 1;
555
-		DBGC ( undinic, "UNDINIC %p uses IRQ %d\n",
556
-		       undinic, undinic->irq );
557
-	}
563
+	DBGC ( undinic, "UNDINIC %p using %s mode\n", undinic,
564
+	       ( undinic->irq_supported ? "interrupt" : "polling" ) );
558
 	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
565
 	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
559
 		       sizeof ( undi_iface.IfaceType ) ) == 0 ) {
566
 		       sizeof ( undi_iface.IfaceType ) ) == 0 ) {
560
 		DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
567
 		DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
573
 	return 0;
580
 	return 0;
574
 
581
 
575
  err_register:
582
  err_register:
576
- err_bad_irq:
577
  err_undi_get_iface_info:
583
  err_undi_get_iface_info:
584
+ err_bad_irq:
578
  err_undi_get_information:
585
  err_undi_get_information:
579
  err_undi_initialize:
586
  err_undi_initialize:
580
 	/* Shut down UNDI stack */
587
 	/* Shut down UNDI stack */

Loading…
Cancel
Save