forked from Imagelibrary/rtems
leon, greth: SMP support by using spin-lock protection
This commit is contained in:
@@ -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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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));
|
||||
|
||||
Reference in New Issue
Block a user