Commit f18ff4f7 authored by Jeff Garzik's avatar Jeff Garzik

[net drivers] update hamachi.c and starfire.c to use MII lib

parent f71c419e
...@@ -57,7 +57,7 @@ obj-$(CONFIG_TC35815) += tc35815.o ...@@ -57,7 +57,7 @@ obj-$(CONFIG_TC35815) += tc35815.o
obj-$(CONFIG_SK98LIN) += sk98lin/ obj-$(CONFIG_SK98LIN) += sk98lin/
obj-$(CONFIG_SKFP) += skfp/ obj-$(CONFIG_SKFP) += skfp/
obj-$(CONFIG_VIA_RHINE) += via-rhine.o mii.o obj-$(CONFIG_VIA_RHINE) += via-rhine.o mii.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o
# #
# end link order section # end link order section
...@@ -71,7 +71,7 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o ...@@ -71,7 +71,7 @@ obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o
obj-$(CONFIG_WINBOND_840) += mii.o obj-$(CONFIG_WINBOND_840) += mii.o
obj-$(CONFIG_SUNDANCE) += sundance.o mii.o obj-$(CONFIG_SUNDANCE) += sundance.o mii.o
obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_HAMACHI) += hamachi.o mii.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
obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_SEEQ8005) += seeq8005.o
obj-$(CONFIG_ETHERTAP) += ethertap.o obj-$(CONFIG_ETHERTAP) += ethertap.o
......
...@@ -505,13 +505,11 @@ struct hamachi_private { ...@@ -505,13 +505,11 @@ struct hamachi_private {
unsigned int cur_tx, dirty_tx; unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int rx_buf_sz; /* Based on MTU+slack. */
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; /* Full-duplex operation requested. */
unsigned int duplex_lock:1; unsigned int duplex_lock:1;
unsigned int medialock:1; /* Do not sense media. */
unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int default_port:4; /* Last dev->if_port value. */
/* MII transceiver section. */ /* MII transceiver section. */
int mii_cnt; /* MII device addresses. */ int mii_cnt; /* MII device addresses. */
u16 advertising; /* NWay media advertisement */ struct mii_if_info mii_if; /* MII lib hooks/info */
unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */
u32 rx_int_var, tx_int_var; /* interrupt control variables */ u32 rx_int_var, tx_int_var; /* interrupt control variables */
u32 option; /* Hold on to a copy of the options */ u32 option; /* Hold on to a copy of the options */
...@@ -554,8 +552,8 @@ MODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)"); ...@@ -554,8 +552,8 @@ MODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)");
MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)"); MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)");
static int read_eeprom(long ioaddr, int location); static int read_eeprom(long ioaddr, int location);
static int mdio_read(long ioaddr, int phy_id, int location); static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(long ioaddr, int phy_id, int location, int value); static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
static int hamachi_open(struct net_device *dev); static int hamachi_open(struct net_device *dev);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void hamachi_timer(unsigned long data); static void hamachi_timer(unsigned long data);
...@@ -637,6 +635,12 @@ static int __init hamachi_init_one (struct pci_dev *pdev, ...@@ -637,6 +635,12 @@ static int __init hamachi_init_one (struct pci_dev *pdev,
hmp = dev->priv; hmp = dev->priv;
spin_lock_init(&hmp->lock); spin_lock_init(&hmp->lock);
hmp->mii_if.dev = dev;
hmp->mii_if.mdio_read = mdio_read;
hmp->mii_if.mdio_write = mdio_write;
hmp->mii_if.phy_id_mask = 0x1f;
hmp->mii_if.reg_num_mask = 0x1f;
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)
goto err_out_cleardev; goto err_out_cleardev;
...@@ -685,18 +689,18 @@ static int __init hamachi_init_one (struct pci_dev *pdev, ...@@ -685,18 +689,18 @@ static int __init hamachi_init_one (struct pci_dev *pdev,
if (option > 0) { if (option > 0) {
hmp->option = option; hmp->option = option;
if (option & 0x200) if (option & 0x200)
hmp->full_duplex = 1; hmp->mii_if.full_duplex = 1;
else if (option & 0x080) else if (option & 0x080)
hmp->full_duplex = 0; hmp->mii_if.full_duplex = 0;
hmp->default_port = option & 15; hmp->default_port = option & 15;
if (hmp->default_port) if (hmp->default_port)
hmp->medialock = 1; hmp->mii_if.force_media = 1;
} }
if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
hmp->full_duplex = 1; hmp->mii_if.full_duplex = 1;
/* lock the duplex mode if someone specified a value */ /* lock the duplex mode if someone specified a value */
if (hmp->full_duplex || (option & 0x080)) if (hmp->mii_if.full_duplex || (option & 0x080))
hmp->duplex_lock = 1; hmp->duplex_lock = 1;
/* Set interrupt tuning parameters */ /* Set interrupt tuning parameters */
...@@ -749,17 +753,21 @@ static int __init hamachi_init_one (struct pci_dev *pdev, ...@@ -749,17 +753,21 @@ static int __init hamachi_init_one (struct pci_dev *pdev,
if (chip_tbl[hmp->chip_id].flags & CanHaveMII) { if (chip_tbl[hmp->chip_id].flags & CanHaveMII) {
int phy, phy_idx = 0; int phy, phy_idx = 0;
for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
int mii_status = mdio_read(ioaddr, phy, 1); int mii_status = mdio_read(dev, phy, MII_BMSR);
if (mii_status != 0xffff && if (mii_status != 0xffff &&
mii_status != 0x0000) { mii_status != 0x0000) {
hmp->phys[phy_idx++] = phy; hmp->phys[phy_idx++] = phy;
hmp->advertising = mdio_read(ioaddr, phy, 4); hmp->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
printk(KERN_INFO "%s: MII PHY found at address %d, status " printk(KERN_INFO "%s: MII PHY found at address %d, status "
"0x%4.4x advertising %4.4x.\n", "0x%4.4x advertising %4.4x.\n",
dev->name, phy, mii_status, hmp->advertising); dev->name, phy, mii_status, hmp->mii_if.advertising);
} }
} }
hmp->mii_cnt = phy_idx; hmp->mii_cnt = phy_idx;
if (hmp->mii_cnt > 0)
hmp->mii_if.phy_id = hmp->phys[0];
else
memset(&hmp->mii_if, 0, sizeof(hmp->mii_if));
} }
/* Configure gigabit autonegotiation. */ /* Configure gigabit autonegotiation. */
writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */
...@@ -805,8 +813,9 @@ static int __init read_eeprom(long ioaddr, int location) ...@@ -805,8 +813,9 @@ static int __init read_eeprom(long ioaddr, int location)
These routines assume the MDIO controller is idle, and do not exit until These routines assume the MDIO controller is idle, and do not exit until
the command is finished. */ the command is finished. */
static int mdio_read(long ioaddr, int phy_id, int location) static int mdio_read(struct net_device *dev, int phy_id, int location)
{ {
long ioaddr = dev->base_addr;
int i; int i;
/* We should check busy first - per docs -KDU */ /* We should check busy first - per docs -KDU */
...@@ -821,8 +830,9 @@ static int mdio_read(long ioaddr, int phy_id, int location) ...@@ -821,8 +830,9 @@ static int mdio_read(long ioaddr, int phy_id, int location)
return readw(ioaddr + MII_Rd_Data); return readw(ioaddr + MII_Rd_Data);
} }
static void mdio_write(long ioaddr, int phy_id, int location, int value) static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
{ {
long ioaddr = dev->base_addr;
int i; int i;
/* We should check busy first - per docs -KDU */ /* We should check busy first - per docs -KDU */
...@@ -912,7 +922,7 @@ static int hamachi_open(struct net_device *dev) ...@@ -912,7 +922,7 @@ static int hamachi_open(struct net_device *dev)
/* Setting the Rx mode will start the Rx process. */ /* Setting the Rx mode will start the Rx process. */
/* If someone didn't choose a duplex, default to full-duplex */ /* If someone didn't choose a duplex, default to full-duplex */
if (hmp->duplex_lock != 1) if (hmp->duplex_lock != 1)
hmp->full_duplex = 1; hmp->mii_if.full_duplex = 1;
/* always 1, takes no more time to do it */ /* always 1, takes no more time to do it */
writew(0x0001, ioaddr + RxChecksum); writew(0x0001, ioaddr + RxChecksum);
...@@ -1909,7 +1919,7 @@ static void set_rx_mode(struct net_device *dev) ...@@ -1909,7 +1919,7 @@ static void set_rx_mode(struct net_device *dev)
static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
{ {
struct hamachi_private *hmp = dev->priv; struct hamachi_private *np = dev->priv;
u32 ethcmd; u32 ethcmd;
if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd))) if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
...@@ -1920,12 +1930,53 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1920,12 +1930,53 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
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, hmp->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 };
if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
return -EINVAL;
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 (!(chip_tbl[np->chip_id].flags & CanHaveMII))
return -EINVAL;
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: {
if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
return -EINVAL;
return mii_nway_restart(&np->mii_if);
}
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK};
if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
return -EINVAL;
edata.data = mii_link_ok(&np->mii_if);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -1933,29 +1984,17 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1933,29 +1984,17 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{ {
long ioaddr = dev->base_addr; struct hamachi_private *np = dev->priv;
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
int rc;
switch(cmd) { if (!netif_running(dev))
case SIOCETHTOOL: return -EINVAL;
return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
data->phy_id = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f;
/* Fall Through */
case SIOCGMIIREG: /* Read MII PHY register. */ if (cmd == SIOCETHTOOL)
data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f); rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
return 0;
case SIOCSMIIREG: /* Write MII PHY register. */ else if (cmd == (SIOCDEVPRIVATE+3)) { /* set rx,tx intr params */
/* TODO: Check the sequencing of this. Might need to stop and
* restart Rx and Tx engines. -KDU
*/
if (!capable(CAP_NET_ADMIN))
return -EPERM;
mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
return 0;
case SIOCDEVPRIVATE+3: { /* set rx,tx intr params */
u32 *d = (u32 *)&rq->ifr_data; u32 *d = (u32 *)&rq->ifr_data;
/* Should add this check here or an ordinary user can do nasty /* Should add this check here or an ordinary user can do nasty
* things. -KDU * things. -KDU
...@@ -1969,11 +2008,16 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1969,11 +2008,16 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name, printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name,
(u32) readl(dev->base_addr + TxIntrCtrl), (u32) readl(dev->base_addr + TxIntrCtrl),
(u32) readl(dev->base_addr + RxIntrCtrl)); (u32) readl(dev->base_addr + RxIntrCtrl));
return 0; rc = 0;
} }
default:
return -EOPNOTSUPP; else {
spin_lock_irq(&np->lock);
rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
spin_unlock_irq(&np->lock);
} }
return rc;
} }
......
...@@ -571,19 +571,18 @@ struct netdev_private { ...@@ -571,19 +571,18 @@ struct netdev_private {
struct net_device_stats stats; struct net_device_stats stats;
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
/* Frequently used values: keep some adjacent for cache effect. */ /* Frequently used values: keep some adjacent for cache effect. */
spinlock_t lock;
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
unsigned int cur_tx, dirty_tx; unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int rx_buf_sz; /* Based on MTU+slack. */
unsigned int tx_full:1, /* The Tx queue is full. */ unsigned int tx_full:1, /* The Tx queue is full. */
/* These values keep track of the transceiver/media in use. */ /* These values keep track of the transceiver/media in use. */
autoneg:1, /* Autonegotiation allowed. */
full_duplex:1, /* Full-duplex operation. */
speed100:1; /* Set if speed == 100MBit. */ speed100:1; /* Set if speed == 100MBit. */
unsigned int intr_mitigation; unsigned int intr_mitigation;
u32 tx_mode; u32 tx_mode;
u8 tx_threshold; u8 tx_threshold;
/* MII transceiver section. */ /* MII transceiver section. */
u16 advertising; /* NWay media advertisement */ struct mii_if_info mii_if; /* MII lib hooks/info */
int phy_cnt; /* MII device addresses. */ int phy_cnt; /* MII device addresses. */
unsigned char phys[PHY_CNT]; /* MII device addresses. */ unsigned char phys[PHY_CNT]; /* MII device addresses. */
}; };
...@@ -726,9 +725,17 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, ...@@ -726,9 +725,17 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
dev->irq = irq; dev->irq = irq;
np = dev->priv; np = dev->priv;
spin_lock_init(&np->lock);
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
np->pci_dev = pdev; np->pci_dev = pdev;
np->mii_if.dev = dev;
np->mii_if.mdio_read = mdio_read;
np->mii_if.mdio_write = mdio_write;
np->mii_if.phy_id_mask = 0x1f;
np->mii_if.reg_num_mask = 0x1f;
drv_flags = netdrv_tbl[chip_idx].drv_flags; drv_flags = netdrv_tbl[chip_idx].drv_flags;
option = card_idx < MAX_UNITS ? options[card_idx] : 0; option = card_idx < MAX_UNITS ? options[card_idx] : 0;
...@@ -737,15 +744,15 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, ...@@ -737,15 +744,15 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
/* The lower four bits are the media type. */ /* The lower four bits are the media type. */
if (option & 0x200) if (option & 0x200)
np->full_duplex = 1; np->mii_if.full_duplex = 1;
if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
np->full_duplex = 1; np->mii_if.full_duplex = 1;
if (np->full_duplex) if (np->mii_if.full_duplex)
np->autoneg = 0; np->mii_if.force_media = 0;
else else
np->autoneg = 1; np->mii_if.force_media = 1;
np->speed100 = 1; np->speed100 = 1;
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
...@@ -787,15 +794,19 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, ...@@ -787,15 +794,19 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
mii_status = mdio_read(dev, phy, MII_BMSR); mii_status = mdio_read(dev, phy, MII_BMSR);
if (mii_status != 0) { if (mii_status != 0) {
np->phys[phy_idx++] = phy; np->phys[phy_idx++] = phy;
np->advertising = mdio_read(dev, phy, MII_ADVERTISE); np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
printk(KERN_INFO "%s: MII PHY found at address %d, status " printk(KERN_INFO "%s: MII PHY found at address %d, status "
"0x%4.4x advertising %4.4x.\n", "0x%4.4x advertising %4.4x.\n",
dev->name, phy, mii_status, np->advertising); dev->name, phy, mii_status, np->mii_if.advertising);
/* there can be only one PHY on-board */ /* there can be only one PHY on-board */
break; break;
} }
} }
np->phy_cnt = phy_idx; np->phy_cnt = phy_idx;
if (np->phy_cnt > 0)
np->mii_if.phy_id = np->phys[0];
else
memset(&np->mii_if, 0, sizeof(np->mii_if));
} }
#ifdef ZEROCOPY #ifdef ZEROCOPY
...@@ -842,7 +853,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val ...@@ -842,7 +853,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2); long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
writel(value, mdio_addr); writel(value, mdio_addr);
/* The busy-wait will occur before a read. */ /* The busy-wait will occur before a read. */
return;
} }
...@@ -985,7 +995,7 @@ static int netdev_open(struct net_device *dev) ...@@ -985,7 +995,7 @@ static int netdev_open(struct net_device *dev)
printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name); printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name);
set_rx_mode(dev); set_rx_mode(dev);
np->advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE); np->mii_if.advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE);
check_duplex(dev); check_duplex(dev);
/* Enable GPIO interrupts on link change */ /* Enable GPIO interrupts on link change */
...@@ -1026,25 +1036,25 @@ static void check_duplex(struct net_device *dev) ...@@ -1026,25 +1036,25 @@ static void check_duplex(struct net_device *dev)
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
u16 reg0; u16 reg0;
mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising); mdio_write(dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising);
mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET); mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET);
udelay(500); udelay(500);
while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET); while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET);
reg0 = mdio_read(dev, np->phys[0], MII_BMCR); reg0 = mdio_read(dev, np->phys[0], MII_BMCR);
if (np->autoneg) { if (!np->mii_if.force_media) {
reg0 |= BMCR_ANENABLE | BMCR_ANRESTART; reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
} else { } else {
reg0 &= ~(BMCR_ANENABLE | BMCR_ANRESTART); reg0 &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
if (np->speed100) if (np->speed100)
reg0 |= BMCR_SPEED100; reg0 |= BMCR_SPEED100;
if (np->full_duplex) if (np->mii_if.full_duplex)
reg0 |= BMCR_FULLDPLX; reg0 |= BMCR_FULLDPLX;
printk(KERN_DEBUG "%s: Link forced to %sMbit %s-duplex\n", printk(KERN_DEBUG "%s: Link forced to %sMbit %s-duplex\n",
dev->name, dev->name,
np->speed100 ? "100" : "10", np->speed100 ? "100" : "10",
np->full_duplex ? "full" : "half"); np->mii_if.full_duplex ? "full" : "half");
} }
mdio_write(dev, np->phys[0], MII_BMCR, reg0); mdio_write(dev, np->phys[0], MII_BMCR, reg0);
} }
...@@ -1555,16 +1565,16 @@ static void netdev_media_change(struct net_device *dev) ...@@ -1555,16 +1565,16 @@ static void netdev_media_change(struct net_device *dev)
reg5 = mdio_read(dev, np->phys[0], MII_LPA); reg5 = mdio_read(dev, np->phys[0], MII_LPA);
if (reg4 & ADVERTISE_100FULL && reg5 & LPA_100FULL) { if (reg4 & ADVERTISE_100FULL && reg5 & LPA_100FULL) {
np->speed100 = 1; np->speed100 = 1;
np->full_duplex = 1; np->mii_if.full_duplex = 1;
} else if (reg4 & ADVERTISE_100HALF && reg5 & LPA_100HALF) { } else if (reg4 & ADVERTISE_100HALF && reg5 & LPA_100HALF) {
np->speed100 = 1; np->speed100 = 1;
np->full_duplex = 0; np->mii_if.full_duplex = 0;
} else if (reg4 & ADVERTISE_10FULL && reg5 & LPA_10FULL) { } else if (reg4 & ADVERTISE_10FULL && reg5 & LPA_10FULL) {
np->speed100 = 0; np->speed100 = 0;
np->full_duplex = 1; np->mii_if.full_duplex = 1;
} else { } else {
np->speed100 = 0; np->speed100 = 0;
np->full_duplex = 0; np->mii_if.full_duplex = 0;
} }
} else { } else {
/* autonegotiation is disabled */ /* autonegotiation is disabled */
...@@ -1573,17 +1583,17 @@ static void netdev_media_change(struct net_device *dev) ...@@ -1573,17 +1583,17 @@ static void netdev_media_change(struct net_device *dev)
else else
np->speed100 = 0; np->speed100 = 0;
if (reg0 & BMCR_FULLDPLX) if (reg0 & BMCR_FULLDPLX)
np->full_duplex = 1; np->mii_if.full_duplex = 1;
else else
np->full_duplex = 0; np->mii_if.full_duplex = 0;
} }
printk(KERN_DEBUG "%s: Link is up, running at %sMbit %s-duplex\n", printk(KERN_DEBUG "%s: Link is up, running at %sMbit %s-duplex\n",
dev->name, dev->name,
np->speed100 ? "100" : "10", np->speed100 ? "100" : "10",
np->full_duplex ? "full" : "half"); np->mii_if.full_duplex ? "full" : "half");
new_tx_mode = np->tx_mode & ~0x2; /* duplex setting */ new_tx_mode = np->tx_mode & ~0x2; /* duplex setting */
if (np->full_duplex) if (np->mii_if.full_duplex)
new_tx_mode |= 2; new_tx_mode |= 2;
if (np->tx_mode != new_tx_mode) { if (np->tx_mode != new_tx_mode) {
np->tx_mode = new_tx_mode; np->tx_mode = new_tx_mode;
...@@ -1718,77 +1728,6 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1718,77 +1728,6 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
return -EFAULT; return -EFAULT;
switch (ecmd.cmd) { switch (ecmd.cmd) {
case ETHTOOL_GSET:
ecmd.supported =
SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_MII;
ecmd.advertising = ADVERTISED_MII;
if (np->advertising & ADVERTISE_10HALF)
ecmd.advertising |= ADVERTISED_10baseT_Half;
if (np->advertising & ADVERTISE_10FULL)
ecmd.advertising |= ADVERTISED_10baseT_Full;
if (np->advertising & ADVERTISE_100HALF)
ecmd.advertising |= ADVERTISED_100baseT_Half;
if (np->advertising & ADVERTISE_100FULL)
ecmd.advertising |= ADVERTISED_100baseT_Full;
if (np->autoneg) {
ecmd.advertising |= ADVERTISED_Autoneg;
ecmd.autoneg = AUTONEG_ENABLE;
} else
ecmd.autoneg = AUTONEG_DISABLE;
ecmd.port = PORT_MII;
ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = np->phys[0];
ecmd.speed = np->speed100 ? SPEED_100 : SPEED_10;
ecmd.duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
ecmd.maxtxpkt = TX_RING_SIZE;
ecmd.maxrxpkt = np->intr_mitigation; /* not 100% accurate */
if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return 0;
case ETHTOOL_SSET: {
u16 autoneg, speed100, full_duplex;
autoneg = (ecmd.autoneg == AUTONEG_ENABLE);
speed100 = (ecmd.speed == SPEED_100);
full_duplex = (ecmd.duplex == DUPLEX_FULL);
np->autoneg = autoneg;
if (speed100 != np->speed100 ||
full_duplex != np->full_duplex) {
np->speed100 = speed100;
np->full_duplex = full_duplex;
/* change advertising bits */
np->advertising &= ~(ADVERTISE_10HALF |
ADVERTISE_10FULL |
ADVERTISE_100HALF |
ADVERTISE_100FULL |
ADVERTISE_100BASE4);
if (speed100) {
if (full_duplex)
np->advertising |= ADVERTISE_100FULL;
else
np->advertising |= ADVERTISE_100HALF;
} else {
if (full_duplex)
np->advertising |= ADVERTISE_10FULL;
else
np->advertising |= ADVERTISE_10HALF;
}
}
check_duplex(dev);
return 0;
}
case ETHTOOL_GDRVINFO: { case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info; struct ethtool_drvinfo info;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
...@@ -1802,26 +1741,35 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1802,26 +1741,35 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
return 0; return 0;
} }
/* restart autonegotiation */ /* get settings */
case ETHTOOL_NWAY_RST: { case ETHTOOL_GSET: {
int tmp; struct ethtool_cmd ecmd = { ETHTOOL_GSET };
int r = -EINVAL; spin_lock_irq(&np->lock);
/* if autoneg is off, it's an error */ mii_ethtool_gset(&np->mii_if, &ecmd);
tmp = mdio_read(dev, np->phys[0], MII_BMCR); spin_unlock_irq(&np->lock);
if (tmp & BMCR_ANENABLE) { if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
tmp |= (BMCR_ANRESTART); return -EFAULT;
mdio_write(dev, np->phys[0], MII_BMCR, tmp); return 0;
r = 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; return r;
} }
/* restart autonegotiation */
case ETHTOOL_NWAY_RST: {
return mii_nway_restart(&np->mii_if);
}
/* get link status */ /* get link status */
case ETHTOOL_GLINK: { case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK}; struct ethtool_value edata = {ETHTOOL_GLINK};
if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS) edata.data = mii_link_ok(&np->mii_if);
edata.data = 1;
else
edata.data = 0;
if (copy_to_user(useraddr, &edata, sizeof(edata))) if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1852,47 +1800,25 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1852,47 +1800,25 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{ {
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
int rc;
switch(cmd) { if (!netif_running(dev))
case SIOCETHTOOL: return -EINVAL;
return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
/* Legacy mii-diag interface */ if (cmd == SIOCETHTOOL)
case SIOCGMIIPHY: /* Get address of MII PHY in use. */ rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
data->phy_id = np->phys[0] & 0x1f;
/* Fall Through */
case SIOCGMIIREG: /* Read MII PHY register. */
data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
return 0;
case SIOCSMIIREG: /* Write MII PHY register. */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (data->phy_id == np->phys[0]) {
u16 value = data->val_in;
switch (data->reg_num) {
case 0:
if (value & (BMCR_RESET | BMCR_ANENABLE))
/* Autonegotiation. */
np->autoneg = 1;
else { else {
np->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0; spin_lock_irq(&np->lock);
np->autoneg = 0; rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
} spin_unlock_irq(&np->lock);
break;
case 4: if ((cmd == SIOCSMIIREG) && (data->phy_id == np->phys[0]))
np->advertising = value;
break;
}
check_duplex(dev); check_duplex(dev);
} }
mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
return 0; return rc;
default:
return -EOPNOTSUPP;
}
} }
static int netdev_close(struct net_device *dev) static int netdev_close(struct net_device *dev)
......
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