From 2fa8eb93e5b2fc684d27f018c0a84341eaed5476 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 22 Apr 2011 15:57:33 -0700 Subject: [PATCH] lwip: handle UNDI stacks which need to be polled If the UNDI stack reports either IRQ 0 or does NOT report the NDIS IRQ supported flag, then poll the interrupt routine from the idle thread instead. This is somewhat limited; we really should have a chain of idle poll routines to support things like serial console. Signed-off-by: H. Peter Anvin --- com32/include/syslinux/pxe_api.h | 19 ++++++++++++- core/fs/pxe/isr.c | 59 ++++++++++++++++++++++++++++------------ core/fs/pxe/pxe.h | 1 - core/include/thread.h | 2 ++ core/lwip/src/netif/undiif.c | 16 +++++++---- core/thread/idle_thread.c | 7 ++++- 6 files changed, 79 insertions(+), 25 deletions(-) diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h index 27166b0..9324329 100644 --- a/com32/include/syslinux/pxe_api.h +++ b/com32/include/syslinux/pxe_api.h @@ -359,7 +359,24 @@ typedef struct s_PXENV_UNDI_GET_IFACE_INFO { uint32_t LinkSpeed; uint32_t ServiceFlags; uint32_t Reserved[4]; -} __packed t_PXENV_UNDI_GET_NDIS_INFO; +} __packed t_PXENV_UNDI_GET_IFACE_INFO; +#define PXE_UNDI_IFACE_FLAG_BCAST 0x00000001 +#define PXE_UNDI_IFACE_FLAG_MCAST 0x00000002 +#define PXE_UNDI_IFACE_FLAG_GROUP 0x00000004 +#define PXE_UNDI_IFACE_FLAG_PROMISC 0x00000008 +#define PXE_UNDI_IFACE_FLAG_SOFTMAC 0x00000010 +#define PXE_UNDI_IFACE_FLAG_STATS 0x00000020 +#define PXE_UNDI_IFACE_FLAG_DIAGS 0x00000040 +#define PXE_UNDI_IFACE_FLAG_LOOPBACK 0x00000080 +#define PXE_UNDI_IFACE_FLAG_RCVCHAIN 0x00000100 +#define PXE_UNDI_IFACE_FLAG_IBMSRCRT 0x00000200 +#define PXE_UNDI_IFACE_FLAG_RESET 0x00000400 +#define PXE_UNDI_IFACE_FLAG_OPEN 0x00000800 +#define PXE_UNDI_IFACE_FLAG_IRQ 0x00001000 +#define PXE_UNDI_IFACE_FLAG_SRCRT 0x00002000 +#define PXE_UNDI_IFACE_FLAG_GDTVIRT 0x00004000 +#define PXE_UNDI_IFACE_FLAG_MULTI 0x00008000 +#define PXE_UNDI_IFACE_FLAG_LKFISZ 0x00010000 typedef struct s_PXENV_UNDI_GET_STATE { #define PXE_UNDI_GET_STATE_STARTED 1 diff --git a/core/fs/pxe/isr.c b/core/fs/pxe/isr.c index 680c7ef..ade3b0d 100644 --- a/core/fs/pxe/isr.c +++ b/core/fs/pxe/isr.c @@ -18,32 +18,35 @@ bool install_irq_vector(uint8_t irq, void (*isr)(void), far_ptr_t *old) { far_ptr_t *entry; unsigned int vec; - + if (irq < 8) vec = irq + 0x08; else if (irq < 16) vec = (irq - 8) + 0x70; else return false; - + entry = (far_ptr_t *)(vec << 2); *old = *entry; entry->ptr = (uint32_t)isr; return true; } -bool uninstall_irq_vector(uint8_t irq, void (*isr), far_ptr_t *old) +static bool uninstall_irq_vector(uint8_t irq, void (*isr), far_ptr_t *old) { far_ptr_t *entry; unsigned int vec; - + + if (!irq) + return true; /* Nothing to uninstall */ + if (irq < 8) vec = irq + 0x08; else if (irq < 16) vec = (irq - 8) + 0x70; else return false; - + entry = (far_ptr_t *)(vec << 2); if (entry->ptr != (uint32_t)isr) @@ -62,47 +65,57 @@ static void pxe_poll_wakeups(void) last_jiffies = now; __thread_process_timeouts(); } - + if (pxe_irq_pending) { pxe_irq_pending = 0; sem_up(&pxe_receive_thread_sem); } } +static bool pxe_isr_poll(void) +{ + static __lowmem t_PXENV_UNDI_ISR isr; + + isr.FuncFlag = PXENV_UNDI_ISR_IN_START; + pxe_call(PXENV_UNDI_ISR, &isr); + + return isr.FuncFlag == PXENV_UNDI_ISR_OUT_OURS; +} + static void pxe_process_irq(void) { static __lowmem t_PXENV_UNDI_ISR isr; - uint16_t func = PXENV_UNDI_ISR_IN_PROCESS; /* First time */ + uint16_t func = PXENV_UNDI_ISR_IN_PROCESS; /* First time */ bool done = false; while (!done) { memset(&isr, 0, sizeof isr); isr.FuncFlag = func; func = PXENV_UNDI_ISR_IN_GET_NEXT; /* Next time */ - + pxe_call(PXENV_UNDI_ISR, &isr); - + switch (isr.FuncFlag) { case PXENV_UNDI_ISR_OUT_DONE: done = true; break; - + case PXENV_UNDI_ISR_OUT_TRANSMIT: /* Transmit complete - nothing for us to do */ break; - + case PXENV_UNDI_ISR_OUT_RECEIVE: undiif_input(&isr); break; - + case PXENV_UNDI_ISR_OUT_BUSY: - /* ISR busy, this should not happen */ + /* ISR busy, this should not happen */ done = true; break; - + default: - /* Invalid return code, this should not happen */ + /* Invalid return code, this should not happen */ done = true; break; } @@ -115,10 +128,16 @@ static void pxe_receive_thread(void *dummy) for (;;) { sem_down(&pxe_receive_thread_sem, 0); - pxe_process_irq(); + if (pxe_irq_vector || pxe_isr_poll()) + pxe_process_irq(); } } +static void pxe_do_isr_poll(void) +{ + sem_up(&pxe_receive_thread_sem); +} + void pxe_init_isr(void) { start_idle_thread(); @@ -132,6 +151,11 @@ void pxe_init_isr(void) pxe_thread = start_thread("pxe receive", 16384, -20, pxe_receive_thread, NULL); core_pm_hook = __schedule; + + if (!pxe_irq_vector) { + /* No IRQ vector, need to poll */ + idle_hook = pxe_do_isr_poll; + } } @@ -139,10 +163,11 @@ void pxe_cleanup_isr(void) { static __lowmem struct s_PXENV_UNDI_CLOSE undi_close; + idle_hook = NULL; sched_hook_func = NULL; core_pm_hook = core_pm_null_hook; kill_thread(pxe_thread); - + memset(&undi_close, 0, sizeof(undi_close)); pxe_call(PXENV_UNDI_CLOSE, &undi_close); uninstall_irq_vector(pxe_irq_vector, pxe_isr, &pxe_irq_chain); diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h index d30e783..0aa3c5a 100644 --- a/core/fs/pxe/pxe.h +++ b/core/fs/pxe/pxe.h @@ -245,7 +245,6 @@ extern far_ptr_t pxe_irq_chain; void pxe_init_isr(void); void pxe_cleanup_isr(void); bool install_irq_vector(uint8_t irq, void (*isr)(void), far_ptr_t *old); -bool uninstall_irq_vector(uint8_t irq, void (*isr), far_ptr_t *old); /* pxe.c */ bool ip_ok(uint32_t); diff --git a/core/include/thread.h b/core/include/thread.h index b283424..7c83b5a 100644 --- a/core/include/thread.h +++ b/core/include/thread.h @@ -95,4 +95,6 @@ void kill_thread(struct thread *); void start_idle_thread(void); void test_thread(void); +extern void (*idle_hook)(void); + #endif /* _THREAD_H */ diff --git a/core/lwip/src/netif/undiif.c b/core/lwip/src/netif/undiif.c index f21eb0b..4e78693 100644 --- a/core/lwip/src/netif/undiif.c +++ b/core/lwip/src/netif/undiif.c @@ -224,15 +224,21 @@ static void low_level_init(struct netif *netif) { static __lowmem t_PXENV_UNDI_GET_INFORMATION undi_info; + static __lowmem t_PXENV_UNDI_GET_IFACE_INFO undi_iface; static __lowmem t_PXENV_UNDI_OPEN undi_open; int i; /* struct undiif *undiif = netif->state; */ pxe_call(PXENV_UNDI_GET_INFORMATION, &undi_info); + pxe_call(PXENV_UNDI_GET_IFACE_INFO, &undi_iface); - dprintf("UNDI: baseio %04x int %d MTU %d type %d\n", - undi_info.BaseIo, undi_info.IntNumber, undi_info.MaxTranUnit, - undi_info.HwType); + dprintf("UNDI: baseio %04x int %d MTU %d type %d \"%s\" flags 0x%x\n", + undi_info.BaseIo, undi_info.IntNumber, undi_info.MaxTranUnit, + undi_info.HwType, undi_iface.IfaceType, undi_iface.ServiceFlags); + + pxe_irq_vector = undi_info.IntNumber; + if (!(undi_iface.ServiceFlags & PXE_UNDI_IFACE_FLAG_IRQ)) + pxe_irq_vector = 0; /* Interrupts not supported */ /* MAC_type and MAC_len should always match what is returned by * PXENV_UNDI_GET_INFORMATION. At the moment the both seem to be @@ -272,8 +278,8 @@ low_level_init(struct netif *netif) netif->flags |= NETIF_FLAG_ETHARP; /* Install the interrupt vector */ - pxe_irq_vector = undi_info.IntNumber; - install_irq_vector(pxe_irq_vector, pxe_isr, &pxe_irq_chain); + if (pxe_irq_vector) + install_irq_vector(pxe_irq_vector, pxe_isr, &pxe_irq_chain); /* Open the UNDI stack - you'd think the BC would have done this... */ undi_open.PktFilter = 0x0003; /* FLTR_DIRECTED | FLTR_BRDCST */ diff --git a/core/thread/idle_thread.c b/core/thread/idle_thread.c index b51a462..e2f8b57 100644 --- a/core/thread/idle_thread.c +++ b/core/thread/idle_thread.c @@ -2,6 +2,8 @@ #include #include +void (*idle_hook)(void); + static void idle_thread_func(void *dummy) { (void)dummy; @@ -9,7 +11,10 @@ static void idle_thread_func(void *dummy) for (;;) { thread_yield(); - asm volatile("hlt"); + if (idle_hook) + idle_hook(); + else + asm volatile("hlt"); } } -- 2.7.4