diff options
Diffstat (limited to 'drivers/net/ethernet/davicom/dm9000.c')
| -rw-r--r-- | drivers/net/ethernet/davicom/dm9000.c | 146 | 
1 files changed, 89 insertions, 57 deletions
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 5f5896e522d..13723c96d1a 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -23,7 +23,6 @@  #include <linux/ioport.h>  #include <linux/netdevice.h>  #include <linux/etherdevice.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/skbuff.h>  #include <linux/spinlock.h> @@ -110,8 +109,9 @@ typedef struct board_info {  	u8		imr_all;  	unsigned int	flags; -	unsigned int	in_suspend :1; -	unsigned int	wake_supported :1; +	unsigned int	in_timeout:1; +	unsigned int	in_suspend:1; +	unsigned int	wake_supported:1;  	enum dm9000_type type; @@ -158,23 +158,11 @@ static inline board_info_t *to_dm9000_board(struct net_device *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) +ior(board_info_t *db, int reg)  {  	writeb(reg, db->io_addr);  	return readb(db->io_data); @@ -185,12 +173,33 @@ ior(board_info_t * db, int reg)   */  static void -iow(board_info_t * db, int reg, int value) +iow(board_info_t *db, int reg, int value)  {  	writeb(reg, db->io_addr);  	writeb(value, db->io_data);  } +static void +dm9000_reset(board_info_t *db) +{ +	dev_dbg(db->dev, "resetting device\n"); + +	/* Reset DM9000, see DM9000 Application Notes V1.22 Jun 11, 2004 page 29 +	 * The essential point is that we have to do a double reset, and the +	 * instruction is to set LBK into MAC internal loopback mode. +	 */ +	iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); +	udelay(100); /* Application note says at least 20 us */ +	if (ior(db, DM9000_NCR) & 1) +		dev_err(db->dev, "dm9000 did not respond to first reset\n"); + +	iow(db, DM9000_NCR, 0); +	iow(db, DM9000_NCR, NCR_RST | NCR_MAC_LBK); +	udelay(100); +	if (ior(db, DM9000_NCR) & 1) +		dev_err(db->dev, "dm9000 did not respond to second reset\n"); +} +  /* routines for sending block to chip */  static void dm9000_outblk_8bit(void __iomem *reg, void *data, int count) @@ -265,7 +274,7 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count)   */  static void dm9000_msleep(board_info_t *db, unsigned int ms)  { -	if (db->in_suspend) +	if (db->in_suspend || db->in_timeout)  		mdelay(ms);  	else  		msleep(ms); @@ -326,7 +335,8 @@ dm9000_phy_write(struct net_device *dev,  	unsigned long reg_save;  	dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value); -	mutex_lock(&db->addr_lock); +	if (!db->in_timeout) +		mutex_lock(&db->addr_lock);  	spin_lock_irqsave(&db->lock, flags); @@ -357,7 +367,8 @@ dm9000_phy_write(struct net_device *dev,  	writeb(reg_save, db->io_addr);  	spin_unlock_irqrestore(&db->lock, flags); -	mutex_unlock(&db->addr_lock); +	if (!db->in_timeout) +		mutex_unlock(&db->addr_lock);  }  /* dm9000_set_io @@ -736,23 +747,28 @@ static const struct ethtool_ops dm9000_ethtool_ops = {  	.get_link		= dm9000_get_link,  	.get_wol		= dm9000_get_wol,  	.set_wol		= dm9000_set_wol, - 	.get_eeprom_len		= dm9000_get_eeprom_len, - 	.get_eeprom		= dm9000_get_eeprom, - 	.set_eeprom		= dm9000_set_eeprom, +	.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)  { +	int lpa;  	struct net_device *ndev = db->ndev; +	struct mii_if_info *mii = &db->mii;  	unsigned ncr = dm9000_read_locked(db, DM9000_NCR); -	if (carrier) -		dev_info(db->dev, "%s: link up, %dMbps, %s-duplex, no LPA\n", +	if (carrier) { +		lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA); +		dev_info(db->dev, +			 "%s: link up, %dMbps, %s-duplex, lpa 0x%04X\n",  			 ndev->name, (nsr & NSR_SPEED) ? 10 : 100, -			 (ncr & NCR_FDX) ? "full" : "half"); -	else +			 (ncr & NCR_FDX) ? "full" : "half", lpa); +	} else {  		dev_info(db->dev, "%s: link down\n", ndev->name); +	}  }  static void @@ -781,7 +797,7 @@ dm9000_poll_work(struct work_struct *w)  		}  	} else  		mii_check_media(&db->mii, netif_msg_link(db), 0); -	 +  	if (netif_running(ndev))  		dm9000_schedule_poll(db);  } @@ -869,6 +885,18 @@ dm9000_hash_table(struct net_device *dev)  	spin_unlock_irqrestore(&db->lock, flags);  } +static void +dm9000_mask_interrupts(board_info_t *db) +{ +	iow(db, DM9000_IMR, IMR_PAR); +} + +static void +dm9000_unmask_interrupts(board_info_t *db) +{ +	iow(db, DM9000_IMR, db->imr_all); +} +  /*   * Initialize dm9000 board   */ @@ -881,6 +909,9 @@ dm9000_init_dm9000(struct net_device *dev)  	dm9000_dbg(db, 1, "entering %s\n", __func__); +	dm9000_reset(db); +	dm9000_mask_interrupts(db); +  	/* I/O mode */  	db->io_mode = ior(db, DM9000_ISR) >> 6;	/* ISR bit7:6 keeps I/O mode */ @@ -890,9 +921,15 @@ dm9000_init_dm9000(struct net_device *dev)  			(dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0);  	iow(db, DM9000_GPCR, GPCR_GEP_CNTL);	/* Let GPIO0 output */ +	iow(db, DM9000_GPR, 0); -	dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ -	dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); /* Init */ +	/* If we are dealing with DM9000B, some extra steps are required: a +	 * manual phy reset, and setting init params. +	 */ +	if (db->type == TYPE_DM9000B) { +		dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); +		dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); +	}  	ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0; @@ -922,9 +959,6 @@ dm9000_init_dm9000(struct net_device *dev)  	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; @@ -940,17 +974,19 @@ static void dm9000_timeout(struct net_device *dev)  	/* Save previous register address */  	spin_lock_irqsave(&db->lock, flags); +	db->in_timeout = 1;  	reg_save = readb(db->io_addr);  	netif_stop_queue(dev); -	dm9000_reset(db);  	dm9000_init_dm9000(dev); +	dm9000_unmask_interrupts(db);  	/* We can accept TX packets again */  	dev->trans_start = jiffies; /* prevent tx timeout */  	netif_wake_queue(dev);  	/* Restore previous register address */  	writeb(reg_save, db->io_addr); +	db->in_timeout = 0;  	spin_unlock_irqrestore(&db->lock, flags);  } @@ -1014,7 +1050,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)  	spin_unlock_irqrestore(&db->lock, flags);  	/* free this SKB */ -	dev_kfree_skb(skb); +	dev_consume_skb_any(skb);  	return NETDEV_TX_OK;  } @@ -1074,7 +1110,6 @@ dm9000_rx(struct net_device *dev)  		if (rxbyte & DM9000_PKT_ERR) {  			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;  		} @@ -1174,9 +1209,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)  	/* Save previous register address */  	reg_save = readb(db->io_addr); -	/* Disable all interrupts */ -	iow(db, DM9000_IMR, IMR_PAR); - +	dm9000_mask_interrupts(db);  	/* Got DM9000 interrupt status */  	int_status = ior(db, DM9000_ISR);	/* Got ISR */  	iow(db, DM9000_ISR, int_status);	/* Clear ISR status */ @@ -1199,9 +1232,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)  		}  	} -	/* Re-enable interrupt mask */ -	iow(db, DM9000_IMR, db->imr_all); - +	dm9000_unmask_interrupts(db);  	/* Restore previous register address */  	writeb(reg_save, db->io_addr); @@ -1232,12 +1263,11 @@ static irqreturn_t dm9000_wol_interrupt(int irq, void *dev_id)  			dev_info(db->dev, "wake by link status change\n");  		if (wcr & WCR_SAMPLEST)  			dev_info(db->dev, "wake by sample packet\n"); -		if (wcr & WCR_MAGICST ) +		if (wcr & WCR_MAGICST)  			dev_info(db->dev, "wake by magic packet\n");  		if (!(wcr & (WCR_LINKST | WCR_SAMPLEST | WCR_MAGICST)))  			dev_err(db->dev, "wake signalled with no reason? "  				"NSR=0x%02x, WSR=0x%02x\n", nsr, wcr); -  	}  	spin_unlock_irqrestore(&db->lock, flags); @@ -1274,6 +1304,9 @@ dm9000_open(struct net_device *dev)  	 * may work, and tell the user that this is a problem */  	if (irqflags == IRQF_TRIGGER_NONE) +		irqflags = irq_get_trigger_type(dev->irq); + +	if (irqflags == IRQF_TRIGGER_NONE)  		dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");  	irqflags |= IRQF_SHARED; @@ -1283,19 +1316,23 @@ dm9000_open(struct net_device *dev)  	mdelay(1); /* delay needs by DM9000B */  	/* Initialize DM9000 board */ -	dm9000_reset(db);  	dm9000_init_dm9000(dev);  	if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))  		return -EAGAIN; +	/* Now that we have an interrupt handler hooked up we can unmask +	 * our interrupts +	 */ +	dm9000_unmask_interrupts(db);  	/* 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); + +	/* Poll initial link status */ +	schedule_delayed_work(&db->phy_poll, 1);  	return 0;  } @@ -1308,7 +1345,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 */ -	iow(db, DM9000_IMR, IMR_PAR);	/* Disable all interrupt */ +	dm9000_mask_interrupts(db);  	iow(db, DM9000_RCR, 0x00);	/* Disable RX */  } @@ -1529,12 +1566,7 @@ dm9000_probe(struct platform_device *pdev)  	db->flags |= DM9000_PLATF_SIMPLE_PHY;  #endif -	/* Fixing bug on dm9000_probe, takeover dm9000_reset(db), -	 * Need 'NCR_MAC_LBK' bit to indeed stable our DM9000 fifo -	 * while probe stage. -	 */ - -	iow(db, DM9000_NCR, NCR_MAC_LBK | NCR_RST); +	dm9000_reset(db);  	/* try multiple times, DM9000 sometimes gets the read wrong */  	for (i = 0; i < 8; i++) { @@ -1603,12 +1635,12 @@ dm9000_probe(struct platform_device *pdev)  	if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {  		mac_src = "platform data"; -		memcpy(ndev->dev_addr, pdata->dev_addr, 6); +		memcpy(ndev->dev_addr, pdata->dev_addr, ETH_ALEN);  	}  	if (!is_valid_ether_addr(ndev->dev_addr)) {  		/* try reading from mac */ -		 +  		mac_src = "chip";  		for (i = 0; i < 6; i++)  			ndev->dev_addr[i] = ior(db, i+DM9000_PAR); @@ -1677,8 +1709,8 @@ dm9000_drv_resume(struct device *dev)  			/* reset if we were not in wake mode to ensure if  			 * the device was powered off it is in a known state */  			if (!db->wake_state) { -				dm9000_reset(db);  				dm9000_init_dm9000(ndev); +				dm9000_unmask_interrupts(db);  			}  			netif_device_attach(ndev);  | 
