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/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,10 +231,13 @@ 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? */
@@ -243,6 +258,7 @@ static void greth_interrupt (void *arg)
/* Clear interrupt sources */
greth->regs->ctrl = ctrl;
SPIN_UNLOCK(&greth->devlock, flags);
/* Send the event(s) */
if ( events )
@@ -633,7 +649,7 @@ 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;
@@ -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,12 +842,11 @@ 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,10 +862,7 @@ sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
int frags;
struct mbuf *mtmp;
int int_en;
rtems_interrupt_level level;
if (inside) printf ("error: sendpacket re-entered!!\n");
inside = 1;
SPIN_IRQFLAGS(flags);
len = 0;
#ifdef GRETH_DEBUG
@@ -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,11 +950,9 @@ 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);
inside = 0;
SPIN_UNLOCK_IRQ(&dp->devlock, flags);
return 0;
}
@@ -960,7 +961,7 @@ 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;
/*
@@ -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
@@ -1034,7 +1035,7 @@ 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;
/*
@@ -1076,10 +1077,10 @@ 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
@@ -1128,7 +1129,6 @@ greth_init (void *arg)
if (sc->daemonTid == 0)
{
/*
* Start driver tasks
*/
@@ -1140,14 +1140,12 @@ greth_init (void *arg)
* Set up GRETH hardware
*/
greth_initialize_hardware (sc);
}
/*
* Tell the world that we're running.
*/
ifp->if_flags |= IFF_RUNNING;
}
/*
@@ -1157,12 +1155,15 @@ 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));