Skip to content

Commit b6ca3aa

Browse files
committedMar 23, 2011
[undi] Cope with devices that erroneously claim not to use interrupts
Some PXE stacks advertise that interrupts are not supported, despite requiring the use of interrupts. Attempt to cope with such cards without breaking others by always hooking the interrupt, and using the "interrupts supported" flag only to decide whether or not to wait for an interrupt before calling PXENV_UNDI_ISR_IN_PROCESS. The possible combinations are therefore: 1. Card generates interrupts and claims to support interrupts iPXE will call PXENV_UNDI_ISR_IN_PROCESS only after an interrupt has been observed. (This is required to avoid lockups in some PXE stacks, which spuriously sulk if called before an interrupt has been generated.) Such a card should work correctly. 2. Card does not generate interrupts and does not claim to support interrupts iPXE will call PXENV_UNDI_ISR_IN_PROCESS indiscriminately, matching the observed behaviour of at least one other PXE NBP (winBoot/i). Such a card should work correctly. 3. Card generates interrupts but claims not to support interrupts iPXE will call PXENV_UNDI_ISR_IN_PROCESS indiscriminately. An interrupt will still result in a call to PXENV_UNDI_ISR_IN_START. Such a card may work correctly. 4. Card does not generate interrupts but claims to support interrupts Such a card will not work at all. Reported-by: Jerry Cheng <jaspers.cheng@msa.hinet.net> Tested-by: Jerry Cheng <jaspers.cheng@msa.hinet.net> Reported-by: Mauricio Silveira <mauricio@livreti.com.br> Tested-by: Mauricio Silveira <mauricio@livreti.com.br> Signed-off-by: Michael Brown <mcb30@ipxe.org>
1 parent 8482451 commit b6ca3aa

File tree

1 file changed

+28
-21
lines changed

1 file changed

+28
-21
lines changed
 

‎src/arch/i386/drivers/net/undinet.c

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -253,16 +253,24 @@ static void undinet_poll ( struct net_device *netdev ) {
253253
int rc;
254254

255255
if ( ! undinic->isr_processing ) {
256-
/* If interrupts are supported, then do nothing unless
257-
* the ISR has been triggered.
256+
/* Allow interrupt to occur. Do this even if
257+
* interrupts are not known to be supported, since
258+
* some cards erroneously report that they do not
259+
* support interrupts.
258260
*/
259-
if ( undinic->irq_supported && ( ! undinet_isr_triggered() ) ){
261+
if ( ! undinet_isr_triggered() ) {
260262
/* Allow interrupt to occur */
261263
__asm__ __volatile__ ( REAL_CODE ( "sti\n\t"
262264
"nop\n\t"
263265
"nop\n\t"
264266
"cli\n\t" ) : : );
265-
return;
267+
268+
/* If interrupts are known to be supported,
269+
* then do nothing on this poll; wait for the
270+
* interrupt to be triggered.
271+
*/
272+
if ( undinic->irq_supported )
273+
return;
266274
}
267275

268276
/* Start ISR processing */
@@ -361,8 +369,8 @@ static int undinet_open ( struct net_device *netdev ) {
361369
struct s_PXENV_UNDI_OPEN undi_open;
362370
int rc;
363371

364-
/* Hook interrupt service routine and enable interrupt if supported */
365-
if ( undinic->irq_supported ) {
372+
/* Hook interrupt service routine and enable interrupt if applicable */
373+
if ( undinic->irq ) {
366374
undinet_hook_isr ( undinic->irq );
367375
enable_irq ( undinic->irq );
368376
send_eoi ( undinic->irq );
@@ -431,8 +439,8 @@ static void undinet_close ( struct net_device *netdev ) {
431439
pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
432440
&undi_close, sizeof ( undi_close ) );
433441

434-
/* Disable interrupt and unhook ISR if supported */
435-
if ( undinic->irq_supported ) {
442+
/* Disable interrupt and unhook ISR if applicable */
443+
if ( undinic->irq ) {
436444
disable_irq ( undinic->irq );
437445
undinet_unhook_isr ( undinic->irq );
438446
}
@@ -532,8 +540,14 @@ int undinet_probe ( struct undi_device *undi ) {
532540
goto err_undi_get_information;
533541
memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
534542
undinic->irq = undi_info.IntNumber;
535-
DBGC ( undinic, "UNDINIC %p has MAC address %s\n",
536-
undinic, eth_ntoa ( netdev->hw_addr ) );
543+
if ( undinic->irq > IRQ_MAX ) {
544+
DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
545+
undinic, undinic->irq );
546+
rc = -EINVAL;
547+
goto err_bad_irq;
548+
}
549+
DBGC ( undinic, "UNDINIC %p has MAC address %s and IRQ %d\n",
550+
undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq );
537551

538552
/* Get interface information */
539553
memset ( &undi_iface, 0, sizeof ( undi_iface ) );
@@ -544,17 +558,10 @@ int undinet_probe ( struct undi_device *undi ) {
544558
DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
545559
undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
546560
undi_iface.ServiceFlags );
547-
if ( undi_iface.ServiceFlags & SUPPORTED_IRQ ) {
548-
if ( undinic->irq > IRQ_MAX ) {
549-
DBGC ( undinic, "UNDINIC %p has invalid IRQ %d\n",
550-
undinic, undinic->irq );
551-
rc = -EINVAL;
552-
goto err_bad_irq;
553-
}
561+
if ( undi_iface.ServiceFlags & SUPPORTED_IRQ )
554562
undinic->irq_supported = 1;
555-
DBGC ( undinic, "UNDINIC %p uses IRQ %d\n",
556-
undinic, undinic->irq );
557-
}
563+
DBGC ( undinic, "UNDINIC %p using %s mode\n", undinic,
564+
( undinic->irq_supported ? "interrupt" : "polling" ) );
558565
if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot",
559566
sizeof ( undi_iface.IfaceType ) ) == 0 ) {
560567
DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n",
@@ -573,8 +580,8 @@ int undinet_probe ( struct undi_device *undi ) {
573580
return 0;
574581

575582
err_register:
576-
err_bad_irq:
577583
err_undi_get_iface_info:
584+
err_bad_irq:
578585
err_undi_get_information:
579586
err_undi_initialize:
580587
/* Shut down UNDI stack */

0 commit comments

Comments
 (0)
Please sign in to comment.