Work around Etherboot 5.4 bug when multiple packets are received.
This commit is contained in:
parent
ca4bd3e24e
commit
2dc8ed1eb8
|
@ -45,8 +45,20 @@ struct undi_nic {
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
/** Currently processing ISR */
|
/** Currently processing ISR */
|
||||||
int isr_processing;
|
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 );
|
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;
|
static volatile uint8_t __text16 ( trigger_count ) = 0;
|
||||||
#define trigger_count __use_text16 ( trigger_count )
|
#define trigger_count __use_text16 ( trigger_count )
|
||||||
|
|
||||||
|
/** Last observed trigger count */
|
||||||
|
static unsigned int last_trigger_count = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook UNDI interrupt service routine
|
* 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
|
* @ret triggered ISR has been triggered since last check
|
||||||
*/
|
*/
|
||||||
static int undinet_isr_triggered ( void ) {
|
static int undinet_isr_triggered ( void ) {
|
||||||
static unsigned int last_trigger_count = 0;
|
|
||||||
unsigned int this_trigger_count;
|
unsigned int this_trigger_count;
|
||||||
|
|
||||||
/* Read trigger_count. Do this only once; it is volatile */
|
/* 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.segment,
|
||||||
undi_isr.Frame.offset, frag_len );
|
undi_isr.Frame.offset, frag_len );
|
||||||
if ( iob_len ( iobuf ) == len ) {
|
if ( iob_len ( iobuf ) == len ) {
|
||||||
|
/* Whole packet received; deliver it */
|
||||||
netdev_rx ( netdev, iobuf );
|
netdev_rx ( netdev, iobuf );
|
||||||
iobuf = NULL;
|
iobuf = NULL;
|
||||||
--rx_quota;
|
--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;
|
break;
|
||||||
case PXENV_UNDI_ISR_OUT_DONE:
|
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_STARTUP undi_startup;
|
||||||
struct s_PXENV_UNDI_INITIALIZE undi_initialize;
|
struct s_PXENV_UNDI_INITIALIZE undi_initialize;
|
||||||
struct s_PXENV_UNDI_GET_INFORMATION undi_info;
|
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_SHUTDOWN undi_shutdown;
|
||||||
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
|
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
|
||||||
struct s_PXENV_STOP_UNDI stop_undi;
|
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",
|
DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
|
||||||
undinic, eth_ntoa ( netdev->ll_addr ), undinic->irq );
|
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 */
|
/* Point to NIC specific routines */
|
||||||
netdev->open = undinet_open;
|
netdev->open = undinet_open;
|
||||||
netdev->close = undinet_close;
|
netdev->close = undinet_close;
|
||||||
|
@ -663,6 +699,7 @@ int undinet_probe ( struct undi_device *undi ) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_register:
|
err_register:
|
||||||
|
err_undi_get_iface_info:
|
||||||
err_bad_irq:
|
err_bad_irq:
|
||||||
err_undi_get_information:
|
err_undi_get_information:
|
||||||
err_undi_initialize:
|
err_undi_initialize:
|
||||||
|
|
Reference in New Issue