Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] via-rhine: change mdelay to msleep and remove from ISR path

Get rid of the mdelay call in rhine_disable_linkmon. The function
is called from the via-rhine versions of mdio_read and mdio_write.
Those functions are indirectly called from rhine_check_media and
rhine_tx_timeout, both of which can be called in interrupt context.

So, create tx_timeout_task and check_media_task as instances of struct
work_struct inside of rhine_private. Then, change rhine_tx_timeout to
invoke schedule_work for tx_timeout_task (i.e. rhine_tx_timeout_task),
moving the work to process context. Also, change rhine_error (invoked
from rhine_interrupt) to invoke schedule_work for check_media_task
(i.e. rhine_check_media_task), which simply calls rhine_check media
in process context. Finally, add a call to flush_scheduled_work in
rhine_close to avoid any resource conflicts with pending work items.

Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>

authored by

John W. Linville and committed by
Jeff Garzik
6ba98d31 92383340

+31 -3
+31 -3
drivers/net/via-rhine.c
··· 490 490 u8 tx_thresh, rx_thresh; 491 491 492 492 struct mii_if_info mii_if; 493 + struct work_struct tx_timeout_task; 494 + struct work_struct check_media_task; 493 495 void __iomem *base; 494 496 }; 495 497 ··· 499 497 static void mdio_write(struct net_device *dev, int phy_id, int location, int value); 500 498 static int rhine_open(struct net_device *dev); 501 499 static void rhine_tx_timeout(struct net_device *dev); 500 + static void rhine_tx_timeout_task(struct net_device *dev); 501 + static void rhine_check_media_task(struct net_device *dev); 502 502 static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); 503 503 static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); 504 504 static void rhine_tx(struct net_device *dev); ··· 855 851 if (rp->quirks & rqRhineI) 856 852 dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; 857 853 854 + INIT_WORK(&rp->tx_timeout_task, 855 + (void (*)(void *))rhine_tx_timeout_task, dev); 856 + 857 + INIT_WORK(&rp->check_media_task, 858 + (void (*)(void *))rhine_check_media_task, dev); 859 + 858 860 /* dev->name not defined before register_netdev()! */ 859 861 rc = register_netdev(dev); 860 862 if (rc) ··· 1087 1077 ioaddr + ChipCmd1); 1088 1078 } 1089 1079 1080 + static void rhine_check_media_task(struct net_device *dev) 1081 + { 1082 + rhine_check_media(dev, 0); 1083 + } 1084 + 1090 1085 static void init_registers(struct net_device *dev) 1091 1086 { 1092 1087 struct rhine_private *rp = netdev_priv(dev); ··· 1145 1130 if (quirks & rqRhineI) { 1146 1131 iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR 1147 1132 1148 - /* Can be called from ISR. Evil. */ 1149 - mdelay(1); 1133 + /* Do not call from ISR! */ 1134 + msleep(1); 1150 1135 1151 1136 /* 0x80 must be set immediately before turning it off */ 1152 1137 iowrite8(0x80, ioaddr + MIICmd); ··· 1234 1219 } 1235 1220 1236 1221 static void rhine_tx_timeout(struct net_device *dev) 1222 + { 1223 + struct rhine_private *rp = netdev_priv(dev); 1224 + 1225 + /* 1226 + * Move bulk of work outside of interrupt context 1227 + */ 1228 + schedule_work(&rp->tx_timeout_task); 1229 + } 1230 + 1231 + static void rhine_tx_timeout_task(struct net_device *dev) 1237 1232 { 1238 1233 struct rhine_private *rp = netdev_priv(dev); 1239 1234 void __iomem *ioaddr = rp->base; ··· 1651 1626 spin_lock(&rp->lock); 1652 1627 1653 1628 if (intr_status & IntrLinkChange) 1654 - rhine_check_media(dev, 0); 1629 + schedule_work(&rp->check_media_task); 1655 1630 if (intr_status & IntrStatsMax) { 1656 1631 rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); 1657 1632 rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); ··· 1899 1874 spin_unlock_irq(&rp->lock); 1900 1875 1901 1876 free_irq(rp->pdev->irq, dev); 1877 + 1878 + flush_scheduled_work(); 1879 + 1902 1880 free_rbufs(dev); 1903 1881 free_tbufs(dev); 1904 1882 free_ring(dev);