Browse Source

[undi] Support underlying UNDI devices that don't support interrupts

Some network cards do not generate interrupts when operated via the
UNDI API.  Allow for this by waiting for the ISR to be triggered only
if the PXE stack advertises that it supports interrupts.  When the PXE
stack does not advertise interrupt support, we skip the call to
PXENV_UNDI_ISR_IN_START and just poll the device using
PXENV_UNDI_ISR_IN_PROCESS.  This matches the observed behaviour of at
least one other PXE NBP (emBoot's winBoot/i), so there is a reasonable
chance of this working.

Originally-implemented-by: Muralidhar Appalla <Muralidhar.Appalla@emulex.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
006d9f1f60
1 changed files with 31 additions and 17 deletions
  1. 31
    17
      src/arch/i386/drivers/net/undinet.c

+ 31
- 17
src/arch/i386/drivers/net/undinet.c View File

43
 
43
 
44
 /** An UNDI NIC */
44
 /** An UNDI NIC */
45
 struct undi_nic {
45
 struct undi_nic {
46
+	/** Device supports IRQs */
47
+	int irq_supported;
46
 	/** Assigned IRQ number */
48
 	/** Assigned IRQ number */
47
 	unsigned int irq;
49
 	unsigned int irq;
48
 	/** Currently processing ISR */
50
 	/** Currently processing ISR */
251
 	int rc;
253
 	int rc;
252
 
254
 
253
 	if ( ! undinic->isr_processing ) {
255
 	if ( ! undinic->isr_processing ) {
254
-		/* Do nothing unless ISR has been triggered */
255
-		if ( ! undinet_isr_triggered() ) {
256
+		/* If interrupts are supported, then do nothing unless
257
+		 * the ISR has been triggered.
258
+		 */
259
+		if ( undinic->irq_supported && ( ! undinet_isr_triggered() ) ){
256
 			/* Allow interrupt to occur */
260
 			/* Allow interrupt to occur */
257
 			__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
261
 			__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
258
 							   "nop\n\t"
262
 							   "nop\n\t"
357
 	struct s_PXENV_UNDI_OPEN undi_open;
361
 	struct s_PXENV_UNDI_OPEN undi_open;
358
 	int rc;
362
 	int rc;
359
 
363
 
360
-	/* Hook interrupt service routine and enable interrupt */
361
-	undinet_hook_isr ( undinic->irq );
362
-	enable_irq ( undinic->irq );
363
-	send_eoi ( undinic->irq );
364
+	/* Hook interrupt service routine and enable interrupt if supported */
365
+	if ( undinic->irq_supported ) {
366
+		undinet_hook_isr ( undinic->irq );
367
+		enable_irq ( undinic->irq );
368
+		send_eoi ( undinic->irq );
369
+	}
364
 
370
 
365
 	/* Set station address.  Required for some PXE stacks; will
371
 	/* Set station address.  Required for some PXE stacks; will
366
 	 * spuriously fail on others.  Ignore failures.  We only ever
372
 	 * spuriously fail on others.  Ignore failures.  We only ever
425
 	pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
431
 	pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
426
 			 &undi_close, sizeof ( undi_close ) );
432
 			 &undi_close, sizeof ( undi_close ) );
427
 
433
 
428
-	/* Disable interrupt and unhook ISR */
429
-	disable_irq ( undinic->irq );
430
-	undinet_unhook_isr ( undinic->irq );
434
+	/* Disable interrupt and unhook ISR if supported */
435
+	if ( undinic->irq_supported ) {
436
+		disable_irq ( undinic->irq );
437
+		undinet_unhook_isr ( undinic->irq );
438
+	}
431
 
439
 
432
 	DBGC ( undinic, "UNDINIC %p closed\n", undinic );
440
 	DBGC ( undinic, "UNDINIC %p closed\n", undinic );
433
 }
441
 }
524
 		goto err_undi_get_information;
532
 		goto err_undi_get_information;
525
 	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
533
 	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
526
 	undinic->irq = undi_info.IntNumber;
534
 	undinic->irq = undi_info.IntNumber;
527
-	if ( undinic->irq > IRQ_MAX ) {
528
-		DBGC ( undinic, "UNDINIC %p invalid IRQ %d\n",
529
-		       undinic, undinic->irq );
530
-		goto err_bad_irq;
531
-	}
532
-	DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
533
-	       undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
535
+	DBGC ( undinic, "UNDINIC %p has MAC address %s\n",
536
+	       undinic, eth_ntoa ( netdev->hw_addr ) );
534
 
537
 
535
 	/* Get interface information */
538
 	/* Get interface information */
536
 	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
539
 	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
541
 	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
544
 	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
542
 	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
545
 	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
543
 	       undi_iface.ServiceFlags );
546
 	       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
+		}
554
+		undinic->irq_supported = 1;
555
+		DBGC ( undinic, "UNDINIC %p uses IRQ %d\n",
556
+		       undinic, undinic->irq );
557
+	}
544
 	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
558
 	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
545
 		       sizeof ( undi_iface.IfaceType ) ) == 0 ) {
559
 		       sizeof ( undi_iface.IfaceType ) ) == 0 ) {
546
 		DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
560
 		DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
559
 	return 0;
573
 	return 0;
560
 
574
 
561
  err_register:
575
  err_register:
562
- err_undi_get_iface_info:
563
  err_bad_irq:
576
  err_bad_irq:
577
+ err_undi_get_iface_info:
564
  err_undi_get_information:
578
  err_undi_get_information:
565
  err_undi_initialize:
579
  err_undi_initialize:
566
 	/* Shut down UNDI stack */
580
 	/* Shut down UNDI stack */

Loading…
Cancel
Save