diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 6a20a54..1fe305c 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -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
@@ -14,44 +12,11 @@
* 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
- *
- * Fixed phy reset.
- * Added tx/rx 32 bit mode.
- * Cleaned up for kernel merge.
- *
- * Port to 2.6 kernel
- *
- * Cleanup of code to remove ifdefs
- * Allowed platform device data to influence access width
- * Reformatting areas of code
- *
- * * removed 2.4 style module parameters
- * * removed removed unused stat counter and fixed
- * net_device_stats
- * * introduced tx_timeout function
- * * reworked locking
+ * (C) Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
*
- * * fixed spinlock call without pointer
- * * ensure spinlock is initialised
+ * Additional updates, Copyright:
*/
#include <linux/module.h>
@@ -63,6 +28,7 @@
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
+#include <linux/ethtool.h>
#include <linux/dm9000.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@@ -80,30 +46,7 @@
#define CARDNAME "dm9000"
#define PFX CARDNAME ": "
-
-#define DM9000_TIMER_WUT jiffies+(HZ*2) /* timer wakeup time : 2 second */
-
-#define DM9000_DEBUG 0
-
-#if DM9000_DEBUG > 2
-#define PRINTK3(args...) printk(CARDNAME ": " args)
-#else
-#define PRINTK3(args...) do { } while(0)
-#endif
-
-#if DM9000_DEBUG > 1
-#define PRINTK2(args...) printk(CARDNAME ": " args)
-#else
-#define PRINTK2(args...) do { } while(0)
-#endif
-
-#if DM9000_DEBUG > 0
-#define PRINTK1(args...) printk(CARDNAME ": " args)
-#define PRINTK(args...) printk(CARDNAME ": " args)
-#else
-#define PRINTK1(args...) do { } while(0)
-#define PRINTK(args...) printk(KERN_DEBUG args)
-#endif
+#define DRV_VERSION "1.30"
#ifdef CONFIG_BLACKFIN
#define readsb insb
@@ -112,9 +55,9 @@
#define writesb outsb
#define writesw outsw
#define writesl outsl
-#define DM9000_IRQ_FLAGS (IRQF_SHARED | IRQF_TRIGGER_HIGH)
+#define DEFAULT_TRIGGER IRQF_TRIGGER_HIGH
#else
-#define DM9000_IRQ_FLAGS (IRQF_SHARED | IRQT_RISING)
+#define DEFAULT_TRIGGER (0)
#endif
/*
@@ -124,6 +67,24 @@ static int watchdog = 5000;
module_param(watchdog, int, 0400);
MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
+/* DM9000 register address locking.
+ *
+ * The DM9000 uses an address register to control where data written
+ * to the data register goes. This means that the address register
+ * must be preserved over interrupts or similar calls.
+ *
+ * During interrupt and other critical calls, a spinlock is used to
+ * protect the system, but the calls themselves save the address
+ * in the address register in case they are interrupting another
+ * access to the device.
+ *
+ * For general accesses a lock is provided so that calls which are
+ * allowed to sleep are serialised so that the address register does
+ * not need to be saved. This lock also serves to serialise access
+ * to the EEPROM and PHY access registers which are shared between
+ * these two devices.
+ */
+
/* Structure/enum declaration ------------------------------- */
typedef struct board_info {
@@ -137,33 +98,52 @@ typedef struct board_info {
u16 dbug_cnt;
u8 io_mode; /* 0:word, 2:byte */
u8 phy_addr;
+ unsigned int flags;
+ unsigned int in_suspend :1;
+
+ int debug_level;
void (*inblk)(void __iomem *port, void *data, int length);
void (*outblk)(void __iomem *port, void *data, int length);
void (*dumpblk)(void __iomem *port, int length);
+ struct device *dev; /* parent device */
+
struct resource *addr_res; /* resources found */
struct resource *data_res;
struct resource *addr_req; /* resources requested */
struct resource *data_req;
struct resource *irq_res;
- struct timer_list timer;
- unsigned char srom[128];
+ struct mutex addr_lock; /* phy and eeprom access lock */
+
spinlock_t lock;
struct mii_if_info mii;
u32 msg_enable;
} board_info_t;
+/* debug code */
+
+#define dm9000_dbg(db, lev, msg...) do { \
+ if ((lev) < CONFIG_DM9000_DEBUGLEVEL && \
+ (lev) < db->debug_level) { \
+ dev_dbg(db->dev, msg); \
+ } \
+} while (0)
+
+static inline board_info_t *to_dm9000_board(struct net_device *dev)
+{
+ return dev->priv;
+}
+
/* function declaration ------------------------------------- */
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_timer(unsigned long);
static void dm9000_init_dm9000(struct net_device *);
static irqreturn_t dm9000_interrupt(int, void *);
@@ -171,20 +151,19 @@ static irqreturn_t dm9000_interrupt(int, void *);
static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);
static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg,
int value);
-static u16 read_srom_word(board_info_t *, int);
+
+static void dm9000_read_eeprom(board_info_t *, int addr, u8 *to);
+static void dm9000_write_eeprom(board_info_t *, int addr, u8 *dp);
static void dm9000_rx(struct net_device *);
static void dm9000_hash_table(struct net_device *);
-//#define DM9000_PROGRAM_EEPROM
-#ifdef DM9000_PROGRAM_EEPROM
-static void program_eeprom(board_info_t * db);
-#endif
/* DM9000 network board routine ---------------------------- */
static void
dm9000_reset(board_info_t * db)
{
- PRINTK1("dm9000x: resetting\n");
+ dev_dbg(db->dev, "resetting device\n");
+
/* RESET device */
writeb(DM9000_NCR, db->io_addr);
udelay(200);
@@ -300,14 +279,10 @@ static void dm9000_set_io(struct board_info *db, int byte_width)
db->inblk = dm9000_inblk_8bit;
break;
- case 2:
- db->dumpblk = dm9000_dumpblk_16bit;
- db->outblk = dm9000_outblk_16bit;
- db->inblk = dm9000_inblk_16bit;
- break;
case 3:
- printk(KERN_ERR PFX ": 3 byte IO, falling back to 16bit\n");
+ dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n");
+ case 2:
db->dumpblk = dm9000_dumpblk_16bit;
db->outblk = dm9000_outblk_16bit;
db->inblk = dm9000_inblk_16bit;
@@ -358,6 +333,139 @@ 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,
+ struct ethtool_drvinfo *info)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+
+ strcpy(info->driver, CARDNAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, to_platform_device(dm->dev)->name);
+}
+
+static u32 dm9000_get_msglevel(struct net_device *dev)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+
+ return dm->msg_enable;
+}
+
+static void dm9000_set_msglevel(struct net_device *dev, u32 value)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+
+ dm->msg_enable = value;
+}
+
+static int dm9000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+
+ mii_ethtool_gset(&dm->mii, cmd);
+ return 0;
+}
+
+static int dm9000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+
+ return mii_ethtool_sset(&dm->mii, cmd);
+}
+
+static int dm9000_nway_reset(struct net_device *dev)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ return mii_nway_restart(&dm->mii);
+}
+
+static u32 dm9000_get_link(struct net_device *dev)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ return mii_link_ok(&dm->mii);
+}
+
+#define DM_EEPROM_MAGIC (0x444D394B)
+
+static int dm9000_get_eeprom_len(struct net_device *dev)
+{
+ return 128;
+}
+
+static int dm9000_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *ee, u8 *data)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ int offset = ee->offset;
+ int len = ee->len;
+ int i;
+
+ /* EEPROM access is aligned to two bytes */
+
+ 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)
+ dm9000_read_eeprom(dm, (offset + i) / 2, data + i);
+
+ return 0;
+}
+
+static int dm9000_set_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *ee, u8 *data)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ int offset = ee->offset;
+ int len = ee->len;
+ int i;
+
+ /* EEPROM access is aligned to two bytes */
+
+ 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;
+
+ for (i = 0; i < len; i += 2)
+ dm9000_write_eeprom(dm, (offset + i) / 2, data + i);
+
+ return 0;
+}
+
+static const struct ethtool_ops dm9000_ethtool_ops = {
+ .get_drvinfo = dm9000_get_drvinfo,
+ .get_settings = dm9000_get_settings,
+ .set_settings = dm9000_set_settings,
+ .get_msglevel = dm9000_get_msglevel,
+ .set_msglevel = dm9000_set_msglevel,
+ .nway_reset = dm9000_nway_reset,
+ .get_link = dm9000_get_link,
+ .get_eeprom_len = dm9000_get_eeprom_len,
+ .get_eeprom = dm9000_get_eeprom,
+ .set_eeprom = dm9000_set_eeprom,
+};
+
+
/* dm9000_release_board
*
* release a board, and any mapped resources
@@ -401,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;
@@ -410,19 +519,22 @@ dm9000_probe(struct platform_device *pdev)
/* Init network device */
ndev = alloc_etherdev(sizeof (struct board_info));
if (!ndev) {
- printk("%s: could not allocate device.\n", CARDNAME);
+ dev_err(&pdev->dev, "could not allocate device.\n");
return -ENOMEM;
}
SET_NETDEV_DEV(ndev, &pdev->dev);
- PRINTK2("dm9000_probe()");
+ dev_dbg(&pdev->dev, "dm9000_probe()");
/* setup board info structure */
db = (struct board_info *) ndev->priv;
memset(db, 0, sizeof (*db));
+ db->dev = &pdev->dev;
+
spin_lock_init(&db->lock);
+ mutex_init(&db->addr_lock);
if (pdev->num_resources < 2) {
ret = -ENODEV;
@@ -450,7 +562,7 @@ dm9000_probe(struct platform_device *pdev)
if (db->addr_res == NULL || db->data_res == NULL ||
db->irq_res == NULL) {
- printk(KERN_ERR PFX "insufficient resources\n");
+ dev_err(db->dev, "insufficient resources\n");
ret = -ENOENT;
goto out;
}
@@ -460,7 +572,7 @@ dm9000_probe(struct platform_device *pdev)
pdev->name);
if (db->addr_req == NULL) {
- printk(KERN_ERR PFX "cannot claim address reg area\n");
+ dev_err(db->dev, "cannot claim address reg area\n");
ret = -EIO;
goto out;
}
@@ -468,7 +580,7 @@ dm9000_probe(struct platform_device *pdev)
db->io_addr = ioremap(db->addr_res->start, i);
if (db->io_addr == NULL) {
- printk(KERN_ERR "failed to ioremap address reg\n");
+ dev_err(db->dev, "failed to ioremap address reg\n");
ret = -EINVAL;
goto out;
}
@@ -478,7 +590,7 @@ dm9000_probe(struct platform_device *pdev)
pdev->name);
if (db->data_req == NULL) {
- printk(KERN_ERR PFX "cannot claim data reg area\n");
+ dev_err(db->dev, "cannot claim data reg area\n");
ret = -EIO;
goto out;
}
@@ -486,7 +598,7 @@ dm9000_probe(struct platform_device *pdev)
db->io_data = ioremap(db->data_res->start, iosize);
if (db->io_data == NULL) {
- printk(KERN_ERR "failed to ioremap data reg\n");
+ dev_err(db->dev,"failed to ioremap data reg\n");