[syslinux:lwip] lwip: handle UNDI stacks which need to be polled

syslinux-bot for H. Peter Anvin hpa at linux.intel.com
Fri Apr 22 20:06:22 PDT 2011


Commit-ID:  2fa8eb93e5b2fc684d27f018c0a84341eaed5476
Gitweb:     http://syslinux.zytor.com/commit/2fa8eb93e5b2fc684d27f018c0a84341eaed5476
Author:     H. Peter Anvin <hpa at linux.intel.com>
AuthorDate: Fri, 22 Apr 2011 15:57:33 -0700
Committer:  H. Peter Anvin <hpa at linux.intel.com>
CommitDate: Fri, 22 Apr 2011 15:57:33 -0700

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 at linux.intel.com>


---
 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 <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");
     }
 }
 



More information about the Syslinux-commits mailing list