Commit 47229b82 authored by Jeff Garzik's avatar Jeff Garzik

Merge mandrakesoft.com:/home/jgarzik/repo/linus-2.5

into mandrakesoft.com:/home/jgarzik/repo/net-drivers-2.5
parents 3dcf3431 52ef1eac
...@@ -27,8 +27,6 @@ ...@@ -27,8 +27,6 @@
TODO, in rough priority order: TODO, in rough priority order:
* Test Tx checksumming thoroughly * Test Tx checksumming thoroughly
* dev->tx_timeout * dev->tx_timeout
* Support forcing media type with a module parameter,
like dl2k.c/sundance.c
* Constants (module parms?) for Rx work limit * Constants (module parms?) for Rx work limit
* Complete reset on PciErr * Complete reset on PciErr
* Consider Rx interrupt mitigation using TimerIntr * Consider Rx interrupt mitigation using TimerIntr
...@@ -49,8 +47,8 @@ ...@@ -49,8 +47,8 @@
*/ */
#define DRV_NAME "8139cp" #define DRV_NAME "8139cp"
#define DRV_VERSION "0.2.1" #define DRV_VERSION "0.3.0"
#define DRV_RELDATE "Aug 9, 2002" #define DRV_RELDATE "Sep 29, 2002"
#include <linux/config.h> #include <linux/config.h>
...@@ -107,6 +105,11 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered mu ...@@ -107,6 +105,11 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered mu
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif
#define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \ #define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \ NETIF_MSG_PROBE | \
NETIF_MSG_LINK) NETIF_MSG_LINK)
...@@ -678,7 +681,7 @@ static void cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs) ...@@ -678,7 +681,7 @@ static void cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
if (status & (TxOK | TxErr | TxEmpty | SWInt)) if (status & (TxOK | TxErr | TxEmpty | SWInt))
cp_tx(cp); cp_tx(cp);
if (status & LinkChg) if (status & LinkChg)
mii_check_media(&cp->mii_if, netif_msg_link(cp)); mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
if (status & PciErr) { if (status & PciErr) {
u16 pci_status; u16 pci_status;
...@@ -988,8 +991,6 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev) ...@@ -988,8 +991,6 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev)
static void cp_stop_hw (struct cp_private *cp) static void cp_stop_hw (struct cp_private *cp)
{ {
struct net_device *dev = cp->dev;
cpw16(IntrMask, 0); cpw16(IntrMask, 0);
cpr16(IntrMask); cpr16(IntrMask);
cpw8(Cmd, 0); cpw8(Cmd, 0);
...@@ -1195,7 +1196,7 @@ static int cp_open (struct net_device *dev) ...@@ -1195,7 +1196,7 @@ static int cp_open (struct net_device *dev)
goto err_out_hw; goto err_out_hw;
netif_carrier_off(dev); netif_carrier_off(dev);
mii_check_media(&cp->mii_if, netif_msg_link(cp)); mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE);
netif_start_queue(dev); netif_start_queue(dev);
return 0; return 0;
...@@ -1654,33 +1655,18 @@ static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr) ...@@ -1654,33 +1655,18 @@ static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{ {
struct cp_private *cp = dev->priv; struct cp_private *cp = dev->priv;
struct mii_ioctl_data *mii; struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &rq->ifr_data;
int rc = 0; int rc;
mii = (struct mii_ioctl_data *) &rq->ifr_data;
if (!netif_running(dev)) if (!netif_running(dev))
return -EINVAL; return -EINVAL;
if (cmd != SIOCETHTOOL) if (cmd == SIOCETHTOOL)
mii->reg_num &= 0x1f;
switch (cmd) {
case SIOCETHTOOL:
return cp_ethtool_ioctl(cp, (void *) rq->ifr_data); return cp_ethtool_ioctl(cp, (void *) rq->ifr_data);
case SIOCGMIIPHY: /* Get the address of the PHY in use. */
mii->phy_id = CP_INTERNAL_PHY;
/* Fall Through */
case SIOCGMIIREG: /* Read the specified MII register. */
mii->val_out = mdio_read (dev, CP_INTERNAL_PHY, mii->reg_num);
break;
default:
rc = -EOPNOTSUPP;
break;
}
rc = generic_mii_ioctl(dev, &cp->mii_if, mii, cmd);
if (rc == 1) /* we don't care about duplex change, fixup rc */
rc = 0;
return rc; return rc;
} }
...@@ -1818,6 +1804,8 @@ static int __devinit cp_init_one (struct pci_dev *pdev, ...@@ -1818,6 +1804,8 @@ static int __devinit cp_init_one (struct pci_dev *pdev,
cp->mii_if.mdio_read = mdio_read; cp->mii_if.mdio_read = mdio_read;
cp->mii_if.mdio_write = mdio_write; cp->mii_if.mdio_write = mdio_write;
cp->mii_if.phy_id = CP_INTERNAL_PHY; cp->mii_if.phy_id = CP_INTERNAL_PHY;
cp->mii_if.phy_id_mask = 0x1f;
cp->mii_if.reg_num_mask = 0x1f;
cp_set_rxbufsize(cp); cp_set_rxbufsize(cp);
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
......
...@@ -578,7 +578,6 @@ struct rtl8139_private { ...@@ -578,7 +578,6 @@ struct rtl8139_private {
signed char phys[4]; /* MII device addresses. */ signed char phys[4]; /* MII device addresses. */
char twistie, twist_row, twist_col; /* Twister tune state. */ char twistie, twist_row, twist_col; /* Twister tune state. */
unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int default_port:4; /* Last dev->if_port value. */
unsigned int medialock:1; /* Don't sense media type. */
spinlock_t lock; spinlock_t lock;
chip_t chipset; chip_t chipset;
pid_t thr_pid; pid_t thr_pid;
...@@ -986,6 +985,8 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, ...@@ -986,6 +985,8 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
tp->mii.dev = dev; tp->mii.dev = dev;
tp->mii.mdio_read = mdio_read; tp->mii.mdio_read = mdio_read;
tp->mii.mdio_write = mdio_write; tp->mii.mdio_write = mdio_write;
tp->mii.phy_id_mask = 0x3f;
tp->mii.reg_num_mask = 0x1f;
/* dev is fully set up and ready to use now */ /* dev is fully set up and ready to use now */
DPRINTK("about to register device named %s (%p)...\n", dev->name, dev); DPRINTK("about to register device named %s (%p)...\n", dev->name, dev);
...@@ -1041,7 +1042,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, ...@@ -1041,7 +1042,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
tp->mii.full_duplex = (option & 0x210) ? 1 : 0; tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
tp->default_port = option & 0xFF; tp->default_port = option & 0xFF;
if (tp->default_port) if (tp->default_port)
tp->medialock = 1; tp->mii.force_media = 1;
} }
if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0)
tp->mii.full_duplex = full_duplex[board_idx]; tp->mii.full_duplex = full_duplex[board_idx];
...@@ -1049,7 +1050,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, ...@@ -1049,7 +1050,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name); printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
/* Changing the MII-advertised media because might prevent /* Changing the MII-advertised media because might prevent
re-connection. */ re-connection. */
tp->mii.duplex_lock = 1; tp->mii.force_media = 1;
} }
if (tp->default_port) { if (tp->default_port) {
printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n", printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n",
...@@ -1306,7 +1307,7 @@ static int rtl8139_open (struct net_device *dev) ...@@ -1306,7 +1307,7 @@ static int rtl8139_open (struct net_device *dev)
} }
tp->mii.full_duplex = tp->mii.duplex_lock; tp->mii.full_duplex = tp->mii.force_media;
tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
tp->twistie = (tp->chipset == CH_8139_K) ? 1 : 0; tp->twistie = (tp->chipset == CH_8139_K) ? 1 : 0;
tp->time_to_die = 0; tp->time_to_die = 0;
...@@ -1537,7 +1538,7 @@ static inline void rtl8139_thread_iter (struct net_device *dev, ...@@ -1537,7 +1538,7 @@ static inline void rtl8139_thread_iter (struct net_device *dev,
mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA); mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
if (!tp->mii.duplex_lock && mii_lpa != 0xffff) { if (!tp->mii.force_media && mii_lpa != 0xffff) {
int duplex = (mii_lpa & LPA_100FULL) int duplex = (mii_lpa & LPA_100FULL)
|| (mii_lpa & 0x01C0) == 0x0040; || (mii_lpa & 0x01C0) == 0x0040;
if (tp->mii.full_duplex != duplex) { if (tp->mii.full_duplex != duplex) {
...@@ -1995,7 +1996,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev, ...@@ -1995,7 +1996,7 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
/* Really link-change on new chips. */ /* Really link-change on new chips. */
int lpar = RTL_R16 (NWayLPAR); int lpar = RTL_R16 (NWayLPAR);
int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040 int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040
|| tp->mii.duplex_lock; || tp->mii.force_media;
if (tp->mii.full_duplex != duplex) { if (tp->mii.full_duplex != duplex) {
tp->mii.full_duplex = duplex; tp->mii.full_duplex = duplex;
#if 0 #if 0
...@@ -2439,58 +2440,25 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) ...@@ -2439,58 +2440,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 rtl8139_private *tp = dev->priv; struct rtl8139_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 = 0; int rc;
int phy = tp->phys[0] & 0x3f;
if (!netif_running(dev)) if (!netif_running(dev))
return -EINVAL; return -EINVAL;
if (cmd != SIOCETHTOOL) { if (cmd == SIOCETHTOOL)
/* With SIOCETHTOOL, this would corrupt the pointer. */ rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
data->phy_id &= 0x3f;
data->reg_num &= 0x1f;
}
switch (cmd) {
case SIOCETHTOOL:
return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
case SIOCGMIIPHY: /* Get the address of the PHY in use. */
data->phy_id = phy;
/* Fall Through */
case SIOCGMIIREG: /* Read the specified MII register. */
data->val_out = mdio_read (dev, data->phy_id, data->reg_num);
break;
case SIOCSMIIREG: /* Write the specified MII register */
if (!capable (CAP_NET_ADMIN)) {
rc = -EPERM;
break;
}
if (data->phy_id == phy) { else {
u16 value = data->val_in; spin_lock_irq(&np->lock);
switch (data->reg_num) { rc = generic_mii_ioctl(dev, &np->mii, data, cmd);
case 0: spin_unlock_irq(&np->lock);
/* Check for autonegotiation on or reset. */
tp->medialock = (value & 0x9000) ? 0 : 1;
if (tp->medialock)
tp->mii.full_duplex = (value & 0x0100) ? 1 : 0;
break;
case 4: tp->mii.advertising = value; break;
}
}
mdio_write(dev, data->phy_id, data->reg_num, data->val_in);
break;
default: if (rc == 1) /* don't care about duplex change, fix up rc */
rc = -EOPNOTSUPP; rc = 0;
break;
} }
return rc; return rc;
......
...@@ -429,6 +429,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -429,6 +429,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ep->mii.dev = dev; ep->mii.dev = dev;
ep->mii.mdio_read = mdio_read; ep->mii.mdio_read = mdio_read;
ep->mii.mdio_write = mdio_write; ep->mii.mdio_write = mdio_write;
ep->mii.phy_id_mask = 0x1f;
ep->mii.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)
...@@ -523,7 +525,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ...@@ -523,7 +525,7 @@ 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->mii.duplex_lock = ep->mii.full_duplex = 1; ep->mii.force_media = 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);
} }
...@@ -854,7 +856,7 @@ static void check_media(struct net_device *dev) ...@@ -854,7 +856,7 @@ static void check_media(struct net_device *dev)
int negotiated = mii_lpa & ep->mii.advertising; int negotiated = mii_lpa & ep->mii.advertising;
int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
if (ep->mii.duplex_lock) if (ep->mii.force_media)
return; return;
if (mii_lpa == 0xffff) /* Bogus read */ if (mii_lpa == 0xffff) /* Bogus read */
return; return;
...@@ -1426,63 +1428,36 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) ...@@ -1426,63 +1428,36 @@ 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 epic_private *ep = dev->priv; struct epic_private *np = dev->priv;
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
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) { /* power-up, if interface is down */
case SIOCETHTOOL: if (! netif_running(dev)) {
return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); outl(0x0200, ioaddr + GENCTL);
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
}
case SIOCGMIIPHY: /* Get address of MII PHY in use. */ /* ethtool commands */
data->phy_id = ep->phys[0] & 0x1f; if (cmd == SIOCETHTOOL)
/* Fall Through */ rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
case SIOCGMIIREG: /* Read MII PHY register. */ /* all other ioctls (the SIOC[GS]MIIxxx ioctls) */
if (! netif_running(dev)) { else {
outl(0x0200, ioaddr + GENCTL); spin_lock_irq(&np->lock);
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); rc = generic_mii_ioctl(dev, &np->mii, data, cmd);
} spin_unlock_irq(&np->lock);
data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); if (rc == 1) /* don't care about duplex change, fixup rc */
#if 0 /* Just leave on if the ioctl() is ever used. */ rc = 0;
if (! netif_running(dev)) { }
outl(0x0008, ioaddr + GENCTL);
outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
}
#endif
return 0;
case SIOCSMIIREG: /* Write MII PHY register. */ /* power-down, if interface is down */
if (!capable(CAP_NET_ADMIN)) if (! netif_running(dev)) {
return -EPERM; outl(0x0008, ioaddr + GENCTL);
if (! netif_running(dev)) { outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
outl(0x0200, ioaddr + GENCTL);
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
}
if (data->phy_id == ep->phys[0]) {
u16 value = data->val_in;
switch (data->reg_num) {
case 0:
/* Check for autonegotiation on or reset. */
ep->mii.duplex_lock = (value & 0x9000) ? 0 : 1;
if (ep->mii.duplex_lock)
ep->mii.full_duplex = (value & 0x0100) ? 1 : 0;
break;
case 4: ep->mii.advertising = value; break;
}
/* Perhaps check_duplex(dev), depending on chip semantics. */
}
mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
#if 0 /* Leave on if the ioctl() is used. */
if (! netif_running(dev)) {
outl(0x0008, ioaddr + GENCTL);
outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
}
#endif
return 0;
default:
return -EOPNOTSUPP;
} }
return rc;
} }
......
...@@ -559,6 +559,8 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, ...@@ -559,6 +559,8 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
np->mii.dev = dev; np->mii.dev = dev;
np->mii.mdio_read = mdio_read; np->mii.mdio_read = mdio_read;
np->mii.mdio_write = mdio_write; np->mii.mdio_write = mdio_write;
np->mii.phy_id_mask = 0x1f;
np->mii.reg_num_mask = 0x1f;
ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
if (!ring_space) { if (!ring_space) {
...@@ -654,7 +656,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, ...@@ -654,7 +656,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL); mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
else else
writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR); writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR);
np->mii.duplex_lock = 1; np->mii.force_media = 1;
} }
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
...@@ -956,7 +958,7 @@ static int netdev_open(struct net_device *dev) ...@@ -956,7 +958,7 @@ static int netdev_open(struct net_device *dev)
// 89/9/1 modify, // 89/9/1 modify,
// np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */ // np->crvalue = 0x00e40001; /* tx store and forward, tx/rx enable */
np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */ np->crvalue |= 0x00e40001; /* tx store and forward, tx/rx enable */
np->mii.full_duplex = np->mii.duplex_lock; np->mii.full_duplex = np->mii.force_media;
getlinkstatus(dev); getlinkstatus(dev);
if (np->linkok) if (np->linkok)
getlinktype(dev); getlinktype(dev);
...@@ -1833,28 +1835,25 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) ...@@ -1833,28 +1835,25 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{ {
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);
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
data->phy_id = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f;
/* Fall Through */
case SIOCGMIIREG: /* Read MII PHY register. */ if (cmd == SIOCETHTOOL)
data->val_out = mdio_read(dev, 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 (!capable(CAP_NET_ADMIN)) spin_lock_irq(&np->lock);
return -EPERM; rc = generic_mii_ioctl(dev, &np->mii, data, cmd);
mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); spin_unlock_irq(&np->lock);
return 0; if (rc == 1) /* don't care about duplex change, fix up rc */
default: rc = 0;
return -EOPNOTSUPP;
} }
return rc;
} }
......
...@@ -3,7 +3,27 @@ ...@@ -3,7 +3,27 @@
mii.c: MII interface library mii.c: MII interface library
Maintained by Jeff Garzik <jgarzik@mandrakesoft.com> Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
Copyright 2001 Jeff Garzik Copyright 2001,2002 Jeff Garzik
Various code came from myson803.c and other files by
Donald Becker. Copyright:
Written 1998-2002 by Donald Becker.
This software may be used and distributed according
to the terms of the GNU General Public License (GPL),
incorporated herein by reference. Drivers based on
or derived from this code fall under the GPL and must
retain the authorship, copyright and license notice.
This file is not a complete program and may only be
used when the entire operating system is licensed
under the GPL.
The author may be reached as becker@scyld.com, or C/O
Scyld Computing Corporation
410 Severn Ave., Suite 210
Annapolis MD 21403
*/ */
...@@ -122,7 +142,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ...@@ -122,7 +142,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr); mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
mii->duplex_lock = 0; mii->force_media = 0;
} else { } else {
u32 bmcr, tmp; u32 bmcr, tmp;
...@@ -139,7 +159,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) ...@@ -139,7 +159,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
if (bmcr != tmp) if (bmcr != tmp)
mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp); mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
mii->duplex_lock = 1; mii->force_media = 1;
} }
return 0; return 0;
} }
...@@ -178,13 +198,15 @@ void mii_check_link (struct mii_if_info *mii) ...@@ -178,13 +198,15 @@ void mii_check_link (struct mii_if_info *mii)
netif_carrier_off(mii->dev); netif_carrier_off(mii->dev);
} }
unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print) unsigned int mii_check_media (struct mii_if_info *mii,
unsigned int ok_to_print,
unsigned int init_media)
{ {
unsigned int old_carrier, new_carrier; unsigned int old_carrier, new_carrier;
int advertise, lpa, media, duplex; int advertise, lpa, media, duplex;
/* if forced media, go no further */ /* if forced media, go no further */
if (mii->duplex_lock) if (mii->force_media)
return 0; /* duplex did not change */ return 0; /* duplex did not change */
/* check current and old link status */ /* check current and old link status */
...@@ -194,7 +216,7 @@ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print) ...@@ -194,7 +216,7 @@ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print)
/* if carrier state did not change, this is a "bounce", /* if carrier state did not change, this is a "bounce",
* just exit as everything is already set correctly * just exit as everything is already set correctly
*/ */
if (old_carrier == new_carrier) if ((!init_media) && (old_carrier == new_carrier))
return 0; /* duplex did not change */ return 0; /* duplex did not change */
/* no carrier, nothing much to do */ /* no carrier, nothing much to do */
...@@ -211,7 +233,7 @@ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print) ...@@ -211,7 +233,7 @@ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print)
netif_carrier_on(mii->dev); netif_carrier_on(mii->dev);
/* get MII advertise and LPA values */ /* get MII advertise and LPA values */
if (mii->advertising) if ((!init_media) && (mii->advertising))
advertise = mii->advertising; advertise = mii->advertising;
else { else {
advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE); advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
...@@ -231,7 +253,7 @@ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print) ...@@ -231,7 +253,7 @@ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print)
duplex ? "full" : "half", duplex ? "full" : "half",
lpa); lpa);
if (mii->full_duplex != duplex) { if ((init_media) || (mii->full_duplex != duplex)) {
mii->full_duplex = duplex; mii->full_duplex = duplex;
return 1; /* duplex changed */ return 1; /* duplex changed */
} }
...@@ -239,6 +261,73 @@ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print) ...@@ -239,6 +261,73 @@ unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print)
return 0; /* duplex did not change */ return 0; /* duplex did not change */
} }
int generic_mii_ioctl(struct net_device *dev, struct mii_if_info *mii_if,
struct mii_ioctl_data *mii_data, int cmd)
{
int rc = 0;
unsigned int duplex_changed = 0;
mii_data->phy_id &= mii_if->phy_id_mask;
mii_data->reg_num &= mii_if->reg_num_mask;
switch(cmd) {
case SIOCGMIIPHY:
mii_data->phy_id = mii_if->phy_id;
/* fall through */
case SIOCGMIIREG:
mii_data->val_out =
mii_if->mdio_read(dev, mii_data->phy_id,
mii_data->reg_num);
break;
case SIOCSMIIREG: {
u16 val = mii_data->val_in;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (mii_data->phy_id == mii_if->phy_id) {
switch(mii_data->reg_num) {
case MII_BMCR: {
unsigned int new_duplex = 0;
if (val & (BMCR_RESET|BMCR_ANENABLE))
mii_if->force_media = 1;
else
mii_if->force_media = 0;
if (mii_if->force_media &&
(val & BMCR_FULLDPLX))
new_duplex = 1;
if (mii_if->full_duplex != new_duplex) {
duplex_changed = 1;
mii_if->full_duplex = new_duplex;
}
break;
}
case MII_ADVERTISE:
mii_if->advertising = val;
break;
default:
/* do nothing */
break;
}
}
mii_if->mdio_write(dev, mii_data->phy_id,
mii_data->reg_num, val);
break;
}
default:
rc = -EOPNOTSUPP;
break;
}
if ((rc == 0) && (duplex_changed))
rc = 1;
return rc;
}
MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>"); MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
MODULE_DESCRIPTION ("MII hardware support library"); MODULE_DESCRIPTION ("MII hardware support library");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -249,4 +338,5 @@ EXPORT_SYMBOL(mii_ethtool_gset); ...@@ -249,4 +338,5 @@ EXPORT_SYMBOL(mii_ethtool_gset);
EXPORT_SYMBOL(mii_ethtool_sset); EXPORT_SYMBOL(mii_ethtool_sset);
EXPORT_SYMBOL(mii_check_link); EXPORT_SYMBOL(mii_check_link);
EXPORT_SYMBOL(mii_check_media); EXPORT_SYMBOL(mii_check_media);
EXPORT_SYMBOL(generic_mii_ioctl);
...@@ -573,6 +573,8 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, ...@@ -573,6 +573,8 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
np->mii_if.dev = dev; np->mii_if.dev = dev;
np->mii_if.mdio_read = mdio_read; np->mii_if.mdio_read = mdio_read;
np->mii_if.mdio_write = mdio_write; np->mii_if.mdio_write = mdio_write;
np->mii_if.phy_id_mask = 0x1f;
np->mii_if.reg_num_mask = 0x1f;
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
dev->open = &netdev_open; dev->open = &netdev_open;
...@@ -1550,27 +1552,25 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1550,27 +1552,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 mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; struct netdev_private *np = dev->priv;
struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
switch(cmd) { int rc;
case SIOCETHTOOL:
return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); if (!netif_running(dev))
case SIOCGMIIPHY: /* Get address of MII PHY in use. */ return -EINVAL;
data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
/* Fall Through */ if (cmd == SIOCETHTOOL)
rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
case SIOCGMIIREG: /* Read MII PHY register. */
data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); else {
return 0; spin_lock_irq(&np->lock);
rc = generic_mii_ioctl(dev, &np->mii_if, data, cmd);
case SIOCSMIIREG: /* Write MII PHY register. */ spin_unlock_irq(&np->lock);
if (!capable(CAP_NET_ADMIN)) if (rc == 1) /* don't care about duplex change, fix up rc */
return -EPERM; rc = 0;
mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
return 0;
default:
return -EOPNOTSUPP;
} }
return rc;
} }
static int netdev_close(struct net_device *dev) static int netdev_close(struct net_device *dev)
......
...@@ -473,7 +473,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, ...@@ -473,7 +473,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
np->mii_if.full_duplex = 1; np->mii_if.full_duplex = 1;
if (np->mii_if.full_duplex) if (np->mii_if.full_duplex)
np->mii_if.duplex_lock = 1; np->mii_if.force_media = 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;
...@@ -773,7 +773,7 @@ static int update_link(struct net_device *dev) ...@@ -773,7 +773,7 @@ static int update_link(struct net_device *dev)
duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL); duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL);
fasteth = negotiated & 0x380; fasteth = negotiated & 0x380;
} }
duplex |= np->mii_if.duplex_lock; duplex |= np->mii_if.force_media;
/* remove fastether and fullduplex */ /* remove fastether and fullduplex */
result = np->csr6 & ~0x20000200; result = np->csr6 & ~0x20000200;
if (duplex) if (duplex)
......
...@@ -516,7 +516,7 @@ static void via_rhine_rx(struct net_device *dev); ...@@ -516,7 +516,7 @@ static void via_rhine_rx(struct net_device *dev);
static void via_rhine_error(struct net_device *dev, int intr_status); static void via_rhine_error(struct net_device *dev, int intr_status);
static void via_rhine_set_rx_mode(struct net_device *dev); static void via_rhine_set_rx_mode(struct net_device *dev);
static struct net_device_stats *via_rhine_get_stats(struct net_device *dev); static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int via_rhine_close(struct net_device *dev); static int via_rhine_close(struct net_device *dev);
static inline void clear_tally_counters(long ioaddr); static inline void clear_tally_counters(long ioaddr);
...@@ -715,6 +715,8 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, ...@@ -715,6 +715,8 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
np->mii_if.dev = dev; np->mii_if.dev = dev;
np->mii_if.mdio_read = mdio_read; np->mii_if.mdio_read = mdio_read;
np->mii_if.mdio_write = mdio_write; np->mii_if.mdio_write = mdio_write;
np->mii_if.phy_id_mask = 0x1f;
np->mii_if.reg_num_mask = 0x1f;
if (dev->mem_start) if (dev->mem_start)
option = dev->mem_start; option = dev->mem_start;
...@@ -731,7 +733,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, ...@@ -731,7 +733,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
if (np->mii_if.full_duplex) { if (np->mii_if.full_duplex) {
printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation" printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
" disabled.\n", dev->name); " disabled.\n", dev->name);
np->mii_if.duplex_lock = 1; np->mii_if.force_media = 1;
} }
/* The chip-specific entries in the device structure. */ /* The chip-specific entries in the device structure. */
...@@ -740,7 +742,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev, ...@@ -740,7 +742,7 @@ static int __devinit via_rhine_init_one (struct pci_dev *pdev,
dev->stop = via_rhine_close; dev->stop = via_rhine_close;
dev->get_stats = via_rhine_get_stats; dev->get_stats = via_rhine_get_stats;
dev->set_multicast_list = via_rhine_set_rx_mode; dev->set_multicast_list = via_rhine_set_rx_mode;
dev->do_ioctl = via_rhine_ioctl; dev->do_ioctl = netdev_ioctl;
dev->tx_timeout = via_rhine_tx_timeout; dev->tx_timeout = via_rhine_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
if (np->drv_flags & ReqTxAlign) if (np->drv_flags & ReqTxAlign)
...@@ -1001,7 +1003,7 @@ static void init_registers(struct net_device *dev) ...@@ -1001,7 +1003,7 @@ static void init_registers(struct net_device *dev)
ioaddr + IntrEnable); ioaddr + IntrEnable);
np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll; np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
if (np->mii_if.duplex_lock) if (np->mii_if.force_media)
np->chip_cmd |= CmdFDuplex; np->chip_cmd |= CmdFDuplex;
writew(np->chip_cmd, ioaddr + ChipCmd); writew(np->chip_cmd, ioaddr + ChipCmd);
...@@ -1043,7 +1045,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value ...@@ -1043,7 +1045,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int regnum, int value
switch (regnum) { switch (regnum) {
case MII_BMCR: /* Is user forcing speed/duplex? */ case MII_BMCR: /* Is user forcing speed/duplex? */
if (value & 0x9000) /* Autonegotiation. */ if (value & 0x9000) /* Autonegotiation. */
np->mii_if.duplex_lock = 0; np->mii_if.force_media = 0;
else else
np->mii_if.full_duplex = (value & 0x0100) ? 1 : 0; np->mii_if.full_duplex = (value & 0x0100) ? 1 : 0;
break; break;
...@@ -1114,7 +1116,7 @@ static void via_rhine_check_duplex(struct net_device *dev) ...@@ -1114,7 +1116,7 @@ static void via_rhine_check_duplex(struct net_device *dev)
int negotiated = mii_lpa & np->mii_if.advertising; int negotiated = mii_lpa & np->mii_if.advertising;
int duplex; int duplex;
if (np->mii_if.duplex_lock || mii_lpa == 0xffff) if (np->mii_if.force_media || mii_lpa == 0xffff)
return; return;
duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
if (np->mii_if.full_duplex != duplex) { if (np->mii_if.full_duplex != duplex) {
...@@ -1586,7 +1588,7 @@ static void via_rhine_set_rx_mode(struct net_device *dev) ...@@ -1586,7 +1588,7 @@ static void via_rhine_set_rx_mode(struct net_device *dev)
writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig); writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
} }
static int via_rhine_ethtool_ioctl (struct net_device *dev, void *useraddr) static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
{ {
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
u32 ethcmd; u32 ethcmd;
...@@ -1669,41 +1671,28 @@ static int via_rhine_ethtool_ioctl (struct net_device *dev, void *useraddr) ...@@ -1669,41 +1671,28 @@ static int via_rhine_ethtool_ioctl (struct net_device *dev, void *useraddr)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int via_rhine_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;
unsigned long flags; int rc;
int retval;
if (cmd == SIOCETHTOOL)
return via_rhine_ethtool_ioctl(dev, (void *) rq->ifr_data);
spin_lock_irqsave(&np->lock, flags); if (!netif_running(dev))
retval = 0; return -EINVAL;
switch(cmd) {
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
data->phy_id = np->phys[0] & 0x1f;
/* Fall Through */
case SIOCGMIIREG: /* Read MII PHY register. */ if (cmd == SIOCETHTOOL)
data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
break;
case SIOCSMIIREG: /* Write MII PHY register. */ else {
if (!capable(CAP_NET_ADMIN)) { spin_lock_irq(&np->lock);
retval = -EPERM; rc = generic_mii_ioctl(dev, &np->mii_if, data, cmd);
break; spin_unlock_irq(&np->lock);
} if (rc == 1) /* don't care about duplex change, fix up rc */
mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in); rc = 0;
break;
default:
retval = -EOPNOTSUPP;
} }
spin_unlock_irqrestore(&np->lock, flags); return rc;
return retval;
} }
static int via_rhine_close(struct net_device *dev) static int via_rhine_close(struct net_device *dev)
......
...@@ -107,9 +107,11 @@ ...@@ -107,9 +107,11 @@
struct mii_if_info { struct mii_if_info {
int phy_id; int phy_id;
int advertising; int advertising;
int phy_id_mask;
int reg_num_mask;
unsigned int full_duplex : 1; unsigned int full_duplex : 1; /* is full duplex? */
unsigned int duplex_lock : 1; unsigned int force_media : 1; /* is autoneg. disabled? */
struct net_device *dev; struct net_device *dev;
int (*mdio_read) (struct net_device *dev, int phy_id, int location); int (*mdio_read) (struct net_device *dev, int phy_id, int location);
...@@ -117,13 +119,19 @@ struct mii_if_info { ...@@ -117,13 +119,19 @@ struct mii_if_info {
}; };
struct ethtool_cmd; struct ethtool_cmd;
struct mii_ioctl_data;
extern int mii_link_ok (struct mii_if_info *mii); extern int mii_link_ok (struct mii_if_info *mii);
extern int mii_nway_restart (struct mii_if_info *mii); extern int mii_nway_restart (struct mii_if_info *mii);
extern int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd); extern int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
extern int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd); extern int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
extern void mii_check_link (struct mii_if_info *mii); extern void mii_check_link (struct mii_if_info *mii);
extern unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print); extern unsigned int mii_check_media (struct mii_if_info *mii,
unsigned int ok_to_print,
unsigned int init_media);
extern int generic_mii_ioctl(struct net_device *dev, struct mii_if_info *mii_if,
struct mii_ioctl_data *mii_data, int cmd);
/* This structure is used in all SIOCxMIIxxx ioctl calls */ /* This structure is used in all SIOCxMIIxxx ioctl calls */
......
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