summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2017-04-13 14:57:01 +0200
committerDaniel Hellstrom <daniel@gaisler.com>2017-05-02 12:34:50 +0200
commit998e34ad33525b6115251d165cd51858868db19e (patch)
tree93f7b42613376e0a5841f07f4d63fccd3aa955af
parentleon, gptimer: offset intnum with subtimer index (diff)
downloadrtems-998e34ad33525b6115251d165cd51858868db19e.tar.bz2
leon, greth: SMP support by using spin-lock protection
-rw-r--r--c/src/lib/libbsp/sparc/shared/net/greth.c132
1 files changed, 69 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 7726799b95..874e5326f1 100644
--- a/c/src/lib/libbsp/sparc/shared/net/greth.c
+++ b/c/src/lib/libbsp/sparc/shared/net/greth.c
@@ -41,6 +41,16 @@
#include <netinet/in.h>
#include <netinet/if_ether.h>
+/* map via rtems_interrupt_lock_* API: */
+#define SPIN_DECLARE(lock) RTEMS_INTERRUPT_LOCK_MEMBER(lock)
+#define SPIN_INIT(lock, name) rtems_interrupt_lock_initialize(lock, name)
+#define SPIN_LOCK(lock, level) rtems_interrupt_lock_acquire_isr(lock, &level)
+#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_lock_acquire(lock, &level)
+#define SPIN_UNLOCK(lock, level) rtems_interrupt_lock_release_isr(lock, &level)
+#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_lock_release(lock, &level)
+#define SPIN_IRQFLAGS(k) rtems_interrupt_lock_context k
+#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k)
+
#ifdef malloc
#undef malloc
#endif
@@ -198,6 +208,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 +231,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 +248,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 +649,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 +769,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 +794,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 +842,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 +862,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 +882,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 +950,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 +961,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 +1011,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 +1022,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 +1035,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 +1077,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 +1129,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 +1155,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 +1398,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));