Browse Source

Work around Etherboot 5.4 bug when multiple packets are received.

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
2dc8ed1eb8
1 changed files with 38 additions and 1 deletions
  1. 38
    1
      src/arch/i386/drivers/net/undinet.c

+ 38
- 1
src/arch/i386/drivers/net/undinet.c View File

@@ -45,8 +45,20 @@ struct undi_nic {
45 45
 	unsigned int irq;
46 46
 	/** Currently processing ISR */
47 47
 	int isr_processing;
48
+	/** Bug workarounds */
49
+	int hacks;
48 50
 };
49 51
 
52
+/**
53
+ * @defgroup undi_hacks UNDI workarounds
54
+ * @{
55
+ */
56
+
57
+/** Work around Etherboot 5.4 bugs */
58
+#define UNDI_HACK_EB54		0x0001
59
+
60
+/** @} */
61
+
50 62
 static void undinet_close ( struct net_device *netdev );
51 63
 
52 64
 /*****************************************************************************
@@ -245,6 +257,9 @@ static struct segoff prev_handler[ IRQ_MAX + 1 ];
245 257
 static volatile uint8_t __text16 ( trigger_count ) = 0;
246 258
 #define trigger_count __use_text16 ( trigger_count )
247 259
 
260
+/** Last observed trigger count */
261
+static unsigned int last_trigger_count = 0;
262
+
248 263
 /**
249 264
  * Hook UNDI interrupt service routine
250 265
  *
@@ -292,7 +307,6 @@ static void undinet_unhook_isr ( unsigned int irq ) {
292 307
  * @ret triggered	ISR has been triggered since last check
293 308
  */
294 309
 static int undinet_isr_triggered ( void ) {
295
-	static unsigned int last_trigger_count = 0;
296 310
 	unsigned int this_trigger_count;
297 311
 
298 312
 	/* Read trigger_count.  Do this only once; it is volatile */
@@ -470,9 +484,15 @@ static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) {
470 484
 					 undi_isr.Frame.segment,
471 485
 					 undi_isr.Frame.offset, frag_len );
472 486
 			if ( iob_len ( iobuf ) == len ) {
487
+				/* Whole packet received; deliver it */
473 488
 				netdev_rx ( netdev, iobuf );
474 489
 				iobuf = NULL;
475 490
 				--rx_quota;
491
+				/* Etherboot 5.4 fails to return all packets
492
+				 * under mild load; pretend it retriggered.
493
+				 */
494
+				if ( undinic->hacks & UNDI_HACK_EB54 )
495
+					--last_trigger_count;
476 496
 			}
477 497
 			break;
478 498
 		case PXENV_UNDI_ISR_OUT_DONE:
@@ -592,6 +612,7 @@ int undinet_probe ( struct undi_device *undi ) {
592 612
 	struct s_PXENV_UNDI_STARTUP undi_startup;
593 613
 	struct s_PXENV_UNDI_INITIALIZE undi_initialize;
594 614
 	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
615
+	struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
595 616
 	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
596 617
 	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
597 618
 	struct s_PXENV_STOP_UNDI stop_undi;
@@ -649,6 +670,21 @@ int undinet_probe ( struct undi_device *undi ) {
649 670
 	DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
650 671
 	       undinic, eth_ntoa ( netdev->ll_addr ), undinic->irq );
651 672
 
673
+	/* Get interface information */
674
+	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
675
+	if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_IFACE_INFO,
676
+				   &undi_iface,
677
+				   sizeof ( undi_iface ) ) ) != 0 )
678
+		goto err_undi_get_iface_info;
679
+	DBGC ( undinic, "UNDINIC %p has type %s and link speed %ld\n",
680
+	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed );
681
+	if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
682
+		       sizeof ( undi_iface.IfaceType ) ) == 0 ) {
683
+		DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
684
+		       undinic );
685
+		undinic->hacks |= UNDI_HACK_EB54;
686
+	}
687
+
652 688
 	/* Point to NIC specific routines */
653 689
 	netdev->open	 = undinet_open;
654 690
 	netdev->close	 = undinet_close;
@@ -663,6 +699,7 @@ int undinet_probe ( struct undi_device *undi ) {
663 699
 	return 0;
664 700
 
665 701
  err_register:
702
+ err_undi_get_iface_info:
666 703
  err_bad_irq:
667 704
  err_undi_get_information:
668 705
  err_undi_initialize:

Loading…
Cancel
Save