[PATCH 29/30] leon, greth: SMP support by using spin-lock protection

Daniel Hellstrom daniel at gaisler.com
Thu Apr 13 19:31:38 UTC 2017


---
 c/src/lib/libbsp/sparc/shared/net/greth.c | 134 ++++++++++++++++--------------
 1 file changed, 71 insertions(+), 63 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/shared/net/greth.c b/c/src/lib/libbsp/sparc/shared/net/greth.c
index 7726799..9af2de2 100644
--- a/c/src/lib/libbsp/sparc/shared/net/greth.c
+++ b/c/src/lib/libbsp/sparc/shared/net/greth.c
@@ -41,6 +41,18 @@
 #include <netinet/in.h>
 #include <netinet/if_ether.h>
 
+#include <rtems/score/isrlock.h> /* spin-lock */
+
+/* map via ISR lock: */
+#define SPIN_DECLARE(lock) ISR_LOCK_MEMBER(lock)
+#define SPIN_INIT(lock, name) _ISR_lock_Initialize(lock, name)
+#define SPIN_LOCK(lock, level) _ISR_lock_Acquire_inline(lock, &level)
+#define SPIN_LOCK_IRQ(lock, level) _ISR_lock_ISR_disable_and_acquire(lock, &level)
+#define SPIN_UNLOCK(lock, level) _ISR_lock_Release_inline(lock, &level)
+#define SPIN_UNLOCK_IRQ(lock, level) _ISR_lock_Release_and_ISR_enable(lock, &level)
+#define SPIN_IRQFLAGS(k) ISR_lock_Context k
+#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k)
+
 #ifdef malloc
 #undef malloc
 #endif
@@ -198,6 +210,8 @@ struct greth_softc
    unsigned long txRetryLimit;
    unsigned long txUnderrun;
 
+   /* Spin-lock ISR protection */
+   SPIN_DECLARE(devlock);
 };
 
 int greth_process_tx_gbit(struct greth_softc *sc);
@@ -219,12 +233,15 @@ static void greth_interrupt (void *arg)
         uint32_t ctrl;
         rtems_event_set events = 0;
         struct greth_softc *greth = arg;
-        
+        SPIN_ISR_IRQFLAGS(flags);
+
         /* read and clear interrupt cause */
         status = greth->regs->status;
         greth->regs->status = status;
+
+        SPIN_LOCK(&greth->devlock, flags);
         ctrl = greth->regs->ctrl;
-        
+
         /* Frame received? */
         if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
         {
@@ -233,17 +250,18 @@ static void greth_interrupt (void *arg)
                 ctrl &= ~GRETH_CTRL_RXIRQ;
                 events |= INTERRUPT_EVENT;
         }
-        
+
         if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
         {
                 greth->txInterrupts++;
                 ctrl &= ~GRETH_CTRL_TXIRQ;
                 events |= GRETH_TX_WAIT_EVENT;
         }
-        
+
         /* Clear interrupt sources */
         greth->regs->ctrl = ctrl;
-        
+        SPIN_UNLOCK(&greth->devlock, flags);
+
         /* Send the event(s) */
         if ( events )
             rtems_bsdnet_event_send(greth->daemonTid, events);
@@ -633,11 +651,11 @@ greth_Daemon (void *arg)
     struct mbuf *m;
     unsigned int len, len_status, bad;
     rtems_event_set events;
-    rtems_interrupt_level level;
+    SPIN_IRQFLAGS(flags);
     int first;
-		int tmp;
-		unsigned int addr;
-    
+    int tmp;
+    unsigned int addr;
+
     for (;;)
       {
         rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
@@ -753,26 +771,24 @@ again:
                     } else {
                             dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
                     }
-                    rtems_interrupt_disable(level);
+                    SPIN_LOCK_IRQ(&dp->devlock, flags);
                     dp->regs->ctrl |= GRETH_CTRL_RXEN;
-                    rtems_interrupt_enable(level);
+                    SPIN_UNLOCK_IRQ(&dp->devlock, flags);
                     dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
             }
-        
+
         /* Always scan twice to avoid deadlock */
         if ( first ){
             first=0;
-            rtems_interrupt_disable(level);
+            SPIN_LOCK_IRQ(&dp->devlock, flags);
             dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
-            rtems_interrupt_enable(level);
+            SPIN_UNLOCK_IRQ(&dp->devlock, flags);
             goto again;
         }
 
       }
-    
 }
 
-static int inside = 0;
 static int
 sendpacket (struct ifnet *ifp, struct mbuf *m)
 {
@@ -780,18 +796,13 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
     unsigned char *temp;
     struct mbuf *n;
     unsigned int len;
-    rtems_interrupt_level level;
-        
-    /*printf("Send packet entered\n");*/
-    if (inside) printf ("error: sendpacket re-entered!!\n");
-    inside = 1;
-    
+    SPIN_IRQFLAGS(flags);
+
     /*
      * Is there a free descriptor available?
      */
     if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
             /* No. */
-            inside = 0;
             return 1;
     }
     
@@ -833,13 +844,12 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
                             GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
             }
             dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
-            rtems_interrupt_disable(level);
+            SPIN_LOCK_IRQ(&dp->devlock, flags);
             dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
-            rtems_interrupt_enable(level);
+            SPIN_UNLOCK_IRQ(&dp->devlock, flags);
             
     }
-    inside = 0;
-    
+
     return 0;
 }
 
@@ -854,11 +864,8 @@ sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
         int frags;
         struct mbuf *mtmp;
         int int_en;
-        rtems_interrupt_level level;
+        SPIN_IRQFLAGS(flags);
 
-        if (inside) printf ("error: sendpacket re-entered!!\n");
-        inside = 1;
-        
         len = 0;
 #ifdef GRETH_DEBUG
         printf("TXD: 0x%08x\n", (int) m->m_data);
@@ -877,13 +884,11 @@ sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
             dp->max_fragsize = frags;
         
         if ( frags > dp->txbufs ){
-            inside = 0;
             printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
             return -1;
         }
         
         if ( frags > (dp->txbufs-dp->tx_cnt) ){
-            inside = 0;
             /* Return number of fragments */
             return frags;
         }
@@ -947,12 +952,10 @@ sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
         dp->tx_cnt++;
       
         /* Tell Hardware about newly enabled descriptor */
-        rtems_interrupt_disable(level);
+        SPIN_LOCK_IRQ(&dp->devlock, flags);
         dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
-        rtems_interrupt_enable(level);
+        SPIN_UNLOCK_IRQ(&dp->devlock, flags);
 
-        inside = 0;
-               
         return 0;
 }
 
@@ -960,9 +963,9 @@ int greth_process_tx_gbit(struct greth_softc *sc)
 {
     struct ifnet *ifp = &sc->arpcom.ac_if;
     struct mbuf *m;
-    rtems_interrupt_level level;
+    SPIN_IRQFLAGS(flags);
     int first=1;
-    
+
     /*
      * Send packets till queue is empty
      */
@@ -1010,10 +1013,10 @@ int greth_process_tx_gbit(struct greth_softc *sc)
              */
             if ( first ){
                 first = 0;
-                rtems_interrupt_disable(level);
+                SPIN_LOCK_IRQ(&sc->devlock, flags);
                 ifp->if_flags |= IFF_OACTIVE;
                 sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
-                rtems_interrupt_enable(level);
+                SPIN_UNLOCK_IRQ(&sc->devlock, flags);
                 
                 /* We must check again to be sure that we didn't 
                  * miss an interrupt (if a packet was sent just before
@@ -1021,7 +1024,7 @@ int greth_process_tx_gbit(struct greth_softc *sc)
                  */
                 continue;
             }
-            
+
             return -1;
         }else{
             /* Sent Ok, proceed to process more packets if available */
@@ -1034,9 +1037,9 @@ int greth_process_tx(struct greth_softc *sc)
 {
     struct ifnet *ifp = &sc->arpcom.ac_if;
     struct mbuf *m;
-    rtems_interrupt_level level;
+    SPIN_IRQFLAGS(flags);
     int first=1;
-    
+
     /*
      * Send packets till queue is empty
      */
@@ -1076,18 +1079,18 @@ int greth_process_tx(struct greth_softc *sc)
              */
             if ( first ){
                 first = 0;
-                rtems_interrupt_disable(level);
+                SPIN_LOCK_IRQ(&sc->devlock, flags);
                 ifp->if_flags |= IFF_OACTIVE;
                 sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
-                rtems_interrupt_enable(level);
-                
+                SPIN_UNLOCK_IRQ(&sc->devlock, flags);
+
                 /* We must check again to be sure that we didn't 
                  * miss an interrupt (if a packet was sent just before
                  * enabling interrupts)
                  */
                 continue;
             }
-            
+
             return -1;
         }else{
             /* Sent Ok, proceed to process more packets if available */
@@ -1128,26 +1131,23 @@ greth_init (void *arg)
 
     if (sc->daemonTid == 0)
       {
-
-	  /*
-	   * Start driver tasks
-	   */
-	  name[3] += sc->minor;
-	  sc->daemonTid = rtems_bsdnet_newproc (name, 4096,
-						  greth_Daemon, sc);
-
-	  /*
-	   * Set up GRETH hardware
-	   */
-      greth_initialize_hardware (sc);
-          
+          /*
+           * Start driver tasks
+           */
+          name[3] += sc->minor;
+          sc->daemonTid = rtems_bsdnet_newproc (name, 4096,
+                                                greth_Daemon, sc);
+
+          /*
+           * Set up GRETH hardware
+           */
+          greth_initialize_hardware (sc);
       }
 
     /*
      * Tell the world that we're running.
      */
     ifp->if_flags |= IFF_RUNNING;
-
 }
 
 /*
@@ -1157,13 +1157,16 @@ static void
 greth_stop (struct greth_softc *sc)
 {
     struct ifnet *ifp = &sc->arpcom.ac_if;
+    SPIN_IRQFLAGS(flags);
 
+    SPIN_LOCK_IRQ(&sc->devlock, flags);
     ifp->if_flags &= ~IFF_RUNNING;
 
     sc->regs->ctrl = 0;		        /* RX/TX OFF */
     sc->regs->ctrl = GRETH_CTRL_RST;	/* Reset ON */
     sc->regs->ctrl = 0;	         	/* Reset OFF */
-    
+    SPIN_UNLOCK_IRQ(&sc->devlock, flags);
+
     sc->next_tx_mbuf = NULL;
 }
 
@@ -1397,6 +1400,11 @@ int greth_init3(struct drvmgr_dev *dev)
         return DRVMGR_FAIL;
     }
 
+    /* Initialize Spin-lock for GRSPW Device. This is to protect
+     * CTRL and DMACTRL registers from ISR.
+     */
+    SPIN_INIT(&sc->devlock, sc->devName);
+
     /* Register GRETH device as an Network interface */
     ifp = malloc(sizeof(struct rtems_bsdnet_ifconfig));
     memset(ifp, 0, sizeof(*ifp));
-- 
2.7.4




More information about the devel mailing list