patch-2.0.36 linux/drivers/net/tulip.c
Next file: linux/drivers/net/via-rhine.c
Previous file: linux/drivers/net/tlan.c
Back to the patch index
Back to the overall index
- Lines: 1049
- Date:
Sun Nov 15 10:33:04 1998
- Orig file:
v2.0.35/linux/drivers/net/tulip.c
- Orig date:
Mon Jul 13 13:46:30 1998
diff -u --recursive --new-file v2.0.35/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
@@ -1,12 +1,13 @@
-/* tulip.c: A DEC 21040-family ethernet driver for linux. */
+/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
/*
Written 1994-1998 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
- This driver is for the SMC EtherPower PCI ethernet adapter.
- It should work with most other DEC 21*40-based ethercards.
+ This driver is for the Digital "Tulip" ethernet adapter interface.
+ It should work with most DEC 21*4*-based chips/ethercards, as well as
+ PNIC and MXIC chips.
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
@@ -17,7 +18,7 @@
*/
#define SMP_CHECK
-static const char version[] = "tulip.c:v0.88 4/7/98 becker@cesdis.gsfc.nasa.gov\n";
+static const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
/* A few user-configurable values. */
@@ -30,6 +31,14 @@
static int options[MAX_UNITS] = {0, };
static int mtu[MAX_UNITS] = {0, }; /* Jumbo MTU for interfaces. */
+/* The possible media types that can be set in options[] are: */
+static const char * const medianame[] = {
+ "10baseT", "10base2", "AUI", "100baseTx",
+ "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+ "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+ "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
+
/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
#ifdef REVERSE_PROBE_ORDER
static int reverse_probe = 1;
@@ -51,18 +60,9 @@
static int rx_copybreak = 100;
#endif
-/* The following example shows how to always use the 10base2 port. */
-#ifdef notdef
-#define TULIP_DEFAULT_MEDIA 1 /* 1 == 10base2 */
-#define TULIP_NO_MEDIA_SWITCH /* Don't switch from this port */
-#endif
-
-/* Define to force full-duplex operation on all Tulip interfaces. */
-/* #define TULIP_FULL_DUPLEX 1 */
-
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT ((2000*HZ)/1000)
+#define TX_TIMEOUT (4*HZ)
#include <linux/config.h>
#ifdef MODULE
@@ -272,8 +272,6 @@
#ifndef PCI_VENDOR_ID_LITEON
#define PCI_VENDOR_ID_LITEON 0x11AD
#endif
-#define PCI_DEVICE_ID_PNIC 0x0002
-#define PCI_DEVICE_ID_PNIC_X 0x0168
#ifndef PCI_VENDOR_ID_MXIC
#define PCI_VENDOR_ID_MXIC 0x10d9
@@ -290,44 +288,44 @@
static void pnic_timer(unsigned long data);
/* A table describing the chip types. */
-enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2};
+enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2, CSR12_IN_SROM = 4,};
static struct tulip_chip_table {
- int device_id;
+ int vendor_id, device_id;
char *chip_name;
int io_size;
int valid_intrs; /* CSR7 interrupt enable settings */
int flags;
void (*media_timer)(unsigned long data);
} tulip_tbl[] = {
- { PCI_DEVICE_ID_DEC_TULIP, "Digital DC21040 Tulip", 128, 0x0001ebef,
- 0, tulip_timer },
- { PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DC21041 Tulip", 128, 0x0001ebef,
- HAS_MEDIA_TABLE, tulip_timer },
- { PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE, tulip_timer },
- { PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", 256, 0x0801fbff,
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
+ "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
+ "Digital DC21041 Tulip", 128, 0x0001ebef, HAS_MEDIA_TABLE, tulip_timer },
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST,
+ "Digital DS21140 Tulip", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM,
+ tulip_timer },
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_21142,
+ "Digital DS21142/3 Tulip", 256, 0x0801fbff,
HAS_MII | HAS_MEDIA_TABLE, t21142_timer },
- { PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 256, 0x0001ebef,
- 0, pnic_timer },
- { PCI_DEVICE_ID_MX98713, "Macronix 98713 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE, tulip_timer /* Tulip-like! */ },
- { PCI_DEVICE_ID_MX98715, "Macronix 98715 PMAC", 256, 0x0001ebef,
- HAS_MEDIA_TABLE, mxic_timer },
- { PCI_DEVICE_ID_MX98725, "Macronix 98725 PMAC", 256, 0x0001ebef,
- HAS_MEDIA_TABLE, mxic_timer },
+ { PCI_VENDOR_ID_LITEON, 0x0002,
+ "Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII, pnic_timer },
+ { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98713,
+ "Macronix 98713 PMAC", 128, 0x0001ebef,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer /* Tulip-like! */ },
+ { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98715,
+ "Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
+ { PCI_VENDOR_ID_MXIC, PCI_DEVICE_ID_MX98725,
+ "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer },
+ { 0x125B, 0x1400, "ASIX AX88140", 128, 0x0001fbff,
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
{0, 0, 0, 0},
};
/* This matches the table above. */
enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
LC82C168, MX98713, MX98715, MX98725};
-static const char * const medianame[] = {
- "10baseT", "10base2", "AUI", "100baseTx",
- "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
- "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
- "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
-};
-/* A full-duplex map for above. */
+/* A full-duplex map for media types. */
enum MediaIs {MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
MediaIs100=16};
static const char media_cap[] =
@@ -378,7 +376,7 @@
struct mediatable {
u16 defaultmedia;
u8 leafcount, csr12dir; /* General purpose pin directions. */
- unsigned has_mii:1;
+ unsigned has_mii:1, has_nonmii:1;
struct medialeaf mleaf[0];
};
@@ -418,6 +416,7 @@
unsigned int tx_full:1; /* The Tx queue is full. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
unsigned int full_duplex_lock:1;
+ unsigned int fake_addr:1; /* Multiport board faked address. */
unsigned int default_port:4; /* Last dev->if_port value. */
unsigned int media2:4; /* Secondary monitored media port. */
unsigned int medialock:1; /* Don't sense media type. */
@@ -434,12 +433,12 @@
};
static struct device *tulip_probe1(int pci_bus, int pci_devfn,
- struct device *dev, int ioaddr,
+ struct device *dev,
int chip_id, int options);
static void parse_eeprom(struct device *dev);
-static int read_eeprom(int ioaddr, int location);
-static int mdio_read(int ioaddr, int phy_id, int location);
-static void mdio_write(int ioaddr, int phy_id, int location, int value);
+static int read_eeprom(long ioaddr, int location);
+static int mdio_read(struct device *dev, int phy_id, int location);
+static void mdio_write(struct device *dev, int phy_id, int location, int value);
static void select_media(struct device *dev, int startup);
static int tulip_open(struct device *dev);
static void tulip_timer(unsigned long data);
@@ -474,98 +473,100 @@
{
int cards_found = 0;
static int pci_index = 0; /* Static, for multiple probe calls. */
+ unsigned char pci_bus, pci_device_fn;
/* Ideally we would detect all network cards in slot order. That would
be best done a central PCI probe dispatch, which wouldn't work
well with the current structure. So instead we detect just the
Tulip cards in slot order. */
- if (pcibios_present()) {
- unsigned char pci_bus, pci_device_fn;
-
- for (;pci_index < 0xff; pci_index++) {
- u16 vendor, device, pci_command, new_command;
- u32 pci_ioaddr;
- int chip_idx = 0;
-
- if (pcibios_find_class
- (PCI_CLASS_NETWORK_ETHERNET << 8,
- reverse_probe ? 0xfe - pci_index : pci_index,
- &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
- if (reverse_probe)
- continue;
- else
- break;
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_VENDOR_ID, &vendor);
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_DEVICE_ID, &device);
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_ioaddr);
- /* Remove I/O space marker in bit 0. */
- pci_ioaddr &= ~3;
-
- if (vendor != PCI_VENDOR_ID_DEC
- && vendor != PCI_VENDOR_ID_LITEON
- && vendor != PCI_VENDOR_ID_MXIC)
+#if LINUX_VERSION_CODE >= 0x20155
+ if (! pci_present())
+ return -ENODEV;
+#else
+ if (! pcibios_present())
+ return -ENODEV;
+#endif
+ for (;pci_index < 0xff; pci_index++) {
+ u16 vendor, device, pci_command, new_command;
+ u32 pci_ioaddr;
+ int chip_idx = 0;
+
+ if (pcibios_find_class
+ (PCI_CLASS_NETWORK_ETHERNET << 8,
+ reverse_probe ? 0xfe - pci_index : pci_index,
+ &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+ if (reverse_probe)
continue;
- if (vendor == PCI_VENDOR_ID_LITEON)
- device = PCI_DEVICE_ID_PNIC_X;
- else if (vendor == PCI_VENDOR_ID_MXIC)
- device = PCI_DEVICE_ID_MX98713;
-
- for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
- if (device == tulip_tbl[chip_idx].device_id)
- break;
- if (tulip_tbl[chip_idx].chip_name == 0) {
+ else
+ break;
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_VENDOR_ID, &vendor);
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_DEVICE_ID, &device);
+
+ for (chip_idx = 0; tulip_tbl[chip_idx].chip_name; chip_idx++)
+ if (vendor == tulip_tbl[chip_idx].vendor_id &&
+ device == tulip_tbl[chip_idx].device_id)
+ break;
+ if (tulip_tbl[chip_idx].chip_name == 0) {
+ if (vendor == PCI_VENDOR_ID_DEC ||
+ vendor == PCI_VENDOR_ID_LITEON)
printk(KERN_INFO "Unknown Tulip-style PCI ethernet chip type"
" %4.4x %4.4x"" detected: not configured.\n",
vendor, device);
- continue;
- }
- if (tulip_debug > 2)
- printk(KERN_DEBUG "Found %s at I/O %#x.\n",
- tulip_tbl[chip_idx].chip_name, pci_ioaddr);
+ continue;
+ }
+#if LINUX_VERSION_CODE >= 0x20155
+ pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
+#else
+ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
+ &pci_ioaddr);
+#endif
+ /* Remove I/O space marker in bit 0. */
+ pci_ioaddr &= ~3;
- if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
- continue;
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "Found %s at I/O %#x.\n",
+ tulip_tbl[chip_idx].chip_name, pci_ioaddr);
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
- if (pci_command != new_command) {
- printk(KERN_INFO " The PCI BIOS has not enabled this"
- " device! Updating PCI command %4.4x->%4.4x.\n",
- pci_command, new_command);
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, new_command);
- }
-
- dev = tulip_probe1(pci_bus, pci_device_fn, dev,
- pci_ioaddr, chip_idx, cards_found);
-
- /* Get and check the bus-master and latency values. */
- if (dev) {
- unsigned char pci_latency;
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < 10) {
- printk(KERN_INFO " PCI latency timer (CFLT) is "
- "unreasonably low at %d. Setting to 64 clocks.\n",
- pci_latency);
- pcibios_write_config_byte(pci_bus, pci_device_fn,
- PCI_LATENCY_TIMER, 64);
- } else if (tulip_debug > 1)
- printk(KERN_INFO " PCI latency timer (CFLT) is %#x, "
- " PCI command is %4.4x.\n",
- pci_latency, new_command);
- /* Bring the 21143 out power-down mode. */
- if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- 0x40, 0x40000000);
- dev = 0;
- cards_found++;
- }
+ if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
+ continue;
+
+ pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, &pci_command);
+ new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+ if (pci_command != new_command) {
+ printk(KERN_INFO " The PCI BIOS has not enabled this"
+ " device! Updating PCI command %4.4x->%4.4x.\n",
+ pci_command, new_command);
+ pcibios_write_config_word(pci_bus, pci_device_fn,
+ PCI_COMMAND, new_command);
+ }
+
+ dev = tulip_probe1(pci_bus, pci_device_fn, dev, chip_idx, cards_found);
+
+ /* Get and check the bus-master and latency values. */
+ if (dev) {
+ unsigned char pci_latency;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency < 10) {
+ printk(KERN_INFO " PCI latency timer (CFLT) is "
+ "unreasonably low at %d. Setting to 64 clocks.\n",
+ pci_latency);
+ pcibios_write_config_byte(pci_bus, pci_device_fn,
+ PCI_LATENCY_TIMER, 64);
+ } else if (tulip_debug > 1)
+ printk(KERN_INFO " PCI latency timer (CFLT) is %#x, "
+ " PCI command is %4.4x.\n",
+ pci_latency, new_command);
+ /* Bring the 21143 out power-down mode. */
+ if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ 0x40, 0x40000000);
+ dev = 0;
+ cards_found++;
}
}
@@ -573,15 +574,17 @@
}
static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
- struct device *dev, int ioaddr,
+ struct device *dev,
int chip_id, int board_idx)
{
static int did_version = 0; /* Already printed version info. */
struct tulip_private *tp;
+ long ioaddr;
+ int irq;
/* See note below on the multiport cards. */
static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
static int last_irq = 0;
- u8 pci_irq_line;
+ static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
int i;
unsigned short sum;
@@ -590,9 +593,25 @@
dev = init_etherdev(dev, 0);
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
- printk(KERN_INFO "%s: %s at %#3x,",
+#if LINUX_VERSION_CODE >= 0x20155
+ irq = pci_find_slot(pci_bus, pci_device_fn)->irq;
+ ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
+#else
+ {
+ u8 pci_irq_line;
+ u32 pci_ioaddr;
+ pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &pci_irq_line);
+ pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0,
+ &pci_ioaddr);
+ irq = pci_irq_line;
+ ioaddr = pci_ioaddr;
+ }
+#endif
+ /* Remove I/O space marker in bit 0. */
+ ioaddr &= ~3;
+
+ printk(KERN_INFO "%s: %s at %#3lx,",
dev->name, tulip_tbl[chip_id].chip_name, ioaddr);
/* Stop the chip's Tx and Rx processes. */
@@ -649,6 +668,10 @@
for (i = 0; i < 8; i ++)
if (ee_data[i] != ee_data[16+i])
sa_offset = 20;
+ if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) {
+ sa_offset = 2; /* Grrr, damn Matrox boards. */
+ multiport_cnt = 4;
+ }
for (i = 0; i < 6; i ++) {
dev->dev_addr[i] = ee_data[i + sa_offset];
sum += ee_data[i + sa_offset];
@@ -672,20 +695,21 @@
dev->dev_addr[i] = last_phys_addr[i];
dev->dev_addr[i] = last_phys_addr[i] + 1;
#if defined(__i386__) /* This BIOS bug doesn't exist on Alphas. */
- pci_irq_line = last_irq;
+ irq = last_irq;
#endif
}
+
for (i = 0; i < 6; i++)
printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]);
- printk(", IRQ %d.\n", pci_irq_line);
- last_irq = pci_irq_line;
+ printk(", IRQ %d.\n", irq);
+ last_irq = irq;
/* We do a request_region() only to register /proc/ioports info. */
/* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
- request_region(ioaddr, TULIP_TOTAL_SIZE, tulip_tbl[chip_id].chip_name);
+ request_region(ioaddr, TULIP_TOTAL_SIZE, dev->name);
dev->base_addr = ioaddr;
- dev->irq = pci_irq_line;
+ dev->irq = irq;
/* Make certain the data structures are quadword aligned. */
tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7);
@@ -746,9 +770,9 @@
but takes much time. */
for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
phy++) {
- int mii_status = mdio_read(ioaddr, phy, 1);
+ int mii_status = mdio_read(dev, phy, 1);
if (mii_status != 0xffff && mii_status != 0x0000) {
- int mii_reg0 = mdio_read(ioaddr, phy, 0);
+ int mii_reg0 = mdio_read(dev, phy, 0);
int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
tp->phys[phy_idx] = phy;
tp->advertising[phy_idx++] = reg4;
@@ -758,11 +782,11 @@
if (1 || (media_cap[tp->default_port] & MediaIsMII)) {
printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d,"
" previously advertising %4.4x.\n",
- dev->name, reg4, phy, mdio_read(ioaddr, phy, 4));
- mdio_write(ioaddr, phy, 4, reg4);
+ dev->name, reg4, phy, mdio_read(dev, phy, 4));
+ mdio_write(dev, phy, 4, reg4);
}
/* Enable autonegotiation: some boards default to off. */
- mdio_write(ioaddr, phy, 0, mii_reg0 |
+ mdio_write(dev, phy, 0, mii_reg0 |
(tp->full_duplex ? 0x1100 : 0x1000) |
(media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
}
@@ -813,10 +837,12 @@
outl(0x1301, ioaddr + CSR12); /* Start NWay. */
break;
case LC82C168:
- outl(0x00420000, ioaddr + CSR6);
- outl(0x30, ioaddr + CSR12);
- outl(0x0001F078, ioaddr + 0xB8);
- outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+ if ( ! tp->mii_cnt) {
+ outl(0x00420000, ioaddr + CSR6);
+ outl(0x30, ioaddr + CSR12);
+ outl(0x0001F078, ioaddr + 0xB8);
+ outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+ }
break;
case MX98713: case MX98715: case MX98725:
outl(0x00000000, ioaddr + CSR6);
@@ -846,7 +872,9 @@
{"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x021f,
0x0000, 0x009E, /* 10baseT */
0x0903, 0x006D, /* 100baseTx */ }},
- {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x013f,
+ {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x033f,
+ 0x0107, 0x8021, /* 100baseFx */
+ 0x0108, 0x8021, /* 100baseFx-FD */
0x0103, 0x006D, /* 100baseTx */ }},
{"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0313,
0x1001, 0x009E, /* 10base2, CSR12 0x10*/
@@ -876,7 +904,7 @@
static unsigned char *last_ee_data = NULL;
static int controller_index = 0;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
unsigned char *ee_data = tp->eeprom;
int i;
@@ -956,8 +984,9 @@
for (i = 0; i < count; i++) {
unsigned char media_code = *p++;
u16 csrvals[3];
- for (i = 0; i < 3; i++) {
- csrvals[i] = get_u16(p);
+ int idx;
+ for (idx = 0; idx < 3; idx++) {
+ csrvals[idx] = get_u16(p);
p += 2;
}
if (media_code & 0x40) {
@@ -977,7 +1006,7 @@
u16 media = get_u16(p);
p += 2;
- if (tp->chip_id == DC21140 || tp->chip_id == MX98713)
+ if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)
csr12dir = *p++;
count = *p++;
mtable = (struct mediatable *)
@@ -989,7 +1018,7 @@
mtable->defaultmedia = media;
mtable->leafcount = count;
mtable->csr12dir = csr12dir;
- mtable->has_mii = 0;
+ mtable->has_nonmii = mtable->has_mii = 0;
printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name,
media & 0x0800 ? "Autosense" : medianame[media & 15]);
@@ -1008,8 +1037,10 @@
if (p[1] & 1) {
mtable->has_mii = 1;
leaf->media = 11;
- } else
+ } else {
+ mtable->has_nonmii = 1;
leaf->media = p[2] & 0x0f;
+ }
leaf->leafdata = p + 2;
p += (p[0] & 0x3f) + 1;
}
@@ -1052,11 +1083,11 @@
#define EE_READ_CMD (6 << 6)
#define EE_ERASE_CMD (7 << 6)
-static int read_eeprom(int ioaddr, int location)
+static int read_eeprom(long ioaddr, int location)
{
int i;
unsigned short retval = 0;
- int ee_addr = ioaddr + CSR9;
+ long ee_addr = ioaddr + CSR9;
int read_cmd = location | EE_READ_CMD;
outl(EE_ENB & ~EE_CS, ee_addr);
@@ -1107,12 +1138,23 @@
#define MDIO_ENB_IN 0x40000
#define MDIO_DATA_READ 0x80000
-static int mdio_read(int ioaddr, int phy_id, int location)
+static int mdio_read(struct device *dev, int phy_id, int location)
{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
int i;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
int retval = 0;
- int mdio_addr = ioaddr + CSR9;
+ long mdio_addr = dev->base_addr + CSR9;
+
+ if (tp->chip_id == LC82C168) {
+ long ioaddr = dev->base_addr;
+ int i = 1000;
+ outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+ while (--i > 0)
+ if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+ return retval & 0xffff;
+ return 0xffff;
+ }
/* Establish sync by sending at least 32 logic ones. */
for (i = 32; i >= 0; i--) {
@@ -1141,11 +1183,23 @@
return (retval>>1) & 0xffff;
}
-static void mdio_write(int ioaddr, int phy_id, int location, int value)
+static void mdio_write(struct device *dev, int phy_id, int location, int value)
{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
int i;
int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
- int mdio_addr = ioaddr + CSR9;
+ long mdio_addr = dev->base_addr + CSR9;
+
+ if (tp->chip_id == LC82C168) {
+ long ioaddr = dev->base_addr;
+ int i = 1000;
+ outl(cmd, ioaddr + 0xA0);
+ do
+ if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
+ break;
+ while (--i > 0);
+ return;
+ }
/* Establish sync by sending 32 logic ones. */
for (i = 32; i >= 0; i--) {
@@ -1177,7 +1231,7 @@
tulip_open(struct device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int i = 0;
/* On some chip revs we must set the MII/SYM port before the reset!? */
@@ -1286,11 +1340,11 @@
int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 :
(dev->if_port == 12 ? 0 : dev->if_port);
for (i = 0; i < tp->mtable->leafcount; i++)
- if (tp->mtable->mleaf[i].media == looking_for) {
- printk(KERN_INFO "%s: Using user-specified media %s.\n",
- dev->name, medianame[dev->if_port]);
- goto media_picked;
- }
+ if (tp->mtable->mleaf[i].media == looking_for) {
+ printk(KERN_INFO "%s: Using user-specified media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ goto media_picked;
+ }
}
if ((tp->mtable->defaultmedia & 0x0800) == 0)
for (i = 0; i < tp->mtable->leafcount; i++)
@@ -1313,6 +1367,10 @@
outl(0x0008, ioaddr + CSR15);
outl(0x0001, ioaddr + CSR13);
outl(0x1301, ioaddr + CSR12);
+ } else if (tp->chip_id == LC82C168 && tp->mii_cnt && ! tp->medialock) {
+ dev->if_port = 11;
+ tp->csr6 = 0x816C0000 | (tp->full_duplex ? 0x0200 : 0);
+ outl(0x0001, ioaddr + CSR15);
} else
select_media(dev, 1);
@@ -1325,14 +1383,15 @@
dev->start = 1;
/* Enable interrupts by setting the interrupt mask. */
+ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
outl(tp->csr6 | 0x2002, ioaddr + CSR6);
outl(0, ioaddr + CSR2); /* Rx poll demand */
if (tulip_debug > 2) {
- printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR13 %8.8x.\n",
+ printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
- inl(ioaddr + CSR13));
+ inl(ioaddr + CSR6));
}
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */
@@ -1348,7 +1407,7 @@
/* Set up the transceiver control registers for the selected media type. */
static void select_media(struct device *dev, int startup)
{
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
struct mediatable *mtable = tp->mtable;
u32 new_csr6;
@@ -1441,7 +1500,7 @@
printk(KERN_DEBUG "%s: Advertising %4.4x on PHY %d (%d).\n",
dev->name, to_advertise, phy_num, tp->phys[phy_num]);
/* Bogus: put in by a committee? */
- mdio_write(ioaddr, tp->phys[phy_num], 4, to_advertise);
+ mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
break;
}
default:
@@ -1462,14 +1521,18 @@
outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
new_csr6 = 0x80020000;
} else if (tp->chip_id == LC82C168) {
- if (startup)
- dev->if_port = 0;
+ if (startup && ! tp->medialock)
+ dev->if_port = tp->mii_cnt ? 11 : 0;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: LiteOn PHY status is %3.3x, CSR12 %4.4x,"
+ printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, CSR12 %4.4x,"
" media %s.\n",
dev->name, inl(ioaddr + 0xB8), inl(ioaddr + CSR12),
medianame[dev->if_port]);
- if (startup) {
+ if (tp->mii_cnt) {
+ new_csr6 = 0x812C0000;
+ outl(0x0001, ioaddr + CSR15);
+ outl(0x0201B07A, ioaddr + 0xB8);
+ } else if (startup) {
/* Start with 10mbps to do autonegotiation. */
outl(0x32, ioaddr + CSR12);
new_csr6 = 0x00420000;
@@ -1525,7 +1588,7 @@
{
struct device *dev = (struct device *)data;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
u32 csr12 = inl(ioaddr + CSR12);
int next_tick = 0;
@@ -1661,22 +1724,22 @@
case 1: case 3: { /* 21140, 21142 MII */
int mii_reg1, mii_reg5;
actually_mii:
- mii_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
- mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
+ mii_reg1 = mdio_read(dev, tp->phys[0], 1);
+ mii_reg5 = mdio_read(dev, tp->phys[0], 5);
if (tulip_debug > 1)
printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
"%4.4x, CSR12 %2.2x, %cD.\n",
dev->name, mii_reg1, mii_reg5, csr12,
tp->full_duplex ? 'F' : 'H');
if (mii_reg1 != 0xffff && (mii_reg1 & 0x0004) == 0) {
- int new_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
- if ((new_reg1 & 0x0004) == 0)
+ int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+ if ((new_reg1 & 0x0004) == 0) {
printk(KERN_INFO "%s: No link beat on the MII interface,"
" status then %4.4x now %4.4x.\n",
dev->name, mii_reg1, new_reg1);
-#ifdef notyet
- goto select_next_media;
-#endif
+ if (tp->mtable && tp->mtable->has_nonmii)
+ goto select_next_media;
+ }
}
if (mii_reg5 == 0xffff || mii_reg5 == 0x0000)
; /* No MII device or no link partner report */
@@ -1724,7 +1787,7 @@
{
struct device *dev = (struct device *)data;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int csr12 = inl(ioaddr + CSR12);
int next_tick = 60*HZ;
int new_csr6 = 0;
@@ -1788,7 +1851,7 @@
static void t21142_lnk_change( struct device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int csr12 = inl(ioaddr + CSR12);
if (tulip_debug > 1)
@@ -1839,7 +1902,7 @@
{
struct device *dev = (struct device *)data;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int next_tick = 60*HZ;
if (tulip_debug > 3) {
@@ -1856,50 +1919,82 @@
{
struct device *dev = (struct device *)data;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int csr12 = inl(ioaddr + CSR12);
- int phy_reg = inl(ioaddr + 0xB8);
int next_tick = 60*HZ;
- int duplex;
+ int new_csr6 = tp->csr6 & ~0x40C40200;
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
- dev->name, phy_reg, inl(ioaddr + CSR5));
- if (tp->full_duplex_lock)
- return; /* Do not bother to set timer. */
- duplex = phy_reg & 0x30000000 ? 1 : 0;
- if (tp->full_duplex != duplex) {
- tp->full_duplex = duplex;
- if (tp->full_duplex)
- tp->csr6 |= 0x0200;
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ int negotiated = mdio_read(dev, tp->phys[0], 5) & tp->advertising[0];
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: LC82C168 negotiated capability %8.8x, "
+ "CSR5 %8.8x.\n",
+ dev->name, negotiated, inl(ioaddr + CSR5));
+
+ if (negotiated & 0x0380) /* 10 vs 100mbps */
+ new_csr6 |= 0x812E0000;
else
- tp->csr6 &= ~0x0200;
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- if (tulip_debug > 0) /* Gurppp, should be >1 */
- printk(KERN_INFO "%s: Setting %s-duplex based on"
- " PNIC PHY report of %8.8x.\n",
- dev->name, tp->full_duplex ? "full" : "half", phy_reg);
- }
- if (phy_reg & 0x04000000) { /* Remote link fault */
- /*outl(0x0201F078, ioaddr + 0xB8);*/
- next_tick = 3*HZ;
- }
- if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+ new_csr6 |= 0x816E0000;
+ if (((negotiated & 0x0300) == 0x0100) /* Duplex */
+ || (negotiated & 0x00C0) == 0x0040
+ || tp->full_duplex_lock) {
+ tp->full_duplex = 1;
+ new_csr6 |= 0x0200;
+ }
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
- "CSR5 %8.8x, PHY %3.3x.\n",
- dev->name, medianame[dev->if_port], csr12,
- inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
- if (dev->if_port == 0) {
- dev->if_port = 3;
+ printk(KERN_DEBUG "%s: LC82C168 MII PHY status %4.4x, Link "
+ "partner report %4.4x, csr6 %8.8x/%8.8x.\n",
+ dev->name, mdio_read(dev, tp->phys[0], 1), negotiated,
+ tp->csr6, inl(ioaddr + CSR6));
+ } else {
+ int phy_reg = inl(ioaddr + 0xB8);
+ int csr5 = inl(ioaddr + CSR5);
+
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: LC82C168 phy status %8.8x, CSR5 %8.8x.\n",
+ dev->name, phy_reg, csr5);
+
+ if (phy_reg & 0x04000000) { /* Remote link fault */
+ /*outl(0x0201F078, ioaddr + 0xB8);*/
+ next_tick = 3*HZ;
+ }
+ if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+ "CSR5 %8.8x, PHY %3.3x.\n",
+ dev->name, medianame[dev->if_port], csr12,
+ inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+ if (tp->medialock) {
+ } else if (dev->if_port == 0) {
+ dev->if_port = 3;
+ outl(0x33, ioaddr + CSR12);
+ new_csr6 = 0x01860000;
+ outl(0x1F868, ioaddr + 0xB8);
+ } else {
+ dev->if_port = 0;
+ outl(0x32, ioaddr + CSR12);
+ new_csr6 = 0x00420000;
+ outl(0x1F078, ioaddr + 0xB8);
+ }
+ new_csr6 |= (tp->csr6 & 0xfdff);
+ next_tick = 3*HZ;
} else
- dev->if_port = 0;
- next_tick = 3*HZ;
- select_media(dev, 0);
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ new_csr6 = tp->csr6;
+ if (tp->full_duplex_lock || (phy_reg & 0x30000000) != 0) {
+ tp->full_duplex = 1;
+ new_csr6 |= 0x00000200;
+ }
+ }
+ if (tp->csr6 != new_csr6) {
+ tp->csr6 = new_csr6;
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */
outl(tp->csr6 | 0x2002, ioaddr + CSR6);
dev->trans_start = jiffies;
+ if (tulip_debug > 0) /* Gurppp, should be >1 */
+ printk(KERN_INFO "%s: Changing PNIC configuration to %s-duplex, "
+ "CSR6 %8.8x.\n",
+ dev->name, tp->full_duplex ? "full" : "half", new_csr6);
}
tp->timer.expires = RUN_AT(next_tick);
add_timer(&tp->timer);
@@ -1908,13 +2003,15 @@
static void tulip_tx_timeout(struct device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
- if (tp->mtable && tp->mtable->has_mii) {
- /* Do nothing -- the media monitor should handle this. */
- if (tulip_debug > 1)
- printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
- dev->name);
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ /* Do nothing -- the media monitor should handle this. */
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+ dev->name);
+ dev->trans_start = jiffies;
+ return;
} else if (tp->chip_id == DC21040) {
if (inl(ioaddr + CSR12) & 0x0002) {
printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n",
@@ -2102,7 +2199,8 @@
#endif
struct tulip_private *tp;
- int csr5, ioaddr, work_budget = max_interrupt_work;
+ long ioaddr;
+ int csr5, work_budget = max_interrupt_work;
if (dev == NULL) {
printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
@@ -2119,8 +2217,8 @@
tp->smp_proc_id, hard_smp_processor_id());
#else
printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
- return;
#endif
+ return;
}
dev->interrupt = 1;
#ifdef SMP_CHECK
@@ -2210,6 +2308,14 @@
}
tp->dirty_tx = dirty_tx;
+ if (csr5 & TxDied) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: The transmitter stopped!"
+ " CSR5 is %x, CSR6 %x.\n",
+ dev->name, csr5, inl(ioaddr + CSR6));
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ }
}
/* Log errors. */
@@ -2261,24 +2367,6 @@
printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
dev->name, inl(ioaddr + CSR5));
-#ifdef notdef
- /* Code that should never be run! Perhaps remove after testing.. */
- {
- static int stopit = 10;
- if (dev->start == 0 && --stopit < 0) {
- printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n"
- KERN_ERR "%s: Disabling interrupt handler %d to avoid "
- "locking up the machine.\n",
- dev->name, dev->name, dev->irq);
-#ifdef SA_SHIRQ
- free_irq(irq, dev);
-#else
- free_irq(irq);
-#endif
- }
- }
-#endif
-
dev->interrupt = 0;
clear_bit(0, (void*)&tp->interrupt);
return;
@@ -2311,6 +2399,9 @@
}
} else if (status & 0x8000) {
/* There was a fatal error. */
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+ dev->name, status);
tp->stats.rx_errors++; /* end of a packet.*/
if (status & 0x0890) tp->stats.rx_length_errors++;
if (status & 0x0004) tp->stats.rx_frame_errors++;
@@ -2318,7 +2409,7 @@
if (status & 0x0001) tp->stats.rx_fifo_errors++;
} else {
/* Omit the four octet CRC from the length. */
- short pkt_len = (status >> 16) - 4;
+ short pkt_len = ((status >> 16) & 0x7FF) - 4;
struct sk_buff *skb;
/* Check if the packet is long enough to just accept without
@@ -2396,7 +2487,7 @@
static int
tulip_close(struct device *dev)
{
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
int i;
@@ -2464,7 +2555,7 @@
tulip_get_stats(struct device *dev)
{
struct tulip_private *tp = (struct tulip_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
if (dev->start)
tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
@@ -2514,7 +2605,7 @@
} else {
save_flags(flags);
cli();
- data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
restore_flags(flags);
}
return 0;
@@ -2525,7 +2616,7 @@
} else {
save_flags(flags);
cli();
- mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
restore_flags(flags);
}
return 0;
@@ -2569,7 +2660,7 @@
static void set_rx_mode(struct device *dev, int num_addrs, void *addrs)
#endif
{
- int ioaddr = dev->base_addr;
+ long ioaddr = dev->base_addr;
int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
struct tulip_private *tp = (struct tulip_private *)dev->priv;
@@ -2686,7 +2777,7 @@
pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
io &= ~3;
- dev = tulip_probe1(bus, devfn, NULL, io, DC21142, -1);
+ dev = tulip_probe1(bus, devfn, NULL, DC21142, -1);
if (dev) {
dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
strcpy(node->dev_name, dev->name);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov