diff options
| author | Jeff Garzik <jgarzik@redhat.com> | 2004-04-13 06:54:27 -0400 |
|---|---|---|
| committer | Jeff Garzik <jgarzik@redhat.com> | 2004-04-13 06:54:27 -0400 |
| commit | e0d3e322be607f2196415b42155eab21bc78e040 (patch) | |
| tree | 82d3252872c0d2b9f67d82da5ea29200647f5c1e | |
| parent | 4d72de2391fe2c02ef972bffc8829b03af38699e (diff) | |
| parent | 93eb7437d1e71ea9b22f5d67c3fc8dbc628f9005 (diff) | |
Merge redhat.com:/spare/repo/netdev-2.6/8139cp
into redhat.com:/spare/repo/net-drivers-2.6
| -rw-r--r-- | drivers/net/8139cp.c | 229 |
1 files changed, 127 insertions, 102 deletions
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 9bfeed893229..da983661221f 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1,6 +1,6 @@ /* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */ /* - Copyright 2001,2002 Jeff Garzik <jgarzik@pobox.com> + Copyright 2001-2004 Jeff Garzik <jgarzik@pobox.com> Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c] Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c] @@ -48,8 +48,8 @@ */ #define DRV_NAME "8139cp" -#define DRV_VERSION "1.1" -#define DRV_RELDATE "Aug 30, 2003" +#define DRV_VERSION "1.2" +#define DRV_RELDATE "Mar 22, 2004" #include <linux/config.h> @@ -69,6 +69,7 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/udp.h> +#include <linux/cache.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -334,36 +335,36 @@ struct cp_extra_stats { }; struct cp_private { - unsigned tx_head; - unsigned tx_tail; - unsigned rx_tail; - void *regs; struct net_device *dev; spinlock_t lock; + u32 msg_enable; + + struct pci_dev *pdev; + u32 rx_config; + u16 cpcmd; + + struct net_device_stats net_stats; + struct cp_extra_stats cp_stats; + struct cp_dma_stats *nic_stats; + dma_addr_t nic_stats_dma; + unsigned rx_tail ____cacheline_aligned; struct cp_desc *rx_ring; - struct cp_desc *tx_ring; - struct ring_info tx_skb[CP_TX_RING_SIZE]; struct ring_info rx_skb[CP_RX_RING_SIZE]; unsigned rx_buf_sz; + + unsigned tx_head ____cacheline_aligned; + unsigned tx_tail; + + struct cp_desc *tx_ring; + struct ring_info tx_skb[CP_TX_RING_SIZE]; dma_addr_t ring_dma; #if CP_VLAN_TAG_USED struct vlan_group *vlgrp; #endif - u32 msg_enable; - - struct net_device_stats net_stats; - struct cp_extra_stats cp_stats; - struct cp_dma_stats *nic_stats; - dma_addr_t nic_stats_dma; - - struct pci_dev *pdev; - u32 rx_config; - u16 cpcmd; - unsigned int wol_enabled : 1; /* Is Wake-on-LAN enabled? */ u32 power_state[16]; @@ -424,25 +425,27 @@ static struct { #if CP_VLAN_TAG_USED static void cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); + unsigned long flags; - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, flags); cp->vlgrp = grp; cp->cpcmd |= RxVlanOn; cpw16(CpCmd, cp->cpcmd); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); } static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); + unsigned long flags; - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, flags); cp->cpcmd &= ~RxVlanOn; cpw16(CpCmd, cp->cpcmd); if (cp->vlgrp) cp->vlgrp->vlan_devices[vid] = NULL; - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); } #endif /* CP_VLAN_TAG_USED */ @@ -510,7 +513,7 @@ static inline unsigned int cp_rx_csum_ok (u32 status) static int cp_rx_poll (struct net_device *dev, int *budget) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); unsigned rx_tail = cp->rx_tail; unsigned rx_work = dev->quota; unsigned rx; @@ -630,9 +633,13 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = dev_instance; - struct cp_private *cp = dev->priv; + struct cp_private *cp; u16 status; + if (unlikely(dev == NULL)) + return IRQ_NONE; + cp = netdev_priv(dev); + status = cpr16(IntrStatus); if (!status || (status == 0xFFFF)) return IRQ_NONE; @@ -648,20 +655,23 @@ cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /* close possible race's with dev_close */ if (unlikely(!netif_running(dev))) { cpw16(IntrMask, 0); - goto out; + spin_unlock(&cp->lock); + return IRQ_HANDLED; } - if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) { + if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) if (netif_rx_schedule_prep(dev)) { cpw16_f(IntrMask, cp_norx_intr_mask); __netif_rx_schedule(dev); } - } + if (status & (TxOK | TxErr | TxEmpty | SWInt)) cp_tx(cp); if (status & LinkChg) mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE); + spin_unlock(&cp->lock); + if (status & PciErr) { u16 pci_status; @@ -672,8 +682,7 @@ cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /* TODO: reset hardware */ } -out: - spin_unlock(&cp->lock); + return IRQ_HANDLED; } @@ -736,7 +745,7 @@ static void cp_tx (struct cp_private *cp) static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); unsigned entry; u32 eor; #if CP_VLAN_TAG_USED @@ -894,7 +903,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev) static void __cp_set_rx_mode (struct net_device *dev) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); u32 mc_filter[2]; /* Multicast hash filter */ int i, rx_mode; u32 tmp; @@ -939,7 +948,7 @@ static void __cp_set_rx_mode (struct net_device *dev) static void cp_set_rx_mode (struct net_device *dev) { unsigned long flags; - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); spin_lock_irqsave (&cp->lock, flags); __cp_set_rx_mode(dev); @@ -955,35 +964,28 @@ static void __cp_get_stats(struct cp_private *cp) static struct net_device_stats *cp_get_stats(struct net_device *dev) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); + unsigned long flags; /* The chip only need report frame silently dropped. */ - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, flags); if (netif_running(dev) && netif_device_present(dev)) __cp_get_stats(cp); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); return &cp->net_stats; } static void cp_stop_hw (struct cp_private *cp) { - struct net_device *dev = cp->dev; - cpw16(IntrStatus, ~(cpr16(IntrStatus))); cpw16_f(IntrMask, 0); cpw8(Cmd, 0); cpw16_f(CpCmd, 0); - cpw16(IntrStatus, ~(cpr16(IntrStatus))); - synchronize_irq(dev->irq); - udelay(10); + cpw16_f(IntrStatus, ~(cpr16(IntrStatus))); cp->rx_tail = 0; cp->tx_head = cp->tx_tail = 0; - - (void) dev; /* avoid compiler warning when synchronize_irq() - * disappears during !CONFIG_SMP - */ } static void cp_reset_hw (struct cp_private *cp) @@ -1012,6 +1014,7 @@ static inline void cp_start_hw (struct cp_private *cp) static void cp_init_hw (struct cp_private *cp) { struct net_device *dev = cp->dev; + dma_addr_t ring_dma; cp_reset_hw(cp); @@ -1037,10 +1040,13 @@ static void cp_init_hw (struct cp_private *cp) cpw32_f(HiTxRingAddr, 0); cpw32_f(HiTxRingAddr + 4, 0); - cpw32_f(RxRingAddr, cp->ring_dma); - cpw32_f(RxRingAddr + 4, 0); /* FIXME: 64-bit PCI */ - cpw32_f(TxRingAddr, cp->ring_dma + (sizeof(struct cp_desc) * CP_RX_RING_SIZE)); - cpw32_f(TxRingAddr + 4, 0); /* FIXME: 64-bit PCI */ + ring_dma = cp->ring_dma; + cpw32_f(RxRingAddr, ring_dma & 0xffffffff); + cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); + + ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; + cpw32_f(TxRingAddr, ring_dma & 0xffffffff); + cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); cpw16(MultiIntr, 0); @@ -1154,7 +1160,7 @@ static void cp_free_rings (struct cp_private *cp) static int cp_open (struct net_device *dev) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); int rc; if (netif_msg_ifup(cp)) @@ -1184,19 +1190,24 @@ err_out_hw: static int cp_close (struct net_device *dev) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); + unsigned long flags; if (netif_msg_ifdown(cp)) printk(KERN_DEBUG "%s: disabling interface\n", dev->name); + spin_lock_irqsave(&cp->lock, flags); + netif_stop_queue(dev); netif_carrier_off(dev); - spin_lock_irq(&cp->lock); cp_stop_hw(cp); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); + + synchronize_irq(dev->irq); free_irq(dev->irq, dev); + cp_free_rings(cp); return 0; } @@ -1204,8 +1215,9 @@ static int cp_close (struct net_device *dev) #ifdef BROKEN static int cp_change_mtu(struct net_device *dev, int new_mtu) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); int rc; + unsigned long flags; /* check for invalid MTU, according to hardware limits */ if (new_mtu < CP_MIN_MTU || new_mtu > CP_MAX_MTU) @@ -1218,7 +1230,7 @@ static int cp_change_mtu(struct net_device *dev, int new_mtu) return 0; } - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, flags); cp_stop_hw(cp); /* stop h/w and free rings */ cp_clean_rings(cp); @@ -1229,7 +1241,7 @@ static int cp_change_mtu(struct net_device *dev, int new_mtu) rc = cp_init_rings(cp); /* realloc and restart h/w */ cp_start_hw(cp); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); return rc; } @@ -1248,7 +1260,7 @@ static char mii_2_8139_map[8] = { static int mdio_read(struct net_device *dev, int phy_id, int location) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); return location < 8 && mii_2_8139_map[location] ? readw(cp->regs + mii_2_8139_map[location]) : 0; @@ -1258,7 +1270,7 @@ 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) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); if (location == 0) { cpw8(Cfg9346, Cfg9346_Unlock); @@ -1326,7 +1338,7 @@ static void netdev_get_wol (struct cp_private *cp, static void cp_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); strcpy (info->driver, DRV_NAME); strcpy (info->version, DRV_VERSION); @@ -1345,55 +1357,57 @@ static int cp_get_stats_count (struct net_device *dev) static int cp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); int rc; + unsigned long flags; - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, flags); rc = mii_ethtool_gset(&cp->mii_if, cmd); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); return rc; } static int cp_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); int rc; + unsigned long flags; - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, flags); rc = mii_ethtool_sset(&cp->mii_if, cmd); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); return rc; } static int cp_nway_reset(struct net_device *dev) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); return mii_nway_restart(&cp->mii_if); } static u32 cp_get_msglevel(struct net_device *dev) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); return cp->msg_enable; } static void cp_set_msglevel(struct net_device *dev, u32 value) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); cp->msg_enable = value; } static u32 cp_get_rx_csum(struct net_device *dev) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); return (cpr16(CpCmd) & RxChkSum) ? 1 : 0; } static int cp_set_rx_csum(struct net_device *dev, u32 data) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); u16 cmd = cp->cpcmd, newcmd; newcmd = cmd; @@ -1404,10 +1418,12 @@ static int cp_set_rx_csum(struct net_device *dev, u32 data) newcmd &= ~RxChkSum; if (newcmd != cmd) { - spin_lock_irq(&cp->lock); + unsigned long flags; + + spin_lock_irqsave(&cp->lock, flags); cp->cpcmd = newcmd; cpw16_f(CpCmd, newcmd); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); } return 0; @@ -1416,35 +1432,38 @@ static int cp_set_rx_csum(struct net_device *dev, u32 data) static void cp_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); + unsigned long flags; if (regs->len < CP_REGS_SIZE) return /* -EINVAL */; regs->version = CP_REGS_VER; - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, flags); memcpy_fromio(p, cp->regs, CP_REGS_SIZE); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); } static void cp_get_wol (struct net_device *dev, struct ethtool_wolinfo *wol) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); + unsigned long flags; - spin_lock_irq (&cp->lock); + spin_lock_irqsave (&cp->lock, flags); netdev_get_wol (cp, wol); - spin_unlock_irq (&cp->lock); + spin_unlock_irqrestore (&cp->lock, flags); } static int cp_set_wol (struct net_device *dev, struct ethtool_wolinfo *wol) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); + unsigned long flags; int rc; - spin_lock_irq (&cp->lock); + spin_lock_irqsave (&cp->lock, flags); rc = netdev_set_wol (cp, wol); - spin_unlock_irq (&cp->lock); + spin_unlock_irqrestore (&cp->lock, flags); return rc; } @@ -1464,13 +1483,13 @@ static void cp_get_strings (struct net_device *dev, u32 stringset, u8 *buf) static void cp_get_ethtool_stats (struct net_device *dev, struct ethtool_stats *estats, u64 *tmp_stats) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); unsigned int work = 100; int i; /* begin NIC statistics dump */ - cpw32(StatsAddr + 4, 0); /* FIXME: 64-bit PCI */ - cpw32(StatsAddr, cp->nic_stats_dma | DumpStats); + cpw32(StatsAddr + 4, (cp->nic_stats_dma >> 16) >> 16); + cpw32(StatsAddr, (cp->nic_stats_dma & 0xffffffff) | DumpStats); cpr32(StatsAddr); while (work-- > 0) { @@ -1526,16 +1545,17 @@ static struct ethtool_ops cp_ethtool_ops = { static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &rq->ifr_data; int rc; + unsigned long flags; if (!netif_running(dev)) return -EINVAL; - spin_lock_irq(&cp->lock); + spin_lock_irqsave(&cp->lock, flags); rc = generic_mii_ioctl(&cp->mii_if, mii, cmd, NULL); - spin_unlock_irq(&cp->lock); + spin_unlock_irqrestore(&cp->lock, flags); return rc; } @@ -1639,7 +1659,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); - cp = dev->priv; + cp = netdev_priv(dev); cp->pdev = pdev; cp->dev = dev; cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug); @@ -1664,12 +1684,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out_mwi; - if (pdev->irq < 2) { - rc = -EIO; - printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n", - pdev->irq, pci_name(pdev)); - goto err_out_res; - } pciaddr = pci_resource_start(pdev, 1); if (!pciaddr) { rc = -EIO; @@ -1686,22 +1700,30 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) /* Configure DMA attributes. */ if ((sizeof(dma_addr_t) > 32) && + !pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL) && !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { pci_using_dac = 1; } else { + pci_using_dac = 0; + rc = pci_set_dma_mask(pdev, 0xffffffffULL); if (rc) { printk(KERN_ERR PFX "No usable DMA configuration, " "aborting.\n"); goto err_out_res; } - pci_using_dac = 0; + rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL); + if (rc) { + printk(KERN_ERR PFX "No usable consistent DMA configuration, " + "aborting.\n"); + goto err_out_res; + } } cp->cpcmd = (pci_using_dac ? PCIDAC : 0) | PCIMulRW | RxChkSum | CpRxOn | CpTxOn; - regs = ioremap_nocache(pciaddr, CP_REGS_SIZE); + regs = ioremap(pciaddr, CP_REGS_SIZE); if (!regs) { rc = -EIO; printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n", @@ -1742,6 +1764,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) dev->vlan_rx_kill_vid = cp_vlan_rx_kill_vid; #endif + if (pci_using_dac) + dev->features |= NETIF_F_HIGHDMA; + dev->irq = pdev->irq; rc = register_netdev(dev); @@ -1783,7 +1808,7 @@ err_out_free: static void cp_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct cp_private *cp = dev->priv; + struct cp_private *cp = netdev_priv(dev); if (!dev) BUG(); @@ -1805,7 +1830,7 @@ static int cp_suspend (struct pci_dev *pdev, u32 state) unsigned long flags; dev = pci_get_drvdata (pdev); - cp = dev->priv; + cp = netdev_priv(dev); if (!dev || !netif_running (dev)) return 0; @@ -1834,7 +1859,7 @@ static int cp_resume (struct pci_dev *pdev) struct cp_private *cp; dev = pci_get_drvdata (pdev); - cp = dev->priv; + cp = netdev_priv(dev); netif_device_attach (dev); |
