mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-11-01 08:38:52 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
21
drivers/net/ethernet/dec/Kconfig
Normal file
21
drivers/net/ethernet/dec/Kconfig
Normal 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
|
||||
5
drivers/net/ethernet/dec/Makefile
Normal file
5
drivers/net/ethernet/dec/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# Makefile for the Digital Equipment Inc. network device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_NET_TULIP) += tulip/
|
||||
257
drivers/net/ethernet/dec/tulip/21142.c
Normal file
257
drivers/net/ethernet/dec/tulip/21142.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
172
drivers/net/ethernet/dec/tulip/Kconfig
Normal file
172
drivers/net/ethernet/dec/tulip/Kconfig
Normal 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
|
||||
19
drivers/net/ethernet/dec/tulip/Makefile
Normal file
19
drivers/net/ethernet/dec/tulip/Makefile
Normal 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
|
||||
2207
drivers/net/ethernet/dec/tulip/de2104x.c
Normal file
2207
drivers/net/ethernet/dec/tulip/de2104x.c
Normal file
File diff suppressed because it is too large
Load diff
5589
drivers/net/ethernet/dec/tulip/de4x5.c
Normal file
5589
drivers/net/ethernet/dec/tulip/de4x5.c
Normal file
File diff suppressed because it is too large
Load diff
1017
drivers/net/ethernet/dec/tulip/de4x5.h
Normal file
1017
drivers/net/ethernet/dec/tulip/de4x5.h
Normal file
File diff suppressed because it is too large
Load diff
2273
drivers/net/ethernet/dec/tulip/dmfe.c
Normal file
2273
drivers/net/ethernet/dec/tulip/dmfe.c
Normal file
File diff suppressed because it is too large
Load diff
382
drivers/net/ethernet/dec/tulip/eeprom.c
Normal file
382
drivers/net/ethernet/dec/tulip/eeprom.c
Normal 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;
|
||||
}
|
||||
|
||||
814
drivers/net/ethernet/dec/tulip/interrupt.c
Normal file
814
drivers/net/ethernet/dec/tulip/interrupt.c
Normal 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;
|
||||
}
|
||||
552
drivers/net/ethernet/dec/tulip/media.c
Normal file
552
drivers/net/ethernet/dec/tulip/media.c
Normal 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;
|
||||
}
|
||||
}
|
||||
170
drivers/net/ethernet/dec/tulip/pnic.c
Normal file
170
drivers/net/ethernet/dec/tulip/pnic.c
Normal 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);
|
||||
}
|
||||
}
|
||||
403
drivers/net/ethernet/dec/tulip/pnic2.c
Normal file
403
drivers/net/ethernet/dec/tulip/pnic2.c
Normal 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);
|
||||
}
|
||||
|
||||
176
drivers/net/ethernet/dec/tulip/timer.c
Normal file
176
drivers/net/ethernet/dec/tulip/timer.c
Normal 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));
|
||||
}
|
||||
|
||||
570
drivers/net/ethernet/dec/tulip/tulip.h
Normal file
570
drivers/net/ethernet/dec/tulip/tulip.h
Normal 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__ */
|
||||
2001
drivers/net/ethernet/dec/tulip/tulip_core.c
Normal file
2001
drivers/net/ethernet/dec/tulip/tulip_core.c
Normal file
File diff suppressed because it is too large
Load diff
1845
drivers/net/ethernet/dec/tulip/uli526x.c
Normal file
1845
drivers/net/ethernet/dec/tulip/uli526x.c
Normal file
File diff suppressed because it is too large
Load diff
1665
drivers/net/ethernet/dec/tulip/winbond-840.c
Normal file
1665
drivers/net/ethernet/dec/tulip/winbond-840.c
Normal file
File diff suppressed because it is too large
Load diff
1171
drivers/net/ethernet/dec/tulip/xircom_cb.c
Normal file
1171
drivers/net/ethernet/dec/tulip/xircom_cb.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue