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
 
1445
 
1446
 		/* Check received opcode */
1446
 		/* Check received opcode */
1447
 		sds_opcode = NX_GET ( sds, opcode );
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
 			/* Process received packet */
1462
 			/* Process received packet */
1452
 			sds_handle = NX_GET ( sds, handle );
1463
 			sds_handle = NX_GET ( sds, handle );
1453
 			iobuf = phantom_port->rds_iobuf[sds_handle];
1464
 			iobuf = phantom_port->rds_iobuf[sds_handle];
1459
 				phantom, phantom_port->port, sds_handle );
1470
 				phantom, phantom_port->port, sds_handle );
1460
 			netdev_rx ( netdev, iobuf );
1471
 			netdev_rx ( netdev, iobuf );
1461
 			phantom_port->rds_iobuf[sds_handle] = NULL;
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
 			DBGC ( phantom, "Phantom %p port %d unexpected SDS "
1487
 			DBGC ( phantom, "Phantom %p port %d unexpected SDS "
1465
 			       "opcode %02x\n",
1488
 			       "opcode %02x\n",
1466
 			       phantom, phantom_port->port, sds_opcode );
1489
 			       phantom, phantom_port->port, sds_opcode );
1467
 			DBGC_HDA ( phantom, virt_to_bus ( sds ),
1490
 			DBGC_HDA ( phantom, virt_to_bus ( sds ),
1468
 				   sds, sizeof ( *sds ) );
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
 		/* Clear status descriptor */
1494
 		/* Clear status descriptor */
1482
 		memset ( sds, 0, sizeof ( *sds ) );
1495
 		memset ( sds, 0, sizeof ( *sds ) );
1483
 
1496
 

Loading…
Cancel
Save