Commit ac9c6a20 authored by Jeff Garzik's avatar Jeff Garzik

winbond-840 (tulip clone) net driver updates:

* Support MII ethtool helper interface, and related ioctls.
* Replace some MII-related magic numbers with constants.
parent 6dd1b949
...@@ -100,7 +100,7 @@ obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o ...@@ -100,7 +100,7 @@ obj-$(CONFIG_AIRONET4500_NONCS) += aironet4500_card.o
obj-$(CONFIG_AIRONET4500_PROC) += aironet4500_proc.o obj-$(CONFIG_AIRONET4500_PROC) += aironet4500_proc.o
obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o
obj-$(CONFIG_WINBOND_840) += winbond-840.o obj-$(CONFIG_WINBOND_840) += winbond-840.o mii.o
obj-$(CONFIG_SUNDANCE) += sundance.o obj-$(CONFIG_SUNDANCE) += sundance.o
obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_HAMACHI) += hamachi.o
obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
power management. power management.
support for big endian descriptors support for big endian descriptors
Copyright (C) 2001 Manfred Spraul Copyright (C) 2001 Manfred Spraul
* ethtool support (jgarzik)
* Replace some MII-related magic numbers with constants (jgarzik)
TODO: TODO:
* enable pci_power_off * enable pci_power_off
...@@ -43,8 +45,8 @@ ...@@ -43,8 +45,8 @@
*/ */
#define DRV_NAME "winbond-840" #define DRV_NAME "winbond-840"
#define DRV_VERSION "1.01-c" #define DRV_VERSION "1.01-d"
#define DRV_RELDATE "6/30/2000" #define DRV_RELDATE "Nov-17-2001"
/* Automatically extracted configuration info: /* Automatically extracted configuration info:
...@@ -364,14 +366,11 @@ struct netdev_private { ...@@ -364,14 +366,11 @@ struct netdev_private {
unsigned int cur_tx, dirty_tx; unsigned int cur_tx, dirty_tx;
unsigned int tx_q_bytes; unsigned int tx_q_bytes;
unsigned int tx_full; /* The Tx queue is full. */ unsigned int tx_full; /* The Tx queue is full. */
/* These values are keep track of the transceiver/media in use. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int duplex_lock:1;
/* MII transceiver section. */ /* MII transceiver section. */
int mii_cnt; /* MII device addresses. */ int mii_cnt; /* MII device addresses. */
u16 advertising; /* NWay media advertisement */
unsigned char phys[MII_CNT]; /* MII device addresses, but only the first is used */ unsigned char phys[MII_CNT]; /* MII device addresses, but only the first is used */
u32 mii; u32 mii;
struct mii_if_info mii_if;
}; };
static int eeprom_read(long ioaddr, int location); static int eeprom_read(long ioaddr, int location);
...@@ -453,6 +452,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, ...@@ -453,6 +452,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
np->chip_id = chip_idx; np->chip_id = chip_idx;
np->drv_flags = pci_id_tbl[chip_idx].drv_flags; np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
spin_lock_init(&np->lock); spin_lock_init(&np->lock);
np->mii_if.dev = dev;
np->mii_if.mdio_read = mdio_read;
np->mii_if.mdio_write = mdio_write;
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
...@@ -462,16 +464,16 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, ...@@ -462,16 +464,16 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
/* The lower four bits are the media type. */ /* The lower four bits are the media type. */
if (option > 0) { if (option > 0) {
if (option & 0x200) if (option & 0x200)
np->full_duplex = 1; np->mii_if.full_duplex = 1;
if (option & 15) if (option & 15)
printk(KERN_INFO "%s: ignoring user supplied media type %d", printk(KERN_INFO "%s: ignoring user supplied media type %d",
dev->name, option & 15); dev->name, option & 15);
} }
if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0)
np->full_duplex = 1; np->mii_if.full_duplex = 1;
if (np->full_duplex) if (np->mii_if.full_duplex)
np->duplex_lock = 1; np->mii_if.duplex_lock = 1;
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
dev->open = &netdev_open; dev->open = &netdev_open;
...@@ -496,18 +498,19 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, ...@@ -496,18 +498,19 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
if (np->drv_flags & CanHaveMII) { if (np->drv_flags & CanHaveMII) {
int phy, phy_idx = 0; int phy, phy_idx = 0;
for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) { for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
int mii_status = mdio_read(dev, phy, 1); int mii_status = mdio_read(dev, phy, MII_BMSR);
if (mii_status != 0xffff && mii_status != 0x0000) { if (mii_status != 0xffff && mii_status != 0x0000) {
np->phys[phy_idx++] = phy; np->phys[phy_idx++] = phy;
np->advertising = mdio_read(dev, phy, 4); np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
np->mii = (mdio_read(dev, phy, 2) << 16)+ np->mii = (mdio_read(dev, phy, MII_PHYSID1) << 16)+
mdio_read(dev, phy, 3); mdio_read(dev, phy, MII_PHYSID2);
printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status " printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status "
"0x%4.4x advertising %4.4x.\n", "0x%4.4x advertising %4.4x.\n",
dev->name, np->mii, phy, mii_status, np->advertising); dev->name, np->mii, phy, mii_status, np->mii_if.advertising);
} }
} }
np->mii_cnt = phy_idx; np->mii_cnt = phy_idx;
np->mii_if.phy_id = np->phys[0];
if (phy_idx == 0) { if (phy_idx == 0) {
printk(KERN_WARNING "%s: MII PHY not found -- this device may " printk(KERN_WARNING "%s: MII PHY not found -- this device may "
"not operate correctly.\n", dev->name); "not operate correctly.\n", dev->name);
...@@ -654,7 +657,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val ...@@ -654,7 +657,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
int i; int i;
if (location == 4 && phy_id == np->phys[0]) if (location == 4 && phy_id == np->phys[0])
np->advertising = value; np->mii_if.advertising = value;
if (mii_preamble_required) if (mii_preamble_required)
mdio_sync(mdio_addr); mdio_sync(mdio_addr);
...@@ -728,12 +731,12 @@ static int update_link(struct net_device *dev) ...@@ -728,12 +731,12 @@ static int update_link(struct net_device *dev)
int duplex, fasteth, result, mii_reg; int duplex, fasteth, result, mii_reg;
/* BSMR */ /* BSMR */
mii_reg = mdio_read(dev, np->phys[0], 1); mii_reg = mdio_read(dev, np->phys[0], MII_BMSR);
if (mii_reg == 0xffff) if (mii_reg == 0xffff)
return np->csr6; return np->csr6;
/* reread: the link status bit is sticky */ /* reread: the link status bit is sticky */
mii_reg = mdio_read(dev, np->phys[0], 1); mii_reg = mdio_read(dev, np->phys[0], MII_BMSR);
if (!(mii_reg & 0x4)) { if (!(mii_reg & 0x4)) {
if (netif_carrier_ok(dev)) { if (netif_carrier_ok(dev)) {
if (debug) if (debug)
...@@ -759,18 +762,18 @@ static int update_link(struct net_device *dev) ...@@ -759,18 +762,18 @@ static int update_link(struct net_device *dev)
* Instead bit 9 and 13 of the BMCR are updated to the result * Instead bit 9 and 13 of the BMCR are updated to the result
* of the negotiation.. * of the negotiation..
*/ */
mii_reg = mdio_read(dev, np->phys[0], 0); mii_reg = mdio_read(dev, np->phys[0], MII_BMCR);
duplex = mii_reg & 0x100; duplex = mii_reg & BMCR_FULLDPLX;
fasteth = mii_reg & 0x2000; fasteth = mii_reg & BMCR_SPEED100;
} else { } else {
int negotiated; int negotiated;
mii_reg = mdio_read(dev, np->phys[0], 5); mii_reg = mdio_read(dev, np->phys[0], MII_LPA);
negotiated = mii_reg & np->advertising; negotiated = mii_reg & np->mii_if.advertising;
duplex = (negotiated & 0x0100) || ((negotiated & 0x02C0) == 0x0040); duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL);
fasteth = negotiated & 0x380; fasteth = negotiated & 0x380;
} }
duplex |= np->duplex_lock; duplex |= np->mii_if.duplex_lock;
/* remove fastether and fullduplex */ /* remove fastether and fullduplex */
result = np->csr6 & ~0x20000200; result = np->csr6 & ~0x20000200;
if (duplex) if (duplex)
...@@ -822,7 +825,7 @@ static inline void update_csr6(struct net_device *dev, int new) ...@@ -822,7 +825,7 @@ static inline void update_csr6(struct net_device *dev, int new)
/* and restart them with the new configuration */ /* and restart them with the new configuration */
writel(np->csr6, ioaddr + NetworkConfig); writel(np->csr6, ioaddr + NetworkConfig);
if (new & 0x200) if (new & 0x200)
np->full_duplex = 1; np->mii_if.full_duplex = 1;
} }
static void netdev_timer(unsigned long data) static void netdev_timer(unsigned long data)
...@@ -1131,7 +1134,7 @@ static void netdev_tx_done(struct net_device *dev) ...@@ -1131,7 +1134,7 @@ static void netdev_tx_done(struct net_device *dev)
if (tx_status & 0x0C80) np->stats.tx_carrier_errors++; if (tx_status & 0x0C80) np->stats.tx_carrier_errors++;
if (tx_status & 0x0200) np->stats.tx_window_errors++; if (tx_status & 0x0200) np->stats.tx_window_errors++;
if (tx_status & 0x0002) np->stats.tx_fifo_errors++; if (tx_status & 0x0002) np->stats.tx_fifo_errors++;
if ((tx_status & 0x0080) && np->full_duplex == 0) if ((tx_status & 0x0080) && np->mii_if.full_duplex == 0)
np->stats.tx_heartbeat_errors++; np->stats.tx_heartbeat_errors++;
#ifdef ETHER_STATS #ifdef ETHER_STATS
if (tx_status & 0x0100) np->stats.collisions16++; if (tx_status & 0x0100) np->stats.collisions16++;
...@@ -1469,6 +1472,56 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1469,6 +1472,56 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
return 0; return 0;
} }
/* get settings */
case ETHTOOL_GSET: {
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
spin_lock_irq(&np->lock);
mii_ethtool_gset(&np->mii_if, &ecmd);
spin_unlock_irq(&np->lock);
if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
}
/* set settings */
case ETHTOOL_SSET: {
int r;
struct ethtool_cmd ecmd;
if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
return -EFAULT;
spin_lock_irq(&np->lock);
r = mii_ethtool_sset(&np->mii_if, &ecmd);
spin_unlock_irq(&np->lock);
return r;
}
/* restart autonegotiation */
case ETHTOOL_NWAY_RST: {
return mii_nway_restart(&np->mii_if);
}
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
edata.data = mii_link_ok(&np->mii_if);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
/* get message-level */
case ETHTOOL_GMSGLVL: {
struct ethtool_value edata = {ETHTOOL_GMSGLVL};
edata.data = debug;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
/* set message-level */
case ETHTOOL_SMSGLVL: {
struct ethtool_value edata;
if (copy_from_user(&edata, useraddr, sizeof(edata)))
return -EFAULT;
debug = edata.data;
return 0;
}
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment