|
@@ -42,6 +42,8 @@ struct undi_nic {
|
42
|
42
|
SEGOFF16_t entry;
|
43
|
43
|
/** Assigned IRQ number */
|
44
|
44
|
unsigned int irq;
|
|
45
|
+ /** Currently processing ISR */
|
|
46
|
+ int isr_processing;
|
45
|
47
|
};
|
46
|
48
|
|
47
|
49
|
static void undinet_close ( struct net_device *netdev );
|
|
@@ -384,24 +386,32 @@ static void undinet_poll ( struct net_device *netdev ) {
|
384
|
386
|
size_t frag_len;
|
385
|
387
|
int rc;
|
386
|
388
|
|
387
|
|
- /* Do nothing unless ISR has been triggered */
|
388
|
|
- if ( ! undinet_isr_triggered() )
|
389
|
|
- return;
|
390
|
|
-
|
391
|
|
- /* See if this was our interrupt */
|
392
|
|
- memset ( &undi_isr, 0, sizeof ( undi_isr ) );
|
393
|
|
- undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
|
394
|
|
- if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
|
395
|
|
- sizeof ( undi_isr ) ) ) != 0 )
|
396
|
|
- return;
|
397
|
|
- if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
|
398
|
|
- return;
|
399
|
|
-
|
400
|
|
- /* Send EOI */
|
401
|
|
- send_eoi ( undinic->irq );
|
|
389
|
+ if ( ! undinic->isr_processing ) {
|
|
390
|
+ /* Do nothing unless ISR has been triggered */
|
|
391
|
+ if ( ! undinet_isr_triggered() )
|
|
392
|
+ return;
|
|
393
|
+
|
|
394
|
+ /* See if this was our interrupt */
|
|
395
|
+ memset ( &undi_isr, 0, sizeof ( undi_isr ) );
|
|
396
|
+ undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
|
|
397
|
+ if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
|
|
398
|
+ sizeof ( undi_isr ) ) ) != 0 )
|
|
399
|
+ return;
|
|
400
|
+ if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
|
|
401
|
+ return;
|
|
402
|
+
|
|
403
|
+ /* Send EOI */
|
|
404
|
+ send_eoi ( undinic->irq );
|
|
405
|
+
|
|
406
|
+ /* Start ISR processing */
|
|
407
|
+ undinic->isr_processing = 1;
|
|
408
|
+ undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
|
|
409
|
+ } else {
|
|
410
|
+ /* Continue ISR processing */
|
|
411
|
+ undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
|
|
412
|
+ }
|
402
|
413
|
|
403
|
414
|
/* Run through the ISR loop */
|
404
|
|
- undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
|
405
|
415
|
while ( 1 ) {
|
406
|
416
|
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
|
407
|
417
|
sizeof ( undi_isr ) ) ) != 0 )
|
|
@@ -420,7 +430,8 @@ static void undinet_poll ( struct net_device *netdev ) {
|
420
|
430
|
DBGC ( undinic, "UNDINIC %p could not "
|
421
|
431
|
"allocate %zd bytes for RX buffer\n",
|
422
|
432
|
undinic, len );
|
423
|
|
- break;
|
|
433
|
+ /* Fragment will be dropped */
|
|
434
|
+ goto done;
|
424
|
435
|
}
|
425
|
436
|
if ( frag_len > pkb_available ( pkb ) ) {
|
426
|
437
|
DBGC ( undinic, "UNDINIC %p fragment too "
|
|
@@ -437,11 +448,13 @@ static void undinet_poll ( struct net_device *netdev ) {
|
437
|
448
|
break;
|
438
|
449
|
case PXENV_UNDI_ISR_OUT_DONE:
|
439
|
450
|
/* Processing complete */
|
|
451
|
+ undinic->isr_processing = 0;
|
440
|
452
|
goto done;
|
441
|
453
|
default:
|
442
|
454
|
/* Should never happen */
|
443
|
455
|
DBGC ( undinic, "UNDINIC %p ISR returned invalid "
|
444
|
456
|
"FuncFlag %04x\n", undinic, undi_isr.FuncFlag );
|
|
457
|
+ undinic->isr_processing = 0;
|
445
|
458
|
goto done;
|
446
|
459
|
}
|
447
|
460
|
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
|
|
@@ -505,6 +518,10 @@ static void undinet_close ( struct net_device *netdev ) {
|
505
|
518
|
struct undi_nic *undinic = netdev->priv;
|
506
|
519
|
struct s_PXENV_UNDI_CLOSE close;
|
507
|
520
|
|
|
521
|
+ /* Ensure ISR has exited cleanly */
|
|
522
|
+ while ( undinic->isr_processing )
|
|
523
|
+ undinet_poll ( netdev );
|
|
524
|
+
|
508
|
525
|
/* Close NIC */
|
509
|
526
|
undinet_call ( undinic, PXENV_UNDI_CLOSE, &close, sizeof ( close ) );
|
510
|
527
|
|