david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Work around Etherboot 5.4 bug when multiple packets are received.

This commit is contained in:
Michael Brown 2007-07-03 15:53:29 +01:00
parent ca4bd3e24e
commit 2dc8ed1eb8
1 changed files with 38 additions and 1 deletions

View File

@ -45,8 +45,20 @@ struct undi_nic {
unsigned int irq;
/** Currently processing ISR */
int isr_processing;
/** Bug workarounds */
int hacks;
};
/**
* @defgroup undi_hacks UNDI workarounds
* @{
*/
/** Work around Etherboot 5.4 bugs */
#define UNDI_HACK_EB54 0x0001
/** @} */
static void undinet_close ( struct net_device *netdev );
/*****************************************************************************
@ -245,6 +257,9 @@ static struct segoff prev_handler[ IRQ_MAX + 1 ];
static volatile uint8_t __text16 ( trigger_count ) = 0;
#define trigger_count __use_text16 ( trigger_count )
/** Last observed trigger count */
static unsigned int last_trigger_count = 0;
/**
* Hook UNDI interrupt service routine
*
@ -292,7 +307,6 @@ static void undinet_unhook_isr ( unsigned int irq ) {
* @ret triggered ISR has been triggered since last check
*/
static int undinet_isr_triggered ( void ) {
static unsigned int last_trigger_count = 0;
unsigned int this_trigger_count;
/* Read trigger_count. Do this only once; it is volatile */
@ -470,9 +484,15 @@ static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) {
undi_isr.Frame.segment,
undi_isr.Frame.offset, frag_len );
if ( iob_len ( iobuf ) == len ) {
/* Whole packet received; deliver it */
netdev_rx ( netdev, iobuf );
iobuf = NULL;
--rx_quota;
/* Etherboot 5.4 fails to return all packets
* under mild load; pretend it retriggered.
*/
if ( undinic->hacks & UNDI_HACK_EB54 )
--last_trigger_count;
}
break;
case PXENV_UNDI_ISR_OUT_DONE:
@ -592,6 +612,7 @@ int undinet_probe ( struct undi_device *undi ) {
struct s_PXENV_UNDI_STARTUP undi_startup;
struct s_PXENV_UNDI_INITIALIZE undi_initialize;
struct s_PXENV_UNDI_GET_INFORMATION undi_info;
struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
struct s_PXENV_STOP_UNDI stop_undi;
@ -649,6 +670,21 @@ int undinet_probe ( struct undi_device *undi ) {
DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
undinic, eth_ntoa ( netdev->ll_addr ), undinic->irq );
/* Get interface information */
memset ( &undi_iface, 0, sizeof ( undi_iface ) );
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_IFACE_INFO,
&undi_iface,
sizeof ( undi_iface ) ) ) != 0 )
goto err_undi_get_iface_info;
DBGC ( undinic, "UNDINIC %p has type %s and link speed %ld\n",
undinic, undi_iface.IfaceType, undi_iface.LinkSpeed );
if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
sizeof ( undi_iface.IfaceType ) ) == 0 ) {
DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
undinic );
undinic->hacks |= UNDI_HACK_EB54;
}
/* Point to NIC specific routines */
netdev->open = undinet_open;
netdev->close = undinet_close;
@ -663,6 +699,7 @@ int undinet_probe ( struct undi_device *undi ) {
return 0;
err_register:
err_undi_get_iface_info:
err_bad_irq:
err_undi_get_information:
err_undi_initialize: