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/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,12 +231,15 @@ 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? */
|
||||||
if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
|
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;
|
ctrl &= ~GRETH_CTRL_RXIRQ;
|
||||||
events |= INTERRUPT_EVENT;
|
events |= INTERRUPT_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
|
if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
|
||||||
{
|
{
|
||||||
greth->txInterrupts++;
|
greth->txInterrupts++;
|
||||||
ctrl &= ~GRETH_CTRL_TXIRQ;
|
ctrl &= ~GRETH_CTRL_TXIRQ;
|
||||||
events |= GRETH_TX_WAIT_EVENT;
|
events |= GRETH_TX_WAIT_EVENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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 )
|
||||||
rtems_bsdnet_event_send(greth->daemonTid, events);
|
rtems_bsdnet_event_send(greth->daemonTid, events);
|
||||||
@@ -633,11 +649,11 @@ 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;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
|
||||||
@@ -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,13 +842,12 @@ 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,11 +862,8 @@ 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
|
||||||
printf("TXD: 0x%08x\n", (int) m->m_data);
|
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;
|
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,12 +950,10 @@ 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,9 +961,9 @@ 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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send packets till queue is empty
|
* Send packets till queue is empty
|
||||||
*/
|
*/
|
||||||
@@ -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
|
||||||
@@ -1021,7 +1022,7 @@ int greth_process_tx_gbit(struct greth_softc *sc)
|
|||||||
*/
|
*/
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}else{
|
}else{
|
||||||
/* Sent Ok, proceed to process more packets if available */
|
/* 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 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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send packets till queue is empty
|
* Send packets till queue is empty
|
||||||
*/
|
*/
|
||||||
@@ -1076,18 +1077,18 @@ 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
|
||||||
* enabling interrupts)
|
* enabling interrupts)
|
||||||
*/
|
*/
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}else{
|
}else{
|
||||||
/* Sent Ok, proceed to process more packets if available */
|
/* Sent Ok, proceed to process more packets if available */
|
||||||
@@ -1128,26 +1129,23 @@ greth_init (void *arg)
|
|||||||
|
|
||||||
if (sc->daemonTid == 0)
|
if (sc->daemonTid == 0)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Start driver tasks
|
||||||
|
*/
|
||||||
|
name[3] += sc->minor;
|
||||||
|
sc->daemonTid = rtems_bsdnet_newproc (name, 4096,
|
||||||
|
greth_Daemon, sc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start driver tasks
|
* Set up GRETH hardware
|
||||||
*/
|
*/
|
||||||
name[3] += sc->minor;
|
greth_initialize_hardware (sc);
|
||||||
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.
|
* Tell the world that we're running.
|
||||||
*/
|
*/
|
||||||
ifp->if_flags |= IFF_RUNNING;
|
ifp->if_flags |= IFF_RUNNING;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1157,13 +1155,16 @@ 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));
|
||||||
|
|||||||
Reference in New Issue
Block a user