david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Added ability to break ISR processing over several calls to poll().

This will allow us to implement RX quotas.
This commit is contained in:
Michael Brown 2007-01-09 17:04:10 +00:00
parent aa7bda7b47
commit 3c2cc59d25
1 changed files with 33 additions and 16 deletions

View File

@ -42,6 +42,8 @@ struct undi_nic {
SEGOFF16_t entry;
/** Assigned IRQ number */
unsigned int irq;
/** Currently processing ISR */
int isr_processing;
};
static void undinet_close ( struct net_device *netdev );
@ -384,24 +386,32 @@ static void undinet_poll ( struct net_device *netdev ) {
size_t frag_len;
int rc;
/* Do nothing unless ISR has been triggered */
if ( ! undinet_isr_triggered() )
return;
if ( ! undinic->isr_processing ) {
/* Do nothing unless ISR has been triggered */
if ( ! undinet_isr_triggered() )
return;
/* See if this was our interrupt */
memset ( &undi_isr, 0, sizeof ( undi_isr ) );
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
sizeof ( undi_isr ) ) ) != 0 )
return;
if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
return;
/* Send EOI */
send_eoi ( undinic->irq );
/* See if this was our interrupt */
memset ( &undi_isr, 0, sizeof ( undi_isr ) );
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
sizeof ( undi_isr ) ) ) != 0 )
return;
if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
return;
/* Send EOI */
send_eoi ( undinic->irq );
/* Start ISR processing */
undinic->isr_processing = 1;
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
} else {
/* Continue ISR processing */
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
}
/* Run through the ISR loop */
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
while ( 1 ) {
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
sizeof ( undi_isr ) ) ) != 0 )
@ -420,7 +430,8 @@ static void undinet_poll ( struct net_device *netdev ) {
DBGC ( undinic, "UNDINIC %p could not "
"allocate %zd bytes for RX buffer\n",
undinic, len );
break;
/* Fragment will be dropped */
goto done;
}
if ( frag_len > pkb_available ( pkb ) ) {
DBGC ( undinic, "UNDINIC %p fragment too "
@ -437,11 +448,13 @@ static void undinet_poll ( struct net_device *netdev ) {
break;
case PXENV_UNDI_ISR_OUT_DONE:
/* Processing complete */
undinic->isr_processing = 0;
goto done;
default:
/* Should never happen */
DBGC ( undinic, "UNDINIC %p ISR returned invalid "
"FuncFlag %04x\n", undinic, undi_isr.FuncFlag );
undinic->isr_processing = 0;
goto done;
}
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
@ -505,6 +518,10 @@ static void undinet_close ( struct net_device *netdev ) {
struct undi_nic *undinic = netdev->priv;
struct s_PXENV_UNDI_CLOSE close;
/* Ensure ISR has exited cleanly */
while ( undinic->isr_processing )
undinet_poll ( netdev );
/* Close NIC */
undinet_call ( undinic, PXENV_UNDI_CLOSE, &close, sizeof ( close ) );