소스 검색

[intel] Push new RX descriptors in batches

Inside a virtual machine, writing the RX ring tail pointer may incur a
substantial overhead of processing inside the hypervisor.  Minimise
this overhead by writing the tail pointer once per batch of
descriptors, rather than once per descriptor.

Profiling under qemu-kvm (version 1.6.2) shows that this reduces the
amount of time taken to refill the RX descriptor ring by around 90%.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 년 전
부모
커밋
b2c7b6a85e
1개의 변경된 파일13개의 추가작업 그리고 8개의 파일을 삭제
  1. 13
    8
      src/drivers/net/intel.c

+ 13
- 8
src/drivers/net/intel.c 파일 보기

456
 	unsigned int rx_idx;
456
 	unsigned int rx_idx;
457
 	unsigned int rx_tail;
457
 	unsigned int rx_tail;
458
 	physaddr_t address;
458
 	physaddr_t address;
459
+	unsigned int refilled = 0;
459
 
460
 
461
+	/* Refill ring */
460
 	while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) {
462
 	while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) {
461
 
463
 
462
 		/* Allocate I/O buffer */
464
 		/* Allocate I/O buffer */
463
 		iobuf = alloc_iob ( INTEL_RX_MAX_LEN );
465
 		iobuf = alloc_iob ( INTEL_RX_MAX_LEN );
464
 		if ( ! iobuf ) {
466
 		if ( ! iobuf ) {
465
 			/* Wait for next refill */
467
 			/* Wait for next refill */
466
-			return;
468
+			break;
467
 		}
469
 		}
468
 
470
 
469
 		/* Get next receive descriptor */
471
 		/* Get next receive descriptor */
470
 		rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC );
472
 		rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC );
471
-		rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC );
472
 		rx = &intel->rx.desc[rx_idx];
473
 		rx = &intel->rx.desc[rx_idx];
473
 
474
 
474
 		/* Populate receive descriptor */
475
 		/* Populate receive descriptor */
477
 		rx->length = 0;
478
 		rx->length = 0;
478
 		rx->status = 0;
479
 		rx->status = 0;
479
 		rx->errors = 0;
480
 		rx->errors = 0;
480
-		wmb();
481
 
481
 
482
 		/* Record I/O buffer */
482
 		/* Record I/O buffer */
483
 		assert ( intel->rx_iobuf[rx_idx] == NULL );
483
 		assert ( intel->rx_iobuf[rx_idx] == NULL );
484
 		intel->rx_iobuf[rx_idx] = iobuf;
484
 		intel->rx_iobuf[rx_idx] = iobuf;
485
 
485
 
486
-		/* Push descriptor to card */
487
-		profile_start ( &intel_vm_refill_profiler );
488
-		writel ( rx_tail, intel->regs + intel->rx.reg + INTEL_xDT );
489
-		profile_stop ( &intel_vm_refill_profiler );
490
-
491
 		DBGC2 ( intel, "INTEL %p RX %d is [%llx,%llx)\n", intel, rx_idx,
486
 		DBGC2 ( intel, "INTEL %p RX %d is [%llx,%llx)\n", intel, rx_idx,
492
 			( ( unsigned long long ) address ),
487
 			( ( unsigned long long ) address ),
493
 			( ( unsigned long long ) address + INTEL_RX_MAX_LEN ) );
488
 			( ( unsigned long long ) address + INTEL_RX_MAX_LEN ) );
489
+		refilled++;
490
+	}
491
+
492
+	/* Push descriptors to card, if applicable */
493
+	if ( refilled ) {
494
+		wmb();
495
+		rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC );
496
+		profile_start ( &intel_vm_refill_profiler );
497
+		writel ( rx_tail, intel->regs + intel->rx.reg + INTEL_xDT );
498
+		profile_stop ( &intel_vm_refill_profiler );
494
 	}
499
 	}
495
 }
500
 }
496
 
501
 

Loading…
취소
저장