patch-2.2.0-pre2 linux/drivers/net/tulip.c
Next file: linux/drivers/nubus/nubus.c
Previous file: linux/drivers/net/sktr.c
Back to the patch index
Back to the overall index
- Lines: 2936
- Date:
Wed Dec 30 22:00:40 1998
- Orig file:
v2.2.0-pre1/linux/drivers/net/tulip.c
- Orig date:
Sun Jun 7 11:16:33 1998
diff -u --recursive --new-file v2.2.0-pre1/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
@@ -1,13 +1,13 @@
-/* tulip.c: A DEC 21040-family ethernet driver for linux. */
+/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
/*
- NOTICE: THIS IS THE ALPHA TEST VERSION!
- Written 1994-1997 by Donald Becker.
+ 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,14 +17,27 @@
http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
*/
-static const char *version = "tulip.c:v0.83 10/19/97 becker@cesdis.gsfc.nasa.gov\n";
+#define SMP_CHECK
+static const char version[] = "tulip.c:v0.89H 5/23/98 becker@cesdis.gsfc.nasa.gov\n";
/* A few user-configurable values. */
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
/* Used to pass the full-duplex flag, etc. */
-static int full_duplex[8] = {0, };
-static int options[8] = {0, };
-static int mtu[8] = {0, }; /* Jumbo MTU for interfaces. */
+static int full_duplex[MAX_UNITS] = {0, };
+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
@@ -38,40 +51,20 @@
bonding and packet priority.
There are no ill effects from too-large receive rings. */
#define TX_RING_SIZE 16
-#define RX_RING_SIZE 16
+#define RX_RING_SIZE 32
/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
#ifdef __alpha__
-static const int rx_copybreak = 1518;
+static int rx_copybreak = 1518;
#else
-static const int rx_copybreak = 100;
+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
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
#include <linux/module.h>
-#include <linux/version.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -82,6 +75,8 @@
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/bios32.h>
+
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
@@ -106,28 +101,13 @@
#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2)
#endif
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338
-#ifdef MODULE
-#if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__)
-char kernel_version[] = UTS_RELEASE;
-#endif
-#else
-#undef MOD_INC_USE_COUNT
-#define MOD_INC_USE_COUNT
-#undef MOD_DEC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-#endif /* 1.3.38 */
-
#if (LINUX_VERSION_CODE >= 0x10344)
#define NEW_MULTICAST
#include <linux/delay.h>
#endif
#if (LINUX_VERSION_CODE >= 0x20100)
-#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
#endif
-#endif
#ifdef SA_SHIRQ
#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs)
#else
@@ -135,8 +115,8 @@
#endif
#if (LINUX_VERSION_CODE < 0x20123)
+#define hard_smp_processor_id() smp_processor_id()
#define test_and_set_bit(val, addr) set_bit(val, addr)
-#include <linux/bios32.h>
#endif
/* This my implementation of shared IRQs, now only used for 1.2.13. */
@@ -167,7 +147,7 @@
This device driver is designed for the DECchip "Tulip", Digital's
single-chip ethernet controllers for PCI. Supported members of the family
-are the 21040, 21041, 21140, 21140A and 21142. These chips are used on
+are the 21040, 21041, 21140, 21140A, 21142, and 21143. These chips are used on
many PCI boards including the SMC EtherPower series.
@@ -268,44 +248,65 @@
#ifndef PCI_VENDOR_ID_LITEON
#define PCI_VENDOR_ID_LITEON 0x11AD
-#define PCI_DEVICE_ID_PNIC 0x0002
-#define PCI_DEVICE_ID_PNIC_X 0x0168
-#else
-/* Now PCI_VENDOR_ID_LITEON is defined, but device IDs have different names */
-#define PCI_DEVICE_ID_PNIC PCI_DEVICE_ID_LITEON_LNE100TX
-#define PCI_DEVICE_ID_PNIC_X 0x0168
+#endif
+
+#ifndef PCI_VENDOR_ID_MXIC
+#define PCI_VENDOR_ID_MXIC 0x10d9
+#define PCI_DEVICE_ID_MX98713 0x0512
+#define PCI_DEVICE_ID_MX98715 0x0531
+#define PCI_DEVICE_ID_MX98725 0x0531
#endif
/* The rest of these values should never change. */
static void tulip_timer(unsigned long data);
+static void t21142_timer(unsigned long data);
+static void mxic_timer(unsigned long data);
+static void pnic_timer(unsigned long data);
/* A table describing the chip types. */
+enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE = 2, CSR12_IN_SROM = 4,};
static struct tulip_chip_table {
- int device_id;
- char *chip_name;
- int flags;
- void (*media_timer)(unsigned long data);
+ 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 DS21040 Tulip", 0, tulip_timer },
- { PCI_DEVICE_ID_DEC_TULIP_PLUS, "Digital DS21041 Tulip", 0, tulip_timer },
- { PCI_DEVICE_ID_DEC_TULIP_FAST, "Digital DS21140 Tulip", 0, tulip_timer },
- { PCI_DEVICE_ID_DEC_TULIP_21142, "Digital DS21142/3 Tulip", 0, tulip_timer },
- { PCI_DEVICE_ID_PNIC_X, "Lite-On 82c168 PNIC", 0, tulip_timer },
+ { 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_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, LC82C168};
+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. */
-static const char media_fd[] =
-{0,0,0,0, 0xff,0xff,0,0, 0xff,0,0xff,0x01, 0,0,0xff,0 };
+/* A full-duplex map for media types. */
+enum MediaIs {MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+ MediaIs100=16};
+static const char media_cap[] =
+{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };
/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
static u16 t21041_csr13[] = { 0xEF05, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
static u16 t21041_csr14[] = { 0x7F3F, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
@@ -325,9 +326,9 @@
/* The bits in the CSR5 status registers, mostly interrupt sources. */
enum status_bits {
TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10,
+ NormalIntr=0x10000, AbnormalIntr=0x8000,
RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
- TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02,
- TxIntr=0x01,
+ TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
};
/* The Tulip Rx and Tx buffer descriptors. */
@@ -352,7 +353,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];
};
@@ -360,7 +361,6 @@
struct mediainfo *next;
int info_type;
int index;
- struct non_mii { char media; unsigned char csr12val; char bitnum, flags;} non_mii;
unsigned char *info;
};
@@ -384,32 +384,38 @@
struct enet_statistics stats;
#endif
struct timer_list timer; /* Media selection timer. */
-#ifdef CONFIG_NET_HW_FLOWCONTROL
- int fc_bit;
+ int interrupt; /* In-interrupt flag. */
+#ifdef SMP_CHECK
+ int smp_proc_id; /* Which processor in IRQ handler. */
#endif
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
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. */
unsigned int mediasense:1; /* Media sensing in progress. */
unsigned int csr6; /* Current CSR6 control settings. */
unsigned char eeprom[128]; /* Serial EEPROM contents. */
- signed char phys[4]; /* MII device addresses. */
+ u16 to_advertise; /* NWay capabilities advertised. */
+ u16 advertising[4];
+ signed char phys[4], mii_cnt; /* MII device addresses. */
struct mediatable *mtable;
int cur_index; /* Current media index. */
- unsigned char pci_bus, pci_device_fn;
+ unsigned char pci_bus, pci_dev_fn;
int pad0, pad1; /* Used for 8-byte alignment */
};
-static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+static struct device *tulip_probe1(int pci_bus, int pci_devfn,
+ 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 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);
@@ -420,24 +426,19 @@
static void tulip_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs);
static int tulip_close(struct device *dev);
static struct enet_statistics *tulip_get_stats(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
#ifdef NEW_MULTICAST
-static void set_multicast_list(struct device *dev);
+static void set_rx_mode(struct device *dev);
#else
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-#endif
-#ifdef CONFIG_NET_FASTROUTE
-#include <linux/if_arp.h>
-#include <net/ip.h>
-
-static int tulip_accept_fastpath(struct device *dev, struct dst_entry *dst);
+static void set_rx_mode(struct device *dev, int num_addrs, void *addrs);
#endif
-#ifdef MODULE
/* A list of all installed Tulip devices, for removing the driver module. */
static struct device *root_tulip_dev = NULL;
-#endif
/* This 21040 probe no longer uses a large fixed contiguous Rx buffer region,
but now receives directly into full-sized skbuffs that are allocated
@@ -449,121 +450,118 @@
{
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 (pci_present()) {
- unsigned char pci_bus, pci_device_fn;
-
- for (;pci_index < 0xff; pci_index++) {
- unsigned char pci_latency;
#if LINUX_VERSION_CODE >= 0x20155
- unsigned int pci_irq_line;
- struct pci_dev *pdev;
+ if (! pci_present())
+ return -ENODEV;
#else
- unsigned char pci_irq_line;
+ if (! pcibios_present())
+ return -ENODEV;
#endif
- unsigned short pci_command, vendor, device;
- unsigned int pci_ioaddr, 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);
+ 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);
+
+ 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 LINUX_VERSION_CODE >= 0x20155
- pdev = pci_find_slot(pci_bus, pci_device_fn);
- pci_irq_line = pdev->irq;
- pci_ioaddr = pdev->base_address[0];
+ pci_ioaddr = pci_find_slot(pci_bus, pci_device_fn)->base_address[0];
#else
- 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);
+ 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;
+ /* Remove I/O space marker in bit 0. */
+ pci_ioaddr &= ~3;
- if (vendor != PCI_VENDOR_ID_DEC
- && vendor != PCI_VENDOR_ID_LITEON)
- continue;
- if (vendor == PCI_VENDOR_ID_LITEON)
- device = PCI_DEVICE_ID_PNIC_X;
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "Found %s at I/O %#x.\n",
+ tulip_tbl[chip_idx].chip_name, pci_ioaddr);
- 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) {
- printk(KERN_INFO "Unknown Digital PCI ethernet chip type"
- " %4.4x"" detected: not configured.\n", device);
- continue;
- }
- if (tulip_debug > 2)
- printk(KERN_DEBUG "Found DEC PCI Tulip at I/O %#x, IRQ %d.\n",
- pci_ioaddr, pci_irq_line);
+ if (check_region(pci_ioaddr, tulip_tbl[chip_idx].io_size))
+ continue;
- if (check_region(pci_ioaddr, TULIP_TOTAL_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);
+ }
-#ifdef MODULE
- dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx,
- cards_found);
-#else
- dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, -1);
-#endif
+ dev = tulip_probe1(pci_bus, pci_device_fn, dev, chip_idx, cards_found);
- if (dev) {
- /* Get and check the bus-master and latency values. */
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, &pci_command);
- if ( ! (pci_command & PCI_COMMAND_MASTER)) {
- printk(KERN_INFO " PCI Master Bit has not been set! Setting...\n");
- pci_command |= PCI_COMMAND_MASTER;
- pcibios_write_config_word(pci_bus, pci_device_fn,
- PCI_COMMAND, pci_command);
- }
- 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);
+ /* 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.\n",
- pci_latency);
- /* Bring the 21143 out power-down mode. */
- if (device == PCI_DEVICE_ID_DEC_TULIP_21142)
+ } 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++;
- }
+ 0x40, 0x40000000);
+ dev = 0;
+ cards_found++;
}
}
return cards_found ? 0 : -ENODEV;
}
-static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq,
+static struct device *tulip_probe1(int pci_bus, int pci_device_fn,
+ 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;
+ static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */
int i;
unsigned short sum;
@@ -572,7 +570,25 @@
dev = init_etherdev(dev, 0);
- 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. */
@@ -629,6 +645,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];
@@ -655,13 +675,15 @@
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", irq);
last_irq = irq;
/* We do a request_region() only to register /proc/ioports info. */
- request_region(ioaddr, TULIP_TOTAL_SIZE, tulip_tbl[chip_id].chip_name);
+ /* Note that proper size is tulip_tbl[chip_id].chip_name, but... */
+ request_region(ioaddr, TULIP_TOTAL_SIZE, dev->name);
dev->base_addr = ioaddr;
dev->irq = irq;
@@ -671,11 +693,11 @@
memset(tp, 0, sizeof(*tp));
dev->priv = tp;
-#ifdef MODULE
tp->next_module = root_tulip_dev;
root_tulip_dev = dev;
-#endif
+ tp->pci_bus = pci_bus;
+ tp->pci_dev_fn = pci_device_fn;
tp->chip_id = chip_id;
#ifdef TULIP_FULL_DUPLEX
@@ -690,36 +712,64 @@
#endif
/* The lower four bits are the media type. */
- if (board_idx >= 0) {
- tp->full_duplex = (options[board_idx]&16) || full_duplex[board_idx]>0;
- if (tp->full_duplex)
- tp->full_duplex_lock = 1;
+ if (board_idx >= 0 && board_idx < MAX_UNITS) {
tp->default_port = options[board_idx] & 15;
- if (tp->default_port)
- tp->medialock = 1;
+ if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+ tp->full_duplex = 1;
if (mtu[board_idx] > 0)
dev->mtu = mtu[board_idx];
}
+ if (dev->mem_start)
+ tp->default_port = dev->mem_start;
+ if (tp->default_port) {
+ tp->medialock = 1;
+ if (media_cap[tp->default_port] & MediaAlwaysFD)
+ tp->full_duplex = 1;
+ }
+ if (tp->full_duplex)
+ tp->full_duplex_lock = 1;
/* This is logically part of probe1(), but too complex to write inline. */
- if (chip_id != DC21040 && chip_id != LC82C168)
+ if (tulip_tbl[chip_id].flags & HAS_MEDIA_TABLE)
parse_eeprom(dev);
- if (tp->mtable && tp->mtable->has_mii) {
+ if (media_cap[tp->default_port] & MediaIsMII) {
+ u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+ tp->to_advertise = media2advert[tp->default_port - 9];
+ } else
+ tp->to_advertise = 0x03e1;
+
+ if ((tp->mtable && tp->mtable->has_mii) ||
+ ( ! tp->mtable && (tulip_tbl[tp->chip_id].flags & HAS_MII))) {
int phy, phy_idx;
/* Find the connected MII xcvrs.
Doing this in open() would allow detecting external xcvrs later,
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, 0);
- if (mii_status != 0xffff && mii_status != 0x0000) {
- tp->phys[phy_idx++] = phy;
- printk(KERN_INFO "%s: MII transceiver found at MDIO address %d.\n",
- dev->name, phy);
+ int mii_status = mdio_read(dev, phy, 1);
+ if (mii_status != 0xffff && mii_status != 0x0000) {
+ 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;
+ printk(KERN_INFO "%s: MII transceiver found at MDIO address "
+ "%d, config %4.4x status %4.4x.\n",
+ dev->name, phy, mii_reg0, mii_status);
+ 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(dev, phy, 4));
+ mdio_write(dev, phy, 4, reg4);
+ }
+ /* Enable autonegotiation: some boards default to off. */
+ mdio_write(dev, phy, 0, mii_reg0 |
+ (tp->full_duplex ? 0x1100 : 0x1000) |
+ (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
}
}
- if (phy_idx == 0) {
+ tp->mii_cnt = phy_idx;
+ if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
dev->name);
tp->phys[0] = 1;
@@ -731,11 +781,11 @@
dev->hard_start_xmit = &tulip_start_xmit;
dev->stop = &tulip_close;
dev->get_stats = &tulip_get_stats;
-#ifdef HAVE_MULTICAST
- dev->set_multicast_list = &set_multicast_list;
+#ifdef HAVE_PRIVATE_IOCTL
+ dev->do_ioctl = &private_ioctl;
#endif
-#ifdef CONFIG_NET_FASTROUTE
- dev->accept_fastpath = tulip_accept_fastpath;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_rx_mode;
#endif
/* Reset the xcvr interface and turn on heartbeat. */
@@ -744,20 +794,37 @@
outl(0x00000000, ioaddr + CSR13);
outl(0xFFFFFFFF, ioaddr + CSR14);
outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
- outl(inl(ioaddr + CSR6) | 0x200, ioaddr + CSR6);
+ outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
outl(0x0000EF05, ioaddr + CSR13);
break;
- case DC21140: case DC21142:
- if (tp->mtable)
- outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
- break;
case DC21040:
outl(0x00000000, ioaddr + CSR13);
outl(0x00000004, ioaddr + CSR13);
break;
+ case DC21140: default:
+ if (tp->mtable)
+ outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+ break;
+ case DC21142:
+ outl(0x82420200, ioaddr + CSR6);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+ break;
case LC82C168:
- outl(0x33, ioaddr + CSR12);
- 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);
+ outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+ outl(0x00000001, ioaddr + CSR13);
break;
}
@@ -782,7 +849,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*/
@@ -796,9 +865,15 @@
{0, 0, 0, 0, {}}};
static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
- "21142 non-MII PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+ "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
#define EEPROM_SIZE 128
+#if defined(__i386__)
+#define get_u16(ptr) (*(u16 *)(ptr))
+#else
+#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
+#endif
+
static void parse_eeprom(struct device *dev)
{
/* The last media info list parsed, for multiport boards. */
@@ -806,7 +881,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;
@@ -870,30 +945,45 @@
}
subsequent_board:
- if (tp->chip_id == DC21041) {
+ if (ee_data[27] == 0) { /* No valid media table. */
+ } else if (tp->chip_id == DC21041) {
unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
- short media = *(u16 *)p;
- int count = p[2];
+ short media;
+ int count;
+
+ media = get_u16(p);
+ p += 2;
+ count = *p++;
printk(KERN_INFO "%s:21041 Media information at %d, default media "
"%4.4x (%s).\n", dev->name, ee_data[27], media,
media & 0x0800 ? "Autosense" : medianame[media & 15]);
for (i = 0; i < count; i++) {
- unsigned char media_code = p[3 + i*7];
- u16 *csrvals = (u16 *)&p[3 + i*7 + 1];
- printk(KERN_INFO "%s: 21041 media %2.2x (%s),"
- " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
- dev->name, media_code & 15, medianame[media_code & 15],
- csrvals[0], csrvals[1], csrvals[2]);
+ unsigned char media_code = *p++;
+ u16 csrvals[3];
+ int idx;
+ for (idx = 0; idx < 3; idx++) {
+ csrvals[idx] = get_u16(p);
+ p += 2;
+ }
+ if (media_code & 0x40) {
+ printk(KERN_INFO "%s: 21041 media %2.2x (%s),"
+ " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n",
+ dev->name, media_code & 15, medianame[media_code & 15],
+ csrvals[0], csrvals[1], csrvals[2]);
+ } else
+ printk(KERN_INFO "%s: 21041 media #%d, %s.\n",
+ dev->name, media_code & 15, medianame[media_code & 15]);
}
} else {
unsigned char *p = (void *)ee_data + ee_data[27];
unsigned char csr12dir = 0;
int count;
struct mediatable *mtable;
- u16 media = *((u16 *)p)++;
+ u16 media = get_u16(p);
- if (tp->chip_id == DC21140)
+ p += 2;
+ if (tulip_tbl[tp->chip_id].flags & CSR12_IN_SROM)
csr12dir = *p++;
count = *p++;
mtable = (struct mediatable *)
@@ -905,7 +995,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]);
@@ -916,14 +1006,18 @@
leaf->type = 0;
leaf->media = p[0] & 0x3f;
leaf->leafdata = p;
+ if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */
+ mtable->has_mii = 1;
p += 4;
} else {
leaf->type = p[1];
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;
}
@@ -966,11 +1060,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);
@@ -1001,6 +1095,16 @@
return retval;
}
+/* MII transceiver control section.
+ Read and write the MII registers using software-generated serial
+ MDIO protocol. See the MII specifications or DP83840A data sheet
+ for details. */
+
+/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually
+ met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+ "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
/* Read and write the MII registers using software-generated serial
MDIO protocol. It is just different enough from the EEPROM protocol
to not share code. The maxium data clock rate is 2.5 Mhz. */
@@ -1010,18 +1114,24 @@
#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */
#define MDIO_ENB_IN 0x40000
#define MDIO_DATA_READ 0x80000
-#ifdef _LINUX_DELAY_H
-#define mdio_delay() udelay(1)
-#else
-#define mdio_delay() __SLOW_DOWN_IO
-#endif
-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;
- unsigned short retval = 0;
- int mdio_addr = ioaddr + CSR9;
+ int retval = 0;
+ 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--) {
@@ -1031,60 +1141,78 @@
mdio_delay();
}
/* Shift the read command bits out. */
- for (i = 17; i >= 0; i--) {
+ for (i = 15; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
- outl(dataval, mdio_addr);
- mdio_delay();
- outl(dataval | MDIO_SHIFT_CLK, mdio_addr);
+ outl(MDIO_ENB | dataval, mdio_addr);
mdio_delay();
- outl(dataval, mdio_addr);
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
- outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- outl(MDIO_ENB_IN, mdio_addr);
-
- for (i = 16; i > 0; i--) {
- outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay();
- retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
outl(MDIO_ENB_IN, mdio_addr);
mdio_delay();
- }
- /* Clear out extra bits. */
- for (i = 16; i > 0; i--) {
+ retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
- outl(MDIO_ENB_IN, mdio_addr);
- mdio_delay();
}
- return retval;
+ return (retval>>1) & 0xffff;
}
-#ifdef CONFIG_NET_HW_FLOWCONTROL
-/* Enable receiver */
-
-void tulip_xon(struct device *dev)
+static void mdio_write(struct device *dev, int phy_id, int location, int value)
{
- struct tulip_private *lp = (struct tulip_private *)dev->priv;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int i;
+ int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+ long mdio_addr = dev->base_addr + CSR9;
- clear_bit(lp->fc_bit, &netdev_fc_xoff);
- if (dev->start)
- outl(lp->csr6 | 0x2002, dev->base_addr + CSR6);
+ 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--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return;
}
-#endif
static int
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!? */
- if (tp->mtable && tp->mtable->has_mii)
+ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
outl(0x00040000, ioaddr + CSR6);
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
@@ -1106,31 +1234,30 @@
Tx and Rx queues and the address filter list. */
#if defined(__alpha__)
/* ToDo: Alpha setting could be better. */
- outl(0x00200000 | 0xE000, ioaddr + CSR0);
+ outl(0x01A00000 | 0xE000, ioaddr + CSR0);
#elif defined(__powerpc__)
- outl(0x00200080 | 0x8000, ioaddr + CSR0);
+ outl(0x01A00080 | 0x8000, ioaddr + CSR0);
#elif defined(__i386__)
#if defined(MODULE)
/* When a module we don't have 'x86' to check. */
- outl(0x00200000 | 0x4800, ioaddr + CSR0);
+ outl(0x01A00000 | 0x4800, ioaddr + CSR0);
#else
-#ifndef ORIGINAL_TEXT
-#define x86 (boot_cpu_data.x86)
+#if (LINUX_VERSION_CODE > 0x2014c)
+#define x86 boot_cpu_data.x86
#endif
- outl(0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
+ outl(0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0);
if (x86 <= 4)
printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
"alignment to %x.\n", dev->name,
- 0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000));
+ 0x01A00000 | (x86 <= 4 ? 0x4800 : 0x8000));
#endif
#else
- outl(0x00200000 | 0x4800, ioaddr + CSR0);
+ outl(0x01A00000 | 0x4800, ioaddr + CSR0);
#warning Processor architecture undefined!
#endif
#ifdef SA_SHIRQ
- if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ,
- tulip_tbl[tp->chip_id].chip_name, dev)) {
+ if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) {
return -EAGAIN;
}
#else
@@ -1178,7 +1305,7 @@
outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
if (dev->if_port == 0)
- dev->if_port = tp->default_port;
+ dev->if_port = tp->default_port;
if (tp->chip_id == DC21041 && dev->if_port > 4)
/* Invalid: Select initial TP, autosense, autonegotiate. */
dev->if_port = 4;
@@ -1186,14 +1313,16 @@
/* Allow selecting a default media. */
if (tp->mtable == NULL)
goto media_picked;
- if (dev->if_port)
+ if (dev->if_port) {
+ 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 ==
- (dev->if_port == 12 ? 0 : dev->if_port)) {
- 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++)
if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) {
@@ -1201,55 +1330,61 @@
dev->name, medianame[tp->mtable->mleaf[i].media]);
goto media_picked;
}
+ /* Start sensing first non-full-duplex media. */
for (i = tp->mtable->leafcount - 1;
- (media_fd[tp->mtable->mleaf[i].media] & 2) && i > 0; i--)
+ (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
;
media_picked:
- tp->cur_index = i;
tp->csr6 = 0;
- select_media(dev, 1);
+ tp->cur_index = i;
+ if (dev->if_port == 0 && tp->chip_id == DC21142) {
+ tp->csr6 = 0x82420200;
+ outl(0x0003FFFF, ioaddr + CSR14);
+ 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);
/* Start the chip's Tx to process setup frame. */
outl(tp->csr6, ioaddr + CSR6);
outl(tp->csr6 | 0x2000, ioaddr + CSR6);
dev->tbusy = 0;
- dev->interrupt = 0;
+ tp->interrupt = 0;
dev->start = 1;
-
/* Enable interrupts by setting the interrupt mask. */
- outl(0x0001ebef, ioaddr + CSR7);
+ 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. */
init_timer(&tp->timer);
- tp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
+ tp->timer.expires = RUN_AT(5*HZ);
tp->timer.data = (unsigned long)dev;
- tp->timer.function = &tulip_timer; /* timer handler */
+ tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
add_timer(&tp->timer);
-#ifdef CONFIG_NET_HW_FLOWCONTROL
- tp->fc_bit = netdev_register_fc(dev, tulip_xon);
-#endif
-#ifdef CONFIG_NET_FASTROUTE
- dev->tx_semaphore = 1;
-#endif
return 0;
}
/* 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;
@@ -1261,8 +1396,8 @@
switch (mleaf->type) {
case 0: /* 21140 non-MII xcvr. */
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control"
- " setting %2.2x.\n",
+ printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
+ " with control setting %2.2x.\n",
dev->name, p[1]);
dev->if_port = p[0];
if (startup)
@@ -1270,26 +1405,11 @@
outl(p[1], ioaddr + CSR12);
new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
break;
- case 1:
- if (startup) {
- outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
- dev->if_port = 11;
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Doing a reset sequence of length %d.\n",
- dev->name, p[2 + p[1]]);
- for (i = 0; i < p[2 + p[1]]; i++)
- outl(p[3 + p[1] + i], ioaddr + CSR12);
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s Doing a transceiver setup sequence of length %d.\n",
- dev->name, p[1]);
- for (i = 0; i < p[1]; i++)
- outl(p[2 + i], ioaddr + CSR12);
- }
- check_mii = 1;
- new_csr6 = 0x020C0000;
- break;
case 2: case 4: {
- u16 *setup = (u16*)&p[1];
+ u16 setup[3];
+ for (i = 0; i < 3; i++)
+ setup[i] = get_u16(&p[i*2 + 1]);
+
dev->if_port = p[0] & 15;
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n",
@@ -1299,59 +1419,74 @@
outl(setup[1], ioaddr + CSR14);
outl(setup[2], ioaddr + CSR15);
outl(setup[0], ioaddr + CSR13);
- setup += 3;
- } else {
+ for (i = 0; i < 3; i++) /* Re-fill setup[] */
+ setup[i] = get_u16(&p[i*2 + 7]);
+ } else if (dev->if_port <= 4) {
outl(0, ioaddr + CSR13);
outl(t21142_csr14[dev->if_port], ioaddr + CSR14);
outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+ } else {
+ outl(0, ioaddr + CSR14);
+ outl(8, ioaddr + CSR15);
+ outl(0, ioaddr + CSR13);
}
outl(setup[0]<<16, ioaddr + CSR15); /* Direction */
outl(setup[1]<<16, ioaddr + CSR15); /* Data */
if (mleaf->type == 4)
- new_csr6 = 0x02000000 | ((setup[2] & 0x71) << 18);
+ new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
else
new_csr6 = 0x82420000;
break;
}
- case 3: {
+ case 1: case 3: {
+ int phy_num = p[0];
int init_length = p[1];
- u16 * init_sequence = (u16*)(p + 2);
- int reset_length = p[2 + init_length*2];
- u16 * reset_sequence = (u16*)&p[3 + init_length*2];
+ u16 *misc_info;
+ u16 to_advertise;
dev->if_port = 11;
- if (startup) {
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Doing a 21142 reset sequence of length %d.\n",
- dev->name, reset_length);
- for (i = 0; i < reset_length; i++)
- outl(reset_sequence[i] << 16, ioaddr + CSR15);
- }
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Doing a 21142 xcvr setup sequence of length %d.\n",
- dev->name, init_length);
- for (i = 0; i < init_length; i++)
- outl(init_sequence[i] << 16, ioaddr + CSR15);
check_mii = 1;
- new_csr6 = 0x020C0000;
+ new_csr6 = 0x020E0000;
+ if (mleaf->type == 3) { /* 21142 */
+ u16 *init_sequence = (u16*)(p+2);
+ u16 *reset_sequence = &((u16*)(p+3))[init_length];
+ int reset_length = p[2 + init_length*2];
+ misc_info = reset_sequence + reset_length;
+ if (startup)
+ for (i = 0; i < reset_length; i++)
+ outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+ for (i = 0; i < init_length; i++)
+ outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+ } else {
+ u8 *init_sequence = p + 2;
+ u8 *reset_sequence = p + 3 + init_length;
+ int reset_length = p[2 + init_length];
+ misc_info = (u16*)(reset_sequence + reset_length);
+ if (startup) {
+ outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+ for (i = 0; i < reset_length; i++)
+ outl(reset_sequence[i], ioaddr + CSR12);
+ }
+ for (i = 0; i < init_length; i++)
+ outl(init_sequence[i], ioaddr + CSR12);
+ }
+ to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
+ tp->advertising[phy_num] = to_advertise;
+ if (tulip_debug > 1 || 1)
+ 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(dev, tp->phys[phy_num], 4, to_advertise);
break;
}
default:
- new_csr6 = 0x020C0000;
+ new_csr6 = 0x020E0000;
}
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
dev->name, medianame[dev->if_port],
inl(ioaddr + CSR12) & 0xff);
- } else if (tp->chip_id == DC21140) {
- /* Set media type to MII @ 100mbps: 0x020C0000 */
- new_csr6 = 0x020C0000;
- dev->if_port = 11;
- if (tulip_debug > 1) {
- printk(KERN_DEBUG "%s: Unknown media control, assuming MII, CSR12 %2.2x.\n",
- dev->name, inl(ioaddr + CSR12) & 0xff);
- }
} else if (tp->chip_id == DC21041) {
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
@@ -1363,14 +1498,24 @@
outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
new_csr6 = 0x80020000;
} else if (tp->chip_id == LC82C168) {
- if (startup)
- dev->if_port = 3;
+ 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 (dev->if_port == 3 || dev->if_port == 5) {
+ 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;
+ outl(0x0001B078, ioaddr + 0xB8);
+ outl(0x0201B078, ioaddr + 0xB8);
+ } else if (dev->if_port == 3 || dev->if_port == 5) {
outl(0x33, ioaddr + CSR12);
new_csr6 = 0x01860000;
if (startup)
@@ -1382,7 +1527,7 @@
new_csr6 = 0x00420000;
outl(0x1F078, ioaddr + 0xB8);
}
- } else { /* 21040 */
+ } else if (tp->chip_id == DC21040) { /* 21040 */
/* Turn on the xcvr interface. */
int csr12 = inl(ioaddr + CSR12);
if (tulip_debug > 1)
@@ -1393,6 +1538,23 @@
outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13);
+ } else { /* Unknown chip type with no media table. */
+ if (tp->default_port == 0)
+ if (tp->mii_cnt) {
+ dev->if_port = 11;
+ } else
+ dev->if_port = 3;
+ if (media_cap[dev->if_port] & MediaIsMII) {
+ new_csr6 = 0x020E0000;
+ } else if (media_cap[dev->if_port] & MediaIsFx) {
+ new_csr6 = 0x028600000;
+ } else
+ new_csr6 = 0x038600000;
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: No media description table, assuming "
+ "%s transceiver, CSR12 %2.2x.\n",
+ dev->name, medianame[dev->if_port],
+ inl(ioaddr + CSR12));
}
tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
@@ -1403,7 +1565,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;
@@ -1467,150 +1629,128 @@
break;
}
break;
- case LC82C168: {
- int phy_reg = inl(ioaddr + 0xB8);
- 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 (phy_reg & 0x04000000) { /* Remote link fault */
- outl(0x0201F078, ioaddr + 0xB8);
- next_tick = (24*HZ)/10;
- } else
- next_tick = 10*HZ;
- if (inl(ioaddr + CSR5) & TPLnkFail) { /* 100baseTx link beat */
+ case DC21140: case DC21142: case MX98713: default: {
+ struct medialeaf *mleaf;
+ unsigned char *p;
+ if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
+ /* Not much that can be done.
+ Assume this a generic MII or SYM transceiver. */
+ next_tick = 60*HZ;
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
+ "CSR12 0x%2.2x.\n",
+ dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
+ break;
+ }
+ mleaf = &tp->mtable->mleaf[tp->cur_index];
+ p = mleaf->leafdata;
+ switch (mleaf->type) {
+ case 0: case 4: {
+ /* Type 0 serial or 4 SYM transceiver. Check the link beat bit. */
+ int offset = mleaf->type == 4 ? 5 : 2;
+ s8 bitnum = p[offset];
+ if (p[offset+1] & 0x80) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG"%s: Transceiver monitor tick "
+ "CSR12=%#2.2x, no media sense.\n",
+ dev->name, csr12);
+ if (mleaf->type == 4) {
+ if (mleaf->media == 3 && (csr12 & 0x02))
+ goto select_next_media;
+ }
+ break;
+ }
+ if (tulip_debug > 2)
+ printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+ " bit %d is %d, expecting %d.\n",
+ dev->name, csr12, (bitnum >> 1) & 7,
+ (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+ (bitnum >= 0));
+ /* Check that the specified bit has the proper value. */
+ if ((bitnum < 0) !=
+ ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+ if (tulip_debug > 1)
+ printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+ medianame[mleaf->media]);
+ if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
+ goto actually_mii;
+ break;
+ }
+ if (tp->medialock)
+ break;
+ select_next_media:
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+ if (media_cap[dev->if_port] & MediaIsFD)
+ goto select_next_media; /* Skip FD entries. */
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;
- } else
- dev->if_port = 0;
- next_tick = (24*HZ)/10;
+ printk(KERN_DEBUG "%s: No link beat on media %s,"
+ " trying transceiver type %s.\n",
+ dev->name, medianame[mleaf->media & 15],
+ medianame[tp->mtable->mleaf[tp->cur_index].media]);
select_media(dev, 0);
+ /* Restart the transmit process. */
outl(tp->csr6 | 0x0002, ioaddr + CSR6);
outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- dev->trans_start = jiffies;
+ next_tick = (24*HZ)/10;
+ break;
}
- break;
- }
- case DC21140: case DC21142: {
- struct medialeaf *mleaf;
- unsigned char *p;
- if (tp->mtable == NULL) { /* No EEPROM info, use generic code. */
- /* Assume this is like a SMC card, and check its link beat bit. */
- if ((dev->if_port == 0 && (csr12 & 0x0080)) ||
- (dev->if_port == 1 && (csr12 & 0x0040) == 0)) {
- dev->if_port ^= 1;
- /* Stop the transmit process. */
- tp->csr6 = (dev->if_port ? 0x03860000 : 0x02420000);
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- printk(KERN_INFO "%s: link beat timed out, CSR12 is 0x%2.2x, switching to"
- " %s media.\n", dev->name,
- csr12 & 0xff,
- dev->if_port ? "100baseTx" : "10baseT");
- outl(tp->csr6 | 0xA002, ioaddr + CSR6);
- dev->trans_start = jiffies;
- next_tick = (24*HZ)/10;
- } else {
- next_tick = 10*HZ;
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: network media monitor 0x%2.2x, link"
- " beat detected as %s.\n", dev->name,
- csr12 & 0xff,
- dev->if_port ? "100baseTx" : "10baseT");
+ case 1: case 3: { /* 21140, 21142 MII */
+ int mii_reg1, mii_reg5;
+ actually_mii:
+ 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(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);
+ 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 */
+ else if (tp->full_duplex_lock)
+ ;
+ else {
+ int negotiated = mii_reg5 & tp->advertising[0];
+ int duplex = ((negotiated & 0x0100) != 0
+ || (negotiated & 0x00C0) == 0x0040);
+ /* 100baseTx-FD or 10T-FD, but not 100-HD */
+ if (tp->full_duplex != duplex) {
+ tp->full_duplex = duplex;
+ if (tp->full_duplex)
+ tp->csr6 |= 0x0200;
+ 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 MII"
+ " Xcvr #%d parter capability of %4.4x.\n",
+ dev->name, tp->full_duplex ? "full" : "half",
+ tp->phys[0], mii_reg5);
+ }
+ }
+ next_tick = 60*HZ;
+ break;
+ }
+ case 2: /* 21142 serial block has no link beat. */
+ default:
break;
}
- mleaf = &tp->mtable->mleaf[tp->cur_index];
- p = mleaf->leafdata;
- switch (mleaf->type) {
- case 0: case 4: {
- /* Type 0 non-MII or #4 SYM transceiver. Check the link beat bit. */
- s8 bitnum = p[mleaf->type == 4 ? 5 : 2];
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x bit %d is"
- " %d, expecting %d.\n",
- dev->name, csr12, (bitnum >> 1) & 7,
- (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
- (bitnum >= 0));
- /* Check that the specified bit has the proper value. */
- if ((bitnum < 0) !=
- ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
- medianame[mleaf->media]);
- break;
- }
- if (tp->medialock)
- break;
- select_next_media:
- if (--tp->cur_index < 0) {
- /* We start again, but should instead look for default. */
- tp->cur_index = tp->mtable->leafcount - 1;
- }
- dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
- if (media_fd[dev->if_port])
- goto select_next_media; /* Skip FD entries. */
- if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: No link beat on media %s,"
- " trying transceiver type %s.\n",
- dev->name, medianame[mleaf->media & 15],
- medianame[tp->mtable->mleaf[tp->cur_index].media]);
- select_media(dev, 0);
- /* Restart the transmit process. */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- next_tick = (24*HZ)/10;
- break;
- }
- case 1: case 3: /* 21140, 21142 MII */
- {
- int mii_reg1 = mdio_read(ioaddr, tp->phys[0], 1);
- int mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5);
- printk(KERN_INFO "%s: MII monitoring tick: CSR12 %2.2x, "
- "MII status %4.4x, Link partner report %4.4x.\n",
- dev->name, csr12, mii_reg1, mii_reg5);
-#ifdef notdef
- if (mii_reg1 != 0xffff && (mii_reg1 & 0x0004) == 0)
- goto select_next_media;
-#else
- if (mii_reg1 != 0xffff && (mii_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,
- mdio_read(ioaddr, tp->phys[0], 1));
-#endif
- if (mii_reg5 == 0xffff || mii_reg5 == 0x0000)
- ; /* No MII device or no link partner report */
- else if (tp->full_duplex_lock)
- ;
- else if ((mii_reg5 & 0x0100) != 0
- || (mii_reg5 & 0x00C0) == 0x0040) {
- /* 100baseTx-FD or 10T-FD, but not 100-HD */
- if (tp->full_duplex == 0) {
- tp->full_duplex = 1;
- 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 MII"
- " Xcvr #%d parter capability of %4.4x.\n",
- dev->name, full_duplex ? "full" : "half",
- tp->phys[0], mii_reg5);
- }
- }
- break;
- case 2: /* 21142 serial block has no link beat. */
- default:
- break;
- }
}
break;
- default: /* Invalid chip type. */
- break;
}
if (next_tick) {
tp->timer.expires = RUN_AT(next_tick);
@@ -1618,16 +1758,237 @@
}
}
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+ of available transceivers. */
+static void t21142_timer(unsigned long data)
+{
+ struct device *dev = (struct device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+ int next_tick = 60*HZ;
+ int new_csr6 = 0;
+
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21142 negotiation status %8.8x, %s.\n",
+ dev->name, csr12, medianame[dev->if_port]);
+ if (dev->if_port == 3) {
+ if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
+ new_csr6 = 0x82420200;
+ outl(new_csr6, ioaddr + CSR6);
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ outl(0x0001, ioaddr + CSR13);
+ outl(0x1301, ioaddr + CSR12); /* Start NWay. */
+ }
+ } else if ((csr12 & 0x7000) != 0x5000) {
+ /* Negotiation failed. Search media types. */
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21142 negotiation failed, status %8.8x.\n",
+ dev->name, csr12);
+ if (!(csr12 & 4)) { /* 10mbps link beat good. */
+ new_csr6 = 0x82420000;
+ dev->if_port = 0;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(t21142_csr15[dev->if_port], ioaddr + CSR15);
+ outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+ } else if (csr12 & 0x100) {
+ new_csr6 = 0x82420200;
+ dev->if_port = 2;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(0x0008, ioaddr + CSR15);
+ outl(0x0001, ioaddr + CSR13);
+ } else {
+ /* Select 100mbps port to check for link beat. */
+ new_csr6 = 0x83860000;
+ dev->if_port = 3;
+ outl(0, ioaddr + CSR13);
+ outl(0x0003FF7F, ioaddr + CSR14);
+ outl(8, ioaddr + CSR15);
+ outl(1, ioaddr + CSR13);
+ }
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: Testing new 21142 media %s.\n",
+ dev->name, medianame[dev->if_port]);
+ if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+ tp->csr6 &= 0x00D5;
+ tp->csr6 |= new_csr6;
+ outl(0x0301, ioaddr + CSR12);
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ }
+ }
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+}
+
+static void t21142_lnk_change( struct device *dev)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21142 link status interrupt %8.8x, CSR5 %x.\n",
+ dev->name, csr12, inl(ioaddr + CSR5));
+
+ if ((csr12 & 0x7000) == 0x5000) {
+ if (csr12 & 0x01800000) {
+ /* Switch to 100mbps mode. */
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ if (csr12 & 0x01000000) {
+ dev->if_port = 5;
+ tp->csr6 = 0x83860200;
+ } else {
+ dev->if_port = 3;
+ tp->csr6 = 0x83860000;
+ }
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ } /* Else 10baseT-FD is handled automatically. */
+ } else if (dev->if_port == 3) {
+ if (!(csr12 & 2))
+ printk(KERN_INFO"%s: 21142 100baseTx link beat good.\n",
+ dev->name);
+ else
+ dev->if_port = 0;
+ } else if (dev->if_port == 0) {
+ if (!(csr12 & 4))
+ printk(KERN_INFO"%s: 21142 10baseT link beat good.\n",
+ dev->name);
+ } else if (!(csr12 & 4)) { /* 10mbps link beat good. */
+ printk(KERN_INFO"%s: 21142 10mpbs sensed media.\n",
+ dev->name);
+ dev->if_port = 0;
+ } else { /* 100mbps link beat good. */
+ printk(KERN_INFO"%s: 21142 100baseTx sensed media.\n",
+ dev->name);
+ dev->if_port = 3;
+ tp->csr6 = 0x83860000;
+ outl(0x0003FF7F, ioaddr + CSR14);
+ outl(0x0301, ioaddr + CSR12);
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ }
+}
+
+
+static void mxic_timer(unsigned long data)
+{
+ struct device *dev = (struct device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int next_tick = 60*HZ;
+
+ if (tulip_debug > 3) {
+ printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+ inl(ioaddr + CSR12));
+ }
+ if (next_tick) {
+ tp->timer.expires = RUN_AT(next_tick);
+ add_timer(&tp->timer);
+ }
+}
+
+static void pnic_timer(unsigned long data)
+{
+ struct device *dev = (struct device *)data;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int csr12 = inl(ioaddr + CSR12);
+ int next_tick = 60*HZ;
+ int new_csr6 = tp->csr6 & ~0x40C40200;
+
+ 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
+ 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: 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
+ 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);
+}
+
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",
@@ -1637,20 +1998,6 @@
}
dev->trans_start = jiffies;
return;
- } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142) {
- /* Stop the transmit process. */
- outl(tp->csr6 | 0x0002, ioaddr + CSR6);
- dev->if_port ^= 1;
- printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
- "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
- dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
- inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
- printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
- dev->name, dev->if_port ? "100baseTx" : "10baseT");
- outl(tp->csr6 | 0x2002, ioaddr + CSR6);
- tp->stats.tx_errors++;
- dev->trans_start = jiffies;
- return;
} else if (tp->chip_id == DC21041) {
u32 csr12 = inl(ioaddr + CSR12);
@@ -1659,19 +2006,38 @@
dev->name, inl(ioaddr + CSR5), csr12,
inl(ioaddr + CSR13), inl(ioaddr + CSR14));
tp->mediasense = 1;
-
- if (dev->if_port == 1 || dev->if_port == 2) {
+ if (dev->if_port == 1 || dev->if_port == 2)
if (csr12 & 0x0004) {
dev->if_port = 2 - dev->if_port;
} else
dev->if_port = 0;
- } else
+ else
dev->if_port = 1;
-
select_media(dev, 0);
tp->stats.tx_errors++;
dev->trans_start = jiffies;
return;
+ } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+ || tp->chip_id == MX98713) {
+ /* Stop the transmit process. */
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+ "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+ dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+ inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ if (tp->mtable) {
+ if (--tp->cur_index < 0) {
+ /* We start again, but should instead look for default. */
+ tp->cur_index = tp->mtable->leafcount - 1;
+ }
+ select_media(dev, 0);
+ printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n",
+ dev->name, dev->if_port ? "100baseTx" : "10baseT");
+ }
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+ tp->stats.tx_errors++;
+ dev->trans_start = jiffies;
+ return;
} else
printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x,"
" resetting...\n",
@@ -1753,40 +2119,12 @@
int entry;
u32 flag;
-#ifdef ORIGINAL_TEXT
-#ifndef final_version
- if (skb == NULL || skb->len <= 0) {
- printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n",
- dev->name);
- dev_tint(dev);
- return 0;
- }
-#endif
-#endif
-
-#ifdef CONFIG_NET_FASTROUTE
- cli();
- if (xchg(&dev->tx_semaphore,0) == 0) {
- sti();
- /* With new queueing algorithm returning 1 when dev->tbusy == 0
- should not result in lockups, but I am still not sure. --ANK
- */
- if (net_ratelimit())
- printk(KERN_CRIT "Please check: are you still alive?\n");
- return 1;
- }
-#endif
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-#ifdef CONFIG_NET_FASTROUTE
- sti();
-#endif
- if (jiffies - dev->trans_start >= TX_TIMEOUT)
- tulip_tx_timeout(dev);
-#ifdef CONFIG_NET_FASTROUTE
- dev->tx_semaphore = 1;
-#endif
+ if (jiffies - dev->trans_start < TX_TIMEOUT)
+ return 1;
+ tulip_tx_timeout(dev);
return 1;
}
@@ -1816,7 +2154,6 @@
if (entry == TX_RING_SIZE-1)
flag |= 0xe2000000;
- tp->stats.tx_bytes += skb->len;
tp->tx_ring[entry].length = skb->len | flag;
tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */
tp->cur_tx++;
@@ -1824,10 +2161,6 @@
outl(0, dev->base_addr + CSR1);
dev->trans_start = jiffies;
-#ifdef CONFIG_NET_FASTROUTE
- dev->tx_semaphore = 1;
- sti();
-#endif
return 0;
}
@@ -1842,8 +2175,9 @@
struct device *dev = (struct device *)(irq2dev_map[irq]);
#endif
- struct tulip_private *lp;
- int csr5, ioaddr, boguscnt = 12;
+ struct tulip_private *tp;
+ long ioaddr;
+ int csr5, work_budget = max_interrupt_work;
if (dev == NULL) {
printk (KERN_ERR" tulip_interrupt(): irq %d for unknown device.\n",
@@ -1852,11 +2186,21 @@
}
ioaddr = dev->base_addr;
- lp = (struct tulip_private *)dev->priv;
- if (dev->interrupt)
+ tp = (struct tulip_private *)dev->priv;
+ if (test_and_set_bit(0, (void*)&tp->interrupt)) {
+#ifdef SMP_CHECK
+ printk(KERN_ERR "%s: Re-entering the interrupt handler with proc %d,"
+ " proc %d already handling.\n", dev->name,
+ tp->smp_proc_id, hard_smp_processor_id());
+#else
printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-
+#endif
+ return;
+ }
dev->interrupt = 1;
+#ifdef SMP_CHECK
+ tp->smp_proc_id = hard_smp_processor_id();
+#endif
do {
csr5 = inl(ioaddr + CSR5);
@@ -1867,23 +2211,24 @@
printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n",
dev->name, csr5, inl(dev->base_addr + CSR5));
- if ((csr5 & 0x00018000) == 0)
+ if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
break;
- if (csr5 & RxIntr)
- tulip_rx(dev);
+ if (csr5 & (RxIntr | RxNoBuf))
+ work_budget -= tulip_rx(dev);
if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
- int dirty_tx;
+ unsigned int dirty_tx;
- for (dirty_tx = lp->dirty_tx; dirty_tx < lp->cur_tx; dirty_tx++) {
+ for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+ dirty_tx++) {
int entry = dirty_tx % TX_RING_SIZE;
- int status = lp->tx_ring[entry].status;
+ int status = tp->tx_ring[entry].status;
if (status < 0)
break; /* It still hasn't been Txed */
/* Check for Rx filter setup frames. */
- if (lp->tx_skbuff[entry] == NULL)
+ if (tp->tx_skbuff[entry] == NULL)
continue;
if (status & 0x8000) {
@@ -1893,74 +2238,104 @@
printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
dev->name, status);
#endif
- lp->stats.tx_errors++;
- if (status & 0x4104) lp->stats.tx_aborted_errors++;
- if (status & 0x0C00) lp->stats.tx_carrier_errors++;
- if (status & 0x0200) lp->stats.tx_window_errors++;
- if (status & 0x0002) lp->stats.tx_fifo_errors++;
- if ((status & 0x0080) && lp->full_duplex == 0)
- lp->stats.tx_heartbeat_errors++;
+ tp->stats.tx_errors++;
+ if (status & 0x4104) tp->stats.tx_aborted_errors++;
+ if (status & 0x0C00) tp->stats.tx_carrier_errors++;
+ if (status & 0x0200) tp->stats.tx_window_errors++;
+ if (status & 0x0002) tp->stats.tx_fifo_errors++;
+ if ((status & 0x0080) && tp->full_duplex == 0)
+ tp->stats.tx_heartbeat_errors++;
#ifdef ETHER_STATS
- if (status & 0x0100) lp->stats.collisions16++;
+ if (status & 0x0100) tp->stats.collisions16++;
#endif
} else {
#ifdef ETHER_STATS
- if (status & 0x0001) lp->stats.tx_deferred++;
+ if (status & 0x0001) tp->stats.tx_deferred++;
#endif
- lp->stats.collisions += (status >> 3) & 15;
- lp->stats.tx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+ tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
+#endif
+ tp->stats.collisions += (status >> 3) & 15;
+ tp->stats.tx_packets++;
}
/* Free the original skb. */
- dev_kfree_skb(lp->tx_skbuff[entry]);
- lp->tx_skbuff[entry] = 0;
+#if (LINUX_VERSION_CODE > 0x20155)
+ dev_kfree_skb(tp->tx_skbuff[entry]);
+#else
+ dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);
+#endif
+ tp->tx_skbuff[entry] = 0;
}
#ifndef final_version
- if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {
+ if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
+ dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
dirty_tx += TX_RING_SIZE;
}
#endif
- if (lp->tx_full && dev->tbusy
- && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+ if (tp->tx_full && dev->tbusy
+ && tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) {
/* The ring is no longer full, clear tbusy. */
- lp->tx_full = 0;
+ tp->tx_full = 0;
dev->tbusy = 0;
mark_bh(NET_BH);
}
- lp->dirty_tx = dirty_tx;
+ 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. */
- if (csr5 & 0x8000) { /* Abnormal error summary bit. */
- if (csr5 & TxJabber) lp->stats.tx_errors++;
+ if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
+ if (csr5 & TxJabber) tp->stats.tx_errors++;
if (csr5 & TxFIFOUnderflow) {
- lp->csr6 |= 0x00200000; /* Reconfigure to store-n-forward. */
- /* Restart the transmit process. */
- outl(lp->csr6 | 0x0002, ioaddr + CSR6);
- outl(lp->csr6 | 0x2002, ioaddr + CSR6);
+ if ((tp->csr6 & 0xC000) != 0xC000)
+ tp->csr6 += 0x4000; /* Bump up the Tx threshold */
+ else
+ tp->csr6 |= 0x00200000; /* Store-n-forward. */
+ /* Restart the transmit process. */
+ outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+ outl(tp->csr6 | 0x2002, ioaddr + CSR6);
}
if (csr5 & RxDied) { /* Missed a Rx frame. */
- lp->stats.rx_errors++;
- lp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+ tp->stats.rx_errors++;
+ tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
}
if (csr5 & TimerInt) {
printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n",
dev->name, csr5);
/* Hmmmmm, it's not clear what to do here. */
}
+ if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)
+ && tp->chip_id == DC21142) {
+ if (tulip_debug > 1)
+ printk(KERN_INFO"%s: 21142 link change, CSR5 = %8.8x.\n",
+ dev->name, csr5);
+ t21142_lnk_change(dev);
+ }
/* Clear all error sources, included undocumented ones! */
- outl(0x000f7ba, ioaddr + CSR5);
+ outl(0x0800f7ba, ioaddr + CSR5);
}
- if (--boguscnt < 0) {
- printk(KERN_WARNING "%s: Too much work at interrupt, csr5=0x%8.8x.\n",
- dev->name, csr5);
- /* Clear all interrupt sources. */
- outl(0x0001ffff, ioaddr + CSR5);
+ if (--work_budget < 0) {
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Too much work at interrupt, "
+ "csr5=0x%8.8x.\n", dev->name, csr5);
+ /* Acknowledge all interrupt sources. */
+ outl(0x8001ffff, ioaddr + CSR5);
+#ifdef notdef
+ /* Clear all but standard interrupt sources. */
+ outl((~csr5) & 0x0001ebef, ioaddr + CSR7);
+#endif
break;
}
} while (1);
@@ -1969,271 +2344,83 @@
printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
dev->name, inl(ioaddr + CSR5));
- /* 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
- }
- }
-
dev->interrupt = 0;
+ clear_bit(0, (void*)&tp->interrupt);
return;
}
-#ifdef CONFIG_NET_FASTROUTE
-/* DMAing cards are the most easy in this respect,
- they are able to make fast route to any device.
-
- Now we allow to make it only to another ethernet card.
- */
-static int tulip_accept_fastpath(struct device *dev, struct dst_entry *dst)
-{
- struct device *odev = dst->dev;
-
- if (dst->ops->protocol != __constant_htons(ETH_P_IP))
- return -1;
- if (odev->type != ARPHRD_ETHER || odev->accept_fastpath == NULL)
- return -1;
-
- return 0;
-}
-
-/*
- Return values:
-
- 0 - packet has gone by fast path.
- 1 - fast path is OK, but device deferred xmit. (semifast path)
-
- 2 - fast path is hit, but packet is a bit strange. (NI)
- 3 - oom
-
- 4 - fast path miss.
- */
-
-static int tulip_fast_forward(struct device *dev, int entry, int len)
-{
- struct tulip_private *lp = (struct tulip_private *)dev->priv;
- struct sk_buff *skb = lp->rx_skbuff[entry];
- struct ethhdr *eth = (void*)skb->data;
-
- if (eth->h_proto == __constant_htons(ETH_P_IP)) {
- struct rtable *rt;
- struct iphdr *iph;
- unsigned h;
-
- iph = (struct iphdr*)(skb->data + ETH_HLEN);
- h = (*(u8*)&iph->daddr^*(u8*)&iph->saddr)&NETDEV_FASTROUTE_HMASK;
- rt = (struct rtable*)(dev->fastpath[h]);
- if (rt &&
- ((u16*)&iph->daddr)[0] == ((u16*)&rt->key.dst)[0] &&
- ((u16*)&iph->daddr)[1] == ((u16*)&rt->key.dst)[1] &&
- ((u16*)&iph->saddr)[0] == ((u16*)&rt->key.src)[0] &&
- ((u16*)&iph->saddr)[1] == ((u16*)&rt->key.src)[1] &&
- rt->u.dst.obsolete == 0) {
- struct device *odev = rt->u.dst.dev;
-
- dev_fastroute_stat.hits++;
-
- if (*(u8*)iph != 0x45 ||
- (eth->h_dest[0]&1) ||
- !neigh_is_valid(rt->u.dst.neighbour) ||
- iph->ttl <= 1)
- goto alas2;
-
- ip_decrease_ttl(iph);
-
- if (1) {
- struct sk_buff *skb2 = DEV_ALLOC_SKB(PKT_BUF_SZ);
- if (skb2 == NULL)
- goto oom;
- lp->rx_ring[entry].buffer1 = virt_to_bus(skb2->tail);
- skb2->dev = dev;
- lp->rx_skbuff[entry] = skb2;
- }
-
- skb_put(skb, len);
-
- ip_statistics.IpInReceives++;
- ip_statistics.IpForwDatagrams++;
-
- /* Could use hh cache */
- memcpy(eth->h_source, odev->dev_addr, 6);
- memcpy(eth->h_dest, rt->u.dst.neighbour->ha, 6);
- skb->dev = odev;
-
-#ifdef FAST_SKB_RECYCLE /* DO NOT DEFINE IT! READ COMMENT */
- /* We could use fast buffer recycling here if odev
- is not DMAing.
-
- The only problem is that we must allocate skb2
- BEFORE we lose skb, otherwise we would make hole in
- tulip rx array. Hence, to implement FAST_SKB_RECYCLE
- we need always keep at least one skb in a safe place.
- */
- atomic_inc(&skb->users);
-#endif
-
- if (odev->tx_semaphore &&
- odev->tbusy == 0 &&
- odev->interrupt == 0 &&
- odev->hard_start_xmit(skb, odev) == 0) {
-#ifdef FAST_SKB_RECYCLE
- if (atomic_read(&skb->users) == 1) {
- skb->tail = skb->data;
- skb->len = 0;
- }
-#endif
- dev_fastroute_stat.succeed++;
- return 0;
- }
-#ifdef FAST_SKB_RECYCLE
- atomic_dec(&skb->users);
-#endif
-
- /* Otherwise... */
- skb->pkt_type = PACKET_FASTROUTE;
- skb->nh.raw = skb->data + ETH_HLEN;
- skb->protocol = __constant_htons(ETH_P_IP);
- dev_fastroute_stat.deferred++;
- return 1;
- }
- }
- return 4;
-
-oom:
- return 3;
-
-alas2:
-#ifdef not_yet
- skb->dst = dst_clone(&rt->u.dst);
- return 2;
-#else
- return 4;
-#endif
-}
-#endif
-
static int
tulip_rx(struct device *dev)
{
- struct tulip_private *lp = (struct tulip_private *)dev->priv;
- int entry = lp->cur_rx % RX_RING_SIZE;
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ int entry = tp->cur_rx % RX_RING_SIZE;
+ int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+ int work_done = 0;
if (tulip_debug > 4)
printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
- lp->rx_ring[entry].status);
+ tp->rx_ring[entry].status);
/* If we own the next entry, it's a new packet. Send it up. */
- while (lp->rx_ring[entry].status >= 0) {
- int status = lp->rx_ring[entry].status;
+ while (tp->rx_ring[entry].status >= 0) {
+ s32 status = tp->rx_ring[entry].status;
+ if (--rx_work_limit < 0)
+ break;
if ((status & 0x0300) != 0x0300) {
if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */
- printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
- "multiple buffers, status %8.8x!\n", dev->name, status);
- lp->stats.rx_length_errors++;
+ if (tulip_debug > 1)
+ printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
+ "multiple buffers, status %8.8x!\n",
+ dev->name, status);
+ tp->stats.rx_length_errors++;
}
} else if (status & 0x8000) {
/* There was a fatal error. */
- lp->stats.rx_errors++; /* end of a packet.*/
- if (status & 0x0890) lp->stats.rx_length_errors++;
- if (status & 0x0004) lp->stats.rx_frame_errors++;
- if (status & 0x0002) lp->stats.rx_crc_errors++;
- if (status & 0x0001) lp->stats.rx_fifo_errors++;
+ 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++;
+ if (status & 0x0002) tp->stats.rx_crc_errors++;
+ if (status & 0x0001) tp->stats.rx_fifo_errors++;
} else {
- /* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */
- short pkt_len = (lp->rx_ring[entry].status >> 16) - 4;
+ short pkt_len = (status >> 16) - 4;
struct sk_buff *skb;
- int rx_in_place = 0;
-
-#ifdef CONFIG_NET_HW_FLOWCONTROL
- if (netdev_dropping)
- goto throttle;
-#endif
- skb = lp->rx_skbuff[entry];
-
-#ifdef CONFIG_NET_FASTROUTE
- switch (tulip_fast_forward(dev, entry, pkt_len)) {
- case 0:
- goto gone;
- case 1:
- goto semi_gone;
- case 2:
- break;
- case 3:
- skb = NULL;
- goto memory_squeeze;
- }
-#endif
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */
- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
- char *temp;
-
- /* Get a fresh skbuff to replace the filled one. */
- newskb = DEV_ALLOC_SKB(PKT_BUF_SZ);
- if (newskb == NULL) {
- skb = NULL; /* No memory, drop the packet. */
- goto memory_squeeze;
- }
- /* Pass up the skb already on the Rx ring. */
- temp = skb_put(skb, pkt_len);
- if (bus_to_virt(lp->rx_ring[entry].buffer1) != temp)
- printk(KERN_ERR "%s: Internal consistency error -- the "
- "skbuff addresses do not match"
- " in tulip_rx: %p vs. %p / %p.\n", dev->name,
- bus_to_virt(lp->rx_ring[entry].buffer1),
- skb->head, temp);
- rx_in_place = 1;
- lp->rx_skbuff[entry] = newskb;
- newskb->dev = dev;
- /* Longword alignment required: do not skb_reserve(2)! */
- lp->rx_ring[entry].buffer1 = virt_to_bus(newskb->tail);
- } else
- skb = DEV_ALLOC_SKB(pkt_len + 2);
-memory_squeeze:
- if (skb == NULL) {
- int i;
- printk(KERN_WARNING "%s: Memory squeeze, deferring packet.\n",
- dev->name);
- /* Check that at least two ring entries are free.
- If not, free one and mark stats->rx_dropped++. */
- for (i = 0; i < RX_RING_SIZE; i++)
- if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0)
- break;
-
- if (i > RX_RING_SIZE -2) {
- lp->stats.rx_dropped++;
- lp->rx_ring[entry].status = 0x80000000;
- lp->cur_rx++;
- }
- break;
- }
- skb->dev = dev;
- if (! rx_in_place) {
- skb_reserve(skb, 2); /* 16 byte align the data fields */
-#if LINUX_VERSION_CODE < 0x20200 || defined(__alpha__)
+ if (pkt_len < rx_copybreak
+ && (skb = DEV_ALLOC_SKB(pkt_len+2)) != NULL) {
+ skb->dev = dev;
+ skb_reserve(skb, 2); /* 16 byte align the IP header */
+#if LINUX_VERSION_CODE < 0x10300
+ memcpy(skb->data, tp->rx_ring[entry].buffer1, pkt_len);
+#elif LINUX_VERSION_CODE < 0x20200 || defined(__alpha__)
memcpy(skb_put(skb, pkt_len),
- bus_to_virt(lp->rx_ring[entry].buffer1), pkt_len);
+ bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
#else
-#ifdef ORIGINAL_TEXT
#warning Code untested
-#else
-#error Code is wrong, and it has nothing to do with 2.2 :-)
+ eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
+ pkt_len, 0);
+ skb_put(skb, pkt_len);
#endif
- eth_copy_and_sum(skb, bus_to_virt(lp->rx_ring[entry].buffer1),
- pkt_len, 0);
+ work_done++;
+ } else { /* Pass up the skb already on the Rx ring. */
+ skb = tp->rx_skbuff[entry];
+ tp->rx_skbuff[entry] = NULL;
+#ifndef final_version
+ {
+ void *temp = skb_put(skb, pkt_len);
+ if (bus_to_virt(tp->rx_ring[entry].buffer1) != temp)
+ printk(KERN_ERR "%s: Internal consistency error! The "
+ "skbuff addresses do not match in tulip_rx:"
+ " %p vs. %p / %p.\n", dev->name,
+ bus_to_virt(tp->rx_ring[entry].buffer1),
+ skb->head, temp);
+ }
+#else
skb_put(skb, pkt_len);
#endif
}
@@ -2242,56 +2429,48 @@
#else
skb->len = pkt_len;
#endif
-#ifdef CONFIG_NET_FASTROUTE
-semi_gone:
-#endif
netif_rx(skb);
-#ifdef CONFIG_NET_HW_FLOWCONTROL
- if (netdev_dropping) {
-throttle:
- if (lp->fc_bit) {
- outl(lp->csr6 | 0x2000, dev->base_addr + CSR6);
- set_bit(lp->fc_bit, &netdev_fc_xoff);
- }
- }
-#endif
-#ifdef CONFIG_NET_FASTROUTE
-gone:
-#endif
- lp->stats.rx_packets++;
-#ifndef ORIGINAL_TEXT
- lp->stats.rx_bytes += pkt_len;
+ dev->last_rx = jiffies;
+ tp->stats.rx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+ tp->stats.rx_bytes += pkt_len;
#endif
}
+ entry = (++tp->cur_rx) % RX_RING_SIZE;
+ }
- lp->rx_ring[entry].status = 0x80000000;
- entry = (++lp->cur_rx) % RX_RING_SIZE;
+ /* Refill the Rx ring buffers. */
+ for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+ entry = tp->dirty_rx % RX_RING_SIZE;
+ if (tp->rx_skbuff[entry] == NULL) {
+ struct sk_buff *skb;
+ skb = tp->rx_skbuff[entry] = DEV_ALLOC_SKB(PKT_BUF_SZ);
+ if (skb == NULL)
+ break;
+ skb->dev = dev; /* Mark as being used by this device. */
+#if LINUX_VERSION_CODE > 0x10300
+ tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+#else
+ tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data);
+#endif
+ work_done++;
+ }
+ tp->rx_ring[entry].status = 0x80000000;
}
- return 0;
+ return work_done;
}
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;
-#ifdef CONFIG_NET_FASTROUTE
- dev->tx_semaphore = 0;
-#endif
dev->start = 0;
dev->tbusy = 1;
-#ifdef CONFIG_NET_HW_FLOWCONTROL
- if (tp->fc_bit) {
- int bit = tp->fc_bit;
- tp->fc_bit = 0;
- netdev_unregister_fc(bit);
- }
-#endif
-
if (tulip_debug > 1)
printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, inl(ioaddr + CSR5));
@@ -2326,12 +2505,20 @@
#if LINUX_VERSION_CODE < 0x20100
skb->free = 1;
#endif
+#if (LINUX_VERSION_CODE > 0x20155)
dev_kfree_skb(skb);
+#else
+ dev_kfree_skb(skb, FREE_WRITE);
+#endif
}
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (tp->tx_skbuff[i])
+#if (LINUX_VERSION_CODE > 0x20155)
dev_kfree_skb(tp->tx_skbuff[i]);
+#else
+ dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);
+#endif
tp->tx_skbuff[i] = 0;
}
@@ -2345,7 +2532,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;
@@ -2353,6 +2540,71 @@
return &tp->stats;
}
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+ struct tulip_private *tp = (struct tulip_private *)dev->priv;
+ long ioaddr = dev->base_addr;
+ u16 *data = (u16 *)&rq->ifr_data;
+ int phy = tp->phys[0] & 0x1f;
+ long flags;
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ if (tp->mtable && tp->mtable->has_mii)
+ data[0] = phy;
+ else if (tp->chip_id == DC21142)
+ data[0] = 32;
+ else
+ return -ENODEV;
+ return 0;
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ if (data[0] == 32) { /* 21142 pseudo-MII */
+ int csr12 = inl(ioaddr + CSR12);
+ int csr14 = inl(ioaddr + CSR14);
+ switch (data[1]) {
+ case 0: {
+ data[3] = ((csr14<<13)&0x4000) + ((csr14<<5)&0x1000);
+ break; }
+ case 1:
+ data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+ + (csr12&0x06 ? 0x04 : 0);
+ break;
+ case 4: {
+ int csr14 = inl(ioaddr + CSR14);
+ data[3] = ((csr14>>9)&0x0380) + ((csr14>>1)&0x20) + 1;
+ break;
+ }
+ case 5: data[3] = inl(ioaddr + CSR12) >> 16; break;
+ default: data[3] = 0; break;
+ }
+ } else {
+ save_flags(flags);
+ cli();
+ data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+ restore_flags(flags);
+ }
+ return 0;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+ if (!suser())
+ return -EPERM;
+ if (data[0] == 32) { /* 21142 pseudo-MII */
+ } else {
+ save_flags(flags);
+ cli();
+ mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ restore_flags(flags);
+ }
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return -EOPNOTSUPP;
+}
+#endif /* HAVE_PRIVATE_IOCTL */
+
/* Set or clear the multicast filter for this adaptor.
Note that we only use exclusion around actually queueing the
new frame, not around filling tp->setup_frame. This is non-deterministic
@@ -2380,12 +2632,12 @@
}
#ifdef NEW_MULTICAST
-static void set_multicast_list(struct device *dev)
+static void set_rx_mode(struct device *dev)
#else
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+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;
@@ -2442,9 +2694,9 @@
}
eaddrs = (u16 *)dev->dev_addr;
do {
- *setup_frm++ = eaddrs[0];
- *setup_frm++ = eaddrs[1];
- *setup_frm++ = eaddrs[2];
+ *setup_frm++ = eaddrs[0];
+ *setup_frm++ = eaddrs[1];
+ *setup_frm++ = eaddrs[2];
} while (++i < 15);
/* Now add this frame to the Tx list. */
if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
@@ -2457,19 +2709,19 @@
entry = tp->cur_tx++ % TX_RING_SIZE;
if (entry != 0) {
- /* Avoid a chip errata by prefixing a dummy entry. */
- tp->tx_skbuff[entry] = 0;
- tp->tx_ring[entry].length =
- (entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
- tp->tx_ring[entry].buffer1 = 0;
- tp->tx_ring[entry].status = 0x80000000;
- entry = tp->cur_tx++ % TX_RING_SIZE;
+ /* Avoid a chip errata by prefixing a dummy entry. */
+ tp->tx_skbuff[entry] = 0;
+ tp->tx_ring[entry].length =
+ (entry == TX_RING_SIZE-1) ? 0x02000000 : 0;
+ tp->tx_ring[entry].buffer1 = 0;
+ tp->tx_ring[entry].status = 0x80000000;
+ entry = tp->cur_tx++ % TX_RING_SIZE;
}
tp->tx_skbuff[entry] = 0;
/* Put the setup frame on the Tx list. */
if (entry == TX_RING_SIZE-1)
- tx_flags |= 0x02000000; /* Wrap ring. */
+ tx_flags |= 0x02000000; /* Wrap ring. */
tp->tx_ring[entry].length = tx_flags;
tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
tp->tx_ring[entry].status = 0x80000000;
@@ -2485,15 +2737,69 @@
}
}
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static dev_node_t *tulip_attach(dev_locator_t *loc)
+{
+ u16 dev_id;
+ u32 io;
+ u8 bus, devfn;
+ struct device *dev;
+
+ if (loc->bus != LOC_PCI) return NULL;
+ bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+ printk(KERN_INFO "tulip_attach(bus %d, function %d)\n", bus, devfn);
+ 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, DC21142, -1);
+ if (dev) {
+ dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+ strcpy(node->dev_name, dev->name);
+ node->major = node->minor = 0;
+ node->next = NULL;
+ MOD_INC_USE_COUNT;
+ return node;
+ }
+ return NULL;
+}
+
+static void tulip_detach(dev_node_t *node)
+{
+ struct device **devp, **next;
+ printk(KERN_INFO "tulip_detach(%s)\n", node->dev_name);
+ for (devp = &root_tulip_dev; *devp; devp = next) {
+ next = &((struct tulip_private *)(*devp)->priv)->next_module;
+ if (strcmp((*devp)->name, node->dev_name) == 0) break;
+ }
+ if (*devp) {
+ unregister_netdev(*devp);
+ kfree(*devp);
+ *devp = *next;
+ kfree(node);
+ MOD_DEC_USE_COUNT;
+ }
+}
+
+struct driver_operations tulip_ops = {
+ "tulip_cb", tulip_attach, NULL, NULL, tulip_detach
+};
+
+#endif /* Cardbus support */
+
+
#ifdef MODULE
#if LINUX_VERSION_CODE > 0x20118
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(reverse_probe, "i");
MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
#endif
/* An additional parameter that may be passed in... */
@@ -2505,8 +2811,12 @@
if (debug >= 0)
tulip_debug = debug;
- root_tulip_dev = NULL;
+#ifdef CARDBUS
+ register_driver(&tulip_ops);
+ return 0;
+#else
return tulip_probe(NULL);
+#endif
}
void
@@ -2514,6 +2824,10 @@
{
struct device *next_dev;
+#ifdef CARDBUS
+ unregister_driver(&tulip_ops);
+#endif
+
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
while (root_tulip_dev) {
next_dev = ((struct tulip_private *)root_tulip_dev->priv)->next_module;
@@ -2528,7 +2842,8 @@
/*
* Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov