patch-2.4.0-test8 linux/drivers/net/pcmcia/pcnet_cs.c
Next file: linux/drivers/net/pcmcia/ray_cs.c
Previous file: linux/drivers/net/pcmcia/nmclan_cs.c
Back to the patch index
Back to the overall index
- Lines: 354
- Date:
Sat Sep 2 00:15:37 2000
- Orig file:
v2.4.0-test7/linux/drivers/net/pcmcia/pcnet_cs.c
- Orig date:
Thu May 11 15:30:07 2000
diff -u --recursive --new-file v2.4.0-test7/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c
@@ -9,9 +9,9 @@
Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory
mode. It will also handle the Socket EA card in either mode.
- Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+ Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
- pcnet_cs.c 1.117 2000/05/04 01:29:47
+ pcnet_cs.c 1.124 2000/07/21 19:47:31
The network driver code is based on Donald Becker's NE2000 code:
@@ -72,7 +72,7 @@
MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
-"pcnet_cs.c 1.117 2000/05/04 01:29:47 (David Hinds)";
+"pcnet_cs.c 1.124 2000/07/21 19:47:31 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -153,7 +153,8 @@
#define USE_BIG_BUF 0x04
#define HAS_IBM_MISC 0x08
#define IS_DL10019 0x10
-#define IS_AX88190 0x20
+#define IS_DL10022 0x20
+#define IS_AX88190 0x40
#define USE_SHMEM 0x80 /* autodetected */
static hw_info_t hw_info[] = {
@@ -219,10 +220,9 @@
#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
-static hw_info_t default_info =
-{ /* Unknown NE2000 Clone */ 0x00, 0x00, 0x00, 0x00, 0 };
-static hw_info_t dl10019_info =
-{ /* D-Link DL10019 chipset */ 0x00, 0x00, 0x00, 0x00, IS_DL10019 };
+static hw_info_t default_info = { 0, 0, 0, 0, 0 };
+static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019 };
+static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10019|IS_DL10022 };
typedef struct pcnet_dev_t {
struct net_device dev; /* so &dev == &pcnet_dev_t */
@@ -232,7 +232,7 @@
caddr_t base;
struct timer_list watchdog;
int stale, fast_poll;
- u_char link_status;
+ u_short link_status;
} pcnet_dev_t;
/*======================================================================
@@ -504,7 +504,8 @@
return NULL;
for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb_p(dev->base_addr + 0x14 + i);
- return &dl10019_info;
+ i = inb(dev->base_addr + 0x1f);
+ return ((i == 0x91)||(i == 0x99)) ? &dl10022_info : &dl10019_info;
}
/*======================================================================
@@ -723,14 +724,18 @@
hw_info = get_hwired(link);
if (hw_info == NULL) {
- printk(KERN_NOTICE "pcnet_cs: unable to read hardware net address\n");
- goto config_undo;
+ printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
+ " address for io base %#3lx\n", dev->base_addr);
+ unregister_netdev(dev);
+ goto failed;
}
info->flags = hw_info->flags;
/* Check for user overrides */
info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
- if ((manfid == MANFID_SOCKET) && (prodid == PRODID_SOCKET_LPE))
+ if ((manfid == MANFID_SOCKET) &&
+ ((prodid == PRODID_SOCKET_LPE) ||
+ (prodid == PRODID_SOCKET_EIO)))
info->flags &= ~USE_BIG_BUF;
if (!use_big_buf)
info->flags &= ~USE_BIG_BUF;
@@ -760,8 +765,9 @@
if (info->flags & IS_DL10019) {
dev->do_ioctl = &do_ioctl;
- printk(KERN_INFO "%s: NE2000 (DL10019 rev %02x): ",
- dev->name, inb(dev->base_addr + 0x1a));
+ printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
+ dev->name, ((info->flags & IS_DL10022) ? 22 : 19),
+ inb(dev->base_addr + 0x1a));
} else if (info->flags & IS_AX88190) {
printk(KERN_INFO "%s: NE2000 (AX88190): ", dev->name);
} else
@@ -776,9 +782,6 @@
printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
return;
-config_undo:
- unregister_netdev(dev);
- goto failed;
cs_failed:
cs_error(link->handle, last_fn, last_ret);
failed:
@@ -876,6 +879,79 @@
return 0;
} /* pcnet_event */
+/*======================================================================
+
+ MII interface support for DL10019 and DL10022 based cards
+
+ On the DL10019, the MII IO direction bit is 0x10; on the DL10022
+ it is 0x20. Setting both bits seems to work on both card types.
+
+======================================================================*/
+
+#define DLINK_GPIO 0x1c
+#define DLINK_DIAG 0x1d
+#define MDIO_SHIFT_CLK 0x80
+#define MDIO_DATA_OUT 0x40
+#define MDIO_DIR_WRITE 0x30
+#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)
+#define MDIO_DATA_READ 0x10
+#define MDIO_MASK 0x0f
+
+static void mdio_sync(ioaddr_t addr)
+{
+ int bits, mask = inb(addr) & MDIO_MASK;
+ for (bits = 0; bits < 32; bits++) {
+ outb(mask | MDIO_DATA_WRITE1, addr);
+ outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
+ }
+}
+
+static int mdio_read(ioaddr_t addr, int phy_id, int loc)
+{
+ u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
+ int i, retval = 0, mask = inb(addr) & MDIO_MASK;
+
+ mdio_sync(addr);
+ for (i = 13; i >= 0; i--) {
+ int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ outb(mask | dat, addr);
+ outb(mask | dat | MDIO_SHIFT_CLK, addr);
+ }
+ for (i = 19; i > 0; i--) {
+ outb(mask, addr);
+ retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
+ outb(mask | MDIO_SHIFT_CLK, addr);
+ }
+ return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
+{
+ u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
+ int i, mask = inb(addr) & MDIO_MASK;
+
+ mdio_sync(addr);
+ for (i = 31; i >= 0; i--) {
+ int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ outb(mask | dat, addr);
+ outb(mask | dat | MDIO_SHIFT_CLK, addr);
+ }
+ for (i = 1; i >= 0; i--) {
+ outb(mask, addr);
+ outb(mask | MDIO_SHIFT_CLK, addr);
+ }
+}
+
+static void mdio_reset(ioaddr_t addr, int phy_id)
+{
+ outb_p(0x08, addr);
+ outb_p(0x0c, addr);
+ outb_p(0x08, addr);
+ outb_p(0x0c, addr);
+ outb_p(0x00, addr);
+}
+
/*====================================================================*/
static void set_misc_reg(struct net_device *dev)
@@ -894,6 +970,12 @@
tmp |= 8;
outb_p(tmp, nic_base + PCNET_MISC);
}
+ if (info->flags & IS_DL10022) {
+ mdio_reset(nic_base + DLINK_GPIO, 0);
+ /* Restart MII autonegotiation */
+ mdio_write(nic_base + DLINK_GPIO, 0, 0, 0x0000);
+ mdio_write(nic_base + DLINK_GPIO, 0, 0, 0x1200);
+ }
}
/*====================================================================*/
@@ -914,8 +996,7 @@
set_misc_reg(dev);
request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
- /* Start by assuming the link is bad */
- info->link_status = 1;
+ info->link_status = 0x00;
info->watchdog.function = &ei_watchdog;
info->watchdog.data = (u_long)info;
info->watchdog.expires = jiffies + HZ;
@@ -1008,13 +1089,14 @@
pcnet_dev_t *info = (pcnet_dev_t *)(arg);
struct net_device *dev = &info->dev;
ioaddr_t nic_base = dev->base_addr;
+ u_short link;
if (!netif_device_present(dev)) goto reschedule;
/* Check for pending interrupt with expired latency timer: with
this, we can limp along even if the interrupt is blocked */
outb_p(E8390_NODMA+E8390_PAGE0, nic_base + E8390_CMD);
- if (info->stale++ && inb_p(nic_base + EN0_ISR)) {
+ if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
if (!info->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
ei_irq_wrapper(dev->irq, dev, NULL);
@@ -1027,15 +1109,30 @@
return;
}
- if (info->flags & IS_DL10019) {
- u_char link = inb(dev->base_addr+0x1c) & 0x01;
- if (link != info->link_status) {
- printk(KERN_INFO "%s: %s link beat\n", dev->name,
- (link) ? "lost" : "found");
- if (!link)
- NS8390_init(dev, 1);
- info->link_status = link;
+ if (!(info->flags & IS_DL10019))
+ goto reschedule;
+
+ link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1) & 0x0004;
+ if (link != info->link_status) {
+ u_short p = mdio_read(dev->base_addr + DLINK_GPIO, 0, 5);
+ printk(KERN_INFO "%s: %s link beat\n", dev->name,
+ (link) ? "found" : "lost");
+ if (link && (info->flags & IS_DL10022)) {
+ /* Disable collision detection on full duplex links */
+ outb((p & 0x0140) ? 4 : 0, dev->base_addr + DLINK_DIAG);
+ }
+ if (link) {
+ if (p)
+ printk(KERN_INFO "%s: autonegotiation complete: "
+ "%sbaseT-%cD selected\n", dev->name,
+ ((p & 0x0180) ? "100" : "10"),
+ ((p & 0x0140) ? 'F' : 'H'));
+ else
+ printk(KERN_INFO "%s: link partner did not autonegotiate\n",
+ dev->name);
+ NS8390_init(dev, 1);
}
+ info->link_status = link;
}
reschedule:
@@ -1043,83 +1140,22 @@
add_timer(&info->watchdog);
}
-/*======================================================================
-
- MII interface support for DL10019 based cards
-
- There are two types of DL10019 based cards. Some have the MII IO
- direction bit as 0x10, others as 0x20; setting both bits seems to
- work on all cards.
-
-======================================================================*/
-
-#define MDIO_SHIFT_CLK 0x80
-#define MDIO_DATA_OUT 0x40
-#define MDIO_DIR_WRITE 0x30
-#define MDIO_DATA_WRITE0 (MDIO_DIR_WRITE)
-#define MDIO_DATA_WRITE1 (MDIO_DIR_WRITE | MDIO_DATA_OUT)
-#define MDIO_DATA_READ 0x10
-#define MDIO_MASK 0x0f
-
-static void mdio_sync(ioaddr_t addr)
-{
- int bits, mask = inb(addr) & MDIO_MASK;
- for (bits = 0; bits < 32; bits++) {
- outb(mask | MDIO_DATA_WRITE1, addr);
- outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
- }
-}
-
-static int mdio_read(ioaddr_t addr, int phy_id, int loc)
-{
- u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
- int i, retval = 0, mask = inb(addr) & MDIO_MASK;
-
- mdio_sync(addr);
- for (i = 13; i >= 0; i--) {
- int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- outb(mask | dat, addr);
- outb(mask | dat | MDIO_SHIFT_CLK, addr);
- }
- for (i = 19; i > 0; i--) {
- outb(mask, addr);
- retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
- outb(mask | MDIO_SHIFT_CLK, addr);
- }
- return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
-{
- u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
- int i, mask = inb(addr) & MDIO_MASK;
-
- mdio_sync(addr);
- for (i = 31; i >= 0; i--) {
- int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
- outb(mask | dat, addr);
- outb(mask | dat | MDIO_SHIFT_CLK, addr);
- }
- for (i = 1; i >= 0; i--) {
- outb(mask, addr);
- outb(mask | MDIO_SHIFT_CLK, addr);
- }
-}
+/*====================================================================*/
static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
u16 *data = (u16 *)&rq->ifr_data;
- ioaddr_t addr = dev->base_addr + 0x1c;
+ ioaddr_t addr = dev->base_addr + DLINK_GPIO;
switch (cmd) {
case SIOCDEVPRIVATE:
data[0] = 0;
case SIOCDEVPRIVATE+1:
- data[3] = mdio_read(addr, 0, data[1] & 0x1f);
+ data[3] = mdio_read(addr, data[0], data[1] & 0x1f);
return 0;
case SIOCDEVPRIVATE+2:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- mdio_write(addr, 0, data[1] & 0x1f, data[2]);
+ mdio_write(addr, data[0], data[1] & 0x1f, data[2]);
return 0;
}
return -EOPNOTSUPP;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)