patch-2.4.13 linux/drivers/net/sundance.c
Next file: linux/drivers/net/sungem.c
Previous file: linux/drivers/net/sunbmac.c
Back to the patch index
Back to the overall index
- Lines: 311
- Date:
Fri Oct 19 08:32:28 2001
- Orig file:
v2.4.12/linux/drivers/net/sundance.c
- Orig date:
Tue Oct 9 17:06:52 2001
diff -u --recursive --new-file v2.4.12/linux/drivers/net/sundance.c linux/drivers/net/sundance.c
@@ -25,10 +25,9 @@
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
-
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 30;
static int mtu;
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
Typical is a 64 element hash table based on the Ethernet CRC. */
@@ -40,15 +39,20 @@
need a copy-align. */
static int rx_copybreak;
-/* Used to pass the media type, etc.
- Both 'options[]' and 'full_duplex[]' should exist for driver
- interoperability.
- The media type is usually passed in 'options[]'.
+/* media[] specifies the media type the NIC operates at.
+ autosense Autosensing active media.
+ 10mbps_hd 10Mbps half duplex.
+ 10mbps_fd 10Mbps full duplex.
+ 100mbps_hd 100Mbps half duplex.
+ 100mbps_fd 100Mbps full duplex.
+ 0 Autosensing active media.
+ 1 10Mbps half duplex.
+ 2 10Mbps full duplex.
+ 3 100Mbps half duplex.
+ 4 100Mbps full duplex.
*/
-#define MAX_UNITS 8 /* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
+#define MAX_UNITS 8
+static char *media[MAX_UNITS];
/* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for compile efficiency.
@@ -65,7 +69,7 @@
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (2*HZ)
+#define TX_TIMEOUT (4*HZ)
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
@@ -98,7 +102,7 @@
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
-
+#include <linux/delay.h>
#include <linux/spinlock.h>
/* These identify the driver base version and may not be removed. */
@@ -114,15 +118,11 @@
MODULE_PARM(mtu, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt");
MODULE_PARM_DESC(mtu, "Sundance Alta MTU (all boards)");
MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options, "Sundance Alta: Bits 0-3: media type, bit 17: full duplex");
-MODULE_PARM_DESC(full_duplex, "Sundance Alta full duplex setting(s) (1)");
-
/*
Theory of Operation
@@ -214,9 +214,12 @@
#endif
static struct pci_device_id sundance_pci_tbl[] __devinitdata = {
- { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { 0, }
+ {0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
+ {0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
+ {0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
+ {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ {0,}
};
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
@@ -231,11 +234,19 @@
int drv_flags; /* Driver use, intended as capability flags. */
};
static struct pci_id_info pci_id_tbl[] = {
- {"OEM Sundance Technology ST201", {0x10021186, 0xffffffff, },
+ {"D-Link DFE-550TX FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
PCI_IOTYPE, 128, CanHaveMII},
- {"Sundance Technology Alta", {0x020113F0, 0xffffffff, },
+ {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter",
+ {0x10031186, 0xffffffff,},
PCI_IOTYPE, 128, CanHaveMII},
- {0,}, /* 0 terminated list. */
+ {"D-Link DFE-580TX 4 port Server Adapter", {0x10121186, 0xffffffff,},
+ PCI_IOTYPE, 128, CanHaveMII},
+ {"D-Link DL10050-based FAST Ethernet Adapter",
+ {0x10021186, 0xffffffff,},
+ PCI_IOTYPE, 128, CanHaveMII},
+ {"Sundance Technology Alta", {0x020113F0, 0xffffffff,},
+ PCI_IOTYPE, 128, CanHaveMII},
+ {0,}, /* 0 terminated list. */
};
/* This driver was written to use PCI memory space, however x86-oriented
@@ -384,9 +395,10 @@
unsigned int tx_full:1; /* The Tx queue is full. */
/* These values are keep track of the transceiver/media in use. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int duplex_lock:1;
unsigned int medialock:1; /* Do not sense media. */
unsigned int default_port:4; /* Last dev->if_port value. */
+ unsigned int an_enable:1;
+ unsigned int speed;
/* Multicast and receive mode. */
spinlock_t mcastlock; /* SMP lock multicast updates. */
u16 mcast_filter[4];
@@ -428,8 +440,9 @@
static int card_idx;
int chip_idx = ent->driver_data;
int irq;
- int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+ int i;
long ioaddr;
+ u16 mii_reg0;
void *ring_space;
dma_addr_t ring_dma;
@@ -489,23 +502,6 @@
np->rx_ring = (struct netdev_desc *)ring_space;
np->rx_ring_dma = ring_dma;
- if (dev->mem_start)
- option = dev->mem_start;
-
- /* The lower four bits are the media type. */
- if (option > 0) {
- if (option & 0x200)
- np->full_duplex = 1;
- np->default_port = option & 15;
- if (np->default_port)
- np->medialock = 1;
- }
- if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
- np->full_duplex = 1;
-
- if (np->full_duplex)
- np->duplex_lock = 1;
-
/* The chip-specific entries in the device structure. */
dev->open = &netdev_open;
dev->hard_start_xmit = &start_tx;
@@ -548,6 +544,56 @@
printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n",
dev->name, readl(ioaddr + ASICCtrl));
}
+ /* Parse override configuration */
+ np->an_enable = 1;
+ if (card_idx < MAX_UNITS) {
+ if (media[card_idx] != NULL) {
+ np->an_enable = 0;
+ if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+ strcmp (media[card_idx], "4") == 0) {
+ np->speed = 100;
+ np->full_duplex = 1;
+ } else if (strcmp (media[card_idx], "100mbps_hd") == 0
+ || strcmp (media[card_idx], "3") == 0) {
+ np->speed = 100;
+ np->full_duplex = 0;
+ } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+ strcmp (media[card_idx], "2") == 0) {
+ np->speed = 10;
+ np->full_duplex = 1;
+ } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+ strcmp (media[card_idx], "1") == 0) {
+ np->speed = 10;
+ np->full_duplex = 0;
+ } else {
+ np->an_enable = 1;
+ }
+ }
+ }
+
+ /* Fibre PHY? */
+ if (readl (ioaddr + ASICCtrl) & 0x80) {
+ /* Default 100Mbps Full */
+ if (np->an_enable) {
+ np->speed = 100;
+ np->full_duplex = 1;
+ np->an_enable = 0;
+ }
+ }
+ /* Reset PHY */
+ mdio_write (dev, np->phys[0], 0, 0x8000);
+ mdelay (300);
+ mdio_write (dev, np->phys[0], 0, 0x1200);
+ /* Force media type */
+ if (!np->an_enable) {
+ mii_reg0 = 0;
+ mii_reg0 |= (np->speed == 100) ? 0x2000 : 0;
+ mii_reg0 |= (np->full_duplex) ? 0x0100 : 0;
+ mdio_write (dev, np->phys[0], 0, mii_reg0);
+ printk (KERN_INFO "Override speed=%d, %s duplex\n",
+ np->speed, np->full_duplex ? "Full" : "Half");
+
+ }
/* Perhaps move the reset here? */
/* Reset the chip to erase previous misconfiguration. */
@@ -714,7 +760,6 @@
if (dev->if_port == 0)
dev->if_port = np->default_port;
- np->full_duplex = np->duplex_lock;
np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED;
set_rx_mode(dev);
@@ -755,9 +800,15 @@
int mii_reg5 = mdio_read(dev, np->phys[0], 5);
int negotiated = mii_reg5 & np->advertising;
int duplex;
-
- if (np->duplex_lock || mii_reg5 == 0xffff)
+
+ /* Force media */
+ if (!np->an_enable || mii_reg5 == 0xffff) {
+ if (np->full_duplex)
+ writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex,
+ ioaddr + MACCtrl0);
return;
+ }
+ /* Autonegotiation */
duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
if (np->full_duplex != duplex) {
np->full_duplex = duplex;
@@ -1003,10 +1054,10 @@
/* Abnormal error summary/uncommon events handlers. */
if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax))
netdev_error(dev, intr_status);
-
if (--boguscnt < 0) {
get_stats(dev);
- printk(KERN_WARNING "%s: Too much work at interrupt, "
+ if (debug > 1)
+ printk(KERN_WARNING "%s: Too much work at interrupt, "
"status=0x%4.4x / 0x%4.4x.\n",
dev->name, intr_status, readw(ioaddr + IntrClear));
/* Re-enable us in 3.2msec. */
@@ -1132,21 +1183,46 @@
{
long ioaddr = dev->base_addr;
struct netdev_private *np = dev->priv;
+ u16 mii_reg0, mii_reg4, mii_reg5;
+ int speed;
if (intr_status & IntrDrvRqst) {
/* Stop the down counter and turn interrupts back on. */
- printk("%s: Turning interrupts back on.\n", dev->name);
+ if (debug > 1)
+ printk("%s: Turning interrupts back on.\n", dev->name);
writew(0, ioaddr + IntrEnable);
writew(0, ioaddr + DownCounter);
writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst |
IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable);
+ /* Ack buggy InRequest */
+ writew (IntrDrvRqst, ioaddr + IntrStatus);
}
if (intr_status & LinkChange) {
- printk(KERN_ERR "%s: Link changed: Autonegotiation advertising"
- " %4.4x partner %4.4x.\n", dev->name,
- mdio_read(dev, np->phys[0], 4),
- mdio_read(dev, np->phys[0], 5));
- check_duplex(dev);
+ if (np->an_enable) {
+ mii_reg4 = mdio_read (dev, np->phys[0], 4);
+ mii_reg5= mdio_read (dev, np->phys[0], 5);
+ mii_reg4 &= mii_reg5;
+ printk (KERN_INFO "%s: Link changed: ", dev->name);
+ if (mii_reg4 & 0x0100)
+ printk ("100Mbps, full duplex\n");
+ else if (mii_reg4 & 0x0080)
+ printk ("100Mbps, half duplex\n");
+ else if (mii_reg4 & 0x0040)
+ printk ("10Mbps, full duplex\n");
+ else if (mii_reg4 & 0x0020)
+ printk ("10Mbps, half duplex\n");
+ else
+ printk ("\n");
+
+ } else {
+ mii_reg0 = mdio_read (dev, np->phys[0], 0);
+ speed = (mii_reg0 & 0x2000) ? 100 : 10;
+ printk (KERN_INFO "%s: Link changed: %dMbps ,",
+ dev->name, speed);
+ printk ("%s duplex.\n", (mii_reg0 & 0x0100) ?
+ "full" : "half");
+ }
+ check_duplex (dev);
}
if (intr_status & StatsMax) {
get_stats(dev);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)