瀏覽代碼

[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 13 年之前
父節點
當前提交
006d9f1f60
共有 1 個文件被更改,包括 31 次插入17 次删除
  1. 31
    17
      src/arch/i386/drivers/net/undinet.c

+ 31
- 17
src/arch/i386/drivers/net/undinet.c 查看文件

@@ -43,6 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
43 43
 
44 44
 /** An UNDI NIC */
45 45
 struct undi_nic {
46
+	/** Device supports IRQs */
47
+	int irq_supported;
46 48
 	/** Assigned IRQ number */
47 49
 	unsigned int irq;
48 50
 	/** Currently processing ISR */
@@ -251,8 +253,10 @@ static void undinet_poll ( struct net_device *netdev ) {
251 253
 	int rc;
252 254
 
253 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 260
 			/* Allow interrupt to occur */
257 261
 			__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
258 262
 							   "nop\n\t"
@@ -357,10 +361,12 @@ static int undinet_open ( struct net_device *netdev ) {
357 361
 	struct s_PXENV_UNDI_OPEN undi_open;
358 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 371
 	/* Set station address.  Required for some PXE stacks; will
366 372
 	 * spuriously fail on others.  Ignore failures.  We only ever
@@ -425,9 +431,11 @@ static void undinet_close ( struct net_device *netdev ) {
425 431
 	pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
426 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 440
 	DBGC ( undinic, "UNDINIC %p closed\n", undinic );
433 441
 }
@@ -524,13 +532,8 @@ int undinet_probe ( struct undi_device *undi ) {
524 532
 		goto err_undi_get_information;
525 533
 	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
526 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 538
 	/* Get interface information */
536 539
 	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
@@ -541,6 +544,17 @@ int undinet_probe ( struct undi_device *undi ) {
541 544
 	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
542 545
 	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
543 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 558
 	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
545 559
 		       sizeof ( undi_iface.IfaceType ) ) == 0 ) {
546 560
 		DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
@@ -559,8 +573,8 @@ int undinet_probe ( struct undi_device *undi ) {
559 573
 	return 0;
560 574
 
561 575
  err_register:
562
- err_undi_get_iface_info:
563 576
  err_bad_irq:
577
+ err_undi_get_iface_info:
564 578
  err_undi_get_information:
565 579
  err_undi_initialize:
566 580
 	/* Shut down UNDI stack */

Loading…
取消
儲存