aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/gianfar.c
diff options
context:
space:
mode:
authorAndy Fleming <afleming@freescale.com>2006-04-20 17:44:29 -0400
committerJeff Garzik <jeff@garzik.org>2006-04-20 17:55:06 -0400
commitfef6108d4556917c45cd9ba397c1c7597f3990e1 (patch)
treef35566dd3ddbda7cc84fc8a03aa3aebeea7dc746 /drivers/net/gianfar.c
parentf18b95c3e2ab0f75b23a5aabab0bc8f99bd6bbf3 (diff)
[PATCH] Fix locking in gianfar
This patch fixes several bugs in the gianfar driver, including a major one where spinlocks were horribly broken: * Split gianfar locks into two types: TX and RX * Made it so gfar_start() now clears RHALT * Fixed a bug where calling gfar_start_xmit() with interrupts off would corrupt the interrupt state * Fixed a bug where a frame could potentially arrive, and never be handled (if no more frames arrived * Fixed a bug where the rx_work_limit would never be observed by the rx completion code * Fixed a bug where the interrupt handlers were not actually protected by their spinlocks Signed-off-by: Andy Fleming <afleming@freescale.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/gianfar.c')
-rw-r--r--drivers/net/gianfar.c56
1 files changed, 28 insertions, 28 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 771e25d8c417..218d31764c52 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -210,7 +210,8 @@ static int gfar_probe(struct platform_device *pdev)
210 goto regs_fail; 210 goto regs_fail;
211 } 211 }
212 212
213 spin_lock_init(&priv->lock); 213 spin_lock_init(&priv->txlock);
214 spin_lock_init(&priv->rxlock);
214 215
215 platform_set_drvdata(pdev, dev); 216 platform_set_drvdata(pdev, dev);
216 217
@@ -515,11 +516,13 @@ void stop_gfar(struct net_device *dev)
515 phy_stop(priv->phydev); 516 phy_stop(priv->phydev);
516 517
517 /* Lock it down */ 518 /* Lock it down */
518 spin_lock_irqsave(&priv->lock, flags); 519 spin_lock_irqsave(&priv->txlock, flags);
520 spin_lock(&priv->rxlock);
519 521
520 gfar_halt(dev); 522 gfar_halt(dev);
521 523
522 spin_unlock_irqrestore(&priv->lock, flags); 524 spin_unlock(&priv->rxlock);
525 spin_unlock_irqrestore(&priv->txlock, flags);
523 526
524 /* Free the IRQs */ 527 /* Free the IRQs */
525 if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { 528 if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
@@ -605,14 +608,15 @@ void gfar_start(struct net_device *dev)
605 tempval |= DMACTRL_INIT_SETTINGS; 608 tempval |= DMACTRL_INIT_SETTINGS;
606 gfar_write(&priv->regs->dmactrl, tempval); 609 gfar_write(&priv->regs->dmactrl, tempval);
607 610
608 /* Clear THLT, so that the DMA starts polling now */
609 gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
610
611 /* Make sure we aren't stopped */ 611 /* Make sure we aren't stopped */
612 tempval = gfar_read(&priv->regs->dmactrl); 612 tempval = gfar_read(&priv->regs->dmactrl);
613 tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); 613 tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
614 gfar_write(&priv->regs->dmactrl, tempval); 614 gfar_write(&priv->regs->dmactrl, tempval);
615 615
616 /* Clear THLT/RHLT, so that the DMA starts polling now */
617 gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
618 gfar_write(&regs->rstat, RSTAT_CLEAR_RHALT);
619
616 /* Unmask the interrupts we look for */ 620 /* Unmask the interrupts we look for */
617 gfar_write(&regs->imask, IMASK_DEFAULT); 621 gfar_write(&regs->imask, IMASK_DEFAULT);
618} 622}
@@ -928,12 +932,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
928 struct txfcb *fcb = NULL; 932 struct txfcb *fcb = NULL;
929 struct txbd8 *txbdp; 933 struct txbd8 *txbdp;
930 u16 status; 934 u16 status;
935 unsigned long flags;
931 936
932 /* Update transmit stats */ 937 /* Update transmit stats */
933 priv->stats.tx_bytes += skb->len; 938 priv->stats.tx_bytes += skb->len;
934 939
935 /* Lock priv now */ 940 /* Lock priv now */
936 spin_lock_irq(&priv->lock); 941 spin_lock_irqsave(&priv->txlock, flags);
937 942
938 /* Point at the first free tx descriptor */ 943 /* Point at the first free tx descriptor */
939 txbdp = priv->cur_tx; 944 txbdp = priv->cur_tx;
@@ -1004,7 +1009,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
1004 gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); 1009 gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
1005 1010
1006 /* Unlock priv */ 1011 /* Unlock priv */
1007 spin_unlock_irq(&priv->lock); 1012 spin_unlock_irqrestore(&priv->txlock, flags);
1008 1013
1009 return 0; 1014 return 0;
1010} 1015}
@@ -1049,7 +1054,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
1049 unsigned long flags; 1054 unsigned long flags;
1050 u32 tempval; 1055 u32 tempval;
1051 1056
1052 spin_lock_irqsave(&priv->lock, flags); 1057 spin_lock_irqsave(&priv->rxlock, flags);
1053 1058
1054 priv->vlgrp = grp; 1059 priv->vlgrp = grp;
1055 1060
@@ -1076,7 +1081,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
1076 gfar_write(&priv->regs->rctrl, tempval); 1081 gfar_write(&priv->regs->rctrl, tempval);
1077 } 1082 }
1078 1083
1079 spin_unlock_irqrestore(&priv->lock, flags); 1084 spin_unlock_irqrestore(&priv->rxlock, flags);
1080} 1085}
1081 1086
1082 1087
@@ -1085,12 +1090,12 @@ static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
1085 struct gfar_private *priv = netdev_priv(dev); 1090 struct gfar_private *priv = netdev_priv(dev);
1086 unsigned long flags; 1091 unsigned long flags;
1087 1092
1088 spin_lock_irqsave(&priv->lock, flags); 1093 spin_lock_irqsave(&priv->rxlock, flags);
1089 1094
1090 if (priv->vlgrp) 1095 if (priv->vlgrp)
1091 priv->vlgrp->vlan_devices[vid] = NULL; 1096 priv->vlgrp->vlan_devices[vid] = NULL;
1092 1097
1093 spin_unlock_irqrestore(&priv->lock, flags); 1098 spin_unlock_irqrestore(&priv->rxlock, flags);
1094} 1099}
1095 1100
1096 1101
@@ -1179,7 +1184,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
1179 gfar_write(&priv->regs->ievent, IEVENT_TX_MASK); 1184 gfar_write(&priv->regs->ievent, IEVENT_TX_MASK);
1180 1185
1181 /* Lock priv */ 1186 /* Lock priv */
1182 spin_lock(&priv->lock); 1187 spin_lock(&priv->txlock);
1183 bdp = priv->dirty_tx; 1188 bdp = priv->dirty_tx;
1184 while ((bdp->status & TXBD_READY) == 0) { 1189 while ((bdp->status & TXBD_READY) == 0) {
1185 /* If dirty_tx and cur_tx are the same, then either the */ 1190 /* If dirty_tx and cur_tx are the same, then either the */
@@ -1224,7 +1229,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
1224 else 1229 else
1225 gfar_write(&priv->regs->txic, 0); 1230 gfar_write(&priv->regs->txic, 0);
1226 1231
1227 spin_unlock(&priv->lock); 1232 spin_unlock(&priv->txlock);
1228 1233
1229 return IRQ_HANDLED; 1234 return IRQ_HANDLED;
1230} 1235}
@@ -1305,9 +1310,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
1305{ 1310{
1306 struct net_device *dev = (struct net_device *) dev_id; 1311 struct net_device *dev = (struct net_device *) dev_id;
1307 struct gfar_private *priv = netdev_priv(dev); 1312 struct gfar_private *priv = netdev_priv(dev);
1308
1309#ifdef CONFIG_GFAR_NAPI 1313#ifdef CONFIG_GFAR_NAPI
1310 u32 tempval; 1314 u32 tempval;
1315#else
1316 unsigned long flags;
1311#endif 1317#endif
1312 1318
1313 /* Clear IEVENT, so rx interrupt isn't called again 1319 /* Clear IEVENT, so rx interrupt isn't called again
@@ -1330,7 +1336,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
1330 } 1336 }
1331#else 1337#else
1332 1338
1333 spin_lock(&priv->lock); 1339 spin_lock_irqsave(&priv->rxlock, flags);
1334 gfar_clean_rx_ring(dev, priv->rx_ring_size); 1340 gfar_clean_rx_ring(dev, priv->rx_ring_size);
1335 1341
1336 /* If we are coalescing interrupts, update the timer */ 1342 /* If we are coalescing interrupts, update the timer */
@@ -1341,7 +1347,7 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
1341 else 1347 else
1342 gfar_write(&priv->regs->rxic, 0); 1348 gfar_write(&priv->regs->rxic, 0);
1343 1349
1344 spin_unlock(&priv->lock); 1350 spin_unlock_irqrestore(&priv->rxlock, flags);
1345#endif 1351#endif
1346 1352
1347 return IRQ_HANDLED; 1353 return IRQ_HANDLED;
@@ -1490,13 +1496,6 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
1490 /* Update the current rxbd pointer to be the next one */ 1496 /* Update the current rxbd pointer to be the next one */
1491 priv->cur_rx = bdp; 1497 priv->cur_rx = bdp;
1492 1498
1493 /* If no packets have arrived since the
1494 * last one we processed, clear the IEVENT RX and
1495 * BSY bits so that another interrupt won't be
1496 * generated when we set IMASK */
1497 if (bdp->status & RXBD_EMPTY)
1498 gfar_write(&priv->regs->ievent, IEVENT_RX_MASK);
1499
1500 return howmany; 1499 return howmany;
1501} 1500}
1502 1501
@@ -1516,7 +1515,7 @@ static int gfar_poll(struct net_device *dev, int *budget)
1516 rx_work_limit -= howmany; 1515 rx_work_limit -= howmany;
1517 *budget -= howmany; 1516 *budget -= howmany;
1518 1517
1519 if (rx_work_limit >= 0) { 1518 if (rx_work_limit > 0) {
1520 netif_rx_complete(dev); 1519 netif_rx_complete(dev);
1521 1520
1522 /* Clear the halt bit in RSTAT */ 1521 /* Clear the halt bit in RSTAT */
@@ -1533,7 +1532,8 @@ static int gfar_poll(struct net_device *dev, int *budget)
1533 gfar_write(&priv->regs->rxic, 0); 1532 gfar_write(&priv->regs->rxic, 0);
1534 } 1533 }
1535 1534
1536 return (rx_work_limit < 0) ? 1 : 0; 1535 /* Return 1 if there's more work to do */
1536 return (rx_work_limit > 0) ? 0 : 1;
1537} 1537}
1538#endif 1538#endif
1539 1539
@@ -1629,7 +1629,7 @@ static void adjust_link(struct net_device *dev)
1629 struct phy_device *phydev = priv->phydev; 1629 struct phy_device *phydev = priv->phydev;
1630 int new_state = 0; 1630 int new_state = 0;
1631 1631
1632 spin_lock_irqsave(&priv->lock, flags); 1632 spin_lock_irqsave(&priv->txlock, flags);
1633 if (phydev->link) { 1633 if (phydev->link) {
1634 u32 tempval = gfar_read(&regs->maccfg2); 1634 u32 tempval = gfar_read(&regs->maccfg2);
1635 u32 ecntrl = gfar_read(&regs->ecntrl); 1635 u32 ecntrl = gfar_read(&regs->ecntrl);
@@ -1694,7 +1694,7 @@ static void adjust_link(struct net_device *dev)
1694 if (new_state && netif_msg_link(priv)) 1694 if (new_state && netif_msg_link(priv))
1695 phy_print_status(phydev); 1695 phy_print_status(phydev);
1696 1696
1697 spin_unlock_irqrestore(&priv->lock, flags); 1697 spin_unlock_irqrestore(&priv->txlock, flags);
1698} 1698}
1699 1699
1700/* Update the hash table based on the current list of multicast 1700/* Update the hash table based on the current list of multicast