Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,21 @@
#
# Digital Equipment Inc network device configuration
#
config NET_VENDOR_DEC
bool "Digital Equipment devices"
default y
depends on PCI || EISA || CARDBUS
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about DEC cards. If you say Y, you will be asked for
your specific card in the following questions.
if NET_VENDOR_DEC
source "drivers/net/ethernet/dec/tulip/Kconfig"
endif # NET_VENDOR_DEC

View file

@ -0,0 +1,5 @@
#
# Makefile for the Digital Equipment Inc. network device drivers.
#
obj-$(CONFIG_NET_TULIP) += tulip/

View file

@ -0,0 +1,257 @@
/*
drivers/net/ethernet/dec/tulip/21142.c
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
DC21143 manual "21143 PCI/CardBus 10/100Mb/s Ethernet LAN Controller
Hardware Reference Manual" is currently available at :
http://developer.intel.com/design/network/manuals/278074.htm
Please submit bugs to http://bugzilla.kernel.org/ .
*/
#include <linux/delay.h>
#include "tulip.h"
static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
of available transceivers. */
void t21142_media_task(struct work_struct *work)
{
struct tulip_private *tp =
container_of(work, struct tulip_private, media_work);
struct net_device *dev = tp->dev;
void __iomem *ioaddr = tp->base_addr;
int csr12 = ioread32(ioaddr + CSR12);
int next_tick = 60*HZ;
int new_csr6 = 0;
int csr14 = ioread32(ioaddr + CSR14);
/* CSR12[LS10,LS100] are not reliable during autonegotiation */
if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000)
csr12 |= 6;
if (tulip_debug > 2)
dev_info(&dev->dev, "21143 negotiation status %08x, %s\n",
csr12, medianame[dev->if_port]);
if (tulip_media_cap[dev->if_port] & MediaIsMII) {
if (tulip_check_duplex(dev) < 0) {
netif_carrier_off(dev);
next_tick = 3*HZ;
} else {
netif_carrier_on(dev);
next_tick = 60*HZ;
}
} else if (tp->nwayset) {
/* Don't screw up a negotiated session! */
if (tulip_debug > 1)
dev_info(&dev->dev,
"Using NWay-set %s media, csr12 %08x\n",
medianame[dev->if_port], csr12);
} else if (tp->medialock) {
;
} else if (dev->if_port == 3) {
if (csr12 & 2) { /* No 100mbps link beat, revert to 10mbps. */
if (tulip_debug > 1)
dev_info(&dev->dev,
"No 21143 100baseTx link beat, %08x, trying NWay\n",
csr12);
t21142_start_nway(dev);
next_tick = 3*HZ;
}
} else if ((csr12 & 0x7000) != 0x5000) {
/* Negotiation failed. Search media types. */
if (tulip_debug > 1)
dev_info(&dev->dev,
"21143 negotiation failed, status %08x\n",
csr12);
if (!(csr12 & 4)) { /* 10mbps link beat good. */
new_csr6 = 0x82420000;
dev->if_port = 0;
iowrite32(0, ioaddr + CSR13);
iowrite32(0x0003FFFF, ioaddr + CSR14);
iowrite16(t21142_csr15[dev->if_port], ioaddr + CSR15);
iowrite32(t21142_csr13[dev->if_port], ioaddr + CSR13);
} else {
/* Select 100mbps port to check for link beat. */
new_csr6 = 0x83860000;
dev->if_port = 3;
iowrite32(0, ioaddr + CSR13);
iowrite32(0x0003FFFF, ioaddr + CSR14);
iowrite16(8, ioaddr + CSR15);
iowrite32(1, ioaddr + CSR13);
}
if (tulip_debug > 1)
dev_info(&dev->dev, "Testing new 21143 media %s\n",
medianame[dev->if_port]);
if (new_csr6 != (tp->csr6 & ~0x00D5)) {
tp->csr6 &= 0x00D5;
tp->csr6 |= new_csr6;
iowrite32(0x0301, ioaddr + CSR12);
tulip_restart_rxtx(tp);
}
next_tick = 3*HZ;
}
/* mod_timer synchronizes us with potential add_timer calls
* from interrupts.
*/
mod_timer(&tp->timer, RUN_AT(next_tick));
}
void t21142_start_nway(struct net_device *dev)
{
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int csr14 = ((tp->sym_advertise & 0x0780) << 9) |
((tp->sym_advertise & 0x0020) << 1) | 0xffbf;
dev->if_port = 0;
tp->nway = tp->mediasense = 1;
tp->nwayset = tp->lpar = 0;
if (tulip_debug > 1)
netdev_dbg(dev, "Restarting 21143 autonegotiation, csr14=%08x\n",
csr14);
iowrite32(0x0001, ioaddr + CSR13);
udelay(100);
iowrite32(csr14, ioaddr + CSR14);
tp->csr6 = 0x82420000 | (tp->sym_advertise & 0x0040 ? FullDuplex : 0);
iowrite32(tp->csr6, ioaddr + CSR6);
if (tp->mtable && tp->mtable->csr15dir) {
iowrite32(tp->mtable->csr15dir, ioaddr + CSR15);
iowrite32(tp->mtable->csr15val, ioaddr + CSR15);
} else
iowrite16(0x0008, ioaddr + CSR15);
iowrite32(0x1301, ioaddr + CSR12); /* Trigger NWAY. */
}
void t21142_lnk_change(struct net_device *dev, int csr5)
{
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int csr12 = ioread32(ioaddr + CSR12);
int csr14 = ioread32(ioaddr + CSR14);
/* CSR12[LS10,LS100] are not reliable during autonegotiation */
if ((csr14 & 0x80) && (csr12 & 0x7000) != 0x5000)
csr12 |= 6;
if (tulip_debug > 1)
dev_info(&dev->dev,
"21143 link status interrupt %08x, CSR5 %x, %08x\n",
csr12, csr5, csr14);
/* If NWay finished and we have a negotiated partner capability. */
if (tp->nway && !tp->nwayset && (csr12 & 0x7000) == 0x5000) {
int setup_done = 0;
int negotiated = tp->sym_advertise & (csr12 >> 16);
tp->lpar = csr12 >> 16;
tp->nwayset = 1;
/* If partner cannot negotiate, it is 10Mbps Half Duplex */
if (!(csr12 & 0x8000)) dev->if_port = 0;
else if (negotiated & 0x0100) dev->if_port = 5;
else if (negotiated & 0x0080) dev->if_port = 3;
else if (negotiated & 0x0040) dev->if_port = 4;
else if (negotiated & 0x0020) dev->if_port = 0;
else {
tp->nwayset = 0;
if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180))
dev->if_port = 3;
}
tp->full_duplex = (tulip_media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0;
if (tulip_debug > 1) {
if (tp->nwayset)
dev_info(&dev->dev,
"Switching to %s based on link negotiation %04x & %04x = %04x\n",
medianame[dev->if_port],
tp->sym_advertise, tp->lpar,
negotiated);
else
dev_info(&dev->dev,
"Autonegotiation failed, using %s, link beat status %04x\n",
medianame[dev->if_port], csr12);
}
if (tp->mtable) {
int i;
for (i = 0; i < tp->mtable->leafcount; i++)
if (tp->mtable->mleaf[i].media == dev->if_port) {
int startup = ! ((tp->chip_id == DC21143 && (tp->revision == 48 || tp->revision == 65)));
tp->cur_index = i;
tulip_select_media(dev, startup);
setup_done = 1;
break;
}
}
if ( ! setup_done) {
tp->csr6 = (dev->if_port & 1 ? 0x838E0000 : 0x82420000) | (tp->csr6 & 0x20ff);
if (tp->full_duplex)
tp->csr6 |= 0x0200;
iowrite32(1, ioaddr + CSR13);
}
#if 0 /* Restart shouldn't be needed. */
iowrite32(tp->csr6 | RxOn, ioaddr + CSR6);
if (tulip_debug > 2)
netdev_dbg(dev, " Restarting Tx and Rx, CSR5 is %08x\n",
ioread32(ioaddr + CSR5));
#endif
tulip_start_rxtx(tp);
if (tulip_debug > 2)
netdev_dbg(dev, " Setting CSR6 %08x/%x CSR12 %08x\n",
tp->csr6, ioread32(ioaddr + CSR6),
ioread32(ioaddr + CSR12));
} else if ((tp->nwayset && (csr5 & 0x08000000) &&
(dev->if_port == 3 || dev->if_port == 5) &&
(csr12 & 2) == 2) ||
(tp->nway && (csr5 & (TPLnkFail)))) {
/* Link blew? Maybe restart NWay. */
del_timer_sync(&tp->timer);
t21142_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
add_timer(&tp->timer);
} else if (dev->if_port == 3 || dev->if_port == 5) {
if (tulip_debug > 1)
dev_info(&dev->dev, "21143 %s link beat %s\n",
medianame[dev->if_port],
(csr12 & 2) ? "failed" : "good");
if ((csr12 & 2) && ! tp->medialock) {
del_timer_sync(&tp->timer);
t21142_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
add_timer(&tp->timer);
} else if (dev->if_port == 5)
iowrite32(csr14 & ~0x080, ioaddr + CSR14);
} else if (dev->if_port == 0 || dev->if_port == 4) {
if ((csr12 & 4) == 0)
dev_info(&dev->dev, "21143 10baseT link beat good\n");
} else if (!(csr12 & 4)) { /* 10mbps link beat good. */
if (tulip_debug)
dev_info(&dev->dev, "21143 10mbps sensed media\n");
dev->if_port = 0;
} else if (tp->nwayset) {
if (tulip_debug)
dev_info(&dev->dev, "21143 using NWay-set %s, csr6 %08x\n",
medianame[dev->if_port], tp->csr6);
} else { /* 100mbps link beat good. */
if (tulip_debug)
dev_info(&dev->dev, "21143 100baseTx sensed media\n");
dev->if_port = 3;
tp->csr6 = 0x838E0000 | (tp->csr6 & 0x20ff);
iowrite32(0x0003FF7F, ioaddr + CSR14);
iowrite32(0x0301, ioaddr + CSR12);
tulip_restart_rxtx(tp);
}
}

View file

@ -0,0 +1,172 @@
#
# Tulip family network device configuration
#
config NET_TULIP
bool "DEC - Tulip devices"
depends on (PCI || EISA || CARDBUS)
---help---
This selects the "Tulip" family of EISA/PCI network cards.
if NET_TULIP
config DE2104X
tristate "Early DECchip Tulip (dc2104x) PCI support"
depends on PCI
select CRC32
---help---
This driver is developed for the SMC EtherPower series Ethernet
cards and also works with cards based on the DECchip
21040 (Tulip series) chips. Some LinkSys PCI cards are
of this type. (If your card is NOT SMC EtherPower 10/100 PCI
(smc9332dst), you can also try the driver for "Generic DECchip"
cards, below. However, most people with a network card of this type
will say Y here.) Do read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module will
be called de2104x.
config DE2104X_DSL
int "Descriptor Skip Length in 32 bit longwords"
depends on DE2104X
range 0 31
default 0
---help---
Setting this value allows to align ring buffer descriptors into their
own cache lines. Value of 4 corresponds to the typical 32 byte line
(the descriptor is 16 bytes). This is necessary on systems that lack
cache coherence, an example is PowerMac 5500. Otherwise 0 is safe.
Default is 0, and range is 0 to 31.
config TULIP
tristate "DECchip Tulip (dc2114x) PCI support"
depends on PCI
select CRC32
---help---
This driver is developed for the SMC EtherPower series Ethernet
cards and also works with cards based on the DECchip
21140 (Tulip series) chips. Some LinkSys PCI cards are
of this type. (If your card is NOT SMC EtherPower 10/100 PCI
(smc9332dst), you can also try the driver for "Generic DECchip"
cards, above. However, most people with a network card of this type
will say Y here.) Do read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here. The module will
be called tulip.
config TULIP_MWI
bool "New bus configuration"
depends on TULIP
---help---
This configures your Tulip card specifically for the card and
system cache line size type you are using.
This is experimental code, not yet tested on many boards.
If unsure, say N.
config TULIP_MMIO
bool "Use PCI shared mem for NIC registers"
depends on TULIP
---help---
Use PCI shared memory for the NIC registers, rather than going through
the Tulip's PIO (programmed I/O ports). Faster, but could produce
obscure bugs if your mainboard has memory controller timing issues.
If in doubt, say N.
config TULIP_NAPI
bool "Use RX polling (NAPI)"
depends on TULIP
---help---
NAPI is a new driver API designed to reduce CPU and interrupt load
when the driver is receiving lots of packets from the card. It is
still somewhat experimental and thus not yet enabled by default.
If your estimated Rx load is 10kpps or more, or if the card will be
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
If in doubt, say N.
config TULIP_NAPI_HW_MITIGATION
bool "Use Interrupt Mitigation"
depends on TULIP_NAPI
---help---
Use HW to reduce RX interrupts. Not strictly necessary since NAPI
reduces RX interrupts by itself. Interrupt mitigation reduces RX
interrupts even at low levels of traffic at the cost of a small
latency.
If in doubt, say Y.
config TULIP_DM910X
def_bool y
depends on TULIP && SPARC
config DE4X5
tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA"
depends on (PCI || EISA)
depends on VIRT_TO_BUS || ALPHA || PPC || SPARC
select CRC32
---help---
This is support for the DIGITAL series of PCI/EISA Ethernet cards.
These include the DE425, DE434, DE435, DE450 and DE500 models. If
you have a network card of this type, say Y and read the
Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. More specific
information is contained in
<file:Documentation/networking/de4x5.txt>.
To compile this driver as a module, choose M here. The module will
be called de4x5.
config WINBOND_840
tristate "Winbond W89c840 Ethernet support"
depends on PCI
select CRC32
select MII
---help---
This driver is for the Winbond W89c840 chip. It also works with
the TX9882 chip on the Compex RL100-ATX board.
More specific information and updates are available from
<http://www.scyld.com/network/drivers.html>.
config DM9102
tristate "Davicom DM910x/DM980x support"
depends on PCI
select CRC32
---help---
This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
Davicom (<http://www.davicom.com.tw/>). If you have such a network
(Ethernet) card, say Y. Some information is contained in the file
<file:Documentation/networking/dmfe.txt>.
To compile this driver as a module, choose M here. The module will
be called dmfe.
config ULI526X
tristate "ULi M526x controller support"
depends on PCI
select CRC32
---help---
This driver is for ULi M5261/M5263 10/100M Ethernet Controller
(<http://www.nvidia.com/page/uli_drivers.html>).
To compile this driver as a module, choose M here. The module will
be called uli526x.
config PCMCIA_XIRCOM
tristate "Xircom CardBus support"
depends on CARDBUS
---help---
This driver is for the Digital "Tulip" Ethernet CardBus adapters.
It should work with most DEC 21*4*-based chips/ethercards, as well
as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and
ASIX.
To compile this driver as a module, choose M here. The module will
be called xircom_cb. If unsure, say N.
endif # NET_TULIP

View file

@ -0,0 +1,19 @@
#
# Makefile for the Linux "Tulip" family network device drivers.
#
ccflags-$(CONFIG_NET_TULIP) := -DDEBUG
obj-$(CONFIG_PCMCIA_XIRCOM) += xircom_cb.o
obj-$(CONFIG_DM9102) += dmfe.o
obj-$(CONFIG_WINBOND_840) += winbond-840.o
obj-$(CONFIG_DE2104X) += de2104x.o
obj-$(CONFIG_TULIP) += tulip.o
obj-$(CONFIG_DE4X5) += de4x5.o
obj-$(CONFIG_ULI526X) += uli526x.o
# Declare multi-part drivers.
tulip-objs := eeprom.o interrupt.o media.o \
timer.o tulip_core.o \
21142.o pnic.o pnic2.o

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,382 @@
/*
drivers/net/ethernet/dec/tulip/eeprom.c
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Please submit bug reports to http://bugzilla.kernel.org/.
*/
#include <linux/pci.h>
#include <linux/slab.h>
#include "tulip.h"
#include <asm/unaligned.h>
/* Serial EEPROM section. */
/* The main routine to parse the very complicated SROM structure.
Search www.digital.com for "21X4 SROM" to get details.
This code is very complex, and will require changes to support
additional cards, so I'll be verbose about what is going on.
*/
/* Known cards that have old-style EEPROMs. */
static struct eeprom_fixup eeprom_fixups[] = {
{"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
{"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
0x0000, 0x009E, /* 10baseT */
0x0004, 0x009E, /* 10baseT-FD */
0x0903, 0x006D, /* 100baseTx */
0x0905, 0x006D, /* 100baseTx-FD */ }},
{"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
0x0107, 0x8021, /* 100baseFx */
0x0108, 0x8021, /* 100baseFx-FD */
0x0100, 0x009E, /* 10baseT */
0x0104, 0x009E, /* 10baseT-FD */
0x0103, 0x006D, /* 100baseTx */
0x0105, 0x006D, /* 100baseTx-FD */ }},
{"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
0x1001, 0x009E, /* 10base2, CSR12 0x10*/
0x0000, 0x009E, /* 10baseT */
0x0004, 0x009E, /* 10baseT-FD */
0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
{"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
0x1B01, 0x0000, /* 10base2, CSR12 0x1B */
0x0B00, 0x009E, /* 10baseT, CSR12 0x0B */
0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
}},
{"NetWinder", 0x00, 0x10, 0x57,
/* Default media = MII
* MII block, reset sequence (3) = 0x0821 0x0000 0x0001, capabilities 0x01e1
*/
{ 0x1e00, 0x0000, 0x000b, 0x8f01, 0x0103, 0x0300, 0x0821, 0x000, 0x0001, 0x0000, 0x01e1 }
},
{"Cobalt Microserver", 0, 0x10, 0xE0, {0x1e00, /* 0 == controller #, 1e == offset */
0x0000, /* 0 == high offset, 0 == gap */
0x0800, /* Default Autoselect */
0x8001, /* 1 leaf, extended type, bogus len */
0x0003, /* Type 3 (MII), PHY #0 */
0x0400, /* 0 init instr, 4 reset instr */
0x0801, /* Set control mode, GP0 output */
0x0000, /* Drive GP0 Low (RST is active low) */
0x0800, /* control mode, GP0 input (undriven) */
0x0000, /* clear control mode */
0x7800, /* 100TX FDX + HDX, 10bT FDX + HDX */
0x01e0, /* Advertise all above */
0x5000, /* FDX all above */
0x1800, /* Set fast TTM in 100bt modes */
0x0000, /* PHY cannot be unplugged */
}},
{NULL}};
static const char *const block_name[] = {
"21140 non-MII",
"21140 MII PHY",
"21142 Serial PHY",
"21142 MII PHY",
"21143 SYM PHY",
"21143 reset method"
};
/**
* tulip_build_fake_mediatable - Build a fake mediatable entry.
* @tp: Ptr to the tulip private data.
*
* Some cards like the 3x5 HSC cards (J3514A) do not have a standard
* srom and can not be handled under the fixup routine. These cards
* still need a valid mediatable entry for correct csr12 setup and
* mii handling.
*
* Since this is currently a parisc-linux specific function, the
* #ifdef __hppa__ should completely optimize this function away for
* non-parisc hardware.
*/
static void tulip_build_fake_mediatable(struct tulip_private *tp)
{
#ifdef CONFIG_GSC
if (tp->flags & NEEDS_FAKE_MEDIA_TABLE) {
static unsigned char leafdata[] =
{ 0x01, /* phy number */
0x02, /* gpr setup sequence length */
0x02, 0x00, /* gpr setup sequence */
0x02, /* phy reset sequence length */
0x01, 0x00, /* phy reset sequence */
0x00, 0x78, /* media capabilities */
0x00, 0xe0, /* nway advertisement */
0x00, 0x05, /* fdx bit map */
0x00, 0x06 /* ttm bit map */
};
tp->mtable = kmalloc(sizeof(struct mediatable) +
sizeof(struct medialeaf), GFP_KERNEL);
if (tp->mtable == NULL)
return; /* Horrible, impossible failure. */
tp->mtable->defaultmedia = 0x800;
tp->mtable->leafcount = 1;
tp->mtable->csr12dir = 0x3f; /* inputs on bit7 for hsc-pci, bit6 for pci-fx */
tp->mtable->has_nonmii = 0;
tp->mtable->has_reset = 0;
tp->mtable->has_mii = 1;
tp->mtable->csr15dir = tp->mtable->csr15val = 0;
tp->mtable->mleaf[0].type = 1;
tp->mtable->mleaf[0].media = 11;
tp->mtable->mleaf[0].leafdata = &leafdata[0];
tp->flags |= HAS_PHY_IRQ;
tp->csr12_shadow = -1;
}
#endif
}
void tulip_parse_eeprom(struct net_device *dev)
{
/*
dev is not registered at this point, so logging messages can't
use dev_<level> or netdev_<level> but dev->name is good via a
hack in the caller
*/
/* The last media info list parsed, for multiport boards. */
static struct mediatable *last_mediatable;
static unsigned char *last_ee_data;
static int controller_index;
struct tulip_private *tp = netdev_priv(dev);
unsigned char *ee_data = tp->eeprom;
int i;
tp->mtable = NULL;
/* Detect an old-style (SA only) EEPROM layout:
memcmp(eedata, eedata+16, 8). */
for (i = 0; i < 8; i ++)
if (ee_data[i] != ee_data[16+i])
break;
if (i >= 8) {
if (ee_data[0] == 0xff) {
if (last_mediatable) {
controller_index++;
pr_info("%s: Controller %d of multiport board\n",
dev->name, controller_index);
tp->mtable = last_mediatable;
ee_data = last_ee_data;
goto subsequent_board;
} else
pr_info("%s: Missing EEPROM, this interface may not work correctly!\n",
dev->name);
return;
}
/* Do a fix-up based on the vendor half of the station address prefix. */
for (i = 0; eeprom_fixups[i].name; i++) {
if (dev->dev_addr[0] == eeprom_fixups[i].addr0 &&
dev->dev_addr[1] == eeprom_fixups[i].addr1 &&
dev->dev_addr[2] == eeprom_fixups[i].addr2) {
if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55)
i++; /* An Accton EN1207, not an outlaw Maxtech. */
memcpy(ee_data + 26, eeprom_fixups[i].newtable,
sizeof(eeprom_fixups[i].newtable));
pr_info("%s: Old format EEPROM on '%s' board. Using substitute media control info\n",
dev->name, eeprom_fixups[i].name);
break;
}
}
if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
pr_info("%s: Old style EEPROM with no media selection information\n",
dev->name);
return;
}
}
controller_index = 0;
if (ee_data[19] > 1) { /* Multiport board. */
last_ee_data = ee_data;
}
subsequent_board:
if (ee_data[27] == 0) { /* No valid media table. */
tulip_build_fake_mediatable(tp);
} else {
unsigned char *p = (void *)ee_data + ee_data[27];
unsigned char csr12dir = 0;
int count, new_advertise = 0;
struct mediatable *mtable;
u16 media = get_u16(p);
p += 2;
if (tp->flags & CSR12_IN_SROM)
csr12dir = *p++;
count = *p++;
/* there is no phy information, don't even try to build mtable */
if (count == 0) {
if (tulip_debug > 0)
pr_warn("%s: no phy info, aborting mtable build\n",
dev->name);
return;
}
mtable = kmalloc(sizeof(struct mediatable) +
count * sizeof(struct medialeaf),
GFP_KERNEL);
if (mtable == NULL)
return; /* Horrible, impossible failure. */
last_mediatable = tp->mtable = mtable;
mtable->defaultmedia = media;
mtable->leafcount = count;
mtable->csr12dir = csr12dir;
mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
mtable->csr15dir = mtable->csr15val = 0;
pr_info("%s: EEPROM default media type %s\n",
dev->name,
media & 0x0800 ? "Autosense"
: medianame[media & MEDIA_MASK]);
for (i = 0; i < count; i++) {
struct medialeaf *leaf = &mtable->mleaf[i];
if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
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] == 0x05) {
mtable->has_reset = i;
leaf->media = p[2] & 0x0f;
} else if (tp->chip_id == DM910X && p[1] == 0x80) {
/* Hack to ignore Davicom delay period block */
mtable->leafcount--;
count--;
i--;
leaf->leafdata = p + 2;
p += (p[0] & 0x3f) + 1;
continue;
} else if (p[1] & 1) {
int gpr_len, reset_len;
mtable->has_mii = 1;
leaf->media = 11;
gpr_len=p[3]*2;
reset_len=p[4+gpr_len]*2;
new_advertise |= get_u16(&p[7+gpr_len+reset_len]);
} else {
mtable->has_nonmii = 1;
leaf->media = p[2] & MEDIA_MASK;
/* Davicom's media number for 100BaseTX is strange */
if (tp->chip_id == DM910X && leaf->media == 1)
leaf->media = 3;
switch (leaf->media) {
case 0: new_advertise |= 0x0020; break;
case 4: new_advertise |= 0x0040; break;
case 3: new_advertise |= 0x0080; break;
case 5: new_advertise |= 0x0100; break;
case 6: new_advertise |= 0x0200; break;
}
if (p[1] == 2 && leaf->media == 0) {
if (p[2] & 0x40) {
u32 base15 = get_unaligned((u16*)&p[7]);
mtable->csr15dir =
(get_unaligned((u16*)&p[9])<<16) + base15;
mtable->csr15val =
(get_unaligned((u16*)&p[11])<<16) + base15;
} else {
mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
}
}
}
leaf->leafdata = p + 2;
p += (p[0] & 0x3f) + 1;
}
if (tulip_debug > 1 && leaf->media == 11) {
unsigned char *bp = leaf->leafdata;
pr_info("%s: MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %02x %02x\n",
dev->name,
bp[0], bp[1], bp[2 + bp[1]*2],
bp[5 + bp[2 + bp[1]*2]*2],
bp[4 + bp[2 + bp[1]*2]*2]);
}
pr_info("%s: Index #%d - Media %s (#%d) described by a %s (%d) block\n",
dev->name,
i, medianame[leaf->media & 15], leaf->media,
leaf->type < ARRAY_SIZE(block_name) ? block_name[leaf->type] : "<unknown>",
leaf->type);
}
if (new_advertise)
tp->sym_advertise = new_advertise;
}
}
/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
#define EE_CS 0x01 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */
#define EE_WRITE_0 0x01
#define EE_WRITE_1 0x05
#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */
#define EE_ENB (0x4800 | EE_CS)
/* Delay between EEPROM clock transitions.
Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
We add a bus turn-around to insure that this remains true. */
#define eeprom_delay() ioread32(ee_addr)
/* The EEPROM commands include the alway-set leading bit. */
#define EE_READ_CMD (6)
/* Note: this routine returns extra data bits for size detection. */
int tulip_read_eeprom(struct net_device *dev, int location, int addr_len)
{
int i;
unsigned retval = 0;
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ee_addr = tp->base_addr + CSR9;
int read_cmd = location | (EE_READ_CMD << addr_len);
/* If location is past the end of what we can address, don't
* read some other location (ie truncate). Just return zero.
*/
if (location > (1 << addr_len) - 1)
return 0;
iowrite32(EE_ENB & ~EE_CS, ee_addr);
iowrite32(EE_ENB, ee_addr);
/* Shift the read command bits out. */
for (i = 4 + addr_len; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
iowrite32(EE_ENB | dataval, ee_addr);
eeprom_delay();
iowrite32(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
retval = (retval << 1) | ((ioread32(ee_addr) & EE_DATA_READ) ? 1 : 0);
}
iowrite32(EE_ENB, ee_addr);
eeprom_delay();
for (i = 16; i > 0; i--) {
iowrite32(EE_ENB | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
retval = (retval << 1) | ((ioread32(ee_addr) & EE_DATA_READ) ? 1 : 0);
iowrite32(EE_ENB, ee_addr);
eeprom_delay();
}
/* Terminate the EEPROM access. */
iowrite32(EE_ENB & ~EE_CS, ee_addr);
return (tp->flags & HAS_SWAPPED_SEEPROM) ? swab16(retval) : retval;
}

View file

@ -0,0 +1,814 @@
/*
drivers/net/ethernet/dec/tulip/interrupt.c
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Please submit bugs to http://bugzilla.kernel.org/ .
*/
#include <linux/pci.h>
#include "tulip.h"
#include <linux/etherdevice.h>
int tulip_rx_copybreak;
unsigned int tulip_max_interrupt_work;
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
#define MIT_SIZE 15
#define MIT_TABLE 15 /* We use 0 or max */
static unsigned int mit_table[MIT_SIZE+1] =
{
/* CRS11 21143 hardware Mitigation Control Interrupt
We use only RX mitigation we other techniques for
TX intr. mitigation.
31 Cycle Size (timer control)
30:27 TX timer in 16 * Cycle size
26:24 TX No pkts before Int.
23:20 RX timer in Cycle size
19:17 RX No pkts before Int.
16 Continues Mode (CM)
*/
0x0, /* IM disabled */
0x80150000, /* RX time = 1, RX pkts = 2, CM = 1 */
0x80150000,
0x80270000,
0x80370000,
0x80490000,
0x80590000,
0x80690000,
0x807B0000,
0x808B0000,
0x809D0000,
0x80AD0000,
0x80BD0000,
0x80CF0000,
0x80DF0000,
// 0x80FF0000 /* RX time = 16, RX pkts = 7, CM = 1 */
0x80F10000 /* RX time = 16, RX pkts = 0, CM = 1 */
};
#endif
int tulip_refill_rx(struct net_device *dev)
{
struct tulip_private *tp = netdev_priv(dev);
int entry;
int refilled = 0;
/* 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_buffers[entry].skb == NULL) {
struct sk_buff *skb;
dma_addr_t mapping;
skb = tp->rx_buffers[entry].skb =
netdev_alloc_skb(dev, PKT_BUF_SZ);
if (skb == NULL)
break;
mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
if (dma_mapping_error(&tp->pdev->dev, mapping)) {
dev_kfree_skb(skb);
tp->rx_buffers[entry].skb = NULL;
break;
}
tp->rx_buffers[entry].mapping = mapping;
tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping);
refilled++;
}
tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
}
if(tp->chip_id == LC82C168) {
if(((ioread32(tp->base_addr + CSR5)>>17)&0x07) == 4) {
/* Rx stopped due to out of buffers,
* restart it
*/
iowrite32(0x01, tp->base_addr + CSR2);
}
}
return refilled;
}
#ifdef CONFIG_TULIP_NAPI
void oom_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct tulip_private *tp = netdev_priv(dev);
napi_schedule(&tp->napi);
}
int tulip_poll(struct napi_struct *napi, int budget)
{
struct tulip_private *tp = container_of(napi, struct tulip_private, napi);
struct net_device *dev = tp->dev;
int entry = tp->cur_rx % RX_RING_SIZE;
int work_done = 0;
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
int received = 0;
#endif
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
/* that one buffer is needed for mit activation; or might be a
bug in the ring buffer code; check later -- JHS*/
if (budget >=RX_RING_SIZE) budget--;
#endif
if (tulip_debug > 4)
netdev_dbg(dev, " In tulip_rx(), entry %d %08x\n",
entry, tp->rx_ring[entry].status);
do {
if (ioread32(tp->base_addr + CSR5) == 0xffffffff) {
netdev_dbg(dev, " In tulip_poll(), hardware disappeared\n");
break;
}
/* Acknowledge current RX interrupt sources. */
iowrite32((RxIntr | RxNoBuf), tp->base_addr + CSR5);
/* If we own the next entry, it is a new packet. Send it up. */
while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
s32 status = le32_to_cpu(tp->rx_ring[entry].status);
short pkt_len;
if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
break;
if (tulip_debug > 5)
netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
entry, status);
if (++work_done >= budget)
goto not_done;
/*
* Omit the four octet CRC from the length.
* (May not be considered valid until we have
* checked status for RxLengthOver2047 bits)
*/
pkt_len = ((status >> 16) & 0x7ff) - 4;
/*
* Maximum pkt_len is 1518 (1514 + vlan header)
* Anything higher than this is always invalid
* regardless of RxLengthOver2047 bits
*/
if ((status & (RxLengthOver2047 |
RxDescCRCError |
RxDescCollisionSeen |
RxDescRunt |
RxDescDescErr |
RxWholePkt)) != RxWholePkt ||
pkt_len > 1518) {
if ((status & (RxLengthOver2047 |
RxWholePkt)) != RxWholePkt) {
/* Ingore earlier buffers. */
if ((status & 0xffff) != 0x7fff) {
if (tulip_debug > 1)
dev_warn(&dev->dev,
"Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
status);
dev->stats.rx_length_errors++;
}
} else {
/* There was a fatal error. */
if (tulip_debug > 2)
netdev_dbg(dev, "Receive error, Rx status %08x\n",
status);
dev->stats.rx_errors++; /* end of a packet.*/
if (pkt_len > 1518 ||
(status & RxDescRunt))
dev->stats.rx_length_errors++;
if (status & 0x0004)
dev->stats.rx_frame_errors++;
if (status & 0x0002)
dev->stats.rx_crc_errors++;
if (status & 0x0001)
dev->stats.rx_fifo_errors++;
}
} else {
struct sk_buff *skb;
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
if (pkt_len < tulip_rx_copybreak &&
(skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) {
skb_reserve(skb, 2); /* 16 byte align the IP header */
pci_dma_sync_single_for_cpu(tp->pdev,
tp->rx_buffers[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
#if ! defined(__alpha__)
skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data,
pkt_len);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
tp->rx_buffers[entry].skb->data,
pkt_len);
#endif
pci_dma_sync_single_for_device(tp->pdev,
tp->rx_buffers[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
} else { /* Pass up the skb already on the Rx ring. */
char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
pkt_len);
#ifndef final_version
if (tp->rx_buffers[entry].mapping !=
le32_to_cpu(tp->rx_ring[entry].buffer1)) {
dev_err(&dev->dev,
"Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n",
le32_to_cpu(tp->rx_ring[entry].buffer1),
(unsigned long long)tp->rx_buffers[entry].mapping,
skb->head, temp);
}
#endif
pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping,
PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
tp->rx_buffers[entry].skb = NULL;
tp->rx_buffers[entry].mapping = 0;
}
skb->protocol = eth_type_trans(skb, dev);
netif_receive_skb(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
}
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
received++;
#endif
entry = (++tp->cur_rx) % RX_RING_SIZE;
if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4)
tulip_refill_rx(dev);
}
/* New ack strategy... irq does not ack Rx any longer
hopefully this helps */
/* Really bad things can happen here... If new packet arrives
* and an irq arrives (tx or just due to occasionally unset
* mask), it will be acked by irq handler, but new thread
* is not scheduled. It is major hole in design.
* No idea how to fix this if "playing with fire" will fail
* tomorrow (night 011029). If it will not fail, we won
* finally: amount of IO did not increase at all. */
} while ((ioread32(tp->base_addr + CSR5) & RxIntr));
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
/* We use this simplistic scheme for IM. It's proven by
real life installations. We can have IM enabled
continuesly but this would cause unnecessary latency.
Unfortunely we can't use all the NET_RX_* feedback here.
This would turn on IM for devices that is not contributing
to backlog congestion with unnecessary latency.
We monitor the device RX-ring and have:
HW Interrupt Mitigation either ON or OFF.
ON: More then 1 pkt received (per intr.) OR we are dropping
OFF: Only 1 pkt received
Note. We only use min and max (0, 15) settings from mit_table */
if( tp->flags & HAS_INTR_MITIGATION) {
if( received > 1 ) {
if( ! tp->mit_on ) {
tp->mit_on = 1;
iowrite32(mit_table[MIT_TABLE], tp->base_addr + CSR11);
}
}
else {
if( tp->mit_on ) {
tp->mit_on = 0;
iowrite32(0, tp->base_addr + CSR11);
}
}
}
#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */
tulip_refill_rx(dev);
/* If RX ring is not full we are out of memory. */
if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
goto oom;
/* Remove us from polling list and enable RX intr. */
napi_complete(napi);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7);
/* The last op happens after poll completion. Which means the following:
* 1. it can race with disabling irqs in irq handler
* 2. it can race with dise/enabling irqs in other poll threads
* 3. if an irq raised after beginning loop, it will be immediately
* triggered here.
*
* Summarizing: the logic results in some redundant irqs both
* due to races in masking and due to too late acking of already
* processed irqs. But it must not result in losing events.
*/
return work_done;
not_done:
if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
tulip_refill_rx(dev);
if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
goto oom;
return work_done;
oom: /* Executed with RX ints disabled */
/* Start timer, stop polling, but do not enable rx interrupts. */
mod_timer(&tp->oom_timer, jiffies+1);
/* Think: timer_pending() was an explicit signature of bug.
* Timer can be pending now but fired and completed
* before we did napi_complete(). See? We would lose it. */
/* remove ourselves from the polling list */
napi_complete(napi);
return work_done;
}
#else /* CONFIG_TULIP_NAPI */
static int tulip_rx(struct net_device *dev)
{
struct tulip_private *tp = netdev_priv(dev);
int entry = tp->cur_rx % RX_RING_SIZE;
int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
int received = 0;
if (tulip_debug > 4)
netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
entry, tp->rx_ring[entry].status);
/* If we own the next entry, it is a new packet. Send it up. */
while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
s32 status = le32_to_cpu(tp->rx_ring[entry].status);
short pkt_len;
if (tulip_debug > 5)
netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
entry, status);
if (--rx_work_limit < 0)
break;
/*
Omit the four octet CRC from the length.
(May not be considered valid until we have
checked status for RxLengthOver2047 bits)
*/
pkt_len = ((status >> 16) & 0x7ff) - 4;
/*
Maximum pkt_len is 1518 (1514 + vlan header)
Anything higher than this is always invalid
regardless of RxLengthOver2047 bits
*/
if ((status & (RxLengthOver2047 |
RxDescCRCError |
RxDescCollisionSeen |
RxDescRunt |
RxDescDescErr |
RxWholePkt)) != RxWholePkt ||
pkt_len > 1518) {
if ((status & (RxLengthOver2047 |
RxWholePkt)) != RxWholePkt) {
/* Ingore earlier buffers. */
if ((status & 0xffff) != 0x7fff) {
if (tulip_debug > 1)
netdev_warn(dev,
"Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
status);
dev->stats.rx_length_errors++;
}
} else {
/* There was a fatal error. */
if (tulip_debug > 2)
netdev_dbg(dev, "Receive error, Rx status %08x\n",
status);
dev->stats.rx_errors++; /* end of a packet.*/
if (pkt_len > 1518 ||
(status & RxDescRunt))
dev->stats.rx_length_errors++;
if (status & 0x0004)
dev->stats.rx_frame_errors++;
if (status & 0x0002)
dev->stats.rx_crc_errors++;
if (status & 0x0001)
dev->stats.rx_fifo_errors++;
}
} else {
struct sk_buff *skb;
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
if (pkt_len < tulip_rx_copybreak &&
(skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) {
skb_reserve(skb, 2); /* 16 byte align the IP header */
pci_dma_sync_single_for_cpu(tp->pdev,
tp->rx_buffers[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
#if ! defined(__alpha__)
skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data,
pkt_len);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
tp->rx_buffers[entry].skb->data,
pkt_len);
#endif
pci_dma_sync_single_for_device(tp->pdev,
tp->rx_buffers[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
} else { /* Pass up the skb already on the Rx ring. */
char *temp = skb_put(skb = tp->rx_buffers[entry].skb,
pkt_len);
#ifndef final_version
if (tp->rx_buffers[entry].mapping !=
le32_to_cpu(tp->rx_ring[entry].buffer1)) {
dev_err(&dev->dev,
"Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %Lx %p / %p\n",
le32_to_cpu(tp->rx_ring[entry].buffer1),
(long long)tp->rx_buffers[entry].mapping,
skb->head, temp);
}
#endif
pci_unmap_single(tp->pdev, tp->rx_buffers[entry].mapping,
PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
tp->rx_buffers[entry].skb = NULL;
tp->rx_buffers[entry].mapping = 0;
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
}
received++;
entry = (++tp->cur_rx) % RX_RING_SIZE;
}
return received;
}
#endif /* CONFIG_TULIP_NAPI */
static inline unsigned int phy_interrupt (struct net_device *dev)
{
#ifdef __hppa__
struct tulip_private *tp = netdev_priv(dev);
int csr12 = ioread32(tp->base_addr + CSR12) & 0xff;
if (csr12 != tp->csr12_shadow) {
/* ack interrupt */
iowrite32(csr12 | 0x02, tp->base_addr + CSR12);
tp->csr12_shadow = csr12;
/* do link change stuff */
spin_lock(&tp->lock);
tulip_check_duplex(dev);
spin_unlock(&tp->lock);
/* clear irq ack bit */
iowrite32(csr12 & ~0x02, tp->base_addr + CSR12);
return 1;
}
#endif
return 0;
}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
irqreturn_t tulip_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *)dev_instance;
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int csr5;
int missed;
int rx = 0;
int tx = 0;
int oi = 0;
int maxrx = RX_RING_SIZE;
int maxtx = TX_RING_SIZE;
int maxoi = TX_RING_SIZE;
#ifdef CONFIG_TULIP_NAPI
int rxd = 0;
#else
int entry;
#endif
unsigned int work_count = tulip_max_interrupt_work;
unsigned int handled = 0;
/* Let's see whether the interrupt really is for us */
csr5 = ioread32(ioaddr + CSR5);
if (tp->flags & HAS_PHY_IRQ)
handled = phy_interrupt (dev);
if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
return IRQ_RETVAL(handled);
tp->nir++;
do {
#ifdef CONFIG_TULIP_NAPI
if (!rxd && (csr5 & (RxIntr | RxNoBuf))) {
rxd++;
/* Mask RX intrs and add the device to poll list. */
iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
napi_schedule(&tp->napi);
if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass)))
break;
}
/* Acknowledge the interrupt sources we handle here ASAP
the poll function does Rx and RxNoBuf acking */
iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5);
#else
/* Acknowledge all of the current interrupt sources ASAP. */
iowrite32(csr5 & 0x0001ffff, ioaddr + CSR5);
if (csr5 & (RxIntr | RxNoBuf)) {
rx += tulip_rx(dev);
tulip_refill_rx(dev);
}
#endif /* CONFIG_TULIP_NAPI */
if (tulip_debug > 4)
netdev_dbg(dev, "interrupt csr5=%#8.8x new csr5=%#8.8x\n",
csr5, ioread32(ioaddr + CSR5));
if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
unsigned int dirty_tx;
spin_lock(&tp->lock);
for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
dirty_tx++) {
int entry = dirty_tx % TX_RING_SIZE;
int status = le32_to_cpu(tp->tx_ring[entry].status);
if (status < 0)
break; /* It still has not been Txed */
/* Check for Rx filter setup frames. */
if (tp->tx_buffers[entry].skb == NULL) {
/* test because dummy frames not mapped */
if (tp->tx_buffers[entry].mapping)
pci_unmap_single(tp->pdev,
tp->tx_buffers[entry].mapping,
sizeof(tp->setup_frame),
PCI_DMA_TODEVICE);
continue;
}
if (status & 0x8000) {
/* There was an major error, log it. */
#ifndef final_version
if (tulip_debug > 1)
netdev_dbg(dev, "Transmit error, Tx status %08x\n",
status);
#endif
dev->stats.tx_errors++;
if (status & 0x4104)
dev->stats.tx_aborted_errors++;
if (status & 0x0C00)
dev->stats.tx_carrier_errors++;
if (status & 0x0200)
dev->stats.tx_window_errors++;
if (status & 0x0002)
dev->stats.tx_fifo_errors++;
if ((status & 0x0080) && tp->full_duplex == 0)
dev->stats.tx_heartbeat_errors++;
} else {
dev->stats.tx_bytes +=
tp->tx_buffers[entry].skb->len;
dev->stats.collisions += (status >> 3) & 15;
dev->stats.tx_packets++;
}
pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
tp->tx_buffers[entry].skb->len,
PCI_DMA_TODEVICE);
/* Free the original skb. */
dev_kfree_skb_irq(tp->tx_buffers[entry].skb);
tp->tx_buffers[entry].skb = NULL;
tp->tx_buffers[entry].mapping = 0;
tx++;
}
#ifndef final_version
if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
dev_err(&dev->dev,
"Out-of-sync dirty pointer, %d vs. %d\n",
dirty_tx, tp->cur_tx);
dirty_tx += TX_RING_SIZE;
}
#endif
if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2)
netif_wake_queue(dev);
tp->dirty_tx = dirty_tx;
if (csr5 & TxDied) {
if (tulip_debug > 2)
dev_warn(&dev->dev,
"The transmitter stopped. CSR5 is %x, CSR6 %x, new CSR6 %x\n",
csr5, ioread32(ioaddr + CSR6),
tp->csr6);
tulip_restart_rxtx(tp);
}
spin_unlock(&tp->lock);
}
/* Log errors. */
if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */
if (csr5 == 0xffffffff)
break;
if (csr5 & TxJabber)
dev->stats.tx_errors++;
if (csr5 & TxFIFOUnderflow) {
if ((tp->csr6 & 0xC000) != 0xC000)
tp->csr6 += 0x4000; /* Bump up the Tx threshold */
else
tp->csr6 |= 0x00200000; /* Store-n-forward. */
/* Restart the transmit process. */
tulip_restart_rxtx(tp);
iowrite32(0, ioaddr + CSR1);
}
if (csr5 & (RxDied | RxNoBuf)) {
if (tp->flags & COMET_MAC_ADDR) {
iowrite32(tp->mc_filter[0], ioaddr + 0xAC);
iowrite32(tp->mc_filter[1], ioaddr + 0xB0);
}
}
if (csr5 & RxDied) { /* Missed a Rx frame. */
dev->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff;
dev->stats.rx_errors++;
tulip_start_rxtx(tp);
}
/*
* NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this
* call is ever done under the spinlock
*/
if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
if (tp->link_change)
(tp->link_change)(dev, csr5);
}
if (csr5 & SystemError) {
int error = (csr5 >> 23) & 7;
/* oops, we hit a PCI error. The code produced corresponds
* to the reason:
* 0 - parity error
* 1 - master abort
* 2 - target abort
* Note that on parity error, we should do a software reset
* of the chip to get it back into a sane state (according
* to the 21142/3 docs that is).
* -- rmk
*/
dev_err(&dev->dev,
"(%lu) System Error occurred (%d)\n",
tp->nir, error);
}
/* Clear all error sources, included undocumented ones! */
iowrite32(0x0800f7ba, ioaddr + CSR5);
oi++;
}
if (csr5 & TimerInt) {
if (tulip_debug > 2)
dev_err(&dev->dev,
"Re-enabling interrupts, %08x\n",
csr5);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
tp->ttimer = 0;
oi++;
}
if (tx > maxtx || rx > maxrx || oi > maxoi) {
if (tulip_debug > 1)
dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n",
csr5, tp->nir, tx, rx, oi);
/* Acknowledge all interrupt sources. */
iowrite32(0x8001ffff, ioaddr + CSR5);
if (tp->flags & HAS_INTR_MITIGATION) {
/* Josip Loncaric at ICASE did extensive experimentation
to develop a good interrupt mitigation setting.*/
iowrite32(0x8b240000, ioaddr + CSR11);
} else if (tp->chip_id == LC82C168) {
/* the LC82C168 doesn't have a hw timer.*/
iowrite32(0x00, ioaddr + CSR7);
mod_timer(&tp->timer, RUN_AT(HZ/50));
} else {
/* Mask all interrupting sources, set timer to
re-enable. */
iowrite32(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7);
iowrite32(0x0012, ioaddr + CSR11);
}
break;
}
work_count--;
if (work_count == 0)
break;
csr5 = ioread32(ioaddr + CSR5);
#ifdef CONFIG_TULIP_NAPI
if (rxd)
csr5 &= ~RxPollInt;
} while ((csr5 & (TxNoBuf |
TxDied |
TxIntr |
TimerInt |
/* Abnormal intr. */
RxDied |
TxFIFOUnderflow |
TxJabber |
TPLnkFail |
SystemError )) != 0);
#else
} while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
tulip_refill_rx(dev);
/* check if the card is in suspend mode */
entry = tp->dirty_rx % RX_RING_SIZE;
if (tp->rx_buffers[entry].skb == NULL) {
if (tulip_debug > 1)
dev_warn(&dev->dev,
"in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n",
tp->nir, tp->cur_rx, tp->ttimer, rx);
if (tp->chip_id == LC82C168) {
iowrite32(0x00, ioaddr + CSR7);
mod_timer(&tp->timer, RUN_AT(HZ/50));
} else {
if (tp->ttimer == 0 || (ioread32(ioaddr + CSR11) & 0xffff) == 0) {
if (tulip_debug > 1)
dev_warn(&dev->dev,
"in rx suspend mode: (%lu) set timer\n",
tp->nir);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
ioaddr + CSR7);
iowrite32(TimerInt, ioaddr + CSR5);
iowrite32(12, ioaddr + CSR11);
tp->ttimer = 1;
}
}
}
#endif /* CONFIG_TULIP_NAPI */
if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) {
dev->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
}
if (tulip_debug > 4)
netdev_dbg(dev, "exiting interrupt, csr5=%#04x\n",
ioread32(ioaddr + CSR5));
return IRQ_HANDLED;
}

View file

@ -0,0 +1,552 @@
/*
drivers/net/ethernet/dec/tulip/media.c
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Please submit bugs to http://bugzilla.kernel.org/ .
*/
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include "tulip.h"
/* 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() ioread32(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. */
#define MDIO_SHIFT_CLK 0x10000
#define MDIO_DATA_WRITE0 0x00000
#define MDIO_DATA_WRITE1 0x20000
#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */
#define MDIO_ENB_IN 0x40000
#define MDIO_DATA_READ 0x80000
static const unsigned char comet_miireg2offset[32] = {
0xB4, 0xB8, 0xBC, 0xC0, 0xC4, 0xC8, 0xCC, 0, 0,0,0,0, 0,0,0,0,
0,0xD0,0,0, 0,0,0,0, 0,0,0,0, 0, 0xD4, 0xD8, 0xDC, };
/* MII transceiver control section.
Read and write the MII registers using software-generated serial
MDIO protocol.
See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
or DP83840A data sheet for more details.
*/
int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
{
struct tulip_private *tp = netdev_priv(dev);
int i;
int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location;
int retval = 0;
void __iomem *ioaddr = tp->base_addr;
void __iomem *mdio_addr = ioaddr + CSR9;
unsigned long flags;
if (location & ~0x1f)
return 0xffff;
if (tp->chip_id == COMET && phy_id == 30) {
if (comet_miireg2offset[location])
return ioread32(ioaddr + comet_miireg2offset[location]);
return 0xffff;
}
spin_lock_irqsave(&tp->mii_lock, flags);
if (tp->chip_id == LC82C168) {
iowrite32(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
ioread32(ioaddr + 0xA0);
ioread32(ioaddr + 0xA0);
for (i = 1000; i >= 0; --i) {
barrier();
if ( ! ((retval = ioread32(ioaddr + 0xA0)) & 0x80000000))
break;
}
spin_unlock_irqrestore(&tp->mii_lock, flags);
return retval & 0xffff;
}
/* Establish sync by sending at least 32 logic ones. */
for (i = 32; i >= 0; i--) {
iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
mdio_delay();
iowrite32(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
/* Shift the read command bits out. */
for (i = 15; i >= 0; i--) {
int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
iowrite32(MDIO_ENB | dataval, mdio_addr);
mdio_delay();
iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
/* Read the two transition, 16 data, and wire-idle bits. */
for (i = 19; i > 0; i--) {
iowrite32(MDIO_ENB_IN, mdio_addr);
mdio_delay();
retval = (retval << 1) | ((ioread32(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
spin_unlock_irqrestore(&tp->mii_lock, flags);
return (retval>>1) & 0xffff;
}
void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val)
{
struct tulip_private *tp = netdev_priv(dev);
int i;
int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff);
void __iomem *ioaddr = tp->base_addr;
void __iomem *mdio_addr = ioaddr + CSR9;
unsigned long flags;
if (location & ~0x1f)
return;
if (tp->chip_id == COMET && phy_id == 30) {
if (comet_miireg2offset[location])
iowrite32(val, ioaddr + comet_miireg2offset[location]);
return;
}
spin_lock_irqsave(&tp->mii_lock, flags);
if (tp->chip_id == LC82C168) {
iowrite32(cmd, ioaddr + 0xA0);
for (i = 1000; i >= 0; --i) {
barrier();
if ( ! (ioread32(ioaddr + 0xA0) & 0x80000000))
break;
}
spin_unlock_irqrestore(&tp->mii_lock, flags);
return;
}
/* Establish sync by sending 32 logic ones. */
for (i = 32; i >= 0; i--) {
iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
mdio_delay();
iowrite32(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;
iowrite32(MDIO_ENB | dataval, mdio_addr);
mdio_delay();
iowrite32(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
/* Clear out extra bits. */
for (i = 2; i > 0; i--) {
iowrite32(MDIO_ENB_IN, mdio_addr);
mdio_delay();
iowrite32(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
mdio_delay();
}
spin_unlock_irqrestore(&tp->mii_lock, flags);
}
/* Set up the transceiver control registers for the selected media type. */
void tulip_select_media(struct net_device *dev, int startup)
{
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
struct mediatable *mtable = tp->mtable;
u32 new_csr6;
int i;
if (mtable) {
struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
unsigned char *p = mleaf->leafdata;
switch (mleaf->type) {
case 0: /* 21140 non-MII xcvr. */
if (tulip_debug > 1)
netdev_dbg(dev, "Using a 21140 non-MII transceiver with control setting %02x\n",
p[1]);
dev->if_port = p[0];
if (startup)
iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
iowrite32(p[1], ioaddr + CSR12);
new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
break;
case 2: case 4: {
u16 setup[5];
u32 csr13val, csr14val, csr15dir, csr15val;
for (i = 0; i < 5; i++)
setup[i] = get_u16(&p[i*2 + 1]);
dev->if_port = p[0] & MEDIA_MASK;
if (tulip_media_cap[dev->if_port] & MediaAlwaysFD)
tp->full_duplex = 1;
if (startup && mtable->has_reset) {
struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
unsigned char *rst = rleaf->leafdata;
if (tulip_debug > 1)
netdev_dbg(dev, "Resetting the transceiver\n");
for (i = 0; i < rst[0]; i++)
iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
}
if (tulip_debug > 1)
netdev_dbg(dev, "21143 non-MII %s transceiver control %04x/%04x\n",
medianame[dev->if_port],
setup[0], setup[1]);
if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
csr13val = setup[0];
csr14val = setup[1];
csr15dir = (setup[3]<<16) | setup[2];
csr15val = (setup[4]<<16) | setup[2];
iowrite32(0, ioaddr + CSR13);
iowrite32(csr14val, ioaddr + CSR14);
iowrite32(csr15dir, ioaddr + CSR15); /* Direction */
iowrite32(csr15val, ioaddr + CSR15); /* Data */
iowrite32(csr13val, ioaddr + CSR13);
} else {
csr13val = 1;
csr14val = 0;
csr15dir = (setup[0]<<16) | 0x0008;
csr15val = (setup[1]<<16) | 0x0008;
if (dev->if_port <= 4)
csr14val = t21142_csr14[dev->if_port];
if (startup) {
iowrite32(0, ioaddr + CSR13);
iowrite32(csr14val, ioaddr + CSR14);
}
iowrite32(csr15dir, ioaddr + CSR15); /* Direction */
iowrite32(csr15val, ioaddr + CSR15); /* Data */
if (startup) iowrite32(csr13val, ioaddr + CSR13);
}
if (tulip_debug > 1)
netdev_dbg(dev, "Setting CSR15 to %08x/%08x\n",
csr15dir, csr15val);
if (mleaf->type == 4)
new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
else
new_csr6 = 0x82420000;
break;
}
case 1: case 3: {
int phy_num = p[0];
int init_length = p[1];
u16 *misc_info, tmp_info;
dev->if_port = 11;
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) {
int timeout = 10; /* max 1 ms */
for (i = 0; i < reset_length; i++)
iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
/* flush posted writes */
ioread32(ioaddr + CSR15);
/* Sect 3.10.3 in DP83840A.pdf (p39) */
udelay(500);
/* Section 4.2 in DP83840A.pdf (p43) */
/* and IEEE 802.3 "22.2.4.1.1 Reset" */
while (timeout-- &&
(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
udelay(100);
}
for (i = 0; i < init_length; i++)
iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
ioread32(ioaddr + CSR15); /* flush posted writes */
} 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) {
int timeout = 10; /* max 1 ms */
iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
for (i = 0; i < reset_length; i++)
iowrite32(reset_sequence[i], ioaddr + CSR12);
/* flush posted writes */
ioread32(ioaddr + CSR12);
/* Sect 3.10.3 in DP83840A.pdf (p39) */
udelay(500);
/* Section 4.2 in DP83840A.pdf (p43) */
/* and IEEE 802.3 "22.2.4.1.1 Reset" */
while (timeout-- &&
(tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
udelay(100);
}
for (i = 0; i < init_length; i++)
iowrite32(init_sequence[i], ioaddr + CSR12);
ioread32(ioaddr + CSR12); /* flush posted writes */
}
tmp_info = get_u16(&misc_info[1]);
if (tmp_info)
tp->advertising[phy_num] = tmp_info | 1;
if (tmp_info && startup < 2) {
if (tp->mii_advertise == 0)
tp->mii_advertise = tp->advertising[phy_num];
if (tulip_debug > 1)
netdev_dbg(dev, " Advertising %04x on MII %d\n",
tp->mii_advertise,
tp->phys[phy_num]);
tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise);
}
break;
}
case 5: case 6: {
u16 setup[5];
new_csr6 = 0; /* FIXME */
for (i = 0; i < 5; i++)
setup[i] = get_u16(&p[i*2 + 1]);
if (startup && mtable->has_reset) {
struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
unsigned char *rst = rleaf->leafdata;
if (tulip_debug > 1)
netdev_dbg(dev, "Resetting the transceiver\n");
for (i = 0; i < rst[0]; i++)
iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
}
break;
}
default:
netdev_dbg(dev, " Invalid media table selection %d\n",
mleaf->type);
new_csr6 = 0x020E0000;
}
if (tulip_debug > 1)
netdev_dbg(dev, "Using media type %s, CSR12 is %02x\n",
medianame[dev->if_port],
ioread32(ioaddr + CSR12) & 0xff);
} else if (tp->chip_id == LC82C168) {
if (startup && ! tp->medialock)
dev->if_port = tp->mii_cnt ? 11 : 0;
if (tulip_debug > 1)
netdev_dbg(dev, "PNIC PHY status is %3.3x, media %s\n",
ioread32(ioaddr + 0xB8),
medianame[dev->if_port]);
if (tp->mii_cnt) {
new_csr6 = 0x810C0000;
iowrite32(0x0001, ioaddr + CSR15);
iowrite32(0x0201B07A, ioaddr + 0xB8);
} else if (startup) {
/* Start with 10mbps to do autonegotiation. */
iowrite32(0x32, ioaddr + CSR12);
new_csr6 = 0x00420000;
iowrite32(0x0001B078, ioaddr + 0xB8);
iowrite32(0x0201B078, ioaddr + 0xB8);
} else if (dev->if_port == 3 || dev->if_port == 5) {
iowrite32(0x33, ioaddr + CSR12);
new_csr6 = 0x01860000;
/* Trigger autonegotiation. */
iowrite32(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
} else {
iowrite32(0x32, ioaddr + CSR12);
new_csr6 = 0x00420000;
iowrite32(0x1F078, ioaddr + 0xB8);
}
} else { /* Unknown chip type with no media table. */
if (tp->default_port == 0)
dev->if_port = tp->mii_cnt ? 11 : 3;
if (tulip_media_cap[dev->if_port] & MediaIsMII) {
new_csr6 = 0x020E0000;
} else if (tulip_media_cap[dev->if_port] & MediaIsFx) {
new_csr6 = 0x02860000;
} else
new_csr6 = 0x03860000;
if (tulip_debug > 1)
netdev_dbg(dev, "No media description table, assuming %s transceiver, CSR12 %02x\n",
medianame[dev->if_port],
ioread32(ioaddr + CSR12));
}
tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
mdelay(1);
}
/*
Check the MII negotiated duplex and change the CSR6 setting if
required.
Return 0 if everything is OK.
Return < 0 if the transceiver is missing or has no link beat.
*/
int tulip_check_duplex(struct net_device *dev)
{
struct tulip_private *tp = netdev_priv(dev);
unsigned int bmsr, lpa, negotiated, new_csr6;
bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
lpa = tulip_mdio_read(dev, tp->phys[0], MII_LPA);
if (tulip_debug > 1)
dev_info(&dev->dev, "MII status %04x, Link partner report %04x\n",
bmsr, lpa);
if (bmsr == 0xffff)
return -2;
if ((bmsr & BMSR_LSTATUS) == 0) {
int new_bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR);
if ((new_bmsr & BMSR_LSTATUS) == 0) {
if (tulip_debug > 1)
dev_info(&dev->dev,
"No link beat on the MII interface, status %04x\n",
new_bmsr);
return -1;
}
}
negotiated = lpa & tp->advertising[0];
tp->full_duplex = mii_duplex(tp->full_duplex_lock, negotiated);
new_csr6 = tp->csr6;
if (negotiated & LPA_100) new_csr6 &= ~TxThreshold;
else new_csr6 |= TxThreshold;
if (tp->full_duplex) new_csr6 |= FullDuplex;
else new_csr6 &= ~FullDuplex;
if (new_csr6 != tp->csr6) {
tp->csr6 = new_csr6;
tulip_restart_rxtx(tp);
if (tulip_debug > 0)
dev_info(&dev->dev,
"Setting %s-duplex based on MII#%d link partner capability of %04x\n",
tp->full_duplex ? "full" : "half",
tp->phys[0], lpa);
return 1;
}
return 0;
}
void tulip_find_mii(struct net_device *dev, int board_idx)
{
struct tulip_private *tp = netdev_priv(dev);
int phyn, phy_idx = 0;
int mii_reg0;
int mii_advert;
unsigned int to_advert, new_bmcr, ane_switch;
/* Find the connected MII xcvrs.
Doing this in open() would allow detecting external xcvrs later,
but takes much time. */
for (phyn = 1; phyn <= 32 && phy_idx < ARRAY_SIZE(tp->phys); phyn++) {
int phy = phyn & 0x1f;
int mii_status = tulip_mdio_read (dev, phy, MII_BMSR);
if ((mii_status & 0x8301) == 0x8001 ||
((mii_status & BMSR_100BASE4) == 0 &&
(mii_status & 0x7800) != 0)) {
/* preserve Becker logic, gain indentation level */
} else {
continue;
}
mii_reg0 = tulip_mdio_read (dev, phy, MII_BMCR);
mii_advert = tulip_mdio_read (dev, phy, MII_ADVERTISE);
ane_switch = 0;
/* if not advertising at all, gen an
* advertising value from the capability
* bits in BMSR
*/
if ((mii_advert & ADVERTISE_ALL) == 0) {
unsigned int tmpadv = tulip_mdio_read (dev, phy, MII_BMSR);
mii_advert = ((tmpadv >> 6) & 0x3e0) | 1;
}
if (tp->mii_advertise) {
tp->advertising[phy_idx] =
to_advert = tp->mii_advertise;
} else if (tp->advertising[phy_idx]) {
to_advert = tp->advertising[phy_idx];
} else {
tp->advertising[phy_idx] =
tp->mii_advertise =
to_advert = mii_advert;
}
tp->phys[phy_idx++] = phy;
pr_info("tulip%d: MII transceiver #%d config %04x status %04x advertising %04x\n",
board_idx, phy, mii_reg0, mii_status, mii_advert);
/* Fixup for DLink with miswired PHY. */
if (mii_advert != to_advert) {
pr_debug("tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n",
board_idx, to_advert, phy, mii_advert);
tulip_mdio_write (dev, phy, 4, to_advert);
}
/* Enable autonegotiation: some boards default to off. */
if (tp->default_port == 0) {
new_bmcr = mii_reg0 | BMCR_ANENABLE;
if (new_bmcr != mii_reg0) {
new_bmcr |= BMCR_ANRESTART;
ane_switch = 1;
}
}
/* ...or disable nway, if forcing media */
else {
new_bmcr = mii_reg0 & ~BMCR_ANENABLE;
if (new_bmcr != mii_reg0)
ane_switch = 1;
}
/* clear out bits we never want at this point */
new_bmcr &= ~(BMCR_CTST | BMCR_FULLDPLX | BMCR_ISOLATE |
BMCR_PDOWN | BMCR_SPEED100 | BMCR_LOOPBACK |
BMCR_RESET);
if (tp->full_duplex)
new_bmcr |= BMCR_FULLDPLX;
if (tulip_media_cap[tp->default_port] & MediaIs100)
new_bmcr |= BMCR_SPEED100;
if (new_bmcr != mii_reg0) {
/* some phys need the ANE switch to
* happen before forced media settings
* will "take." However, we write the
* same value twice in order not to
* confuse the sane phys.
*/
if (ane_switch) {
tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr);
udelay (10);
}
tulip_mdio_write (dev, phy, MII_BMCR, new_bmcr);
}
}
tp->mii_cnt = phy_idx;
if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) {
pr_info("tulip%d: ***WARNING***: No MII transceiver found!\n",
board_idx);
tp->phys[0] = 1;
}
}

View file

@ -0,0 +1,170 @@
/*
drivers/net/ethernet/dec/tulip/pnic.c
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Please submit bugs to http://bugzilla.kernel.org/ .
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include "tulip.h"
void pnic_do_nway(struct net_device *dev)
{
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
u32 phy_reg = ioread32(ioaddr + 0xB8);
u32 new_csr6 = tp->csr6 & ~0x40C40200;
if (phy_reg & 0x78000000) { /* Ignore baseT4 */
if (phy_reg & 0x20000000) dev->if_port = 5;
else if (phy_reg & 0x40000000) dev->if_port = 3;
else if (phy_reg & 0x10000000) dev->if_port = 4;
else if (phy_reg & 0x08000000) dev->if_port = 0;
tp->nwayset = 1;
new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000;
iowrite32(0x32 | (dev->if_port & 1), ioaddr + CSR12);
if (dev->if_port & 1)
iowrite32(0x1F868, ioaddr + 0xB8);
if (phy_reg & 0x30000000) {
tp->full_duplex = 1;
new_csr6 |= 0x00000200;
}
if (tulip_debug > 1)
netdev_dbg(dev, "PNIC autonegotiated status %08x, %s\n",
phy_reg, medianame[dev->if_port]);
if (tp->csr6 != new_csr6) {
tp->csr6 = new_csr6;
/* Restart Tx */
tulip_restart_rxtx(tp);
dev->trans_start = jiffies;
}
}
}
void pnic_lnk_change(struct net_device *dev, int csr5)
{
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int phy_reg = ioread32(ioaddr + 0xB8);
if (tulip_debug > 1)
netdev_dbg(dev, "PNIC link changed state %08x, CSR5 %08x\n",
phy_reg, csr5);
if (ioread32(ioaddr + CSR5) & TPLnkFail) {
iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
/* If we use an external MII, then we mustn't use the
* internal negotiation.
*/
if (tulip_media_cap[dev->if_port] & MediaIsMII)
return;
if (! tp->nwayset || time_after(jiffies, dev_trans_start(dev) + 1*HZ)) {
tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
iowrite32(tp->csr6, ioaddr + CSR6);
iowrite32(0x30, ioaddr + CSR12);
iowrite32(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
dev->trans_start = jiffies;
}
} else if (ioread32(ioaddr + CSR5) & TPLnkPass) {
if (tulip_media_cap[dev->if_port] & MediaIsMII) {
spin_lock(&tp->lock);
tulip_check_duplex(dev);
spin_unlock(&tp->lock);
} else {
pnic_do_nway(dev);
}
iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
}
}
void pnic_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int next_tick = 60*HZ;
if(!ioread32(ioaddr + CSR7)) {
/* the timer was called due to a work overflow
* in the interrupt handler. Skip the connection
* checks, the nic is definitively speaking with
* his link partner.
*/
goto too_good_connection;
}
if (tulip_media_cap[dev->if_port] & MediaIsMII) {
spin_lock_irq(&tp->lock);
if (tulip_check_duplex(dev) > 0)
next_tick = 3*HZ;
spin_unlock_irq(&tp->lock);
} else {
int csr12 = ioread32(ioaddr + CSR12);
int new_csr6 = tp->csr6 & ~0x40C40200;
int phy_reg = ioread32(ioaddr + 0xB8);
int csr5 = ioread32(ioaddr + CSR5);
if (tulip_debug > 1)
netdev_dbg(dev, "PNIC timer PHY status %08x, %s CSR5 %08x\n",
phy_reg, medianame[dev->if_port], csr5);
if (phy_reg & 0x04000000) { /* Remote link fault */
iowrite32(0x0201F078, ioaddr + 0xB8);
next_tick = 1*HZ;
tp->nwayset = 0;
} else if (phy_reg & 0x78000000) { /* Ignore baseT4 */
pnic_do_nway(dev);
next_tick = 60*HZ;
} else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
if (tulip_debug > 1)
netdev_dbg(dev, "%s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n",
medianame[dev->if_port],
csr12,
ioread32(ioaddr + CSR5),
ioread32(ioaddr + 0xB8));
next_tick = 3*HZ;
if (tp->medialock) {
} else if (tp->nwayset && (dev->if_port & 1)) {
next_tick = 1*HZ;
} else if (dev->if_port == 0) {
dev->if_port = 3;
iowrite32(0x33, ioaddr + CSR12);
new_csr6 = 0x01860000;
iowrite32(0x1F868, ioaddr + 0xB8);
} else {
dev->if_port = 0;
iowrite32(0x32, ioaddr + CSR12);
new_csr6 = 0x00420000;
iowrite32(0x1F078, ioaddr + 0xB8);
}
if (tp->csr6 != new_csr6) {
tp->csr6 = new_csr6;
/* Restart Tx */
tulip_restart_rxtx(tp);
dev->trans_start = jiffies;
if (tulip_debug > 1)
dev_info(&dev->dev,
"Changing PNIC configuration to %s %s-duplex, CSR6 %08x\n",
medianame[dev->if_port],
tp->full_duplex ? "full" : "half",
new_csr6);
}
}
}
too_good_connection:
mod_timer(&tp->timer, RUN_AT(next_tick));
if(!ioread32(ioaddr + CSR7)) {
if (tulip_debug > 1)
dev_info(&dev->dev, "sw timer wakeup\n");
disable_irq(dev->irq);
tulip_refill_rx(dev);
enable_irq(dev->irq);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
}
}

View file

@ -0,0 +1,403 @@
/*
drivers/net/ethernet/dec/tulip/pnic2.c
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
Modified to hep support PNIC_II by Kevin B. Hendricks
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Please submit bugs to http://bugzilla.kernel.org/ .
*/
/* Understanding the PNIC_II - everything is this file is based
* on the PNIC_II_PDF datasheet which is sorely lacking in detail
*
* As I understand things, here are the registers and bits that
* explain the masks and constants used in this file that are
* either different from the 21142/3 or important for basic operation.
*
*
* CSR 6 (mask = 0xfe3bd1fd of bits not to change)
* -----
* Bit 24 - SCR
* Bit 23 - PCS
* Bit 22 - TTM (Trasmit Threshold Mode)
* Bit 18 - Port Select
* Bit 13 - Start - 1, Stop - 0 Transmissions
* Bit 11:10 - Loop Back Operation Mode
* Bit 9 - Full Duplex mode (Advertise 10BaseT-FD is CSR14<7> is set)
* Bit 1 - Start - 1, Stop - 0 Receive
*
*
* CSR 14 (mask = 0xfff0ee39 of bits not to change)
* ------
* Bit 19 - PAUSE-Pause
* Bit 18 - Advertise T4
* Bit 17 - Advertise 100baseTx-FD
* Bit 16 - Advertise 100baseTx-HD
* Bit 12 - LTE - Link Test Enable
* Bit 7 - ANE - Auto Negotiate Enable
* Bit 6 - HDE - Advertise 10baseT-HD
* Bit 2 - Reset to Power down - kept as 1 for normal operation
* Bit 1 - Loop Back enable for 10baseT MCC
*
*
* CSR 12
* ------
* Bit 25 - Partner can do T4
* Bit 24 - Partner can do 100baseTx-FD
* Bit 23 - Partner can do 100baseTx-HD
* Bit 22 - Partner can do 10baseT-FD
* Bit 21 - Partner can do 10baseT-HD
* Bit 15 - LPN is 1 if all above bits are valid other wise 0
* Bit 14:12 - autonegotiation state (write 001 to start autonegotiate)
* Bit 3 - Autopolarity state
* Bit 2 - LS10B - link state of 10baseT 0 - good, 1 - failed
* Bit 1 - LS100B - link state of 100baseT 0 - good, 1 - failed
*
*
* Data Port Selection Info
*-------------------------
*
* CSR14<7> CSR6<18> CSR6<22> CSR6<23> CSR6<24> MODE/PORT
* 1 0 0 (X) 0 (X) 1 NWAY
* 0 0 1 0 (X) 0 10baseT
* 0 1 0 1 1 (X) 100baseT
*
*
*/
#include "tulip.h"
#include <linux/delay.h>
void pnic2_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int next_tick = 60*HZ;
if (tulip_debug > 3)
dev_info(&dev->dev, "PNIC2 negotiation status %08x\n",
ioread32(ioaddr + CSR12));
if (next_tick) {
mod_timer(&tp->timer, RUN_AT(next_tick));
}
}
void pnic2_start_nway(struct net_device *dev)
{
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int csr14;
int csr12;
/* set up what to advertise during the negotiation */
/* load in csr14 and mask off bits not to touch
* comment at top of file explains mask value
*/
csr14 = (ioread32(ioaddr + CSR14) & 0xfff0ee39);
/* bit 17 - advetise 100baseTx-FD */
if (tp->sym_advertise & 0x0100) csr14 |= 0x00020000;
/* bit 16 - advertise 100baseTx-HD */
if (tp->sym_advertise & 0x0080) csr14 |= 0x00010000;
/* bit 6 - advertise 10baseT-HD */
if (tp->sym_advertise & 0x0020) csr14 |= 0x00000040;
/* Now set bit 12 Link Test Enable, Bit 7 Autonegotiation Enable
* and bit 0 Don't PowerDown 10baseT
*/
csr14 |= 0x00001184;
if (tulip_debug > 1)
netdev_dbg(dev, "Restarting PNIC2 autonegotiation, csr14=%08x\n",
csr14);
/* tell pnic2_lnk_change we are doing an nway negotiation */
dev->if_port = 0;
tp->nway = tp->mediasense = 1;
tp->nwayset = tp->lpar = 0;
/* now we have to set up csr6 for NWAY state */
tp->csr6 = ioread32(ioaddr + CSR6);
if (tulip_debug > 1)
netdev_dbg(dev, "On Entry to Nway, csr6=%08x\n", tp->csr6);
/* mask off any bits not to touch
* comment at top of file explains mask value
*/
tp->csr6 = tp->csr6 & 0xfe3bd1fd;
/* don't forget that bit 9 is also used for advertising */
/* advertise 10baseT-FD for the negotiation (bit 9) */
if (tp->sym_advertise & 0x0040) tp->csr6 |= 0x00000200;
/* set bit 24 for nway negotiation mode ...
* see Data Port Selection comment at top of file
* and "Stop" - reset both Transmit (bit 13) and Receive (bit 1)
*/
tp->csr6 |= 0x01000000;
iowrite32(csr14, ioaddr + CSR14);
iowrite32(tp->csr6, ioaddr + CSR6);
udelay(100);
/* all set up so now force the negotiation to begin */
/* read in current values and mask off all but the
* Autonegotiation bits 14:12. Writing a 001 to those bits
* should start the autonegotiation
*/
csr12 = (ioread32(ioaddr + CSR12) & 0xffff8fff);
csr12 |= 0x1000;
iowrite32(csr12, ioaddr + CSR12);
}
void pnic2_lnk_change(struct net_device *dev, int csr5)
{
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int csr14;
/* read the staus register to find out what is up */
int csr12 = ioread32(ioaddr + CSR12);
if (tulip_debug > 1)
dev_info(&dev->dev,
"PNIC2 link status interrupt %08x, CSR5 %x, %08x\n",
csr12, csr5, ioread32(ioaddr + CSR14));
/* If NWay finished and we have a negotiated partner capability.
* check bits 14:12 for bit pattern 101 - all is good
*/
if (tp->nway && !tp->nwayset) {
/* we did an auto negotiation */
if ((csr12 & 0x7000) == 0x5000) {
/* negotiation ended successfully */
/* get the link partners reply and mask out all but
* bits 24-21 which show the partners capabilities
* and match those to what we advertised
*
* then begin to interpret the results of the negotiation.
* Always go in this order : (we are ignoring T4 for now)
* 100baseTx-FD, 100baseTx-HD, 10baseT-FD, 10baseT-HD
*/
int negotiated = ((csr12 >> 16) & 0x01E0) & tp->sym_advertise;
tp->lpar = (csr12 >> 16);
tp->nwayset = 1;
if (negotiated & 0x0100) dev->if_port = 5;
else if (negotiated & 0x0080) dev->if_port = 3;
else if (negotiated & 0x0040) dev->if_port = 4;
else if (negotiated & 0x0020) dev->if_port = 0;
else {
if (tulip_debug > 1)
dev_info(&dev->dev,
"funny autonegotiate result csr12 %08x advertising %04x\n",
csr12, tp->sym_advertise);
tp->nwayset = 0;
/* so check if 100baseTx link state is okay */
if ((csr12 & 2) == 0 && (tp->sym_advertise & 0x0180))
dev->if_port = 3;
}
/* now record the duplex that was negotiated */
tp->full_duplex = 0;
if ((dev->if_port == 4) || (dev->if_port == 5))
tp->full_duplex = 1;
if (tulip_debug > 1) {
if (tp->nwayset)
dev_info(&dev->dev,
"Switching to %s based on link negotiation %04x & %04x = %04x\n",
medianame[dev->if_port],
tp->sym_advertise, tp->lpar,
negotiated);
}
/* remember to turn off bit 7 - autonegotiate
* enable so we can properly end nway mode and
* set duplex (ie. use csr6<9> again)
*/
csr14 = (ioread32(ioaddr + CSR14) & 0xffffff7f);
iowrite32(csr14,ioaddr + CSR14);
/* now set the data port and operating mode
* (see the Data Port Selection comments at
* the top of the file
*/
/* get current csr6 and mask off bits not to touch */
/* see comment at top of file */
tp->csr6 = (ioread32(ioaddr + CSR6) & 0xfe3bd1fd);
/* so if using if_port 3 or 5 then select the 100baseT
* port else select the 10baseT port.
* See the Data Port Selection table at the top
* of the file which was taken from the PNIC_II.PDF
* datasheet
*/
if (dev->if_port & 1) tp->csr6 |= 0x01840000;
else tp->csr6 |= 0x00400000;
/* now set the full duplex bit appropriately */
if (tp->full_duplex) tp->csr6 |= 0x00000200;
iowrite32(1, ioaddr + CSR13);
if (tulip_debug > 2)
netdev_dbg(dev, "Setting CSR6 %08x/%x CSR12 %08x\n",
tp->csr6,
ioread32(ioaddr + CSR6),
ioread32(ioaddr + CSR12));
/* now the following actually writes out the
* new csr6 values
*/
tulip_start_rxtx(tp);
return;
} else {
dev_info(&dev->dev,
"Autonegotiation failed, using %s, link beat status %04x\n",
medianame[dev->if_port], csr12);
/* remember to turn off bit 7 - autonegotiate
* enable so we don't forget
*/
csr14 = (ioread32(ioaddr + CSR14) & 0xffffff7f);
iowrite32(csr14,ioaddr + CSR14);
/* what should we do when autonegotiate fails?
* should we try again or default to baseline
* case. I just don't know.
*
* for now default to some baseline case
*/
dev->if_port = 0;
tp->nway = 0;
tp->nwayset = 1;
/* set to 10baseTx-HD - see Data Port Selection
* comment given at the top of the file
*/
tp->csr6 = (ioread32(ioaddr + CSR6) & 0xfe3bd1fd);
tp->csr6 |= 0x00400000;
tulip_restart_rxtx(tp);
return;
}
}
if ((tp->nwayset && (csr5 & 0x08000000) &&
(dev->if_port == 3 || dev->if_port == 5) &&
(csr12 & 2) == 2) || (tp->nway && (csr5 & (TPLnkFail)))) {
/* Link blew? Maybe restart NWay. */
if (tulip_debug > 2)
netdev_dbg(dev, "Ugh! Link blew?\n");
del_timer_sync(&tp->timer);
pnic2_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
add_timer(&tp->timer);
return;
}
if (dev->if_port == 3 || dev->if_port == 5) {
/* we are at 100mb and a potential link change occurred */
if (tulip_debug > 1)
dev_info(&dev->dev, "PNIC2 %s link beat %s\n",
medianame[dev->if_port],
(csr12 & 2) ? "failed" : "good");
/* check 100 link beat */
tp->nway = 0;
tp->nwayset = 1;
/* if failed then try doing an nway to get in sync */
if ((csr12 & 2) && ! tp->medialock) {
del_timer_sync(&tp->timer);
pnic2_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
add_timer(&tp->timer);
}
return;
}
if (dev->if_port == 0 || dev->if_port == 4) {
/* we are at 10mb and a potential link change occurred */
if (tulip_debug > 1)
dev_info(&dev->dev, "PNIC2 %s link beat %s\n",
medianame[dev->if_port],
(csr12 & 4) ? "failed" : "good");
tp->nway = 0;
tp->nwayset = 1;
/* if failed, try doing an nway to get in sync */
if ((csr12 & 4) && ! tp->medialock) {
del_timer_sync(&tp->timer);
pnic2_start_nway(dev);
tp->timer.expires = RUN_AT(3*HZ);
add_timer(&tp->timer);
}
return;
}
if (tulip_debug > 1)
dev_info(&dev->dev, "PNIC2 Link Change Default?\n");
/* if all else fails default to trying 10baseT-HD */
dev->if_port = 0;
/* make sure autonegotiate enable is off */
csr14 = (ioread32(ioaddr + CSR14) & 0xffffff7f);
iowrite32(csr14,ioaddr + CSR14);
/* set to 10baseTx-HD - see Data Port Selection
* comment given at the top of the file
*/
tp->csr6 = (ioread32(ioaddr + CSR6) & 0xfe3bd1fd);
tp->csr6 |= 0x00400000;
tulip_restart_rxtx(tp);
}

View file

@ -0,0 +1,176 @@
/*
drivers/net/ethernet/dec/tulip/timer.c
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Please submit bugs to http://bugzilla.kernel.org/ .
*/
#include "tulip.h"
void tulip_media_task(struct work_struct *work)
{
struct tulip_private *tp =
container_of(work, struct tulip_private, media_work);
struct net_device *dev = tp->dev;
void __iomem *ioaddr = tp->base_addr;
u32 csr12 = ioread32(ioaddr + CSR12);
int next_tick = 2*HZ;
unsigned long flags;
if (tulip_debug > 2) {
netdev_dbg(dev, "Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n",
medianame[dev->if_port],
ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6),
csr12, ioread32(ioaddr + CSR13),
ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
}
switch (tp->chip_id) {
case DC21140:
case DC21142:
case MX98713:
case COMPEX9881:
case DM910X:
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)
netdev_dbg(dev, "network media monitor CSR6 %08x CSR12 0x%02x\n",
ioread32(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)
netdev_dbg(dev, "Transceiver monitor tick CSR12=%#02x, no media sense\n",
csr12);
if (mleaf->type == 4) {
if (mleaf->media == 3 && (csr12 & 0x02))
goto select_next_media;
}
break;
}
if (tulip_debug > 2)
netdev_dbg(dev, "Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n",
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 > 2)
netdev_dbg(dev, "Link beat detected for %s\n",
medianame[mleaf->media & MEDIA_MASK]);
if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
goto actually_mii;
netif_carrier_on(dev);
break;
}
netif_carrier_off(dev);
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 (tulip_media_cap[dev->if_port] & MediaIsFD)
goto select_next_media; /* Skip FD entries. */
if (tulip_debug > 1)
netdev_dbg(dev, "No link beat on media %s, trying transceiver type %s\n",
medianame[mleaf->media & MEDIA_MASK],
medianame[tp->mtable->mleaf[tp->cur_index].media]);
tulip_select_media(dev, 0);
/* Restart the transmit process. */
tulip_restart_rxtx(tp);
next_tick = (24*HZ)/10;
break;
}
case 1: case 3: /* 21140, 21142 MII */
actually_mii:
if (tulip_check_duplex(dev) < 0) {
netif_carrier_off(dev);
next_tick = 3*HZ;
} else {
netif_carrier_on(dev);
next_tick = 60*HZ;
}
break;
case 2: /* 21142 serial block has no link beat. */
default:
break;
}
}
break;
}
spin_lock_irqsave(&tp->lock, flags);
if (tp->timeout_recovery) {
tulip_tx_timeout_complete(tp, ioaddr);
tp->timeout_recovery = 0;
}
spin_unlock_irqrestore(&tp->lock, flags);
/* mod_timer synchronizes us with potential add_timer calls
* from interrupts.
*/
mod_timer(&tp->timer, RUN_AT(next_tick));
}
void mxic_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int next_tick = 60*HZ;
if (tulip_debug > 3) {
dev_info(&dev->dev, "MXIC negotiation status %08x\n",
ioread32(ioaddr + CSR12));
}
if (next_tick) {
mod_timer(&tp->timer, RUN_AT(next_tick));
}
}
void comet_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct tulip_private *tp = netdev_priv(dev);
int next_tick = 2*HZ;
if (tulip_debug > 1)
netdev_dbg(dev, "Comet link status %04x partner capability %04x\n",
tulip_mdio_read(dev, tp->phys[0], 1),
tulip_mdio_read(dev, tp->phys[0], 5));
/* mod_timer synchronizes us with potential add_timer calls
* from interrupts.
*/
if (tulip_check_duplex(dev) < 0)
{ netif_carrier_off(dev); }
else
{ netif_carrier_on(dev); }
mod_timer(&tp->timer, RUN_AT(next_tick));
}

View file

@ -0,0 +1,570 @@
/*
drivers/net/ethernet/dec/tulip/tulip.h
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
Please submit bugs to http://bugzilla.kernel.org/ .
*/
#ifndef __NET_TULIP_H__
#define __NET_TULIP_H__
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/unaligned.h>
/* undefine, or define to various debugging levels (>4 == obscene levels) */
#define TULIP_DEBUG 1
#ifdef CONFIG_TULIP_MMIO
#define TULIP_BAR 1 /* CBMA */
#else
#define TULIP_BAR 0 /* CBIO */
#endif
struct tulip_chip_table {
char *chip_name;
int io_size;
int valid_intrs; /* CSR7 interrupt enable settings */
int flags;
void (*media_timer) (unsigned long);
work_func_t media_task;
};
enum tbl_flag {
HAS_MII = 0x00001,
HAS_MEDIA_TABLE = 0x00002,
CSR12_IN_SROM = 0x00004,
ALWAYS_CHECK_MII = 0x00008,
HAS_ACPI = 0x00010,
MC_HASH_ONLY = 0x00020, /* Hash-only multicast filter. */
HAS_PNICNWAY = 0x00080,
HAS_NWAY = 0x00040, /* Uses internal NWay xcvr. */
HAS_INTR_MITIGATION = 0x00100,
IS_ASIX = 0x00200,
HAS_8023X = 0x00400,
COMET_MAC_ADDR = 0x00800,
HAS_PCI_MWI = 0x01000,
HAS_PHY_IRQ = 0x02000,
HAS_SWAPPED_SEEPROM = 0x04000,
NEEDS_FAKE_MEDIA_TABLE = 0x08000,
COMET_PM = 0x10000,
};
/* chip types. careful! order is VERY IMPORTANT here, as these
* are used throughout the driver as indices into arrays */
/* Note 21142 == 21143. */
enum chips {
DC21040 = 0,
DC21041 = 1,
DC21140 = 2,
DC21142 = 3, DC21143 = 3,
LC82C168,
MX98713,
MX98715,
MX98725,
AX88140,
PNIC2,
COMET,
COMPEX9881,
I21145,
DM910X,
CONEXANT,
};
enum MediaIs {
MediaIsFD = 1,
MediaAlwaysFD = 2,
MediaIsMII = 4,
MediaIsFx = 8,
MediaIs100 = 16
};
/* Offsets to the Command and Status Registers, "CSRs". All accesses
must be longword instructions and quadword aligned. */
enum tulip_offsets {
CSR0 = 0,
CSR1 = 0x08,
CSR2 = 0x10,
CSR3 = 0x18,
CSR4 = 0x20,
CSR5 = 0x28,
CSR6 = 0x30,
CSR7 = 0x38,
CSR8 = 0x40,
CSR9 = 0x48,
CSR10 = 0x50,
CSR11 = 0x58,
CSR12 = 0x60,
CSR13 = 0x68,
CSR14 = 0x70,
CSR15 = 0x78,
CSR18 = 0x88,
CSR19 = 0x8c,
CSR20 = 0x90,
CSR27 = 0xAC,
CSR28 = 0xB0,
};
/* register offset and bits for CFDD PCI config reg */
enum pci_cfg_driver_reg {
CFDD = 0x40,
CFDD_Sleep = (1 << 31),
CFDD_Snooze = (1 << 30),
};
#define RxPollInt (RxIntr|RxNoBuf|RxDied|RxJabber)
/* The bits in the CSR5 status registers, mostly interrupt sources. */
enum status_bits {
TimerInt = 0x800,
SystemError = 0x2000,
TPLnkFail = 0x1000,
TPLnkPass = 0x10,
NormalIntr = 0x10000,
AbnormalIntr = 0x8000,
RxJabber = 0x200,
RxDied = 0x100,
RxNoBuf = 0x80,
RxIntr = 0x40,
TxFIFOUnderflow = 0x20,
RxErrIntr = 0x10,
TxJabber = 0x08,
TxNoBuf = 0x04,
TxDied = 0x02,
TxIntr = 0x01,
};
/* bit mask for CSR5 TX/RX process state */
#define CSR5_TS 0x00700000
#define CSR5_RS 0x000e0000
enum tulip_mode_bits {
TxThreshold = (1 << 22),
FullDuplex = (1 << 9),
TxOn = 0x2000,
AcceptBroadcast = 0x0100,
AcceptAllMulticast = 0x0080,
AcceptAllPhys = 0x0040,
AcceptRunt = 0x0008,
RxOn = 0x0002,
RxTx = (TxOn | RxOn),
};
enum tulip_busconfig_bits {
MWI = (1 << 24),
MRL = (1 << 23),
MRM = (1 << 21),
CALShift = 14,
BurstLenShift = 8,
};
/* The Tulip Rx and Tx buffer descriptors. */
struct tulip_rx_desc {
__le32 status;
__le32 length;
__le32 buffer1;
__le32 buffer2;
};
struct tulip_tx_desc {
__le32 status;
__le32 length;
__le32 buffer1;
__le32 buffer2; /* We use only buffer 1. */
};
enum desc_status_bits {
DescOwned = 0x80000000,
DescWholePkt = 0x60000000,
DescEndPkt = 0x40000000,
DescStartPkt = 0x20000000,
DescEndRing = 0x02000000,
DescUseLink = 0x01000000,
/*
* Error summary flag is logical or of 'CRC Error', 'Collision Seen',
* 'Frame Too Long', 'Runt' and 'Descriptor Error' flags generated
* within tulip chip.
*/
RxDescErrorSummary = 0x8000,
RxDescCRCError = 0x0002,
RxDescCollisionSeen = 0x0040,
/*
* 'Frame Too Long' flag is set if packet length including CRC exceeds
* 1518. However, a full sized VLAN tagged frame is 1522 bytes
* including CRC.
*
* The tulip chip does not block oversized frames, and if this flag is
* set on a receive descriptor it does not indicate the frame has been
* truncated. The receive descriptor also includes the actual length.
* Therefore we can safety ignore this flag and check the length
* ourselves.
*/
RxDescFrameTooLong = 0x0080,
RxDescRunt = 0x0800,
RxDescDescErr = 0x4000,
RxWholePkt = 0x00000300,
/*
* Top three bits of 14 bit frame length (status bits 27-29) should
* never be set as that would make frame over 2047 bytes. The Receive
* Watchdog flag (bit 4) may indicate the length is over 2048 and the
* length field is invalid.
*/
RxLengthOver2047 = 0x38000010
};
enum t21143_csr6_bits {
csr6_sc = (1<<31),
csr6_ra = (1<<30),
csr6_ign_dest_msb = (1<<26),
csr6_mbo = (1<<25),
csr6_scr = (1<<24), /* scramble mode flag: can't be set */
csr6_pcs = (1<<23), /* Enables PCS functions (symbol mode requires csr6_ps be set) default is set */
csr6_ttm = (1<<22), /* Transmit Threshold Mode, set for 10baseT, 0 for 100BaseTX */
csr6_sf = (1<<21), /* Store and forward. If set ignores TR bits */
csr6_hbd = (1<<19), /* Heart beat disable. Disables SQE function in 10baseT */
csr6_ps = (1<<18), /* Port Select. 0 (defualt) = 10baseT, 1 = 100baseTX: can't be set */
csr6_ca = (1<<17), /* Collision Offset Enable. If set uses special algorithm in low collision situations */
csr6_trh = (1<<15), /* Transmit Threshold high bit */
csr6_trl = (1<<14), /* Transmit Threshold low bit */
/***************************************************************
* This table shows transmit threshold values based on media *
* and these two registers (from PNIC1 & 2 docs) Note: this is *
* all meaningless if sf is set. *
***************************************************************/
/***********************************
* (trh,trl) * 100BaseTX * 10BaseT *
***********************************
* (0,0) * 128 * 72 *
* (0,1) * 256 * 96 *
* (1,0) * 512 * 128 *
* (1,1) * 1024 * 160 *
***********************************/
csr6_fc = (1<<12), /* Forces a collision in next transmission (for testing in loopback mode) */
csr6_om_int_loop = (1<<10), /* internal (FIFO) loopback flag */
csr6_om_ext_loop = (1<<11), /* external (PMD) loopback flag */
/* set both and you get (PHY) loopback */
csr6_fd = (1<<9), /* Full duplex mode, disables hearbeat, no loopback */
csr6_pm = (1<<7), /* Pass All Multicast */
csr6_pr = (1<<6), /* Promiscuous mode */
csr6_sb = (1<<5), /* Start(1)/Stop(0) backoff counter */
csr6_if = (1<<4), /* Inverse Filtering, rejects only addresses in address table: can't be set */
csr6_pb = (1<<3), /* Pass Bad Frames, (1) causes even bad frames to be passed on */
csr6_ho = (1<<2), /* Hash-only filtering mode: can't be set */
csr6_hp = (1<<0), /* Hash/Perfect Receive Filtering Mode: can't be set */
csr6_mask_capture = (csr6_sc | csr6_ca),
csr6_mask_defstate = (csr6_mask_capture | csr6_mbo),
csr6_mask_hdcap = (csr6_mask_defstate | csr6_hbd | csr6_ps),
csr6_mask_hdcaptt = (csr6_mask_hdcap | csr6_trh | csr6_trl),
csr6_mask_fullcap = (csr6_mask_hdcaptt | csr6_fd),
csr6_mask_fullpromisc = (csr6_pr | csr6_pm),
csr6_mask_filters = (csr6_hp | csr6_ho | csr6_if),
csr6_mask_100bt = (csr6_scr | csr6_pcs | csr6_hbd),
};
enum tulip_comet_csr13_bits {
/* The LINKOFFE and LINKONE work in conjunction with LSCE, i.e. they
* determine which link status transition wakes up if LSCE is
* enabled */
comet_csr13_linkoffe = (1 << 17),
comet_csr13_linkone = (1 << 16),
comet_csr13_wfre = (1 << 10),
comet_csr13_mpre = (1 << 9),
comet_csr13_lsce = (1 << 8),
comet_csr13_wfr = (1 << 2),
comet_csr13_mpr = (1 << 1),
comet_csr13_lsc = (1 << 0),
};
enum tulip_comet_csr18_bits {
comet_csr18_pmes_sticky = (1 << 24),
comet_csr18_pm_mode = (1 << 19),
comet_csr18_apm_mode = (1 << 18),
comet_csr18_d3a = (1 << 7)
};
enum tulip_comet_csr20_bits {
comet_csr20_pmes = (1 << 15),
};
/* Keep the ring sizes a power of two for efficiency.
Making the Tx ring too large decreases the effectiveness of channel
bonding and packet priority.
There are no ill effects from too-large receive rings. */
#define TX_RING_SIZE 32
#define RX_RING_SIZE 128
#define MEDIA_MASK 31
/* The receiver on the DC21143 rev 65 can fail to close the last
* receive descriptor in certain circumstances (see errata) when
* using MWI. This can only occur if the receive buffer ends on
* a cache line boundary, so the "+ 4" below ensures it doesn't.
*/
#define PKT_BUF_SZ (1536 + 4) /* Size of each temporary Rx buffer. */
#define TULIP_MIN_CACHE_LINE 8 /* in units of 32-bit words */
#if defined(__sparc__) || defined(__hppa__)
/* The UltraSparc PCI controllers will disconnect at every 64-byte
* crossing anyways so it makes no sense to tell Tulip to burst
* any more than that.
*/
#define TULIP_MAX_CACHE_LINE 16 /* in units of 32-bit words */
#else
#define TULIP_MAX_CACHE_LINE 32 /* in units of 32-bit words */
#endif
/* Ring-wrap flag in length field, use for last ring entry.
0x01000000 means chain on buffer2 address,
0x02000000 means use the ring start address in CSR2/3.
Note: Some work-alike chips do not function correctly in chained mode.
The ASIX chip works only in chained mode.
Thus we indicates ring mode, but always write the 'next' field for
chained mode as well.
*/
#define DESC_RING_WRAP 0x02000000
#define EEPROM_SIZE 512 /* 2 << EEPROM_ADDRLEN */
#define RUN_AT(x) (jiffies + (x))
#define get_u16(ptr) get_unaligned_le16((ptr))
struct medialeaf {
u8 type;
u8 media;
unsigned char *leafdata;
};
struct mediatable {
u16 defaultmedia;
u8 leafcount;
u8 csr12dir; /* General purpose pin directions. */
unsigned has_mii:1;
unsigned has_nonmii:1;
unsigned has_reset:6;
u32 csr15dir;
u32 csr15val; /* 21143 NWay setting. */
struct medialeaf mleaf[0];
};
struct mediainfo {
struct mediainfo *next;
int info_type;
int index;
unsigned char *info;
};
struct ring_info {
struct sk_buff *skb;
dma_addr_t mapping;
};
struct tulip_private {
const char *product_name;
struct net_device *next_module;
struct tulip_rx_desc *rx_ring;
struct tulip_tx_desc *tx_ring;
dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct ring_info tx_buffers[TX_RING_SIZE];
/* The addresses of receive-in-place skbuffs. */
struct ring_info rx_buffers[RX_RING_SIZE];
u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */
int chip_id;
int revision;
int flags;
struct napi_struct napi;
struct timer_list timer; /* Media selection timer. */
struct timer_list oom_timer; /* Out of memory timer. */
u32 mc_filter[2];
spinlock_t lock;
spinlock_t mii_lock;
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
int mit_on;
#endif
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 nway:1, nwayset:1; /* 21143 internal NWay. */
unsigned int timeout_recovery:1;
unsigned int csr0; /* CSR0 setting. */
unsigned int csr6; /* Current CSR6 control settings. */
unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
void (*link_change) (struct net_device * dev, int csr5);
struct ethtool_wolinfo wolinfo; /* WOL settings */
u16 sym_advertise, mii_advertise; /* NWay capabilities advertised. */
u16 lpar; /* 21143 Link partner ability. */
u16 advertising[4];
signed char phys[4], mii_cnt; /* MII device addresses. */
struct mediatable *mtable;
int cur_index; /* Current media index. */
int saved_if_port;
struct pci_dev *pdev;
int ttimer;
int susp_rx;
unsigned long nir;
void __iomem *base_addr;
int csr12_shadow;
int pad0; /* Used for 8-byte alignment */
struct work_struct media_work;
struct net_device *dev;
};
struct eeprom_fixup {
char *name;
unsigned char addr0;
unsigned char addr1;
unsigned char addr2;
u16 newtable[32]; /* Max length below. */
};
/* 21142.c */
extern u16 t21142_csr14[];
void t21142_media_task(struct work_struct *work);
void t21142_start_nway(struct net_device *dev);
void t21142_lnk_change(struct net_device *dev, int csr5);
/* PNIC2.c */
void pnic2_lnk_change(struct net_device *dev, int csr5);
void pnic2_timer(unsigned long data);
void pnic2_start_nway(struct net_device *dev);
void pnic2_lnk_change(struct net_device *dev, int csr5);
/* eeprom.c */
void tulip_parse_eeprom(struct net_device *dev);
int tulip_read_eeprom(struct net_device *dev, int location, int addr_len);
/* interrupt.c */
extern unsigned int tulip_max_interrupt_work;
extern int tulip_rx_copybreak;
irqreturn_t tulip_interrupt(int irq, void *dev_instance);
int tulip_refill_rx(struct net_device *dev);
#ifdef CONFIG_TULIP_NAPI
int tulip_poll(struct napi_struct *napi, int budget);
#endif
/* media.c */
int tulip_mdio_read(struct net_device *dev, int phy_id, int location);
void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int value);
void tulip_select_media(struct net_device *dev, int startup);
int tulip_check_duplex(struct net_device *dev);
void tulip_find_mii (struct net_device *dev, int board_idx);
/* pnic.c */
void pnic_do_nway(struct net_device *dev);
void pnic_lnk_change(struct net_device *dev, int csr5);
void pnic_timer(unsigned long data);
/* timer.c */
void tulip_media_task(struct work_struct *work);
void mxic_timer(unsigned long data);
void comet_timer(unsigned long data);
/* tulip_core.c */
extern int tulip_debug;
extern const char * const medianame[];
extern const char tulip_media_cap[];
extern struct tulip_chip_table tulip_tbl[];
void oom_timer(unsigned long data);
extern u8 t21040_csr13[];
static inline void tulip_start_rxtx(struct tulip_private *tp)
{
void __iomem *ioaddr = tp->base_addr;
iowrite32(tp->csr6 | RxTx, ioaddr + CSR6);
barrier();
(void) ioread32(ioaddr + CSR6); /* mmio sync */
}
static inline void tulip_stop_rxtx(struct tulip_private *tp)
{
void __iomem *ioaddr = tp->base_addr;
u32 csr6 = ioread32(ioaddr + CSR6);
if (csr6 & RxTx) {
unsigned i=1300/10;
iowrite32(csr6 & ~RxTx, ioaddr + CSR6);
barrier();
/* wait until in-flight frame completes.
* Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin)
* Typically expect this loop to end in < 50 us on 100BT.
*/
while (--i && (ioread32(ioaddr + CSR5) & (CSR5_TS|CSR5_RS)))
udelay(10);
if (!i)
netdev_dbg(tp->dev, "tulip_stop_rxtx() failed (CSR5 0x%x CSR6 0x%x)\n",
ioread32(ioaddr + CSR5),
ioread32(ioaddr + CSR6));
}
}
static inline void tulip_restart_rxtx(struct tulip_private *tp)
{
tulip_stop_rxtx(tp);
udelay(5);
tulip_start_rxtx(tp);
}
static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __iomem *ioaddr)
{
/* Stop and restart the chip's Tx processes. */
tulip_restart_rxtx(tp);
/* Trigger an immediate transmit demand. */
iowrite32(0, ioaddr + CSR1);
tp->dev->stats.tx_errors++;
}
#endif /* __NET_TULIP_H__ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff