Skip to content

Commit

Permalink
[undi] Support underlying UNDI devices that don't support interrupts
Browse files Browse the repository at this point in the history
Some network cards do not generate interrupts when operated via the
UNDI API.  Allow for this by waiting for the ISR to be triggered only
if the PXE stack advertises that it supports interrupts.  When the PXE
stack does not advertise interrupt support, we skip the call to
PXENV_UNDI_ISR_IN_START and just poll the device using
PXENV_UNDI_ISR_IN_PROCESS.  This matches the observed behaviour of at
least one other PXE NBP (emBoot's winBoot/i), so there is a reasonable
chance of this working.

Originally-implemented-by: Muralidhar Appalla <Muralidhar.Appalla@emulex.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Nov 19, 2010
1 parent 7e33adc commit 006d9f1
Showing 1 changed file with 31 additions and 17 deletions.
48 changes: 31 additions & 17 deletions src/arch/i386/drivers/net/undinet.c
Expand Up @@ -43,6 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER );

/** An UNDI NIC */
struct undi_nic {
/** Device supports IRQs */
int irq_supported;
/** Assigned IRQ number */
unsigned int irq;
/** Currently processing ISR */
Expand Down Expand Up @@ -251,8 +253,10 @@ static void undinet_poll ( struct net_device *netdev ) {
int rc;

if ( ! undinic->isr_processing ) {
/* Do nothing unless ISR has been triggered */
if ( ! undinet_isr_triggered() ) {
/* If interrupts are supported, then do nothing unless
* the ISR has been triggered.
*/
if ( undinic->irq_supported && ( ! undinet_isr_triggered() ) ){
/* Allow interrupt to occur */
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
"nop\n\t"
Expand Down Expand Up @@ -357,10 +361,12 @@ static int undinet_open ( struct net_device *netdev ) {
struct s_PXENV_UNDI_OPEN undi_open;
int rc;

/* Hook interrupt service routine and enable interrupt */
undinet_hook_isr ( undinic->irq );
enable_irq ( undinic->irq );
send_eoi ( undinic->irq );
/* Hook interrupt service routine and enable interrupt if supported */
if ( undinic->irq_supported ) {
undinet_hook_isr ( undinic->irq );
enable_irq ( undinic->irq );
send_eoi ( undinic->irq );
}

/* Set station address. Required for some PXE stacks; will
* spuriously fail on others. Ignore failures. We only ever
Expand Down Expand Up @@ -425,9 +431,11 @@ static void undinet_close ( struct net_device *netdev ) {
pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
&undi_close, sizeof ( undi_close ) );

/* Disable interrupt and unhook ISR */
disable_irq ( undinic->irq );
undinet_unhook_isr ( undinic->irq );
/* Disable interrupt and unhook ISR if supported */
if ( undinic->irq_supported ) {
disable_irq ( undinic->irq );
undinet_unhook_isr ( undinic->irq );
}

DBGC ( undinic, "UNDINIC %p closed\n", undinic );
}
Expand Down Expand Up @@ -524,13 +532,8 @@ int undinet_probe ( struct undi_device *undi ) {
goto err_undi_get_information;
memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
undinic->irq = undi_info.IntNumber;
if ( undinic->irq > IRQ_MAX ) {
DBGC ( undinic, "UNDINIC %p invalid IRQ %d\n",
undinic, undinic->irq );
goto err_bad_irq;
}
DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n",
undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
DBGC ( undinic, "UNDINIC %p has MAC address %s\n",
undinic, eth_ntoa ( netdev->hw_addr ) );

/* Get interface information */
memset ( &undi_iface, 0, sizeof ( undi_iface ) );
Expand All @@ -541,6 +544,17 @@ int undinet_probe ( struct undi_device *undi ) {
DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
undi_iface.ServiceFlags );
if ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) {
if ( undinic->irq > IRQ_MAX ) {
DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
undinic, undinic->irq );
rc = -EINVAL;
goto err_bad_irq;
}
undinic->irq_supported = 1;
DBGC ( undinic, "UNDINIC %p uses IRQ %d\n",
undinic, undinic->irq );
}
if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
sizeof ( undi_iface.IfaceType ) ) == 0 ) {
DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
Expand All @@ -559,8 +573,8 @@ int undinet_probe ( struct undi_device *undi ) {
return 0;

err_register:
err_undi_get_iface_info:
err_bad_irq:
err_undi_get_iface_info:
err_undi_get_information:
err_undi_initialize:
/* Shut down UNDI stack */
Expand Down

0 comments on commit 006d9f1

Please sign in to comment.