linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Davicom DM9000C driver
@ 2012-09-19  5:58 Allen Huang (黃偉格)
  2012-09-19 16:39 ` Bruno Prémont
  2012-09-19 23:35 ` Jonathan Corbet
  0 siblings, 2 replies; 7+ messages in thread
From: Allen Huang (黃偉格) @ 2012-09-19  5:58 UTC (permalink / raw)
  To: linux-kernel
  Cc: 'Michael Chen', 'Charles', 'Joseph Chang'

[-- Attachment #1: Type: text/plain, Size: 275 bytes --]

Hi,

I'm Allen Huang from Davicom. We are hereby opensourcing the linux
driver for our DM9000C. 

We would appreciate any comments that you have on our driver and
whether it is ready to go into the kernel. Please see DM9000C driver in the
attachment.

Best regards, 

Allen


[-- Attachment #2: dm9000_KT2.6.31.c --]
[-- Type: application/octet-stream, Size: 38672 bytes --]

/*
 *      Davicom DM9000 Fast Ethernet driver for Linux.
 * 	Copyright (C) 1997  Sten Wang
 *
 * 	This program is free software; you can redistribute it and/or
 * 	modify it under the terms of the GNU General Public License
 * 	as published by the Free Software Foundation; either version 2
 * 	of the License, or (at your option) any later version.
 *
 * 	This program is distributed in the hope that it will be useful,
 * 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 	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.
 *
 * Additional updates, Copyright:
 *	Ben Dooks <ben@simtec.co.uk>
 *	Sascha Hauer <s.hauer@pengutronix.de>
 *  
 * 2010.07.20 V_R1 1.Write PHY Reg27 = 0xE100
 *								 2.Just enable PHY once after GPIO setting in dm9000_init_dm9000()
 *								 3.Remove power down PHY in dm9000_shutdown()
 * 2010.07.20 V_R2 1.Delay 20ms after PHY power on
 *								 2.Reset PHY after PHY power on in dm9000_init_dm9000()
 * 2012.06.05 KT2.6.31_R2 1. Add the solution to fix the power-on FIFO data bytes shift issue! (Wr NCR 0x03)
 */

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#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>
#include <linux/irq.h>

#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>

#include "dm9000.h"

/* Board/System/Debug information/definition ---------------- */

#define DM9000_PHY		0x40	/* PHY address 0x01 */

#define CARDNAME	"dm9000"
#define DRV_VERSION	"2.6.31"

/*
 * Transmit timeout, default 5 seconds.
 */
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.
 */

/* The driver supports the original DM9000E, and now the two newer
 * devices, DM9000A and DM9000B.
 */

enum dm9000_type {
	TYPE_DM9000E,	/* original DM9000 */
	TYPE_DM9000A,
	TYPE_DM9000B
};

/* Structure/enum declaration ------------------------------- */
typedef struct board_info {

	void __iomem	*io_addr;	/* Register I/O base address */
	void __iomem	*io_data;	/* Data I/O address */
	u16		 irq;		/* IRQ */

	u16		tx_pkt_cnt;
	u16		queue_pkt_len;
	u16		queue_start_addr;
	u16		dbug_cnt;
	u8		io_mode;		/* 0:word, 2:byte */
	u8		phy_addr;
	u8		imr_all;

	unsigned int	flags;
	unsigned int	in_suspend :1;
	int		debug_level;

	enum dm9000_type type;

	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 mutex	 addr_lock;	/* phy and eeprom access lock */

	struct delayed_work phy_poll;
	struct net_device  *ndev;

	spinlock_t	lock;

	struct mii_if_info mii;
	u32		msg_enable;
} board_info_t;

static void
dm9000_phy_write(struct net_device *dev,
		 int phyaddr_unused, int reg, int value);

/* 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 netdev_priv(dev);
}

/* DM9000 network board routine ---------------------------- */

static void
dm9000_reset(board_info_t * db)
{
	dev_dbg(db->dev, "resetting device\n");

	/* RESET device */
	writeb(DM9000_NCR, db->io_addr);
	udelay(200);
	writeb(NCR_RST, db->io_data);
	udelay(200);
}

/*
 *   Read a byte from I/O port
 */
static u8
ior(board_info_t * db, int reg)
{
	writeb(reg, db->io_addr);
	return readb(db->io_data);
}

/*
 *   Write a byte to I/O port
 */

static void
iow(board_info_t * db, int reg, int value)
{
	writeb(reg, db->io_addr);
	writeb(value, db->io_data);
}

/* routines for sending block to chip */

static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count)
{
	writesb(reg, data, count);
}

static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count)
{
	writesw(reg, data, (count+1) >> 1);
}

static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count)
{
	writesl(reg, data, (count+3) >> 2);
}

/* input block from chip to memory */

static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count)
{
	readsb(reg, data, count);
}


static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count)
{
	readsw(reg, data, (count+1) >> 1);
}

static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count)
{
	readsl(reg, data, (count+3) >> 2);
}

/* dump block from chip to null */

static void dm9000_dumpblk_8bit(void __iomem *reg, int count)
{
	int i;
	int tmp;

	for (i = 0; i < count; i++)
		tmp = readb(reg);
}

static void dm9000_dumpblk_16bit(void __iomem *reg, int count)
{
	int i;
	int tmp;

	count = (count + 1) >> 1;

	for (i = 0; i < count; i++)
		tmp = readw(reg);
}

static void dm9000_dumpblk_32bit(void __iomem *reg, int count)
{
	int i;
	int tmp;

	count = (count + 3) >> 2;

	for (i = 0; i < count; i++)
		tmp = readl(reg);
}

/* dm9000_set_io
 *
 * select the specified set of io routines to use with the
 * device
 */

static void dm9000_set_io(struct board_info *db, int byte_width)
{
	/* use the size of the data resource to work out what IO
	 * routines we want to use
	 */

	switch (byte_width) {
	case 1:
		db->dumpblk = dm9000_dumpblk_8bit;
		db->outblk  = dm9000_outblk_8bit;
		db->inblk   = dm9000_inblk_8bit;
		break;


	case 3:
		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;
		break;

	case 4:
	default:
		db->dumpblk = dm9000_dumpblk_32bit;
		db->outblk  = dm9000_outblk_32bit;
		db->inblk   = dm9000_inblk_32bit;
		break;
	}
}

static void dm9000_schedule_poll(board_info_t *db)
{
	if (db->type == TYPE_DM9000E)
		schedule_delayed_work(&db->phy_poll, HZ * 2);
}

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);
}

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;

		msleep(1);

		if (timeout-- < 0) {
			dev_dbg(db->dev, "timeout waiting EEPROM\n");
			break;
		}
	}

	return 0;
}

/*
 *  Read a word data from EEPROM
 */
static void
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);

	iow(db, DM9000_EPAR, offset);
	iow(db, DM9000_EPCR, EPCR_ERPRR);

	spin_unlock_irqrestore(&db->lock, flags);

	dm9000_wait_eeprom(db);

	/* delay for at-least 150uS */
	msleep(1);

	spin_lock_irqsave(&db->lock, flags);

	iow(db, DM9000_EPCR, 0x0);

	to[0] = ior(db, DM9000_EPDRL);
	to[1] = ior(db, DM9000_EPDRH);

	spin_unlock_irqrestore(&db->lock, flags);

	mutex_unlock(&db->addr_lock);
}

/*
 * Write a word data to SROM
 */
static void
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);
	iow(db, DM9000_EPAR, offset);
	iow(db, DM9000_EPDRH, data[1]);
	iow(db, DM9000_EPDRL, data[0]);
	iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
	spin_unlock_irqrestore(&db->lock, flags);

	dm9000_wait_eeprom(db);

	mdelay(1);	/* wait at least 150uS to clear */

	spin_lock_irqsave(&db->lock, flags);
	iow(db, DM9000_EPCR, 0);
	spin_unlock_irqrestore(&db->lock, flags);

	mutex_unlock(&db->addr_lock);
}

/* 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);
	u32 ret;

	if (dm->flags & DM9000_PLATF_EXT_PHY)
		ret = mii_link_ok(&dm->mii);
	else
		ret = dm9000_read_locked(dm, DM9000_NSR) & NSR_LINKST ? 1 : 0;

	return ret;
}

#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,
};

static void dm9000_show_carrier(board_info_t *db,
				unsigned carrier, unsigned nsr)
{
	struct net_device *ndev = db->ndev;
	unsigned ncr = dm9000_read_locked(db, DM9000_NCR);

	if (carrier)
		dev_info(db->dev, "%s: link up, %dMbps, %s-duplex, no LPA\n",
			 ndev->name, (nsr & NSR_SPEED) ? 10 : 100,
			 (ncr & NCR_FDX) ? "full" : "half");
	else
		dev_info(db->dev, "%s: link down\n", ndev->name);
}


static unsigned char dm9000_type_to_char(enum dm9000_type type)
{
	switch (type) {
	case TYPE_DM9000E: return 'e';
	case TYPE_DM9000A: return 'a';
	case TYPE_DM9000B: return 'b';
	}

	return '?';
}

static void
dm9000_poll_work(struct work_struct *w)
{
	struct delayed_work *dw = container_of(w, struct delayed_work, work);
	board_info_t *db = container_of(dw, board_info_t, phy_poll);
	struct net_device *ndev = db->ndev;

//JJ2
//	if (db->flags & DM9000_PLATF_SIMPLE_PHY &&
//	    !(db->flags & DM9000_PLATF_EXT_PHY)) {
//  =
		if(1){						
		unsigned nsr = dm9000_read_locked(db, DM9000_NSR);
		unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0;
		unsigned new_carrier;

		new_carrier = (nsr & NSR_LINKST) ? 1 : 0;

		if (old_carrier != new_carrier) {
			
			if (new_carrier)
			  printk(KERN_INFO "[dm9000%c %s Ethernet Driver, V%s]: Link-Up!!\n",dm9000_type_to_char(db->type), CARDNAME, DRV_VERSION); //JJ2
			else
			  printk(KERN_INFO "[%s Ethernet Driver, V%s]: Link-Down!!\n", CARDNAME, DRV_VERSION); //JJ2
			
			if (netif_msg_link(db))
				dm9000_show_carrier(db, new_carrier, nsr);

			if (!new_carrier)
				netif_carrier_off(ndev);
			else
				netif_carrier_on(ndev);
		}
	} else
		mii_check_media(&db->mii, netif_msg_link(db), 0);
	
	if (netif_running(ndev))
		dm9000_schedule_poll(db);
}

/* dm9000_release_board
 *
 * release a board, and any mapped resources
 */

static void
dm9000_release_board(struct platform_device *pdev, struct board_info *db)
{
	/* unmap our resources */

	iounmap(db->io_addr);
	iounmap(db->io_data);

	/* release the resources */

	release_resource(db->data_req);
	kfree(db->data_req);

	release_resource(db->addr_req);
	kfree(db->addr_req);
}



/*
 *  Set DM9000 multicast address
 */
static void
dm9000_hash_table(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	struct dev_mc_list *mcptr = dev->mc_list;
	int mc_cnt = dev->mc_count;
	int i, oft;
	u32 hash_val;
	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);

	for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
		iow(db, oft, dev->dev_addr[i]);

	/* Clear Hash Table */
	for (i = 0; i < 4; i++)
		hash_table[i] = 0x0;

	/* 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 = 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 = DM9000_MAR; i < 4; i++) {
		iow(db, oft++, hash_table[i]);
		iow(db, oft++, hash_table[i] >> 8);
	}

	iow(db, DM9000_RCR, rcr);
	spin_unlock_irqrestore(&db->lock, flags);
}

/*
 * Initilize dm9000 board
 */
static void
dm9000_init_dm9000(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	unsigned int imr;

	dm9000_dbg(db, 1, "entering %s\n", __func__);

	/* I/O mode */
	db->io_mode = ior(db, DM9000_ISR) >> 6;	/* ISR bit7:6 keeps I/O mode */

	/* GPIO0 on pre-activate PHY */
//V_R1	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */
	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */
	iow(db, DM9000_GPR, 0);	/* Enable PHY */
        mdelay(20);  //V_R2

	dm9000_phy_write(dev, 0, 0, 0x8000); //V_R2 reset PHY
        mdelay (20);


//	if (db->flags & DM9000_PLATF_EXT_PHY)
//		iow(db, DM9000_NCR, NCR_EXT_PHY);

	/* Program operating register */
	iow(db, DM9000_TCR, 0);	        /* TX Polling clear */
	iow(db, DM9000_BPTR, 0x3f);	/* Less 3Kb, 200us */
	iow(db, DM9000_FCR, 0xff);	/* Flow Control */
	iow(db, DM9000_SMCR, 0);        /* Special Mode */
	/* clear TX status */
	iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
	iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */

	/* Set address filter table */
	dm9000_hash_table(dev);

	imr = IMR_PAR | IMR_PTM | IMR_PRM;
	if (db->type != TYPE_DM9000E)
		imr |= IMR_LNKCHNG;

	db->imr_all = imr;

	/* Enable TX/RX interrupt mask */
	iow(db, DM9000_IMR, imr);

	/* Init Driver variable */
	db->tx_pkt_cnt = 0;
	db->queue_pkt_len = 0;
	dev->trans_start = 0;
	
	dm9000_phy_write(dev, 0, 27, 0xE100); //V_R1
}

/* Our watchdog timed out. Called by the networking layer */
static void dm9000_timeout(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	u8 reg_save;
	unsigned long flags;

	/* Save previous register address */
	reg_save = readb(db->io_addr);
	spin_lock_irqsave(&db->lock, flags);

	netif_stop_queue(dev);
	printk(KERN_INFO "[%s Ethernet Driver, V%s]: Timeout!!\n", CARDNAME, DRV_VERSION); //JJ1
	dm9000_reset(db);
	dm9000_init_dm9000(dev);
	/* We can accept TX packets again */
	dev->trans_start = jiffies;
	netif_wake_queue(dev);

	/* Restore previous register address */
	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock, flags);
}

/*
 *  Hardware start transmission.
 *  Send a packet to media from the upper layer.
 */
static int
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	unsigned long flags;
	board_info_t *db = netdev_priv(dev);

	dm9000_dbg(db, 3, "%s:\n", __func__);

	if (db->tx_pkt_cnt > 1)
		return 1;

	spin_lock_irqsave(&db->lock, flags);

	/* Move data to DM9000 TX RAM */
	writeb(DM9000_MWCMD, db->io_addr);

	(db->outblk)(db->io_data, skb->data, skb->len);
	dev->stats.tx_bytes += skb->len;

	db->tx_pkt_cnt++;
	/* 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);
		iow(db, DM9000_TXPLH, skb->len >> 8);

		/* Issue TX polling command */
		iow(db, DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */

		dev->trans_start = jiffies;	/* save the time stamp */
	} else {
		/* Second packet */
		db->queue_pkt_len = skb->len;
		netif_stop_queue(dev);
	}

	spin_unlock_irqrestore(&db->lock, flags);

	/* free this SKB */
	dev_kfree_skb(skb);

	return 0;
}

/*
 * DM9000 interrupt handler
 * receive the packet to upper layer, free the transmitted packet
 */

static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
	int tx_status = ior(db, DM9000_NSR);	/* Got TX status */

	if (tx_status & (NSR_TX2END | NSR_TX1END)) {
		/* One packet sent complete */
		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);
			iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
			iow(db, DM9000_TCR, TCR_TXREQ);
			dev->trans_start = jiffies;
		}
		netif_wake_queue(dev);
	}
}

struct dm9000_rxhdr {
	u8	RxPktReady;
	u8	RxStatus;
	__le16	RxLen;
} __attribute__((__packed__));

/*
 *  Received a packet and pass to upper layer
 */
static void
dm9000_rx(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	struct dm9000_rxhdr rxhdr;
	struct sk_buff *skb;
	u8 rxbyte, *rdptr;
	bool GoodPacket;
	int RxLen;

	/* Check packet ready or not */
	do {
		ior(db, DM9000_MRCMDX);	/* Dummy read */

		/* Get most updated data */
		rxbyte = readb(db->io_data);

		/* Status check: this byte must be 0 or 1 */
		if (rxbyte > DM9000_PKT_RDY) {
			dev_warn(db->dev, "status check fail: %d\n", rxbyte);
			iow(db, DM9000_RCR, 0x00);	/* Stop Device */
			iow(db, DM9000_ISR, IMR_PAR);	/* Stop INT request */
			return;
		}

		if (rxbyte != DM9000_PKT_RDY)
			return;

		/* A packet ready now  & Get status/length */
		GoodPacket = true;
		writeb(DM9000_MRCMD, db->io_addr);

		(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));

		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;
			if (netif_msg_rx_err(db))
				dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
		}

		if (RxLen > DM9000_PKT_MAX) {
			dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
		}

		/* rxhdr.RxStatus is identical to RSR register. */
		if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
				      RSR_PLE | RSR_RWTO |
				      RSR_LCS | RSR_RF)) {
			GoodPacket = false;
			if (rxhdr.RxStatus & RSR_FOE) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "fifo error\n");
				dev->stats.rx_fifo_errors++;
				printk(KERN_INFO "[%s Ethernet Driver, V%s]: FIFO Over Flow!!\n", CARDNAME, DRV_VERSION); //JJ1
			}
			if (rxhdr.RxStatus & RSR_CE) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "crc error\n");
				dev->stats.rx_crc_errors++;
			}
			if (rxhdr.RxStatus & RSR_RF) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "length error\n");
				dev->stats.rx_length_errors++;
			}
		}

		/* Move data from DM9000 */
		if (GoodPacket
		    && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
			skb_reserve(skb, 2);
			rdptr = (u8 *) skb_put(skb, RxLen - 4);

			/* Read received packet from RX SRAM */

			(db->inblk)(db->io_data, rdptr, RxLen);
			dev->stats.rx_bytes += RxLen;

			/* Pass to upper layer */
			skb->protocol = eth_type_trans(skb, dev);
			netif_rx(skb);
			dev->stats.rx_packets++;

		} else {
			/* need to dump the packet's data */

			(db->dumpblk)(db->io_data, RxLen);
		}
	} while (rxbyte == DM9000_PKT_RDY);
}

static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	board_info_t *db = netdev_priv(dev);
	int int_status;
	unsigned long flags;
	u8 reg_save;

	dm9000_dbg(db, 3, "entering %s\n", __func__);

	/* A real interrupt coming */

	/* holders of db->lock must always block IRQs */
	spin_lock_irqsave(&db->lock, flags);

	/* Save previous register address */
	reg_save = readb(db->io_addr);

	/* Disable all interrupts */
	iow(db, DM9000_IMR, IMR_PAR);

	/* Got DM9000 interrupt status */
	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);

	/* Trnasmit Interrupt check */
	if (int_status & ISR_PTS)
		dm9000_tx_done(dev, db);

	if (db->type != TYPE_DM9000E) {
		if (int_status & ISR_LNKCHNG) {
			/* fire a link-change request */
			schedule_delayed_work(&db->phy_poll, 1);
		}
	}

	/* Re-enable interrupt mask */
	iow(db, DM9000_IMR, db->imr_all);

	/* Restore previous register address */
	writeb(reg_save, db->io_addr);

	 spin_unlock_irqrestore(&db->lock, flags);

	return IRQ_HANDLED;
}

#ifdef CONFIG_NET_POLL_CONTROLLER
/*
 *Used by netconsole
 */
static void dm9000_poll_controller(struct net_device *dev)
{
	disable_irq(dev->irq);
	dm9000_interrupt(dev->irq, dev);
	enable_irq(dev->irq);
}
#endif

/*
 *  Open the interface.
 *  The interface is opened whenever "ifconfig" actives it.
 */
static int
dm9000_open(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

	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 */

	if (irqflags == IRQF_TRIGGER_NONE)
		dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");

	irqflags |= IRQF_SHARED;

	if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))
		return -EAGAIN;

	/* Initialize DM9000 board */
	dm9000_reset(db);
	dm9000_init_dm9000(dev);

	/* Init driver variable */
	db->dbug_cnt = 0;

	mii_check_media(&db->mii, netif_msg_link(db), 1);
	netif_start_queue(dev);
	
	dm9000_schedule_poll(db);

	return 0;
}

/*
 * Sleep, either by using msleep() or if we are suspending, then
 * use mdelay() to sleep.
 */
static void dm9000_msleep(board_info_t *db, unsigned int ms)
{
	if (db->in_suspend)
		mdelay(ms);
	else
		msleep(ms);
}

/*
 *   Read a word from phyxcer
 */
static int
dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
{
	board_info_t *db = netdev_priv(dev);
	unsigned long flags;
	unsigned int reg_save;
	int ret;

	mutex_lock(&db->addr_lock);

	spin_lock_irqsave(&db->lock,flags);

	/* Save previous register address */
	reg_save = readb(db->io_addr);

	/* Fill the phyxcer register into REG_0C */
	iow(db, DM9000_EPAR, DM9000_PHY | reg);

	iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);	/* Issue phyxcer read command */

	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock,flags);

	dm9000_msleep(db, 1);		/* Wait read complete */

	spin_lock_irqsave(&db->lock,flags);
	reg_save = readb(db->io_addr);

	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer read command */

	/* The read data keeps on REG_0D & REG_0E */
	ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);

	/* restore the previous address */
	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock,flags);

	mutex_unlock(&db->addr_lock);

	dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
	return ret;
}

/*
 *   Write a word to phyxcer
 */
static void
dm9000_phy_write(struct net_device *dev,
		 int phyaddr_unused, int reg, int value)
{
	board_info_t *db = netdev_priv(dev);
	unsigned long flags;
	unsigned long reg_save;

	dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
	mutex_lock(&db->addr_lock);

	spin_lock_irqsave(&db->lock,flags);

	/* Save previous register address */
	reg_save = readb(db->io_addr);

	/* Fill the phyxcer register into REG_0C */
	iow(db, DM9000_EPAR, DM9000_PHY | reg);

	/* Fill the written data into REG_0D & REG_0E */
	iow(db, DM9000_EPDRL, value);
	iow(db, DM9000_EPDRH, value >> 8);

	iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW);	/* Issue phyxcer write command */

	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock, flags);

	dm9000_msleep(db, 1);		/* Wait write complete */

	spin_lock_irqsave(&db->lock,flags);
	reg_save = readb(db->io_addr);

	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer write command */

	/* restore the previous address */
	writeb(reg_save, db->io_addr);

	spin_unlock_irqrestore(&db->lock, flags);
	mutex_unlock(&db->addr_lock);
}

static void
dm9000_shutdown(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);

	/* RESET device */
	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);	/* PHY RESET */
//V_R1	iow(db, DM9000_GPR, 0x01);	/* Power-Down PHY */
	iow(db, DM9000_IMR, IMR_PAR);	/* Disable all interrupt */
	iow(db, DM9000_RCR, 0x00);	/* Disable RX */
}

/*
 * Stop the interface.
 * The interface is stopped when it is brought.
 */
static int
dm9000_stop(struct net_device *ndev)
{
	board_info_t *db = netdev_priv(ndev);

	if (netif_msg_ifdown(db))
		dev_dbg(db->dev, "shutting down %s\n", ndev->name);

	cancel_delayed_work_sync(&db->phy_poll);

	netif_stop_queue(ndev);
	netif_carrier_off(ndev);

	/* free interrupt */
	free_irq(ndev->irq, ndev);

	dm9000_shutdown(ndev);

	return 0;
}

#define res_size(_r) (((_r)->end - (_r)->start) + 1)

static const struct net_device_ops dm9000_netdev_ops = {
         .ndo_open = dm9000_open,
         .ndo_stop = dm9000_stop,
         .ndo_start_xmit = dm9000_start_xmit,
         .ndo_tx_timeout = dm9000_timeout,
         .ndo_set_multicast_list = dm9000_hash_table,
         .ndo_do_ioctl = dm9000_ioctl,
         .ndo_change_mtu = eth_change_mtu,
         .ndo_validate_addr = eth_validate_addr,
         .ndo_set_mac_address = eth_mac_addr,
    #ifdef CONFIG_NET_POLL_CONTROLLER
         .ndo_poll_controller = dm9000_poll_controller,
    #endif
};


/*
 * Search DM9000 board, allocate space and register it
 */
static int __devinit
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;
	int ret = 0;
	int iosize;
	int i;
	u32 id_val;

	/* Init network device */
	ndev = alloc_etherdev(sizeof(struct board_info));
	if (!ndev) {
		dev_err(&pdev->dev, "could not allocate device.\n");
		return -ENOMEM;
	}

	SET_NETDEV_DEV(ndev, &pdev->dev);

	dev_dbg(&pdev->dev, "dm9000_probe()\n");
	 ndev->netdev_ops = &dm9000_netdev_ops;
	/* setup board info structure */
	db = netdev_priv(ndev);
	memset(db, 0, sizeof(*db));

	db->dev = &pdev->dev;
	db->ndev = ndev;

	spin_lock_init(&db->lock);
	mutex_init(&db->addr_lock);

	INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);

	db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

	if (db->addr_res == NULL || db->data_res == NULL ||
	    db->irq_res == NULL) {
		dev_err(db->dev, "insufficient resources\n");
		ret = -ENOENT;
		goto out;
	}

	iosize = res_size(db->addr_res);
	db->addr_req = request_mem_region(db->addr_res->start, iosize,
					  pdev->name);

	if (db->addr_req == NULL) {
		dev_err(db->dev, "cannot claim address reg area\n");
		ret = -EIO;
		goto out;
	}

	db->io_addr = ioremap(db->addr_res->start, iosize);

	if (db->io_addr == NULL) {
		dev_err(db->dev, "failed to ioremap address reg\n");
		ret = -EINVAL;
		goto out;
	}

	iosize = res_size(db->data_res);
	db->data_req = request_mem_region(db->data_res->start, iosize,
					  pdev->name);

	if (db->data_req == NULL) {
		dev_err(db->dev, "cannot claim data reg area\n");
		ret = -EIO;
		goto out;
	}

	db->io_data = ioremap(db->data_res->start, iosize);

	if (db->io_data == NULL) {
		dev_err(db->dev, "failed to ioremap data reg\n");
		ret = -EINVAL;
		goto out;
	}

	/* fill in parameters for net-dev structure */
	ndev->base_addr = (unsigned long)db->io_addr;
	ndev->irq	= db->irq_res->start;
	//Stone add
	printk("[dm9] %s ndev->irq=%x \n",__func__,ndev->irq);

	/* ensure at least we have a default set of IO routines */
	dm9000_set_io(db, iosize);

	/* check to see if anything is being over-ridden */
	if (pdata != NULL) {
		/* check to see if the driver wants to over-ride the
		 * default IO width */

		if (pdata->flags & DM9000_PLATF_8BITONLY)
			dm9000_set_io(db, 1);

		if (pdata->flags & DM9000_PLATF_16BITONLY)
			dm9000_set_io(db, 2);

		if (pdata->flags & DM9000_PLATF_32BITONLY)
			dm9000_set_io(db, 4);

		/* check to see if there are any IO routine
		 * over-rides */

		if (pdata->inblk != NULL)
			db->inblk = pdata->inblk;

		if (pdata->outblk != NULL)
			db->outblk = pdata->outblk;

		if (pdata->dumpblk != NULL)
			db->dumpblk = pdata->dumpblk;

		db->flags = pdata->flags;
	}

#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
	db->flags |= DM9000_PLATF_SIMPLE_PHY;
#endif

//Stone add
//	dm9000_reset(db);
  iow(db, DM9000_NCR, 0x03);

	/* try multiple times, DM9000 sometimes gets the read wrong */
	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;
		id_val |= (u32)ior(db, DM9000_PIDH) << 24;

		printk("[dm9].%d read id 0x%08x\n", i+1, id_val);
		
		if (id_val == DM9000_ID)
			break;
		dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
	}
	
	printk(KERN_INFO "[%s Ethernet Driver, V%s]: KV= %d.%d.%d !!\n", CARDNAME, DRV_VERSION,  //JJ1 
	                            (LINUX_VERSION_CODE>>16 & 0xff),
	                            (LINUX_VERSION_CODE>>8 & 0xff),
	                            (LINUX_VERSION_CODE & 0xff) ); //#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
	printk(KERN_INFO "[%s Ethernet Driver, V%s]: ChipID= 0x%x !!\n", CARDNAME, DRV_VERSION, id_val ); // JJ1

	if (id_val != DM9000_ID) {
		dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
		ret = -ENODEV;
		goto out;
	}

	/* Identify what type of DM9000 we are working on */

	id_val = ior(db, DM9000_CHIPR);
	dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);
	printk(KERN_INFO "[DM9000]dm9000 revision 0x%02x\n", id_val); //V_R1

	switch (id_val) {
	case CHIPR_DM9000A:
		db->type = TYPE_DM9000A;
		break;
	case CHIPR_DM9000B:
		db->type = TYPE_DM9000B;
		break;
	default:
		dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
		db->type = TYPE_DM9000E;
	}

	/* from this point we assume that we have found a DM9000 */

	/* driver system function */
	ether_setup(ndev);
	
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
			ndev->netdev_ops = &dm9000_netdev_ops; // new kernel 2.6.31 
			ndev->watchdog_timeo	= msecs_to_jiffies(watchdog);	
	 		ndev->ethtool_ops	 = &dm9000_ethtool_ops;
#else
	ndev->open		 = &dm9000_open;
	ndev->hard_start_xmit    = &dm9000_start_xmit;
	ndev->tx_timeout         = &dm9000_timeout;
	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
	ndev->stop		 = &dm9000_stop;
	ndev->set_multicast_list = &dm9000_hash_table;
	ndev->ethtool_ops	 = &dm9000_ethtool_ops;
	ndev->do_ioctl		 = &dm9000_ioctl;
#endif


#ifdef CONFIG_NET_POLL_CONTROLLER
	ndev->poll_controller	 = &dm9000_poll_controller;
#endif

	db->msg_enable       = NETIF_MSG_LINK;
	db->mii.phy_id_mask  = 0x1f;
	db->mii.reg_num_mask = 0x1f;
	db->mii.force_media  = 0;
	db->mii.full_duplex  = 0;
	db->mii.dev	     = ndev;
	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) && pdata != NULL) {
		mac_src = "platform data";
		memcpy(ndev->dev_addr, pdata->dev_addr, 6);
	}

	if (!is_valid_ether_addr(ndev->dev_addr)) {
		/* try reading from mac */
		
		mac_src = "chip";

		static unsigned char mac_addr[6] = {0x00,0x11,0x22,0x33,0x44,0x55};
		static unsigned char mac_tmp[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
		for (i = 0; i < 6; i++)
			ndev->dev_addr[i] = ior(db, i+DM9000_PAR);

		// Mark Chang 20100521
		// -------------------
		if (!memcmp(ndev->dev_addr, mac_tmp, 6))
			memcpy(ndev->dev_addr, mac_addr, 6);
	}

	if (!is_valid_ether_addr(ndev->dev_addr))
		dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
			 "set using ifconfig\n", ndev->name);

	platform_set_drvdata(pdev, ndev);
	ret = register_netdev(ndev);

	if (ret == 0)
		printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
		       ndev->name, dm9000_type_to_char(db->type),
		       db->io_addr, db->io_data, ndev->irq,
		       ndev->dev_addr, mac_src);
	return 0;

out:
	dev_err(db->dev, "not found (%d).\n", ret);

	dm9000_release_board(pdev, db);
	free_netdev(ndev);

	return ret;
}

static int
dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	board_info_t *db;

	if (ndev) {
		db = netdev_priv(ndev);
		db->in_suspend = 1;

		if (netif_running(ndev)) {
			netif_device_detach(ndev);
			dm9000_shutdown(ndev);
		}
	}
	return 0;
}

static int
dm9000_drv_resume(struct platform_device *dev)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	board_info_t *db = netdev_priv(ndev);

	if (ndev) {

		if (netif_running(ndev)) {
			dm9000_reset(db);
			dm9000_init_dm9000(ndev);

			netif_device_attach(ndev);
		}

		db->in_suspend = 0;
	}
	return 0;
}

static int __devexit
dm9000_drv_remove(struct platform_device *pdev)
{
	struct net_device *ndev = platform_get_drvdata(pdev);

	platform_set_drvdata(pdev, NULL);

	unregister_netdev(ndev);
	dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev));
	free_netdev(ndev);		/* free device structure */

	dev_dbg(&pdev->dev, "released and freed device\n");
	return 0;
}

static struct platform_driver dm9000_driver = {
	.driver	= {
		.name    = "dm9000",
		.owner	 = THIS_MODULE,
	},
	.probe   = dm9000_probe,
	.remove  = __devexit_p(dm9000_drv_remove),
	.suspend = dm9000_drv_suspend,
	.resume  = dm9000_drv_resume,
};

static int __init
dm9000_init(void)
{
	printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);

	return platform_driver_register(&dm9000_driver);
}

static void __exit
dm9000_cleanup(void)
{
	platform_driver_unregister(&dm9000_driver);
}

module_init(dm9000_init);
module_exit(dm9000_cleanup);

MODULE_AUTHOR("Sascha Hauer, Ben Dooks");
MODULE_DESCRIPTION("Davicom DM9000 network driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dm9000");

[-- Attachment #3: dm9000_KT2.6.31.h --]
[-- Type: application/octet-stream, Size: 4326 bytes --]

/*
 * dm9000 Ethernet
 */

#ifndef _DM9000X_H_
#define _DM9000X_H_

#define DM9000_ID		0x90000A46

/* although the registers are 16 bit, they are 32-bit aligned.
 */

#define DM9000_NCR             0x00
#define DM9000_NSR             0x01
#define DM9000_TCR             0x02
#define DM9000_TSR1            0x03
#define DM9000_TSR2            0x04
#define DM9000_RCR             0x05
#define DM9000_RSR             0x06
#define DM9000_ROCR            0x07
#define DM9000_BPTR            0x08
#define DM9000_FCTR            0x09
#define DM9000_FCR             0x0A
#define DM9000_EPCR            0x0B
#define DM9000_EPAR            0x0C
#define DM9000_EPDRL           0x0D
#define DM9000_EPDRH           0x0E
#define DM9000_WCR             0x0F

#define DM9000_PAR             0x10
#define DM9000_MAR             0x16

#define DM9000_GPCR	       0x1e
#define DM9000_GPR             0x1f
#define DM9000_TRPAL           0x22
#define DM9000_TRPAH           0x23
#define DM9000_RWPAL           0x24
#define DM9000_RWPAH           0x25

#define DM9000_VIDL            0x28
#define DM9000_VIDH            0x29
#define DM9000_PIDL            0x2A
#define DM9000_PIDH            0x2B

#define DM9000_CHIPR           0x2C
#define DM9000_SMCR            0x2F

#define CHIPR_DM9000A	       0x19
#define CHIPR_DM9000B	       0x1A  //V_R1 0x1B

#define DM9000_MRCMDX          0xF0
#define DM9000_MRCMD           0xF2
#define DM9000_MRRL            0xF4
#define DM9000_MRRH            0xF5
#define DM9000_MWCMDX          0xF6
#define DM9000_MWCMD           0xF8
#define DM9000_MWRL            0xFA
#define DM9000_MWRH            0xFB
#define DM9000_TXPLL           0xFC
#define DM9000_TXPLH           0xFD
#define DM9000_ISR             0xFE
#define DM9000_IMR             0xFF

#define NCR_EXT_PHY         (1<<7)
#define NCR_WAKEEN          (1<<6)
#define NCR_FCOL            (1<<4)
#define NCR_FDX             (1<<3)
#define NCR_LBK             (3<<1)
#define NCR_RST	            (1<<0)

#define NSR_SPEED           (1<<7)
#define NSR_LINKST          (1<<6)
#define NSR_WAKEST          (1<<5)
#define NSR_TX2END          (1<<3)
#define NSR_TX1END          (1<<2)
#define NSR_RXOV            (1<<1)

#define TCR_TJDIS           (1<<6)
#define TCR_EXCECM          (1<<5)
#define TCR_PAD_DIS2        (1<<4)
#define TCR_CRC_DIS2        (1<<3)
#define TCR_PAD_DIS1        (1<<2)
#define TCR_CRC_DIS1        (1<<1)
#define TCR_TXREQ           (1<<0)

#define TSR_TJTO            (1<<7)
#define TSR_LC              (1<<6)
#define TSR_NC              (1<<5)
#define TSR_LCOL            (1<<4)
#define TSR_COL             (1<<3)
#define TSR_EC              (1<<2)

#define RCR_WTDIS           (1<<6)
#define RCR_DIS_LONG        (1<<5)
#define RCR_DIS_CRC         (1<<4)
#define RCR_ALL	            (1<<3)
#define RCR_RUNT            (1<<2)
#define RCR_PRMSC           (1<<1)
#define RCR_RXEN            (1<<0)

#define RSR_RF              (1<<7)
#define RSR_MF              (1<<6)
#define RSR_LCS             (1<<5)
#define RSR_RWTO            (1<<4)
#define RSR_PLE             (1<<3)
#define RSR_AE              (1<<2)
#define RSR_CE              (1<<1)
#define RSR_FOE             (1<<0)

#define FCTR_HWOT(ot)	(( ot & 0xf ) << 4 )
#define FCTR_LWOT(ot)	( ot & 0xf )

#define IMR_PAR             (1<<7)
#define IMR_ROOM            (1<<3)
#define IMR_ROM             (1<<2)
#define IMR_PTM             (1<<1)
#define IMR_PRM             (1<<0)

#define ISR_ROOS            (1<<3)
#define ISR_ROS             (1<<2)
#define ISR_PTS             (1<<1)
#define ISR_PRS             (1<<0)
#define ISR_CLR_STATUS      (ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS)

#define EPCR_REEP           (1<<5)
#define EPCR_WEP            (1<<4)
#define EPCR_EPOS           (1<<3)
#define EPCR_ERPRR          (1<<2)
#define EPCR_ERPRW          (1<<1)
#define EPCR_ERRE           (1<<0)

#define GPCR_GEP_CNTL       (1<<0)

#define DM9000_PKT_RDY		0x01	/* Packet ready to receive */
#define DM9000_PKT_MAX		1536	/* Received packet max size */

/* DM9000A / DM9000B definitions */

#define IMR_LNKCHNG		(1<<5)
#define IMR_UNDERRUN		(1<<4)

#define ISR_LNKCHNG		(1<<5)
#define ISR_UNDERRUN		(1<<4)

#endif /* _DM9000X_H_ */


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Davicom DM9000C driver
  2012-09-19  5:58 Davicom DM9000C driver Allen Huang (黃偉格)
@ 2012-09-19 16:39 ` Bruno Prémont
  2012-09-19 23:35 ` Jonathan Corbet
  1 sibling, 0 replies; 7+ messages in thread
From: Bruno Prémont @ 2012-09-19 16:39 UTC (permalink / raw)
  To: Allen Huang
  Cc: linux-kernel, 'Michael Chen', 'Charles',
	'Joseph Chang',
	Linux network list

[-- Attachment #1: Type: text/plain, Size: 1252 bytes --]

Hi Allen,

[CCing netdev, keeping .c/.h source attached]

On Wed, 19 September 2012 Allen Huang (黃偉格)  <allen_huang@davicom.com.tw> wrote:
> I'm Allen Huang from Davicom. We are hereby opensourcing the linux
> driver for our DM9000C. 

Ah, from looking at the code DM9000C looks like it is some nerwork chip,
what platforms does it show up on?

> We would appreciate any comments that you have on our driver and
> whether it is ready to go into the kernel. Please see DM9000C driver in the
> attachment.

It would be nice if you could include the changes to Kconfig/Makefile
including a description as it's not clear on what kind of devices the
chip can be encountered.

Also please properly tag the source files attachments as text/plain.


With a quick glance at the code:
- your comments are often single-line C++ style //
  and should be changed to /*  */.

- comments that look like author/revision tags

- there are blocks of code commented or inside if (1) {}

- some printk calls missing KERN_ severity tag

- indentation issues


Please fix above issues (and have a look at scripts/checkpatch.pl) and
respin (as a patch) taking care to CC netdev so network people have to
chance to see it.

Bruno

[-- Attachment #2: dm9000_KT2.6.31.c --]
[-- Type: text/plain, Size: 37105 bytes --]

/*
 *      Davicom DM9000 Fast Ethernet driver for Linux.
 * 	Copyright (C) 1997  Sten Wang
 *
 * 	This program is free software; you can redistribute it and/or
 * 	modify it under the terms of the GNU General Public License
 * 	as published by the Free Software Foundation; either version 2
 * 	of the License, or (at your option) any later version.
 *
 * 	This program is distributed in the hope that it will be useful,
 * 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 	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.
 *
 * Additional updates, Copyright:
 *	Ben Dooks <ben@simtec.co.uk>
 *	Sascha Hauer <s.hauer@pengutronix.de>
 *  
 * 2010.07.20 V_R1 1.Write PHY Reg27 = 0xE100
 *								 2.Just enable PHY once after GPIO setting in dm9000_init_dm9000()
 *								 3.Remove power down PHY in dm9000_shutdown()
 * 2010.07.20 V_R2 1.Delay 20ms after PHY power on
 *								 2.Reset PHY after PHY power on in dm9000_init_dm9000()
 * 2012.06.05 KT2.6.31_R2 1. Add the solution to fix the power-on FIFO data bytes shift issue! (Wr NCR 0x03)
 */

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#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>
#include <linux/irq.h>

#include <asm/delay.h>
#include <asm/irq.h>
#include <asm/io.h>

#include "dm9000.h"

/* Board/System/Debug information/definition ---------------- */

#define DM9000_PHY		0x40	/* PHY address 0x01 */

#define CARDNAME	"dm9000"
#define DRV_VERSION	"2.6.31"

/*
 * Transmit timeout, default 5 seconds.
 */
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.
 */

/* The driver supports the original DM9000E, and now the two newer
 * devices, DM9000A and DM9000B.
 */

enum dm9000_type {
	TYPE_DM9000E,	/* original DM9000 */
	TYPE_DM9000A,
	TYPE_DM9000B
};

/* Structure/enum declaration ------------------------------- */
typedef struct board_info {

	void __iomem	*io_addr;	/* Register I/O base address */
	void __iomem	*io_data;	/* Data I/O address */
	u16		 irq;		/* IRQ */

	u16		tx_pkt_cnt;
	u16		queue_pkt_len;
	u16		queue_start_addr;
	u16		dbug_cnt;
	u8		io_mode;		/* 0:word, 2:byte */
	u8		phy_addr;
	u8		imr_all;

	unsigned int	flags;
	unsigned int	in_suspend :1;
	int		debug_level;

	enum dm9000_type type;

	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 mutex	 addr_lock;	/* phy and eeprom access lock */

	struct delayed_work phy_poll;
	struct net_device  *ndev;

	spinlock_t	lock;

	struct mii_if_info mii;
	u32		msg_enable;
} board_info_t;

static void
dm9000_phy_write(struct net_device *dev,
		 int phyaddr_unused, int reg, int value);

/* 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 netdev_priv(dev);
}

/* DM9000 network board routine ---------------------------- */

static void
dm9000_reset(board_info_t * db)
{
	dev_dbg(db->dev, "resetting device\n");

	/* RESET device */
	writeb(DM9000_NCR, db->io_addr);
	udelay(200);
	writeb(NCR_RST, db->io_data);
	udelay(200);
}

/*
 *   Read a byte from I/O port
 */
static u8
ior(board_info_t * db, int reg)
{
	writeb(reg, db->io_addr);
	return readb(db->io_data);
}

/*
 *   Write a byte to I/O port
 */

static void
iow(board_info_t * db, int reg, int value)
{
	writeb(reg, db->io_addr);
	writeb(value, db->io_data);
}

/* routines for sending block to chip */

static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count)
{
	writesb(reg, data, count);
}

static void dm9000_outblk_16bit(void __iomem *reg, void *data, int count)
{
	writesw(reg, data, (count+1) >> 1);
}

static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count)
{
	writesl(reg, data, (count+3) >> 2);
}

/* input block from chip to memory */

static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count)
{
	readsb(reg, data, count);
}


static void dm9000_inblk_16bit(void __iomem *reg, void *data, int count)
{
	readsw(reg, data, (count+1) >> 1);
}

static void dm9000_inblk_32bit(void __iomem *reg, void *data, int count)
{
	readsl(reg, data, (count+3) >> 2);
}

/* dump block from chip to null */

static void dm9000_dumpblk_8bit(void __iomem *reg, int count)
{
	int i;
	int tmp;

	for (i = 0; i < count; i++)
		tmp = readb(reg);
}

static void dm9000_dumpblk_16bit(void __iomem *reg, int count)
{
	int i;
	int tmp;

	count = (count + 1) >> 1;

	for (i = 0; i < count; i++)
		tmp = readw(reg);
}

static void dm9000_dumpblk_32bit(void __iomem *reg, int count)
{
	int i;
	int tmp;

	count = (count + 3) >> 2;

	for (i = 0; i < count; i++)
		tmp = readl(reg);
}

/* dm9000_set_io
 *
 * select the specified set of io routines to use with the
 * device
 */

static void dm9000_set_io(struct board_info *db, int byte_width)
{
	/* use the size of the data resource to work out what IO
	 * routines we want to use
	 */

	switch (byte_width) {
	case 1:
		db->dumpblk = dm9000_dumpblk_8bit;
		db->outblk  = dm9000_outblk_8bit;
		db->inblk   = dm9000_inblk_8bit;
		break;


	case 3:
		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;
		break;

	case 4:
	default:
		db->dumpblk = dm9000_dumpblk_32bit;
		db->outblk  = dm9000_outblk_32bit;
		db->inblk   = dm9000_inblk_32bit;
		break;
	}
}

static void dm9000_schedule_poll(board_info_t *db)
{
	if (db->type == TYPE_DM9000E)
		schedule_delayed_work(&db->phy_poll, HZ * 2);
}

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);
}

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;

		msleep(1);

		if (timeout-- < 0) {
			dev_dbg(db->dev, "timeout waiting EEPROM\n");
			break;
		}
	}

	return 0;
}

/*
 *  Read a word data from EEPROM
 */
static void
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);

	iow(db, DM9000_EPAR, offset);
	iow(db, DM9000_EPCR, EPCR_ERPRR);

	spin_unlock_irqrestore(&db->lock, flags);

	dm9000_wait_eeprom(db);

	/* delay for at-least 150uS */
	msleep(1);

	spin_lock_irqsave(&db->lock, flags);

	iow(db, DM9000_EPCR, 0x0);

	to[0] = ior(db, DM9000_EPDRL);
	to[1] = ior(db, DM9000_EPDRH);

	spin_unlock_irqrestore(&db->lock, flags);

	mutex_unlock(&db->addr_lock);
}

/*
 * Write a word data to SROM
 */
static void
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);
	iow(db, DM9000_EPAR, offset);
	iow(db, DM9000_EPDRH, data[1]);
	iow(db, DM9000_EPDRL, data[0]);
	iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
	spin_unlock_irqrestore(&db->lock, flags);

	dm9000_wait_eeprom(db);

	mdelay(1);	/* wait at least 150uS to clear */

	spin_lock_irqsave(&db->lock, flags);
	iow(db, DM9000_EPCR, 0);
	spin_unlock_irqrestore(&db->lock, flags);

	mutex_unlock(&db->addr_lock);
}

/* 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);
	u32 ret;

	if (dm->flags & DM9000_PLATF_EXT_PHY)
		ret = mii_link_ok(&dm->mii);
	else
		ret = dm9000_read_locked(dm, DM9000_NSR) & NSR_LINKST ? 1 : 0;

	return ret;
}

#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,
};

static void dm9000_show_carrier(board_info_t *db,
				unsigned carrier, unsigned nsr)
{
	struct net_device *ndev = db->ndev;
	unsigned ncr = dm9000_read_locked(db, DM9000_NCR);

	if (carrier)
		dev_info(db->dev, "%s: link up, %dMbps, %s-duplex, no LPA\n",
			 ndev->name, (nsr & NSR_SPEED) ? 10 : 100,
			 (ncr & NCR_FDX) ? "full" : "half");
	else
		dev_info(db->dev, "%s: link down\n", ndev->name);
}


static unsigned char dm9000_type_to_char(enum dm9000_type type)
{
	switch (type) {
	case TYPE_DM9000E: return 'e';
	case TYPE_DM9000A: return 'a';
	case TYPE_DM9000B: return 'b';
	}

	return '?';
}

static void
dm9000_poll_work(struct work_struct *w)
{
	struct delayed_work *dw = container_of(w, struct delayed_work, work);
	board_info_t *db = container_of(dw, board_info_t, phy_poll);
	struct net_device *ndev = db->ndev;

//JJ2
//	if (db->flags & DM9000_PLATF_SIMPLE_PHY &&
//	    !(db->flags & DM9000_PLATF_EXT_PHY)) {
//  =
		if(1){						
		unsigned nsr = dm9000_read_locked(db, DM9000_NSR);
		unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0;
		unsigned new_carrier;

		new_carrier = (nsr & NSR_LINKST) ? 1 : 0;

		if (old_carrier != new_carrier) {
			
			if (new_carrier)
			  printk(KERN_INFO "[dm9000%c %s Ethernet Driver, V%s]: Link-Up!!\n",dm9000_type_to_char(db->type), CARDNAME, DRV_VERSION); //JJ2
			else
			  printk(KERN_INFO "[%s Ethernet Driver, V%s]: Link-Down!!\n", CARDNAME, DRV_VERSION); //JJ2
			
			if (netif_msg_link(db))
				dm9000_show_carrier(db, new_carrier, nsr);

			if (!new_carrier)
				netif_carrier_off(ndev);
			else
				netif_carrier_on(ndev);
		}
	} else
		mii_check_media(&db->mii, netif_msg_link(db), 0);
	
	if (netif_running(ndev))
		dm9000_schedule_poll(db);
}

/* dm9000_release_board
 *
 * release a board, and any mapped resources
 */

static void
dm9000_release_board(struct platform_device *pdev, struct board_info *db)
{
	/* unmap our resources */

	iounmap(db->io_addr);
	iounmap(db->io_data);

	/* release the resources */

	release_resource(db->data_req);
	kfree(db->data_req);

	release_resource(db->addr_req);
	kfree(db->addr_req);
}



/*
 *  Set DM9000 multicast address
 */
static void
dm9000_hash_table(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	struct dev_mc_list *mcptr = dev->mc_list;
	int mc_cnt = dev->mc_count;
	int i, oft;
	u32 hash_val;
	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);

	for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
		iow(db, oft, dev->dev_addr[i]);

	/* Clear Hash Table */
	for (i = 0; i < 4; i++)
		hash_table[i] = 0x0;

	/* 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 = 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 = DM9000_MAR; i < 4; i++) {
		iow(db, oft++, hash_table[i]);
		iow(db, oft++, hash_table[i] >> 8);
	}

	iow(db, DM9000_RCR, rcr);
	spin_unlock_irqrestore(&db->lock, flags);
}

/*
 * Initilize dm9000 board
 */
static void
dm9000_init_dm9000(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	unsigned int imr;

	dm9000_dbg(db, 1, "entering %s\n", __func__);

	/* I/O mode */
	db->io_mode = ior(db, DM9000_ISR) >> 6;	/* ISR bit7:6 keeps I/O mode */

	/* GPIO0 on pre-activate PHY */
//V_R1	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */
	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */
	iow(db, DM9000_GPR, 0);	/* Enable PHY */
        mdelay(20);  //V_R2

	dm9000_phy_write(dev, 0, 0, 0x8000); //V_R2 reset PHY
        mdelay (20);


//	if (db->flags & DM9000_PLATF_EXT_PHY)
//		iow(db, DM9000_NCR, NCR_EXT_PHY);

	/* Program operating register */
	iow(db, DM9000_TCR, 0);	        /* TX Polling clear */
	iow(db, DM9000_BPTR, 0x3f);	/* Less 3Kb, 200us */
	iow(db, DM9000_FCR, 0xff);	/* Flow Control */
	iow(db, DM9000_SMCR, 0);        /* Special Mode */
	/* clear TX status */
	iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
	iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */

	/* Set address filter table */
	dm9000_hash_table(dev);

	imr = IMR_PAR | IMR_PTM | IMR_PRM;
	if (db->type != TYPE_DM9000E)
		imr |= IMR_LNKCHNG;

	db->imr_all = imr;

	/* Enable TX/RX interrupt mask */
	iow(db, DM9000_IMR, imr);

	/* Init Driver variable */
	db->tx_pkt_cnt = 0;
	db->queue_pkt_len = 0;
	dev->trans_start = 0;
	
	dm9000_phy_write(dev, 0, 27, 0xE100); //V_R1
}

/* Our watchdog timed out. Called by the networking layer */
static void dm9000_timeout(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	u8 reg_save;
	unsigned long flags;

	/* Save previous register address */
	reg_save = readb(db->io_addr);
	spin_lock_irqsave(&db->lock, flags);

	netif_stop_queue(dev);
	printk(KERN_INFO "[%s Ethernet Driver, V%s]: Timeout!!\n", CARDNAME, DRV_VERSION); //JJ1
	dm9000_reset(db);
	dm9000_init_dm9000(dev);
	/* We can accept TX packets again */
	dev->trans_start = jiffies;
	netif_wake_queue(dev);

	/* Restore previous register address */
	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock, flags);
}

/*
 *  Hardware start transmission.
 *  Send a packet to media from the upper layer.
 */
static int
dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	unsigned long flags;
	board_info_t *db = netdev_priv(dev);

	dm9000_dbg(db, 3, "%s:\n", __func__);

	if (db->tx_pkt_cnt > 1)
		return 1;

	spin_lock_irqsave(&db->lock, flags);

	/* Move data to DM9000 TX RAM */
	writeb(DM9000_MWCMD, db->io_addr);

	(db->outblk)(db->io_data, skb->data, skb->len);
	dev->stats.tx_bytes += skb->len;

	db->tx_pkt_cnt++;
	/* 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);
		iow(db, DM9000_TXPLH, skb->len >> 8);

		/* Issue TX polling command */
		iow(db, DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */

		dev->trans_start = jiffies;	/* save the time stamp */
	} else {
		/* Second packet */
		db->queue_pkt_len = skb->len;
		netif_stop_queue(dev);
	}

	spin_unlock_irqrestore(&db->lock, flags);

	/* free this SKB */
	dev_kfree_skb(skb);

	return 0;
}

/*
 * DM9000 interrupt handler
 * receive the packet to upper layer, free the transmitted packet
 */

static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
{
	int tx_status = ior(db, DM9000_NSR);	/* Got TX status */

	if (tx_status & (NSR_TX2END | NSR_TX1END)) {
		/* One packet sent complete */
		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);
			iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
			iow(db, DM9000_TCR, TCR_TXREQ);
			dev->trans_start = jiffies;
		}
		netif_wake_queue(dev);
	}
}

struct dm9000_rxhdr {
	u8	RxPktReady;
	u8	RxStatus;
	__le16	RxLen;
} __attribute__((__packed__));

/*
 *  Received a packet and pass to upper layer
 */
static void
dm9000_rx(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	struct dm9000_rxhdr rxhdr;
	struct sk_buff *skb;
	u8 rxbyte, *rdptr;
	bool GoodPacket;
	int RxLen;

	/* Check packet ready or not */
	do {
		ior(db, DM9000_MRCMDX);	/* Dummy read */

		/* Get most updated data */
		rxbyte = readb(db->io_data);

		/* Status check: this byte must be 0 or 1 */
		if (rxbyte > DM9000_PKT_RDY) {
			dev_warn(db->dev, "status check fail: %d\n", rxbyte);
			iow(db, DM9000_RCR, 0x00);	/* Stop Device */
			iow(db, DM9000_ISR, IMR_PAR);	/* Stop INT request */
			return;
		}

		if (rxbyte != DM9000_PKT_RDY)
			return;

		/* A packet ready now  & Get status/length */
		GoodPacket = true;
		writeb(DM9000_MRCMD, db->io_addr);

		(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));

		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;
			if (netif_msg_rx_err(db))
				dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
		}

		if (RxLen > DM9000_PKT_MAX) {
			dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
		}

		/* rxhdr.RxStatus is identical to RSR register. */
		if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
				      RSR_PLE | RSR_RWTO |
				      RSR_LCS | RSR_RF)) {
			GoodPacket = false;
			if (rxhdr.RxStatus & RSR_FOE) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "fifo error\n");
				dev->stats.rx_fifo_errors++;
				printk(KERN_INFO "[%s Ethernet Driver, V%s]: FIFO Over Flow!!\n", CARDNAME, DRV_VERSION); //JJ1
			}
			if (rxhdr.RxStatus & RSR_CE) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "crc error\n");
				dev->stats.rx_crc_errors++;
			}
			if (rxhdr.RxStatus & RSR_RF) {
				if (netif_msg_rx_err(db))
					dev_dbg(db->dev, "length error\n");
				dev->stats.rx_length_errors++;
			}
		}

		/* Move data from DM9000 */
		if (GoodPacket
		    && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
			skb_reserve(skb, 2);
			rdptr = (u8 *) skb_put(skb, RxLen - 4);

			/* Read received packet from RX SRAM */

			(db->inblk)(db->io_data, rdptr, RxLen);
			dev->stats.rx_bytes += RxLen;

			/* Pass to upper layer */
			skb->protocol = eth_type_trans(skb, dev);
			netif_rx(skb);
			dev->stats.rx_packets++;

		} else {
			/* need to dump the packet's data */

			(db->dumpblk)(db->io_data, RxLen);
		}
	} while (rxbyte == DM9000_PKT_RDY);
}

static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	board_info_t *db = netdev_priv(dev);
	int int_status;
	unsigned long flags;
	u8 reg_save;

	dm9000_dbg(db, 3, "entering %s\n", __func__);

	/* A real interrupt coming */

	/* holders of db->lock must always block IRQs */
	spin_lock_irqsave(&db->lock, flags);

	/* Save previous register address */
	reg_save = readb(db->io_addr);

	/* Disable all interrupts */
	iow(db, DM9000_IMR, IMR_PAR);

	/* Got DM9000 interrupt status */
	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);

	/* Trnasmit Interrupt check */
	if (int_status & ISR_PTS)
		dm9000_tx_done(dev, db);

	if (db->type != TYPE_DM9000E) {
		if (int_status & ISR_LNKCHNG) {
			/* fire a link-change request */
			schedule_delayed_work(&db->phy_poll, 1);
		}
	}

	/* Re-enable interrupt mask */
	iow(db, DM9000_IMR, db->imr_all);

	/* Restore previous register address */
	writeb(reg_save, db->io_addr);

	 spin_unlock_irqrestore(&db->lock, flags);

	return IRQ_HANDLED;
}

#ifdef CONFIG_NET_POLL_CONTROLLER
/*
 *Used by netconsole
 */
static void dm9000_poll_controller(struct net_device *dev)
{
	disable_irq(dev->irq);
	dm9000_interrupt(dev->irq, dev);
	enable_irq(dev->irq);
}
#endif

/*
 *  Open the interface.
 *  The interface is opened whenever "ifconfig" actives it.
 */
static int
dm9000_open(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);
	unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

	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 */

	if (irqflags == IRQF_TRIGGER_NONE)
		dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");

	irqflags |= IRQF_SHARED;

	if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))
		return -EAGAIN;

	/* Initialize DM9000 board */
	dm9000_reset(db);
	dm9000_init_dm9000(dev);

	/* Init driver variable */
	db->dbug_cnt = 0;

	mii_check_media(&db->mii, netif_msg_link(db), 1);
	netif_start_queue(dev);
	
	dm9000_schedule_poll(db);

	return 0;
}

/*
 * Sleep, either by using msleep() or if we are suspending, then
 * use mdelay() to sleep.
 */
static void dm9000_msleep(board_info_t *db, unsigned int ms)
{
	if (db->in_suspend)
		mdelay(ms);
	else
		msleep(ms);
}

/*
 *   Read a word from phyxcer
 */
static int
dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
{
	board_info_t *db = netdev_priv(dev);
	unsigned long flags;
	unsigned int reg_save;
	int ret;

	mutex_lock(&db->addr_lock);

	spin_lock_irqsave(&db->lock,flags);

	/* Save previous register address */
	reg_save = readb(db->io_addr);

	/* Fill the phyxcer register into REG_0C */
	iow(db, DM9000_EPAR, DM9000_PHY | reg);

	iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);	/* Issue phyxcer read command */

	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock,flags);

	dm9000_msleep(db, 1);		/* Wait read complete */

	spin_lock_irqsave(&db->lock,flags);
	reg_save = readb(db->io_addr);

	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer read command */

	/* The read data keeps on REG_0D & REG_0E */
	ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);

	/* restore the previous address */
	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock,flags);

	mutex_unlock(&db->addr_lock);

	dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
	return ret;
}

/*
 *   Write a word to phyxcer
 */
static void
dm9000_phy_write(struct net_device *dev,
		 int phyaddr_unused, int reg, int value)
{
	board_info_t *db = netdev_priv(dev);
	unsigned long flags;
	unsigned long reg_save;

	dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
	mutex_lock(&db->addr_lock);

	spin_lock_irqsave(&db->lock,flags);

	/* Save previous register address */
	reg_save = readb(db->io_addr);

	/* Fill the phyxcer register into REG_0C */
	iow(db, DM9000_EPAR, DM9000_PHY | reg);

	/* Fill the written data into REG_0D & REG_0E */
	iow(db, DM9000_EPDRL, value);
	iow(db, DM9000_EPDRH, value >> 8);

	iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW);	/* Issue phyxcer write command */

	writeb(reg_save, db->io_addr);
	spin_unlock_irqrestore(&db->lock, flags);

	dm9000_msleep(db, 1);		/* Wait write complete */

	spin_lock_irqsave(&db->lock,flags);
	reg_save = readb(db->io_addr);

	iow(db, DM9000_EPCR, 0x0);	/* Clear phyxcer write command */

	/* restore the previous address */
	writeb(reg_save, db->io_addr);

	spin_unlock_irqrestore(&db->lock, flags);
	mutex_unlock(&db->addr_lock);
}

static void
dm9000_shutdown(struct net_device *dev)
{
	board_info_t *db = netdev_priv(dev);

	/* RESET device */
	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);	/* PHY RESET */
//V_R1	iow(db, DM9000_GPR, 0x01);	/* Power-Down PHY */
	iow(db, DM9000_IMR, IMR_PAR);	/* Disable all interrupt */
	iow(db, DM9000_RCR, 0x00);	/* Disable RX */
}

/*
 * Stop the interface.
 * The interface is stopped when it is brought.
 */
static int
dm9000_stop(struct net_device *ndev)
{
	board_info_t *db = netdev_priv(ndev);

	if (netif_msg_ifdown(db))
		dev_dbg(db->dev, "shutting down %s\n", ndev->name);

	cancel_delayed_work_sync(&db->phy_poll);

	netif_stop_queue(ndev);
	netif_carrier_off(ndev);

	/* free interrupt */
	free_irq(ndev->irq, ndev);

	dm9000_shutdown(ndev);

	return 0;
}

#define res_size(_r) (((_r)->end - (_r)->start) + 1)

static const struct net_device_ops dm9000_netdev_ops = {
         .ndo_open = dm9000_open,
         .ndo_stop = dm9000_stop,
         .ndo_start_xmit = dm9000_start_xmit,
         .ndo_tx_timeout = dm9000_timeout,
         .ndo_set_multicast_list = dm9000_hash_table,
         .ndo_do_ioctl = dm9000_ioctl,
         .ndo_change_mtu = eth_change_mtu,
         .ndo_validate_addr = eth_validate_addr,
         .ndo_set_mac_address = eth_mac_addr,
    #ifdef CONFIG_NET_POLL_CONTROLLER
         .ndo_poll_controller = dm9000_poll_controller,
    #endif
};


/*
 * Search DM9000 board, allocate space and register it
 */
static int __devinit
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;
	int ret = 0;
	int iosize;
	int i;
	u32 id_val;

	/* Init network device */
	ndev = alloc_etherdev(sizeof(struct board_info));
	if (!ndev) {
		dev_err(&pdev->dev, "could not allocate device.\n");
		return -ENOMEM;
	}

	SET_NETDEV_DEV(ndev, &pdev->dev);

	dev_dbg(&pdev->dev, "dm9000_probe()\n");
	 ndev->netdev_ops = &dm9000_netdev_ops;
	/* setup board info structure */
	db = netdev_priv(ndev);
	memset(db, 0, sizeof(*db));

	db->dev = &pdev->dev;
	db->ndev = ndev;

	spin_lock_init(&db->lock);
	mutex_init(&db->addr_lock);

	INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);

	db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

	if (db->addr_res == NULL || db->data_res == NULL ||
	    db->irq_res == NULL) {
		dev_err(db->dev, "insufficient resources\n");
		ret = -ENOENT;
		goto out;
	}

	iosize = res_size(db->addr_res);
	db->addr_req = request_mem_region(db->addr_res->start, iosize,
					  pdev->name);

	if (db->addr_req == NULL) {
		dev_err(db->dev, "cannot claim address reg area\n");
		ret = -EIO;
		goto out;
	}

	db->io_addr = ioremap(db->addr_res->start, iosize);

	if (db->io_addr == NULL) {
		dev_err(db->dev, "failed to ioremap address reg\n");
		ret = -EINVAL;
		goto out;
	}

	iosize = res_size(db->data_res);
	db->data_req = request_mem_region(db->data_res->start, iosize,
					  pdev->name);

	if (db->data_req == NULL) {
		dev_err(db->dev, "cannot claim data reg area\n");
		ret = -EIO;
		goto out;
	}

	db->io_data = ioremap(db->data_res->start, iosize);

	if (db->io_data == NULL) {
		dev_err(db->dev, "failed to ioremap data reg\n");
		ret = -EINVAL;
		goto out;
	}

	/* fill in parameters for net-dev structure */
	ndev->base_addr = (unsigned long)db->io_addr;
	ndev->irq	= db->irq_res->start;
	//Stone add
	printk("[dm9] %s ndev->irq=%x \n",__func__,ndev->irq);

	/* ensure at least we have a default set of IO routines */
	dm9000_set_io(db, iosize);

	/* check to see if anything is being over-ridden */
	if (pdata != NULL) {
		/* check to see if the driver wants to over-ride the
		 * default IO width */

		if (pdata->flags & DM9000_PLATF_8BITONLY)
			dm9000_set_io(db, 1);

		if (pdata->flags & DM9000_PLATF_16BITONLY)
			dm9000_set_io(db, 2);

		if (pdata->flags & DM9000_PLATF_32BITONLY)
			dm9000_set_io(db, 4);

		/* check to see if there are any IO routine
		 * over-rides */

		if (pdata->inblk != NULL)
			db->inblk = pdata->inblk;

		if (pdata->outblk != NULL)
			db->outblk = pdata->outblk;

		if (pdata->dumpblk != NULL)
			db->dumpblk = pdata->dumpblk;

		db->flags = pdata->flags;
	}

#ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
	db->flags |= DM9000_PLATF_SIMPLE_PHY;
#endif

//Stone add
//	dm9000_reset(db);
  iow(db, DM9000_NCR, 0x03);

	/* try multiple times, DM9000 sometimes gets the read wrong */
	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;
		id_val |= (u32)ior(db, DM9000_PIDH) << 24;

		printk("[dm9].%d read id 0x%08x\n", i+1, id_val);
		
		if (id_val == DM9000_ID)
			break;
		dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
	}
	
	printk(KERN_INFO "[%s Ethernet Driver, V%s]: KV= %d.%d.%d !!\n", CARDNAME, DRV_VERSION,  //JJ1 
	                            (LINUX_VERSION_CODE>>16 & 0xff),
	                            (LINUX_VERSION_CODE>>8 & 0xff),
	                            (LINUX_VERSION_CODE & 0xff) ); //#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
	printk(KERN_INFO "[%s Ethernet Driver, V%s]: ChipID= 0x%x !!\n", CARDNAME, DRV_VERSION, id_val ); // JJ1

	if (id_val != DM9000_ID) {
		dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
		ret = -ENODEV;
		goto out;
	}

	/* Identify what type of DM9000 we are working on */

	id_val = ior(db, DM9000_CHIPR);
	dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);
	printk(KERN_INFO "[DM9000]dm9000 revision 0x%02x\n", id_val); //V_R1

	switch (id_val) {
	case CHIPR_DM9000A:
		db->type = TYPE_DM9000A;
		break;
	case CHIPR_DM9000B:
		db->type = TYPE_DM9000B;
		break;
	default:
		dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
		db->type = TYPE_DM9000E;
	}

	/* from this point we assume that we have found a DM9000 */

	/* driver system function */
	ether_setup(ndev);
	
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
			ndev->netdev_ops = &dm9000_netdev_ops; // new kernel 2.6.31 
			ndev->watchdog_timeo	= msecs_to_jiffies(watchdog);	
	 		ndev->ethtool_ops	 = &dm9000_ethtool_ops;
#else
	ndev->open		 = &dm9000_open;
	ndev->hard_start_xmit    = &dm9000_start_xmit;
	ndev->tx_timeout         = &dm9000_timeout;
	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
	ndev->stop		 = &dm9000_stop;
	ndev->set_multicast_list = &dm9000_hash_table;
	ndev->ethtool_ops	 = &dm9000_ethtool_ops;
	ndev->do_ioctl		 = &dm9000_ioctl;
#endif


#ifdef CONFIG_NET_POLL_CONTROLLER
	ndev->poll_controller	 = &dm9000_poll_controller;
#endif

	db->msg_enable       = NETIF_MSG_LINK;
	db->mii.phy_id_mask  = 0x1f;
	db->mii.reg_num_mask = 0x1f;
	db->mii.force_media  = 0;
	db->mii.full_duplex  = 0;
	db->mii.dev	     = ndev;
	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) && pdata != NULL) {
		mac_src = "platform data";
		memcpy(ndev->dev_addr, pdata->dev_addr, 6);
	}

	if (!is_valid_ether_addr(ndev->dev_addr)) {
		/* try reading from mac */
		
		mac_src = "chip";

		static unsigned char mac_addr[6] = {0x00,0x11,0x22,0x33,0x44,0x55};
		static unsigned char mac_tmp[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
		for (i = 0; i < 6; i++)
			ndev->dev_addr[i] = ior(db, i+DM9000_PAR);

		// Mark Chang 20100521
		// -------------------
		if (!memcmp(ndev->dev_addr, mac_tmp, 6))
			memcpy(ndev->dev_addr, mac_addr, 6);
	}

	if (!is_valid_ether_addr(ndev->dev_addr))
		dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
			 "set using ifconfig\n", ndev->name);

	platform_set_drvdata(pdev, ndev);
	ret = register_netdev(ndev);

	if (ret == 0)
		printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
		       ndev->name, dm9000_type_to_char(db->type),
		       db->io_addr, db->io_data, ndev->irq,
		       ndev->dev_addr, mac_src);
	return 0;

out:
	dev_err(db->dev, "not found (%d).\n", ret);

	dm9000_release_board(pdev, db);
	free_netdev(ndev);

	return ret;
}

static int
dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	board_info_t *db;

	if (ndev) {
		db = netdev_priv(ndev);
		db->in_suspend = 1;

		if (netif_running(ndev)) {
			netif_device_detach(ndev);
			dm9000_shutdown(ndev);
		}
	}
	return 0;
}

static int
dm9000_drv_resume(struct platform_device *dev)
{
	struct net_device *ndev = platform_get_drvdata(dev);
	board_info_t *db = netdev_priv(ndev);

	if (ndev) {

		if (netif_running(ndev)) {
			dm9000_reset(db);
			dm9000_init_dm9000(ndev);

			netif_device_attach(ndev);
		}

		db->in_suspend = 0;
	}
	return 0;
}

static int __devexit
dm9000_drv_remove(struct platform_device *pdev)
{
	struct net_device *ndev = platform_get_drvdata(pdev);

	platform_set_drvdata(pdev, NULL);

	unregister_netdev(ndev);
	dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev));
	free_netdev(ndev);		/* free device structure */

	dev_dbg(&pdev->dev, "released and freed device\n");
	return 0;
}

static struct platform_driver dm9000_driver = {
	.driver	= {
		.name    = "dm9000",
		.owner	 = THIS_MODULE,
	},
	.probe   = dm9000_probe,
	.remove  = __devexit_p(dm9000_drv_remove),
	.suspend = dm9000_drv_suspend,
	.resume  = dm9000_drv_resume,
};

static int __init
dm9000_init(void)
{
	printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);

	return platform_driver_register(&dm9000_driver);
}

static void __exit
dm9000_cleanup(void)
{
	platform_driver_unregister(&dm9000_driver);
}

module_init(dm9000_init);
module_exit(dm9000_cleanup);

MODULE_AUTHOR("Sascha Hauer, Ben Dooks");
MODULE_DESCRIPTION("Davicom DM9000 network driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:dm9000");

[-- Attachment #3: dm9000_KT2.6.31.h --]
[-- Type: text/plain, Size: 4180 bytes --]

/*
 * dm9000 Ethernet
 */

#ifndef _DM9000X_H_
#define _DM9000X_H_

#define DM9000_ID		0x90000A46

/* although the registers are 16 bit, they are 32-bit aligned.
 */

#define DM9000_NCR             0x00
#define DM9000_NSR             0x01
#define DM9000_TCR             0x02
#define DM9000_TSR1            0x03
#define DM9000_TSR2            0x04
#define DM9000_RCR             0x05
#define DM9000_RSR             0x06
#define DM9000_ROCR            0x07
#define DM9000_BPTR            0x08
#define DM9000_FCTR            0x09
#define DM9000_FCR             0x0A
#define DM9000_EPCR            0x0B
#define DM9000_EPAR            0x0C
#define DM9000_EPDRL           0x0D
#define DM9000_EPDRH           0x0E
#define DM9000_WCR             0x0F

#define DM9000_PAR             0x10
#define DM9000_MAR             0x16

#define DM9000_GPCR	       0x1e
#define DM9000_GPR             0x1f
#define DM9000_TRPAL           0x22
#define DM9000_TRPAH           0x23
#define DM9000_RWPAL           0x24
#define DM9000_RWPAH           0x25

#define DM9000_VIDL            0x28
#define DM9000_VIDH            0x29
#define DM9000_PIDL            0x2A
#define DM9000_PIDH            0x2B

#define DM9000_CHIPR           0x2C
#define DM9000_SMCR            0x2F

#define CHIPR_DM9000A	       0x19
#define CHIPR_DM9000B	       0x1A  //V_R1 0x1B

#define DM9000_MRCMDX          0xF0
#define DM9000_MRCMD           0xF2
#define DM9000_MRRL            0xF4
#define DM9000_MRRH            0xF5
#define DM9000_MWCMDX          0xF6
#define DM9000_MWCMD           0xF8
#define DM9000_MWRL            0xFA
#define DM9000_MWRH            0xFB
#define DM9000_TXPLL           0xFC
#define DM9000_TXPLH           0xFD
#define DM9000_ISR             0xFE
#define DM9000_IMR             0xFF

#define NCR_EXT_PHY         (1<<7)
#define NCR_WAKEEN          (1<<6)
#define NCR_FCOL            (1<<4)
#define NCR_FDX             (1<<3)
#define NCR_LBK             (3<<1)
#define NCR_RST	            (1<<0)

#define NSR_SPEED           (1<<7)
#define NSR_LINKST          (1<<6)
#define NSR_WAKEST          (1<<5)
#define NSR_TX2END          (1<<3)
#define NSR_TX1END          (1<<2)
#define NSR_RXOV            (1<<1)

#define TCR_TJDIS           (1<<6)
#define TCR_EXCECM          (1<<5)
#define TCR_PAD_DIS2        (1<<4)
#define TCR_CRC_DIS2        (1<<3)
#define TCR_PAD_DIS1        (1<<2)
#define TCR_CRC_DIS1        (1<<1)
#define TCR_TXREQ           (1<<0)

#define TSR_TJTO            (1<<7)
#define TSR_LC              (1<<6)
#define TSR_NC              (1<<5)
#define TSR_LCOL            (1<<4)
#define TSR_COL             (1<<3)
#define TSR_EC              (1<<2)

#define RCR_WTDIS           (1<<6)
#define RCR_DIS_LONG        (1<<5)
#define RCR_DIS_CRC         (1<<4)
#define RCR_ALL	            (1<<3)
#define RCR_RUNT            (1<<2)
#define RCR_PRMSC           (1<<1)
#define RCR_RXEN            (1<<0)

#define RSR_RF              (1<<7)
#define RSR_MF              (1<<6)
#define RSR_LCS             (1<<5)
#define RSR_RWTO            (1<<4)
#define RSR_PLE             (1<<3)
#define RSR_AE              (1<<2)
#define RSR_CE              (1<<1)
#define RSR_FOE             (1<<0)

#define FCTR_HWOT(ot)	(( ot & 0xf ) << 4 )
#define FCTR_LWOT(ot)	( ot & 0xf )

#define IMR_PAR             (1<<7)
#define IMR_ROOM            (1<<3)
#define IMR_ROM             (1<<2)
#define IMR_PTM             (1<<1)
#define IMR_PRM             (1<<0)

#define ISR_ROOS            (1<<3)
#define ISR_ROS             (1<<2)
#define ISR_PTS             (1<<1)
#define ISR_PRS             (1<<0)
#define ISR_CLR_STATUS      (ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS)

#define EPCR_REEP           (1<<5)
#define EPCR_WEP            (1<<4)
#define EPCR_EPOS           (1<<3)
#define EPCR_ERPRR          (1<<2)
#define EPCR_ERPRW          (1<<1)
#define EPCR_ERRE           (1<<0)

#define GPCR_GEP_CNTL       (1<<0)

#define DM9000_PKT_RDY		0x01	/* Packet ready to receive */
#define DM9000_PKT_MAX		1536	/* Received packet max size */

/* DM9000A / DM9000B definitions */

#define IMR_LNKCHNG		(1<<5)
#define IMR_UNDERRUN		(1<<4)

#define ISR_LNKCHNG		(1<<5)
#define ISR_UNDERRUN		(1<<4)

#endif /* _DM9000X_H_ */


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Davicom DM9000C driver
  2012-09-19  5:58 Davicom DM9000C driver Allen Huang (黃偉格)
  2012-09-19 16:39 ` Bruno Prémont
@ 2012-09-19 23:35 ` Jonathan Corbet
  2012-09-20  9:08   ` Arnd Bergmann
  1 sibling, 1 reply; 7+ messages in thread
From: Jonathan Corbet @ 2012-09-19 23:35 UTC (permalink / raw)
  To: Allen Huang
  Cc: linux-kernel, 'Michael Chen', 'Charles',
	'Joseph Chang'

On Wed, 19 Sep 2012 13:58:08 +0800
Allen Huang (黃偉格)  <allen_huang@davicom.com.tw> wrote:

> I'm Allen Huang from Davicom. We are hereby opensourcing the linux
> driver for our DM9000C. 

That is great, but please read the development process documentation on
how best to submit something like this.  We would much rather see a patch
(inline, not as an attachment) to facilitate the review.

I'm going to take a quick look, but this is *not* a thorough review.

> /*
>  *      Davicom DM9000 Fast Ethernet driver for Linux.
>  * 	Copyright (C) 1997  Sten Wang
>  *
>  * 	This program is free software; you can redistribute it and/or
>  * 	modify it under the terms of the GNU General Public License
>  * 	as published by the Free Software Foundation; either version 2
>  * 	of the License, or (at your option) any later version.
>  *
>  * 	This program is distributed in the hope that it will be useful,
>  * 	but WITHOUT ANY WARRANTY; without even the implied warranty of
>  * 	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.

This line contradicts what comes above; GPL is not "all rights reserved."

>  * Additional updates, Copyright:
>  *	Ben Dooks <ben@simtec.co.uk>
>  *	Sascha Hauer <s.hauer@pengutronix.de>
>  *  
>  * 2010.07.20 V_R1 1.Write PHY Reg27 = 0xE100
>  *								 2.Just enable PHY once after GPIO setting in dm9000_init_dm9000()

The 80-column limit isn't as set in stone as it once was, but this still
pushes the limits rather farther than needed.  In general, though,
changelog information belongs in the VCS, not in the header comments.

> /* 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.
>  */

This seems like a bit of a strange locking scheme.  Are the accesses to
this register pair so slow that you can't just protect the set with a
spinlock and be done with it?

> /* Structure/enum declaration ------------------------------- */
> typedef struct board_info {

typedef is strongly discouraged in kernel code; just use "struct
board_info" in your code.  Though a more descriptive name wouldn't hurt. 

> 	void __iomem	*io_addr;	/* Register I/O base address */
> 	void __iomem	*io_data;	/* Data I/O address */
> 	u16		 irq;		/* IRQ */
> 
> 	u16		tx_pkt_cnt;
> 	u16		queue_pkt_len;
> 	u16		queue_start_addr;
> 	u16		dbug_cnt;
> 	u8		io_mode;		/* 0:word, 2:byte */
> 	u8		phy_addr;
> 	u8		imr_all;
> 
> 	unsigned int	flags;
> 	unsigned int	in_suspend :1;
> 	int		debug_level;

This structure will have a lot of holes; maybe that's not a problem.

[...]
> 
> static void
> dm9000_phy_write(struct net_device *dev,
> 		 int phyaddr_unused, int reg, int value);

Why not just define this function here and avoid the forward declaration? 

> /* 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)

We have nice dynamic debugging facilities that make this kind of stuff
unnecessary.  See https://lwn.net/Articles/434833/

> /* DM9000 network board routine ---------------------------- */
> 
> static void
> dm9000_reset(board_info_t * db)
> {
> 	dev_dbg(db->dev, "resetting device\n");
> 
> 	/* RESET device */
> 	writeb(DM9000_NCR, db->io_addr);
> 	udelay(200);
> 	writeb(NCR_RST, db->io_data);
> 	udelay(200);
> }
> 
> /*
>  *   Read a byte from I/O port
>  */
> static u8
> ior(board_info_t * db, int reg)
> {
> 	writeb(reg, db->io_addr);
> 	return readb(db->io_data);
> }
> 
> /*
>  *   Write a byte to I/O port
>  */
> 
> static void
> iow(board_info_t * db, int reg, int value)
> {
> 	writeb(reg, db->io_addr);
> 	writeb(value, db->io_data);
> }

So the locking you were talking about is clearly happening at a higher
level than here.  It would be good to note what locking is expected by
these functions.

> static void dm9000_set_io(struct board_info *db, int byte_width)
> {
> 	/* use the size of the data resource to work out what IO
> 	 * routines we want to use
> 	 */
> 
> 	switch (byte_width) {
> 	case 1:
> 		db->dumpblk = dm9000_dumpblk_8bit;
> 		db->outblk  = dm9000_outblk_8bit;
> 		db->inblk   = dm9000_inblk_8bit;
> 		break;
> 
> 
> 	case 3:
> 		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;
> 		break;
> 
> 	case 4:
> 	default:
> 		db->dumpblk = dm9000_dumpblk_32bit;
> 		db->outblk  = dm9000_outblk_32bit;
> 		db->inblk   = dm9000_inblk_32bit;
> 		break;
> 	}
> }

It might be nice to move these function pointers into their own structure.
You could then declare them static and const and just assign the structure
pointer here.

> static void dm9000_schedule_poll(board_info_t *db)
> {
> 	if (db->type == TYPE_DM9000E)
> 		schedule_delayed_work(&db->phy_poll, HZ * 2);

Coding style: HZ*2.  Running checkpatch would be a good idea.

[...]

> /*
>  *  Read a word data from EEPROM
>  */
> static void
> 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);

So I'm still really confused by this locking.  What is ->addr_lock
protecting? 

> 	spin_lock_irqsave(&db->lock, flags);
> 
> 	iow(db, DM9000_EPAR, offset);
> 	iow(db, DM9000_EPCR, EPCR_ERPRR);
> 
> 	spin_unlock_irqrestore(&db->lock, flags);
> 
> 	dm9000_wait_eeprom(db);
> 
> 	/* delay for at-least 150uS */
> 	msleep(1);
> 
> 	spin_lock_irqsave(&db->lock, flags);
> 
> 	iow(db, DM9000_EPCR, 0x0);
> 
> 	to[0] = ior(db, DM9000_EPDRL);
> 	to[1] = ior(db, DM9000_EPDRH);
> 
> 	spin_unlock_irqrestore(&db->lock, flags);
> 
> 	mutex_unlock(&db->addr_lock);
> }
> 
> /*
>  * Write a word data to SROM
>  */
> static void
> 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);
> 	iow(db, DM9000_EPAR, offset);
> 	iow(db, DM9000_EPDRH, data[1]);
> 	iow(db, DM9000_EPDRL, data[0]);
> 	iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);
> 	spin_unlock_irqrestore(&db->lock, flags);
> 
> 	dm9000_wait_eeprom(db);
> 
> 	mdelay(1);	/* wait at least 150uS to clear */

Why mdelay() here?  You used msleep() above.

> 	spin_lock_irqsave(&db->lock, flags);
> 	iow(db, DM9000_EPCR, 0);
> 	spin_unlock_irqrestore(&db->lock, flags);
> 
> 	mutex_unlock(&db->addr_lock);
> }

[...]
> static void
> dm9000_poll_work(struct work_struct *w)
> {
> 	struct delayed_work *dw = container_of(w, struct delayed_work, work);
> 	board_info_t *db = container_of(dw, board_info_t, phy_poll);
> 	struct net_device *ndev = db->ndev;
> 
> //JJ2
> //	if (db->flags & DM9000_PLATF_SIMPLE_PHY &&
> //	    !(db->flags & DM9000_PLATF_EXT_PHY)) {
> //  =

This kind of stuff should come out - either you need it or you don't.

> 		if(1){						

Likewise.  Plus the coding syle is wrong :)

> 		unsigned nsr = dm9000_read_locked(db, DM9000_NSR);
> 		unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0;
> 		unsigned new_carrier;
> 
> 		new_carrier = (nsr & NSR_LINKST) ? 1 : 0;
> 
> 		if (old_carrier != new_carrier) {
> 			
> 			if (new_carrier)
> 			  printk(KERN_INFO "[dm9000%c %s Ethernet Driver, V%s]: Link-Up!!\n",dm9000_type_to_char(db->type), CARDNAME, DRV_VERSION); //JJ2

Why not dev_info() here?

> 			else
> 			  printk(KERN_INFO "[%s Ethernet Driver, V%s]: Link-Down!!\n", CARDNAME, DRV_VERSION); //JJ2
> 			
> 			if (netif_msg_link(db))
> 				dm9000_show_carrier(db, new_carrier, nsr);
> 
> 			if (!new_carrier)
> 				netif_carrier_off(ndev);
> 			else
> 				netif_carrier_on(ndev);
> 		}
> 	} else
> 		mii_check_media(&db->mii, netif_msg_link(db), 0);
> 	
> 	if (netif_running(ndev))
> 		dm9000_schedule_poll(db);
> }
> 
> /* dm9000_release_board
>  *
>  * release a board, and any mapped resources
>  */
> 
> static void
> dm9000_release_board(struct platform_device *pdev, struct board_info *db)
> {
> 	/* unmap our resources */
> 
> 	iounmap(db->io_addr);
> 	iounmap(db->io_data);
> 
> 	/* release the resources */
> 
> 	release_resource(db->data_req);

I think this wants to be release_mem_region()

> 	kfree(db->data_req);

...and this shouldn't be here at all.

> 	release_resource(db->addr_req);
> 	kfree(db->addr_req);
> }

[...]

> /*
>  * Initilize dm9000 board
>  */
> static void
> dm9000_init_dm9000(struct net_device *dev)
> {
> 	board_info_t *db = netdev_priv(dev);
> 	unsigned int imr;
> 
> 	dm9000_dbg(db, 1, "entering %s\n", __func__);
> 
> 	/* I/O mode */
> 	db->io_mode = ior(db, DM9000_ISR) >> 6;	/* ISR bit7:6 keeps I/O mode */

So this looks like it wants the lock held?

> 	/* GPIO0 on pre-activate PHY */
> //V_R1	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */
> 	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */
> 	iow(db, DM9000_GPR, 0);	/* Enable PHY */
>         mdelay(20);  //V_R2
> 
> 	dm9000_phy_write(dev, 0, 0, 0x8000); //V_R2 reset PHY
>         mdelay (20);

...and now we have 40ms of hard delay with the lock held and interrupts
disabled?  Ouch.

> //	if (db->flags & DM9000_PLATF_EXT_PHY)
> //		iow(db, DM9000_NCR, NCR_EXT_PHY);
> 
> 	/* Program operating register */
> 	iow(db, DM9000_TCR, 0);	        /* TX Polling clear */
> 	iow(db, DM9000_BPTR, 0x3f);	/* Less 3Kb, 200us */
> 	iow(db, DM9000_FCR, 0xff);	/* Flow Control */
> 	iow(db, DM9000_SMCR, 0);        /* Special Mode */
> 	/* clear TX status */
> 	iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
> 	iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */
> 
> 	/* Set address filter table */
> 	dm9000_hash_table(dev);
> 
> 	imr = IMR_PAR | IMR_PTM | IMR_PRM;
> 	if (db->type != TYPE_DM9000E)
> 		imr |= IMR_LNKCHNG;
> 
> 	db->imr_all = imr;
> 
> 	/* Enable TX/RX interrupt mask */
> 	iow(db, DM9000_IMR, imr);
> 
> 	/* Init Driver variable */
> 	db->tx_pkt_cnt = 0;
> 	db->queue_pkt_len = 0;
> 	dev->trans_start = 0;
> 	
> 	dm9000_phy_write(dev, 0, 27, 0xE100); //V_R1
> }
> 
> /* Our watchdog timed out. Called by the networking layer */
> static void dm9000_timeout(struct net_device *dev)
> {
> 	board_info_t *db = netdev_priv(dev);
> 	u8 reg_save;
> 	unsigned long flags;
> 
> 	/* Save previous register address */
> 	reg_save = readb(db->io_addr);
> 	spin_lock_irqsave(&db->lock, flags);

Repeating myself, but I still don't get this; why not just protect all
accesses to the register pair and avoid this kind of error-prone stuff?

> 	netif_stop_queue(dev);
> 	printk(KERN_INFO "[%s Ethernet Driver, V%s]: Timeout!!\n", CARDNAME, DRV_VERSION); //JJ1
> 	dm9000_reset(db);
> 	dm9000_init_dm9000(dev);

So we can have that 40ms with interrupts off whenever a timeout occurs.

> 	/* We can accept TX packets again */
> 	dev->trans_start = jiffies;
> 	netif_wake_queue(dev);
> 
> 	/* Restore previous register address */
> 	writeb(reg_save, db->io_addr);
> 	spin_unlock_irqrestore(&db->lock, flags);
> }
> 
> /*
>  *  Hardware start transmission.
>  *  Send a packet to media from the upper layer.
>  */
> static int
> dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
> {
> 	unsigned long flags;
> 	board_info_t *db = netdev_priv(dev);
> 
> 	dm9000_dbg(db, 3, "%s:\n", __func__);
> 
> 	if (db->tx_pkt_cnt > 1)
> 		return 1;
> 
> 	spin_lock_irqsave(&db->lock, flags);
> 
> 	/* Move data to DM9000 TX RAM */
> 	writeb(DM9000_MWCMD, db->io_addr);

So this time you don't save the address.  I'm glad somebody knows when that
needs to happen.

> 	(db->outblk)(db->io_data, skb->data, skb->len);
> 	dev->stats.tx_bytes += skb->len;
> 
> 	db->tx_pkt_cnt++;
> 	/* 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);
> 		iow(db, DM9000_TXPLH, skb->len >> 8);
> 
> 		/* Issue TX polling command */
> 		iow(db, DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */
> 
> 		dev->trans_start = jiffies;	/* save the time stamp */
> 	} else {
> 		/* Second packet */
> 		db->queue_pkt_len = skb->len;
> 		netif_stop_queue(dev);
> 	}
> 
> 	spin_unlock_irqrestore(&db->lock, flags);
> 
> 	/* free this SKB */
> 	dev_kfree_skb(skb);
> 
> 	return 0;
> }

[...]

> struct dm9000_rxhdr {
> 	u8	RxPktReady;
> 	u8	RxStatus;
> 	__le16	RxLen;
> } __attribute__((__packed__));

I'd put this at the top with the rest.

> /*
>  *  Received a packet and pass to upper layer
>  */
> static void
> dm9000_rx(struct net_device *dev)
> {
> 	board_info_t *db = netdev_priv(dev);
> 	struct dm9000_rxhdr rxhdr;
> 	struct sk_buff *skb;
> 	u8 rxbyte, *rdptr;
> 	bool GoodPacket;
> 	int RxLen;
> 
> 	/* Check packet ready or not */
> 	do {
> 		ior(db, DM9000_MRCMDX);	/* Dummy read */

Who has taken the spinlock to make this safe?

> 		/* Get most updated data */
> 		rxbyte = readb(db->io_data);

Who has set io_addr here?  Are you counting on that ior() call to do it?

> 		/* Status check: this byte must be 0 or 1 */
> 		if (rxbyte > DM9000_PKT_RDY) {
> 			dev_warn(db->dev, "status check fail: %d\n", rxbyte);
> 			iow(db, DM9000_RCR, 0x00);	/* Stop Device */
> 			iow(db, DM9000_ISR, IMR_PAR);	/* Stop INT request */
> 			return;
> 		}
> 
> 		if (rxbyte != DM9000_PKT_RDY)
> 			return;
> 
> 		/* A packet ready now  & Get status/length */
> 		GoodPacket = true;
> 		writeb(DM9000_MRCMD, db->io_addr);
> 
> 		(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
> 
> 		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;
> 			if (netif_msg_rx_err(db))
> 				dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
> 		}
> 
> 		if (RxLen > DM9000_PKT_MAX) {
> 			dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
> 		}

No brackets needed for single-line bodies

> 		/* rxhdr.RxStatus is identical to RSR register. */
> 		if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
> 				      RSR_PLE | RSR_RWTO |
> 				      RSR_LCS | RSR_RF)) {
> 			GoodPacket = false;
> 			if (rxhdr.RxStatus & RSR_FOE) {
> 				if (netif_msg_rx_err(db))
> 					dev_dbg(db->dev, "fifo error\n");
> 				dev->stats.rx_fifo_errors++;
> 				printk(KERN_INFO "[%s Ethernet Driver, V%s]: FIFO Over Flow!!\n", CARDNAME, DRV_VERSION); //JJ1
> 			}
> 			if (rxhdr.RxStatus & RSR_CE) {
> 				if (netif_msg_rx_err(db))
> 					dev_dbg(db->dev, "crc error\n");
> 				dev->stats.rx_crc_errors++;
> 			}
> 			if (rxhdr.RxStatus & RSR_RF) {
> 				if (netif_msg_rx_err(db))
> 					dev_dbg(db->dev, "length error\n");
> 				dev->stats.rx_length_errors++;
> 			}
> 		}
> 
> 		/* Move data from DM9000 */
> 		if (GoodPacket
> 		    && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
> 			skb_reserve(skb, 2);
> 			rdptr = (u8 *) skb_put(skb, RxLen - 4);
> 
> 			/* Read received packet from RX SRAM */
> 
> 			(db->inblk)(db->io_data, rdptr, RxLen);
> 			dev->stats.rx_bytes += RxLen;
> 
> 			/* Pass to upper layer */
> 			skb->protocol = eth_type_trans(skb, dev);
> 			netif_rx(skb);
> 			dev->stats.rx_packets++;
> 
> 		} else {
> 			/* need to dump the packet's data */
> 
> 			(db->dumpblk)(db->io_data, RxLen);
> 		}
> 	} while (rxbyte == DM9000_PKT_RDY);
> }
> 
> static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
> {
> 	struct net_device *dev = dev_id;
> 	board_info_t *db = netdev_priv(dev);
> 	int int_status;
> 	unsigned long flags;
> 	u8 reg_save;
> 
> 	dm9000_dbg(db, 3, "entering %s\n", __func__);
> 
> 	/* A real interrupt coming */
> 
> 	/* holders of db->lock must always block IRQs */

...and here is not the place to document that.

> 	spin_lock_irqsave(&db->lock, flags);
> 
> 	/* Save previous register address */
> 	reg_save = readb(db->io_addr);
> 
> 	/* Disable all interrupts */
> 	iow(db, DM9000_IMR, IMR_PAR);
> 
> 	/* Got DM9000 interrupt status */
> 	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);
> 
> 	/* Trnasmit Interrupt check */
> 	if (int_status & ISR_PTS)
> 		dm9000_tx_done(dev, db);
> 
> 	if (db->type != TYPE_DM9000E) {
> 		if (int_status & ISR_LNKCHNG) {
> 			/* fire a link-change request */
> 			schedule_delayed_work(&db->phy_poll, 1);
> 		}
> 	}
> 
> 	/* Re-enable interrupt mask */
> 	iow(db, DM9000_IMR, db->imr_all);
> 
> 	/* Restore previous register address */
> 	writeb(reg_save, db->io_addr);
> 
> 	 spin_unlock_irqrestore(&db->lock, flags);
> 
> 	return IRQ_HANDLED;

Did you ever check to see that the interrupt was actually from your device? 

> }

...and this is where I ran out of time, sorry.  Hope this much was helpful.

jon

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Davicom DM9000C driver
  2012-09-19 23:35 ` Jonathan Corbet
@ 2012-09-20  9:08   ` Arnd Bergmann
  2012-09-20 11:02     ` Arnd Bergmann
  2012-09-20 13:30     ` Jonathan Corbet
  0 siblings, 2 replies; 7+ messages in thread
From: Arnd Bergmann @ 2012-09-20  9:08 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Allen Huang, linux-kernel, 'Michael Chen',
	'Charles', 'Joseph Chang'

On Wednesday 19 September 2012, Jonathan Corbet wrote:
> On Wed, 19 Sep 2012 13:58:08 +0800
> Allen Huang (黃偉格)  <allen_huang@davicom.com.tw> wrote:
> 
> > I'm Allen Huang from Davicom. We are hereby opensourcing the linux
> > driver for our DM9000C. 
> 
> That is great, but please read the development process documentation on
> how best to submit something like this.  We would much rather see a patch
> (inline, not as an attachment) to facilitate the review.

More importantly, the patch should be against the version that is
already present in the kernel as drivers/net/ethernet/davicom/dm9000.c,
which appears to be mostly the same as the version that is submitted
here.

So while all the comments on the driver are valuable, they also apply
to the code we already have since 2005.

	Arnd

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Davicom DM9000C driver
  2012-09-20  9:08   ` Arnd Bergmann
@ 2012-09-20 11:02     ` Arnd Bergmann
  2012-09-21  1:49       ` Michael Chen
  2012-09-20 13:30     ` Jonathan Corbet
  1 sibling, 1 reply; 7+ messages in thread
From: Arnd Bergmann @ 2012-09-20 11:02 UTC (permalink / raw)
  To: Jonathan Corbet
  Cc: Allen Huang, linux-kernel, 'Michael Chen',
	'Charles', 'Joseph Chang'

On Thursday 20 September 2012, Arnd Bergmann wrote:
> On Wednesday 19 September 2012, Jonathan Corbet wrote:
> > On Wed, 19 Sep 2012 13:58:08 +0800
> > Allen Huang (黃偉格)  <allen_huang@davicom.com.tw> wrote:
> > 
> > > I'm Allen Huang from Davicom. We are hereby opensourcing the linux
> > > driver for our DM9000C. 
> > 
> > That is great, but please read the development process documentation on
> > how best to submit something like this.  We would much rather see a patch
> > (inline, not as an attachment) to facilitate the review.
> 
> More importantly, the patch should be against the version that is
> already present in the kernel as drivers/net/ethernet/davicom/dm9000.c,
> which appears to be mostly the same as the version that is submitted
> here.
> 
> So while all the comments on the driver are valuable, they also apply
> to the code we already have since 2005.

For fun, I've also tracked down the version that the new submission is
branched from, it's 2.6.29 with a small number of bug fixes that
are in later version. Here is the diff against the 2.6.29 version
of the driver. There are a few changes to the PHY handling that
are not also upstream in 3.6. It's probably worth submitting them
separately with a good explanation why they are required.

	Arnd

diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 254ec62..2cd4f0b 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -17,6 +17,13 @@
  * Additional updates, Copyright:
  *	Ben Dooks <ben@simtec.co.uk>
  *	Sascha Hauer <s.hauer@pengutronix.de>
+ *  
+ * 2010.07.20 V_R1 1.Write PHY Reg27 = 0xE100
+ *								 2.Just enable PHY once after GPIO setting in dm9000_init_dm9000()
+ *								 3.Remove power down PHY in dm9000_shutdown()
+ * 2010.07.20 V_R2 1.Delay 20ms after PHY power on
+ *								 2.Reset PHY after PHY power on in dm9000_init_dm9000()
+ * 2012.06.05 KT2.6.31_R2 1. Add the solution to fix the power-on FIFO data bytes shift issue! (Wr NCR 0x03)
  */
 
 #include <linux/module.h>
@@ -25,6 +32,7 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
+#include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
@@ -45,7 +53,7 @@
 #define DM9000_PHY		0x40	/* PHY address 0x01 */
 
 #define CARDNAME	"dm9000"
-#define DRV_VERSION	"1.31"
+#define DRV_VERSION	"2.6.31"
 
 /*
  * Transmit timeout, default 5 seconds.
@@ -126,6 +134,10 @@ typedef struct board_info {
 	u32		msg_enable;
 } board_info_t;
 
+static void
+dm9000_phy_write(struct net_device *dev,
+		 int phyaddr_unused, int reg, int value);
+
 /* debug code */
 
 #define dm9000_dbg(db, lev, msg...) do {		\
@@ -556,6 +568,18 @@ static void dm9000_show_carrier(board_info_t *db,
 		dev_info(db->dev, "%s: link down\n", ndev->name);
 }
 
+
+static unsigned char dm9000_type_to_char(enum dm9000_type type)
+{
+	switch (type) {
+	case TYPE_DM9000E: return 'e';
+	case TYPE_DM9000A: return 'a';
+	case TYPE_DM9000B: return 'b';
+	}
+
+	return '?';
+}
+
 static void
 dm9000_poll_work(struct work_struct *w)
 {
@@ -563,8 +587,11 @@ dm9000_poll_work(struct work_struct *w)
 	board_info_t *db = container_of(dw, board_info_t, phy_poll);
 	struct net_device *ndev = db->ndev;
 
-	if (db->flags & DM9000_PLATF_SIMPLE_PHY &&
-	    !(db->flags & DM9000_PLATF_EXT_PHY)) {
+//JJ2
+//	if (db->flags & DM9000_PLATF_SIMPLE_PHY &&
+//	    !(db->flags & DM9000_PLATF_EXT_PHY)) {
+//  =
+		if(1){						
 		unsigned nsr = dm9000_read_locked(db, DM9000_NSR);
 		unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0;
 		unsigned new_carrier;
@@ -572,6 +599,12 @@ dm9000_poll_work(struct work_struct *w)
 		new_carrier = (nsr & NSR_LINKST) ? 1 : 0;
 
 		if (old_carrier != new_carrier) {
+			
+			if (new_carrier)
+			  printk(KERN_INFO "[dm9000%c %s Ethernet Driver, V%s]: Link-Up!!\n",dm9000_type_to_char(db->type), CARDNAME, DRV_VERSION); //JJ2
+			else
+			  printk(KERN_INFO "[%s Ethernet Driver, V%s]: Link-Down!!\n", CARDNAME, DRV_VERSION); //JJ2
+			
 			if (netif_msg_link(db))
 				dm9000_show_carrier(db, new_carrier, nsr);
 
@@ -609,16 +642,7 @@ dm9000_release_board(struct platform_device *pdev, struct board_info *db)
 	kfree(db->addr_req);
 }
 
-static unsigned char dm9000_type_to_char(enum dm9000_type type)
-{
-	switch (type) {
-	case TYPE_DM9000E: return 'e';
-	case TYPE_DM9000A: return 'a';
-	case TYPE_DM9000B: return 'b';
-	}
 
-	return '?';
-}
 
 /*
  *  Set DM9000 multicast address
@@ -686,12 +710,17 @@ dm9000_init_dm9000(struct net_device *dev)
 	db->io_mode = ior(db, DM9000_ISR) >> 6;	/* ISR bit7:6 keeps I/O mode */
 
 	/* GPIO0 on pre-activate PHY */
-	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */
+//V_R1	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */
 	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */
 	iow(db, DM9000_GPR, 0);	/* Enable PHY */
+        mdelay(20);  //V_R2
+
+	dm9000_phy_write(dev, 0, 0, 0x8000); //V_R2 reset PHY
+        mdelay (20);
+
 
-	if (db->flags & DM9000_PLATF_EXT_PHY)
-		iow(db, DM9000_NCR, NCR_EXT_PHY);
+//	if (db->flags & DM9000_PLATF_EXT_PHY)
+//		iow(db, DM9000_NCR, NCR_EXT_PHY);
 
 	/* Program operating register */
 	iow(db, DM9000_TCR, 0);	        /* TX Polling clear */
@@ -718,6 +747,8 @@ dm9000_init_dm9000(struct net_device *dev)
 	db->tx_pkt_cnt = 0;
 	db->queue_pkt_len = 0;
 	dev->trans_start = 0;
+	
+	dm9000_phy_write(dev, 0, 27, 0xE100); //V_R1
 }
 
 /* Our watchdog timed out. Called by the networking layer */
@@ -732,6 +763,7 @@ static void dm9000_timeout(struct net_device *dev)
 	spin_lock_irqsave(&db->lock, flags);
 
 	netif_stop_queue(dev);
+	printk(KERN_INFO "[%s Ethernet Driver, V%s]: Timeout!!\n", CARDNAME, DRV_VERSION); //JJ1
 	dm9000_reset(db);
 	dm9000_init_dm9000(dev);
 	/* We can accept TX packets again */
@@ -888,6 +920,7 @@ dm9000_rx(struct net_device *dev)
 				if (netif_msg_rx_err(db))
 					dev_dbg(db->dev, "fifo error\n");
 				dev->stats.rx_fifo_errors++;
+				printk(KERN_INFO "[%s Ethernet Driver, V%s]: FIFO Over Flow!!\n", CARDNAME, DRV_VERSION); //JJ1
 			}
 			if (rxhdr.RxStatus & RSR_CE) {
 				if (netif_msg_rx_err(db))
@@ -974,7 +1007,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
 	/* Restore previous register address */
 	writeb(reg_save, db->io_addr);
 
-	spin_unlock_irqrestore(&db->lock, flags);
+	 spin_unlock_irqrestore(&db->lock, flags);
 
 	return IRQ_HANDLED;
 }
@@ -1140,7 +1173,7 @@ dm9000_shutdown(struct net_device *dev)
 
 	/* RESET device */
 	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);	/* PHY RESET */
-	iow(db, DM9000_GPR, 0x01);	/* Power-Down PHY */
+//V_R1	iow(db, DM9000_GPR, 0x01);	/* Power-Down PHY */
 	iow(db, DM9000_IMR, IMR_PAR);	/* Disable all interrupt */
 	iow(db, DM9000_RCR, 0x00);	/* Disable RX */
 }
@@ -1172,6 +1205,22 @@ dm9000_stop(struct net_device *ndev)
 
 #define res_size(_r) (((_r)->end - (_r)->start) + 1)
 
+static const struct net_device_ops dm9000_netdev_ops = {
+         .ndo_open = dm9000_open,
+         .ndo_stop = dm9000_stop,
+         .ndo_start_xmit = dm9000_start_xmit,
+         .ndo_tx_timeout = dm9000_timeout,
+         .ndo_set_multicast_list = dm9000_hash_table,
+         .ndo_do_ioctl = dm9000_ioctl,
+         .ndo_change_mtu = eth_change_mtu,
+         .ndo_validate_addr = eth_validate_addr,
+         .ndo_set_mac_address = eth_mac_addr,
+    #ifdef CONFIG_NET_POLL_CONTROLLER
+         .ndo_poll_controller = dm9000_poll_controller,
+    #endif
+};
+
+
 /*
  * Search DM9000 board, allocate space and register it
  */
@@ -1197,7 +1246,7 @@ dm9000_probe(struct platform_device *pdev)
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	dev_dbg(&pdev->dev, "dm9000_probe()\n");
-
+	 ndev->netdev_ops = &dm9000_netdev_ops;
 	/* setup board info structure */
 	db = netdev_priv(ndev);
 	memset(db, 0, sizeof(*db));
@@ -1260,6 +1309,8 @@ dm9000_probe(struct platform_device *pdev)
 	/* fill in parameters for net-dev structure */
 	ndev->base_addr = (unsigned long)db->io_addr;
 	ndev->irq	= db->irq_res->start;
+	//Stone add
+	printk("[dm9] %s ndev->irq=%x \n",__func__,ndev->irq);
 
 	/* ensure at least we have a default set of IO routines */
 	dm9000_set_io(db, iosize);
@@ -1297,7 +1348,9 @@ dm9000_probe(struct platform_device *pdev)
 	db->flags |= DM9000_PLATF_SIMPLE_PHY;
 #endif
 
-	dm9000_reset(db);
+//Stone add
+//	dm9000_reset(db);
+  iow(db, DM9000_NCR, 0x03);
 
 	/* try multiple times, DM9000 sometimes gets the read wrong */
 	for (i = 0; i < 8; i++) {
@@ -1306,10 +1359,18 @@ dm9000_probe(struct platform_device *pdev)
 		id_val |= (u32)ior(db, DM9000_PIDL) << 16;
 		id_val |= (u32)ior(db, DM9000_PIDH) << 24;
 
+		printk("[dm9].%d read id 0x%08x\n", i+1, id_val);
+		
 		if (id_val == DM9000_ID)
 			break;
 		dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
 	}
+	
+	printk(KERN_INFO "[%s Ethernet Driver, V%s]: KV= %d.%d.%d !!\n", CARDNAME, DRV_VERSION,  //JJ1 
+	                            (LINUX_VERSION_CODE>>16 & 0xff),
+	                            (LINUX_VERSION_CODE>>8 & 0xff),
+	                            (LINUX_VERSION_CODE & 0xff) ); //#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+	printk(KERN_INFO "[%s Ethernet Driver, V%s]: ChipID= 0x%x !!\n", CARDNAME, DRV_VERSION, id_val ); // JJ1
 
 	if (id_val != DM9000_ID) {
 		dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
@@ -1321,6 +1382,7 @@ dm9000_probe(struct platform_device *pdev)
 
 	id_val = ior(db, DM9000_CHIPR);
 	dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);
+	printk(KERN_INFO "[DM9000]dm9000 revision 0x%02x\n", id_val); //V_R1
 
 	switch (id_val) {
 	case CHIPR_DM9000A:
@@ -1338,7 +1400,12 @@ dm9000_probe(struct platform_device *pdev)
 
 	/* driver system function */
 	ether_setup(ndev);
-
+	
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+			ndev->netdev_ops = &dm9000_netdev_ops; // new kernel 2.6.31 
+			ndev->watchdog_timeo	= msecs_to_jiffies(watchdog);	
+	 		ndev->ethtool_ops	 = &dm9000_ethtool_ops;
+#else
 	ndev->open		 = &dm9000_open;
 	ndev->hard_start_xmit    = &dm9000_start_xmit;
 	ndev->tx_timeout         = &dm9000_timeout;
@@ -1347,6 +1414,8 @@ dm9000_probe(struct platform_device *pdev)
 	ndev->set_multicast_list = &dm9000_hash_table;
 	ndev->ethtool_ops	 = &dm9000_ethtool_ops;
 	ndev->do_ioctl		 = &dm9000_ioctl;
+#endif
+
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	ndev->poll_controller	 = &dm9000_poll_controller;
@@ -1376,8 +1445,16 @@ dm9000_probe(struct platform_device *pdev)
 		/* try reading from mac */
 		
 		mac_src = "chip";
+
+		static unsigned char mac_addr[6] = {0x00,0x11,0x22,0x33,0x44,0x55};
+		static unsigned char mac_tmp[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
 		for (i = 0; i < 6; i++)
 			ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
+
+		// Mark Chang 20100521
+		// -------------------
+		if (!memcmp(ndev->dev_addr, mac_tmp, 6))
+			memcpy(ndev->dev_addr, mac_addr, 6);
 	}
 
 	if (!is_valid_ether_addr(ndev->dev_addr))
diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h
index ba25cf5..81dc979 100644
--- a/drivers/net/dm9000.h
+++ b/drivers/net/dm9000.h
@@ -46,7 +46,7 @@
 #define DM9000_SMCR            0x2F
 
 #define CHIPR_DM9000A	       0x19
-#define CHIPR_DM9000B	       0x1B
+#define CHIPR_DM9000B	       0x1A  //V_R1 0x1B
 
 #define DM9000_MRCMDX          0xF0
 #define DM9000_MRCMD           0xF2

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: Davicom DM9000C driver
  2012-09-20  9:08   ` Arnd Bergmann
  2012-09-20 11:02     ` Arnd Bergmann
@ 2012-09-20 13:30     ` Jonathan Corbet
  1 sibling, 0 replies; 7+ messages in thread
From: Jonathan Corbet @ 2012-09-20 13:30 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Allen Huang, linux-kernel, 'Michael Chen',
	'Charles', 'Joseph Chang'

On Thu, 20 Sep 2012 09:08:00 +0000
Arnd Bergmann <arnd@arndb.de> wrote:

> More importantly, the patch should be against the version that is
> already present in the kernel as drivers/net/ethernet/davicom/dm9000.c,
> which appears to be mostly the same as the version that is submitted
> here.

Sigh.  Leave it to me to miss the most important part of all.  Ignore
me, please, and listen to Arnd - good advice in general.

jon

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: Davicom DM9000C driver
  2012-09-20 11:02     ` Arnd Bergmann
@ 2012-09-21  1:49       ` Michael Chen
  0 siblings, 0 replies; 7+ messages in thread
From: Michael Chen @ 2012-09-21  1:49 UTC (permalink / raw)
  To: 'Arnd Bergmann', 'Jonathan Corbet'
  Cc: 'Allen Huang ("黃偉格")',
	linux-kernel, 'Joseph Chang',
	'劉元智(Russell Liu)'

Dear Arnd and Linux Expert,

First of all, appreciate you all for your efforts on our DM9000C driver. 

Davicom Semiconductor Inc. is a fabless IC design house, located in Taiwan.
DM9000C is 10/100Mbps Ethernet IC with ISA-like interface.

Meanwhile, to facilitate the coming works with you efficiently, the key
members at Davicom side will be:
Mr. Allen Huang, PM
Mr. Russell Liu, Sr. FAE
Mr. Joseph Chang, Sr. Software Manager

Look forward to your guidance to make our product driver conform Linux.

Thanks.

BR,
Michael Chen
Director
Davicom Semiconductor Inc.
www.davicom.com.tw

-----Original Message-----
From: Arnd Bergmann [mailto:arnd@arndb.de] 
Sent: Thursday, September 20, 2012 7:03 PM
To: Jonathan Corbet
Cc: Allen Huang ("黃偉格"); linux-kernel@vger.kernel.org; 'Michael Chen';
'Charles'; 'Joseph Chang'
Subject: Re: Davicom DM9000C driver

On Thursday 20 September 2012, Arnd Bergmann wrote:
> On Wednesday 19 September 2012, Jonathan Corbet wrote:
> > On Wed, 19 Sep 2012 13:58:08 +0800
> > Allen Huang (黃偉格)  <allen_huang@davicom.com.tw> wrote:
> > 
> > > I'm Allen Huang from Davicom. We are hereby opensourcing the linux
> > > driver for our DM9000C. 
> > 
> > That is great, but please read the development process documentation on
> > how best to submit something like this.  We would much rather see a
patch
> > (inline, not as an attachment) to facilitate the review.
> 
> More importantly, the patch should be against the version that is
> already present in the kernel as drivers/net/ethernet/davicom/dm9000.c,
> which appears to be mostly the same as the version that is submitted
> here.
> 
> So while all the comments on the driver are valuable, they also apply
> to the code we already have since 2005.

For fun, I've also tracked down the version that the new submission is
branched from, it's 2.6.29 with a small number of bug fixes that
are in later version. Here is the diff against the 2.6.29 version
of the driver. There are a few changes to the PHY handling that
are not also upstream in 3.6. It's probably worth submitting them
separately with a good explanation why they are required.

	Arnd

diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 254ec62..2cd4f0b 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -17,6 +17,13 @@
  * Additional updates, Copyright:
  *	Ben Dooks <ben@simtec.co.uk>
  *	Sascha Hauer <s.hauer@pengutronix.de>
+ *  
+ * 2010.07.20 V_R1 1.Write PHY Reg27 = 0xE100
+ *								 2.Just
enable PHY once after GPIO setting in dm9000_init_dm9000()
+ *								 3.Remove
power down PHY in dm9000_shutdown()
+ * 2010.07.20 V_R2 1.Delay 20ms after PHY power on
+ *								 2.Reset PHY
after PHY power on in dm9000_init_dm9000()
+ * 2012.06.05 KT2.6.31_R2 1. Add the solution to fix the power-on FIFO data
bytes shift issue! (Wr NCR 0x03)
  */
 
 #include <linux/module.h>
@@ -25,6 +32,7 @@
 #include <linux/etherdevice.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
+#include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
@@ -45,7 +53,7 @@
 #define DM9000_PHY		0x40	/* PHY address 0x01 */
 
 #define CARDNAME	"dm9000"
-#define DRV_VERSION	"1.31"
+#define DRV_VERSION	"2.6.31"
 
 /*
  * Transmit timeout, default 5 seconds.
@@ -126,6 +134,10 @@ typedef struct board_info {
 	u32		msg_enable;
 } board_info_t;
 
+static void
+dm9000_phy_write(struct net_device *dev,
+		 int phyaddr_unused, int reg, int value);
+
 /* debug code */
 
 #define dm9000_dbg(db, lev, msg...) do {		\
@@ -556,6 +568,18 @@ static void dm9000_show_carrier(board_info_t *db,
 		dev_info(db->dev, "%s: link down\n", ndev->name);
 }
 
+
+static unsigned char dm9000_type_to_char(enum dm9000_type type)
+{
+	switch (type) {
+	case TYPE_DM9000E: return 'e';
+	case TYPE_DM9000A: return 'a';
+	case TYPE_DM9000B: return 'b';
+	}
+
+	return '?';
+}
+
 static void
 dm9000_poll_work(struct work_struct *w)
 {
@@ -563,8 +587,11 @@ dm9000_poll_work(struct work_struct *w)
 	board_info_t *db = container_of(dw, board_info_t, phy_poll);
 	struct net_device *ndev = db->ndev;
 
-	if (db->flags & DM9000_PLATF_SIMPLE_PHY &&
-	    !(db->flags & DM9000_PLATF_EXT_PHY)) {
+//JJ2
+//	if (db->flags & DM9000_PLATF_SIMPLE_PHY &&
+//	    !(db->flags & DM9000_PLATF_EXT_PHY)) {
+//  =
+		if(1){						
 		unsigned nsr = dm9000_read_locked(db, DM9000_NSR);
 		unsigned old_carrier = netif_carrier_ok(ndev) ? 1 : 0;
 		unsigned new_carrier;
@@ -572,6 +599,12 @@ dm9000_poll_work(struct work_struct *w)
 		new_carrier = (nsr & NSR_LINKST) ? 1 : 0;
 
 		if (old_carrier != new_carrier) {
+			
+			if (new_carrier)
+			  printk(KERN_INFO "[dm9000%c %s Ethernet Driver,
V%s]: Link-Up!!\n",dm9000_type_to_char(db->type), CARDNAME, DRV_VERSION);
//JJ2
+			else
+			  printk(KERN_INFO "[%s Ethernet Driver, V%s]:
Link-Down!!\n", CARDNAME, DRV_VERSION); //JJ2
+			
 			if (netif_msg_link(db))
 				dm9000_show_carrier(db, new_carrier, nsr);
 
@@ -609,16 +642,7 @@ dm9000_release_board(struct platform_device *pdev,
struct board_info *db)
 	kfree(db->addr_req);
 }
 
-static unsigned char dm9000_type_to_char(enum dm9000_type type)
-{
-	switch (type) {
-	case TYPE_DM9000E: return 'e';
-	case TYPE_DM9000A: return 'a';
-	case TYPE_DM9000B: return 'b';
-	}
 
-	return '?';
-}
 
 /*
  *  Set DM9000 multicast address
@@ -686,12 +710,17 @@ dm9000_init_dm9000(struct net_device *dev)
 	db->io_mode = ior(db, DM9000_ISR) >> 6;	/* ISR bit7:6 keeps I/O mode
*/
 
 	/* GPIO0 on pre-activate PHY */
-	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */
+//V_R1	iow(db, DM9000_GPR, 0);	/* REG_1F bit0 activate phyxcer */
 	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */
 	iow(db, DM9000_GPR, 0);	/* Enable PHY */
+        mdelay(20);  //V_R2
+
+	dm9000_phy_write(dev, 0, 0, 0x8000); //V_R2 reset PHY
+        mdelay (20);
+
 
-	if (db->flags & DM9000_PLATF_EXT_PHY)
-		iow(db, DM9000_NCR, NCR_EXT_PHY);
+//	if (db->flags & DM9000_PLATF_EXT_PHY)
+//		iow(db, DM9000_NCR, NCR_EXT_PHY);
 
 	/* Program operating register */
 	iow(db, DM9000_TCR, 0);	        /* TX Polling clear */
@@ -718,6 +747,8 @@ dm9000_init_dm9000(struct net_device *dev)
 	db->tx_pkt_cnt = 0;
 	db->queue_pkt_len = 0;
 	dev->trans_start = 0;
+	
+	dm9000_phy_write(dev, 0, 27, 0xE100); //V_R1
 }
 
 /* Our watchdog timed out. Called by the networking layer */
@@ -732,6 +763,7 @@ static void dm9000_timeout(struct net_device *dev)
 	spin_lock_irqsave(&db->lock, flags);
 
 	netif_stop_queue(dev);
+	printk(KERN_INFO "[%s Ethernet Driver, V%s]: Timeout!!\n", CARDNAME,
DRV_VERSION); //JJ1
 	dm9000_reset(db);
 	dm9000_init_dm9000(dev);
 	/* We can accept TX packets again */
@@ -888,6 +920,7 @@ dm9000_rx(struct net_device *dev)
 				if (netif_msg_rx_err(db))
 					dev_dbg(db->dev, "fifo error\n");
 				dev->stats.rx_fifo_errors++;
+				printk(KERN_INFO "[%s Ethernet Driver, V%s]:
FIFO Over Flow!!\n", CARDNAME, DRV_VERSION); //JJ1
 			}
 			if (rxhdr.RxStatus & RSR_CE) {
 				if (netif_msg_rx_err(db))
@@ -974,7 +1007,7 @@ static irqreturn_t dm9000_interrupt(int irq, void
*dev_id)
 	/* Restore previous register address */
 	writeb(reg_save, db->io_addr);
 
-	spin_unlock_irqrestore(&db->lock, flags);
+	 spin_unlock_irqrestore(&db->lock, flags);
 
 	return IRQ_HANDLED;
 }
@@ -1140,7 +1173,7 @@ dm9000_shutdown(struct net_device *dev)
 
 	/* RESET device */
 	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET);	/* PHY RESET */
-	iow(db, DM9000_GPR, 0x01);	/* Power-Down PHY */
+//V_R1	iow(db, DM9000_GPR, 0x01);	/* Power-Down PHY */
 	iow(db, DM9000_IMR, IMR_PAR);	/* Disable all interrupt */
 	iow(db, DM9000_RCR, 0x00);	/* Disable RX */
 }
@@ -1172,6 +1205,22 @@ dm9000_stop(struct net_device *ndev)
 
 #define res_size(_r) (((_r)->end - (_r)->start) + 1)
 
+static const struct net_device_ops dm9000_netdev_ops = {
+         .ndo_open = dm9000_open,
+         .ndo_stop = dm9000_stop,
+         .ndo_start_xmit = dm9000_start_xmit,
+         .ndo_tx_timeout = dm9000_timeout,
+         .ndo_set_multicast_list = dm9000_hash_table,
+         .ndo_do_ioctl = dm9000_ioctl,
+         .ndo_change_mtu = eth_change_mtu,
+         .ndo_validate_addr = eth_validate_addr,
+         .ndo_set_mac_address = eth_mac_addr,
+    #ifdef CONFIG_NET_POLL_CONTROLLER
+         .ndo_poll_controller = dm9000_poll_controller,
+    #endif
+};
+
+
 /*
  * Search DM9000 board, allocate space and register it
  */
@@ -1197,7 +1246,7 @@ dm9000_probe(struct platform_device *pdev)
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	dev_dbg(&pdev->dev, "dm9000_probe()\n");
-
+	 ndev->netdev_ops = &dm9000_netdev_ops;
 	/* setup board info structure */
 	db = netdev_priv(ndev);
 	memset(db, 0, sizeof(*db));
@@ -1260,6 +1309,8 @@ dm9000_probe(struct platform_device *pdev)
 	/* fill in parameters for net-dev structure */
 	ndev->base_addr = (unsigned long)db->io_addr;
 	ndev->irq	= db->irq_res->start;
+	//Stone add
+	printk("[dm9] %s ndev->irq=%x \n",__func__,ndev->irq);
 
 	/* ensure at least we have a default set of IO routines */
 	dm9000_set_io(db, iosize);
@@ -1297,7 +1348,9 @@ dm9000_probe(struct platform_device *pdev)
 	db->flags |= DM9000_PLATF_SIMPLE_PHY;
 #endif
 
-	dm9000_reset(db);
+//Stone add
+//	dm9000_reset(db);
+  iow(db, DM9000_NCR, 0x03);
 
 	/* try multiple times, DM9000 sometimes gets the read wrong */
 	for (i = 0; i < 8; i++) {
@@ -1306,10 +1359,18 @@ dm9000_probe(struct platform_device *pdev)
 		id_val |= (u32)ior(db, DM9000_PIDL) << 16;
 		id_val |= (u32)ior(db, DM9000_PIDH) << 24;
 
+		printk("[dm9].%d read id 0x%08x\n", i+1, id_val);
+		
 		if (id_val == DM9000_ID)
 			break;
 		dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
 	}
+	
+	printk(KERN_INFO "[%s Ethernet Driver, V%s]: KV= %d.%d.%d !!\n",
CARDNAME, DRV_VERSION,  //JJ1 
+	                            (LINUX_VERSION_CODE>>16 & 0xff),
+	                            (LINUX_VERSION_CODE>>8 & 0xff),
+	                            (LINUX_VERSION_CODE & 0xff) ); //#define
KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+	printk(KERN_INFO "[%s Ethernet Driver, V%s]: ChipID= 0x%x !!\n",
CARDNAME, DRV_VERSION, id_val ); // JJ1
 
 	if (id_val != DM9000_ID) {
 		dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
@@ -1321,6 +1382,7 @@ dm9000_probe(struct platform_device *pdev)
 
 	id_val = ior(db, DM9000_CHIPR);
 	dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);
+	printk(KERN_INFO "[DM9000]dm9000 revision 0x%02x\n", id_val); //V_R1
 
 	switch (id_val) {
 	case CHIPR_DM9000A:
@@ -1338,7 +1400,12 @@ dm9000_probe(struct platform_device *pdev)
 
 	/* driver system function */
 	ether_setup(ndev);
-
+	
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31)
+			ndev->netdev_ops = &dm9000_netdev_ops; // new kernel
2.6.31 
+			ndev->watchdog_timeo	=
msecs_to_jiffies(watchdog);	
+	 		ndev->ethtool_ops	 = &dm9000_ethtool_ops;
+#else
 	ndev->open		 = &dm9000_open;
 	ndev->hard_start_xmit    = &dm9000_start_xmit;
 	ndev->tx_timeout         = &dm9000_timeout;
@@ -1347,6 +1414,8 @@ dm9000_probe(struct platform_device *pdev)
 	ndev->set_multicast_list = &dm9000_hash_table;
 	ndev->ethtool_ops	 = &dm9000_ethtool_ops;
 	ndev->do_ioctl		 = &dm9000_ioctl;
+#endif
+
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	ndev->poll_controller	 = &dm9000_poll_controller;
@@ -1376,8 +1445,16 @@ dm9000_probe(struct platform_device *pdev)
 		/* try reading from mac */
 		
 		mac_src = "chip";
+
+		static unsigned char mac_addr[6] =
{0x00,0x11,0x22,0x33,0x44,0x55};
+		static unsigned char mac_tmp[6] = {0xff,0xff,0xff,0xff,0xff,
0xff};
 		for (i = 0; i < 6; i++)
 			ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
+
+		// Mark Chang 20100521
+		// -------------------
+		if (!memcmp(ndev->dev_addr, mac_tmp, 6))
+			memcpy(ndev->dev_addr, mac_addr, 6);
 	}
 
 	if (!is_valid_ether_addr(ndev->dev_addr))
diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h
index ba25cf5..81dc979 100644
--- a/drivers/net/dm9000.h
+++ b/drivers/net/dm9000.h
@@ -46,7 +46,7 @@
 #define DM9000_SMCR            0x2F
 
 #define CHIPR_DM9000A	       0x19
-#define CHIPR_DM9000B	       0x1B
+#define CHIPR_DM9000B	       0x1A  //V_R1 0x1B
 
 #define DM9000_MRCMDX          0xF0
 #define DM9000_MRCMD           0xF2

-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-09-21  2:19 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-19  5:58 Davicom DM9000C driver Allen Huang (黃偉格)
2012-09-19 16:39 ` Bruno Prémont
2012-09-19 23:35 ` Jonathan Corbet
2012-09-20  9:08   ` Arnd Bergmann
2012-09-20 11:02     ` Arnd Bergmann
2012-09-21  1:49       ` Michael Chen
2012-09-20 13:30     ` Jonathan Corbet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).