diff --git a/src/arch/i386/drivers/net/undiisr.S b/src/arch/i386/drivers/net/undiisr.S new file mode 100644 index 00000000..b5838693 --- /dev/null +++ b/src/arch/i386/drivers/net/undiisr.S @@ -0,0 +1,70 @@ +#define PXENV_UNDI_ISR 0x0014 +#define PXENV_UNDI_ISR_IN_START 1 +#define PXENV_UNDI_ISR_OUT_OURS 0 +#define PXENV_UNDI_ISR_OUT_NOT_OURS 1 + +#define IRQ_PIC_CUTOFF 8 +#define ICR_EOI_NON_SPECIFIC 0x20 +#define PIC1_ICR 0x20 +#define PIC2_ICR 0xa0 + + .text + .arch i386 + .section ".text16", "ax", @progbits + .section ".data16", "aw", @progbits + .code16 + + .section ".text16" + .globl undiisr +undiisr: + + /* Preserve registers */ + pushw %ds + pushw %es + pusha + + /* Issue UNDI API call */ + movw %cs:rm_ds, %ax + movw %ax, %ds + movw %ax, %es + movw $undinet_params, %di + movw $PXENV_UNDI_ISR, %bx + movw $PXENV_UNDI_ISR_IN_START, funcflag + pushw %es + pushw %di + pushw %bx + lcall *undinet_entry_point + addw $6, %sp + cmpw $PXENV_UNDI_ISR_OUT_OURS, funcflag + jne chain + +ack: /* Record interrupt occurence */ + incb undiisr_trigger_count + /* Send EOI */ + movb $ICR_EOI_NON_SPECIFIC, %al + cmpb $IRQ_PIC_CUTOFF, undiisr_irq + jb 1f + outb %al, $PIC2_ICR +1: outb %al, $PIC1_ICR + jmp exit + +chain: /* Chain to next handler */ + pushfw + lcall *undiisr_next_handler + +exit: /* Restore registers and return */ + popa + popw %es + popw %ds + iret + + .section ".data16" +undinet_params: +status: .word 0 +funcflag: .word 0 +bufferlength: .word 0 +framelength: .word 0 +frameheaderlength: .word 0 +frame: .word 0, 0 +prottype: .byte 0 +pkttype: .byte 0 diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c index 3ed0ed64..c9a610ae 100644 --- a/src/arch/i386/drivers/net/undinet.c +++ b/src/arch/i386/drivers/net/undinet.c @@ -146,7 +146,7 @@ static union u_PXENV_ANY __data16 ( undinet_params ); * Used as the indirection vector for all UNDI API calls. Resides in * base memory. */ -static SEGOFF16_t __data16 ( undinet_entry_point ); +SEGOFF16_t __data16 ( undinet_entry_point ); #define undinet_entry_point __use_data16 ( undinet_entry_point ) /** @@ -245,17 +245,21 @@ static int undinet_call ( struct undi_nic *undinic, unsigned int function, /** * UNDI interrupt service routine * - * The UNDI ISR simply increments a counter (@c trigger_count) and - * exits. + * The UNDI ISR increments a counter (@c trigger_count) and exits. */ -extern void undinet_isr ( void ); +extern void undiisr ( void ); -/** Dummy chain vector */ -static struct segoff prev_handler[ IRQ_MAX + 1 ]; +/** IRQ number */ +uint8_t __data16 ( undiisr_irq ); +#define undiisr_irq __use_data16 ( undiisr_irq ) + +/** IRQ chain vector */ +struct segoff __data16 ( undiisr_next_handler ); +#define undiisr_next_handler __use_data16 ( undiisr_next_handler ) /** IRQ trigger count */ -static volatile uint8_t __text16 ( trigger_count ) = 0; -#define trigger_count __use_text16 ( trigger_count ) +volatile uint8_t __data16 ( undiisr_trigger_count ) = 0; +#define undiisr_trigger_count __use_data16 ( undiisr_trigger_count ) /** Last observed trigger count */ static unsigned int last_trigger_count = 0; @@ -275,16 +279,12 @@ static unsigned int last_trigger_count = 0; static void undinet_hook_isr ( unsigned int irq ) { assert ( irq <= IRQ_MAX ); + assert ( undiisr_irq == 0 ); - __asm__ __volatile__ ( TEXT16_CODE ( "\nundinet_isr:\n\t" - "incb %%cs:%c0\n\t" - "iret\n\t" ) - : : "p" ( & __from_text16 ( trigger_count ) ) ); - + undiisr_irq = irq; hook_bios_interrupt ( IRQ_INT ( irq ), - ( ( unsigned int ) undinet_isr ), - &prev_handler[irq] ); - + ( ( unsigned int ) undiisr ), + &undiisr_next_handler ); } /** @@ -297,8 +297,9 @@ static void undinet_unhook_isr ( unsigned int irq ) { assert ( irq <= IRQ_MAX ); unhook_bios_interrupt ( IRQ_INT ( irq ), - ( ( unsigned int ) undinet_isr ), - &prev_handler[irq] ); + ( ( unsigned int ) undiisr ), + &undiisr_next_handler ); + undiisr_irq = 0; } /** @@ -310,7 +311,7 @@ static int undinet_isr_triggered ( void ) { unsigned int this_trigger_count; /* Read trigger_count. Do this only once; it is volatile */ - this_trigger_count = trigger_count; + this_trigger_count = undiisr_trigger_count; if ( this_trigger_count == last_trigger_count ) { /* Not triggered */ @@ -424,6 +425,7 @@ static void undinet_poll ( struct net_device *netdev ) { if ( ! undinet_isr_triggered() ) return; +#if 0 /* See if this was our interrupt */ memset ( &undi_isr, 0, sizeof ( undi_isr ) ); undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START; @@ -443,6 +445,7 @@ static void undinet_poll ( struct net_device *netdev ) { /* If this wasn't our interrupt, exit now */ if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS ) return; +#endif /* Start ISR processing */ undinic->isr_processing = 1;