m68knommu: fix FEC driver locking
It's easy: grab locks before talking to hardware and realease them afterwards. The one big lock has been splitted into a hw_lock and mii_lock. Signed-off-by: Sebastian Siewior <bigeasy@linutronix.de> Signed-off-by: Greg Ungerer <gerg@uclinux.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
c1d9615680
Коммит
3b2b74cad3
|
@ -209,7 +209,10 @@ struct fec_enet_private {
|
||||||
cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
|
cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
|
||||||
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
|
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
|
||||||
uint tx_full;
|
uint tx_full;
|
||||||
spinlock_t lock;
|
/* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
|
||||||
|
spinlock_t hw_lock;
|
||||||
|
/* hold while accessing the mii_list_t() elements */
|
||||||
|
spinlock_t mii_lock;
|
||||||
|
|
||||||
uint phy_id;
|
uint phy_id;
|
||||||
uint phy_id_done;
|
uint phy_id_done;
|
||||||
|
@ -313,6 +316,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
volatile fec_t *fecp;
|
volatile fec_t *fecp;
|
||||||
volatile cbd_t *bdp;
|
volatile cbd_t *bdp;
|
||||||
unsigned short status;
|
unsigned short status;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
fep = netdev_priv(dev);
|
fep = netdev_priv(dev);
|
||||||
fecp = (volatile fec_t*)dev->base_addr;
|
fecp = (volatile fec_t*)dev->base_addr;
|
||||||
|
@ -322,6 +326,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&fep->hw_lock, flags);
|
||||||
/* Fill in a Tx ring entry */
|
/* Fill in a Tx ring entry */
|
||||||
bdp = fep->cur_tx;
|
bdp = fep->cur_tx;
|
||||||
|
|
||||||
|
@ -332,6 +337,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
* This should not happen, since dev->tbusy should be set.
|
* This should not happen, since dev->tbusy should be set.
|
||||||
*/
|
*/
|
||||||
printk("%s: tx queue full!.\n", dev->name);
|
printk("%s: tx queue full!.\n", dev->name);
|
||||||
|
spin_unlock_irqrestore(&fep->hw_lock, flags);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -370,8 +376,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
flush_dcache_range((unsigned long)skb->data,
|
flush_dcache_range((unsigned long)skb->data,
|
||||||
(unsigned long)skb->data + skb->len);
|
(unsigned long)skb->data + skb->len);
|
||||||
|
|
||||||
spin_lock_irq(&fep->lock);
|
|
||||||
|
|
||||||
/* Send it on its way. Tell FEC it's ready, interrupt when done,
|
/* Send it on its way. Tell FEC it's ready, interrupt when done,
|
||||||
* it's the last BD of the frame, and to put the CRC on the end.
|
* it's the last BD of the frame, and to put the CRC on the end.
|
||||||
*/
|
*/
|
||||||
|
@ -400,7 +404,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
|
|
||||||
fep->cur_tx = (cbd_t *)bdp;
|
fep->cur_tx = (cbd_t *)bdp;
|
||||||
|
|
||||||
spin_unlock_irq(&fep->lock);
|
spin_unlock_irqrestore(&fep->hw_lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -458,19 +462,20 @@ fec_enet_interrupt(int irq, void * dev_id)
|
||||||
struct net_device *dev = dev_id;
|
struct net_device *dev = dev_id;
|
||||||
volatile fec_t *fecp;
|
volatile fec_t *fecp;
|
||||||
uint int_events;
|
uint int_events;
|
||||||
int handled = 0;
|
irqreturn_t ret = IRQ_NONE;
|
||||||
|
|
||||||
fecp = (volatile fec_t*)dev->base_addr;
|
fecp = (volatile fec_t*)dev->base_addr;
|
||||||
|
|
||||||
/* Get the interrupt events that caused us to be here.
|
/* Get the interrupt events that caused us to be here.
|
||||||
*/
|
*/
|
||||||
while ((int_events = fecp->fec_ievent) != 0) {
|
do {
|
||||||
|
int_events = fecp->fec_ievent;
|
||||||
fecp->fec_ievent = int_events;
|
fecp->fec_ievent = int_events;
|
||||||
|
|
||||||
/* Handle receive event in its own function.
|
/* Handle receive event in its own function.
|
||||||
*/
|
*/
|
||||||
if (int_events & FEC_ENET_RXF) {
|
if (int_events & FEC_ENET_RXF) {
|
||||||
handled = 1;
|
ret = IRQ_HANDLED;
|
||||||
fec_enet_rx(dev);
|
fec_enet_rx(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,17 +484,18 @@ fec_enet_interrupt(int irq, void * dev_id)
|
||||||
them as part of the transmit process.
|
them as part of the transmit process.
|
||||||
*/
|
*/
|
||||||
if (int_events & FEC_ENET_TXF) {
|
if (int_events & FEC_ENET_TXF) {
|
||||||
handled = 1;
|
ret = IRQ_HANDLED;
|
||||||
fec_enet_tx(dev);
|
fec_enet_tx(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (int_events & FEC_ENET_MII) {
|
if (int_events & FEC_ENET_MII) {
|
||||||
handled = 1;
|
ret = IRQ_HANDLED;
|
||||||
fec_enet_mii(dev);
|
fec_enet_mii(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} while (int_events);
|
||||||
return IRQ_RETVAL(handled);
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -502,7 +508,7 @@ fec_enet_tx(struct net_device *dev)
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
fep = netdev_priv(dev);
|
fep = netdev_priv(dev);
|
||||||
spin_lock(&fep->lock);
|
spin_lock_irq(&fep->hw_lock);
|
||||||
bdp = fep->dirty_tx;
|
bdp = fep->dirty_tx;
|
||||||
|
|
||||||
while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
|
while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
|
||||||
|
@ -561,7 +567,7 @@ fec_enet_tx(struct net_device *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fep->dirty_tx = (cbd_t *)bdp;
|
fep->dirty_tx = (cbd_t *)bdp;
|
||||||
spin_unlock(&fep->lock);
|
spin_unlock_irq(&fep->hw_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -588,6 +594,8 @@ fec_enet_rx(struct net_device *dev)
|
||||||
fep = netdev_priv(dev);
|
fep = netdev_priv(dev);
|
||||||
fecp = (volatile fec_t*)dev->base_addr;
|
fecp = (volatile fec_t*)dev->base_addr;
|
||||||
|
|
||||||
|
spin_lock_irq(&fep->hw_lock);
|
||||||
|
|
||||||
/* First, grab all of the stats for the incoming packet.
|
/* First, grab all of the stats for the incoming packet.
|
||||||
* These get messed up if we get called due to a busy condition.
|
* These get messed up if we get called due to a busy condition.
|
||||||
*/
|
*/
|
||||||
|
@ -693,6 +701,8 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
|
||||||
*/
|
*/
|
||||||
fecp->fec_r_des_active = 0;
|
fecp->fec_r_des_active = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
spin_unlock_irq(&fep->hw_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -706,11 +716,11 @@ fec_enet_mii(struct net_device *dev)
|
||||||
uint mii_reg;
|
uint mii_reg;
|
||||||
|
|
||||||
fep = netdev_priv(dev);
|
fep = netdev_priv(dev);
|
||||||
|
spin_lock_irq(&fep->mii_lock);
|
||||||
|
|
||||||
ep = fep->hwp;
|
ep = fep->hwp;
|
||||||
mii_reg = ep->fec_mii_data;
|
mii_reg = ep->fec_mii_data;
|
||||||
|
|
||||||
spin_lock(&fep->lock);
|
|
||||||
|
|
||||||
if ((mip = mii_head) == NULL) {
|
if ((mip = mii_head) == NULL) {
|
||||||
printk("MII and no head!\n");
|
printk("MII and no head!\n");
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
@ -727,7 +737,7 @@ fec_enet_mii(struct net_device *dev)
|
||||||
ep->fec_mii_data = mip->mii_regval;
|
ep->fec_mii_data = mip->mii_regval;
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
spin_unlock(&fep->lock);
|
spin_unlock_irq(&fep->mii_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -741,12 +751,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
|
||||||
/* Add PHY address to register command.
|
/* Add PHY address to register command.
|
||||||
*/
|
*/
|
||||||
fep = netdev_priv(dev);
|
fep = netdev_priv(dev);
|
||||||
|
spin_lock_irqsave(&fep->mii_lock, flags);
|
||||||
|
|
||||||
regval |= fep->phy_addr << 23;
|
regval |= fep->phy_addr << 23;
|
||||||
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
||||||
spin_lock_irqsave(&fep->lock,flags);
|
|
||||||
|
|
||||||
if ((mip = mii_free) != NULL) {
|
if ((mip = mii_free) != NULL) {
|
||||||
mii_free = mip->mii_next;
|
mii_free = mip->mii_next;
|
||||||
mip->mii_regval = regval;
|
mip->mii_regval = regval;
|
||||||
|
@ -763,9 +772,8 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&fep->lock,flags);
|
spin_unlock_irqrestore(&fep->mii_lock, flags);
|
||||||
|
return retval;
|
||||||
return(retval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
|
static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
|
||||||
|
@ -2308,6 +2316,9 @@ int __init fec_enet_init(struct net_device *dev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&fep->hw_lock);
|
||||||
|
spin_lock_init(&fep->mii_lock);
|
||||||
|
|
||||||
/* Create an Ethernet device instance.
|
/* Create an Ethernet device instance.
|
||||||
*/
|
*/
|
||||||
fecp = (volatile fec_t *) fec_hw[index];
|
fecp = (volatile fec_t *) fec_hw[index];
|
||||||
|
|
Загрузка…
Ссылка в новой задаче