lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sun, 8 Jan 2012 12:57:06 +0100
From:	Bjarke Istrup Pedersen <gurligebis@...too.org>
To:	Francois Romieu <romieu@...zoreil.com>
Cc:	netdev@...r.kernel.org, rl@...lgate.ch,
	David Miller <davem@...emloft.net>
Subject: Re: [PATCH net-next 0/7] via-rhine NAPI rework and misc.

2012/1/7 Francois Romieu <romieu@...zoreil.com>:
> I have reworked the series since the last submission so as to limit
> unneeded changes before the move of work from IRQ context to NAPI
> and work queue.  Those changes were mostly related to debug messages.
> They are now done later in the the series. I have included a few
> resume + suspend changes as well. Unbalanced task disabling should
> now be fixed. Newly introduced methods have been set so as to
> limit useless forward declarations.
>
> I am very confident that everything works fine and it is fairly well
> known that my patches always reach perfection, especially on week end
> when I'd better go downtown to avoid the noise of those pesky young
> neighbors. I have however not included Bjarke's Tested-by since the
> content is not strictly identical. I'll gladly do so for #1..#4 if
> everything is ok.

Hey,

It runs great, I've been testing it for the last hour without any
problems, lots of trafic and connections, and the usual messing around
with tools :)
You're welcome to add my as Tested-by if you want.

/Bjarke

> The changes are equally available as :
>
> git://violet.fr.zoreil.com/romieu/linux davem-next.via-rhine
>
> Distance from 'davem-next' (356b95424cfb456e14a59eaa579422ce014c424b)
> ---------------------------------------------------------------------
>
> e92b9b3b091d5fcdaed91d6fa9410deae135704b
> fc3e0f8aec05dd812cba2c1e31c3d1f5fc85e55c
> a384a33bb1c9ec2d99db2046b41f57023fa7d77b
> 7ab87ff4c770eed71e3777936299292739fcd0fe
> a5abec1e84c3d9cd197667e5fa94f25c21a2cb8e
> a20a28bc321fefcc23f8da7ce3722e6ae7a7199d
> 269f3114b53a3ce93eb5977852ac2624a380f600
>
> Diffstat
> --------
>
>  drivers/net/ethernet/via/via-rhine.c |  668 +++++++++++++++++++---------------
>  1 files changed, 368 insertions(+), 300 deletions(-)
>
> Shortlog
> --------
>
> Francois Romieu (7):
>      via-rhine: factor out tx_thresh handling
>      via-rhine: balance interrupt acknowledge and events retrieval.
>      via-rhine: remove useless forward declarations.
>      via-rhine: move work from irq handler to softirq and beyond.
>      via-rhine: RHINE_WAIT_FOR macro removal.
>      via-rhine: per device debug level.
>      via-rhine: rework suspend and resume.
>
> Patch
> -----
>
> diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
> index 5c4983b..10b18eb 100644
> --- a/drivers/net/ethernet/via/via-rhine.c
> +++ b/drivers/net/ethernet/via/via-rhine.c
> @@ -39,10 +39,9 @@
>
>  /* A few user-configurable values.
>    These may be modified when a driver module is loaded. */
> -
> -#define DEBUG
> -static int debug = 1;  /* 1 normal messages, 0 quiet .. 7 verbose. */
> -static int max_interrupt_work = 20;
> +static int debug = 0;
> +#define RHINE_MSG_DEFAULT \
> +        (0x0000)
>
>  /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
>    Setting to > 1518 effectively disables this feature. */
> @@ -128,12 +127,10 @@ MODULE_AUTHOR("Donald Becker <becker@...ld.com>");
>  MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
>  MODULE_LICENSE("GPL");
>
> -module_param(max_interrupt_work, int, 0);
>  module_param(debug, int, 0);
>  module_param(rx_copybreak, int, 0);
>  module_param(avoid_D3, bool, 0);
> -MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
> -MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
> +MODULE_PARM_DESC(debug, "VIA Rhine debug message flags");
>  MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
>  MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)");
>
> @@ -351,16 +348,25 @@ static const int mmio_verify_registers[] = {
>
>  /* Bits in the interrupt status/mask registers. */
>  enum intr_status_bits {
> -       IntrRxDone=0x0001, IntrRxErr=0x0004, IntrRxEmpty=0x0020,
> -       IntrTxDone=0x0002, IntrTxError=0x0008, IntrTxUnderrun=0x0210,
> -       IntrPCIErr=0x0040,
> -       IntrStatsMax=0x0080, IntrRxEarly=0x0100,
> -       IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
> -       IntrTxAborted=0x2000, IntrLinkChange=0x4000,
> -       IntrRxWakeUp=0x8000,
> -       IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
> -       IntrTxDescRace=0x080000,        /* mapped from IntrStatus2 */
> -       IntrTxErrSummary=0x082218,
> +       IntrRxDone      = 0x0001,
> +       IntrTxDone      = 0x0002,
> +       IntrRxErr       = 0x0004,
> +       IntrTxError     = 0x0008,
> +       IntrRxEmpty     = 0x0020,
> +       IntrPCIErr      = 0x0040,
> +       IntrStatsMax    = 0x0080,
> +       IntrRxEarly     = 0x0100,
> +       IntrTxUnderrun  = 0x0210,
> +       IntrRxOverflow  = 0x0400,
> +       IntrRxDropped   = 0x0800,
> +       IntrRxNoBuf     = 0x1000,
> +       IntrTxAborted   = 0x2000,
> +       IntrLinkChange  = 0x4000,
> +       IntrRxWakeUp    = 0x8000,
> +       IntrTxDescRace          = 0x080000,     /* mapped from IntrStatus2 */
> +       IntrNormalSummary       = IntrRxDone | IntrTxDone,
> +       IntrTxErrSummary        = IntrTxDescRace | IntrTxAborted | IntrTxError |
> +                                 IntrTxUnderrun,
>  };
>
>  /* Bits in WOLcrSet/WOLcrClr and PwrcsrSet/PwrcsrClr */
> @@ -439,8 +445,13 @@ struct rhine_private {
>        struct net_device *dev;
>        struct napi_struct napi;
>        spinlock_t lock;
> +       struct mutex task_lock;
> +       bool task_enable;
> +       struct work_struct slow_event_task;
>        struct work_struct reset_task;
>
> +       u32 msg_enable;
> +
>        /* Frequently used values: keep some adjacent for cache effect. */
>        u32 quirks;
>        struct rx_desc *rx_head_desc;
> @@ -476,41 +487,50 @@ 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 int  rhine_open(struct net_device *dev);
>  static void rhine_reset_task(struct work_struct *work);
> +static void rhine_slow_event_task(struct work_struct *work);
>  static void rhine_tx_timeout(struct net_device *dev);
>  static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
>                                  struct net_device *dev);
>  static irqreturn_t rhine_interrupt(int irq, void *dev_instance);
>  static void rhine_tx(struct net_device *dev);
>  static int rhine_rx(struct net_device *dev, int limit);
> -static void rhine_error(struct net_device *dev, int intr_status);
>  static void rhine_set_rx_mode(struct net_device *dev);
>  static struct net_device_stats *rhine_get_stats(struct net_device *dev);
>  static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
>  static const struct ethtool_ops netdev_ethtool_ops;
>  static int  rhine_close(struct net_device *dev);
> -static void rhine_shutdown (struct pci_dev *pdev);
>  static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid);
>  static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid);
> -static void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr);
> -static void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr);
> -static void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask);
> -static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask);
> -static void rhine_init_cam_filter(struct net_device *dev);
> -static void rhine_update_vcam(struct net_device *dev);
> -
> -#define RHINE_WAIT_FOR(condition)                              \
> -do {                                                           \
> -       int i = 1024;                                           \
> -       while (!(condition) && --i)                             \
> -               ;                                               \
> -       if (debug > 1 && i < 512)                               \
> -               pr_info("%4d cycles used @ %s:%d\n",            \
> -                       1024 - i, __func__, __LINE__);          \
> -} while (0)
> -
> -static inline u32 get_intr_status(struct net_device *dev)
> +static void rhine_restart_tx(struct net_device *dev);
> +
> +static void rhine_wait_bit(struct rhine_private *rp, u8 reg, u8 mask, bool high)
> +{
> +       void __iomem *ioaddr = rp->base;
> +       int i;
> +
> +       for (i = 0; i < 1024; i++) {
> +               if (high ^ !!(ioread8(ioaddr + reg) & mask))
> +                       break;
> +               udelay(10);
> +       }
> +       if (i > 64) {
> +               netif_dbg(rp, hw, rp->dev, "%s bit wait (%02x/%02x) cycle "
> +                         "count: %04d\n", high ? "high" : "low", reg, mask, i);
> +       }
> +}
> +
> +static void rhine_wait_bit_high(struct rhine_private *rp, u8 reg, u8 mask)
> +{
> +       rhine_wait_bit(rp, reg, mask, true);
> +}
> +
> +static void rhine_wait_bit_low(struct rhine_private *rp, u8 reg, u8 mask)
> +{
> +       rhine_wait_bit(rp, reg, mask, false);
> +}
> +
> +static u32 rhine_get_events(struct rhine_private *rp)
>  {
> -       struct rhine_private *rp = netdev_priv(dev);
>        void __iomem *ioaddr = rp->base;
>        u32 intr_status;
>
> @@ -521,6 +541,16 @@ static inline u32 get_intr_status(struct net_device *dev)
>        return intr_status;
>  }
>
> +static void rhine_ack_events(struct rhine_private *rp, u32 mask)
> +{
> +       void __iomem *ioaddr = rp->base;
> +
> +       if (rp->quirks & rqStatusWBRace)
> +               iowrite8(mask >> 16, ioaddr + IntrStatus2);
> +       iowrite16(mask, ioaddr + IntrStatus);
> +       mmiowb();
> +}
> +
>  /*
>  * Get power related registers into sane state.
>  * Notify user about past WOL event.
> @@ -585,6 +615,7 @@ static void rhine_chip_reset(struct net_device *dev)
>  {
>        struct rhine_private *rp = netdev_priv(dev);
>        void __iomem *ioaddr = rp->base;
> +       u8 cmd1;
>
>        iowrite8(Cmd1Reset, ioaddr + ChipCmd1);
>        IOSYNC;
> @@ -597,13 +628,12 @@ static void rhine_chip_reset(struct net_device *dev)
>                        iowrite8(0x40, ioaddr + MiscCmd);
>
>                /* Reset can take somewhat longer (rare) */
> -               RHINE_WAIT_FOR(!(ioread8(ioaddr + ChipCmd1) & Cmd1Reset));
> +               rhine_wait_bit_low(rp, ChipCmd1, Cmd1Reset);
>        }
>
> -       if (debug > 1)
> -               netdev_info(dev, "Reset %s\n",
> -                           (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ?
> -                           "failed" : "succeeded");
> +       cmd1 = ioread8(ioaddr + ChipCmd1);
> +       netif_info(rp, hw, dev, "Reset %s\n", (cmd1 & Cmd1Reset) ?
> +                  "failed" : "succeeded");
>  }
>
>  #ifdef USE_MMIO
> @@ -629,9 +659,15 @@ static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev)
>  {
>        struct rhine_private *rp = netdev_priv(dev);
>        void __iomem *ioaddr = rp->base;
> +       int i;
>
>        outb(0x20, pioaddr + MACRegEEcsr);
> -       RHINE_WAIT_FOR(!(inb(pioaddr + MACRegEEcsr) & 0x20));
> +       for (i = 0; i < 1024; i++) {
> +               if (!(inb(pioaddr + MACRegEEcsr) & 0x20))
> +                       break;
> +       }
> +       if (i > 512)
> +               pr_info("%4d cycles used @ %s:%d\n", i, __func__, __LINE__);
>
>  #ifdef USE_MMIO
>        /*
> @@ -657,23 +693,127 @@ static void rhine_poll(struct net_device *dev)
>  }
>  #endif
>
> +static void rhine_kick_tx_threshold(struct rhine_private *rp)
> +{
> +       if (rp->tx_thresh < 0xe0) {
> +               void __iomem *ioaddr = rp->base;
> +
> +               rp->tx_thresh += 0x20;
> +               BYTE_REG_BITS_SET(rp->tx_thresh, 0x80, ioaddr + TxConfig);
> +       }
> +}
> +
> +static void rhine_tx_err(struct rhine_private *rp, u32 status)
> +{
> +       struct net_device *dev = rp->dev;
> +
> +       if (status & IntrTxAborted) {
> +               netif_info(rp, tx_err, dev,
> +                          "Abort %08x, frame dropped\n", status);
> +       }
> +
> +       if (status & IntrTxUnderrun) {
> +               rhine_kick_tx_threshold(rp);
> +               netif_info(rp, tx_err ,dev, "Transmitter underrun, "
> +                          "Tx threshold now %02x\n", rp->tx_thresh);
> +       }
> +
> +       if (status & IntrTxDescRace)
> +               netif_info(rp, tx_err, dev, "Tx descriptor write-back race\n");
> +
> +       if ((status & IntrTxError) &&
> +           (status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace)) == 0) {
> +               rhine_kick_tx_threshold(rp);
> +               netif_info(rp, tx_err, dev, "Unspecified error. "
> +                          "Tx threshold now %02x\n", rp->tx_thresh);
> +       }
> +
> +       rhine_restart_tx(dev);
> +}
> +
> +static void rhine_update_rx_crc_and_missed_errord(struct rhine_private *rp)
> +{
> +       void __iomem *ioaddr = rp->base;
> +       struct net_device_stats *stats = &rp->dev->stats;
> +
> +       stats->rx_crc_errors    += ioread16(ioaddr + RxCRCErrs);
> +       stats->rx_missed_errors += ioread16(ioaddr + RxMissed);
> +
> +       /*
> +        * Clears the "tally counters" for CRC errors and missed frames(?).
> +        * It has been reported that some chips need a write of 0 to clear
> +        * these, for others the counters are set to 1 when written to and
> +        * instead cleared when read. So we clear them both ways ...
> +        */
> +       iowrite32(0, ioaddr + RxMissed);
> +       ioread16(ioaddr + RxCRCErrs);
> +       ioread16(ioaddr + RxMissed);
> +}
> +
> +#define RHINE_EVENT_NAPI_RX    (IntrRxDone | \
> +                                IntrRxErr | \
> +                                IntrRxEmpty | \
> +                                IntrRxOverflow | \
> +                                IntrRxDropped | \
> +                                IntrRxNoBuf | \
> +                                IntrRxWakeUp)
> +
> +#define RHINE_EVENT_NAPI_TX_ERR        (IntrTxError | \
> +                                IntrTxAborted | \
> +                                IntrTxUnderrun | \
> +                                IntrTxDescRace)
> +#define RHINE_EVENT_NAPI_TX    (IntrTxDone | RHINE_EVENT_NAPI_TX_ERR)
> +
> +#define RHINE_EVENT_NAPI       (RHINE_EVENT_NAPI_RX | \
> +                                RHINE_EVENT_NAPI_TX | \
> +                                IntrStatsMax)
> +#define RHINE_EVENT_SLOW       (IntrPCIErr | IntrLinkChange)
> +#define RHINE_EVENT            (RHINE_EVENT_NAPI | RHINE_EVENT_SLOW)
> +
>  static int rhine_napipoll(struct napi_struct *napi, int budget)
>  {
>        struct rhine_private *rp = container_of(napi, struct rhine_private, napi);
>        struct net_device *dev = rp->dev;
>        void __iomem *ioaddr = rp->base;
> -       int work_done;
> +       u16 enable_mask = RHINE_EVENT & 0xffff;
> +       int work_done = 0;
> +       u32 status;
> +
> +       status = rhine_get_events(rp);
> +       rhine_ack_events(rp, status & ~RHINE_EVENT_SLOW);
> +
> +       if (status & RHINE_EVENT_NAPI_RX)
> +               work_done += rhine_rx(dev, budget);
> +
> +       if (status & RHINE_EVENT_NAPI_TX) {
> +               if (status & RHINE_EVENT_NAPI_TX_ERR) {
> +                       /* Avoid scavenging before Tx engine turned off */
> +                       rhine_wait_bit_low(rp, ChipCmd, CmdTxOn);
> +                       if (ioread8(ioaddr + ChipCmd) & CmdTxOn)
> +                               netif_warn(rp, tx_err, dev, "Tx still on\n");
> +               }
>
> -       work_done = rhine_rx(dev, budget);
> +               rhine_tx(dev);
> +
> +               if (status & RHINE_EVENT_NAPI_TX_ERR)
> +                       rhine_tx_err(rp, status);
> +       }
> +
> +       if (status & IntrStatsMax) {
> +               spin_lock(&rp->lock);
> +               rhine_update_rx_crc_and_missed_errord(rp);
> +               spin_unlock(&rp->lock);
> +       }
> +
> +       if (status & RHINE_EVENT_SLOW) {
> +               enable_mask &= ~RHINE_EVENT_SLOW;
> +               schedule_work(&rp->slow_event_task);
> +       }
>
>        if (work_done < budget) {
>                napi_complete(napi);
> -
> -               iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
> -                         IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
> -                         IntrTxDone | IntrTxError | IntrTxUnderrun |
> -                         IntrPCIErr | IntrStatsMax | IntrLinkChange,
> -                         ioaddr + IntrEnable);
> +               iowrite16(enable_mask, ioaddr + IntrEnable);
> +               mmiowb();
>        }
>        return work_done;
>  }
> @@ -797,6 +937,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
>        rp->quirks = quirks;
>        rp->pioaddr = pioaddr;
>        rp->pdev = pdev;
> +       rp->msg_enable = netif_msg_init(debug, RHINE_MSG_DEFAULT);
>
>        rc = pci_request_regions(pdev, DRV_NAME);
>        if (rc)
> @@ -856,7 +997,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
>        dev->irq = pdev->irq;
>
>        spin_lock_init(&rp->lock);
> +       mutex_init(&rp->task_lock);
>        INIT_WORK(&rp->reset_task, rhine_reset_task);
> +       INIT_WORK(&rp->slow_event_task, rhine_slow_event_task);
>
>        rp->mii_if.dev = dev;
>        rp->mii_if.mdio_read = mdio_read;
> @@ -916,8 +1059,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
>                }
>        }
>        rp->mii_if.phy_id = phy_id;
> -       if (debug > 1 && avoid_D3)
> -               netdev_info(dev, "No D3 power state at shutdown\n");
> +       if (avoid_D3)
> +               netif_info(rp, probe, dev, "No D3 power state at shutdown\n");
>
>        return 0;
>
> @@ -1093,7 +1236,7 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
>        struct rhine_private *rp = netdev_priv(dev);
>        void __iomem *ioaddr = rp->base;
>
> -       mii_check_media(&rp->mii_if, debug, init_media);
> +       mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media);
>
>        if (rp->mii_if.full_duplex)
>            iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex,
> @@ -1101,24 +1244,26 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
>        else
>            iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex,
>                   ioaddr + ChipCmd1);
> -       if (debug > 1)
> -               netdev_info(dev, "force_media %d, carrier %d\n",
> -                           rp->mii_if.force_media, netif_carrier_ok(dev));
> +
> +       netif_info(rp, link, dev, "force_media %d, carrier %d\n",
> +                  rp->mii_if.force_media, netif_carrier_ok(dev));
>  }
>
>  /* Called after status of force_media possibly changed */
>  static void rhine_set_carrier(struct mii_if_info *mii)
>  {
> +       struct net_device *dev = mii->dev;
> +       struct rhine_private *rp = netdev_priv(dev);
> +
>        if (mii->force_media) {
>                /* autoneg is off: Link is always assumed to be up */
> -               if (!netif_carrier_ok(mii->dev))
> -                       netif_carrier_on(mii->dev);
> -       }
> -       else    /* Let MMI library update carrier status */
> -               rhine_check_media(mii->dev, 0);
> -       if (debug > 1)
> -               netdev_info(mii->dev, "force_media %d, carrier %d\n",
> -                           mii->force_media, netif_carrier_ok(mii->dev));
> +               if (!netif_carrier_ok(dev))
> +                       netif_carrier_on(dev);
> +       } else  /* Let MMI library update carrier status */
> +               rhine_check_media(dev, 0);
> +
> +       netif_info(rp, link, dev, "force_media %d, carrier %d\n",
> +                  mii->force_media, netif_carrier_ok(dev));
>  }
>
>  /**
> @@ -1266,10 +1411,10 @@ static int rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
>  {
>        struct rhine_private *rp = netdev_priv(dev);
>
> -       spin_lock_irq(&rp->lock);
> +       spin_lock_bh(&rp->lock);
>        set_bit(vid, rp->active_vlans);
>        rhine_update_vcam(dev);
> -       spin_unlock_irq(&rp->lock);
> +       spin_unlock_bh(&rp->lock);
>        return 0;
>  }
>
> @@ -1277,10 +1422,10 @@ static int rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
>  {
>        struct rhine_private *rp = netdev_priv(dev);
>
> -       spin_lock_irq(&rp->lock);
> +       spin_lock_bh(&rp->lock);
>        clear_bit(vid, rp->active_vlans);
>        rhine_update_vcam(dev);
> -       spin_unlock_irq(&rp->lock);
> +       spin_unlock_bh(&rp->lock);
>        return 0;
>  }
>
> @@ -1310,12 +1455,7 @@ static void init_registers(struct net_device *dev)
>
>        napi_enable(&rp->napi);
>
> -       /* Enable interrupts by setting the interrupt mask. */
> -       iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
> -              IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
> -              IntrTxDone | IntrTxError | IntrTxUnderrun |
> -              IntrPCIErr | IntrStatsMax | IntrLinkChange,
> -              ioaddr + IntrEnable);
> +       iowrite16(RHINE_EVENT & 0xffff, ioaddr + IntrEnable);
>
>        iowrite16(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8),
>               ioaddr + ChipCmd);
> @@ -1323,23 +1463,27 @@ static void init_registers(struct net_device *dev)
>  }
>
>  /* Enable MII link status auto-polling (required for IntrLinkChange) */
> -static void rhine_enable_linkmon(void __iomem *ioaddr)
> +static void rhine_enable_linkmon(struct rhine_private *rp)
>  {
> +       void __iomem *ioaddr = rp->base;
> +
>        iowrite8(0, ioaddr + MIICmd);
>        iowrite8(MII_BMSR, ioaddr + MIIRegAddr);
>        iowrite8(0x80, ioaddr + MIICmd);
>
> -       RHINE_WAIT_FOR((ioread8(ioaddr + MIIRegAddr) & 0x20));
> +       rhine_wait_bit_high(rp, MIIRegAddr, 0x20);
>
>        iowrite8(MII_BMSR | 0x40, ioaddr + MIIRegAddr);
>  }
>
>  /* Disable MII link status auto-polling (required for MDIO access) */
> -static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
> +static void rhine_disable_linkmon(struct rhine_private *rp)
>  {
> +       void __iomem *ioaddr = rp->base;
> +
>        iowrite8(0, ioaddr + MIICmd);
>
> -       if (quirks & rqRhineI) {
> +       if (rp->quirks & rqRhineI) {
>                iowrite8(0x01, ioaddr + MIIRegAddr);    // MII_BMSR
>
>                /* Can be called from ISR. Evil. */
> @@ -1348,13 +1492,13 @@ static void rhine_disable_linkmon(void __iomem *ioaddr, u32 quirks)
>                /* 0x80 must be set immediately before turning it off */
>                iowrite8(0x80, ioaddr + MIICmd);
>
> -               RHINE_WAIT_FOR(ioread8(ioaddr + MIIRegAddr) & 0x20);
> +               rhine_wait_bit_high(rp, MIIRegAddr, 0x20);
>
>                /* Heh. Now clear 0x80 again. */
>                iowrite8(0, ioaddr + MIICmd);
>        }
>        else
> -               RHINE_WAIT_FOR(ioread8(ioaddr + MIIRegAddr) & 0x80);
> +               rhine_wait_bit_high(rp, MIIRegAddr, 0x80);
>  }
>
>  /* Read and write over the MII Management Data I/O (MDIO) interface. */
> @@ -1365,16 +1509,16 @@ static int mdio_read(struct net_device *dev, int phy_id, int regnum)
>        void __iomem *ioaddr = rp->base;
>        int result;
>
> -       rhine_disable_linkmon(ioaddr, rp->quirks);
> +       rhine_disable_linkmon(rp);
>
>        /* rhine_disable_linkmon already cleared MIICmd */
>        iowrite8(phy_id, ioaddr + MIIPhyAddr);
>        iowrite8(regnum, ioaddr + MIIRegAddr);
>        iowrite8(0x40, ioaddr + MIICmd);                /* Trigger read */
> -       RHINE_WAIT_FOR(!(ioread8(ioaddr + MIICmd) & 0x40));
> +       rhine_wait_bit_low(rp, MIICmd, 0x40);
>        result = ioread16(ioaddr + MIIData);
>
> -       rhine_enable_linkmon(ioaddr);
> +       rhine_enable_linkmon(rp);
>        return result;
>  }
>
> @@ -1383,16 +1527,33 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value
>        struct rhine_private *rp = netdev_priv(dev);
>        void __iomem *ioaddr = rp->base;
>
> -       rhine_disable_linkmon(ioaddr, rp->quirks);
> +       rhine_disable_linkmon(rp);
>
>        /* rhine_disable_linkmon already cleared MIICmd */
>        iowrite8(phy_id, ioaddr + MIIPhyAddr);
>        iowrite8(regnum, ioaddr + MIIRegAddr);
>        iowrite16(value, ioaddr + MIIData);
>        iowrite8(0x20, ioaddr + MIICmd);                /* Trigger write */
> -       RHINE_WAIT_FOR(!(ioread8(ioaddr + MIICmd) & 0x20));
> +       rhine_wait_bit_low(rp, MIICmd, 0x20);
>
> -       rhine_enable_linkmon(ioaddr);
> +       rhine_enable_linkmon(rp);
> +}
> +
> +static void rhine_task_disable(struct rhine_private *rp)
> +{
> +       mutex_lock(&rp->task_lock);
> +       rp->task_enable = false;
> +       mutex_unlock(&rp->task_lock);
> +
> +       cancel_work_sync(&rp->slow_event_task);
> +       cancel_work_sync(&rp->reset_task);
> +}
> +
> +static void rhine_task_enable(struct rhine_private *rp)
> +{
> +       mutex_lock(&rp->task_lock);
> +       rp->task_enable = true;
> +       mutex_unlock(&rp->task_lock);
>  }
>
>  static int rhine_open(struct net_device *dev)
> @@ -1406,8 +1567,7 @@ static int rhine_open(struct net_device *dev)
>        if (rc)
>                return rc;
>
> -       if (debug > 1)
> -               netdev_dbg(dev, "%s() irq %d\n", __func__, rp->pdev->irq);
> +       netif_dbg(rp, ifup, dev, "%s() irq %d\n", __func__, rp->pdev->irq);
>
>        rc = alloc_ring(dev);
>        if (rc) {
> @@ -1417,11 +1577,12 @@ static int rhine_open(struct net_device *dev)
>        alloc_rbufs(dev);
>        alloc_tbufs(dev);
>        rhine_chip_reset(dev);
> +       rhine_task_enable(rp);
>        init_registers(dev);
> -       if (debug > 2)
> -               netdev_dbg(dev, "%s() Done - status %04x MII status: %04x\n",
> -                          __func__, ioread16(ioaddr + ChipCmd),
> -                          mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
> +
> +       netif_dbg(rp, ifup, dev, "%s() Done - status %04x MII status: %04x\n",
> +                 __func__, ioread16(ioaddr + ChipCmd),
> +                 mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
>
>        netif_start_queue(dev);
>
> @@ -1434,11 +1595,12 @@ static void rhine_reset_task(struct work_struct *work)
>                                                reset_task);
>        struct net_device *dev = rp->dev;
>
> -       /* protect against concurrent rx interrupts */
> -       disable_irq(rp->pdev->irq);
> +       mutex_lock(&rp->task_lock);
>
> -       napi_disable(&rp->napi);
> +       if (!rp->task_enable)
> +               goto out_unlock;
>
> +       napi_disable(&rp->napi);
>        spin_lock_bh(&rp->lock);
>
>        /* clear all descriptors */
> @@ -1452,11 +1614,13 @@ static void rhine_reset_task(struct work_struct *work)
>        init_registers(dev);
>
>        spin_unlock_bh(&rp->lock);
> -       enable_irq(rp->pdev->irq);
>
>        dev->trans_start = jiffies; /* prevent tx timeout */
>        dev->stats.tx_errors++;
>        netif_wake_queue(dev);
> +
> +out_unlock:
> +       mutex_unlock(&rp->task_lock);
>  }
>
>  static void rhine_tx_timeout(struct net_device *dev)
> @@ -1477,7 +1641,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
>        struct rhine_private *rp = netdev_priv(dev);
>        void __iomem *ioaddr = rp->base;
>        unsigned entry;
> -       unsigned long flags;
>
>        /* Caution: the write order is important here, set the field
>           with the "ownership" bits last. */
> @@ -1529,7 +1692,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
>                rp->tx_ring[entry].tx_status = 0;
>
>        /* lock eth irq */
> -       spin_lock_irqsave(&rp->lock, flags);
>        wmb();
>        rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn);
>        wmb();
> @@ -1550,78 +1712,43 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
>        if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN)
>                netif_stop_queue(dev);
>
> -       spin_unlock_irqrestore(&rp->lock, flags);
> +       netif_dbg(rp, tx_queued, dev, "Transmit frame #%d queued in slot %d\n",
> +                 rp->cur_tx - 1, entry);
>
> -       if (debug > 4) {
> -               netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n",
> -                          rp->cur_tx-1, entry);
> -       }
>        return NETDEV_TX_OK;
>  }
>
> +static void rhine_irq_disable(struct rhine_private *rp)
> +{
> +       iowrite16(0x0000, rp->base + IntrEnable);
> +       mmiowb();
> +}
> +
>  /* The interrupt handler does all of the Rx thread work and cleans up
>    after the Tx thread. */
>  static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
>  {
>        struct net_device *dev = dev_instance;
>        struct rhine_private *rp = netdev_priv(dev);
> -       void __iomem *ioaddr = rp->base;
> -       u32 intr_status;
> -       int boguscnt = max_interrupt_work;
> +       u32 status;
>        int handled = 0;
>
> -       while ((intr_status = get_intr_status(dev))) {
> -               handled = 1;
> -
> -               /* Acknowledge all of the current interrupt sources ASAP. */
> -               if (intr_status & IntrTxDescRace)
> -                       iowrite8(0x08, ioaddr + IntrStatus2);
> -               iowrite16(intr_status & 0xffff, ioaddr + IntrStatus);
> -               IOSYNC;
> +       status = rhine_get_events(rp);
>
> -               if (debug > 4)
> -                       netdev_dbg(dev, "Interrupt, status %08x\n",
> -                                  intr_status);
> -
> -               if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
> -                                  IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) {
> -                       iowrite16(IntrTxAborted |
> -                                 IntrTxDone | IntrTxError | IntrTxUnderrun |
> -                                 IntrPCIErr | IntrStatsMax | IntrLinkChange,
> -                                 ioaddr + IntrEnable);
> -
> -                       napi_schedule(&rp->napi);
> -               }
> +       netif_dbg(rp, intr, dev, "Interrupt, status %08x\n", status);
>
> -               if (intr_status & (IntrTxErrSummary | IntrTxDone)) {
> -                       if (intr_status & IntrTxErrSummary) {
> -                               /* Avoid scavenging before Tx engine turned off */
> -                               RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn));
> -                               if (debug > 2 &&
> -                                   ioread8(ioaddr+ChipCmd) & CmdTxOn)
> -                                       netdev_warn(dev,
> -                                                   "%s: Tx engine still on\n",
> -                                                   __func__);
> -                       }
> -                       rhine_tx(dev);
> -               }
> +       if (status & RHINE_EVENT) {
> +               handled = 1;
>
> -               /* Abnormal error summary/uncommon events handlers. */
> -               if (intr_status & (IntrPCIErr | IntrLinkChange |
> -                                  IntrStatsMax | IntrTxError | IntrTxAborted |
> -                                  IntrTxUnderrun | IntrTxDescRace))
> -                       rhine_error(dev, intr_status);
> +               rhine_irq_disable(rp);
> +               napi_schedule(&rp->napi);
> +       }
>
> -               if (--boguscnt < 0) {
> -                       netdev_warn(dev, "Too much work at interrupt, status=%#08x\n",
> -                                   intr_status);
> -                       break;
> -               }
> +       if (status & ~(IntrLinkChange | IntrStatsMax | RHINE_EVENT_NAPI)) {
> +               netif_err(rp, intr, dev, "Something Wicked happened! %08x\n",
> +                         status);
>        }
>
> -       if (debug > 3)
> -               netdev_dbg(dev, "exiting interrupt, status=%08x\n",
> -                          ioread16(ioaddr + IntrStatus));
>        return IRQ_RETVAL(handled);
>  }
>
> @@ -1632,20 +1759,16 @@ static void rhine_tx(struct net_device *dev)
>        struct rhine_private *rp = netdev_priv(dev);
>        int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE;
>
> -       spin_lock(&rp->lock);
> -
>        /* find and cleanup dirty tx descriptors */
>        while (rp->dirty_tx != rp->cur_tx) {
>                txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
> -               if (debug > 6)
> -                       netdev_dbg(dev, "Tx scavenge %d status %08x\n",
> -                                  entry, txstatus);
> +               netif_dbg(rp, tx_done, dev, "Tx scavenge %d status %08x\n",
> +                         entry, txstatus);
>                if (txstatus & DescOwn)
>                        break;
>                if (txstatus & 0x8000) {
> -                       if (debug > 1)
> -                               netdev_dbg(dev, "Transmit error, Tx status %08x\n",
> -                                          txstatus);
> +                       netif_dbg(rp, tx_done, dev,
> +                                 "Transmit error, Tx status %08x\n", txstatus);
>                        dev->stats.tx_errors++;
>                        if (txstatus & 0x0400)
>                                dev->stats.tx_carrier_errors++;
> @@ -1667,10 +1790,8 @@ static void rhine_tx(struct net_device *dev)
>                                dev->stats.collisions += (txstatus >> 3) & 0x0F;
>                        else
>                                dev->stats.collisions += txstatus & 0x0F;
> -                       if (debug > 6)
> -                               netdev_dbg(dev, "collisions: %1.1x:%1.1x\n",
> -                                          (txstatus >> 3) & 0xF,
> -                                          txstatus & 0xF);
> +                       netif_dbg(rp, tx_done, dev, "collisions: %1.1x:%1.1x\n",
> +                                 (txstatus >> 3) & 0xF, txstatus & 0xF);
>                        dev->stats.tx_bytes += rp->tx_skbuff[entry]->len;
>                        dev->stats.tx_packets++;
>                }
> @@ -1687,8 +1808,6 @@ static void rhine_tx(struct net_device *dev)
>        }
>        if ((rp->cur_tx - rp->dirty_tx) < TX_QUEUE_LEN - 4)
>                netif_wake_queue(dev);
> -
> -       spin_unlock(&rp->lock);
>  }
>
>  /**
> @@ -1713,11 +1832,8 @@ static int rhine_rx(struct net_device *dev, int limit)
>        int count;
>        int entry = rp->cur_rx % RX_RING_SIZE;
>
> -       if (debug > 4) {
> -               netdev_dbg(dev, "%s(), entry %d status %08x\n",
> -                          __func__, entry,
> -                          le32_to_cpu(rp->rx_head_desc->rx_status));
> -       }
> +       netif_dbg(rp, rx_status, dev, "%s(), entry %d status %08x\n", __func__,
> +                 entry, le32_to_cpu(rp->rx_head_desc->rx_status));
>
>        /* If EOP is set on the next entry, it's a new packet. Send it up. */
>        for (count = 0; count < limit; ++count) {
> @@ -1729,9 +1845,8 @@ static int rhine_rx(struct net_device *dev, int limit)
>                if (desc_status & DescOwn)
>                        break;
>
> -               if (debug > 4)
> -                       netdev_dbg(dev, "%s() status is %08x\n",
> -                                  __func__, desc_status);
> +               netif_dbg(rp, rx_status, dev, "%s() status %08x\n", __func__,
> +                         desc_status);
>
>                if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
>                        if ((desc_status & RxWholePkt) != RxWholePkt) {
> @@ -1747,9 +1862,9 @@ static int rhine_rx(struct net_device *dev, int limit)
>                                dev->stats.rx_length_errors++;
>                        } else if (desc_status & RxErr) {
>                                /* There was a error. */
> -                               if (debug > 2)
> -                                       netdev_dbg(dev, "%s() Rx error was %08x\n",
> -                                                  __func__, desc_status);
> +                               netif_dbg(rp, rx_err, dev,
> +                                         "%s() Rx error %08x\n", __func__,
> +                                         desc_status);
>                                dev->stats.rx_errors++;
>                                if (desc_status & 0x0030)
>                                        dev->stats.rx_length_errors++;
> @@ -1839,19 +1954,6 @@ static int rhine_rx(struct net_device *dev, int limit)
>        return count;
>  }
>
> -/*
> - * Clears the "tally counters" for CRC errors and missed frames(?).
> - * It has been reported that some chips need a write of 0 to clear
> - * these, for others the counters are set to 1 when written to and
> - * instead cleared when read. So we clear them both ways ...
> - */
> -static inline void clear_tally_counters(void __iomem *ioaddr)
> -{
> -       iowrite32(0, ioaddr + RxMissed);
> -       ioread16(ioaddr + RxCRCErrs);
> -       ioread16(ioaddr + RxMissed);
> -}
> -
>  static void rhine_restart_tx(struct net_device *dev) {
>        struct rhine_private *rp = netdev_priv(dev);
>        void __iomem *ioaddr = rp->base;
> @@ -1862,7 +1964,7 @@ static void rhine_restart_tx(struct net_device *dev) {
>         * If new errors occurred, we need to sort them out before doing Tx.
>         * In that case the ISR will be back here RSN anyway.
>         */
> -       intr_status = get_intr_status(dev);
> +       intr_status = rhine_get_events(rp);
>
>        if ((intr_status & IntrTxErrSummary) == 0) {
>
> @@ -1883,79 +1985,50 @@ static void rhine_restart_tx(struct net_device *dev) {
>        }
>        else {
>                /* This should never happen */
> -               if (debug > 1)
> -                       netdev_warn(dev, "%s() Another error occurred %08x\n",
> -                                  __func__, intr_status);
> +               netif_warn(rp, tx_err, dev, "another error occurred %08x\n",
> +                          intr_status);
>        }
>
>  }
>
> -static void rhine_error(struct net_device *dev, int intr_status)
> +static void rhine_slow_event_task(struct work_struct *work)
>  {
> -       struct rhine_private *rp = netdev_priv(dev);
> -       void __iomem *ioaddr = rp->base;
> +       struct rhine_private *rp =
> +               container_of(work, struct rhine_private, slow_event_task);
> +       struct net_device *dev = rp->dev;
> +       u32 intr_status;
>
> -       spin_lock(&rp->lock);
> +       mutex_lock(&rp->task_lock);
> +
> +       if (!rp->task_enable)
> +               goto out_unlock;
> +
> +       intr_status = rhine_get_events(rp);
> +       rhine_ack_events(rp, intr_status & RHINE_EVENT_SLOW);
>
>        if (intr_status & IntrLinkChange)
>                rhine_check_media(dev, 0);
> -       if (intr_status & IntrStatsMax) {
> -               dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
> -               dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
> -               clear_tally_counters(ioaddr);
> -       }
> -       if (intr_status & IntrTxAborted) {
> -               if (debug > 1)
> -                       netdev_info(dev, "Abort %08x, frame dropped\n",
> -                                   intr_status);
> -       }
> -       if (intr_status & IntrTxUnderrun) {
> -               if (rp->tx_thresh < 0xE0)
> -                       BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
> -               if (debug > 1)
> -                       netdev_info(dev, "Transmitter underrun, Tx threshold now %02x\n",
> -                                   rp->tx_thresh);
> -       }
> -       if (intr_status & IntrTxDescRace) {
> -               if (debug > 2)
> -                       netdev_info(dev, "Tx descriptor write-back race\n");
> -       }
> -       if ((intr_status & IntrTxError) &&
> -           (intr_status & (IntrTxAborted |
> -            IntrTxUnderrun | IntrTxDescRace)) == 0) {
> -               if (rp->tx_thresh < 0xE0) {
> -                       BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
> -               }
> -               if (debug > 1)
> -                       netdev_info(dev, "Unspecified error. Tx threshold now %02x\n",
> -                                   rp->tx_thresh);
> -       }
> -       if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace |
> -                          IntrTxError))
> -               rhine_restart_tx(dev);
> -
> -       if (intr_status & ~(IntrLinkChange | IntrStatsMax | IntrTxUnderrun |
> -                           IntrTxError | IntrTxAborted | IntrNormalSummary |
> -                           IntrTxDescRace)) {
> -               if (debug > 1)
> -                       netdev_err(dev, "Something Wicked happened! %08x\n",
> -                                  intr_status);
> -       }
>
> -       spin_unlock(&rp->lock);
> +       if (intr_status & IntrPCIErr)
> +               netif_warn(rp, hw, dev, "PCI error\n");
> +
> +       napi_disable(&rp->napi);
> +       rhine_irq_disable(rp);
> +       /* Slow and safe. Consider __napi_schedule as a replacement ? */
> +       napi_enable(&rp->napi);
> +       napi_schedule(&rp->napi);
> +
> +out_unlock:
> +       mutex_unlock(&rp->task_lock);
>  }
>
>  static struct net_device_stats *rhine_get_stats(struct net_device *dev)
>  {
>        struct rhine_private *rp = netdev_priv(dev);
> -       void __iomem *ioaddr = rp->base;
> -       unsigned long flags;
>
> -       spin_lock_irqsave(&rp->lock, flags);
> -       dev->stats.rx_crc_errors += ioread16(ioaddr + RxCRCErrs);
> -       dev->stats.rx_missed_errors += ioread16(ioaddr + RxMissed);
> -       clear_tally_counters(ioaddr);
> -       spin_unlock_irqrestore(&rp->lock, flags);
> +       spin_lock_bh(&rp->lock);
> +       rhine_update_rx_crc_and_missed_errord(rp);
> +       spin_unlock_bh(&rp->lock);
>
>        return &dev->stats;
>  }
> @@ -2022,9 +2095,9 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
>        struct rhine_private *rp = netdev_priv(dev);
>        int rc;
>
> -       spin_lock_irq(&rp->lock);
> +       mutex_lock(&rp->task_lock);
>        rc = mii_ethtool_gset(&rp->mii_if, cmd);
> -       spin_unlock_irq(&rp->lock);
> +       mutex_unlock(&rp->task_lock);
>
>        return rc;
>  }
> @@ -2034,10 +2107,10 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
>        struct rhine_private *rp = netdev_priv(dev);
>        int rc;
>
> -       spin_lock_irq(&rp->lock);
> +       mutex_lock(&rp->task_lock);
>        rc = mii_ethtool_sset(&rp->mii_if, cmd);
> -       spin_unlock_irq(&rp->lock);
>        rhine_set_carrier(&rp->mii_if);
> +       mutex_unlock(&rp->task_lock);
>
>        return rc;
>  }
> @@ -2058,12 +2131,16 @@ static u32 netdev_get_link(struct net_device *dev)
>
>  static u32 netdev_get_msglevel(struct net_device *dev)
>  {
> -       return debug;
> +       struct rhine_private *rp = netdev_priv(dev);
> +
> +       return rp->msg_enable;
>  }
>
>  static void netdev_set_msglevel(struct net_device *dev, u32 value)
>  {
> -       debug = value;
> +       struct rhine_private *rp = netdev_priv(dev);
> +
> +       rp->msg_enable = value;
>  }
>
>  static void rhine_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
> @@ -2119,10 +2196,10 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
>        if (!netif_running(dev))
>                return -EINVAL;
>
> -       spin_lock_irq(&rp->lock);
> +       mutex_lock(&rp->task_lock);
>        rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL);
> -       spin_unlock_irq(&rp->lock);
>        rhine_set_carrier(&rp->mii_if);
> +       mutex_unlock(&rp->task_lock);
>
>        return rc;
>  }
> @@ -2132,27 +2209,21 @@ static int rhine_close(struct net_device *dev)
>        struct rhine_private *rp = netdev_priv(dev);
>        void __iomem *ioaddr = rp->base;
>
> +       rhine_task_disable(rp);
>        napi_disable(&rp->napi);
> -       cancel_work_sync(&rp->reset_task);
>        netif_stop_queue(dev);
>
> -       spin_lock_irq(&rp->lock);
> -
> -       if (debug > 1)
> -               netdev_dbg(dev, "Shutting down ethercard, status was %04x\n",
> -                          ioread16(ioaddr + ChipCmd));
> +       netif_dbg(rp, ifdown, dev, "Shutting down ethercard, status was %04x\n",
> +                 ioread16(ioaddr + ChipCmd));
>
>        /* Switch to loopback mode to avoid hardware races. */
>        iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig);
>
> -       /* Disable interrupts by clearing the interrupt mask. */
> -       iowrite16(0x0000, ioaddr + IntrEnable);
> +       rhine_irq_disable(rp);
>
>        /* Stop the chip's Tx and Rx processes. */
>        iowrite16(CmdStop, ioaddr + ChipCmd);
>
> -       spin_unlock_irq(&rp->lock);
> -
>        free_irq(rp->pdev->irq, dev);
>        free_rbufs(dev);
>        free_tbufs(dev);
> @@ -2192,6 +2263,8 @@ static void rhine_shutdown (struct pci_dev *pdev)
>        if (rp->quirks & rq6patterns)
>                iowrite8(0x04, ioaddr + WOLcgClr);
>
> +       spin_lock(&rp->lock);
> +
>        if (rp->wolopts & WAKE_MAGIC) {
>                iowrite8(WOLmagic, ioaddr + WOLcrSet);
>                /*
> @@ -2216,58 +2289,46 @@ static void rhine_shutdown (struct pci_dev *pdev)
>                iowrite8(ioread8(ioaddr + StickyHW) | 0x04, ioaddr + StickyHW);
>        }
>
> -       /* Hit power state D3 (sleep) */
> -       if (!avoid_D3)
> -               iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
> +       spin_unlock(&rp->lock);
>
> -       /* TODO: Check use of pci_enable_wake() */
> +       if (system_state == SYSTEM_POWER_OFF && !avoid_D3) {
> +               iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
>
> +               pci_wake_from_d3(pdev, true);
> +               pci_set_power_state(pdev, PCI_D3hot);
> +       }
>  }
>
> -#ifdef CONFIG_PM
> -static int rhine_suspend(struct pci_dev *pdev, pm_message_t state)
> +#ifdef CONFIG_PM_SLEEP
> +static int rhine_suspend(struct device *device)
>  {
> +       struct pci_dev *pdev = to_pci_dev(device);
>        struct net_device *dev = pci_get_drvdata(pdev);
>        struct rhine_private *rp = netdev_priv(dev);
> -       unsigned long flags;
>
>        if (!netif_running(dev))
>                return 0;
>
> +       rhine_task_disable(rp);
> +       rhine_irq_disable(rp);
>        napi_disable(&rp->napi);
>
>        netif_device_detach(dev);
> -       pci_save_state(pdev);
>
> -       spin_lock_irqsave(&rp->lock, flags);
>        rhine_shutdown(pdev);
> -       spin_unlock_irqrestore(&rp->lock, flags);
>
> -       free_irq(dev->irq, dev);
>        return 0;
>  }
>
> -static int rhine_resume(struct pci_dev *pdev)
> +static int rhine_resume(struct device *device)
>  {
> +       struct pci_dev *pdev = to_pci_dev(device);
>        struct net_device *dev = pci_get_drvdata(pdev);
>        struct rhine_private *rp = netdev_priv(dev);
> -       unsigned long flags;
> -       int ret;
>
>        if (!netif_running(dev))
>                return 0;
>
> -       if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
> -               netdev_err(dev, "request_irq failed\n");
> -
> -       ret = pci_set_power_state(pdev, PCI_D0);
> -       if (debug > 1)
> -               netdev_info(dev, "Entering power state D0 %s (%d)\n",
> -                           ret ? "failed" : "succeeded", ret);
> -
> -       pci_restore_state(pdev);
> -
> -       spin_lock_irqsave(&rp->lock, flags);
>  #ifdef USE_MMIO
>        enable_mmio(rp->pioaddr, rp->quirks);
>  #endif
> @@ -2276,25 +2337,32 @@ static int rhine_resume(struct pci_dev *pdev)
>        free_rbufs(dev);
>        alloc_tbufs(dev);
>        alloc_rbufs(dev);
> +       rhine_task_enable(rp);
> +       spin_lock_bh(&rp->lock);
>        init_registers(dev);
> -       spin_unlock_irqrestore(&rp->lock, flags);
> +       spin_unlock_bh(&rp->lock);
>
>        netif_device_attach(dev);
>
>        return 0;
>  }
> -#endif /* CONFIG_PM */
> +
> +static SIMPLE_DEV_PM_OPS(rhine_pm_ops, rhine_suspend, rhine_resume);
> +#define RHINE_PM_OPS   (&rhine_pm_ops)
> +
> +#else
> +
> +#define RHINE_PM_OPS   NULL
> +
> +#endif /* !CONFIG_PM_SLEEP */
>
>  static struct pci_driver rhine_driver = {
>        .name           = DRV_NAME,
>        .id_table       = rhine_pci_tbl,
>        .probe          = rhine_init_one,
>        .remove         = __devexit_p(rhine_remove_one),
> -#ifdef CONFIG_PM
> -       .suspend        = rhine_suspend,
> -       .resume         = rhine_resume,
> -#endif /* CONFIG_PM */
> -       .shutdown =     rhine_shutdown,
> +       .shutdown       = rhine_shutdown,
> +       .driver.pm      = RHINE_PM_OPS,
>  };
>
>  static struct dmi_system_id __initdata rhine_dmi_table[] = {
> --
> Ueimor
>
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ