X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fsundance.c;h=f860ea150395871357639e4f457834fbf67408c1;hb=3e44017b589f001941723dfdfede2ca6284dddce;hp=5de0554fd7c67e7503d75d150bed0dc73348c553;hpb=b06c093ed2dc968b3c140dafa55fa6c7b72169e5;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 5de0554..f860ea1 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -16,86 +16,15 @@ Support and updates available at http://www.scyld.com/network/sundance.html - - - Version LK1.01a (jgarzik): - - Replace some MII-related magic numbers with constants - - Version LK1.02 (D-Link): - - Add new board to PCI ID list - - Fix multicast bug - - Version LK1.03 (D-Link): - - New Rx scheme, reduce Rx congestion - - Option to disable flow control - - Version LK1.04 (D-Link): - - Tx timeout recovery - - More support for ethtool. - - Version LK1.04a: - - Remove unused/constant members from struct pci_id_info - (which then allows removal of 'drv_flags' from private struct) - (jgarzik) - - If no phy is found, fail to load that board (jgarzik) - - Always start phy id scan at id 1 to avoid problems (Donald Becker) - - Autodetect where mii_preable_required is needed, - default to not needed. (Donald Becker) - - Version LK1.04b: - - Remove mii_preamble_required module parameter (Donald Becker) - - Add per-interface mii_preamble_required (setting is autodetected) - (Donald Becker) - - Remove unnecessary cast from void pointer (jgarzik) - - Re-align comments in private struct (jgarzik) - - Version LK1.04c (jgarzik): - - Support bitmapped message levels (NETIF_MSG_xxx), and the - two ethtool ioctls that get/set them - - Don't hand-code MII ethtool support, use standard API/lib - - Version LK1.04d: - - Merge from Donald Becker's sundance.c: (Jason Lunz) - * proper support for variably-sized MTUs - * default to PIO, to fix chip bugs - - Add missing unregister_netdev (Jason Lunz) - - Add CONFIG_SUNDANCE_MMIO config option (jgarzik) - - Better rx buf size calculation (Donald Becker) - - Version LK1.05 (D-Link): - - Fix DFE-580TX packet drop issue (for DL10050C) - - Fix reset_tx logic - - Version LK1.06 (D-Link): - - Fix crash while unloading driver - - Versin LK1.06b (D-Link): - - New tx scheme, adaptive tx_coalesce - - Version LK1.07 (D-Link): - - Fix tx bugs in big-endian machines - - Remove unused max_interrupt_work module parameter, the new - NAPI-like rx scheme doesn't need it. - - Remove redundancy get_stats() in intr_handler(), those - I/O access could affect performance in ARM-based system - - Add Linux software VLAN support - - Version LK1.08 (D-Link): - - Fix bug of custom mac address - (StationAddr register only accept word write) - - Version LK1.09 (D-Link): - - Fix the flowctrl bug. - - Set Pause bit in MII ANAR if flow control enabled. - - Version LK1.09a (ICPlus): - - Add the delay time in reading the contents of EEPROM + [link no longer provides useful info -jgarzik] + Archives of the mailing list are still available at + http://www.beowulf.org/pipermail/netdrivers/ */ #define DRV_NAME "sundance" -#define DRV_VERSION "1.01+LK1.09a" -#define DRV_RELDATE "10-Jul-2003" +#define DRV_VERSION "1.2" +#define DRV_RELDATE "11-Sep-2006" /* The user-configurable values. @@ -103,7 +32,7 @@ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). Typical is a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; +static const int multicast_filter_limit = 32; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. @@ -180,9 +109,8 @@ static char *media[MAX_UNITS]; #endif /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = -KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" -KERN_INFO " http://www.scyld.com/network/sundance.html\n"; +static char version[] = +KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n"; MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Sundance Alta Ethernet driver"); @@ -263,8 +191,10 @@ IV. Notes IVb. References The Sundance ST201 datasheet, preliminary version. -http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +The Kendin KS8723 datasheet, preliminary version. +The ICplus IP100 datasheet, preliminary version. +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html IVc. Errata @@ -275,14 +205,15 @@ IVc. Errata #define USE_IO_OPS 1 #endif -static struct pci_device_id sundance_pci_tbl[] = { - {0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0}, - {0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1}, - {0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2}, - {0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3}, - {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - {0,} +static const struct pci_device_id sundance_pci_tbl[] = { + { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 }, + { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 }, + { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 }, + { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 }, + { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, + { } }; MODULE_DEVICE_TABLE(pci, sundance_pci_tbl); @@ -293,14 +224,15 @@ enum { struct pci_id_info { const char *name; }; -static struct pci_id_info pci_id_tbl[] = { +static const struct pci_id_info pci_id_tbl[] __devinitdata = { {"D-Link DFE-550TX FAST Ethernet Adapter"}, {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"}, {"D-Link DFE-580TX 4 port Server Adapter"}, {"D-Link DFE-530TXS FAST Ethernet Adapter"}, {"D-Link DL10050-based FAST Ethernet Adapter"}, {"Sundance Technology Alta"}, - {NULL,}, /* 0 terminated list. */ + {"IC Plus Corporation IP100A FAST Ethernet Adapter"}, + { } /* terminate list. */ }; /* This driver was written to use PCI memory space, however x86-oriented @@ -331,8 +263,6 @@ enum alta_offsets { ASICCtrl = 0x30, EEData = 0x34, EECtrl = 0x36, - TxStartThresh = 0x3c, - RxEarlyThresh = 0x3e, FlashAddr = 0x40, FlashData = 0x44, TxStatus = 0x46, @@ -410,9 +340,9 @@ enum mac_ctrl1_bits { /* Note that using only 32 bit fields simplifies conversion to big-endian architectures. */ struct netdev_desc { - u32 next_desc; - u32 status; - struct desc_frag { u32 addr, length; } frag[1]; + __le32 next_desc; + __le32 status; + struct desc_frag { __le32 addr, length; } frag[1]; }; /* Bits in netdev_desc.status */ @@ -467,7 +397,6 @@ struct netdev_private { unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ struct pci_dev *pci_dev; void __iomem *base; - unsigned char pci_rev_id; }; /* The station address location in the EEPROM. */ @@ -480,6 +409,7 @@ static int change_mtu(struct net_device *dev, int new_mtu); static int eeprom_read(void __iomem *ioaddr, int location); 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 mdio_wait_link(struct net_device *dev, int wait); static int netdev_open(struct net_device *dev); static void check_duplex(struct net_device *dev); static void netdev_timer(unsigned long data); @@ -487,7 +417,7 @@ static void tx_timeout(struct net_device *dev); static void init_ring(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static int reset_tx (struct net_device *dev); -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static irqreturn_t intr_handler(int irq, void *dev_instance); static void rx_poll(unsigned long data); static void tx_poll(unsigned long data); static void refill_rx (struct net_device *dev); @@ -498,7 +428,26 @@ static int __set_mac_addr(struct net_device *dev); static struct net_device_stats *get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_close(struct net_device *dev); -static struct ethtool_ops ethtool_ops; +static const struct ethtool_ops ethtool_ops; + +static void sundance_reset(struct net_device *dev, unsigned long reset_cmd) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = np->base + ASICCtrl; + int countdown; + + /* ST201 documentation states ASICCtrl is a 32bit register */ + iowrite32 (reset_cmd | ioread32 (ioaddr), ioaddr); + /* ST201 documentation states reset can take up to 1 ms */ + countdown = 10 + 1; + while (ioread32 (ioaddr) & (ResetBusy << 16)) { + if (--countdown == 0) { + printk(KERN_WARNING "%s : reset not completed !!\n", dev->name); + break; + } + udelay(100); + } +} static int __devinit sundance_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -518,8 +467,8 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, #else int bar = 1; #endif - int phy, phy_idx = 0; - + int phy, phy_end, phy_idx = 0; + DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -537,7 +486,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, dev = alloc_etherdev(sizeof(*np)); if (!dev) return -ENOMEM; - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); if (pci_request_regions(pdev, DRV_NAME)) @@ -548,8 +496,8 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, goto err_out_res; for (i = 0; i < 3; i++) - ((u16 *)dev->dev_addr)[i] = - le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); + ((__le16 *)dev->dev_addr)[i] = + cpu_to_le16(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); dev->base_addr = (unsigned long)ioaddr; @@ -595,23 +543,31 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, dev->change_mtu = &change_mtu; pci_set_drvdata(pdev, dev); - pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id); - i = register_netdev(dev); if (i) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %p, ", - dev->name, pci_id_tbl[chip_idx].name, ioaddr); - for (i = 0; i < 5; i++) - printk("%2.2x:", dev->dev_addr[i]); - printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + dev->name, pci_id_tbl[chip_idx].name, ioaddr, + print_mac(mac, dev->dev_addr), irq); np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; - for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, MII_BMSR); + + /* + * It seems some phys doesn't deal well with address 0 being accessed + * first + */ + if (sundance_pci_tbl[np->chip_id].device == 0x0200) { + phy = 0; + phy_end = 31; + } else { + phy = 1; + phy_end = 32; /* wraps to zero, due to 'phy & 0x1f' */ + } + for (; phy <= phy_end && phy_idx < MII_CNT; phy++) { int phyx = phy & 0x1f; + int mii_status = mdio_read(dev, phyx, MII_BMSR); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phyx; np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE); @@ -692,7 +648,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, /* Reset the chip to erase previous misconfiguration. */ if (netif_msg_hw(np)) printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl)); - iowrite16(0x00ff, ioaddr + ASICCtrl + 2); + sundance_reset(dev, 0x00ff << 16); if (netif_msg_hw(np)) printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl)); @@ -830,15 +786,34 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val return; } +static int mdio_wait_link(struct net_device *dev, int wait) +{ + int bmsr; + int phy_id; + struct netdev_private *np; + + np = netdev_priv(dev); + phy_id = np->phys[0]; + + do { + bmsr = mdio_read(dev, phy_id, MII_BMSR); + if (bmsr & 0x0004) + return 0; + mdelay(1); + } while (--wait > 0); + return -1; +} + static int netdev_open(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base; + unsigned long flags; int i; /* Do we need to reset the chip??? */ - i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev); + i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev); if (i) return i; @@ -874,10 +849,14 @@ static int netdev_open(struct net_device *dev) iowrite8(100, ioaddr + RxDMAPollPeriod); iowrite8(127, ioaddr + TxDMAPollPeriod); /* Fix DFE-580TX packet drop issue */ - if (np->pci_rev_id >= 0x14) + if (np->pci_dev->revision >= 0x14) iowrite8(0x01, ioaddr + DebugCtrl1); netif_start_queue(dev); + spin_lock_irqsave(&np->lock, flags); + reset_tx(dev); + spin_unlock_irqrestore(&np->lock, flags); + iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); if (netif_msg_ifup(np)) @@ -951,7 +930,7 @@ static void tx_timeout(struct net_device *dev) struct netdev_private *np = netdev_priv(dev); void __iomem *ioaddr = np->base; unsigned long flag; - + netif_stop_queue(dev); tasklet_disable(&np->tx_tasklet); iowrite16(0, ioaddr + IntrEnable); @@ -968,13 +947,13 @@ static void tx_timeout(struct net_device *dev) le32_to_cpu(np->tx_ring[i].next_desc), le32_to_cpu(np->tx_ring[i].status), (le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff, - le32_to_cpu(np->tx_ring[i].frag[0].addr), + le32_to_cpu(np->tx_ring[i].frag[0].addr), le32_to_cpu(np->tx_ring[i].frag[0].length)); } - printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", - ioread32(np->base + TxListPtr), + printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", + ioread32(np->base + TxListPtr), netif_queue_stopped(dev)); - printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", + printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", np->cur_tx, np->cur_tx % TX_RING_SIZE, np->dirty_tx, np->dirty_tx % TX_RING_SIZE); printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx); @@ -1046,9 +1025,9 @@ static void tx_poll (unsigned long data) struct net_device *dev = (struct net_device *)data; struct netdev_private *np = netdev_priv(dev); unsigned head = np->cur_task % TX_RING_SIZE; - struct netdev_desc *txdesc = + struct netdev_desc *txdesc = &np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE]; - + /* Chain the next pointer */ for (; np->cur_tx - np->cur_task > 0; np->cur_task++) { int entry = np->cur_task % TX_RING_SIZE; @@ -1118,23 +1097,20 @@ reset_tx (struct net_device *dev) struct sk_buff *skb; int i; int irq = in_interrupt(); - + /* Reset tx logic, TxListPtr will be cleaned */ iowrite16 (TxDisable, ioaddr + MACCtrl1); - iowrite16 (TxReset | DMAReset | FIFOReset | NetworkReset, - ioaddr + ASICCtrl + 2); - for (i=50; i > 0; i--) { - if ((ioread16(ioaddr + ASICCtrl + 2) & ResetBusy) == 0) - break; - mdelay(1); - } + sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16); + /* free all tx skbuff */ for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].next_desc = 0; + skb = np->tx_skbuff[i]; if (skb) { - pci_unmap_single(np->pci_dev, - np->tx_ring[i].frag[0].addr, skb->len, - PCI_DMA_TODEVICE); + pci_unmap_single(np->pci_dev, + le32_to_cpu(np->tx_ring[i].frag[0].addr), + skb->len, PCI_DMA_TODEVICE); if (irq) dev_kfree_skb_irq (skb); else @@ -1145,13 +1121,17 @@ reset_tx (struct net_device *dev) } np->cur_tx = np->dirty_tx = 0; np->cur_task = 0; + + np->last_tx = NULL; + iowrite8(127, ioaddr + TxDMAPollPeriod); + iowrite16 (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); return 0; } -/* The interrupt handler cleans up after the Tx thread, +/* The interrupt handler cleans up after the Tx thread, and schedule a Rx thread work */ -static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +static irqreturn_t intr_handler(int irq, void *dev_instance) { struct net_device *dev = (struct net_device *)dev_instance; struct netdev_private *np = netdev_priv(dev); @@ -1160,6 +1140,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs int tx_cnt; int tx_status; int handled = 0; + int i; do { @@ -1190,23 +1171,36 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs ("%s: Transmit status is %2.2x.\n", dev->name, tx_status); if (tx_status & 0x1e) { + if (netif_msg_tx_err(np)) + printk("%s: Transmit error status %4.4x.\n", + dev->name, tx_status); np->stats.tx_errors++; if (tx_status & 0x10) np->stats.tx_fifo_errors++; if (tx_status & 0x08) np->stats.collisions++; + if (tx_status & 0x04) + np->stats.tx_fifo_errors++; if (tx_status & 0x02) np->stats.tx_window_errors++; - /* This reset has not been verified!. */ - if (tx_status & 0x10) { /* Reset the Tx. */ - np->stats.tx_fifo_errors++; - spin_lock(&np->lock); - reset_tx(dev); - spin_unlock(&np->lock); + + /* + ** This reset has been verified on + ** DFE-580TX boards ! phdm@macqel.be. + */ + if (tx_status & 0x10) { /* TxUnderrun */ + /* Restart Tx FIFO and transmitter */ + sundance_reset(dev, (NetworkReset|FIFOReset|TxReset) << 16); + /* No need to reset the Tx pointer here */ } - if (tx_status & 0x1e) /* Restart the Tx. */ - iowrite16 (TxEnable, - ioaddr + MACCtrl1); + /* Restart the Tx. Need to make sure tx enabled */ + i = 10; + do { + iowrite16(ioread16(ioaddr + MACCtrl1) | TxEnable, ioaddr + MACCtrl1); + if (ioread16(ioaddr + MACCtrl1) & TxEnabled) + break; + mdelay(1); + } while (--i); } /* Yup, this is a documentation bug. It cost me *hours*. */ iowrite16 (0, ioaddr + TxStatus); @@ -1220,8 +1214,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs } else { hw_frame_id = ioread8(ioaddr + TxFrameId); } - - if (np->pci_rev_id >= 0x14) { + + if (np->pci_dev->revision >= 0x14) { spin_lock(&np->lock); for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; @@ -1233,13 +1227,13 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs !(le32_to_cpu(np->tx_ring[entry].status) & 0x00010000)) break; - if (sw_frame_id == (hw_frame_id + 1) % + if (sw_frame_id == (hw_frame_id + 1) % TX_RING_SIZE) break; skb = np->tx_skbuff[entry]; /* Free the original skb. */ pci_unmap_single(np->pci_dev, - np->tx_ring[entry].frag[0].addr, + le32_to_cpu(np->tx_ring[entry].frag[0].addr), skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq (np->tx_skbuff[entry]); np->tx_skbuff[entry] = NULL; @@ -1252,13 +1246,13 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { int entry = np->dirty_tx % TX_RING_SIZE; struct sk_buff *skb; - if (!(le32_to_cpu(np->tx_ring[entry].status) + if (!(le32_to_cpu(np->tx_ring[entry].status) & 0x00010000)) break; skb = np->tx_skbuff[entry]; /* Free the original skb. */ pci_unmap_single(np->pci_dev, - np->tx_ring[entry].frag[0].addr, + le32_to_cpu(np->tx_ring[entry].frag[0].addr), skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq (np->tx_skbuff[entry]); np->tx_skbuff[entry] = NULL; @@ -1267,7 +1261,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs } spin_unlock(&np->lock); } - + if (netif_queue_stopped(dev) && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { /* The ring is no longer full, clear busy flag. */ @@ -1334,22 +1328,21 @@ static void rx_poll(unsigned long data) to a minimally-sized skbuff. */ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev, - desc->frag[0].addr, + le32_to_cpu(desc->frag[0].addr), np->rx_buf_sz, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0); + skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len); pci_dma_sync_single_for_device(np->pci_dev, - desc->frag[0].addr, + le32_to_cpu(desc->frag[0].addr), np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); } else { pci_unmap_single(np->pci_dev, - desc->frag[0].addr, + le32_to_cpu(desc->frag[0].addr), np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put(skb = np->rx_skbuff[entry], pkt_len); @@ -1419,41 +1412,51 @@ static void netdev_error(struct net_device *dev, int intr_status) int speed; if (intr_status & LinkChange) { - if (np->an_enable) { - mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE); - mii_lpa= mdio_read (dev, np->phys[0], MII_LPA); - mii_advertise &= mii_lpa; - printk (KERN_INFO "%s: Link changed: ", dev->name); - if (mii_advertise & ADVERTISE_100FULL) { - np->speed = 100; - printk ("100Mbps, full duplex\n"); - } else if (mii_advertise & ADVERTISE_100HALF) { - np->speed = 100; - printk ("100Mbps, half duplex\n"); - } else if (mii_advertise & ADVERTISE_10FULL) { - np->speed = 10; - printk ("10Mbps, full duplex\n"); - } else if (mii_advertise & ADVERTISE_10HALF) { - np->speed = 10; - printk ("10Mbps, half duplex\n"); - } else - printk ("\n"); + if (mdio_wait_link(dev, 10) == 0) { + printk(KERN_INFO "%s: Link up\n", dev->name); + if (np->an_enable) { + mii_advertise = mdio_read(dev, np->phys[0], + MII_ADVERTISE); + mii_lpa = mdio_read(dev, np->phys[0], MII_LPA); + mii_advertise &= mii_lpa; + printk(KERN_INFO "%s: Link changed: ", + dev->name); + if (mii_advertise & ADVERTISE_100FULL) { + np->speed = 100; + printk("100Mbps, full duplex\n"); + } else if (mii_advertise & ADVERTISE_100HALF) { + np->speed = 100; + printk("100Mbps, half duplex\n"); + } else if (mii_advertise & ADVERTISE_10FULL) { + np->speed = 10; + printk("10Mbps, full duplex\n"); + } else if (mii_advertise & ADVERTISE_10HALF) { + np->speed = 10; + printk("10Mbps, half duplex\n"); + } else + printk("\n"); + } else { + mii_ctl = mdio_read(dev, np->phys[0], MII_BMCR); + speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; + np->speed = speed; + printk(KERN_INFO "%s: Link changed: %dMbps ,", + dev->name, speed); + printk("%s duplex.\n", + (mii_ctl & BMCR_FULLDPLX) ? + "full" : "half"); + } + check_duplex(dev); + if (np->flowctrl && np->mii_if.full_duplex) { + iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200, + ioaddr + MulticastFilter1+2); + iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl, + ioaddr + MACCtrl0); + } + netif_carrier_on(dev); } else { - mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR); - speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10; - np->speed = speed; - printk (KERN_INFO "%s: Link changed: %dMbps ,", - dev->name, speed); - printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ? - "full" : "half"); - } - check_duplex (dev); - if (np->flowctrl && np->mii_if.full_duplex) { - iowrite16(ioread16(ioaddr + MulticastFilter1+2) | 0x0200, - ioaddr + MulticastFilter1+2); - iowrite16(ioread16(ioaddr + MACCtrl0) | EnbFlowCtrl, - ioaddr + MACCtrl0); + printk(KERN_INFO "%s: Link down\n", dev->name); + netif_carrier_off(dev); } } if (intr_status & StatsMax) { @@ -1503,8 +1506,6 @@ static void set_rx_mode(struct net_device *dev) int i; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - /* Unconditionally log net taps. */ - printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys; } else if ((dev->mc_count > multicast_filter_limit) @@ -1610,7 +1611,7 @@ static void set_msglevel(struct net_device *dev, u32 val) np->msg_enable = val; } -static struct ethtool_ops ethtool_ops = { +static const struct ethtool_ops ethtool_ops = { .begin = check_if_running, .get_drvinfo = get_drvinfo, .get_settings = get_settings, @@ -1619,15 +1620,12 @@ static struct ethtool_ops ethtool_ops = { .get_link = get_link, .get_msglevel = get_msglevel, .set_msglevel = set_msglevel, - .get_perm_addr = ethtool_op_get_perm_addr, }; static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; int rc; - int i; if (!netif_running(dev)) return -EINVAL; @@ -1635,30 +1633,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irq(&np->lock); rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL); spin_unlock_irq(&np->lock); - switch (cmd) { - case SIOCDEVPRIVATE: - for (i=0; itx_ring_dma + i*sizeof(*np->tx_ring)), - le32_to_cpu(np->tx_ring[i].next_desc), - le32_to_cpu(np->tx_ring[i].status), - (le32_to_cpu(np->tx_ring[i].status) >> 2) - & 0xff, - le32_to_cpu(np->tx_ring[i].frag[0].addr), - le32_to_cpu(np->tx_ring[i].frag[0].length)); - } - printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", - ioread32(np->base + TxListPtr), - netif_queue_stopped(dev)); - printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", - np->cur_tx, np->cur_tx % TX_RING_SIZE, - np->dirty_tx, np->dirty_tx % TX_RING_SIZE); - printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx); - printk(KERN_DEBUG "cur_task=%d\n", np->cur_task); - printk(KERN_DEBUG "TxStatus=%04x\n", ioread16(ioaddr + TxStatus)); - return 0; - } - return rc; } @@ -1670,6 +1644,14 @@ static int netdev_close(struct net_device *dev) struct sk_buff *skb; int i; + /* Wait and kill tasklet */ + tasklet_kill(&np->rx_tasklet); + tasklet_kill(&np->tx_tasklet); + np->cur_tx = 0; + np->dirty_tx = 0; + np->cur_task = 0; + np->last_tx = NULL; + netif_stop_queue(dev); if (netif_msg_ifdown(np)) { @@ -1684,12 +1666,26 @@ static int netdev_close(struct net_device *dev) /* Disable interrupts by clearing the interrupt mask. */ iowrite16(0x0000, ioaddr + IntrEnable); + /* Disable Rx and Tx DMA for safely release resource */ + iowrite32(0x500, ioaddr + DMACtrl); + /* Stop the chip's Tx and Rx processes. */ iowrite16(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); - /* Wait and kill tasklet */ - tasklet_kill(&np->rx_tasklet); - tasklet_kill(&np->tx_tasklet); + for (i = 2000; i > 0; i--) { + if ((ioread32(ioaddr + DMACtrl) & 0xc000) == 0) + break; + mdelay(1); + } + + iowrite16(GlobalReset | DMAReset | FIFOReset | NetworkReset, + ioaddr +ASICCtrl + 2); + + for (i = 2000; i > 0; i--) { + if ((ioread16(ioaddr + ASICCtrl +2) & ResetBusy) == 0) + break; + mdelay(1); + } #ifdef __i386__ if (netif_msg_hw(np)) { @@ -1716,22 +1712,23 @@ static int netdev_close(struct net_device *dev) /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].status = 0; - np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */ skb = np->rx_skbuff[i]; if (skb) { pci_unmap_single(np->pci_dev, - np->rx_ring[i].frag[0].addr, np->rx_buf_sz, - PCI_DMA_FROMDEVICE); + le32_to_cpu(np->rx_ring[i].frag[0].addr), + np->rx_buf_sz, PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); np->rx_skbuff[i] = NULL; } + np->rx_ring[i].frag[0].addr = cpu_to_le32(0xBADF00D0); /* poison */ } for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_ring[i].next_desc = 0; skb = np->tx_skbuff[i]; if (skb) { pci_unmap_single(np->pci_dev, - np->tx_ring[i].frag[0].addr, skb->len, - PCI_DMA_TODEVICE); + le32_to_cpu(np->tx_ring[i].frag[0].addr), + skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); np->tx_skbuff[i] = NULL; } @@ -1772,7 +1769,7 @@ static int __init sundance_init(void) #ifdef MODULE printk(version); #endif - return pci_module_init(&sundance_driver); + return pci_register_driver(&sundance_driver); } static void __exit sundance_exit(void)