]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/dm9000.c
es1968: fix sleep-while-holding-lock bug
[linux-2.6-omap-h63xx.git] / drivers / net / dm9000.c
index 5a883711d1f4548be5330c306fc6ab949b3e18d3..d63cc93f055dfd2be2c8a493a514b20a743fd9fa 100644 (file)
@@ -1,7 +1,5 @@
 /*
- *   dm9000.c: Version 1.2 03/18/2003
- *
- *         A Davicom DM9000 ISA NIC fast Ethernet driver for Linux.
+ *      Davicom DM9000 Fast Ethernet driver for Linux.
  *     Copyright (C) 1997  Sten Wang
  *
  *     This program is free software; you can redistribute it and/or
  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *     GNU General Public License for more details.
  *
- *   (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
- *
- * V0.11       06/20/2001      REG_0A bit3=1, default enable BP with DA match
- *     06/22/2001      Support DM9801 progrmming
- *                     E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000
- *                     E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200
- *                             R17 = (R17 & 0xfff0) | NF + 3
- *                     E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200
- *                             R17 = (R17 & 0xfff0) | NF
- *
- * v1.00                       modify by simon 2001.9.5
- *                         change for kernel 2.4.x
- *
- * v1.1   11/09/2001           fix force mode bug
- *
- * v1.2   03/18/2003       Weilun Huang <weilun_huang@davicom.com.tw>:
- *                     Fixed phy reset.
- *                     Added tx/rx 32 bit mode.
- *                     Cleaned up for kernel merge.
+ * (C) Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
  *
- *        03/03/2004    Sascha Hauer <s.hauer@pengutronix.de>
- *                      Port to 2.6 kernel
- *
- *       24-Sep-2004   Ben Dooks <ben@simtec.co.uk>
- *                     Cleanup of code to remove ifdefs
- *                     Allowed platform device data to influence access width
- *                     Reformatting areas of code
- *
- *        17-Mar-2005   Sascha Hauer <s.hauer@pengutronix.de>
- *                      * removed 2.4 style module parameters
- *                      * removed removed unused stat counter and fixed
- *                        net_device_stats
- *                      * introduced tx_timeout function
- *                      * reworked locking
- *
- *       01-Jul-2005   Ben Dooks <ben@simtec.co.uk>
- *                     * fixed spinlock call without pointer
- *                     * ensure spinlock is initialised
+ * Additional updates, Copyright:
+ *     Ben Dooks <ben@simtec.co.uk>
+ *     Sascha Hauer <s.hauer@pengutronix.de>
  */
 
 #include <linux/module.h>
@@ -177,6 +142,7 @@ static int dm9000_probe(struct platform_device *);
 static int dm9000_open(struct net_device *);
 static int dm9000_start_xmit(struct sk_buff *, struct net_device *);
 static int dm9000_stop(struct net_device *);
+static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd);
 
 static void dm9000_init_dm9000(struct net_device *);
 
@@ -367,6 +333,16 @@ static void dm9000_poll_controller(struct net_device *dev)
 }
 #endif
 
+static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+       board_info_t *dm = to_dm9000_board(dev);
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL);
+}
+
 /* ethtool ops */
 
 static void dm9000_get_drvinfo(struct net_device *dev,
@@ -440,6 +416,9 @@ static int dm9000_get_eeprom(struct net_device *dev,
        if ((len & 1) != 0 || (offset & 1) != 0)
                return -EINVAL;
 
+       if (dm->flags & DM9000_PLATF_NO_EEPROM)
+               return -ENOENT;
+
        ee->magic = DM_EEPROM_MAGIC;
 
        for (i = 0; i < len; i += 2)
@@ -461,6 +440,9 @@ static int dm9000_set_eeprom(struct net_device *dev,
        if ((len & 1) != 0 || (offset & 1) != 0)
                return -EINVAL;
 
+       if (dm->flags & DM9000_PLATF_NO_EEPROM)
+               return -ENOENT;
+
        if (ee->magic != DM_EEPROM_MAGIC)
                return -EINVAL;
 
@@ -527,6 +509,7 @@ dm9000_probe(struct platform_device *pdev)
        struct dm9000_plat_data *pdata = pdev->dev.platform_data;
        struct board_info *db;  /* Point a board information structure */
        struct net_device *ndev;
+       const unsigned char *mac_src;
        unsigned long base;
        int ret = 0;
        int iosize;
@@ -661,7 +644,7 @@ dm9000_probe(struct platform_device *pdev)
        dm9000_reset(db);
 
        /* try two times, DM9000 sometimes gets the first read wrong */
-       for (i = 0; i < 2; i++) {
+       for (i = 0; i < 8; i++) {
                id_val  = ior(db, DM9000_VIDL);
                id_val |= (u32)ior(db, DM9000_VIDH) << 8;
                id_val |= (u32)ior(db, DM9000_PIDL) << 16;
@@ -690,6 +673,7 @@ dm9000_probe(struct platform_device *pdev)
        ndev->stop               = &dm9000_stop;
        ndev->set_multicast_list = &dm9000_hash_table;
        ndev->ethtool_ops        = &dm9000_ethtool_ops;
+       ndev->do_ioctl           = &dm9000_ioctl;
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
        ndev->poll_controller    = &dm9000_poll_controller;
@@ -704,13 +688,16 @@ dm9000_probe(struct platform_device *pdev)
        db->mii.mdio_read    = dm9000_phy_read;
        db->mii.mdio_write   = dm9000_phy_write;
 
+       mac_src = "eeprom";
+
        /* try reading the node address from the attached EEPROM */
        for (i = 0; i < 6; i += 2)
                dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
 
        if (!is_valid_ether_addr(ndev->dev_addr)) {
                /* try reading from mac */
-
+               
+               mac_src = "chip";
                for (i = 0; i < 6; i++)
                        ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
        }
@@ -724,9 +711,9 @@ dm9000_probe(struct platform_device *pdev)
 
        if (ret == 0) {
                DECLARE_MAC_BUF(mac);
-               printk("%s: dm9000 at %p,%p IRQ %d MAC: %s\n",
+               printk("%s: dm9000 at %p,%p IRQ %d MAC: %s (%s)\n",
                       ndev->name,  db->io_addr, db->io_data, ndev->irq,
-                      print_mac(mac, ndev->dev_addr));
+                      print_mac(mac, ndev->dev_addr), mac_src);
        }
        return 0;
 
@@ -749,7 +736,8 @@ dm9000_open(struct net_device *dev)
        board_info_t *db = (board_info_t *) dev->priv;
        unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
 
-       dev_dbg(db->dev, "entering %s\n", __func__);
+       if (netif_msg_ifup(db))
+               dev_dbg(db->dev, "enabling %s\n", dev->name);
 
        /* If there is no IRQ type specified, default to something that
         * may work, and tell the user that this is a problem */
@@ -810,8 +798,6 @@ dm9000_init_dm9000(struct net_device *dev)
        /* Set address filter table */
        dm9000_hash_table(dev);
 
-       /* Activate DM9000 */
-       iow(db, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
        /* Enable TX/RX interrupt mask */
        iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
 
@@ -848,8 +834,8 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* TX control: First packet immediately send, second packet queue */
        if (db->tx_pkt_cnt == 1) {
                /* Set TX length to DM9000 */
-               iow(db, DM9000_TXPLL, skb->len & 0xff);
-               iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);
+               iow(db, DM9000_TXPLL, skb->len);
+               iow(db, DM9000_TXPLH, skb->len >> 8);
 
                /* Issue TX polling command */
                iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
@@ -890,7 +876,8 @@ dm9000_stop(struct net_device *ndev)
 {
        board_info_t *db = (board_info_t *) ndev->priv;
 
-       dm9000_dbg(db, 1, "entering %s\n", __func__);
+       if (netif_msg_ifdown(db))
+               dev_dbg(db->dev, "shutting down %s\n", ndev->name);
 
        netif_stop_queue(ndev);
        netif_carrier_off(ndev);
@@ -918,10 +905,13 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db)
                db->tx_pkt_cnt--;
                dev->stats.tx_packets++;
 
+               if (netif_msg_tx_done(db))
+                       dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
+
                /* Queue packet check & send */
                if (db->tx_pkt_cnt > 0) {
-                       iow(db, DM9000_TXPLL, db->queue_pkt_len & 0xff);
-                       iow(db, DM9000_TXPLH, (db->queue_pkt_len >> 8) & 0xff);
+                       iow(db, DM9000_TXPLL, db->queue_pkt_len);
+                       iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
                        iow(db, DM9000_TCR, TCR_TXREQ);
                        dev->trans_start = jiffies;
                }
@@ -953,6 +943,9 @@ dm9000_interrupt(int irq, void *dev_id)
        int_status = ior(db, DM9000_ISR);       /* Got ISR */
        iow(db, DM9000_ISR, int_status);        /* Clear ISR status */
 
+       if (netif_msg_intr(db))
+               dev_dbg(db->dev, "interrupt status %02x\n", int_status);
+
        /* Received the coming packet */
        if (int_status & ISR_PRS)
                dm9000_rx(dev);
@@ -975,7 +968,7 @@ dm9000_interrupt(int irq, void *dev_id)
 struct dm9000_rxhdr {
        u8      RxPktReady;
        u8      RxStatus;
-       u16     RxLen;
+       __le16  RxLen;
 } __attribute__((__packed__));
 
 /*
@@ -1017,10 +1010,15 @@ dm9000_rx(struct net_device *dev)
 
                RxLen = le16_to_cpu(rxhdr.RxLen);
 
+               if (netif_msg_rx_status(db))
+                       dev_dbg(db->dev, "RX: status %02x, length %04x\n",
+                               rxhdr.RxStatus, RxLen);
+
                /* Packet Status check */
                if (RxLen < 0x40) {
                        GoodPacket = false;
-                       dev_dbg(db->dev, "Bad Packet received (runt)\n");
+                       if (netif_msg_rx_err(db))
+                               dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
                }
 
                if (RxLen > DM9000_PKT_MAX) {
@@ -1030,15 +1028,18 @@ dm9000_rx(struct net_device *dev)
                if (rxhdr.RxStatus & 0xbf) {
                        GoodPacket = false;
                        if (rxhdr.RxStatus & 0x01) {
-                               dev_dbg(db->dev, "fifo error\n");
+                               if (netif_msg_rx_err(db))
+                                       dev_dbg(db->dev, "fifo error\n");
                                dev->stats.rx_fifo_errors++;
                        }
                        if (rxhdr.RxStatus & 0x02) {
-                               dev_dbg(db->dev, "crc error\n");
+                               if (netif_msg_rx_err(db))
+                                       dev_dbg(db->dev, "crc error\n");
                                dev->stats.rx_crc_errors++;
                        }
                        if (rxhdr.RxStatus & 0x80) {
-                               dev_dbg(db->dev, "length error\n");
+                               if (netif_msg_rx_err(db))
+                                       dev_dbg(db->dev, "length error\n");
                                dev->stats.rx_length_errors++;
                        }
                }
@@ -1067,6 +1068,50 @@ dm9000_rx(struct net_device *dev)
        } while (rxbyte == DM9000_PKT_RDY);
 }
 
+static unsigned int
+dm9000_read_locked(board_info_t *db, int reg)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&db->lock, flags);
+       ret = ior(db, reg);
+       spin_unlock_irqrestore(&db->lock, flags);
+
+       return ret;
+}
+
+static int dm9000_wait_eeprom(board_info_t *db)
+{
+       unsigned int status;
+       int timeout = 8;        /* wait max 8msec */
+
+       /* The DM9000 data sheets say we should be able to
+        * poll the ERRE bit in EPCR to wait for the EEPROM
+        * operation. From testing several chips, this bit
+        * does not seem to work. 
+        *
+        * We attempt to use the bit, but fall back to the
+        * timeout (which is why we do not return an error
+        * on expiry) to say that the EEPROM operation has
+        * completed.
+        */
+
+       while (1) {
+               status = dm9000_read_locked(db, DM9000_EPCR);
+
+               if ((status & EPCR_ERRE) == 0)
+                       break;
+
+               if (timeout-- < 0) {
+                       dev_dbg(db->dev, "timeout waiting EEPROM\n");
+                       break;
+               }
+       }
+
+       return 0;
+}
+
 /*
  *  Read a word data from EEPROM
  */
@@ -1075,6 +1120,12 @@ dm9000_read_eeprom(board_info_t *db, int offset, u8 *to)
 {
        unsigned long flags;
 
+       if (db->flags & DM9000_PLATF_NO_EEPROM) {
+               to[0] = 0xff;
+               to[1] = 0xff;
+               return;
+       }
+
        mutex_lock(&db->addr_lock);
 
        spin_lock_irqsave(&db->lock, flags);
@@ -1084,8 +1135,10 @@ dm9000_read_eeprom(board_info_t *db, int offset, u8 *to)
 
        spin_unlock_irqrestore(&db->lock, flags);
 
-       mdelay(8);              /* according to the datasheet 200us should be enough,
-                                  but it doesn't work */
+       dm9000_wait_eeprom(db);
+
+       /* delay for at-least 150uS */
+       msleep(1);
 
        spin_lock_irqsave(&db->lock, flags);
 
@@ -1107,6 +1160,9 @@ dm9000_write_eeprom(board_info_t *db, int offset, u8 *data)
 {
        unsigned long flags;
 
+       if (db->flags & DM9000_PLATF_NO_EEPROM)
+               return;
+
        mutex_lock(&db->addr_lock);
 
        spin_lock_irqsave(&db->lock, flags);
@@ -1116,7 +1172,9 @@ dm9000_write_eeprom(board_info_t *db, int offset, u8 *data)
        iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
        spin_unlock_irqrestore(&db->lock, flags);
 
-       mdelay(8);              /* same shit */
+       dm9000_wait_eeprom(db);
+
+       mdelay(1);      /* wait at least 150uS to clear */
 
        spin_lock_irqsave(&db->lock, flags);
        iow(db, DM9000_EPCR, 0);
@@ -1125,24 +1183,6 @@ dm9000_write_eeprom(board_info_t *db, int offset, u8 *data)
        mutex_unlock(&db->addr_lock);
 }
 
-/*
- *  Calculate the CRC valude of the Rx packet
- *  flag = 1 : return the reverse CRC (for the received packet CRC)
- *         0 : return the normal CRC (for Hash Table index)
- */
-
-static unsigned long
-cal_CRC(unsigned char *Data, unsigned int Len, u8 flag)
-{
-
-       u32 crc = ether_crc_le(Len, Data);
-
-       if (flag)
-               return ~crc;
-
-       return crc;
-}
-
 /*
  *  Set DM9000 multicast address
  */
@@ -1152,15 +1192,17 @@ dm9000_hash_table(struct net_device *dev)
        board_info_t *db = (board_info_t *) dev->priv;
        struct dev_mc_list *mcptr = dev->mc_list;
        int mc_cnt = dev->mc_count;
+       int i, oft;
        u32 hash_val;
-       u16 i, oft, hash_table[4];
+       u16 hash_table[4];
+       u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;
        unsigned long flags;
 
        dm9000_dbg(db, 1, "entering %s\n", __func__);
 
-       spin_lock_irqsave(&db->lock,flags);
+       spin_lock_irqsave(&db->lock, flags);
 
-       for (i = 0, oft = 0x10; i < 6; i++, oft++)
+       for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
                iow(db, oft, dev->dev_addr[i]);
 
        /* Clear Hash Table */
@@ -1170,19 +1212,26 @@ dm9000_hash_table(struct net_device *dev)
        /* broadcast address */
        hash_table[3] = 0x8000;
 
+       if (dev->flags & IFF_PROMISC)
+               rcr |= RCR_PRMSC;
+
+       if (dev->flags & IFF_ALLMULTI)
+               rcr |= RCR_ALL;
+
        /* the multicast address in Hash Table : 64 bits */
        for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
-               hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;
+               hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f;
                hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
        }
 
        /* Write the hash table to MAC MD table */
-       for (i = 0, oft = 0x16; i < 4; i++) {
-               iow(db, oft++, hash_table[i] & 0xff);
-               iow(db, oft++, (hash_table[i] >> 8) & 0xff);
+       for (i = 0, oft = DM9000_MAR; i < 4; i++) {
+               iow(db, oft++, hash_table[i]);
+               iow(db, oft++, hash_table[i] >> 8);
        }
 
-       spin_unlock_irqrestore(&db->lock,flags);
+       iow(db, DM9000_RCR, rcr);
+       spin_unlock_irqrestore(&db->lock, flags);
 }
 
 
@@ -1263,8 +1312,8 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value)
        iow(db, DM9000_EPAR, DM9000_PHY | reg);
 
        /* Fill the written data into REG_0D & REG_0E */
-       iow(db, DM9000_EPDRL, (value & 0xff));
-       iow(db, DM9000_EPDRH, ((value >> 8) & 0xff));
+       iow(db, DM9000_EPDRL, value);
+       iow(db, DM9000_EPDRH, value >> 8);
 
        iow(db, DM9000_EPCR, 0xa);      /* Issue phyxcer write command */