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 );
/*****************************************************************************
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
*
* @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 */
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:
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;
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;
return 0;
err_register:
+ err_undi_get_iface_info:
err_bad_irq:
err_undi_get_information:
err_undi_initialize: