Commit 3a756e7a authored by Linus Torvalds's avatar Linus Torvalds

Merge http://gkernel.bkbits.net/net-drivers-2.5

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 2d1a3871 9b425022
...@@ -24,6 +24,7 @@ sequences). To utilise this ability, you have to do 8 things: ...@@ -24,6 +24,7 @@ sequences). To utilise this ability, you have to do 8 things:
kernel with the ewrk3 configuration turned off and reboot. kernel with the ewrk3 configuration turned off and reboot.
5) insmod ewrk3.o 5) insmod ewrk3.o
[Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y] [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
[Adam Kropelin: Multiple cards now supported by irq=x1,x2 io=y1,y2]
6) run the net startup bits for your new eth?? interface manually 6) run the net startup bits for your new eth?? interface manually
(usually /etc/rc.inet[12] at boot time). (usually /etc/rc.inet[12] at boot time).
7) enjoy! 7) enjoy!
......
...@@ -49,11 +49,13 @@ ...@@ -49,11 +49,13 @@
- Power Management support - Power Management support
v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com> v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com>
- Full duplex support - Full duplex support
v1.19 16Oct2002 Zwane Mwaikambo <zwane@linuxpower.ca>
- Additional ethtool features
*/ */
#define DRV_NAME "3c509" #define DRV_NAME "3c509"
#define DRV_VERSION "1.18c" #define DRV_VERSION "1.19"
#define DRV_RELDATE "1Mar2002" #define DRV_RELDATE "16Oct2002"
/* A few values that may be tweaked. */ /* A few values that may be tweaked. */
...@@ -140,9 +142,11 @@ enum RxFilter { ...@@ -140,9 +142,11 @@ enum RxFilter {
#define TX_STATUS 0x0B #define TX_STATUS 0x0B
#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */ #define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */
#define WN0_CONF_CTRL 0x04 /* Window 0: Configuration control register */
#define WN0_ADDR_CONF 0x06 /* Window 0: Address configuration register */
#define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */ #define WN0_IRQ 0x08 /* Window 0: Set IRQ line in bits 12-15. */
#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */ #define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ #define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */ #define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */
#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */ #define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */
...@@ -981,6 +985,119 @@ el3_close(struct net_device *dev) ...@@ -981,6 +985,119 @@ el3_close(struct net_device *dev)
return 0; return 0;
} }
static int
el3_link_ok(struct net_device *dev)
{
int ioaddr = dev->base_addr;
u16 tmp;
EL3WINDOW(4);
tmp = inw(ioaddr + WN4_MEDIA);
EL3WINDOW(1);
return tmp & (1<<11);
}
static int
el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
int ioaddr = dev->base_addr;
EL3WINDOW(0);
/* obtain current tranceiver via WN4_MEDIA? */
tmp = inw(ioaddr + WN0_ADDR_CONF);
ecmd->transceiver = XCVR_INTERNAL;
switch (tmp >> 14) {
case 0:
ecmd->port = PORT_TP;
break;
case 1:
ecmd->port = PORT_AUI;
ecmd->transceiver = XCVR_EXTERNAL;
break;
case 3:
ecmd->port = PORT_BNC;
default:
break;
}
ecmd->duplex = DUPLEX_HALF;
ecmd->supported = 0;
tmp = inw(ioaddr + WN0_CONF_CTRL);
if (tmp & (1<<13))
ecmd->supported |= SUPPORTED_AUI;
if (tmp & (1<<12))
ecmd->supported |= SUPPORTED_BNC;
if (tmp & (1<<9)) {
ecmd->supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full; /* hmm... */
EL3WINDOW(4);
tmp = inw(ioaddr + WN4_NETDIAG);
if (tmp & FD_ENABLE)
ecmd->duplex = DUPLEX_FULL;
}
ecmd->speed = SPEED_10;
EL3WINDOW(1);
return 0;
}
static int
el3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
int ioaddr = dev->base_addr;
if (ecmd->speed != SPEED_10)
return -EINVAL;
if ((ecmd->duplex != DUPLEX_HALF) && (ecmd->duplex != DUPLEX_FULL))
return -EINVAL;
if ((ecmd->transceiver != XCVR_INTERNAL) && (ecmd->transceiver != XCVR_EXTERNAL))
return -EINVAL;
/* change XCVR type */
EL3WINDOW(0);
tmp = inw(ioaddr + WN0_ADDR_CONF);
switch (ecmd->port) {
case PORT_TP:
tmp &= ~(3<<14);
dev->if_port = 0;
break;
case PORT_AUI:
tmp |= (1<<14);
dev->if_port = 1;
break;
case PORT_BNC:
tmp |= (3<<14);
dev->if_port = 3;
break;
default:
return -EINVAL;
}
outw(tmp, ioaddr + WN0_ADDR_CONF);
if (dev->if_port == 3) {
/* fire up the DC-DC convertor if BNC gets enabled */
tmp = inw(ioaddr + WN0_ADDR_CONF);
if (tmp & (3 << 14)) {
outw(StartCoax, ioaddr + EL3_CMD);
udelay(800);
} else
return -EIO;
}
EL3WINDOW(4);
tmp = inw(ioaddr + WN4_NETDIAG);
if (ecmd->duplex == DUPLEX_FULL)
tmp |= FD_ENABLE;
else
tmp &= ~FD_ENABLE;
outw(tmp, ioaddr + WN4_NETDIAG);
EL3WINDOW(1);
return 0;
}
/** /**
* netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
* @dev: network interface on which out-of-band action is to be performed * @dev: network interface on which out-of-band action is to be performed
...@@ -989,9 +1106,11 @@ el3_close(struct net_device *dev) ...@@ -989,9 +1106,11 @@ el3_close(struct net_device *dev)
* Process the various commands of the SIOCETHTOOL interface. * Process the various commands of the SIOCETHTOOL interface.
*/ */
static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) static int
netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
{ {
u32 ethcmd; u32 ethcmd;
struct el3_private *lp = dev->priv;
/* dev_ioctl() in ../../net/core/dev.c has already checked /* dev_ioctl() in ../../net/core/dev.c has already checked
capable(CAP_NET_ADMIN), so don't bother with that here. */ capable(CAP_NET_ADMIN), so don't bother with that here. */
...@@ -1010,6 +1129,41 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) ...@@ -1010,6 +1129,41 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
return 0; return 0;
} }
/* get settings */
case ETHTOOL_GSET: {
int ret;
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
spin_lock_irq(&lp->lock);
ret = el3_netdev_get_ecmd(dev, &ecmd);
spin_unlock_irq(&lp->lock);
if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return ret;
}
/* set settings */
case ETHTOOL_SSET: {
int ret;
struct ethtool_cmd ecmd;
if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
return -EFAULT;
spin_lock_irq(&lp->lock);
ret = el3_netdev_set_ecmd(dev, &ecmd);
spin_unlock_irq(&lp->lock);
return ret;
}
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = { ETHTOOL_GLINK };
spin_lock_irq(&lp->lock);
edata.data = el3_link_ok(dev);
spin_unlock_irq(&lp->lock);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
/* get message-level */ /* get message-level */
case ETHTOOL_GMSGLVL: { case ETHTOOL_GMSGLVL: {
struct ethtool_value edata = {ETHTOOL_GMSGLVL}; struct ethtool_value edata = {ETHTOOL_GMSGLVL};
...@@ -1043,7 +1197,8 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) ...@@ -1043,7 +1197,8 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
* Process the various out-of-band ioctls passed to this driver. * Process the various out-of-band ioctls passed to this driver.
*/ */
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)
{ {
int rc = 0; int rc = 0;
...@@ -1060,7 +1215,8 @@ static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1060,7 +1215,8 @@ static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
return rc; return rc;
} }
static void el3_down(struct net_device *dev) static void
el3_down(struct net_device *dev)
{ {
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
...@@ -1077,7 +1233,7 @@ static void el3_down(struct net_device *dev) ...@@ -1077,7 +1233,7 @@ static void el3_down(struct net_device *dev)
/* Turn off thinnet power. Green! */ /* Turn off thinnet power. Green! */
outw(StopCoax, ioaddr + EL3_CMD); outw(StopCoax, ioaddr + EL3_CMD);
else if (dev->if_port == 0) { else if (dev->if_port == 0) {
/* Disable link beat and jabber, if_port may change ere next open(). */ /* Disable link beat and jabber, if_port may change here next open(). */
EL3WINDOW(4); EL3WINDOW(4);
outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
} }
...@@ -1087,7 +1243,8 @@ static void el3_down(struct net_device *dev) ...@@ -1087,7 +1243,8 @@ static void el3_down(struct net_device *dev)
update_stats(dev); update_stats(dev);
} }
static void el3_up(struct net_device *dev) static void
el3_up(struct net_device *dev)
{ {
int i, sw_info, net_diag; int i, sw_info, net_diag;
int ioaddr = dev->base_addr; int ioaddr = dev->base_addr;
...@@ -1176,7 +1333,8 @@ static void el3_up(struct net_device *dev) ...@@ -1176,7 +1333,8 @@ static void el3_up(struct net_device *dev)
/* Power Management support functions */ /* Power Management support functions */
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int el3_suspend(struct pm_dev *pdev) static int
el3_suspend(struct pm_dev *pdev)
{ {
unsigned long flags; unsigned long flags;
struct net_device *dev; struct net_device *dev;
...@@ -1202,7 +1360,8 @@ static int el3_suspend(struct pm_dev *pdev) ...@@ -1202,7 +1360,8 @@ static int el3_suspend(struct pm_dev *pdev)
return 0; return 0;
} }
static int el3_resume(struct pm_dev *pdev) static int
el3_resume(struct pm_dev *pdev)
{ {
unsigned long flags; unsigned long flags;
struct net_device *dev; struct net_device *dev;
...@@ -1228,7 +1387,8 @@ static int el3_resume(struct pm_dev *pdev) ...@@ -1228,7 +1387,8 @@ static int el3_resume(struct pm_dev *pdev)
return 0; return 0;
} }
static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data) static int
el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
{ {
switch (rqst) { switch (rqst) {
case PM_SUSPEND: case PM_SUSPEND:
......
...@@ -186,6 +186,11 @@ ...@@ -186,6 +186,11 @@
* also added text to distinguish type of load balancing (rr or xor) * also added text to distinguish type of load balancing (rr or xor)
* - change arp_ip_target module param from "1-12s" (array of 12 ptrs) * - change arp_ip_target module param from "1-12s" (array of 12 ptrs)
* to "s" (a single ptr) * to "s" (a single ptr)
*
* 2002/09/18 - Jay Vosburgh <fubar at us dot ibm dot com>
* - Fixed up bond_check_dev_link() (and callers): removed some magic
* numbers, banished local MII_ defines, wrapped ioctl calls to
* prevent EFAULT errors
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -228,15 +233,6 @@ ...@@ -228,15 +233,6 @@
#define BOND_LINK_MON_INTERV 0 #define BOND_LINK_MON_INTERV 0
#endif #endif
#undef MII_LINK_UP
#define MII_LINK_UP 0x04
#undef MII_ENDOF_NWAY
#define MII_ENDOF_NWAY 0x20
#undef MII_LINK_READY
#define MII_LINK_READY (MII_LINK_UP)
#ifndef BOND_LINK_ARP_INTERV #ifndef BOND_LINK_ARP_INTERV
#define BOND_LINK_ARP_INTERV 0 #define BOND_LINK_ARP_INTERV 0
#endif #endif
...@@ -386,13 +382,25 @@ static slave_t *bond_detach_slave(bonding_t *bond, slave_t *slave) ...@@ -386,13 +382,25 @@ static slave_t *bond_detach_slave(bonding_t *bond, slave_t *slave)
return slave; return slave;
} }
/*
* Less bad way to call ioctl from within the kernel; this needs to be
* done some other way to get the call out of interrupt context.
* Needs "ioctl" variable to be supplied by calling context.
*/
#define IOCTL(dev, arg, cmd) ({ \
int ret; \
mm_segment_t fs = get_fs(); \
set_fs(get_ds()); \
ret = ioctl(dev, arg, cmd); \
set_fs(fs); \
ret; })
/* /*
* if <dev> supports MII link status reporting, check its link * if <dev> supports MII link status reporting, check its link status.
* and report it as a bit field in a short int : *
* - 0x04 means link is up, * Return either BMSR_LSTATUS, meaning that the link is up (or we
* - 0x20 means end of autonegociation * can't tell and just pretend it is), or 0, meaning that the link is
* If the device doesn't support MII, then we only report 0x24, * down.
* meaning that the link is up and running since we can't check it.
*/ */
static u16 bond_check_dev_link(struct net_device *dev) static u16 bond_check_dev_link(struct net_device *dev)
{ {
...@@ -401,7 +409,8 @@ static u16 bond_check_dev_link(struct net_device *dev) ...@@ -401,7 +409,8 @@ static u16 bond_check_dev_link(struct net_device *dev)
struct mii_ioctl_data *mii; struct mii_ioctl_data *mii;
struct ethtool_value etool; struct ethtool_value etool;
if ((ioctl = dev->do_ioctl) != NULL) { /* ioctl to access MII */ ioctl = dev->do_ioctl;
if (ioctl) {
/* TODO: set pointer to correct ioctl on a per team member */ /* TODO: set pointer to correct ioctl on a per team member */
/* bases to make this more efficient. that is, once */ /* bases to make this more efficient. that is, once */
/* we determine the correct ioctl, we will always */ /* we determine the correct ioctl, we will always */
...@@ -415,9 +424,9 @@ static u16 bond_check_dev_link(struct net_device *dev) ...@@ -415,9 +424,9 @@ static u16 bond_check_dev_link(struct net_device *dev)
/* effect... */ /* effect... */
etool.cmd = ETHTOOL_GLINK; etool.cmd = ETHTOOL_GLINK;
ifr.ifr_data = (char*)&etool; ifr.ifr_data = (char*)&etool;
if (ioctl(dev, &ifr, SIOCETHTOOL) == 0) { if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) {
if (etool.data == 1) { if (etool.data == 1) {
return(MII_LINK_READY); return BMSR_LSTATUS;
} }
else { else {
return(0); return(0);
...@@ -431,21 +440,17 @@ static u16 bond_check_dev_link(struct net_device *dev) ...@@ -431,21 +440,17 @@ static u16 bond_check_dev_link(struct net_device *dev)
/* Yes, the mii is overlaid on the ifreq.ifr_ifru */ /* Yes, the mii is overlaid on the ifreq.ifr_ifru */
mii = (struct mii_ioctl_data *)&ifr.ifr_data; mii = (struct mii_ioctl_data *)&ifr.ifr_data;
if (ioctl(dev, &ifr, SIOCGMIIPHY) != 0) { if (IOCTL(dev, &ifr, SIOCGMIIPHY) != 0) {
return MII_LINK_READY; /* can't tell */ return BMSR_LSTATUS; /* can't tell */
} }
mii->reg_num = 1; mii->reg_num = MII_BMSR;
if (ioctl(dev, &ifr, SIOCGMIIREG) == 0) { if (IOCTL(dev, &ifr, SIOCGMIIREG) == 0) {
/* return mii->val_out & BMSR_LSTATUS;
* mii->val_out contains MII reg 1, BMSR
* 0x0004 means link established
*/
return mii->val_out;
} }
} }
return MII_LINK_READY; /* spoof link up ( we can't check it) */ return BMSR_LSTATUS; /* spoof link up ( we can't check it) */
} }
static u16 bond_check_mii_link(bonding_t *bond) static u16 bond_check_mii_link(bonding_t *bond)
...@@ -459,7 +464,7 @@ static u16 bond_check_mii_link(bonding_t *bond) ...@@ -459,7 +464,7 @@ static u16 bond_check_mii_link(bonding_t *bond)
read_unlock(&bond->ptrlock); read_unlock(&bond->ptrlock);
read_unlock_irqrestore(&bond->lock, flags); read_unlock_irqrestore(&bond->lock, flags);
return (has_active_interface ? MII_LINK_READY : 0); return (has_active_interface ? BMSR_LSTATUS : 0);
} }
static int bond_open(struct net_device *dev) static int bond_open(struct net_device *dev)
...@@ -797,8 +802,8 @@ static int bond_enslave(struct net_device *master_dev, ...@@ -797,8 +802,8 @@ static int bond_enslave(struct net_device *master_dev,
new_slave->link_failure_count = 0; new_slave->link_failure_count = 0;
/* check for initial state */ /* check for initial state */
if ((miimon <= 0) || ((bond_check_dev_link(slave_dev) & MII_LINK_READY) if ((miimon <= 0) ||
== MII_LINK_READY)) { (bond_check_dev_link(slave_dev) == BMSR_LSTATUS)) {
#ifdef BONDING_DEBUG #ifdef BONDING_DEBUG
printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n"); printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n");
#endif #endif
...@@ -1220,7 +1225,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -1220,7 +1225,7 @@ static void bond_mii_monitor(struct net_device *master)
switch (slave->link) { switch (slave->link) {
case BOND_LINK_UP: /* the link was up */ case BOND_LINK_UP: /* the link was up */
if ((link_state & MII_LINK_UP) == MII_LINK_UP) { if (link_state == BMSR_LSTATUS) {
/* link stays up, tell that this one /* link stays up, tell that this one
is immediately available */ is immediately available */
if (IS_UP(dev) && (mindelay > -2)) { if (IS_UP(dev) && (mindelay > -2)) {
...@@ -1256,7 +1261,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -1256,7 +1261,7 @@ static void bond_mii_monitor(struct net_device *master)
ensure proper action to be taken ensure proper action to be taken
*/ */
case BOND_LINK_FAIL: /* the link has just gone down */ case BOND_LINK_FAIL: /* the link has just gone down */
if ((link_state & MII_LINK_UP) == 0) { if (link_state != BMSR_LSTATUS) {
/* link stays down */ /* link stays down */
if (slave->delay <= 0) { if (slave->delay <= 0) {
/* link down for too long time */ /* link down for too long time */
...@@ -1285,7 +1290,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -1285,7 +1290,7 @@ static void bond_mii_monitor(struct net_device *master)
} else { } else {
slave->delay--; slave->delay--;
} }
} else if ((link_state & MII_LINK_READY) == MII_LINK_READY) { } else {
/* link up again */ /* link up again */
slave->link = BOND_LINK_UP; slave->link = BOND_LINK_UP;
printk(KERN_INFO printk(KERN_INFO
...@@ -1304,7 +1309,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -1304,7 +1309,7 @@ static void bond_mii_monitor(struct net_device *master)
} }
break; break;
case BOND_LINK_DOWN: /* the link was down */ case BOND_LINK_DOWN: /* the link was down */
if ((link_state & MII_LINK_READY) != MII_LINK_READY) { if (link_state != BMSR_LSTATUS) {
/* the link stays down, nothing more to do */ /* the link stays down, nothing more to do */
break; break;
} else { /* link going up */ } else { /* link going up */
...@@ -1326,7 +1331,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -1326,7 +1331,7 @@ static void bond_mii_monitor(struct net_device *master)
case there's something to do. case there's something to do.
*/ */
case BOND_LINK_BACK: /* the link has just come back */ case BOND_LINK_BACK: /* the link has just come back */
if ((link_state & MII_LINK_UP) == 0) { if (link_state != BMSR_LSTATUS) {
/* link down again */ /* link down again */
slave->link = BOND_LINK_DOWN; slave->link = BOND_LINK_DOWN;
printk(KERN_INFO printk(KERN_INFO
...@@ -1335,8 +1340,7 @@ static void bond_mii_monitor(struct net_device *master) ...@@ -1335,8 +1340,7 @@ static void bond_mii_monitor(struct net_device *master)
master->name, master->name,
(updelay - slave->delay) * miimon, (updelay - slave->delay) * miimon,
dev->name); dev->name);
} } else {
else if ((link_state & MII_LINK_READY) == MII_LINK_READY) {
/* link stays up */ /* link stays up */
if (slave->delay == 0) { if (slave->delay == 0) {
/* now the link has been up for long time enough */ /* now the link has been up for long time enough */
...@@ -2110,7 +2114,7 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) ...@@ -2110,7 +2114,7 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length)
len += sprintf(buf + len, "MII Status: "); len += sprintf(buf + len, "MII Status: ");
len += sprintf(buf + len, len += sprintf(buf + len,
link == MII_LINK_READY ? "up\n" : "down\n"); link == BMSR_LSTATUS ? "up\n" : "down\n");
len += sprintf(buf + len, "MII Polling Interval (ms): %d\n", len += sprintf(buf + len, "MII Polling Interval (ms): %d\n",
miimon); miimon);
len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay); len += sprintf(buf + len, "Up Delay (ms): %d\n", updelay);
......
...@@ -135,7 +135,7 @@ static int e1000_init_module(void); ...@@ -135,7 +135,7 @@ static int e1000_init_module(void);
static void e1000_exit_module(void); static void e1000_exit_module(void);
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void e1000_remove(struct pci_dev *pdev); static void e1000_remove(struct pci_dev *pdev);
static void e1000_sw_init(struct e1000_adapter *adapter); static int e1000_sw_init(struct e1000_adapter *adapter);
static int e1000_open(struct net_device *netdev); static int e1000_open(struct net_device *netdev);
static int e1000_close(struct net_device *netdev); static int e1000_close(struct net_device *netdev);
static int e1000_setup_tx_resources(struct e1000_adapter *adapter); static int e1000_setup_tx_resources(struct e1000_adapter *adapter);
...@@ -415,7 +415,8 @@ e1000_probe(struct pci_dev *pdev, ...@@ -415,7 +415,8 @@ e1000_probe(struct pci_dev *pdev,
/* setup the private structure */ /* setup the private structure */
e1000_sw_init(adapter); if(e1000_sw_init(adapter))
goto err_sw_init;
if(adapter->hw.mac_type >= e1000_82543) { if(adapter->hw.mac_type >= e1000_82543) {
netdev->features = NETIF_F_SG | netdev->features = NETIF_F_SG |
...@@ -500,6 +501,7 @@ e1000_probe(struct pci_dev *pdev, ...@@ -500,6 +501,7 @@ e1000_probe(struct pci_dev *pdev,
cards_found++; cards_found++;
return 0; return 0;
err_sw_init:
err_eeprom: err_eeprom:
iounmap(adapter->hw.hw_addr); iounmap(adapter->hw.hw_addr);
err_ioremap: err_ioremap:
...@@ -555,7 +557,7 @@ e1000_remove(struct pci_dev *pdev) ...@@ -555,7 +557,7 @@ e1000_remove(struct pci_dev *pdev)
* OS network device settings (MTU size). * OS network device settings (MTU size).
**/ **/
static void __devinit static int __devinit
e1000_sw_init(struct e1000_adapter *adapter) e1000_sw_init(struct e1000_adapter *adapter)
{ {
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
...@@ -564,11 +566,11 @@ e1000_sw_init(struct e1000_adapter *adapter) ...@@ -564,11 +566,11 @@ e1000_sw_init(struct e1000_adapter *adapter)
/* PCI config space info */ /* PCI config space info */
pci_read_config_word(pdev, PCI_VENDOR_ID, &hw->vendor_id); hw->vendor_id = pdev->vendor;
pci_read_config_word(pdev, PCI_DEVICE_ID, &hw->device_id); hw->device_id = pdev->device;
pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, hw->subsystem_vendor_id = pdev->subsystem_vendor;
&hw->subsystem_vendor_id); hw->subsystem_id = pdev->subsystem_device;
pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_id);
pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
...@@ -581,7 +583,7 @@ e1000_sw_init(struct e1000_adapter *adapter) ...@@ -581,7 +583,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
if (e1000_set_mac_type(hw)) { if (e1000_set_mac_type(hw)) {
E1000_ERR("Unknown MAC Type\n"); E1000_ERR("Unknown MAC Type\n");
BUG(); return -1;
} }
/* flow control settings */ /* flow control settings */
...@@ -622,6 +624,8 @@ e1000_sw_init(struct e1000_adapter *adapter) ...@@ -622,6 +624,8 @@ e1000_sw_init(struct e1000_adapter *adapter)
atomic_set(&adapter->irq_sem, 1); atomic_set(&adapter->irq_sem, 1);
spin_lock_init(&adapter->stats_lock); spin_lock_init(&adapter->stats_lock);
return 0;
} }
/** /**
......
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
kernel with the ewrk3 configuration turned off and reboot. kernel with the ewrk3 configuration turned off and reboot.
5) insmod ewrk3.o 5) insmod ewrk3.o
[Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y] [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
[Adam Kropelin: now accepts irq=x1,x2 io=y1,y2 for multiple cards]
6) run the net startup bits for your new eth?? interface manually 6) run the net startup bits for your new eth?? interface manually
(usually /etc/rc.inet[12] at boot time). (usually /etc/rc.inet[12] at boot time).
7) enjoy! 7) enjoy!
...@@ -130,10 +131,12 @@ ...@@ -130,10 +131,12 @@
Add new multicasting code. Add new multicasting code.
0.41 20-Jan-96 Fix IRQ set up problem reported by 0.41 20-Jan-96 Fix IRQ set up problem reported by
<kenneth@bbs.sas.ntu.ac.sg>. <kenneth@bbs.sas.ntu.ac.sg>.
0.42 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi> 0.42 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi>
0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
0.44 08-Nov-01 use library crc32 functions <Matt_Domsch@dell.com> 0.44 08-Nov-01 use library crc32 functions <Matt_Domsch@dell.com>
0.45 19-Jul-02 fix unaligned access on alpha <martin@bruli.net> 0.45 19-Jul-02 fix unaligned access on alpha <martin@bruli.net>
0.46 10-Oct-02 cli/sti removal <VDA@port.imtp.ilyichevsk.odessa.ua>
Multiple NIC support when module <akropel1@rochester.rr.com>
========================================================================= =========================================================================
*/ */
...@@ -167,7 +170,7 @@ ...@@ -167,7 +170,7 @@
#include "ewrk3.h" #include "ewrk3.h"
static char version[] __initdata = static char version[] __initdata =
"ewrk3.c:v0.43a 2001/02/04 davies@maniac.ultranet.com\n"; "ewrk3.c:v0.46 2002/10/09 davies@maniac.ultranet.com\n";
#ifdef EWRK3_DEBUG #ifdef EWRK3_DEBUG
static int ewrk3_debug = EWRK3_DEBUG; static int ewrk3_debug = EWRK3_DEBUG;
...@@ -196,6 +199,7 @@ static int ewrk3_debug = 1; ...@@ -196,6 +199,7 @@ static int ewrk3_debug = 1;
#define EWRK3_IOP_INC 0x20 /* I/O address increment */ #define EWRK3_IOP_INC 0x20 /* I/O address increment */
#define EWRK3_TOTAL_SIZE 0x20 /* required I/O address length */ #define EWRK3_TOTAL_SIZE 0x20 /* required I/O address length */
/* If you change this, remember to also change MODULE_PARM array limits */
#ifndef MAX_NUM_EWRK3S #ifndef MAX_NUM_EWRK3S
#define MAX_NUM_EWRK3S 21 #define MAX_NUM_EWRK3S 21
#endif #endif
...@@ -1716,6 +1720,11 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1716,6 +1720,11 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
break; break;
case EWRK3_SET_MCA: /* Set a multicast address */ case EWRK3_SET_MCA: /* Set a multicast address */
if (capable(CAP_NET_ADMIN)) { if (capable(CAP_NET_ADMIN)) {
if (ioc->len > 1024)
{
status = -EINVAL;
break;
}
if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) { if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) {
status = -EFAULT; status = -EFAULT;
break; break;
...@@ -1843,35 +1852,62 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -1843,35 +1852,62 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
} }
#ifdef MODULE #ifdef MODULE
static struct net_device thisEthwrk; static struct net_device *ewrk3_devs[MAX_NUM_EWRK3S];
static int io = 0x300; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */ static int ndevs;
static int irq = 5; /* or use the insmod io= irq= options */ static int io[MAX_NUM_EWRK3S+1] = { 0x300, 0, }; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
static int irq[MAX_NUM_EWRK3S+1] = { 5, 0, }; /* or use the insmod io= irq= options */
MODULE_PARM(io, "i"); /* '21' below should really be 'MAX_NUM_EWRK3S' */
MODULE_PARM(irq, "i"); MODULE_PARM(io, "0-21i");
MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address"); MODULE_PARM(irq, "0-21i");
MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number"); MODULE_PARM_DESC(io, "EtherWORKS 3 I/O base address(es)");
MODULE_PARM_DESC(irq, "EtherWORKS 3 IRQ number(s)");
int init_module(void) int init_module(void)
{ {
thisEthwrk.base_addr = io; int i=0;
thisEthwrk.irq = irq;
thisEthwrk.init = ewrk3_probe; while( io[i] && irq[i] ) {
if (register_netdev(&thisEthwrk) != 0) ewrk3_devs[ndevs] = kmalloc(sizeof(struct net_device), GFP_KERNEL);
return -EIO; if (!ewrk3_devs[ndevs])
return 0; goto error;
memset(ewrk3_devs[ndevs], 0, sizeof(struct net_device));
ewrk3_devs[ndevs]->base_addr = io[i];
ewrk3_devs[ndevs]->irq = irq[i];
ewrk3_devs[ndevs]->init = ewrk3_probe;
if (register_netdev(ewrk3_devs[ndevs]) == 0)
ndevs++;
else
kfree(ewrk3_devs[ndevs]);
i++;
}
return ndevs ? 0 : -EIO;
error:
cleanup_module();
return -ENOMEM;
} }
void cleanup_module(void) void cleanup_module(void)
{ {
unregister_netdev(&thisEthwrk); int i;
if (thisEthwrk.priv) {
kfree(thisEthwrk.priv); for( i=0; i<ndevs; i++ )
thisEthwrk.priv = NULL; {
} unregister_netdev(ewrk3_devs[i]);
thisEthwrk.irq = 0; if (ewrk3_devs[i]->priv) {
kfree(ewrk3_devs[i]->priv);
ewrk3_devs[i]->priv = NULL;
}
ewrk3_devs[i]->irq = 0;
release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE); release_region(ewrk3_devs[i]->base_addr, EWRK3_TOTAL_SIZE);
kfree(ewrk3_devs[i]);
ewrk3_devs[i] = NULL;
}
} }
#endif /* MODULE */ #endif /* MODULE */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -243,7 +243,7 @@ unsigned int mii_check_media (struct mii_if_info *mii, ...@@ -243,7 +243,7 @@ unsigned int mii_check_media (struct mii_if_info *mii,
/* figure out media and duplex from advertise and LPA values */ /* figure out media and duplex from advertise and LPA values */
media = mii_nway_result(lpa & advertise); media = mii_nway_result(lpa & advertise);
duplex = (media & (ADVERTISE_100FULL | ADVERTISE_10FULL)) ? 1 : 0; duplex = (media & ADVERTISE_FULL) ? 1 : 0;
if (ok_to_print) if (ok_to_print)
printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n", printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
smc91c92_cs.c 1.113 2001/10/13 00:08:53 smc91c92_cs.c 1.2 2002/09/28 15:00:00
This driver contains code written by Donald Becker This driver contains code written by Donald Becker
(becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au), (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
...@@ -37,12 +37,15 @@ ...@@ -37,12 +37,15 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <pcmcia/version.h> #include <pcmcia/version.h>
#include <pcmcia/cs_types.h> #include <pcmcia/cs_types.h>
...@@ -88,6 +91,9 @@ static const char *version = ...@@ -88,6 +91,9 @@ static const char *version =
#define DEBUG(n, args...) #define DEBUG(n, args...)
#endif #endif
#define DRV_NAME "smc91c92_cs"
#define DRV_VERSION "1.2"
/*====================================================================*/ /*====================================================================*/
/* Operational parameter that usually are not changed. */ /* Operational parameter that usually are not changed. */
...@@ -109,6 +115,7 @@ static dev_link_t *dev_list; ...@@ -109,6 +115,7 @@ static dev_link_t *dev_list;
struct smc_private { struct smc_private {
dev_link_t link; dev_link_t link;
struct net_device dev; struct net_device dev;
spinlock_t lock;
u_short manfid; u_short manfid;
u_short cardid; u_short cardid;
struct net_device_stats stats; struct net_device_stats stats;
...@@ -122,7 +129,7 @@ struct smc_private { ...@@ -122,7 +129,7 @@ struct smc_private {
u_short media_status; u_short media_status;
u_short fast_poll; u_short fast_poll;
u_short link_status; u_short link_status;
int phy_id; struct mii_if_info mii_if;
}; };
/* Special definitions for Megahertz multifunction cards */ /* Special definitions for Megahertz multifunction cards */
...@@ -292,9 +299,11 @@ static int s9k_config(struct net_device *dev, struct ifmap *map); ...@@ -292,9 +299,11 @@ static int s9k_config(struct net_device *dev, struct ifmap *map);
static void smc_set_xcvr(struct net_device *dev, int if_port); static void smc_set_xcvr(struct net_device *dev, int if_port);
static void smc_reset(struct net_device *dev); static void smc_reset(struct net_device *dev);
static void media_check(u_long arg); static void media_check(u_long arg);
static void mdio_sync(ioaddr_t addr); static void smc_mdio_sync(ioaddr_t addr);
static int mdio_read(ioaddr_t addr, int phy_id, int loc); static int smc_mdio_read(struct net_device *dev, int phy_id, int loc);
static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value); static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value);
static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int smc_link_ok(struct net_device *dev);
/*====================================================================== /*======================================================================
...@@ -346,7 +355,7 @@ static dev_link_t *smc91c92_attach(void) ...@@ -346,7 +355,7 @@ static dev_link_t *smc91c92_attach(void)
if (!smc) return NULL; if (!smc) return NULL;
memset(smc, 0, sizeof(struct smc_private)); memset(smc, 0, sizeof(struct smc_private));
link = &smc->link; dev = &smc->dev; link = &smc->link; dev = &smc->dev;
spin_lock_init(&smc->lock);
link->release.function = &smc91c92_release; link->release.function = &smc91c92_release;
link->release.data = (u_long)link; link->release.data = (u_long)link;
link->io.NumPorts1 = 16; link->io.NumPorts1 = 16;
...@@ -369,6 +378,7 @@ static dev_link_t *smc91c92_attach(void) ...@@ -369,6 +378,7 @@ static dev_link_t *smc91c92_attach(void)
dev->get_stats = &smc91c92_get_stats; dev->get_stats = &smc91c92_get_stats;
dev->set_config = &s9k_config; dev->set_config = &s9k_config;
dev->set_multicast_list = &set_rx_mode; dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &smc_ioctl;
ether_setup(dev); ether_setup(dev);
dev->open = &smc91c92_open; dev->open = &smc91c92_open;
dev->stop = &smc91c92_close; dev->stop = &smc91c92_close;
...@@ -377,6 +387,12 @@ static dev_link_t *smc91c92_attach(void) ...@@ -377,6 +387,12 @@ static dev_link_t *smc91c92_attach(void)
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
#endif #endif
dev->priv = link->priv = link->irq.Instance = smc; dev->priv = link->priv = link->irq.Instance = smc;
smc->mii_if.dev = dev;
smc->mii_if.mdio_read = smc_mdio_read;
smc->mii_if.mdio_write = smc_mdio_write;
smc->mii_if.phy_id_mask = 0x1f;
smc->mii_if.reg_num_mask = 0x1f;
/* Register with Card Services */ /* Register with Card Services */
link->next = dev_list; link->next = dev_list;
...@@ -1044,10 +1060,10 @@ static void smc91c92_config(dev_link_t *link) ...@@ -1044,10 +1060,10 @@ static void smc91c92_config(dev_link_t *link)
SMC_SELECT_BANK(3); SMC_SELECT_BANK(3);
for (i = 0; i < 32; i++) { for (i = 0; i < 32; i++) {
j = mdio_read(dev->base_addr + MGMT, i, 1); j = smc_mdio_read(dev, i, 1);
if ((j != 0) && (j != 0xffff)) break; if ((j != 0) && (j != 0xffff)) break;
} }
smc->phy_id = (i < 32) ? i : -1; smc->mii_if.phy_id = (i < 32) ? i : -1;
if (i < 32) { if (i < 32) {
DEBUG(0, " MII transceiver at index %d, status %x.\n", i, j); DEBUG(0, " MII transceiver at index %d, status %x.\n", i, j);
} else { } else {
...@@ -1190,7 +1206,7 @@ static int smc91c92_event(event_t event, int priority, ...@@ -1190,7 +1206,7 @@ static int smc91c92_event(event_t event, int priority,
#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT) #define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)
#define MDIO_DATA_READ 0x02 #define MDIO_DATA_READ 0x02
static void mdio_sync(ioaddr_t addr) static void smc_mdio_sync(ioaddr_t addr)
{ {
int bits; int bits;
for (bits = 0; bits < 32; bits++) { for (bits = 0; bits < 32; bits++) {
...@@ -1199,12 +1215,13 @@ static void mdio_sync(ioaddr_t addr) ...@@ -1199,12 +1215,13 @@ static void mdio_sync(ioaddr_t addr)
} }
} }
static int mdio_read(ioaddr_t addr, int phy_id, int loc) static int smc_mdio_read(struct net_device *dev, int phy_id, int loc)
{ {
ioaddr_t addr = dev->base_addr + MGMT;
u_int cmd = (0x06<<10)|(phy_id<<5)|loc; u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
int i, retval = 0; int i, retval = 0;
mdio_sync(addr); smc_mdio_sync(addr);
for (i = 13; i >= 0; i--) { for (i = 13; i >= 0; i--) {
int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0; int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
outb(dat, addr); outb(dat, addr);
...@@ -1218,12 +1235,13 @@ static int mdio_read(ioaddr_t addr, int phy_id, int loc) ...@@ -1218,12 +1235,13 @@ static int mdio_read(ioaddr_t addr, int phy_id, int loc)
return (retval>>1) & 0xffff; return (retval>>1) & 0xffff;
} }
static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value) static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value)
{ {
ioaddr_t addr = dev->base_addr + MGMT;
u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value; u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
int i; int i;
mdio_sync(addr); smc_mdio_sync(addr);
for (i = 31; i >= 0; i--) { for (i = 31; i >= 0; i--) {
int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0; int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
outb(dat, addr); outb(dat, addr);
...@@ -1777,6 +1795,7 @@ static void fill_multicast_tbl(int count, struct dev_mc_list *addrs, ...@@ -1777,6 +1795,7 @@ static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
static void set_rx_mode(struct net_device *dev) static void set_rx_mode(struct net_device *dev)
{ {
ioaddr_t ioaddr = dev->base_addr; ioaddr_t ioaddr = dev->base_addr;
struct smc_private *smc = dev->priv;
u_int multicast_table[ 2 ] = { 0, }; u_int multicast_table[ 2 ] = { 0, };
unsigned long flags; unsigned long flags;
u_short rx_cfg_setting; u_short rx_cfg_setting;
...@@ -1795,16 +1814,15 @@ static void set_rx_mode(struct net_device *dev) ...@@ -1795,16 +1814,15 @@ static void set_rx_mode(struct net_device *dev)
} }
/* Load MC table and Rx setting into the chip without interrupts. */ /* Load MC table and Rx setting into the chip without interrupts. */
save_flags(flags); spin_lock_irqsave(&smc->lock, flags);
cli();
SMC_SELECT_BANK(3); SMC_SELECT_BANK(3);
outl(multicast_table[0], ioaddr + MULTICAST0); outl(multicast_table[0], ioaddr + MULTICAST0);
outl(multicast_table[1], ioaddr + MULTICAST4); outl(multicast_table[1], ioaddr + MULTICAST4);
SMC_SELECT_BANK(0); SMC_SELECT_BANK(0);
outw(rx_cfg_setting, ioaddr + RCR); outw(rx_cfg_setting, ioaddr + RCR);
SMC_SELECT_BANK(2); SMC_SELECT_BANK(2);
restore_flags(flags); spin_unlock_irqrestore(&smc->lock, flags);
return; return;
} }
...@@ -1917,11 +1935,11 @@ static void smc_reset(struct net_device *dev) ...@@ -1917,11 +1935,11 @@ static void smc_reset(struct net_device *dev)
SMC_SELECT_BANK(3); SMC_SELECT_BANK(3);
/* Reset MII */ /* Reset MII */
mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x8000); smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
/* Restart MII autonegotiation */ /* Restart MII autonegotiation */
mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x0000); smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
mdio_write(ioaddr + MGMT, smc->phy_id, 0, 0x1200); smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
} }
/* Enable interrupts. */ /* Enable interrupts. */
...@@ -1942,7 +1960,6 @@ static void media_check(u_long arg) ...@@ -1942,7 +1960,6 @@ static void media_check(u_long arg)
struct net_device *dev = &smc->dev; struct net_device *dev = &smc->dev;
ioaddr_t ioaddr = dev->base_addr; ioaddr_t ioaddr = dev->base_addr;
u_short i, media, saved_bank; u_short i, media, saved_bank;
ioaddr_t mii_addr = dev->base_addr + MGMT;
u_short link; u_short link;
saved_bank = inw(ioaddr + BANK_SELECT); saved_bank = inw(ioaddr + BANK_SELECT);
...@@ -1974,20 +1991,20 @@ static void media_check(u_long arg) ...@@ -1974,20 +1991,20 @@ static void media_check(u_long arg)
} }
if (smc->cfg & CFG_MII_SELECT) { if (smc->cfg & CFG_MII_SELECT) {
if (smc->phy_id < 0) if (smc->mii_if.phy_id < 0)
goto reschedule; goto reschedule;
SMC_SELECT_BANK(3); SMC_SELECT_BANK(3);
link = mdio_read(mii_addr, smc->phy_id, 1); link = smc_mdio_read(dev, smc->mii_if.phy_id, 1);
if (!link || (link == 0xffff)) { if (!link || (link == 0xffff)) {
printk(KERN_INFO "%s: MII is missing!\n", dev->name); printk(KERN_INFO "%s: MII is missing!\n", dev->name);
smc->phy_id = -1; smc->mii_if.phy_id = -1;
goto reschedule; goto reschedule;
} }
link &= 0x0004; link &= 0x0004;
if (link != smc->link_status) { if (link != smc->link_status) {
u_short p = mdio_read(mii_addr, smc->phy_id, 5); u_short p = smc_mdio_read(dev, smc->mii_if.phy_id, 5);
printk(KERN_INFO "%s: %s link beat\n", dev->name, printk(KERN_INFO "%s: %s link beat\n", dev->name,
(link) ? "found" : "lost"); (link) ? "found" : "lost");
if (link) { if (link) {
...@@ -2043,6 +2060,191 @@ static void media_check(u_long arg) ...@@ -2043,6 +2060,191 @@ static void media_check(u_long arg)
SMC_SELECT_BANK(saved_bank); SMC_SELECT_BANK(saved_bank);
} }
static int smc_link_ok(struct net_device *dev)
{
ioaddr_t ioaddr = dev->base_addr;
struct smc_private *smc = dev->priv;
if (smc->cfg & CFG_MII_SELECT) {
return mii_link_ok(&smc->mii_if);
} else {
SMC_SELECT_BANK(0);
return inw(ioaddr + EPH) & EPH_LINK_OK;
}
}
static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
ioaddr_t ioaddr = dev->base_addr;
ecmd->supported = (SUPPORTED_TP | SUPPORTED_AUI |
SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full);
SMC_SELECT_BANK(1);
tmp = inw(ioaddr + CONFIG);
ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
ecmd->transceiver = XCVR_INTERNAL;
ecmd->speed = SPEED_10;
ecmd->phy_address = ioaddr + MGMT;
SMC_SELECT_BANK(0);
tmp = inw(ioaddr + TCR);
ecmd->duplex = (tmp & TCR_FDUPLX) ? DUPLEX_FULL : DUPLEX_HALF;
return 0;
}
static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
ioaddr_t ioaddr = dev->base_addr;
if (ecmd->speed != SPEED_10)
return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
return -EINVAL;
if (ecmd->transceiver != XCVR_INTERNAL)
return -EINVAL;
if (ecmd->port == PORT_AUI)
smc_set_xcvr(dev, 1);
else
smc_set_xcvr(dev, 0);
SMC_SELECT_BANK(0);
tmp = inw(ioaddr + TCR);
if (ecmd->duplex == DUPLEX_FULL)
tmp |= TCR_FDUPLX;
else
tmp &= ~TCR_FDUPLX;
outw(ioaddr + TCR, tmp);
return 0;
}
static int smc_ethtool_ioctl (struct net_device *dev, void *useraddr)
{
u32 ethcmd;
struct smc_private *smc = dev->priv;
if (get_user(ethcmd, (u32 *)useraddr))
return -EFAULT;
switch (ethcmd) {
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strcpy(info.driver, DRV_NAME);
strcpy(info.version, DRV_VERSION);
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
/* get settings */
case ETHTOOL_GSET: {
int ret;
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
spin_lock_irq(&smc->lock);
if (smc->cfg & CFG_MII_SELECT)
ret = mii_ethtool_gset(&smc->mii_if, &ecmd);
else
ret = smc_netdev_get_ecmd(dev, &ecmd);
spin_unlock_irq(&smc->lock);
if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
return -EFAULT;
return ret;
}
/* set settings */
case ETHTOOL_SSET: {
int ret;
struct ethtool_cmd ecmd;
if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
return -EFAULT;
spin_lock_irq(&smc->lock);
if (smc->cfg & CFG_MII_SELECT)
ret = mii_ethtool_sset(&smc->mii_if, &ecmd);
else
ret = smc_netdev_set_ecmd(dev, &ecmd);
spin_unlock_irq(&smc->lock);
return ret;
}
/* get link status */
case ETHTOOL_GLINK: {
struct ethtool_value edata = { ETHTOOL_GLINK };
spin_lock_irq(&smc->lock);
edata.data = smc_link_ok(dev);
spin_unlock_irq(&smc->lock);
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
}
#ifdef PCMCIA_DEBUG
/* get message-level */
case ETHTOOL_GMSGLVL: {
struct ethtool_value edata = { ETHTOOL_GMSGLVL };
edata.data = pc_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;
pc_debug = edata.data;
return 0;
}
#endif
/* restart autonegotiation */
case ETHTOOL_NWAY_RST: {
if (smc->cfg & CFG_MII_SELECT)
return mii_nway_restart(&smc->mii_if);
else
return -EOPNOTSUPP;
}
default:
break;
}
return -EOPNOTSUPP;
}
static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
{
struct smc_private *smc = dev->priv;
struct mii_ioctl_data *mii;
int rc = 0;
mii = (struct mii_ioctl_data *) &rq->ifr_data;
if (!netif_running(dev))
return -EINVAL;
switch (cmd) {
case SIOCETHTOOL:
rc = smc_ethtool_ioctl(dev, (void *) rq->ifr_data);
break;
default:
spin_lock_irq(&smc->lock);
rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
spin_unlock_irq(&smc->lock);
break;
}
return rc;
}
/*====================================================================*/ /*====================================================================*/
static int __init init_smc91c92_cs(void) static int __init init_smc91c92_cs(void)
...@@ -2069,3 +2271,4 @@ static void __exit exit_smc91c92_cs(void) ...@@ -2069,3 +2271,4 @@ static void __exit exit_smc91c92_cs(void)
module_init(init_smc91c92_cs); module_init(init_smc91c92_cs);
module_exit(exit_smc91c92_cs); module_exit(exit_smc91c92_cs);
...@@ -253,7 +253,7 @@ static int __init tms_pci_init (void) ...@@ -253,7 +253,7 @@ static int __init tms_pci_init (void)
return 0; return 0;
} }
static void __devexit tms_pci_rmmod (void) static void __exit tms_pci_rmmod (void)
{ {
pci_unregister_driver (&tms_pci_driver); pci_unregister_driver (&tms_pci_driver);
} }
......
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