Commit 6ba98d31 authored by John W. Linville's avatar John W. Linville Committed by Jeff Garzik

[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: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 92383340
...@@ -490,6 +490,8 @@ struct rhine_private { ...@@ -490,6 +490,8 @@ struct rhine_private {
u8 tx_thresh, rx_thresh; u8 tx_thresh, rx_thresh;
struct mii_if_info mii_if; struct mii_if_info mii_if;
struct work_struct tx_timeout_task;
struct work_struct check_media_task;
void __iomem *base; void __iomem *base;
}; };
...@@ -497,6 +499,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); ...@@ -497,6 +499,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static int rhine_open(struct net_device *dev); static int rhine_open(struct net_device *dev);
static void rhine_tx_timeout(struct net_device *dev); static void rhine_tx_timeout(struct net_device *dev);
static void rhine_tx_timeout_task(struct net_device *dev);
static void rhine_check_media_task(struct net_device *dev);
static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev); static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static void rhine_tx(struct net_device *dev); static void rhine_tx(struct net_device *dev);
...@@ -851,6 +855,12 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, ...@@ -851,6 +855,12 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if (rp->quirks & rqRhineI) if (rp->quirks & rqRhineI)
dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
INIT_WORK(&rp->tx_timeout_task,
(void (*)(void *))rhine_tx_timeout_task, dev);
INIT_WORK(&rp->check_media_task,
(void (*)(void *))rhine_check_media_task, dev);
/* dev->name not defined before register_netdev()! */ /* dev->name not defined before register_netdev()! */
rc = register_netdev(dev); rc = register_netdev(dev);
if (rc) if (rc)
...@@ -1077,6 +1087,11 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) ...@@ -1077,6 +1087,11 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
ioaddr + ChipCmd1); ioaddr + ChipCmd1);
} }
static void rhine_check_media_task(struct net_device *dev)
{
rhine_check_media(dev, 0);
}
static void init_registers(struct net_device *dev) static void init_registers(struct net_device *dev)
{ {
struct rhine_private *rp = netdev_priv(dev); struct rhine_private *rp = netdev_priv(dev);
...@@ -1130,8 +1145,8 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks) ...@@ -1130,8 +1145,8 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
if (quirks & rqRhineI) { if (quirks & rqRhineI) {
iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR iowrite8(0x01, ioaddr + MIIRegAddr); // MII_BMSR
/* Can be called from ISR. Evil. */ /* Do not call from ISR! */
mdelay(1); msleep(1);
/* 0x80 must be set immediately before turning it off */ /* 0x80 must be set immediately before turning it off */
iowrite8(0x80, ioaddr + MIICmd); iowrite8(0x80, ioaddr + MIICmd);
...@@ -1219,6 +1234,16 @@ static int rhine_open(struct net_device *dev) ...@@ -1219,6 +1234,16 @@ static int rhine_open(struct net_device *dev)
} }
static void rhine_tx_timeout(struct net_device *dev) static void rhine_tx_timeout(struct net_device *dev)
{
struct rhine_private *rp = netdev_priv(dev);
/*
* Move bulk of work outside of interrupt context
*/
schedule_work(&rp->tx_timeout_task);
}
static void rhine_tx_timeout_task(struct net_device *dev)
{ {
struct rhine_private *rp = netdev_priv(dev); struct rhine_private *rp = netdev_priv(dev);
void __iomem *ioaddr = rp->base; void __iomem *ioaddr = rp->base;
...@@ -1626,7 +1651,7 @@ static void rhine_error(struct net_device *dev, int intr_status) ...@@ -1626,7 +1651,7 @@ static void rhine_error(struct net_device *dev, int intr_status)
spin_lock(&rp->lock); spin_lock(&rp->lock);
if (intr_status & IntrLinkChange) if (intr_status & IntrLinkChange)
rhine_check_media(dev, 0); schedule_work(&rp->check_media_task);
if (intr_status & IntrStatsMax) { if (intr_status & IntrStatsMax) {
rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs); rp->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed); rp->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
...@@ -1874,6 +1899,9 @@ static int rhine_close(struct net_device *dev) ...@@ -1874,6 +1899,9 @@ static int rhine_close(struct net_device *dev)
spin_unlock_irq(&rp->lock); spin_unlock_irq(&rp->lock);
free_irq(rp->pdev->irq, dev); free_irq(rp->pdev->irq, dev);
flush_scheduled_work();
free_rbufs(dev); free_rbufs(dev);
free_tbufs(dev); free_tbufs(dev);
free_ring(dev); free_ring(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment