|
@@ -364,7 +364,8 @@ static int undinet_transmit ( struct net_device *netdev,
|
364
|
364
|
/**
|
365
|
365
|
* Poll for received packets
|
366
|
366
|
*
|
367
|
|
- * @v netdev Network device
|
|
367
|
+ * @v netdev Network device
|
|
368
|
+ * @v rx_quota Maximum number of packets to receive
|
368
|
369
|
*
|
369
|
370
|
* Fun, fun, fun. UNDI drivers don't use polling; they use
|
370
|
371
|
* interrupts. We therefore cheat and pretend that an interrupt has
|
|
@@ -382,7 +383,7 @@ static int undinet_transmit ( struct net_device *netdev,
|
382
|
383
|
* of installing a genuine interrupt service routine and dealing with
|
383
|
384
|
* the wonderful 8259 Programmable Interrupt Controller. Joy.
|
384
|
385
|
*/
|
385
|
|
-static void undinet_poll ( struct net_device *netdev ) {
|
|
386
|
+static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) {
|
386
|
387
|
struct undi_nic *undinic = netdev->priv;
|
387
|
388
|
struct s_PXENV_UNDI_ISR undi_isr;
|
388
|
389
|
struct pk_buff *pkb = NULL;
|
|
@@ -416,7 +417,7 @@ static void undinet_poll ( struct net_device *netdev ) {
|
416
|
417
|
}
|
417
|
418
|
|
418
|
419
|
/* Run through the ISR loop */
|
419
|
|
- while ( 1 ) {
|
|
420
|
+ while ( rx_quota ) {
|
420
|
421
|
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
|
421
|
422
|
sizeof ( undi_isr ) ) ) != 0 )
|
422
|
423
|
break;
|
|
@@ -448,6 +449,7 @@ static void undinet_poll ( struct net_device *netdev ) {
|
448
|
449
|
if ( pkb_len ( pkb ) == len ) {
|
449
|
450
|
netdev_rx ( netdev, pkb );
|
450
|
451
|
pkb = NULL;
|
|
452
|
+ --rx_quota;
|
451
|
453
|
}
|
452
|
454
|
break;
|
453
|
455
|
case PXENV_UNDI_ISR_OUT_DONE:
|
|
@@ -480,8 +482,8 @@ static void undinet_poll ( struct net_device *netdev ) {
|
480
|
482
|
*/
|
481
|
483
|
static int undinet_open ( struct net_device *netdev ) {
|
482
|
484
|
struct undi_nic *undinic = netdev->priv;
|
483
|
|
- struct s_PXENV_UNDI_SET_STATION_ADDRESS set_address;
|
484
|
|
- struct s_PXENV_UNDI_OPEN open;
|
|
485
|
+ struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address;
|
|
486
|
+ struct s_PXENV_UNDI_OPEN undi_open;
|
485
|
487
|
int rc;
|
486
|
488
|
|
487
|
489
|
/* Hook interrupt service routine and enable interrupt */
|
|
@@ -494,16 +496,16 @@ static int undinet_open ( struct net_device *netdev ) {
|
494
|
496
|
* use it to set the MAC address to the card's permanent value
|
495
|
497
|
* anyway.
|
496
|
498
|
*/
|
497
|
|
- memcpy ( set_address.StationAddress, netdev->ll_addr,
|
498
|
|
- sizeof ( set_address.StationAddress ) );
|
|
499
|
+ memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
|
|
500
|
+ sizeof ( undi_set_address.StationAddress ) );
|
499
|
501
|
undinet_call ( undinic, PXENV_UNDI_SET_STATION_ADDRESS,
|
500
|
|
- &set_address, sizeof ( set_address ) );
|
|
502
|
+ &undi_set_address, sizeof ( undi_set_address ) );
|
501
|
503
|
|
502
|
504
|
/* Open NIC */
|
503
|
|
- memset ( &open, 0, sizeof ( open ) );
|
504
|
|
- open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST );
|
505
|
|
- if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &open,
|
506
|
|
- sizeof ( open ) ) ) != 0 )
|
|
505
|
+ memset ( &undi_open, 0, sizeof ( undi_open ) );
|
|
506
|
+ undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST );
|
|
507
|
+ if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &undi_open,
|
|
508
|
+ sizeof ( undi_open ) ) ) != 0 )
|
507
|
509
|
goto err;
|
508
|
510
|
|
509
|
511
|
return 0;
|
|
@@ -520,14 +522,31 @@ static int undinet_open ( struct net_device *netdev ) {
|
520
|
522
|
*/
|
521
|
523
|
static void undinet_close ( struct net_device *netdev ) {
|
522
|
524
|
struct undi_nic *undinic = netdev->priv;
|
523
|
|
- struct s_PXENV_UNDI_CLOSE close;
|
|
525
|
+ struct s_PXENV_UNDI_ISR undi_isr;
|
|
526
|
+ struct s_PXENV_UNDI_CLOSE undi_close;
|
|
527
|
+ int rc;
|
524
|
528
|
|
525
|
529
|
/* Ensure ISR has exited cleanly */
|
526
|
|
- while ( undinic->isr_processing )
|
527
|
|
- undinet_poll ( netdev );
|
|
530
|
+ while ( undinic->isr_processing ) {
|
|
531
|
+ undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
|
|
532
|
+ if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
|
|
533
|
+ sizeof ( undi_isr ) ) ) != 0 )
|
|
534
|
+ break;
|
|
535
|
+ switch ( undi_isr.FuncFlag ) {
|
|
536
|
+ case PXENV_UNDI_ISR_OUT_TRANSMIT:
|
|
537
|
+ case PXENV_UNDI_ISR_OUT_RECEIVE:
|
|
538
|
+ /* Continue draining */
|
|
539
|
+ break;
|
|
540
|
+ default:
|
|
541
|
+ /* Stop processing */
|
|
542
|
+ undinic->isr_processing = 0;
|
|
543
|
+ break;
|
|
544
|
+ }
|
|
545
|
+ }
|
528
|
546
|
|
529
|
547
|
/* Close NIC */
|
530
|
|
- undinet_call ( undinic, PXENV_UNDI_CLOSE, &close, sizeof ( close ) );
|
|
548
|
+ undinet_call ( undinic, PXENV_UNDI_CLOSE, &undi_close,
|
|
549
|
+ sizeof ( undi_close ) );
|
531
|
550
|
|
532
|
551
|
/* Disable interrupt and unhook ISR */
|
533
|
552
|
disable_irq ( undinic->irq );
|