Browse Source

Merge branch 'master' of /pub/scm/gpxe

tags/v0.9.3
Marty Connor 17 years ago
parent
commit
4bcfe7507b

+ 48
- 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 */
@@ -333,6 +347,16 @@ static int undinet_transmit ( struct net_device *netdev,
333 347
 	size_t len = iob_len ( iobuf );
334 348
 	int rc;
335 349
 
350
+	/* Technically, we ought to make sure that the previous
351
+	 * transmission has completed before we re-use the buffer.
352
+	 * However, many PXE stacks (including at least some Intel PXE
353
+	 * stacks and Etherboot 5.4) fail to generate TX completions.
354
+	 * In practice this won't be a problem, since our TX datapath
355
+	 * has a very low packet volume and we can get away with
356
+	 * assuming that a TX will be complete by the time we want to
357
+	 * transmit the next packet.
358
+	 */
359
+
336 360
 	/* Copy packet to UNDI I/O buffer */
337 361
 	if ( len > sizeof ( basemem_packet ) )
338 362
 		len = sizeof ( basemem_packet );
@@ -460,9 +484,15 @@ static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) {
460 484
 					 undi_isr.Frame.segment,
461 485
 					 undi_isr.Frame.offset, frag_len );
462 486
 			if ( iob_len ( iobuf ) == len ) {
487
+				/* Whole packet received; deliver it */
463 488
 				netdev_rx ( netdev, iobuf );
464 489
 				iobuf = NULL;
465 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;
466 496
 			}
467 497
 			break;
468 498
 		case PXENV_UNDI_ISR_OUT_DONE:
@@ -582,6 +612,7 @@ int undinet_probe ( struct undi_device *undi ) {
582 612
 	struct s_PXENV_UNDI_STARTUP undi_startup;
583 613
 	struct s_PXENV_UNDI_INITIALIZE undi_initialize;
584 614
 	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
615
+	struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
585 616
 	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
586 617
 	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
587 618
 	struct s_PXENV_STOP_UNDI stop_undi;
@@ -639,6 +670,21 @@ int undinet_probe ( struct undi_device *undi ) {
639 670
 	DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
640 671
 	       undinic, eth_ntoa ( netdev->ll_addr ), undinic->irq );
641 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
+
642 688
 	/* Point to NIC specific routines */
643 689
 	netdev->open	 = undinet_open;
644 690
 	netdev->close	 = undinet_close;
@@ -653,6 +699,7 @@ int undinet_probe ( struct undi_device *undi ) {
653 699
 	return 0;
654 700
 
655 701
  err_register:
702
+ err_undi_get_iface_info:
656 703
  err_bad_irq:
657 704
  err_undi_get_information:
658 705
  err_undi_initialize:

+ 1
- 1
src/drivers/bus/isapnp.c View File

@@ -529,7 +529,7 @@ static int isapnp_try_isolate ( void ) {
529 529
  *
530 530
  */
531 531
 static void isapnp_isolate ( void ) {
532
-	for ( isapnp_read_port = ISAPNP_READ_PORT_MIN ;
532
+	for ( isapnp_read_port = ISAPNP_READ_PORT_START ;
533 533
 	      isapnp_read_port <= ISAPNP_READ_PORT_MAX ;
534 534
 	      isapnp_read_port += ISAPNP_READ_PORT_STEP ) {
535 535
 		/* Avoid problematic locations such as the NE2000

+ 8
- 3
src/drivers/net/legacy.c View File

@@ -57,12 +57,17 @@ static void legacy_poll ( struct net_device *netdev, unsigned int rx_quota ) {
57 57
 	}
58 58
 }
59 59
 
60
-static int legacy_open ( struct net_device *netdev __unused ) {
60
+static int legacy_open ( struct net_device *netdev ) {
61
+	struct nic *nic = netdev->priv;
62
+
63
+	nic->nic_op->irq ( nic, ENABLE );
61 64
 	return 0;
62 65
 }
63 66
 
64
-static void legacy_close ( struct net_device *netdev __unused ) {
65
-	/* Nothing to do */
67
+static void legacy_close ( struct net_device *netdev ) {
68
+	struct nic *nic = netdev->priv;
69
+
70
+	nic->nic_op->irq ( nic, DISABLE );
66 71
 }
67 72
 
68 73
 int legacy_probe ( void *hwdev,

+ 0
- 23
src/drivers/net/pnic.c View File

@@ -160,29 +160,6 @@ static int pnic_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
160 160
 	return 0;
161 161
 }
162 162
 
163
-/**************************************************************************
164
-IRQ - Handle card interrupt status
165
-***************************************************************************/
166
-#if 0
167
-static void pnic_irq ( struct net_device *netdev, irq_action_t action ) {
168
-	struct pnic *pnic = netdev->priv;
169
-	uint8_t enabled;
170
-
171
-	switch ( action ) {
172
-	case DISABLE :
173
-	case ENABLE :
174
-		enabled = ( action == ENABLE ? 1 : 0 );
175
-		pnic_command ( pnic, PNIC_CMD_MASK_IRQ,
176
-			       &enabled, sizeof ( enabled ), NULL, 0, NULL );
177
-		break;
178
-	case FORCE :
179
-		pnic_command ( pnic, PNIC_CMD_FORCE_IRQ,
180
-			       NULL, 0, NULL, 0, NULL );
181
-		break;
182
-	}
183
-}
184
-#endif
185
-
186 163
 /**************************************************************************
187 164
 OPEN - Open network device
188 165
 ***************************************************************************/

+ 1
- 30
src/drivers/net/rtl8139.c View File

@@ -380,8 +380,7 @@ static int rtl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
380 380
 
381 381
 	/* Check for space in TX ring */
382 382
 	if ( rtl->tx.iobuf[rtl->tx.next] != NULL ) {
383
-		printf ( "TX overflow\n" );
384
-		free_iob ( iobuf );
383
+		DBG ( "TX overflow\n" );
385 384
 		return -ENOBUFS;
386 385
 	}
387 386
 
@@ -472,34 +471,6 @@ static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) {
472 471
 	}
473 472
 }
474 473
 
475
-#if 0
476
-static void rtl_irq(struct nic *nic, irq_action_t action)
477
-{
478
-	unsigned int mask;
479
-	/* Bit of a guess as to which interrupts we should allow */
480
-	unsigned int interested = ROK | RER | RXOVW | FOVW | SERR;
481
-
482
-	switch ( action ) {
483
-	case DISABLE :
484
-	case ENABLE :
485
-		mask = inw(rtl->ioaddr + IntrMask);
486
-		mask = mask & ~interested;
487
-		if ( action == ENABLE ) mask = mask | interested;
488
-		outw(mask, rtl->ioaddr + IntrMask);
489
-		break;
490
-	case FORCE :
491
-		/* Apparently writing a 1 to this read-only bit of a
492
-		 * read-only and otherwise unrelated register will
493
-		 * force an interrupt.  If you ever want to see how
494
-		 * not to write a datasheet, read the one for the
495
-		 * RTL8139...
496
-		 */
497
-		outb(EROK, rtl->ioaddr + RxEarlyStatus);
498
-		break;
499
-	}
500
-}
501
-#endif
502
-
503 474
 /**
504 475
  * Probe PCI device
505 476
  *

+ 6
- 1
src/include/gpxe/isapnp.h View File

@@ -49,7 +49,8 @@
49 49
 /* Port addresses */
50 50
 #define ISAPNP_ADDRESS		0x279
51 51
 #define ISAPNP_WRITE_DATA	0xa79
52
-#define ISAPNP_READ_PORT_MIN	0x213	/* ISAPnP spec says 0x203, but
52
+#define ISAPNP_READ_PORT_MIN	0x203
53
+#define ISAPNP_READ_PORT_START	0x213	/* ISAPnP spec says 0x203, but
53 54
 					 * Linux ISAPnP starts at
54 55
 					 * 0x213 with no explanatory
55 56
 					 * comment.  0x203 probably
@@ -63,6 +64,10 @@
63 64
 					 * any value less than 16.
64 65
 					 */
65 66
 
67
+/* Card select numbers */
68
+#define ISAPNP_CSN_MIN		0x01
69
+#define ISAPNP_CSN_MAX		0x0f
70
+
66 71
 /* Registers */
67 72
 #define ISAPNP_READPORT			0x00
68 73
 #define ISAPNP_SERIALISOLATION 		0x01

+ 6
- 5
src/include/gpxe/netdevice.h View File

@@ -289,8 +289,9 @@ netdev_put ( struct net_device *netdev ) {
289 289
 }
290 290
 
291 291
 extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf );
292
-void netdev_tx_complete ( struct net_device *netdev, struct io_buffer *iobuf );
293
-void netdev_tx_complete_next ( struct net_device *netdev );
292
+extern void netdev_tx_complete ( struct net_device *netdev,
293
+				 struct io_buffer *iobuf );
294
+extern void netdev_tx_complete_next ( struct net_device *netdev );
294 295
 extern void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf );
295 296
 extern int netdev_poll ( struct net_device *netdev, unsigned int rx_quota );
296 297
 extern struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev );
@@ -299,9 +300,9 @@ extern int register_netdev ( struct net_device *netdev );
299 300
 extern int netdev_open ( struct net_device *netdev );
300 301
 extern void netdev_close ( struct net_device *netdev );
301 302
 extern void unregister_netdev ( struct net_device *netdev );
302
-struct net_device * find_netdev ( const char *name );
303
-struct net_device * find_pci_netdev ( unsigned int busdevfn );
304
-
303
+extern struct net_device * find_netdev ( const char *name );
304
+extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
305
+						     unsigned int location );
305 306
 extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
306 307
 		    struct net_protocol *net_protocol, const void *ll_dest );
307 308
 extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev,

+ 41
- 32
src/interface/pxe/pxe_preboot.c View File

@@ -28,6 +28,9 @@
28 28
 #include <stdlib.h>
29 29
 #include <gpxe/uaccess.h>
30 30
 #include <gpxe/dhcp.h>
31
+#include <gpxe/device.h>
32
+#include <gpxe/netdevice.h>
33
+#include <gpxe/isapnp.h>
31 34
 #include <basemem_packet.h>
32 35
 #include "pxe.h"
33 36
 #include "pxe_call.h"
@@ -196,41 +199,47 @@ PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
196 199
  * Status: working
197 200
  */
198 201
 PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
202
+	unsigned int isapnp_read_port;
203
+	unsigned int isapnp_csn;
204
+	unsigned int pci_busdevfn;
205
+	unsigned int bus_type;
206
+	unsigned int location;
207
+	struct net_device *netdev;
208
+
209
+	DBG ( "PXENV_START_UNDI %04x:%04x:%04x",
210
+	      start_undi->AX, start_undi->BX, start_undi->DX );
211
+
212
+	/* Determine bus type and location */
213
+	isapnp_read_port = start_undi->DX;
214
+	isapnp_csn = start_undi->BX;
215
+	pci_busdevfn = start_undi->AX;
216
+
217
+	/* Use a heuristic to decide whether we are PCI or ISAPnP */
218
+	if ( ( isapnp_read_port >= ISAPNP_READ_PORT_MIN ) &&
219
+	     ( isapnp_read_port <= ISAPNP_READ_PORT_MAX ) &&
220
+	     ( isapnp_csn >= ISAPNP_CSN_MIN ) &&
221
+	     ( isapnp_csn <= ISAPNP_CSN_MAX ) ) {
222
+		bus_type = BUS_TYPE_ISAPNP;
223
+		location = isapnp_csn;
224
+	} else {
225
+		bus_type = BUS_TYPE_PCI;
226
+		location = pci_busdevfn;
227
+	}
199 228
 
200
-	DBG ( "PXENV_START_UNDI" );
201
-
202
-#if 0
203
-	/* Record PCI bus & devfn passed by caller, so we know which
204
-	 * NIC they want to use.
205
-	 *
206
-	 * If they don't match our already-existing NIC structure, set
207
-	 * values to ensure that the specified NIC is used at the next
208
-	 * call to pxe_intialise_nic().
209
-	 */
210
-	bus = ( start_undi->AX >> 8 ) & 0xff;
211
-	devfn = start_undi->AX & 0xff;
212
-
213
-#warning "device probing mechanism has completely changed"
214
-#if 0
215
-	if ( ( pci->dev.driver == NULL ) ||
216
-	     ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
217
-		/* This is quite a bit of a hack and relies on
218
-		 * knowledge of the internal operation of Etherboot's
219
-		 * probe mechanism.
220
-		 */
221
-		DBG ( " set PCI %hhx:%hhx.%hhx",
222
-		      bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
223
-		dev->type = BOOT_NIC;
224
-		dev->to_probe = PROBE_PCI;
225
-		memset ( &dev->state, 0, sizeof(dev->state) );
226
-		pci->advance = 1;
227
-		pci->dev.use_specified = 1;
228
-		pci->dev.bus = bus;
229
-		pci->dev.devfn = devfn;
229
+	/* Look for a matching net device */
230
+	netdev = find_netdev_by_location ( bus_type, location );
231
+	if ( ! netdev ) {
232
+		DBG ( " no net device found" );
233
+		start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC;
234
+		return PXENV_EXIT_FAILURE;
230 235
 	}
231
-#endif
236
+	DBG ( " using netdev %s", netdev->name );
232 237
 
233
-#endif
238
+	/* Save as PXE net device */
239
+	pxe_set_netdev ( netdev );
240
+
241
+	/* Hook INT 1A */
242
+	pxe_hook_int1a();
234 243
 
235 244
 	start_undi->Status = PXENV_STATUS_SUCCESS;
236 245
 	return PXENV_EXIT_SUCCESS;

+ 5
- 8
src/interface/pxe/pxe_undi.c View File

@@ -394,18 +394,15 @@ PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
394 394
 
395 395
 /* PXENV_UNDI_FORCE_INTERRUPT
396 396
  *
397
- * Status: working
397
+ * Status: won't implement (would require driver API changes for no
398
+ * perceptible benefit)
398 399
  */
399 400
 PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
400 401
 					  *undi_force_interrupt ) {
401 402
 	DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
402 403
 
403
-#if 0
404
-	eth_irq ( FORCE );
405
-#endif
406
-
407
-	undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
408
-	return PXENV_EXIT_SUCCESS;
404
+	undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
405
+	return PXENV_EXIT_FAILURE;
409 406
 }
410 407
 
411 408
 /* PXENV_UNDI_GET_MCAST_ADDRESS
@@ -483,7 +480,7 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
483 480
 	 * Most PXE stacks seem to take this approach.
484 481
 	 */
485 482
 	snprintf ( ( char * ) undi_get_iface_info->IfaceType,
486
-		   sizeof ( undi_get_iface_info->IfaceType ), "Etherboot" );
483
+		   sizeof ( undi_get_iface_info->IfaceType ), "gPXE" );
487 484
 	undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
488 485
 	undi_get_iface_info->ServiceFlags = 0;
489 486
 	memset ( undi_get_iface_info->Reserved, 0,

+ 8
- 0
src/net/ipv4.c View File

@@ -141,12 +141,20 @@ void del_ipv4_address ( struct net_device *netdev ) {
141 141
  * @v dest		Final destination address
142 142
  * @ret dest		Next hop destination address
143 143
  * @ret miniroute	Routing table entry to use, or NULL if no route
144
+ *
145
+ * If the route requires use of a gateway, the next hop destination
146
+ * address will be overwritten with the gateway address.
144 147
  */
145 148
 static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
146 149
 	struct ipv4_miniroute *miniroute;
147 150
 	int local;
148 151
 	int has_gw;
149 152
 
153
+	/* Never attempt to route the broadcast address */
154
+	if ( dest->s_addr == INADDR_BROADCAST )
155
+		return NULL;
156
+
157
+	/* Find first usable route in routing table */
150 158
 	list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
151 159
 		local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
152 160
 			    & miniroute->netmask.s_addr ) == 0 );

+ 6
- 4
src/net/netdevice.c View File

@@ -356,15 +356,17 @@ struct net_device * find_netdev ( const char *name ) {
356 356
 /**
357 357
  * Get network device by PCI bus:dev.fn address
358 358
  *
359
- * @v busdevfn		PCI bus:dev.fn address
359
+ * @v bus_type		Bus type
360
+ * @v location		Bus location
360 361
  * @ret netdev		Network device, or NULL
361 362
  */
362
-struct net_device * find_pci_netdev ( unsigned int busdevfn ) {
363
+struct net_device * find_netdev_by_location ( unsigned int bus_type,
364
+					      unsigned int location ) {
363 365
 	struct net_device *netdev;
364 366
 
365 367
 	list_for_each_entry ( netdev, &net_devices, list ) {
366
-		if ( ( netdev->dev->desc.bus_type == BUS_TYPE_PCI ) &&
367
-		     ( netdev->dev->desc.location == busdevfn ) )
368
+		if ( ( netdev->dev->desc.bus_type == bus_type ) &&
369
+		     ( netdev->dev->desc.location == location ) )
368 370
 			return netdev;
369 371
 	}
370 372
 

Loading…
Cancel
Save