diff options
| author | Michael Brown | 2007-01-09 22:47:01 +0100 |
|---|---|---|
| committer | Michael Brown | 2007-01-09 22:47:01 +0100 |
| commit | c65fae2475ca652ef7948f286881b0c06bce861b (patch) | |
| tree | 5588ec4b947ecc79201ee613d1cd0a0a7ca6d1d8 /src/arch/i386 | |
| parent | Autopadding was sometimes overwriting the struct list_head at the end (diff) | |
| download | ipxe-c65fae2475ca652ef7948f286881b0c06bce861b.tar.gz ipxe-c65fae2475ca652ef7948f286881b0c06bce861b.tar.xz ipxe-c65fae2475ca652ef7948f286881b0c06bce861b.zip | |
Add RX quotas to the net device poll() method. This avoids the problem
of alloc_pkb() exhaustion when e.g. an iSCSI-booted DOS session is left
idle for a long time at the C:\ prompt and builds up a huge packet
backlog.
Diffstat (limited to 'src/arch/i386')
| -rw-r--r-- | src/arch/i386/drivers/net/undinet.c | 51 |
1 files changed, 35 insertions, 16 deletions
diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c index c53ff53cf..5ff9bd428 100644 --- a/src/arch/i386/drivers/net/undinet.c +++ b/src/arch/i386/drivers/net/undinet.c @@ -364,7 +364,8 @@ static int undinet_transmit ( struct net_device *netdev, /** * Poll for received packets * - * @v netdev Network device + * @v netdev Network device + * @v rx_quota Maximum number of packets to receive * * Fun, fun, fun. UNDI drivers don't use polling; they use * interrupts. We therefore cheat and pretend that an interrupt has @@ -382,7 +383,7 @@ static int undinet_transmit ( struct net_device *netdev, * of installing a genuine interrupt service routine and dealing with * the wonderful 8259 Programmable Interrupt Controller. Joy. */ -static void undinet_poll ( struct net_device *netdev ) { +static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) { struct undi_nic *undinic = netdev->priv; struct s_PXENV_UNDI_ISR undi_isr; struct pk_buff *pkb = NULL; @@ -416,7 +417,7 @@ static void undinet_poll ( struct net_device *netdev ) { } /* Run through the ISR loop */ - while ( 1 ) { + while ( rx_quota ) { if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr, sizeof ( undi_isr ) ) ) != 0 ) break; @@ -448,6 +449,7 @@ static void undinet_poll ( struct net_device *netdev ) { if ( pkb_len ( pkb ) == len ) { netdev_rx ( netdev, pkb ); pkb = NULL; + --rx_quota; } break; case PXENV_UNDI_ISR_OUT_DONE: @@ -480,8 +482,8 @@ static void undinet_poll ( struct net_device *netdev ) { */ static int undinet_open ( struct net_device *netdev ) { struct undi_nic *undinic = netdev->priv; - struct s_PXENV_UNDI_SET_STATION_ADDRESS set_address; - struct s_PXENV_UNDI_OPEN open; + struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address; + struct s_PXENV_UNDI_OPEN undi_open; int rc; /* Hook interrupt service routine and enable interrupt */ @@ -494,16 +496,16 @@ static int undinet_open ( struct net_device *netdev ) { * use it to set the MAC address to the card's permanent value * anyway. */ - memcpy ( set_address.StationAddress, netdev->ll_addr, - sizeof ( set_address.StationAddress ) ); + memcpy ( undi_set_address.StationAddress, netdev->ll_addr, + sizeof ( undi_set_address.StationAddress ) ); undinet_call ( undinic, PXENV_UNDI_SET_STATION_ADDRESS, - &set_address, sizeof ( set_address ) ); + &undi_set_address, sizeof ( undi_set_address ) ); /* Open NIC */ - memset ( &open, 0, sizeof ( open ) ); - open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST ); - if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &open, - sizeof ( open ) ) ) != 0 ) + memset ( &undi_open, 0, sizeof ( undi_open ) ); + undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST ); + if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &undi_open, + sizeof ( undi_open ) ) ) != 0 ) goto err; return 0; @@ -520,14 +522,31 @@ static int undinet_open ( struct net_device *netdev ) { */ static void undinet_close ( struct net_device *netdev ) { struct undi_nic *undinic = netdev->priv; - struct s_PXENV_UNDI_CLOSE close; + struct s_PXENV_UNDI_ISR undi_isr; + struct s_PXENV_UNDI_CLOSE undi_close; + int rc; /* Ensure ISR has exited cleanly */ - while ( undinic->isr_processing ) - undinet_poll ( netdev ); + while ( undinic->isr_processing ) { + undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; + if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr, + sizeof ( undi_isr ) ) ) != 0 ) + break; + switch ( undi_isr.FuncFlag ) { + case PXENV_UNDI_ISR_OUT_TRANSMIT: + case PXENV_UNDI_ISR_OUT_RECEIVE: + /* Continue draining */ + break; + default: + /* Stop processing */ + undinic->isr_processing = 0; + break; + } + } /* Close NIC */ - undinet_call ( undinic, PXENV_UNDI_CLOSE, &close, sizeof ( close ) ); + undinet_call ( undinic, PXENV_UNDI_CLOSE, &undi_close, + sizeof ( undi_close ) ); /* Disable interrupt and unhook ISR */ disable_irq ( undinic->irq ); |
