summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2011-04-22 15:57:33 -0700
committerH. Peter Anvin <hpa@linux.intel.com>2011-04-22 15:57:33 -0700
commit2fa8eb93e5b2fc684d27f018c0a84341eaed5476 (patch)
tree2a29092e6e79813f930c76ed8d6f78e5843bab04
parentf5203bfa11fde88d16f471b4050ed1da73387c7a (diff)
downloadsyslinux-2fa8eb93e5b2fc684d27f018c0a84341eaed5476.tar.gz
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 <hpa@linux.intel.com>
-rw-r--r--com32/include/syslinux/pxe_api.h19
-rw-r--r--core/fs/pxe/isr.c59
-rw-r--r--core/fs/pxe/pxe.h1
-rw-r--r--core/include/thread.h2
-rw-r--r--core/lwip/src/netif/undiif.c16
-rw-r--r--core/thread/idle_thread.c7
6 files changed, 79 insertions, 25 deletions
diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h
index 27166b0b..93243294 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 680c7ef6..ade3b0d2 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 d30e7839..0aa3c5a7 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 b283424d..7c83b5a9 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 f21eb0b8..4e786935 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 b51a4627..e2f8b579 100644
--- a/core/thread/idle_thread.c
+++ b/core/thread/idle_thread.c
@@ -2,6 +2,8 @@
#include <limits.h>
#include <sys/cpu.h>
+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");
}
}