Browse Source

[phantom] Guard against partially-written status descriptors

Conjecture: The hardware issues 64-bit DMA writes of status descriptors,
which some PCI bridges seem to split into two 32-bit writes in reverse
order (i.e. dword 1 first).  This means that we sometimes observe a
partial status descriptor.  Add an explicit check to ensure that the
descriptor is complete before processing it.

Also ensure that the RDS consumer counter is incremented only when we
know that we have actually consumed an RX descriptor.
tags/v0.9.4
Michael Brown 16 years ago
parent
commit
4e033c774b
1 changed files with 28 additions and 15 deletions
  1. 28
    15
      src/drivers/net/phantom/phantom.c

+ 28
- 15
src/drivers/net/phantom/phantom.c View File

@@ -1445,9 +1445,20 @@ static void phantom_poll ( struct net_device *netdev ) {
1445 1445
 
1446 1446
 		/* Check received opcode */
1447 1447
 		sds_opcode = NX_GET ( sds, opcode );
1448
-		switch ( sds_opcode ) {
1449
-		case UNM_RXPKT_DESC:
1450
-		case UNM_SYN_OFFLOAD:
1448
+		if ( ( sds_opcode == UNM_RXPKT_DESC ) ||
1449
+		     ( sds_opcode == UNM_SYN_OFFLOAD ) ) {
1450
+
1451
+			/* Sanity check: ensure that all of the SDS
1452
+			 * descriptor has been written.
1453
+			 */
1454
+			if ( NX_GET ( sds, total_length ) == 0 ) {
1455
+				DBGC ( phantom, "Phantom %p port %d SDS %d "
1456
+				       "incomplete; deferring\n", phantom,
1457
+				       phantom_port->port, sds_consumer_idx );
1458
+				/* Leave for next poll() */
1459
+				break;
1460
+			}
1461
+
1451 1462
 			/* Process received packet */
1452 1463
 			sds_handle = NX_GET ( sds, handle );
1453 1464
 			iobuf = phantom_port->rds_iobuf[sds_handle];
@@ -1459,25 +1470,27 @@ static void phantom_poll ( struct net_device *netdev ) {
1459 1470
 				phantom, phantom_port->port, sds_handle );
1460 1471
 			netdev_rx ( netdev, iobuf );
1461 1472
 			phantom_port->rds_iobuf[sds_handle] = NULL;
1462
-			break;
1463
-		default:
1473
+
1474
+			/* Update RDS consumer counter.  This is a
1475
+			 * lower bound for the number of descriptors
1476
+			 * that have been read by the hardware, since
1477
+			 * the hardware must have read at least one
1478
+			 * descriptor for each completion that we
1479
+			 * receive.
1480
+			 */
1481
+			rds_consumer_idx =
1482
+				( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS );
1483
+			phantom_port->rds_consumer_idx = rds_consumer_idx;
1484
+
1485
+		} else {
1486
+
1464 1487
 			DBGC ( phantom, "Phantom %p port %d unexpected SDS "
1465 1488
 			       "opcode %02x\n",
1466 1489
 			       phantom, phantom_port->port, sds_opcode );
1467 1490
 			DBGC_HDA ( phantom, virt_to_bus ( sds ),
1468 1491
 				   sds, sizeof ( *sds ) );
1469
-			break;
1470 1492
 		}
1471 1493
 			
1472
-		/* Update RDS consumer counter.  This is a lower bound
1473
-		 * for the number of descriptors that have been read
1474
-		 * by the hardware, since the hardware must have read
1475
-		 * at least one descriptor for each completion that we
1476
-		 * receive.
1477
-		 */
1478
-		rds_consumer_idx = ( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS );
1479
-		phantom_port->rds_consumer_idx = rds_consumer_idx;
1480
-
1481 1494
 		/* Clear status descriptor */
1482 1495
 		memset ( sds, 0, sizeof ( *sds ) );
1483 1496
 

Loading…
Cancel
Save