leon, greth: SMP support by using spin-lock protection

This commit is contained in:
Daniel Hellstrom
2017-04-13 14:57:01 +02:00
parent 8927c0f8e7
commit 998e34ad33

View File

@@ -41,6 +41,16 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/if_ether.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 #ifdef malloc
#undef malloc #undef malloc
#endif #endif
@@ -198,6 +208,8 @@ struct greth_softc
unsigned long txRetryLimit; unsigned long txRetryLimit;
unsigned long txUnderrun; unsigned long txUnderrun;
/* Spin-lock ISR protection */
SPIN_DECLARE(devlock);
}; };
int greth_process_tx_gbit(struct greth_softc *sc); int greth_process_tx_gbit(struct greth_softc *sc);
@@ -219,10 +231,13 @@ static void greth_interrupt (void *arg)
uint32_t ctrl; uint32_t ctrl;
rtems_event_set events = 0; rtems_event_set events = 0;
struct greth_softc *greth = arg; struct greth_softc *greth = arg;
SPIN_ISR_IRQFLAGS(flags);
/* read and clear interrupt cause */ /* read and clear interrupt cause */
status = greth->regs->status; status = greth->regs->status;
greth->regs->status = status; greth->regs->status = status;
SPIN_LOCK(&greth->devlock, flags);
ctrl = greth->regs->ctrl; ctrl = greth->regs->ctrl;
/* Frame received? */ /* Frame received? */
@@ -243,6 +258,7 @@ static void greth_interrupt (void *arg)
/* Clear interrupt sources */ /* Clear interrupt sources */
greth->regs->ctrl = ctrl; greth->regs->ctrl = ctrl;
SPIN_UNLOCK(&greth->devlock, flags);
/* Send the event(s) */ /* Send the event(s) */
if ( events ) if ( events )
@@ -633,7 +649,7 @@ greth_Daemon (void *arg)
struct mbuf *m; struct mbuf *m;
unsigned int len, len_status, bad; unsigned int len, len_status, bad;
rtems_event_set events; rtems_event_set events;
rtems_interrupt_level level; SPIN_IRQFLAGS(flags);
int first; int first;
int tmp; int tmp;
unsigned int addr; unsigned int addr;
@@ -753,26 +769,24 @@ again:
} else { } else {
dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ; 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; 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; dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
} }
/* Always scan twice to avoid deadlock */ /* Always scan twice to avoid deadlock */
if ( first ){ if ( first ){
first=0; first=0;
rtems_interrupt_disable(level); SPIN_LOCK_IRQ(&dp->devlock, flags);
dp->regs->ctrl |= GRETH_CTRL_RXIRQ; dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
rtems_interrupt_enable(level); SPIN_UNLOCK_IRQ(&dp->devlock, flags);
goto again; goto again;
} }
} }
} }
static int inside = 0;
static int static int
sendpacket (struct ifnet *ifp, struct mbuf *m) sendpacket (struct ifnet *ifp, struct mbuf *m)
{ {
@@ -780,18 +794,13 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
unsigned char *temp; unsigned char *temp;
struct mbuf *n; struct mbuf *n;
unsigned int len; unsigned int len;
rtems_interrupt_level level; SPIN_IRQFLAGS(flags);
/*printf("Send packet entered\n");*/
if (inside) printf ("error: sendpacket re-entered!!\n");
inside = 1;
/* /*
* Is there a free descriptor available? * Is there a free descriptor available?
*/ */
if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){ if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){
/* No. */ /* No. */
inside = 0;
return 1; return 1;
} }
@@ -833,12 +842,11 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len; GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
} }
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; 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; dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
rtems_interrupt_enable(level); SPIN_UNLOCK_IRQ(&dp->devlock, flags);
} }
inside = 0;
return 0; return 0;
} }
@@ -854,10 +862,7 @@ sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
int frags; int frags;
struct mbuf *mtmp; struct mbuf *mtmp;
int int_en; int int_en;
rtems_interrupt_level level; SPIN_IRQFLAGS(flags);
if (inside) printf ("error: sendpacket re-entered!!\n");
inside = 1;
len = 0; len = 0;
#ifdef GRETH_DEBUG #ifdef GRETH_DEBUG
@@ -877,13 +882,11 @@ sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
dp->max_fragsize = frags; dp->max_fragsize = frags;
if ( frags > dp->txbufs ){ if ( frags > dp->txbufs ){
inside = 0;
printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n"); printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
return -1; return -1;
} }
if ( frags > (dp->txbufs-dp->tx_cnt) ){ if ( frags > (dp->txbufs-dp->tx_cnt) ){
inside = 0;
/* Return number of fragments */ /* Return number of fragments */
return frags; return frags;
} }
@@ -947,11 +950,9 @@ sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
dp->tx_cnt++; dp->tx_cnt++;
/* Tell Hardware about newly enabled descriptor */ /* 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; dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
rtems_interrupt_enable(level); SPIN_UNLOCK_IRQ(&dp->devlock, flags);
inside = 0;
return 0; return 0;
} }
@@ -960,7 +961,7 @@ int greth_process_tx_gbit(struct greth_softc *sc)
{ {
struct ifnet *ifp = &sc->arpcom.ac_if; struct ifnet *ifp = &sc->arpcom.ac_if;
struct mbuf *m; struct mbuf *m;
rtems_interrupt_level level; SPIN_IRQFLAGS(flags);
int first=1; int first=1;
/* /*
@@ -1010,10 +1011,10 @@ int greth_process_tx_gbit(struct greth_softc *sc)
*/ */
if ( first ){ if ( first ){
first = 0; first = 0;
rtems_interrupt_disable(level); SPIN_LOCK_IRQ(&sc->devlock, flags);
ifp->if_flags |= IFF_OACTIVE; ifp->if_flags |= IFF_OACTIVE;
sc->regs->ctrl |= GRETH_CTRL_TXIRQ; 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 /* We must check again to be sure that we didn't
* miss an interrupt (if a packet was sent just before * miss an interrupt (if a packet was sent just before
@@ -1034,7 +1035,7 @@ int greth_process_tx(struct greth_softc *sc)
{ {
struct ifnet *ifp = &sc->arpcom.ac_if; struct ifnet *ifp = &sc->arpcom.ac_if;
struct mbuf *m; struct mbuf *m;
rtems_interrupt_level level; SPIN_IRQFLAGS(flags);
int first=1; int first=1;
/* /*
@@ -1076,10 +1077,10 @@ int greth_process_tx(struct greth_softc *sc)
*/ */
if ( first ){ if ( first ){
first = 0; first = 0;
rtems_interrupt_disable(level); SPIN_LOCK_IRQ(&sc->devlock, flags);
ifp->if_flags |= IFF_OACTIVE; ifp->if_flags |= IFF_OACTIVE;
sc->regs->ctrl |= GRETH_CTRL_TXIRQ; 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 /* We must check again to be sure that we didn't
* miss an interrupt (if a packet was sent just before * miss an interrupt (if a packet was sent just before
@@ -1128,7 +1129,6 @@ greth_init (void *arg)
if (sc->daemonTid == 0) if (sc->daemonTid == 0)
{ {
/* /*
* Start driver tasks * Start driver tasks
*/ */
@@ -1140,14 +1140,12 @@ greth_init (void *arg)
* Set up GRETH hardware * Set up GRETH hardware
*/ */
greth_initialize_hardware (sc); greth_initialize_hardware (sc);
} }
/* /*
* Tell the world that we're running. * Tell the world that we're running.
*/ */
ifp->if_flags |= IFF_RUNNING; ifp->if_flags |= IFF_RUNNING;
} }
/* /*
@@ -1157,12 +1155,15 @@ static void
greth_stop (struct greth_softc *sc) greth_stop (struct greth_softc *sc)
{ {
struct ifnet *ifp = &sc->arpcom.ac_if; struct ifnet *ifp = &sc->arpcom.ac_if;
SPIN_IRQFLAGS(flags);
SPIN_LOCK_IRQ(&sc->devlock, flags);
ifp->if_flags &= ~IFF_RUNNING; ifp->if_flags &= ~IFF_RUNNING;
sc->regs->ctrl = 0; /* RX/TX OFF */ sc->regs->ctrl = 0; /* RX/TX OFF */
sc->regs->ctrl = GRETH_CTRL_RST; /* Reset ON */ sc->regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
sc->regs->ctrl = 0; /* Reset OFF */ sc->regs->ctrl = 0; /* Reset OFF */
SPIN_UNLOCK_IRQ(&sc->devlock, flags);
sc->next_tx_mbuf = NULL; sc->next_tx_mbuf = NULL;
} }
@@ -1397,6 +1398,11 @@ int greth_init3(struct drvmgr_dev *dev)
return DRVMGR_FAIL; 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 */ /* Register GRETH device as an Network interface */
ifp = malloc(sizeof(struct rtems_bsdnet_ifconfig)); ifp = malloc(sizeof(struct rtems_bsdnet_ifconfig));
memset(ifp, 0, sizeof(*ifp)); memset(ifp, 0, sizeof(*ifp));