Commit f4d57a02 authored by Jeff Garzik's avatar Jeff Garzik

epic100 net driver updates:

* Fix wake-up sequence for some clone boards.
* Support media-related ethtool ioctls, using MII ethtool helper lib.
parent 948d8589
...@@ -53,11 +53,18 @@ ...@@ -53,11 +53,18 @@
LK1.1.10: LK1.1.10:
* revert MII transceiver init change (jgarzik) * revert MII transceiver init change (jgarzik)
LK1.1.11:
* implement ETHTOOL_[GS]SET, _NWAY_RST, _[GS]MSGLVL, _GLINK (jgarzik)
* replace some MII-related magic numbers with constants
LK1.1.12:
* fix power-up sequence
*/ */
#define DRV_NAME "epic100" #define DRV_NAME "epic100"
#define DRV_VERSION "1.11+LK1.1.10" #define DRV_VERSION "1.11+LK1.1.12"
#define DRV_RELDATE "July 6, 2001" #define DRV_RELDATE "Jan 18, 2002"
/* The user-configurable values. /* The user-configurable values.
...@@ -318,12 +325,9 @@ struct epic_private { ...@@ -318,12 +325,9 @@ struct epic_private {
/* Ring pointers. */ /* Ring pointers. */
spinlock_t lock; /* Group with Tx control cache line. */ spinlock_t lock; /* Group with Tx control cache line. */
unsigned int cur_tx, dirty_tx; unsigned int cur_tx, dirty_tx;
struct descriptor *last_tx_desc;
unsigned int cur_rx, dirty_rx; unsigned int cur_rx, dirty_rx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int rx_buf_sz; /* Based on MTU+slack. */
struct descriptor *last_rx_desc;
long last_rx_time; /* Last Rx, in jiffies. */
struct pci_dev *pci_dev; /* PCI bus location. */ struct pci_dev *pci_dev; /* PCI bus location. */
int chip_id, chip_flags; int chip_id, chip_flags;
...@@ -335,13 +339,9 @@ struct epic_private { ...@@ -335,13 +339,9 @@ struct epic_private {
signed char phys[4]; /* MII device addresses. */ signed char phys[4]; /* MII device addresses. */
u16 advertising; /* NWay media advertisement */ u16 advertising; /* NWay media advertisement */
int mii_phy_cnt; int mii_phy_cnt;
struct mii_if_info mii;
unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Current duplex setting. */
unsigned int duplex_lock:1; /* Duplex forced by the user. */
unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int default_port:4; /* Last dev->if_port value. */
unsigned int media2:4; /* Secondary monitored media port. */
unsigned int medialock:1; /* Don't sense media type. */
unsigned int mediasense:1; /* Media sensing in progress. */
}; };
static int epic_open(struct net_device *dev); static int epic_open(struct net_device *dev);
...@@ -420,6 +420,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -420,6 +420,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
ep = dev->priv; ep = dev->priv;
ep->mii.dev = dev;
ep->mii.mdio_read = mdio_read;
ep->mii.mdio_write = mdio_write;
ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
if (!ring_space) if (!ring_space)
...@@ -481,7 +484,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -481,7 +484,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
{ {
int phy, phy_idx = 0; int phy, phy_idx = 0;
for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); phy++) { for (phy = 1; phy < 32 && phy_idx < sizeof(ep->phys); 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) {
ep->phys[phy_idx++] = phy; ep->phys[phy_idx++] = phy;
printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control " printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control "
...@@ -492,16 +495,17 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -492,16 +495,17 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ep->mii_phy_cnt = phy_idx; ep->mii_phy_cnt = phy_idx;
if (phy_idx != 0) { if (phy_idx != 0) {
phy = ep->phys[0]; phy = ep->phys[0];
ep->advertising = mdio_read(dev, phy, 4); ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link " printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
"partner %4.4x.\n", "partner %4.4x.\n",
pdev->slot_name, ep->advertising, mdio_read(dev, phy, 5)); pdev->slot_name, ep->mii.advertising, mdio_read(dev, phy, 5));
} else if ( ! (ep->chip_flags & NO_MII)) { } else if ( ! (ep->chip_flags & NO_MII)) {
printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n", printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
pdev->slot_name); pdev->slot_name);
/* Use the known PHY address of the EPII. */ /* Use the known PHY address of the EPII. */
ep->phys[0] = 3; ep->phys[0] = 3;
} }
ep->mii.phy_id = ep->phys[0];
} }
/* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */ /* Turn off the MII xcvr (175 only!), leave the chip in low-power mode. */
...@@ -511,13 +515,11 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -511,13 +515,11 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
/* The lower four bits are the media type. */ /* The lower four bits are the media type. */
if (duplex) { if (duplex) {
ep->duplex_lock = ep->full_duplex = 1; ep->mii.duplex_lock = ep->mii.full_duplex = 1;
printk(KERN_INFO DRV_NAME "(%s): Forced full duplex operation requested.\n", printk(KERN_INFO DRV_NAME "(%s): Forced full duplex operation requested.\n",
pdev->slot_name); pdev->slot_name);
} }
dev->if_port = ep->default_port = option; dev->if_port = ep->default_port = option;
if (ep->default_port)
ep->medialock = 1;
/* The Epic-specific entries in the device structure. */ /* The Epic-specific entries in the device structure. */
dev->open = &epic_open; dev->open = &epic_open;
...@@ -676,9 +678,8 @@ static int epic_open(struct net_device *dev) ...@@ -676,9 +678,8 @@ static int epic_open(struct net_device *dev)
required by the details of which bits are reset and the transceiver required by the details of which bits are reset and the transceiver
wiring on the Ositech CardBus card. wiring on the Ositech CardBus card.
*/ */
#if 0
outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg); outl(0x12, ioaddr + MIICfg);
#endif
if (ep->chip_flags & MII_PWRDWN) if (ep->chip_flags & MII_PWRDWN)
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
...@@ -700,29 +701,29 @@ static int epic_open(struct net_device *dev) ...@@ -700,29 +701,29 @@ static int epic_open(struct net_device *dev)
if (media2miictl[dev->if_port & 15]) { if (media2miictl[dev->if_port & 15]) {
if (ep->mii_phy_cnt) if (ep->mii_phy_cnt)
mdio_write(dev, ep->phys[0], 0, media2miictl[dev->if_port&15]); mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]);
if (dev->if_port == 1) { if (dev->if_port == 1) {
if (debug > 1) if (debug > 1)
printk(KERN_INFO "%s: Using the 10base2 transceiver, MII " printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
"status %4.4x.\n", "status %4.4x.\n",
dev->name, mdio_read(dev, ep->phys[0], 1)); dev->name, mdio_read(dev, ep->phys[0], MII_BMSR));
} }
} else { } else {
int mii_reg5 = mdio_read(dev, ep->phys[0], 5); int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA);
if (mii_reg5 != 0xffff) { if (mii_lpa != 0xffff) {
if ((mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040) if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL)
ep->full_duplex = 1; ep->mii.full_duplex = 1;
else if (! (mii_reg5 & 0x4000)) else if (! (mii_lpa & LPA_LPACK))
mdio_write(dev, ep->phys[0], 0, 0x1200); mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
if (debug > 1) if (debug > 1)
printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d" printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
" register read of %4.4x.\n", dev->name, " register read of %4.4x.\n", dev->name,
ep->full_duplex ? "full" : "half", ep->mii.full_duplex ? "full" : "half",
ep->phys[0], mii_reg5); ep->phys[0], mii_lpa);
} }
} }
outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
outl(ep->rx_ring_dma, ioaddr + PRxCDAR); outl(ep->rx_ring_dma, ioaddr + PRxCDAR);
outl(ep->tx_ring_dma, ioaddr + PTxCDAR); outl(ep->tx_ring_dma, ioaddr + PTxCDAR);
...@@ -742,7 +743,7 @@ static int epic_open(struct net_device *dev) ...@@ -742,7 +743,7 @@ static int epic_open(struct net_device *dev)
printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x " printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
"%s-duplex.\n", "%s-duplex.\n",
dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL), dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL),
ep->full_duplex ? "full" : "half"); ep->mii.full_duplex ? "full" : "half");
/* Set the timer to switch to check for link beat and perhaps switch /* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */ to an alternate media type. */
...@@ -811,7 +812,7 @@ static void epic_restart(struct net_device *dev) ...@@ -811,7 +812,7 @@ static void epic_restart(struct net_device *dev)
ep->tx_threshold = TX_FIFO_THRESH; ep->tx_threshold = TX_FIFO_THRESH;
outl(ep->tx_threshold, ioaddr + TxThresh); outl(ep->tx_threshold, ioaddr + TxThresh);
outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)* outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)*
sizeof(struct epic_rx_desc), ioaddr + PRxCDAR); sizeof(struct epic_rx_desc), ioaddr + PRxCDAR);
outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)* outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)*
...@@ -837,20 +838,20 @@ static void check_media(struct net_device *dev) ...@@ -837,20 +838,20 @@ static void check_media(struct net_device *dev)
{ {
struct epic_private *ep = dev->priv; struct epic_private *ep = dev->priv;
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
int mii_reg5 = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], 5) : 0; int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0;
int negotiated = mii_reg5 & ep->advertising; int negotiated = mii_lpa & ep->mii.advertising;
int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
if (ep->duplex_lock) if (ep->mii.duplex_lock)
return; return;
if (mii_reg5 == 0xffff) /* Bogus read */ if (mii_lpa == 0xffff) /* Bogus read */
return; return;
if (ep->full_duplex != duplex) { if (ep->mii.full_duplex != duplex) {
ep->full_duplex = duplex; ep->mii.full_duplex = duplex;
printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link" printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"
" partner capability of %4.4x.\n", dev->name, " partner capability of %4.4x.\n", dev->name,
ep->full_duplex ? "full" : "half", ep->phys[0], mii_reg5); ep->mii.full_duplex ? "full" : "half", ep->phys[0], mii_lpa);
outl(ep->full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl); outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
} }
} }
...@@ -914,7 +915,6 @@ static void epic_init_ring(struct net_device *dev) ...@@ -914,7 +915,6 @@ static void epic_init_ring(struct net_device *dev)
ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
ep->dirty_tx = ep->cur_tx = 0; ep->dirty_tx = ep->cur_tx = 0;
ep->cur_rx = ep->dirty_rx = 0; ep->cur_rx = ep->dirty_rx = 0;
ep->last_rx_time = jiffies;
ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
/* Initialize all Rx descriptors. */ /* Initialize all Rx descriptors. */
...@@ -1351,17 +1351,66 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) ...@@ -1351,17 +1351,66 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
return -EFAULT; return -EFAULT;
switch (ethcmd) { switch (ethcmd) {
case ETHTOOL_GDRVINFO: case ETHTOOL_GDRVINFO: {
{ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, DRV_NAME);
strcpy (info.driver, DRV_NAME); strcpy (info.version, DRV_VERSION);
strcpy (info.version, DRV_VERSION); strcpy (info.bus_info, np->pci_dev->slot_name);
strcpy (info.bus_info, np->pci_dev->slot_name); if (copy_to_user (useraddr, &info, sizeof (info)))
if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT;
return -EFAULT; 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, &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, &ecmd);
spin_unlock_irq(&np->lock);
return r;
}
/* restart autonegotiation */
case ETHTOOL_NWAY_RST: {
return mii_nway_restart(&np->mii);
}
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
edata.data = mii_link_ok(&np->mii);
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;
}
default: default:
break; break;
} }
...@@ -1412,11 +1461,11 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1412,11 +1461,11 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (data->reg_num) { switch (data->reg_num) {
case 0: case 0:
/* Check for autonegotiation on or reset. */ /* Check for autonegotiation on or reset. */
ep->duplex_lock = (value & 0x9000) ? 0 : 1; ep->mii.duplex_lock = (value & 0x9000) ? 0 : 1;
if (ep->duplex_lock) if (ep->mii.duplex_lock)
ep->full_duplex = (value & 0x0100) ? 1 : 0; ep->mii.full_duplex = (value & 0x0100) ? 1 : 0;
break; break;
case 4: ep->advertising = value; break; case 4: ep->mii.advertising = value; break;
} }
/* Perhaps check_duplex(dev), depending on chip semantics. */ /* Perhaps check_duplex(dev), depending on chip semantics. */
} }
......
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