Index: head/share/man/man4/dc.4 =================================================================== --- head/share/man/man4/dc.4 (revision 123165) +++ head/share/man/man4/dc.4 (revision 123166) @@ -1,401 +1,403 @@ .\" Copyright (c) 1997, 1998, 1999 .\" Bill Paul . All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by Bill Paul. .\" 4. Neither the name of the author nor the names of any co-contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF .\" THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd November 20, 1999 .Dt DC 4 .Os .Sh NAME .Nm dc .Nd "DEC/Intel 21143 and clone 10/100 ethernet driver" .Sh SYNOPSIS .Cd "device miibus" .Cd "device dc" .Sh DESCRIPTION The .Nm driver provides support for several PCI fast ethernet adapters and embedded controllers based on the following chipsets: .Pp .Bl -bullet -compact -offset indent .It DEC/Intel 21143 .It ADMtek AL981 Comet, AN985 Centaur, ADM9511 Centaur II and ADM9513 Centaur II .It ASIX Electronics AX88140A and AX88141 .It Conexant LANfinity RS7112 (miniPCI) .It Davicom DM9009, DM9100, DM9102 and DM9102A .It Lite-On 82c168 and 82c169 PNIC .It Lite-On/Macronix 82c115 PNIC II .It Macronix 98713, 98713A, 98715, 98715A, 98715AEC-C, 98725, 98727 and 98732 .It Xircom X3201 (cardbus only) .El .Pp All of these chips have the same general register layout, DMA descriptor format and method of operation. All of the clone chips are based on the 21143 design with various modifications. The 21143 itself has support for 10baseT, BNC, AUI, MII and symbol media attachments, 10 and 100Mbps speeds in full or half duplex, built in NWAY autonegotiation and wake on LAN. The 21143 also offers several receive filter programming options including perfect filtering, inverse perfect filtering and hash table filtering. .Pp Some clone chips duplicate the 21143 fairly closely while others only maintain superficial similarities. Some support only MII media attachments. Others use different receiver filter programming mechanisms. At least one supports only chained DMA descriptors (most support both chained descriptors and contiguously allocated fixed size rings). Some chips (especially the PNIC) also have peculiar bugs. The .Nm driver does its best to provide generalized support for all of these chipsets in order to keep special case code to a minimum. .Pp These chips are used by many vendors which makes it difficult to provide a complete list of all supported cards. The following NICs are known to work with the .Nm driver at this time: .Pp .Bl -bullet -compact -offset indent .It 3Com OfficeConnect 10/100B (ADMtek AN985 Centaur-P) .It Abocom FE2500 .It Accton EN1217 (98715A) .It Accton EN2242 MiniPCI .It Adico AE310TX (98715A) .It Alfa Inc GFC2204 (ASIX AX88140A) .It Built in 10Mbps only ethernet on Compaq Presario 7900 series desktops (21143, non-MII) .It Built in DE500-BA on DEC Alpha workstations (21143, non-MII) .It Built in ethernet on LinkSys EtherFast 10/100 Instant GigaDrive (DM9102, MII) .It CNet Pro110B (ASIX AX88140A) .It CNet Pro120A (98715A or 98713A) and CNet Pro120B (98715) .It Compex RL100-TX (98713 or 98713A) .It D-Link DFE-570TX (21143, MII, quad port) .It Digital DE500-BA 10/100 (21143, non-MII) .It +ELECOM Laneed LD-CBL/TXA (ADMtek AN985) +.It Hawking CB102 CardBus .It IBM EtherJet Cardbus Adapter .It Intel PRO/100 Mobile Cardbus (versions that use the X3201 chipset) .It Jaton XpressNet (Davicom DM9102) .It Kingston KNE100TX (21143, MII) .It Kingston KNE110TX (PNIC 82c169) .It LinkSys LNE100TX (PNIC 82c168, 82c169) .It LinkSys LNE100TX v2.0 (PNIC II 82c115) .It LinkSys LNE100TX v4.0/4.1 (ADMtek AN985 Centaur-P) .It Matrox FastNIC 10/100 (PNIC 82c168, 82c169) .It Melco LGY-PCI-TXL .It Microsoft MN-120 10/100 CardBus (ADMTek Centaur-C) .It Microsoft MN-130 10/100 PCI (ADMTek Centaur-P) .It NDC SOHOware SFA110A (98713A) .It NDC SOHOware SFA110A Rev B4 (98715AEC-C) .It NetGear FA310-TX Rev. D1, D2 or D3 (PNIC 82c169) .It Netgear FA511 .It PlaneX FNW-3602-T (ADMtek AN985) .It SVEC PN102-TX (98713) .It Xircom Cardbus Realport .It Xircom Cardbus Ethernet 10/100 .It Xircom Cardbus Ethernet II 10/100 .El .Pp The .Nm driver supports the following media types: .Pp .Bl -tag -width xxxxxxxxxxxxxxxxxxxx .It autoselect Enable autoselection of the media type and options. The user can manually override the autoselected mode by adding media options to the .Pa /etc/rc.conf file. .Pp Note: the built-in NWAY autonegotiation on the original PNIC 82c168 chip is horribly broken and is not supported by the .Nm driver at this time (see the .Sx BUGS section for details). The original 82c168 appears on very early revisions of the LinkSys LNE100TX and Matrox FastNIC. .It 10baseT/UTP Set 10Mbps operation. The .Ar mediaopt option can also be used to enable .Ar full-duplex operation. Not specifying .Ar full duplex implies .Ar half-duplex mode. .It 100baseTX Set 100Mbps (fast ethernet) operation. The .Ar mediaopt option can also be used to enable .Ar full-duplex operation. Not specifying .Ar full duplex implies .Ar half-duplex mode. .El .Pp The .Nm driver supports the following media options: .Pp .Bl -tag -width xxxxxxxxxxxxxxxxxxxx .It full-duplex Force full duplex operation. The interface will operate in half duplex mode if this media option is not specified. .El .Pp Note that the 100baseTX media type may not be available on certain Intel 21143 adapters which support 10mbps media attachments only. For more information on configuring this device, see .Xr ifconfig 8 . .Sh DIAGNOSTICS .Bl -diag .It "dc%d: couldn't map ports/memory" A fatal initialization error has occurred. .It "dc%d: couldn't map interrupt" A fatal initialization error has occurred. .It "dc%d: watchdog timeout" A packet was queued for transmission and a transmit command was issued, but the device failed to acknowledge the transmission before a timeout expired. This can happen if the device is unable to deliver interrupts for some reason, of if there is a problem with the network connection (cable or network equipment) that results in a loss of link. .It "dc%d: no memory for rx list" The driver failed to allocate an mbuf for the receiver ring. .It "dc%d: TX underrun -- increasing TX threshold" The device generated a transmit underrun error while attempting to DMA and transmit a packet. This happens if the host is not able to DMA the packet data into the NIC's FIFO fast enough. The driver will dynamically increase the transmit start threshold so that more data must be DMAed into the FIFO before the NIC will start transmitting it onto the wire. .It "dc%d: TX underrun -- using store and forward mode" The device continued to generate transmit underruns even after all possible transmit start threshold settings had been tried, so the driver programmed the chip for store and forward mode. In this mode, the NIC will not begin transmission until the entire packet has been transfered into its FIFO memory. .It "dc%d: chip is in D3 power state -- setting to D0" This message applies only to adapters which support power management. Some operating systems place the controller in low power mode when shutting down, and some PCI BIOSes fail to bring the chip out of this state before configuring it. The controller loses all of its PCI configuration in the D3 state, so if the BIOS does not set it back to full power mode in time, it won't be able to configure it correctly. The driver tries to detect this condition and bring the adapter back to the D0 (full power) state, but this may not be enough to return the driver to a fully operational condition. If you see this message at boot time and the driver fails to attach the device as a network interface, you will have to perform a second warm boot to have the device properly configured. .Pp Note that this condition only occurs when warm booting from another operating system. If you power down your system prior to booting .Fx , the card should be configured correctly. .El .Sh SEE ALSO .Xr arp 4 , .Xr miibus 4 , .Xr netintro 4 , .Xr ng_ether 4 , .Xr ifconfig 8 .Rs .%T ADMtek AL981, AL983 and AL985 data sheets .%O http://www.admtek.com.tw .Re .Rs .%T ASIX Electronics AX88140A and AX88141 data sheets .%O http://www.asix.com.tw .Re .Rs .%T Davicom DM9102 data sheet .%O http://www.davicom8.com .Re .Rs .%T Intel 21143 Hardware Reference Manual .%O http://developer.intel.com .Re .Rs .%T Macronix 98713/A, 98715/A and 98725 data sheets .%O http://www.macronix.com .Re .Rs .%T Macronix 98713/A and 98715/A app notes .%O http://www.macronix.com .Re .Sh HISTORY The .Nm device driver first appeared in .Fx 4.0 . .Sh AUTHORS The .Nm driver was written by .An Bill Paul Aq wpaul@ee.columbia.edu . .Sh BUGS The Macronix application notes claim that in order to put the chips in normal operation, the driver must write a certain magic number into the CSR16 register. The numbers are documented in the app notes, but the exact meaning of the bits is not. .Pp The 98713A seems to have a problem with 10Mbps full duplex mode. The transmitter works but the receiver tends to produce many unexplained errors leading to very poor overall performance. The 98715A does not exhibit this problem. All other modes on the 98713A seem to work correctly. .Pp The original 82c168 PNIC chip has built in NWAY support which is used on certain early LinkSys LNE100TX and Matrox FastNIC cards, however it is horribly broken and difficult to use reliably. Consequently, autonegotiation is not currently supported for this chipset: the driver defaults the NIC to 10baseT half duplex, and it's up to the operator to manually select a different mode if necessary. (Later cards use an external MII transceiver to implement NWAY autonegotiation and work correctly.) .Pp The .Nm driver programs 82c168 and 82c169 PNIC chips to use the store and forward setting for the transmit start threshold by default. This is to work around problems with some NIC/PCI bus combinations where the PNIC can transmit corrupt frames when operating at 100Mbps, probably due to PCI DMA burst transfer errors. .Pp The 82c168 and 82c169 PNIC chips also have a receiver bug that sometimes manifests during periods of heavy receive and transmit activity, where the chip will improperly DMA received frames to the host. The chips appear to upload several kilobytes of garbage data along with the received frame data, dirtying several RX buffers instead of just the expected one. The .Nm driver detects this condition and will salvage the frame; however, it incurs a serious performance penalty in the process. .Pp The PNIC chips also sometimes generate a transmit underrun error when the driver attempts to download the receiver filter setup frame, which can result in the receive filter being incorrectly programmed. The .Nm driver will watch for this condition and requeue the setup frame until it is transfered successfully. .Pp The ADMtek AL981 chip (and possibly the AN985 as well) has been observed to sometimes wedge on transmit: this appears to happen when the driver queues a sequence of frames which cause it to wrap from the end of the transmit descriptor ring back to the beginning. The .Nm driver attempts to avoid this condition by not queuing any frames past the end of the transmit ring during a single invocation of the .Fn dc_start routine. This workaround has a negligible impact on transmit performance. Index: head/sys/dev/dc/if_dc.c =================================================================== --- head/sys/dev/dc/if_dc.c (revision 123165) +++ head/sys/dev/dc/if_dc.c (revision 123166) @@ -1,3866 +1,3868 @@ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * DEC "tulip" clone ethernet driver. Supports the DEC/Intel 21143 * series chips and several workalikes including the following: * * Macronix 98713/98715/98725/98727/98732 PMAC (www.macronix.com) * Macronix/Lite-On 82c115 PNIC II (www.macronix.com) * Lite-On 82c168/82c169 PNIC (www.litecom.com) * ASIX Electronics AX88140A (www.asix.com.tw) * ASIX Electronics AX88141 (www.asix.com.tw) * ADMtek AL981 (www.admtek.com.tw) * ADMtek AN985 (www.admtek.com.tw) * Netgear FA511 (www.netgear.com) Appears to be rebadged ADMTek AN985 * Davicom DM9100, DM9102, DM9102A (www.davicom8.com) * Accton EN1217 (www.accton.com) * Xircom X3201 (www.xircom.com) * Abocom FE2500 * Conexant LANfinity (www.conexant.com) * 3Com OfficeConnect 10/100B 3CSOHO100B (www.3com.com) * * Datasheets for the 21143 are available at developer.intel.com. * Datasheets for the clone parts can be found at their respective sites. * (Except for the PNIC; see www.freebsd.org/~wpaul/PNIC/pnic.ps.gz.) * The PNIC II is essentially a Macronix 98715A chip; the only difference * worth noting is that its multicast hash table is only 128 bits wide * instead of 512. * * Written by Bill Paul * Electrical Engineering Department * Columbia University, New York City */ /* * The Intel 21143 is the successor to the DEC 21140. It is basically * the same as the 21140 but with a few new features. The 21143 supports * three kinds of media attachments: * * o MII port, for 10Mbps and 100Mbps support and NWAY * autonegotiation provided by an external PHY. * o SYM port, for symbol mode 100Mbps support. * o 10baseT port. * o AUI/BNC port. * * The 100Mbps SYM port and 10baseT port can be used together in * combination with the internal NWAY support to create a 10/100 * autosensing configuration. * * Note that not all tulip workalikes are handled in this driver: we only * deal with those which are relatively well behaved. The Winbond is * handled separately due to its different register offsets and the * special handling needed for its various bugs. The PNIC is handled * here, but I'm not thrilled about it. * * All of the workalike chips use some form of MII transceiver support * with the exception of the Macronix chips, which also have a SYM port. * The ASIX AX88140A is also documented to have a SYM port, but all * the cards I've seen use an MII transceiver, probably because the * AX88140A doesn't support internal NWAY. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DC_USEIOSPACE #ifdef __alpha__ #define SRM_MEDIA #endif #include MODULE_DEPEND(dc, pci, 1, 1, 1); MODULE_DEPEND(dc, ether, 1, 1, 1); MODULE_DEPEND(dc, miibus, 1, 1, 1); /* "controller miibus0" required. See GENERIC if you get errors here. */ #include "miibus_if.h" /* * Various supported device vendors/types and their names. */ static struct dc_type dc_devs[] = { { DC_VENDORID_DEC, DC_DEVICEID_21143, "Intel 21143 10/100BaseTX" }, { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9009, "Davicom DM9009 10/100BaseTX" }, { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9100, "Davicom DM9100 10/100BaseTX" }, { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102, "Davicom DM9102 10/100BaseTX" }, { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102, "Davicom DM9102A 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_AL981, "ADMtek AL981 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_AN985, "ADMtek AN985 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_ADM9511, "ADMtek ADM9511 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_ADM9513, "ADMtek ADM9513 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_FA511, "Netgear FA511 10/100BaseTX" }, { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A, "ASIX AX88140A 10/100BaseTX" }, { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A, "ASIX AX88141 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_98713, "Macronix 98713 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_98713, "Macronix 98713A 10/100BaseTX" }, { DC_VENDORID_CP, DC_DEVICEID_98713_CP, "Compex RL100-TX 10/100BaseTX" }, { DC_VENDORID_CP, DC_DEVICEID_98713_CP, "Compex RL100-TX 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_987x5, "Macronix 98715/98715A 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_987x5, "Macronix 98715AEC-C 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_987x5, "Macronix 98725 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_98727, "Macronix 98727/98732 10/100BaseTX" }, { DC_VENDORID_LO, DC_DEVICEID_82C115, "LC82C115 PNIC II 10/100BaseTX" }, { DC_VENDORID_LO, DC_DEVICEID_82C168, "82c168 PNIC 10/100BaseTX" }, { DC_VENDORID_LO, DC_DEVICEID_82C168, "82c169 PNIC 10/100BaseTX" }, { DC_VENDORID_ACCTON, DC_DEVICEID_EN1217, "Accton EN1217 10/100BaseTX" }, { DC_VENDORID_ACCTON, DC_DEVICEID_EN2242, "Accton EN2242 MiniPCI 10/100BaseTX" }, { DC_VENDORID_XIRCOM, DC_DEVICEID_X3201, "Xircom X3201 10/100BaseTX" }, { DC_VENDORID_ABOCOM, DC_DEVICEID_FE2500, "Abocom FE2500 10/100BaseTX" }, + { DC_VENDORID_ABOCOM, DC_DEVICEID_FE2500MX, + "Abocom FE2500MX 10/100BaseTX" }, { DC_VENDORID_CONEXANT, DC_DEVICEID_RS7112, "Conexant LANfinity MiniPCI 10/100BaseTX" }, { DC_VENDORID_HAWKING, DC_DEVICEID_HAWKING_PN672TX, "Hawking CB102 CardBus 10/100" }, { DC_VENDORID_PLANEX, DC_DEVICEID_FNW3602T, "PlaneX FNW-3602-T CardBus 10/100" }, { DC_VENDORID_3COM, DC_DEVICEID_3CSOHOB, "3Com OfficeConnect 10/100B" }, { DC_VENDORID_MICROSOFT, DC_DEVICEID_MSMN120, "Microsoft MN-120 CardBus 10/100" }, { DC_VENDORID_MICROSOFT, DC_DEVICEID_MSMN130, "Microsoft MN-130 10/100" }, { DC_VENDORID_MICROSOFT, DC_DEVICEID_MSMN130_FAKE, "Microsoft MN-130 10/100" }, { 0, 0, NULL } }; static int dc_probe (device_t); static int dc_attach (device_t); static int dc_detach (device_t); static int dc_suspend (device_t); static int dc_resume (device_t); #ifndef BURN_BRIDGES static void dc_acpi (device_t); #endif static struct dc_type *dc_devtype (device_t); static int dc_newbuf (struct dc_softc *, int, int); static int dc_encap (struct dc_softc *, struct mbuf **); static void dc_pnic_rx_bug_war (struct dc_softc *, int); static int dc_rx_resync (struct dc_softc *); static void dc_rxeof (struct dc_softc *); static void dc_txeof (struct dc_softc *); static void dc_tick (void *); static void dc_tx_underrun (struct dc_softc *); static void dc_intr (void *); static void dc_start (struct ifnet *); static int dc_ioctl (struct ifnet *, u_long, caddr_t); static void dc_init (void *); static void dc_stop (struct dc_softc *); static void dc_watchdog (struct ifnet *); static void dc_shutdown (device_t); static int dc_ifmedia_upd (struct ifnet *); static void dc_ifmedia_sts (struct ifnet *, struct ifmediareq *); static void dc_delay (struct dc_softc *); static void dc_eeprom_idle (struct dc_softc *); static void dc_eeprom_putbyte (struct dc_softc *, int); static void dc_eeprom_getword (struct dc_softc *, int, u_int16_t *); static void dc_eeprom_getword_pnic (struct dc_softc *, int, u_int16_t *); static void dc_eeprom_getword_xircom (struct dc_softc *, int, u_int16_t *); static void dc_eeprom_width (struct dc_softc *); static void dc_read_eeprom (struct dc_softc *, caddr_t, int, int, int); static void dc_mii_writebit (struct dc_softc *, int); static int dc_mii_readbit (struct dc_softc *); static void dc_mii_sync (struct dc_softc *); static void dc_mii_send (struct dc_softc *, u_int32_t, int); static int dc_mii_readreg (struct dc_softc *, struct dc_mii_frame *); static int dc_mii_writereg (struct dc_softc *, struct dc_mii_frame *); static int dc_miibus_readreg (device_t, int, int); static int dc_miibus_writereg (device_t, int, int, int); static void dc_miibus_statchg (device_t); static void dc_miibus_mediainit (device_t); static void dc_setcfg (struct dc_softc *, int); static uint32_t dc_mchash_le (struct dc_softc *, const uint8_t *); static uint32_t dc_mchash_be (const uint8_t *); static void dc_setfilt_21143 (struct dc_softc *); static void dc_setfilt_asix (struct dc_softc *); static void dc_setfilt_admtek (struct dc_softc *); static void dc_setfilt_xircom (struct dc_softc *); static void dc_setfilt (struct dc_softc *); static void dc_reset (struct dc_softc *); static int dc_list_rx_init (struct dc_softc *); static int dc_list_tx_init (struct dc_softc *); static void dc_read_srom (struct dc_softc *, int); static void dc_parse_21143_srom (struct dc_softc *); static void dc_decode_leaf_sia (struct dc_softc *, struct dc_eblock_sia *); static void dc_decode_leaf_mii (struct dc_softc *, struct dc_eblock_mii *); static void dc_decode_leaf_sym (struct dc_softc *, struct dc_eblock_sym *); static void dc_apply_fixup (struct dc_softc *, int); static void dc_dma_map_txbuf (void *, bus_dma_segment_t *, int, bus_size_t, int); static void dc_dma_map_rxbuf (void *, bus_dma_segment_t *, int, bus_size_t, int); #ifdef DC_USEIOSPACE #define DC_RES SYS_RES_IOPORT #define DC_RID DC_PCI_CFBIO #else #define DC_RES SYS_RES_MEMORY #define DC_RID DC_PCI_CFBMA #endif static device_method_t dc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, dc_probe), DEVMETHOD(device_attach, dc_attach), DEVMETHOD(device_detach, dc_detach), DEVMETHOD(device_suspend, dc_suspend), DEVMETHOD(device_resume, dc_resume), DEVMETHOD(device_shutdown, dc_shutdown), /* bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), /* MII interface */ DEVMETHOD(miibus_readreg, dc_miibus_readreg), DEVMETHOD(miibus_writereg, dc_miibus_writereg), DEVMETHOD(miibus_statchg, dc_miibus_statchg), DEVMETHOD(miibus_mediainit, dc_miibus_mediainit), { 0, 0 } }; static driver_t dc_driver = { "dc", dc_methods, sizeof(struct dc_softc) }; static devclass_t dc_devclass; #ifdef __i386__ static int dc_quick = 1; SYSCTL_INT(_hw, OID_AUTO, dc_quick, CTLFLAG_RW, &dc_quick, 0, "do not m_devget() in dc driver"); #endif DRIVER_MODULE(dc, cardbus, dc_driver, dc_devclass, 0, 0); DRIVER_MODULE(dc, pci, dc_driver, dc_devclass, 0, 0); DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0); #define DC_SETBIT(sc, reg, x) \ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x)) #define DC_CLRBIT(sc, reg, x) \ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x)) #define SIO_SET(x) DC_SETBIT(sc, DC_SIO, (x)) #define SIO_CLR(x) DC_CLRBIT(sc, DC_SIO, (x)) #define IS_MPSAFE 0 static void dc_delay(struct dc_softc *sc) { int idx; for (idx = (300 / 33) + 1; idx > 0; idx--) CSR_READ_4(sc, DC_BUSCTL); } static void dc_eeprom_width(struct dc_softc *sc) { int i; /* Force EEPROM to idle state. */ dc_eeprom_idle(sc); /* Enter EEPROM access mode. */ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); for (i = 3; i--;) { if (6 & (1 << i)) DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); else DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); } for (i = 1; i <= 12; i++) { DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); if (!(CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT)) { DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); break; } DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); } /* Turn off EEPROM access mode. */ dc_eeprom_idle(sc); if (i < 4 || i > 12) sc->dc_romwidth = 6; else sc->dc_romwidth = i; /* Enter EEPROM access mode. */ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); /* Turn off EEPROM access mode. */ dc_eeprom_idle(sc); } static void dc_eeprom_idle(struct dc_softc *sc) { int i; CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); for (i = 0; i < 25; i++) { DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); } DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); CSR_WRITE_4(sc, DC_SIO, 0x00000000); } /* * Send a read command and address to the EEPROM, check for ACK. */ static void dc_eeprom_putbyte(struct dc_softc *sc, int addr) { int d, i; d = DC_EECMD_READ >> 6; for (i = 3; i--; ) { if (d & (1 << i)) DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); else DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); } /* * Feed in each bit and strobe the clock. */ for (i = sc->dc_romwidth; i--;) { if (addr & (1 << i)) { SIO_SET(DC_SIO_EE_DATAIN); } else { SIO_CLR(DC_SIO_EE_DATAIN); } dc_delay(sc); SIO_SET(DC_SIO_EE_CLK); dc_delay(sc); SIO_CLR(DC_SIO_EE_CLK); dc_delay(sc); } } /* * Read a word of data stored in the EEPROM at address 'addr.' * The PNIC 82c168/82c169 has its own non-standard way to read * the EEPROM. */ static void dc_eeprom_getword_pnic(struct dc_softc *sc, int addr, u_int16_t *dest) { int i; u_int32_t r; CSR_WRITE_4(sc, DC_PN_SIOCTL, DC_PN_EEOPCODE_READ | addr); for (i = 0; i < DC_TIMEOUT; i++) { DELAY(1); r = CSR_READ_4(sc, DC_SIO); if (!(r & DC_PN_SIOCTL_BUSY)) { *dest = (u_int16_t)(r & 0xFFFF); return; } } } /* * Read a word of data stored in the EEPROM at address 'addr.' * The Xircom X3201 has its own non-standard way to read * the EEPROM, too. */ static void dc_eeprom_getword_xircom(struct dc_softc *sc, int addr, u_int16_t *dest) { SIO_SET(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ); addr *= 2; CSR_WRITE_4(sc, DC_ROM, addr | 0x160); *dest = (u_int16_t)CSR_READ_4(sc, DC_SIO) & 0xff; addr += 1; CSR_WRITE_4(sc, DC_ROM, addr | 0x160); *dest |= ((u_int16_t)CSR_READ_4(sc, DC_SIO) & 0xff) << 8; SIO_CLR(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ); } /* * Read a word of data stored in the EEPROM at address 'addr.' */ static void dc_eeprom_getword(struct dc_softc *sc, int addr, u_int16_t *dest) { int i; u_int16_t word = 0; /* Force EEPROM to idle state. */ dc_eeprom_idle(sc); /* Enter EEPROM access mode. */ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); /* * Send address of word we want to read. */ dc_eeprom_putbyte(sc, addr); /* * Start reading bits from EEPROM. */ for (i = 0x8000; i; i >>= 1) { SIO_SET(DC_SIO_EE_CLK); dc_delay(sc); if (CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT) word |= i; dc_delay(sc); SIO_CLR(DC_SIO_EE_CLK); dc_delay(sc); } /* Turn off EEPROM access mode. */ dc_eeprom_idle(sc); *dest = word; } /* * Read a sequence of words from the EEPROM. */ static void dc_read_eeprom(struct dc_softc *sc, caddr_t dest, int off, int cnt, int swap) { int i; u_int16_t word = 0, *ptr; for (i = 0; i < cnt; i++) { if (DC_IS_PNIC(sc)) dc_eeprom_getword_pnic(sc, off + i, &word); else if (DC_IS_XIRCOM(sc)) dc_eeprom_getword_xircom(sc, off + i, &word); else dc_eeprom_getword(sc, off + i, &word); ptr = (u_int16_t *)(dest + (i * 2)); if (swap) *ptr = ntohs(word); else *ptr = word; } } /* * The following two routines are taken from the Macronix 98713 * Application Notes pp.19-21. */ /* * Write a bit to the MII bus. */ static void dc_mii_writebit(struct dc_softc *sc, int bit) { if (bit) CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE | DC_SIO_MII_DATAOUT); else CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE); DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK); DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK); } /* * Read a bit from the MII bus. */ static int dc_mii_readbit(struct dc_softc *sc) { CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_READ | DC_SIO_MII_DIR); CSR_READ_4(sc, DC_SIO); DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK); DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK); if (CSR_READ_4(sc, DC_SIO) & DC_SIO_MII_DATAIN) return (1); return (0); } /* * Sync the PHYs by setting data bit and strobing the clock 32 times. */ static void dc_mii_sync(struct dc_softc *sc) { int i; CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE); for (i = 0; i < 32; i++) dc_mii_writebit(sc, 1); } /* * Clock a series of bits through the MII. */ static void dc_mii_send(struct dc_softc *sc, u_int32_t bits, int cnt) { int i; for (i = (0x1 << (cnt - 1)); i; i >>= 1) dc_mii_writebit(sc, bits & i); } /* * Read an PHY register through the MII. */ static int dc_mii_readreg(struct dc_softc *sc, struct dc_mii_frame *frame) { int i, ack; DC_LOCK(sc); /* * Set up frame for RX. */ frame->mii_stdelim = DC_MII_STARTDELIM; frame->mii_opcode = DC_MII_READOP; frame->mii_turnaround = 0; frame->mii_data = 0; /* * Sync the PHYs. */ dc_mii_sync(sc); /* * Send command/address info. */ dc_mii_send(sc, frame->mii_stdelim, 2); dc_mii_send(sc, frame->mii_opcode, 2); dc_mii_send(sc, frame->mii_phyaddr, 5); dc_mii_send(sc, frame->mii_regaddr, 5); #ifdef notdef /* Idle bit */ dc_mii_writebit(sc, 1); dc_mii_writebit(sc, 0); #endif /* Check for ack. */ ack = dc_mii_readbit(sc); /* * Now try reading data bits. If the ack failed, we still * need to clock through 16 cycles to keep the PHY(s) in sync. */ if (ack) { for (i = 0; i < 16; i++) dc_mii_readbit(sc); goto fail; } for (i = 0x8000; i; i >>= 1) { if (!ack) { if (dc_mii_readbit(sc)) frame->mii_data |= i; } } fail: dc_mii_writebit(sc, 0); dc_mii_writebit(sc, 0); DC_UNLOCK(sc); if (ack) return (1); return (0); } /* * Write to a PHY register through the MII. */ static int dc_mii_writereg(struct dc_softc *sc, struct dc_mii_frame *frame) { DC_LOCK(sc); /* * Set up frame for TX. */ frame->mii_stdelim = DC_MII_STARTDELIM; frame->mii_opcode = DC_MII_WRITEOP; frame->mii_turnaround = DC_MII_TURNAROUND; /* * Sync the PHYs. */ dc_mii_sync(sc); dc_mii_send(sc, frame->mii_stdelim, 2); dc_mii_send(sc, frame->mii_opcode, 2); dc_mii_send(sc, frame->mii_phyaddr, 5); dc_mii_send(sc, frame->mii_regaddr, 5); dc_mii_send(sc, frame->mii_turnaround, 2); dc_mii_send(sc, frame->mii_data, 16); /* Idle bit. */ dc_mii_writebit(sc, 0); dc_mii_writebit(sc, 0); DC_UNLOCK(sc); return (0); } static int dc_miibus_readreg(device_t dev, int phy, int reg) { struct dc_mii_frame frame; struct dc_softc *sc; int i, rval, phy_reg = 0; sc = device_get_softc(dev); bzero(&frame, sizeof(frame)); /* * Note: both the AL981 and AN985 have internal PHYs, * however the AL981 provides direct access to the PHY * registers while the AN985 uses a serial MII interface. * The AN985's MII interface is also buggy in that you * can read from any MII address (0 to 31), but only address 1 * behaves normally. To deal with both cases, we pretend * that the PHY is at MII address 1. */ if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR) return (0); /* * Note: the ukphy probes of the RS7112 report a PHY at * MII address 0 (possibly HomePNA?) and 1 (ethernet) * so we only respond to correct one. */ if (DC_IS_CONEXANT(sc) && phy != DC_CONEXANT_PHYADDR) return (0); if (sc->dc_pmode != DC_PMODE_MII) { if (phy == (MII_NPHY - 1)) { switch (reg) { case MII_BMSR: /* * Fake something to make the probe * code think there's a PHY here. */ return (BMSR_MEDIAMASK); break; case MII_PHYIDR1: if (DC_IS_PNIC(sc)) return (DC_VENDORID_LO); return (DC_VENDORID_DEC); break; case MII_PHYIDR2: if (DC_IS_PNIC(sc)) return (DC_DEVICEID_82C168); return (DC_DEVICEID_21143); break; default: return (0); break; } } else return (0); } if (DC_IS_PNIC(sc)) { CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_READ | (phy << 23) | (reg << 18)); for (i = 0; i < DC_TIMEOUT; i++) { DELAY(1); rval = CSR_READ_4(sc, DC_PN_MII); if (!(rval & DC_PN_MII_BUSY)) { rval &= 0xFFFF; return (rval == 0xFFFF ? 0 : rval); } } return (0); } if (DC_IS_COMET(sc)) { switch (reg) { case MII_BMCR: phy_reg = DC_AL_BMCR; break; case MII_BMSR: phy_reg = DC_AL_BMSR; break; case MII_PHYIDR1: phy_reg = DC_AL_VENID; break; case MII_PHYIDR2: phy_reg = DC_AL_DEVID; break; case MII_ANAR: phy_reg = DC_AL_ANAR; break; case MII_ANLPAR: phy_reg = DC_AL_LPAR; break; case MII_ANER: phy_reg = DC_AL_ANER; break; default: printf("dc%d: phy_read: bad phy register %x\n", sc->dc_unit, reg); return (0); break; } rval = CSR_READ_4(sc, phy_reg) & 0x0000FFFF; if (rval == 0xFFFF) return (0); return (rval); } frame.mii_phyaddr = phy; frame.mii_regaddr = reg; if (sc->dc_type == DC_TYPE_98713) { phy_reg = CSR_READ_4(sc, DC_NETCFG); CSR_WRITE_4(sc, DC_NETCFG, phy_reg & ~DC_NETCFG_PORTSEL); } dc_mii_readreg(sc, &frame); if (sc->dc_type == DC_TYPE_98713) CSR_WRITE_4(sc, DC_NETCFG, phy_reg); return (frame.mii_data); } static int dc_miibus_writereg(device_t dev, int phy, int reg, int data) { struct dc_softc *sc; struct dc_mii_frame frame; int i, phy_reg = 0; sc = device_get_softc(dev); bzero(&frame, sizeof(frame)); if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR) return (0); if (DC_IS_CONEXANT(sc) && phy != DC_CONEXANT_PHYADDR) return (0); if (DC_IS_PNIC(sc)) { CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_WRITE | (phy << 23) | (reg << 10) | data); for (i = 0; i < DC_TIMEOUT; i++) { if (!(CSR_READ_4(sc, DC_PN_MII) & DC_PN_MII_BUSY)) break; } return (0); } if (DC_IS_COMET(sc)) { switch (reg) { case MII_BMCR: phy_reg = DC_AL_BMCR; break; case MII_BMSR: phy_reg = DC_AL_BMSR; break; case MII_PHYIDR1: phy_reg = DC_AL_VENID; break; case MII_PHYIDR2: phy_reg = DC_AL_DEVID; break; case MII_ANAR: phy_reg = DC_AL_ANAR; break; case MII_ANLPAR: phy_reg = DC_AL_LPAR; break; case MII_ANER: phy_reg = DC_AL_ANER; break; default: printf("dc%d: phy_write: bad phy register %x\n", sc->dc_unit, reg); return (0); break; } CSR_WRITE_4(sc, phy_reg, data); return (0); } frame.mii_phyaddr = phy; frame.mii_regaddr = reg; frame.mii_data = data; if (sc->dc_type == DC_TYPE_98713) { phy_reg = CSR_READ_4(sc, DC_NETCFG); CSR_WRITE_4(sc, DC_NETCFG, phy_reg & ~DC_NETCFG_PORTSEL); } dc_mii_writereg(sc, &frame); if (sc->dc_type == DC_TYPE_98713) CSR_WRITE_4(sc, DC_NETCFG, phy_reg); return (0); } static void dc_miibus_statchg(device_t dev) { struct dc_softc *sc; struct mii_data *mii; struct ifmedia *ifm; sc = device_get_softc(dev); if (DC_IS_ADMTEK(sc)) return; mii = device_get_softc(sc->dc_miibus); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc) && IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) { dc_setcfg(sc, ifm->ifm_media); sc->dc_if_media = ifm->ifm_media; } else { dc_setcfg(sc, mii->mii_media_active); sc->dc_if_media = mii->mii_media_active; } } /* * Special support for DM9102A cards with HomePNA PHYs. Note: * with the Davicom DM9102A/DM9801 eval board that I have, it seems * to be impossible to talk to the management interface of the DM9801 * PHY (its MDIO pin is not connected to anything). Consequently, * the driver has to just 'know' about the additional mode and deal * with it itself. *sigh* */ static void dc_miibus_mediainit(device_t dev) { struct dc_softc *sc; struct mii_data *mii; struct ifmedia *ifm; int rev; rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF; sc = device_get_softc(dev); mii = device_get_softc(sc->dc_miibus); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc) && rev >= DC_REVISION_DM9102A) ifmedia_add(ifm, IFM_ETHER | IFM_HPNA_1, 0, NULL); } #define DC_POLY 0xEDB88320 #define DC_BITS_512 9 #define DC_BITS_128 7 #define DC_BITS_64 6 static uint32_t dc_mchash_le(struct dc_softc *sc, const uint8_t *addr) { uint32_t crc; int idx, bit; uint8_t data; /* Compute CRC for the address value. */ crc = 0xFFFFFFFF; /* initial value */ for (idx = 0; idx < 6; idx++) { for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DC_POLY : 0); } /* * The hash table on the PNIC II and the MX98715AEC-C/D/E * chips is only 128 bits wide. */ if (sc->dc_flags & DC_128BIT_HASH) return (crc & ((1 << DC_BITS_128) - 1)); /* The hash table on the MX98715BEC is only 64 bits wide. */ if (sc->dc_flags & DC_64BIT_HASH) return (crc & ((1 << DC_BITS_64) - 1)); /* Xircom's hash filtering table is different (read: weird) */ /* Xircom uses the LEAST significant bits */ if (DC_IS_XIRCOM(sc)) { if ((crc & 0x180) == 0x180) return ((crc & 0x0F) + (crc & 0x70) * 3 + (14 << 4)); else return ((crc & 0x1F) + ((crc >> 1) & 0xF0) * 3 + (12 << 4)); } return (crc & ((1 << DC_BITS_512) - 1)); } /* * Calculate CRC of a multicast group address, return the lower 6 bits. */ static uint32_t dc_mchash_be(const uint8_t *addr) { uint32_t crc, carry; int idx, bit; uint8_t data; /* Compute CRC for the address value. */ crc = 0xFFFFFFFF; /* initial value */ for (idx = 0; idx < 6; idx++) { for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) { carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01); data >>= 1; crc <<= 1; if (carry) crc = (crc ^ 0x04c11db6) | carry; } } /* Return the filter bit position. */ return ((crc >> 26) & 0x0000003F); } /* * 21143-style RX filter setup routine. Filter programming is done by * downloading a special setup frame into the TX engine. 21143, Macronix, * PNIC, PNIC II and Davicom chips are programmed this way. * * We always program the chip using 'hash perfect' mode, i.e. one perfect * address (our node address) and a 512-bit hash filter for multicast * frames. We also sneak the broadcast address into the hash filter since * we need that too. */ static void dc_setfilt_21143(struct dc_softc *sc) { struct dc_desc *sframe; u_int32_t h, *sp; struct ifmultiaddr *ifma; struct ifnet *ifp; int i; ifp = &sc->arpcom.ac_if; i = sc->dc_cdata.dc_tx_prod; DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT); sc->dc_cdata.dc_tx_cnt++; sframe = &sc->dc_ldata->dc_tx_list[i]; sp = sc->dc_cdata.dc_sbuf; bzero(sp, DC_SFRAME_LEN); sframe->dc_data = htole32(sc->dc_saddr); sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK | DC_FILTER_HASHPERF | DC_TXCTL_FINT); sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)sc->dc_cdata.dc_sbuf; /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); if (ifp->if_flags & IFF_ALLMULTI) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); sp[h >> 4] |= htole32(1 << (h & 0xF)); } if (ifp->if_flags & IFF_BROADCAST) { h = dc_mchash_le(sc, ifp->if_broadcastaddr); sp[h >> 4] |= htole32(1 << (h & 0xF)); } /* Set our MAC address */ sp[39] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[0]); sp[40] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[1]); sp[41] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[2]); sframe->dc_status = htole32(DC_TXSTAT_OWN); CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); /* * The PNIC takes an exceedingly long time to process its * setup frame; wait 10ms after posting the setup frame * before proceeding, just so it has time to swallow its * medicine. */ DELAY(10000); ifp->if_timer = 5; } static void dc_setfilt_admtek(struct dc_softc *sc) { struct ifnet *ifp; struct ifmultiaddr *ifma; int h = 0; u_int32_t hashes[2] = { 0, 0 }; ifp = &sc->arpcom.ac_if; /* Init our MAC address. */ CSR_WRITE_4(sc, DC_AL_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0])); CSR_WRITE_4(sc, DC_AL_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4])); /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); if (ifp->if_flags & IFF_ALLMULTI) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); /* First, zot all the existing hash bits. */ CSR_WRITE_4(sc, DC_AL_MAR0, 0); CSR_WRITE_4(sc, DC_AL_MAR1, 0); /* * If we're already in promisc or allmulti mode, we * don't have to bother programming the multicast filter. */ if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) return; /* Now program new ones. */ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; if (DC_IS_CENTAUR(sc)) h = dc_mchash_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); else h = dc_mchash_be( LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); } CSR_WRITE_4(sc, DC_AL_MAR0, hashes[0]); CSR_WRITE_4(sc, DC_AL_MAR1, hashes[1]); } static void dc_setfilt_asix(struct dc_softc *sc) { struct ifnet *ifp; struct ifmultiaddr *ifma; int h = 0; u_int32_t hashes[2] = { 0, 0 }; ifp = &sc->arpcom.ac_if; /* Init our MAC address */ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR0); CSR_WRITE_4(sc, DC_AX_FILTDATA, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0])); CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR1); CSR_WRITE_4(sc, DC_AX_FILTDATA, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4])); /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); if (ifp->if_flags & IFF_ALLMULTI) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); /* * The ASIX chip has a special bit to enable reception * of broadcast frames. */ if (ifp->if_flags & IFF_BROADCAST) DC_SETBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD); else DC_CLRBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD); /* first, zot all the existing hash bits */ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0); CSR_WRITE_4(sc, DC_AX_FILTDATA, 0); CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1); CSR_WRITE_4(sc, DC_AX_FILTDATA, 0); /* * If we're already in promisc or allmulti mode, we * don't have to bother programming the multicast filter. */ if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) return; /* now program new ones */ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); } CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0); CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[0]); CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1); CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[1]); } static void dc_setfilt_xircom(struct dc_softc *sc) { struct ifnet *ifp; struct ifmultiaddr *ifma; struct dc_desc *sframe; u_int32_t h, *sp; int i; ifp = &sc->arpcom.ac_if; DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON)); i = sc->dc_cdata.dc_tx_prod; DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT); sc->dc_cdata.dc_tx_cnt++; sframe = &sc->dc_ldata->dc_tx_list[i]; sp = sc->dc_cdata.dc_sbuf; bzero(sp, DC_SFRAME_LEN); sframe->dc_data = htole32(sc->dc_saddr); sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK | DC_FILTER_HASHPERF | DC_TXCTL_FINT); sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)sc->dc_cdata.dc_sbuf; /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); if (ifp->if_flags & IFF_ALLMULTI) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); sp[h >> 4] |= htole32(1 << (h & 0xF)); } if (ifp->if_flags & IFF_BROADCAST) { h = dc_mchash_le(sc, ifp->if_broadcastaddr); sp[h >> 4] |= htole32(1 << (h & 0xF)); } /* Set our MAC address */ sp[0] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[0]); sp[1] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[1]); sp[2] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[2]); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON); ifp->if_flags |= IFF_RUNNING; sframe->dc_status = htole32(DC_TXSTAT_OWN); CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); /* * Wait some time... */ DELAY(1000); ifp->if_timer = 5; } static void dc_setfilt(struct dc_softc *sc) { if (DC_IS_INTEL(sc) || DC_IS_MACRONIX(sc) || DC_IS_PNIC(sc) || DC_IS_PNICII(sc) || DC_IS_DAVICOM(sc) || DC_IS_CONEXANT(sc)) dc_setfilt_21143(sc); if (DC_IS_ASIX(sc)) dc_setfilt_asix(sc); if (DC_IS_ADMTEK(sc)) dc_setfilt_admtek(sc); if (DC_IS_XIRCOM(sc)) dc_setfilt_xircom(sc); } /* * In order to fiddle with the 'full-duplex' and '100Mbps' bits in * the netconfig register, we first have to put the transmit and/or * receive logic in the idle state. */ static void dc_setcfg(struct dc_softc *sc, int media) { int i, restart = 0, watchdogreg; u_int32_t isr; if (IFM_SUBTYPE(media) == IFM_NONE) return; if (CSR_READ_4(sc, DC_NETCFG) & (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON)) { restart = 1; DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON)); for (i = 0; i < DC_TIMEOUT; i++) { isr = CSR_READ_4(sc, DC_ISR); if (isr & DC_ISR_TX_IDLE && ((isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED || (isr & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT)) break; DELAY(10); } if (i == DC_TIMEOUT) printf("dc%d: failed to force tx and " "rx to idle state\n", sc->dc_unit); } if (IFM_SUBTYPE(media) == IFM_100_TX) { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT); if (sc->dc_pmode == DC_PMODE_MII) { if (DC_IS_INTEL(sc)) { /* There's a write enable bit here that reads as 1. */ watchdogreg = CSR_READ_4(sc, DC_WATCHDOG); watchdogreg &= ~DC_WDOG_CTLWREN; watchdogreg |= DC_WDOG_JABBERDIS; CSR_WRITE_4(sc, DC_WATCHDOG, watchdogreg); } else { DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS); } DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS | DC_NETCFG_PORTSEL | DC_NETCFG_SCRAMBLER)); if (sc->dc_type == DC_TYPE_98713) DC_SETBIT(sc, DC_NETCFG, (DC_NETCFG_PCS | DC_NETCFG_SCRAMBLER)); if (!DC_IS_DAVICOM(sc)) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); if (DC_IS_INTEL(sc)) dc_apply_fixup(sc, IFM_AUTO); } else { if (DC_IS_PNIC(sc)) { DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_SPEEDSEL); DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP); DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL); } DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER); if (DC_IS_INTEL(sc)) dc_apply_fixup(sc, (media & IFM_GMASK) == IFM_FDX ? IFM_100_TX | IFM_FDX : IFM_100_TX); } } if (IFM_SUBTYPE(media) == IFM_10_T) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT); if (sc->dc_pmode == DC_PMODE_MII) { /* There's a write enable bit here that reads as 1. */ if (DC_IS_INTEL(sc)) { watchdogreg = CSR_READ_4(sc, DC_WATCHDOG); watchdogreg &= ~DC_WDOG_CTLWREN; watchdogreg |= DC_WDOG_JABBERDIS; CSR_WRITE_4(sc, DC_WATCHDOG, watchdogreg); } else { DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS); } DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS | DC_NETCFG_PORTSEL | DC_NETCFG_SCRAMBLER)); if (sc->dc_type == DC_TYPE_98713) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS); if (!DC_IS_DAVICOM(sc)) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); if (DC_IS_INTEL(sc)) dc_apply_fixup(sc, IFM_AUTO); } else { if (DC_IS_PNIC(sc)) { DC_PN_GPIO_CLRBIT(sc, DC_PN_GPIO_SPEEDSEL); DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP); DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL); } DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PCS); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER); if (DC_IS_INTEL(sc)) { DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); if ((media & IFM_GMASK) == IFM_FDX) DC_SETBIT(sc, DC_10BTCTRL, 0x7F3D); else DC_SETBIT(sc, DC_10BTCTRL, 0x7F3F); DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); DC_CLRBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); dc_apply_fixup(sc, (media & IFM_GMASK) == IFM_FDX ? IFM_10_T | IFM_FDX : IFM_10_T); DELAY(20000); } } } /* * If this is a Davicom DM9102A card with a DM9801 HomePNA * PHY and we want HomePNA mode, set the portsel bit to turn * on the external MII port. */ if (DC_IS_DAVICOM(sc)) { if (IFM_SUBTYPE(media) == IFM_HPNA_1) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); sc->dc_link = 1; } else { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); } } if ((media & IFM_GMASK) == IFM_FDX) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc)) DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX); } else { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc)) DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX); } if (restart) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON | DC_NETCFG_RX_ON); } static void dc_reset(struct dc_softc *sc) { int i; DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET); for (i = 0; i < DC_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_4(sc, DC_BUSCTL) & DC_BUSCTL_RESET)) break; } if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc) || DC_IS_CONEXANT(sc) || DC_IS_XIRCOM(sc) || DC_IS_INTEL(sc)) { DELAY(10000); DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET); i = 0; } if (i == DC_TIMEOUT) printf("dc%d: reset never completed!\n", sc->dc_unit); /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); CSR_WRITE_4(sc, DC_IMR, 0x00000000); CSR_WRITE_4(sc, DC_BUSCTL, 0x00000000); CSR_WRITE_4(sc, DC_NETCFG, 0x00000000); /* * Bring the SIA out of reset. In some cases, it looks * like failing to unreset the SIA soon enough gets it * into a state where it will never come out of reset * until we reset the whole chip again. */ if (DC_IS_INTEL(sc)) { DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); CSR_WRITE_4(sc, DC_10BTCTRL, 0); CSR_WRITE_4(sc, DC_WATCHDOG, 0); } } static struct dc_type * dc_devtype(device_t dev) { struct dc_type *t; u_int32_t rev; t = dc_devs; while (t->dc_name != NULL) { if ((pci_get_vendor(dev) == t->dc_vid) && (pci_get_device(dev) == t->dc_did)) { /* Check the PCI revision */ rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF; if (t->dc_did == DC_DEVICEID_98713 && rev >= DC_REVISION_98713A) t++; if (t->dc_did == DC_DEVICEID_98713_CP && rev >= DC_REVISION_98713A) t++; if (t->dc_did == DC_DEVICEID_987x5 && rev >= DC_REVISION_98715AEC_C) t++; if (t->dc_did == DC_DEVICEID_987x5 && rev >= DC_REVISION_98725) t++; if (t->dc_did == DC_DEVICEID_AX88140A && rev >= DC_REVISION_88141) t++; if (t->dc_did == DC_DEVICEID_82C168 && rev >= DC_REVISION_82C169) t++; if (t->dc_did == DC_DEVICEID_DM9102 && rev >= DC_REVISION_DM9102A) t++; /* * The Microsoft MN-130 has a device ID of 0x0002, * which happens to be the same as the PNIC 82c168. * To keep dc_attach() from getting confused, we * pretend its ID is something different. * XXX: ideally, dc_attach() should be checking * vendorid+deviceid together to avoid such * collisions. */ if (t->dc_vid == DC_VENDORID_MICROSOFT && t->dc_did == DC_DEVICEID_MSMN130) t++; return (t); } t++; } return (NULL); } /* * Probe for a 21143 or clone chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. * We do a little bit of extra work to identify the exact type of * chip. The MX98713 and MX98713A have the same PCI vendor/device ID, * but different revision IDs. The same is true for 98715/98715A * chips and the 98725, as well as the ASIX and ADMtek chips. In some * cases, the exact chip revision affects driver behavior. */ static int dc_probe(device_t dev) { struct dc_type *t; t = dc_devtype(dev); if (t != NULL) { device_set_desc(dev, t->dc_name); return (0); } return (ENXIO); } #ifndef BURN_BRIDGES static void dc_acpi(device_t dev) { int unit; u_int32_t iobase, membase, irq; unit = device_get_unit(dev); if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { /* Save important PCI config data. */ iobase = pci_read_config(dev, DC_PCI_CFBIO, 4); membase = pci_read_config(dev, DC_PCI_CFBMA, 4); irq = pci_read_config(dev, DC_PCI_CFIT, 4); /* Reset the power state. */ printf("dc%d: chip is in D%d power mode " "-- setting to D0\n", unit, pci_get_powerstate(dev)); pci_set_powerstate(dev, PCI_POWERSTATE_D0); /* Restore PCI config data. */ pci_write_config(dev, DC_PCI_CFBIO, iobase, 4); pci_write_config(dev, DC_PCI_CFBMA, membase, 4); pci_write_config(dev, DC_PCI_CFIT, irq, 4); } } #endif static void dc_apply_fixup(struct dc_softc *sc, int media) { struct dc_mediainfo *m; u_int8_t *p; int i; u_int32_t reg; m = sc->dc_mi; while (m != NULL) { if (m->dc_media == media) break; m = m->dc_next; } if (m == NULL) return; for (i = 0, p = m->dc_reset_ptr; i < m->dc_reset_len; i++, p += 2) { reg = (p[0] | (p[1] << 8)) << 16; CSR_WRITE_4(sc, DC_WATCHDOG, reg); } for (i = 0, p = m->dc_gp_ptr; i < m->dc_gp_len; i++, p += 2) { reg = (p[0] | (p[1] << 8)) << 16; CSR_WRITE_4(sc, DC_WATCHDOG, reg); } } static void dc_decode_leaf_sia(struct dc_softc *sc, struct dc_eblock_sia *l) { struct dc_mediainfo *m; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); switch (l->dc_sia_code & ~DC_SIA_CODE_EXT) { case DC_SIA_CODE_10BT: m->dc_media = IFM_10_T; break; case DC_SIA_CODE_10BT_FDX: m->dc_media = IFM_10_T | IFM_FDX; break; case DC_SIA_CODE_10B2: m->dc_media = IFM_10_2; break; case DC_SIA_CODE_10B5: m->dc_media = IFM_10_5; break; default: break; } /* * We need to ignore CSR13, CSR14, CSR15 for SIA mode. * Things apparently already work for cards that do * supply Media Specific Data. */ if (l->dc_sia_code & DC_SIA_CODE_EXT) { m->dc_gp_len = 2; m->dc_gp_ptr = (u_int8_t *)&l->dc_un.dc_sia_ext.dc_sia_gpio_ctl; } else { m->dc_gp_len = 2; m->dc_gp_ptr = (u_int8_t *)&l->dc_un.dc_sia_noext.dc_sia_gpio_ctl; } m->dc_next = sc->dc_mi; sc->dc_mi = m; sc->dc_pmode = DC_PMODE_SIA; } static void dc_decode_leaf_sym(struct dc_softc *sc, struct dc_eblock_sym *l) { struct dc_mediainfo *m; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (l->dc_sym_code == DC_SYM_CODE_100BT) m->dc_media = IFM_100_TX; if (l->dc_sym_code == DC_SYM_CODE_100BT_FDX) m->dc_media = IFM_100_TX | IFM_FDX; m->dc_gp_len = 2; m->dc_gp_ptr = (u_int8_t *)&l->dc_sym_gpio_ctl; m->dc_next = sc->dc_mi; sc->dc_mi = m; sc->dc_pmode = DC_PMODE_SYM; } static void dc_decode_leaf_mii(struct dc_softc *sc, struct dc_eblock_mii *l) { struct dc_mediainfo *m; u_int8_t *p; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); /* We abuse IFM_AUTO to represent MII. */ m->dc_media = IFM_AUTO; m->dc_gp_len = l->dc_gpr_len; p = (u_int8_t *)l; p += sizeof(struct dc_eblock_mii); m->dc_gp_ptr = p; p += 2 * l->dc_gpr_len; m->dc_reset_len = *p; p++; m->dc_reset_ptr = p; m->dc_next = sc->dc_mi; sc->dc_mi = m; } static void dc_read_srom(struct dc_softc *sc, int bits) { int size; size = 2 << bits; sc->dc_srom = malloc(size, M_DEVBUF, M_NOWAIT); dc_read_eeprom(sc, (caddr_t)sc->dc_srom, 0, (size / 2), 0); } static void dc_parse_21143_srom(struct dc_softc *sc) { struct dc_leaf_hdr *lhdr; struct dc_eblock_hdr *hdr; int have_mii, i, loff; char *ptr; have_mii = 0; loff = sc->dc_srom[27]; lhdr = (struct dc_leaf_hdr *)&(sc->dc_srom[loff]); ptr = (char *)lhdr; ptr += sizeof(struct dc_leaf_hdr) - 1; /* * Look if we got a MII media block. */ for (i = 0; i < lhdr->dc_mcnt; i++) { hdr = (struct dc_eblock_hdr *)ptr; if (hdr->dc_type == DC_EBLOCK_MII) have_mii++; ptr += (hdr->dc_len & 0x7F); ptr++; } /* * Do the same thing again. Only use SIA and SYM media * blocks if no MII media block is available. */ ptr = (char *)lhdr; ptr += sizeof(struct dc_leaf_hdr) - 1; for (i = 0; i < lhdr->dc_mcnt; i++) { hdr = (struct dc_eblock_hdr *)ptr; switch (hdr->dc_type) { case DC_EBLOCK_MII: dc_decode_leaf_mii(sc, (struct dc_eblock_mii *)hdr); break; case DC_EBLOCK_SIA: if (! have_mii) dc_decode_leaf_sia(sc, (struct dc_eblock_sia *)hdr); break; case DC_EBLOCK_SYM: if (! have_mii) dc_decode_leaf_sym(sc, (struct dc_eblock_sym *)hdr); break; default: /* Don't care. Yet. */ break; } ptr += (hdr->dc_len & 0x7F); ptr++; } } static void dc_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) { u_int32_t *paddr; KASSERT(nseg == 1, ("wrong number of segments, should be 1")); paddr = arg; *paddr = segs->ds_addr; } /* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */ static int dc_attach(device_t dev) { int tmp = 0; u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command; struct dc_softc *sc; struct ifnet *ifp; u_int32_t revision; int unit, error = 0, rid, mac_offset; int i; u_int8_t *mac; sc = device_get_softc(dev); unit = device_get_unit(dev); mtx_init(&sc->dc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); #ifndef BURN_BRIDGES /* * Handle power management nonsense. */ dc_acpi(dev); #endif /* * Map control/status registers. */ pci_enable_busmaster(dev); rid = DC_RID; sc->dc_res = bus_alloc_resource(dev, DC_RES, &rid, 0, ~0, 1, RF_ACTIVE); if (sc->dc_res == NULL) { printf("dc%d: couldn't map ports/memory\n", unit); error = ENXIO; goto fail; } sc->dc_btag = rman_get_bustag(sc->dc_res); sc->dc_bhandle = rman_get_bushandle(sc->dc_res); /* Allocate interrupt. */ rid = 0; sc->dc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->dc_irq == NULL) { printf("dc%d: couldn't map interrupt\n", unit); error = ENXIO; goto fail; } /* Need this info to decide on a chip type. */ sc->dc_info = dc_devtype(dev); revision = pci_read_config(dev, DC_PCI_CFRV, 4) & 0x000000FF; /* Get the eeprom width, but PNIC and XIRCOM have diff eeprom */ if (sc->dc_info->dc_did != DC_DEVICEID_82C168 && sc->dc_info->dc_did != DC_DEVICEID_X3201) dc_eeprom_width(sc); switch (sc->dc_info->dc_did) { case DC_DEVICEID_21143: sc->dc_type = DC_TYPE_21143; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; sc->dc_flags |= DC_REDUCED_MII_POLL; /* Save EEPROM contents so we can parse them later. */ dc_read_srom(sc, sc->dc_romwidth); break; case DC_DEVICEID_DM9009: case DC_DEVICEID_DM9100: case DC_DEVICEID_DM9102: sc->dc_type = DC_TYPE_DM9102; sc->dc_flags |= DC_TX_COALESCE | DC_TX_INTR_ALWAYS; sc->dc_flags |= DC_REDUCED_MII_POLL | DC_TX_STORENFWD; sc->dc_flags |= DC_TX_ALIGN; sc->dc_pmode = DC_PMODE_MII; /* Increase the latency timer value. */ command = pci_read_config(dev, DC_PCI_CFLT, 4); command &= 0xFFFF00FF; command |= 0x00008000; pci_write_config(dev, DC_PCI_CFLT, command, 4); break; case DC_DEVICEID_AL981: sc->dc_type = DC_TYPE_AL981; sc->dc_flags |= DC_TX_USE_TX_INTR; sc->dc_flags |= DC_TX_ADMTEK_WAR; sc->dc_pmode = DC_PMODE_MII; dc_read_srom(sc, sc->dc_romwidth); break; case DC_DEVICEID_AN985: case DC_DEVICEID_ADM9511: case DC_DEVICEID_ADM9513: case DC_DEVICEID_FA511: case DC_DEVICEID_FE2500: case DC_DEVICEID_EN2242: case DC_DEVICEID_HAWKING_PN672TX: case DC_DEVICEID_3CSOHOB: case DC_DEVICEID_MSMN120: case DC_DEVICEID_MSMN130_FAKE: /* XXX avoid collision with PNIC*/ sc->dc_type = DC_TYPE_AN985; sc->dc_flags |= DC_64BIT_HASH; sc->dc_flags |= DC_TX_USE_TX_INTR; sc->dc_flags |= DC_TX_ADMTEK_WAR; sc->dc_pmode = DC_PMODE_MII; /* Don't read SROM for - auto-loaded on reset */ break; case DC_DEVICEID_98713: case DC_DEVICEID_98713_CP: if (revision < DC_REVISION_98713A) { sc->dc_type = DC_TYPE_98713; } if (revision >= DC_REVISION_98713A) { sc->dc_type = DC_TYPE_98713A; sc->dc_flags |= DC_21143_NWAY; } sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; break; case DC_DEVICEID_987x5: case DC_DEVICEID_EN1217: /* * Macronix MX98715AEC-C/D/E parts have only a * 128-bit hash table. We need to deal with these * in the same manner as the PNIC II so that we * get the right number of bits out of the * CRC routine. */ if (revision >= DC_REVISION_98715AEC_C && revision < DC_REVISION_98725) sc->dc_flags |= DC_128BIT_HASH; sc->dc_type = DC_TYPE_987x5; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; sc->dc_flags |= DC_REDUCED_MII_POLL | DC_21143_NWAY; break; case DC_DEVICEID_98727: sc->dc_type = DC_TYPE_987x5; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; sc->dc_flags |= DC_REDUCED_MII_POLL | DC_21143_NWAY; break; case DC_DEVICEID_82C115: sc->dc_type = DC_TYPE_PNICII; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR | DC_128BIT_HASH; sc->dc_flags |= DC_REDUCED_MII_POLL | DC_21143_NWAY; break; case DC_DEVICEID_82C168: sc->dc_type = DC_TYPE_PNIC; sc->dc_flags |= DC_TX_STORENFWD | DC_TX_INTR_ALWAYS; sc->dc_flags |= DC_PNIC_RX_BUG_WAR; sc->dc_pnic_rx_buf = malloc(DC_RXLEN * 5, M_DEVBUF, M_NOWAIT); if (revision < DC_REVISION_82C169) sc->dc_pmode = DC_PMODE_SYM; break; case DC_DEVICEID_AX88140A: sc->dc_type = DC_TYPE_ASIX; sc->dc_flags |= DC_TX_USE_TX_INTR | DC_TX_INTR_FIRSTFRAG; sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_pmode = DC_PMODE_MII; break; case DC_DEVICEID_X3201: sc->dc_type = DC_TYPE_XIRCOM; sc->dc_flags |= DC_TX_INTR_ALWAYS | DC_TX_COALESCE | DC_TX_ALIGN; /* * We don't actually need to coalesce, but we're doing * it to obtain a double word aligned buffer. * The DC_TX_COALESCE flag is required. */ sc->dc_pmode = DC_PMODE_MII; break; case DC_DEVICEID_RS7112: sc->dc_type = DC_TYPE_CONEXANT; sc->dc_flags |= DC_TX_INTR_ALWAYS; sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_pmode = DC_PMODE_MII; dc_read_srom(sc, sc->dc_romwidth); break; default: printf("dc%d: unknown device: %x\n", sc->dc_unit, sc->dc_info->dc_did); break; } /* Save the cache line size. */ if (DC_IS_DAVICOM(sc)) sc->dc_cachesize = 0; else sc->dc_cachesize = pci_read_config(dev, DC_PCI_CFLT, 4) & 0xFF; /* Reset the adapter. */ dc_reset(sc); /* Take 21143 out of snooze mode */ if (DC_IS_INTEL(sc) || DC_IS_XIRCOM(sc)) { command = pci_read_config(dev, DC_PCI_CFDD, 4); command &= ~(DC_CFDD_SNOOZE_MODE | DC_CFDD_SLEEP_MODE); pci_write_config(dev, DC_PCI_CFDD, command, 4); } /* * Try to learn something about the supported media. * We know that ASIX and ADMtek and Davicom devices * will *always* be using MII media, so that's a no-brainer. * The tricky ones are the Macronix/PNIC II and the * Intel 21143. */ if (DC_IS_INTEL(sc)) dc_parse_21143_srom(sc); else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) { if (sc->dc_type == DC_TYPE_98713) sc->dc_pmode = DC_PMODE_MII; else sc->dc_pmode = DC_PMODE_SYM; } else if (!sc->dc_pmode) sc->dc_pmode = DC_PMODE_MII; /* * Get station address from the EEPROM. */ switch(sc->dc_type) { case DC_TYPE_98713: case DC_TYPE_98713A: case DC_TYPE_987x5: case DC_TYPE_PNICII: dc_read_eeprom(sc, (caddr_t)&mac_offset, (DC_EE_NODEADDR_OFFSET / 2), 1, 0); dc_read_eeprom(sc, (caddr_t)&eaddr, (mac_offset / 2), 3, 0); break; case DC_TYPE_PNIC: dc_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 1); break; case DC_TYPE_DM9102: case DC_TYPE_21143: case DC_TYPE_ASIX: dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0); break; case DC_TYPE_AL981: case DC_TYPE_AN985: *(u_int32_t *)(&eaddr[0]) = CSR_READ_4(sc, DC_AL_PAR0); *(u_int16_t *)(&eaddr[4]) = CSR_READ_4(sc, DC_AL_PAR1); break; case DC_TYPE_CONEXANT: bcopy(sc->dc_srom + DC_CONEXANT_EE_NODEADDR, &eaddr, ETHER_ADDR_LEN); break; case DC_TYPE_XIRCOM: /* The MAC comes from the CIS. */ mac = pci_get_ether(dev); if (!mac) { device_printf(dev, "No station address in CIS!\n"); error = ENXIO; goto fail; } bcopy(mac, eaddr, ETHER_ADDR_LEN); break; default: dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0); break; } /* * A 21143 or clone chip was detected. Inform the world. */ printf("dc%d: Ethernet address: %6D\n", unit, eaddr, ":"); sc->dc_unit = unit; bcopy(eaddr, &sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, sizeof(struct dc_list_data), 1, sizeof(struct dc_list_data), 0, NULL, NULL, &sc->dc_ltag); if (error) { printf("dc%d: failed to allocate busdma tag\n", unit); error = ENXIO; goto fail; } error = bus_dmamem_alloc(sc->dc_ltag, (void **)&sc->dc_ldata, BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->dc_lmap); if (error) { printf("dc%d: failed to allocate DMA safe memory\n", unit); error = ENXIO; goto fail; } error = bus_dmamap_load(sc->dc_ltag, sc->dc_lmap, sc->dc_ldata, sizeof(struct dc_list_data), dc_dma_map_addr, &sc->dc_laddr, BUS_DMA_NOWAIT); if (error) { printf("dc%d: cannot get address of the descriptors\n", unit); error = ENXIO; goto fail; } /* * Allocate a busdma tag and DMA safe memory for the multicast * setup frame. */ error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, DC_SFRAME_LEN + DC_MIN_FRAMELEN, 1, DC_SFRAME_LEN + DC_MIN_FRAMELEN, 0, NULL, NULL, &sc->dc_stag); if (error) { printf("dc%d: failed to allocate busdma tag\n", unit); error = ENXIO; goto fail; } error = bus_dmamem_alloc(sc->dc_stag, (void **)&sc->dc_cdata.dc_sbuf, BUS_DMA_NOWAIT, &sc->dc_smap); if (error) { printf("dc%d: failed to allocate DMA safe memory\n", unit); error = ENXIO; goto fail; } error = bus_dmamap_load(sc->dc_stag, sc->dc_smap, sc->dc_cdata.dc_sbuf, DC_SFRAME_LEN, dc_dma_map_addr, &sc->dc_saddr, BUS_DMA_NOWAIT); if (error) { printf("dc%d: cannot get address of the descriptors\n", unit); error = ENXIO; goto fail; } /* Allocate a busdma tag for mbufs. */ error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES * DC_TX_LIST_CNT, DC_TX_LIST_CNT, MCLBYTES, 0, NULL, NULL, &sc->dc_mtag); if (error) { printf("dc%d: failed to allocate busdma tag\n", unit); error = ENXIO; goto fail; } /* Create the TX/RX busdma maps. */ for (i = 0; i < DC_TX_LIST_CNT; i++) { error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_cdata.dc_tx_map[i]); if (error) { printf("dc%d: failed to init TX ring\n", unit); error = ENXIO; goto fail; } } for (i = 0; i < DC_RX_LIST_CNT; i++) { error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_cdata.dc_rx_map[i]); if (error) { printf("dc%d: failed to init RX ring\n", unit); error = ENXIO; goto fail; } } error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_sparemap); if (error) { printf("dc%d: failed to init RX ring\n", unit); error = ENXIO; goto fail; } ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); /* XXX: bleah, MTU gets overwritten in ether_ifattach() */ ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = dc_ioctl; ifp->if_start = dc_start; ifp->if_watchdog = dc_watchdog; ifp->if_init = dc_init; ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = DC_TX_LIST_CNT - 1; /* * Do MII setup. If this is a 21143, check for a PHY on the * MII bus after applying any necessary fixups to twiddle the * GPIO bits. If we don't end up finding a PHY, restore the * old selection (SIA only or SIA/SYM) and attach the dcphy * driver instead. */ if (DC_IS_INTEL(sc)) { dc_apply_fixup(sc, IFM_AUTO); tmp = sc->dc_pmode; sc->dc_pmode = DC_PMODE_MII; } error = mii_phy_probe(dev, &sc->dc_miibus, dc_ifmedia_upd, dc_ifmedia_sts); if (error && DC_IS_INTEL(sc)) { sc->dc_pmode = tmp; if (sc->dc_pmode != DC_PMODE_SIA) sc->dc_pmode = DC_PMODE_SYM; sc->dc_flags |= DC_21143_NWAY; mii_phy_probe(dev, &sc->dc_miibus, dc_ifmedia_upd, dc_ifmedia_sts); /* * For non-MII cards, we need to have the 21143 * drive the LEDs. Except there are some systems * like the NEC VersaPro NoteBook PC which have no * LEDs, and twiddling these bits has adverse effects * on them. (I.e. you suddenly can't get a link.) */ if (pci_read_config(dev, DC_PCI_CSID, 4) != 0x80281033) sc->dc_flags |= DC_TULIP_LEDS; error = 0; } if (error) { printf("dc%d: MII without any PHY!\n", sc->dc_unit); goto fail; } if (DC_IS_XIRCOM(sc)) { /* * setup General Purpose Port mode and data so the tulip * can talk to the MII. */ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN | DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); DELAY(10); CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN | DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); DELAY(10); } if (DC_IS_ADMTEK(sc)) { /* * Set automatic TX underrun recovery for the ADMtek chips */ DC_SETBIT(sc, DC_AL_CR, DC_AL_CR_ATUR); } /* * Tell the upper layer(s) we support long frames. */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_MTU; callout_init(&sc->dc_stat_ch, IS_MPSAFE ? CALLOUT_MPSAFE : 0); #ifdef SRM_MEDIA sc->dc_srm_media = 0; /* Remember the SRM console media setting */ if (DC_IS_INTEL(sc)) { command = pci_read_config(dev, DC_PCI_CFDD, 4); command &= ~(DC_CFDD_SNOOZE_MODE | DC_CFDD_SLEEP_MODE); switch ((command >> 8) & 0xff) { case 3: sc->dc_srm_media = IFM_10_T; break; case 4: sc->dc_srm_media = IFM_10_T | IFM_FDX; break; case 5: sc->dc_srm_media = IFM_100_TX; break; case 6: sc->dc_srm_media = IFM_100_TX | IFM_FDX; break; } if (sc->dc_srm_media) sc->dc_srm_media |= IFM_ACTIVE | IFM_ETHER; } #endif /* * Call MI attach routine. */ ether_ifattach(ifp, eaddr); /* Hook interrupt last to avoid having to lock softc */ error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET | (IS_MPSAFE ? INTR_MPSAFE : 0), dc_intr, sc, &sc->dc_intrhand); if (error) { printf("dc%d: couldn't set up irq\n", unit); ether_ifdetach(ifp); goto fail; } fail: if (error) dc_detach(dev); return (error); } /* * Shutdown hardware and free up resources. This can be called any * time after the mutex has been initialized. It is called in both * the error case in attach and the normal detach case so it needs * to be careful about only freeing resources that have actually been * allocated. */ static int dc_detach(device_t dev) { struct dc_softc *sc; struct ifnet *ifp; struct dc_mediainfo *m; int i; sc = device_get_softc(dev); KASSERT(mtx_initialized(&sc->dc_mtx), ("dc mutex not initialized")); DC_LOCK(sc); ifp = &sc->arpcom.ac_if; /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { dc_stop(sc); ether_ifdetach(ifp); } if (sc->dc_miibus) device_delete_child(dev, sc->dc_miibus); bus_generic_detach(dev); if (sc->dc_intrhand) bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand); if (sc->dc_irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq); if (sc->dc_res) bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res); if (sc->dc_cdata.dc_sbuf != NULL) bus_dmamem_free(sc->dc_stag, sc->dc_cdata.dc_sbuf, sc->dc_smap); if (sc->dc_ldata != NULL) bus_dmamem_free(sc->dc_ltag, sc->dc_ldata, sc->dc_lmap); for (i = 0; i < DC_TX_LIST_CNT; i++) bus_dmamap_destroy(sc->dc_mtag, sc->dc_cdata.dc_tx_map[i]); for (i = 0; i < DC_RX_LIST_CNT; i++) bus_dmamap_destroy(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i]); bus_dmamap_destroy(sc->dc_mtag, sc->dc_sparemap); if (sc->dc_stag) bus_dma_tag_destroy(sc->dc_stag); if (sc->dc_mtag) bus_dma_tag_destroy(sc->dc_mtag); if (sc->dc_ltag) bus_dma_tag_destroy(sc->dc_ltag); free(sc->dc_pnic_rx_buf, M_DEVBUF); while (sc->dc_mi != NULL) { m = sc->dc_mi->dc_next; free(sc->dc_mi, M_DEVBUF); sc->dc_mi = m; } free(sc->dc_srom, M_DEVBUF); DC_UNLOCK(sc); mtx_destroy(&sc->dc_mtx); return (0); } /* * Initialize the transmit descriptors. */ static int dc_list_tx_init(struct dc_softc *sc) { struct dc_chain_data *cd; struct dc_list_data *ld; int i, nexti; cd = &sc->dc_cdata; ld = sc->dc_ldata; for (i = 0; i < DC_TX_LIST_CNT; i++) { if (i == DC_TX_LIST_CNT - 1) nexti = 0; else nexti = i + 1; ld->dc_tx_list[i].dc_next = htole32(DC_TXDESC(sc, nexti)); cd->dc_tx_chain[i] = NULL; ld->dc_tx_list[i].dc_data = 0; ld->dc_tx_list[i].dc_ctl = 0; } cd->dc_tx_prod = cd->dc_tx_cons = cd->dc_tx_cnt = 0; bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); return (0); } /* * Initialize the RX descriptors and allocate mbufs for them. Note that * we arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */ static int dc_list_rx_init(struct dc_softc *sc) { struct dc_chain_data *cd; struct dc_list_data *ld; int i, nexti; cd = &sc->dc_cdata; ld = sc->dc_ldata; for (i = 0; i < DC_RX_LIST_CNT; i++) { if (dc_newbuf(sc, i, 1) != 0) return (ENOBUFS); if (i == DC_RX_LIST_CNT - 1) nexti = 0; else nexti = i + 1; ld->dc_rx_list[i].dc_next = htole32(DC_RXDESC(sc, nexti)); } cd->dc_rx_prod = 0; bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); return (0); } static void dc_dma_map_rxbuf(arg, segs, nseg, mapsize, error) void *arg; bus_dma_segment_t *segs; int nseg; bus_size_t mapsize; int error; { struct dc_softc *sc; struct dc_desc *c; sc = arg; c = &sc->dc_ldata->dc_rx_list[sc->dc_cdata.dc_rx_cur]; if (error) { sc->dc_cdata.dc_rx_err = error; return; } KASSERT(nseg == 1, ("wrong number of segments, should be 1")); sc->dc_cdata.dc_rx_err = 0; c->dc_data = htole32(segs->ds_addr); } /* * Initialize an RX descriptor and attach an MBUF cluster. */ static int dc_newbuf(struct dc_softc *sc, int i, int alloc) { struct mbuf *m_new; bus_dmamap_t tmp; int error; if (alloc) { m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); if (m_new == NULL) return (ENOBUFS); } else { m_new = sc->dc_cdata.dc_rx_chain[i]; m_new->m_data = m_new->m_ext.ext_buf; } m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; m_adj(m_new, sizeof(u_int64_t)); /* * If this is a PNIC chip, zero the buffer. This is part * of the workaround for the receive bug in the 82c168 and * 82c169 chips. */ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) bzero(mtod(m_new, char *), m_new->m_len); /* No need to remap the mbuf if we're reusing it. */ if (alloc) { sc->dc_cdata.dc_rx_cur = i; error = bus_dmamap_load_mbuf(sc->dc_mtag, sc->dc_sparemap, m_new, dc_dma_map_rxbuf, sc, 0); if (error) { m_freem(m_new); return (error); } if (sc->dc_cdata.dc_rx_err != 0) { m_freem(m_new); return (sc->dc_cdata.dc_rx_err); } bus_dmamap_unload(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i]); tmp = sc->dc_cdata.dc_rx_map[i]; sc->dc_cdata.dc_rx_map[i] = sc->dc_sparemap; sc->dc_sparemap = tmp; sc->dc_cdata.dc_rx_chain[i] = m_new; } sc->dc_ldata->dc_rx_list[i].dc_ctl = htole32(DC_RXCTL_RLINK | DC_RXLEN); sc->dc_ldata->dc_rx_list[i].dc_status = htole32(DC_RXSTAT_OWN); bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i], BUS_DMASYNC_PREREAD); bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); return (0); } /* * Grrrrr. * The PNIC chip has a terrible bug in it that manifests itself during * periods of heavy activity. The exact mode of failure if difficult to * pinpoint: sometimes it only happens in promiscuous mode, sometimes it * will happen on slow machines. The bug is that sometimes instead of * uploading one complete frame during reception, it uploads what looks * like the entire contents of its FIFO memory. The frame we want is at * the end of the whole mess, but we never know exactly how much data has * been uploaded, so salvaging the frame is hard. * * There is only one way to do it reliably, and it's disgusting. * Here's what we know: * * - We know there will always be somewhere between one and three extra * descriptors uploaded. * * - We know the desired received frame will always be at the end of the * total data upload. * * - We know the size of the desired received frame because it will be * provided in the length field of the status word in the last descriptor. * * Here's what we do: * * - When we allocate buffers for the receive ring, we bzero() them. * This means that we know that the buffer contents should be all * zeros, except for data uploaded by the chip. * * - We also force the PNIC chip to upload frames that include the * ethernet CRC at the end. * * - We gather all of the bogus frame data into a single buffer. * * - We then position a pointer at the end of this buffer and scan * backwards until we encounter the first non-zero byte of data. * This is the end of the received frame. We know we will encounter * some data at the end of the frame because the CRC will always be * there, so even if the sender transmits a packet of all zeros, * we won't be fooled. * * - We know the size of the actual received frame, so we subtract * that value from the current pointer location. This brings us * to the start of the actual received packet. * * - We copy this into an mbuf and pass it on, along with the actual * frame length. * * The performance hit is tremendous, but it beats dropping frames all * the time. */ #define DC_WHOLEFRAME (DC_RXSTAT_FIRSTFRAG | DC_RXSTAT_LASTFRAG) static void dc_pnic_rx_bug_war(struct dc_softc *sc, int idx) { struct dc_desc *cur_rx; struct dc_desc *c = NULL; struct mbuf *m = NULL; unsigned char *ptr; int i, total_len; u_int32_t rxstat = 0; i = sc->dc_pnic_rx_bug_save; cur_rx = &sc->dc_ldata->dc_rx_list[idx]; ptr = sc->dc_pnic_rx_buf; bzero(ptr, DC_RXLEN * 5); /* Copy all the bytes from the bogus buffers. */ while (1) { c = &sc->dc_ldata->dc_rx_list[i]; rxstat = le32toh(c->dc_status); m = sc->dc_cdata.dc_rx_chain[i]; bcopy(mtod(m, char *), ptr, DC_RXLEN); ptr += DC_RXLEN; /* If this is the last buffer, break out. */ if (i == idx || rxstat & DC_RXSTAT_LASTFRAG) break; dc_newbuf(sc, i, 0); DC_INC(i, DC_RX_LIST_CNT); } /* Find the length of the actual receive frame. */ total_len = DC_RXBYTES(rxstat); /* Scan backwards until we hit a non-zero byte. */ while (*ptr == 0x00) ptr--; /* Round off. */ if ((uintptr_t)(ptr) & 0x3) ptr -= 1; /* Now find the start of the frame. */ ptr -= total_len; if (ptr < sc->dc_pnic_rx_buf) ptr = sc->dc_pnic_rx_buf; /* * Now copy the salvaged frame to the last mbuf and fake up * the status word to make it look like a successful * frame reception. */ dc_newbuf(sc, i, 0); bcopy(ptr, mtod(m, char *), total_len); cur_rx->dc_status = htole32(rxstat | DC_RXSTAT_FIRSTFRAG); } /* * This routine searches the RX ring for dirty descriptors in the * event that the rxeof routine falls out of sync with the chip's * current descriptor pointer. This may happen sometimes as a result * of a "no RX buffer available" condition that happens when the chip * consumes all of the RX buffers before the driver has a chance to * process the RX ring. This routine may need to be called more than * once to bring the driver back in sync with the chip, however we * should still be getting RX DONE interrupts to drive the search * for new packets in the RX ring, so we should catch up eventually. */ static int dc_rx_resync(struct dc_softc *sc) { struct dc_desc *cur_rx; int i, pos; pos = sc->dc_cdata.dc_rx_prod; for (i = 0; i < DC_RX_LIST_CNT; i++) { cur_rx = &sc->dc_ldata->dc_rx_list[pos]; if (!(le32toh(cur_rx->dc_status) & DC_RXSTAT_OWN)) break; DC_INC(pos, DC_RX_LIST_CNT); } /* If the ring really is empty, then just return. */ if (i == DC_RX_LIST_CNT) return (0); /* We've fallen behing the chip: catch it. */ sc->dc_cdata.dc_rx_prod = pos; return (EAGAIN); } /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */ static void dc_rxeof(struct dc_softc *sc) { struct mbuf *m; struct ifnet *ifp; struct dc_desc *cur_rx; int i, total_len = 0; u_int32_t rxstat; DC_LOCK_ASSERT(sc); ifp = &sc->arpcom.ac_if; i = sc->dc_cdata.dc_rx_prod; bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_POSTREAD); while (!(le32toh(sc->dc_ldata->dc_rx_list[i].dc_status) & DC_RXSTAT_OWN)) { #ifdef DEVICE_POLLING if (ifp->if_flags & IFF_POLLING) { if (sc->rxcycles <= 0) break; sc->rxcycles--; } #endif cur_rx = &sc->dc_ldata->dc_rx_list[i]; rxstat = le32toh(cur_rx->dc_status); m = sc->dc_cdata.dc_rx_chain[i]; bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i], BUS_DMASYNC_POSTREAD); total_len = DC_RXBYTES(rxstat); if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) { if ((rxstat & DC_WHOLEFRAME) != DC_WHOLEFRAME) { if (rxstat & DC_RXSTAT_FIRSTFRAG) sc->dc_pnic_rx_bug_save = i; if ((rxstat & DC_RXSTAT_LASTFRAG) == 0) { DC_INC(i, DC_RX_LIST_CNT); continue; } dc_pnic_rx_bug_war(sc, i); rxstat = le32toh(cur_rx->dc_status); total_len = DC_RXBYTES(rxstat); } } /* * If an error occurs, update stats, clear the * status word and leave the mbuf cluster in place: * it should simply get re-used next time this descriptor * comes up in the ring. However, don't report long * frames as errors since they could be vlans. */ if ((rxstat & DC_RXSTAT_RXERR)) { if (!(rxstat & DC_RXSTAT_GIANT) || (rxstat & (DC_RXSTAT_CRCERR | DC_RXSTAT_DRIBBLE | DC_RXSTAT_MIIERE | DC_RXSTAT_COLLSEEN | DC_RXSTAT_RUNT | DC_RXSTAT_DE))) { ifp->if_ierrors++; if (rxstat & DC_RXSTAT_COLLSEEN) ifp->if_collisions++; dc_newbuf(sc, i, 0); if (rxstat & DC_RXSTAT_CRCERR) { DC_INC(i, DC_RX_LIST_CNT); continue; } else { dc_init(sc); return; } } } /* No errors; receive the packet. */ total_len -= ETHER_CRC_LEN; #ifdef __i386__ /* * On the x86 we do not have alignment problems, so try to * allocate a new buffer for the receive ring, and pass up * the one where the packet is already, saving the expensive * copy done in m_devget(). * If we are on an architecture with alignment problems, or * if the allocation fails, then use m_devget and leave the * existing buffer in the receive ring. */ if (dc_quick && dc_newbuf(sc, i, 1) == 0) { m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len; DC_INC(i, DC_RX_LIST_CNT); } else #endif { struct mbuf *m0; m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, NULL); dc_newbuf(sc, i, 0); DC_INC(i, DC_RX_LIST_CNT); if (m0 == NULL) { ifp->if_ierrors++; continue; } m = m0; } ifp->if_ipackets++; DC_UNLOCK(sc); (*ifp->if_input)(ifp, m); DC_LOCK(sc); } sc->dc_cdata.dc_rx_prod = i; } /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ static void dc_txeof(struct dc_softc *sc) { struct dc_desc *cur_tx = NULL; struct ifnet *ifp; int idx; u_int32_t ctl, txstat; ifp = &sc->arpcom.ac_if; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_POSTREAD); idx = sc->dc_cdata.dc_tx_cons; while (idx != sc->dc_cdata.dc_tx_prod) { cur_tx = &sc->dc_ldata->dc_tx_list[idx]; txstat = le32toh(cur_tx->dc_status); ctl = le32toh(cur_tx->dc_ctl); if (txstat & DC_TXSTAT_OWN) break; if (!(ctl & DC_TXCTL_FIRSTFRAG) || ctl & DC_TXCTL_SETUP) { if (ctl & DC_TXCTL_SETUP) { /* * Yes, the PNIC is so brain damaged * that it will sometimes generate a TX * underrun error while DMAing the RX * filter setup frame. If we detect this, * we have to send the setup frame again, * or else the filter won't be programmed * correctly. */ if (DC_IS_PNIC(sc)) { if (txstat & DC_TXSTAT_ERRSUM) dc_setfilt(sc); } sc->dc_cdata.dc_tx_chain[idx] = NULL; } sc->dc_cdata.dc_tx_cnt--; DC_INC(idx, DC_TX_LIST_CNT); continue; } if (DC_IS_XIRCOM(sc) || DC_IS_CONEXANT(sc)) { /* * XXX: Why does my Xircom taunt me so? * For some reason it likes setting the CARRLOST flag * even when the carrier is there. wtf?!? * Who knows, but Conexant chips have the * same problem. Maybe they took lessons * from Xircom. */ if (/*sc->dc_type == DC_TYPE_21143 &&*/ sc->dc_pmode == DC_PMODE_MII && ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM | DC_TXSTAT_NOCARRIER))) txstat &= ~DC_TXSTAT_ERRSUM; } else { if (/*sc->dc_type == DC_TYPE_21143 &&*/ sc->dc_pmode == DC_PMODE_MII && ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM | DC_TXSTAT_NOCARRIER | DC_TXSTAT_CARRLOST))) txstat &= ~DC_TXSTAT_ERRSUM; } if (txstat & DC_TXSTAT_ERRSUM) { ifp->if_oerrors++; if (txstat & DC_TXSTAT_EXCESSCOLL) ifp->if_collisions++; if (txstat & DC_TXSTAT_LATECOLL) ifp->if_collisions++; if (!(txstat & DC_TXSTAT_UNDERRUN)) { dc_init(sc); return; } } ifp->if_collisions += (txstat & DC_TXSTAT_COLLCNT) >> 3; ifp->if_opackets++; if (sc->dc_cdata.dc_tx_chain[idx] != NULL) { bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx]); m_freem(sc->dc_cdata.dc_tx_chain[idx]); sc->dc_cdata.dc_tx_chain[idx] = NULL; } sc->dc_cdata.dc_tx_cnt--; DC_INC(idx, DC_TX_LIST_CNT); } if (idx != sc->dc_cdata.dc_tx_cons) { /* Some buffers have been freed. */ sc->dc_cdata.dc_tx_cons = idx; ifp->if_flags &= ~IFF_OACTIVE; } ifp->if_timer = (sc->dc_cdata.dc_tx_cnt == 0) ? 0 : 5; } static void dc_tick(void *xsc) { struct dc_softc *sc; struct mii_data *mii; struct ifnet *ifp; u_int32_t r; sc = xsc; DC_LOCK(sc); ifp = &sc->arpcom.ac_if; mii = device_get_softc(sc->dc_miibus); if (sc->dc_flags & DC_REDUCED_MII_POLL) { if (sc->dc_flags & DC_21143_NWAY) { r = CSR_READ_4(sc, DC_10BTSTAT); if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX && (r & DC_TSTAT_LS100)) { sc->dc_link = 0; mii_mediachg(mii); } if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T && (r & DC_TSTAT_LS10)) { sc->dc_link = 0; mii_mediachg(mii); } if (sc->dc_link == 0) mii_tick(mii); } else { r = CSR_READ_4(sc, DC_ISR); if ((r & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT && sc->dc_cdata.dc_tx_cnt == 0) { mii_tick(mii); if (!(mii->mii_media_status & IFM_ACTIVE)) sc->dc_link = 0; } } } else mii_tick(mii); /* * When the init routine completes, we expect to be able to send * packets right away, and in fact the network code will send a * gratuitous ARP the moment the init routine marks the interface * as running. However, even though the MAC may have been initialized, * there may be a delay of a few seconds before the PHY completes * autonegotiation and the link is brought up. Any transmissions * made during that delay will be lost. Dealing with this is tricky: * we can't just pause in the init routine while waiting for the * PHY to come ready since that would bring the whole system to * a screeching halt for several seconds. * * What we do here is prevent the TX start routine from sending * any packets until a link has been established. After the * interface has been initialized, the tick routine will poll * the state of the PHY until the IFM_ACTIVE flag is set. Until * that time, packets will stay in the send queue, and once the * link comes up, they will be flushed out to the wire. */ if (!sc->dc_link && mii->mii_media_status & IFM_ACTIVE && IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { sc->dc_link++; if (ifp->if_snd.ifq_head != NULL) dc_start(ifp); } if (sc->dc_flags & DC_21143_NWAY && !sc->dc_link) callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc); else callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc); DC_UNLOCK(sc); } /* * A transmit underrun has occurred. Back off the transmit threshold, * or switch to store and forward mode if we have to. */ static void dc_tx_underrun(struct dc_softc *sc) { u_int32_t isr; int i; if (DC_IS_DAVICOM(sc)) dc_init(sc); if (DC_IS_INTEL(sc)) { /* * The real 21143 requires that the transmitter be idle * in order to change the transmit threshold or store * and forward state. */ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); for (i = 0; i < DC_TIMEOUT; i++) { isr = CSR_READ_4(sc, DC_ISR); if (isr & DC_ISR_TX_IDLE) break; DELAY(10); } if (i == DC_TIMEOUT) { printf("dc%d: failed to force tx to idle state\n", sc->dc_unit); dc_init(sc); } } printf("dc%d: TX underrun -- ", sc->dc_unit); sc->dc_txthresh += DC_TXTHRESH_INC; if (sc->dc_txthresh > DC_TXTHRESH_MAX) { printf("using store and forward mode\n"); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); } else { printf("increasing TX threshold\n"); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH); DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh); } if (DC_IS_INTEL(sc)) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); } #ifdef DEVICE_POLLING static poll_handler_t dc_poll; static void dc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct dc_softc *sc = ifp->if_softc; if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ /* Re-enable interrupts. */ CSR_WRITE_4(sc, DC_IMR, DC_INTRS); return; } DC_LOCK(sc); sc->rxcycles = count; dc_rxeof(sc); dc_txeof(sc); if (ifp->if_snd.ifq_head != NULL && !(ifp->if_flags & IFF_OACTIVE)) dc_start(ifp); if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ u_int32_t status; status = CSR_READ_4(sc, DC_ISR); status &= (DC_ISR_RX_WATDOGTIMEO | DC_ISR_RX_NOBUF | DC_ISR_TX_NOBUF | DC_ISR_TX_IDLE | DC_ISR_TX_UNDERRUN | DC_ISR_BUS_ERR); if (!status) { DC_UNLOCK(sc); return; } /* ack what we have */ CSR_WRITE_4(sc, DC_ISR, status); if (status & (DC_ISR_RX_WATDOGTIMEO | DC_ISR_RX_NOBUF)) { u_int32_t r = CSR_READ_4(sc, DC_FRAMESDISCARDED); ifp->if_ierrors += (r & 0xffff) + ((r >> 17) & 0x7ff); if (dc_rx_resync(sc)) dc_rxeof(sc); } /* restart transmit unit if necessary */ if (status & DC_ISR_TX_IDLE && sc->dc_cdata.dc_tx_cnt) CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); if (status & DC_ISR_TX_UNDERRUN) dc_tx_underrun(sc); if (status & DC_ISR_BUS_ERR) { printf("dc_poll: dc%d bus error\n", sc->dc_unit); dc_reset(sc); dc_init(sc); } } DC_UNLOCK(sc); } #endif /* DEVICE_POLLING */ static void dc_intr(void *arg) { struct dc_softc *sc; struct ifnet *ifp; u_int32_t status; sc = arg; if (sc->suspended) return; if ((CSR_READ_4(sc, DC_ISR) & DC_INTRS) == 0) return; DC_LOCK(sc); ifp = &sc->arpcom.ac_if; #ifdef DEVICE_POLLING if (ifp->if_flags & IFF_POLLING) goto done; if (ether_poll_register(dc_poll, ifp)) { /* ok, disable interrupts */ CSR_WRITE_4(sc, DC_IMR, 0x00000000); goto done; } #endif /* Suppress unwanted interrupts */ if (!(ifp->if_flags & IFF_UP)) { if (CSR_READ_4(sc, DC_ISR) & DC_INTRS) dc_stop(sc); DC_UNLOCK(sc); return; } /* Disable interrupts. */ CSR_WRITE_4(sc, DC_IMR, 0x00000000); while (((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) && status != 0xFFFFFFFF) { CSR_WRITE_4(sc, DC_ISR, status); if (status & DC_ISR_RX_OK) { int curpkts; curpkts = ifp->if_ipackets; dc_rxeof(sc); if (curpkts == ifp->if_ipackets) { while (dc_rx_resync(sc)) dc_rxeof(sc); } } if (status & (DC_ISR_TX_OK | DC_ISR_TX_NOBUF)) dc_txeof(sc); if (status & DC_ISR_TX_IDLE) { dc_txeof(sc); if (sc->dc_cdata.dc_tx_cnt) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); } } if (status & DC_ISR_TX_UNDERRUN) dc_tx_underrun(sc); if ((status & DC_ISR_RX_WATDOGTIMEO) || (status & DC_ISR_RX_NOBUF)) { int curpkts; curpkts = ifp->if_ipackets; dc_rxeof(sc); if (curpkts == ifp->if_ipackets) { while (dc_rx_resync(sc)) dc_rxeof(sc); } } if (status & DC_ISR_BUS_ERR) { dc_reset(sc); dc_init(sc); } } /* Re-enable interrupts. */ CSR_WRITE_4(sc, DC_IMR, DC_INTRS); if (ifp->if_snd.ifq_head != NULL) dc_start(ifp); #ifdef DEVICE_POLLING done: #endif DC_UNLOCK(sc); } static void dc_dma_map_txbuf(arg, segs, nseg, mapsize, error) void *arg; bus_dma_segment_t *segs; int nseg; bus_size_t mapsize; int error; { struct dc_softc *sc; struct dc_desc *f; int cur, first, frag, i; sc = arg; if (error) { sc->dc_cdata.dc_tx_err = error; return; } first = cur = frag = sc->dc_cdata.dc_tx_prod; for (i = 0; i < nseg; i++) { if ((sc->dc_flags & DC_TX_ADMTEK_WAR) && (frag == (DC_TX_LIST_CNT - 1)) && (first != sc->dc_cdata.dc_tx_first)) { bus_dmamap_unload(sc->dc_mtag, sc->dc_cdata.dc_tx_map[first]); sc->dc_cdata.dc_tx_err = ENOBUFS; return; } f = &sc->dc_ldata->dc_tx_list[frag]; f->dc_ctl = htole32(DC_TXCTL_TLINK | segs[i].ds_len); if (i == 0) { f->dc_status = 0; f->dc_ctl |= htole32(DC_TXCTL_FIRSTFRAG); } else f->dc_status = htole32(DC_TXSTAT_OWN); f->dc_data = htole32(segs[i].ds_addr); cur = frag; DC_INC(frag, DC_TX_LIST_CNT); } sc->dc_cdata.dc_tx_err = 0; sc->dc_cdata.dc_tx_prod = frag; sc->dc_cdata.dc_tx_cnt += nseg; sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG); if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG) sc->dc_ldata->dc_tx_list[first].dc_ctl |= htole32(DC_TXCTL_FINT); if (sc->dc_flags & DC_TX_INTR_ALWAYS) sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT); if (sc->dc_flags & DC_TX_USE_TX_INTR && sc->dc_cdata.dc_tx_cnt > 64) sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT); sc->dc_ldata->dc_tx_list[first].dc_status = htole32(DC_TXSTAT_OWN); } /* * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ static int dc_encap(struct dc_softc *sc, struct mbuf **m_head) { struct mbuf *m; int error, idx, chainlen = 0; /* * If there's no way we can send any packets, return now. */ if (DC_TX_LIST_CNT - sc->dc_cdata.dc_tx_cnt < 6) return (ENOBUFS); /* * Count the number of frags in this chain to see if * we need to m_defrag. Since the descriptor list is shared * by all packets, we'll m_defrag long chains so that they * do not use up the entire list, even if they would fit. */ for (m = *m_head; m != NULL; m = m->m_next) chainlen++; if ((chainlen > DC_TX_LIST_CNT / 4) || ((DC_TX_LIST_CNT - (chainlen + sc->dc_cdata.dc_tx_cnt)) < 6)) { m = m_defrag(*m_head, M_DONTWAIT); if (m == NULL) return (ENOBUFS); *m_head = m; } /* * Start packing the mbufs in this chain into * the fragment pointers. Stop when we run out * of fragments or hit the end of the mbuf chain. */ idx = sc->dc_cdata.dc_tx_prod; error = bus_dmamap_load_mbuf(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], *m_head, dc_dma_map_txbuf, sc, 0); if (error) return (error); if (sc->dc_cdata.dc_tx_err != 0) return (sc->dc_cdata.dc_tx_err); sc->dc_cdata.dc_tx_chain[idx] = *m_head; bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], BUS_DMASYNC_PREWRITE); bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); return (0); } /* * Main transmit routine. To avoid having to do mbuf copies, we put pointers * to the mbuf data regions directly in the transmit lists. We also save a * copy of the pointers since the transmit list fragment pointers are * physical addresses. */ static void dc_start(struct ifnet *ifp) { struct dc_softc *sc; struct mbuf *m_head = NULL, *m; int idx; sc = ifp->if_softc; DC_LOCK(sc); if (!sc->dc_link && ifp->if_snd.ifq_len < 10) { DC_UNLOCK(sc); return; } if (ifp->if_flags & IFF_OACTIVE) { DC_UNLOCK(sc); return; } idx = sc->dc_cdata.dc_tx_first = sc->dc_cdata.dc_tx_prod; while (sc->dc_cdata.dc_tx_chain[idx] == NULL) { IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; if (sc->dc_flags & DC_TX_COALESCE && (m_head->m_next != NULL || sc->dc_flags & DC_TX_ALIGN)) { m = m_defrag(m_head, M_DONTWAIT); if (m == NULL) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } else { m_head = m; } } if (dc_encap(sc, &m_head)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } idx = sc->dc_cdata.dc_tx_prod; /* * If there's a BPF listener, bounce a copy of this frame * to him. */ BPF_MTAP(ifp, m_head); if (sc->dc_flags & DC_TX_ONE) { ifp->if_flags |= IFF_OACTIVE; break; } } /* Transmit */ if (!(sc->dc_flags & DC_TX_POLL)) CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); /* * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; DC_UNLOCK(sc); } static void dc_init(void *xsc) { struct dc_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; struct mii_data *mii; DC_LOCK(sc); mii = device_get_softc(sc->dc_miibus); /* * Cancel pending I/O and free all RX/TX buffers. */ dc_stop(sc); dc_reset(sc); /* * Set cache alignment and burst length. */ if (DC_IS_ASIX(sc) || DC_IS_DAVICOM(sc)) CSR_WRITE_4(sc, DC_BUSCTL, 0); else CSR_WRITE_4(sc, DC_BUSCTL, DC_BUSCTL_MRME | DC_BUSCTL_MRLE); /* * Evenly share the bus between receive and transmit process. */ if (DC_IS_INTEL(sc)) DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_ARBITRATION); if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc)) { DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_USECA); } else { DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_16LONG); } if (sc->dc_flags & DC_TX_POLL) DC_SETBIT(sc, DC_BUSCTL, DC_TXPOLL_1); switch(sc->dc_cachesize) { case 32: DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_32LONG); break; case 16: DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_16LONG); break; case 8: DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_8LONG); break; case 0: default: DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_NONE); break; } if (sc->dc_flags & DC_TX_STORENFWD) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); else { if (sc->dc_txthresh > DC_TXTHRESH_MAX) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); } else { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh); } } DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_NO_RXCRC); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_BACKOFF); if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) { /* * The app notes for the 98713 and 98715A say that * in order to have the chips operate properly, a magic * number must be written to CSR16. Macronix does not * document the meaning of these bits so there's no way * to know exactly what they do. The 98713 has a magic * number all its own; the rest all use a different one. */ DC_CLRBIT(sc, DC_MX_MAGICPACKET, 0xFFFF0000); if (sc->dc_type == DC_TYPE_98713) DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98713); else DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98715); } if (DC_IS_XIRCOM(sc)) { /* * setup General Purpose Port mode and data so the tulip * can talk to the MII. */ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN | DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); DELAY(10); CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN | DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); DELAY(10); } DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH); DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_MIN); /* Init circular RX list. */ if (dc_list_rx_init(sc) == ENOBUFS) { printf("dc%d: initialization failed: no " "memory for rx buffers\n", sc->dc_unit); dc_stop(sc); DC_UNLOCK(sc); return; } /* * Init TX descriptors. */ dc_list_tx_init(sc); /* * Load the address of the RX list. */ CSR_WRITE_4(sc, DC_RXADDR, DC_RXDESC(sc, 0)); CSR_WRITE_4(sc, DC_TXADDR, DC_TXDESC(sc, 0)); /* * Enable interrupts. */ #ifdef DEVICE_POLLING /* * ... but only if we are not polling, and make sure they are off in * the case of polling. Some cards (e.g. fxp) turn interrupts on * after a reset. */ if (ifp->if_flags & IFF_POLLING) CSR_WRITE_4(sc, DC_IMR, 0x00000000); else #endif CSR_WRITE_4(sc, DC_IMR, DC_INTRS); CSR_WRITE_4(sc, DC_ISR, 0xFFFFFFFF); /* Enable transmitter. */ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); /* * If this is an Intel 21143 and we're not using the * MII port, program the LED control pins so we get * link and activity indications. */ if (sc->dc_flags & DC_TULIP_LEDS) { CSR_WRITE_4(sc, DC_WATCHDOG, DC_WDOG_CTLWREN | DC_WDOG_LINK | DC_WDOG_ACTIVITY); CSR_WRITE_4(sc, DC_WATCHDOG, 0); } /* * Load the RX/multicast filter. We do this sort of late * because the filter programming scheme on the 21143 and * some clones requires DMAing a setup frame via the TX * engine, and we need the transmitter enabled for that. */ dc_setfilt(sc); /* Enable receiver. */ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON); CSR_WRITE_4(sc, DC_RXSTART, 0xFFFFFFFF); mii_mediachg(mii); dc_setcfg(sc, sc->dc_if_media); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; /* Don't start the ticker if this is a homePNA link. */ if (IFM_SUBTYPE(mii->mii_media.ifm_media) == IFM_HPNA_1) sc->dc_link = 1; else { if (sc->dc_flags & DC_21143_NWAY) callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc); else callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc); } #ifdef SRM_MEDIA if(sc->dc_srm_media) { struct ifreq ifr; ifr.ifr_media = sc->dc_srm_media; ifmedia_ioctl(ifp, &ifr, &mii->mii_media, SIOCSIFMEDIA); sc->dc_srm_media = 0; } #endif DC_UNLOCK(sc); } /* * Set media options. */ static int dc_ifmedia_upd(struct ifnet *ifp) { struct dc_softc *sc; struct mii_data *mii; struct ifmedia *ifm; sc = ifp->if_softc; mii = device_get_softc(sc->dc_miibus); mii_mediachg(mii); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc) && IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) dc_setcfg(sc, ifm->ifm_media); else sc->dc_link = 0; return (0); } /* * Report current media status. */ static void dc_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct dc_softc *sc; struct mii_data *mii; struct ifmedia *ifm; sc = ifp->if_softc; mii = device_get_softc(sc->dc_miibus); mii_pollstat(mii); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc)) { if (IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) { ifmr->ifm_active = ifm->ifm_media; ifmr->ifm_status = 0; return; } } ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; } static int dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct dc_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; struct mii_data *mii; int error = 0; DC_LOCK(sc); switch (command) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { int need_setfilt = (ifp->if_flags ^ sc->dc_if_flags) & (IFF_PROMISC | IFF_ALLMULTI); if (ifp->if_flags & IFF_RUNNING) { if (need_setfilt) dc_setfilt(sc); } else { sc->dc_txthresh = 0; dc_init(sc); } } else { if (ifp->if_flags & IFF_RUNNING) dc_stop(sc); } sc->dc_if_flags = ifp->if_flags; error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: dc_setfilt(sc); error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: mii = device_get_softc(sc->dc_miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); #ifdef SRM_MEDIA if (sc->dc_srm_media) sc->dc_srm_media = 0; #endif break; default: error = ether_ioctl(ifp, command, data); break; } DC_UNLOCK(sc); return (error); } static void dc_watchdog(struct ifnet *ifp) { struct dc_softc *sc; sc = ifp->if_softc; DC_LOCK(sc); ifp->if_oerrors++; printf("dc%d: watchdog timeout\n", sc->dc_unit); dc_stop(sc); dc_reset(sc); dc_init(sc); if (ifp->if_snd.ifq_head != NULL) dc_start(ifp); DC_UNLOCK(sc); } /* * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ static void dc_stop(struct dc_softc *sc) { struct ifnet *ifp; struct dc_list_data *ld; struct dc_chain_data *cd; int i; u_int32_t ctl; DC_LOCK(sc); ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; ld = sc->dc_ldata; cd = &sc->dc_cdata; callout_stop(&sc->dc_stat_ch); ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); #ifdef DEVICE_POLLING ether_poll_deregister(ifp); #endif DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON | DC_NETCFG_TX_ON)); CSR_WRITE_4(sc, DC_IMR, 0x00000000); CSR_WRITE_4(sc, DC_TXADDR, 0x00000000); CSR_WRITE_4(sc, DC_RXADDR, 0x00000000); sc->dc_link = 0; /* * Free data in the RX lists. */ for (i = 0; i < DC_RX_LIST_CNT; i++) { if (cd->dc_rx_chain[i] != NULL) { m_freem(cd->dc_rx_chain[i]); cd->dc_rx_chain[i] = NULL; } } bzero(&ld->dc_rx_list, sizeof(ld->dc_rx_list)); /* * Free the TX list buffers. */ for (i = 0; i < DC_TX_LIST_CNT; i++) { if (cd->dc_tx_chain[i] != NULL) { ctl = le32toh(ld->dc_tx_list[i].dc_ctl); if ((ctl & DC_TXCTL_SETUP) || !(ctl & DC_TXCTL_FIRSTFRAG)) { cd->dc_tx_chain[i] = NULL; continue; } bus_dmamap_unload(sc->dc_mtag, cd->dc_tx_map[i]); m_freem(cd->dc_tx_chain[i]); cd->dc_tx_chain[i] = NULL; } } bzero(&ld->dc_tx_list, sizeof(ld->dc_tx_list)); DC_UNLOCK(sc); } /* * Device suspend routine. Stop the interface and save some PCI * settings in case the BIOS doesn't restore them properly on * resume. */ static int dc_suspend(device_t dev) { struct dc_softc *sc; int i, s; s = splimp(); sc = device_get_softc(dev); dc_stop(sc); for (i = 0; i < 5; i++) sc->saved_maps[i] = pci_read_config(dev, PCIR_BAR(i), 4); sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); sc->suspended = 1; splx(s); return (0); } /* * Device resume routine. Restore some PCI settings in case the BIOS * doesn't, re-enable busmastering, and restart the interface if * appropriate. */ static int dc_resume(device_t dev) { struct dc_softc *sc; struct ifnet *ifp; int i, s; s = splimp(); sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; #ifndef BURN_BRIDGES dc_acpi(dev); #endif /* better way to do this? */ for (i = 0; i < 5; i++) pci_write_config(dev, PCIR_BAR(i), sc->saved_maps[i], 4); pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); /* reenable busmastering */ pci_enable_busmaster(dev); pci_enable_io(dev, DC_RES); /* reinitialize interface if necessary */ if (ifp->if_flags & IFF_UP) dc_init(sc); sc->suspended = 0; splx(s); return (0); } /* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ static void dc_shutdown(device_t dev) { struct dc_softc *sc; sc = device_get_softc(dev); dc_stop(sc); } Index: head/sys/dev/dc/if_dcreg.h =================================================================== --- head/sys/dev/dc/if_dcreg.h (revision 123165) +++ head/sys/dev/dc/if_dcreg.h (revision 123166) @@ -1,1229 +1,1230 @@ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * 21143 and clone common register definitions. */ #define DC_BUSCTL 0x00 /* bus control */ #define DC_TXSTART 0x08 /* tx start demand */ #define DC_RXSTART 0x10 /* rx start demand */ #define DC_RXADDR 0x18 /* rx descriptor list start addr */ #define DC_TXADDR 0x20 /* tx descriptor list start addr */ #define DC_ISR 0x28 /* interrupt status register */ #define DC_NETCFG 0x30 /* network config register */ #define DC_IMR 0x38 /* interrupt mask */ #define DC_FRAMESDISCARDED 0x40 /* # of discarded frames */ #define DC_SIO 0x48 /* MII and ROM/EEPROM access */ #define DC_ROM 0x50 /* ROM programming address */ #define DC_TIMER 0x58 /* general timer */ #define DC_10BTSTAT 0x60 /* SIA status */ #define DC_SIARESET 0x68 /* SIA connectivity */ #define DC_10BTCTRL 0x70 /* SIA transmit and receive */ #define DC_WATCHDOG 0x78 /* SIA and general purpose port */ #define DC_SIAGP 0x78 /* SIA and general purpose port (X3201) */ /* * There are two general 'types' of MX chips that we need to be * concerned with. One is the original 98713, which has its internal * NWAY support controlled via the MDIO bits in the serial I/O * register. The other is everything else (from the 98713A on up), * which has its internal NWAY controlled via CSR13, CSR14 and CSR15, * just like the 21143. This type setting also governs which of the * 'magic' numbers we write to CSR16. The PNIC II falls into the * 98713A/98715/98715A/98725 category. */ #define DC_TYPE_98713 0x1 #define DC_TYPE_98713A 0x2 #define DC_TYPE_987x5 0x3 /* Other type of supported chips. */ #define DC_TYPE_21143 0x4 /* Intel 21143 */ #define DC_TYPE_ASIX 0x5 /* ASIX AX88140A/AX88141 */ #define DC_TYPE_AL981 0x6 /* ADMtek AL981 Comet */ #define DC_TYPE_AN985 0x7 /* ADMtek AN985 Centaur */ #define DC_TYPE_DM9102 0x8 /* Davicom DM9102 */ #define DC_TYPE_PNICII 0x9 /* 82c115 PNIC II */ #define DC_TYPE_PNIC 0xA /* 82c168/82c169 PNIC I */ #define DC_TYPE_XIRCOM 0xB /* Xircom X3201 */ #define DC_TYPE_CONEXANT 0xC /* Conexant LANfinity RS7112 */ #define DC_IS_MACRONIX(x) \ (x->dc_type == DC_TYPE_98713 || \ x->dc_type == DC_TYPE_98713A || \ x->dc_type == DC_TYPE_987x5) #define DC_IS_ADMTEK(x) \ (x->dc_type == DC_TYPE_AL981 || \ x->dc_type == DC_TYPE_AN985) #define DC_IS_INTEL(x) (x->dc_type == DC_TYPE_21143) #define DC_IS_ASIX(x) (x->dc_type == DC_TYPE_ASIX) #define DC_IS_COMET(x) (x->dc_type == DC_TYPE_AL981) #define DC_IS_CENTAUR(x) (x->dc_type == DC_TYPE_AN985) #define DC_IS_DAVICOM(x) (x->dc_type == DC_TYPE_DM9102) #define DC_IS_PNICII(x) (x->dc_type == DC_TYPE_PNICII) #define DC_IS_PNIC(x) (x->dc_type == DC_TYPE_PNIC) #define DC_IS_XIRCOM(x) (x->dc_type == DC_TYPE_XIRCOM) #define DC_IS_CONEXANT(x) (x->dc_type == DC_TYPE_CONEXANT) /* MII/symbol mode port types */ #define DC_PMODE_MII 0x1 #define DC_PMODE_SYM 0x2 #define DC_PMODE_SIA 0x3 /* * Bus control bits. */ #define DC_BUSCTL_RESET 0x00000001 #define DC_BUSCTL_ARBITRATION 0x00000002 #define DC_BUSCTL_SKIPLEN 0x0000007C #define DC_BUSCTL_BUF_BIGENDIAN 0x00000080 #define DC_BUSCTL_BURSTLEN 0x00003F00 #define DC_BUSCTL_CACHEALIGN 0x0000C000 #define DC_BUSCTL_TXPOLL 0x000E0000 #define DC_BUSCTL_DBO 0x00100000 #define DC_BUSCTL_MRME 0x00200000 #define DC_BUSCTL_MRLE 0x00800000 #define DC_BUSCTL_MWIE 0x01000000 #define DC_BUSCTL_ONNOW_ENB 0x04000000 #define DC_SKIPLEN_1LONG 0x00000004 #define DC_SKIPLEN_2LONG 0x00000008 #define DC_SKIPLEN_3LONG 0x00000010 #define DC_SKIPLEN_4LONG 0x00000020 #define DC_SKIPLEN_5LONG 0x00000040 #define DC_CACHEALIGN_NONE 0x00000000 #define DC_CACHEALIGN_8LONG 0x00004000 #define DC_CACHEALIGN_16LONG 0x00008000 #define DC_CACHEALIGN_32LONG 0x0000C000 #define DC_BURSTLEN_USECA 0x00000000 #define DC_BURSTLEN_1LONG 0x00000100 #define DC_BURSTLEN_2LONG 0x00000200 #define DC_BURSTLEN_4LONG 0x00000400 #define DC_BURSTLEN_8LONG 0x00000800 #define DC_BURSTLEN_16LONG 0x00001000 #define DC_BURSTLEN_32LONG 0x00002000 #define DC_TXPOLL_OFF 0x00000000 #define DC_TXPOLL_1 0x00020000 #define DC_TXPOLL_2 0x00040000 #define DC_TXPOLL_3 0x00060000 #define DC_TXPOLL_4 0x00080000 #define DC_TXPOLL_5 0x000A0000 #define DC_TXPOLL_6 0x000C0000 #define DC_TXPOLL_7 0x000E0000 /* * Interrupt status bits. */ #define DC_ISR_TX_OK 0x00000001 #define DC_ISR_TX_IDLE 0x00000002 #define DC_ISR_TX_NOBUF 0x00000004 #define DC_ISR_TX_JABBERTIMEO 0x00000008 #define DC_ISR_LINKGOOD 0x00000010 #define DC_ISR_TX_UNDERRUN 0x00000020 #define DC_ISR_RX_OK 0x00000040 #define DC_ISR_RX_NOBUF 0x00000080 #define DC_ISR_RX_READ 0x00000100 #define DC_ISR_RX_WATDOGTIMEO 0x00000200 #define DC_ISR_TX_EARLY 0x00000400 #define DC_ISR_TIMER_EXPIRED 0x00000800 #define DC_ISR_LINKFAIL 0x00001000 #define DC_ISR_BUS_ERR 0x00002000 #define DC_ISR_RX_EARLY 0x00004000 #define DC_ISR_ABNORMAL 0x00008000 #define DC_ISR_NORMAL 0x00010000 #define DC_ISR_RX_STATE 0x000E0000 #define DC_ISR_TX_STATE 0x00700000 #define DC_ISR_BUSERRTYPE 0x03800000 #define DC_ISR_100MBPSLINK 0x08000000 #define DC_ISR_MAGICKPACK 0x10000000 #define DC_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */ #define DC_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */ #define DC_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */ #define DC_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */ #define DC_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */ #define DC_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */ #define DC_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */ #define DC_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */ #define DC_TXSTATE_RESET 0x00000000 /* 000 - reset */ #define DC_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */ #define DC_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */ #define DC_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */ #define DC_TXSTATE_RSVD 0x00400000 /* 100 - reserved */ #define DC_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */ #define DC_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */ #define DC_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */ /* * Network config bits. */ #define DC_NETCFG_RX_HASHPERF 0x00000001 #define DC_NETCFG_RX_ON 0x00000002 #define DC_NETCFG_RX_HASHONLY 0x00000004 #define DC_NETCFG_RX_BADFRAMES 0x00000008 #define DC_NETCFG_RX_INVFILT 0x00000010 #define DC_NETCFG_BACKOFFCNT 0x00000020 #define DC_NETCFG_RX_PROMISC 0x00000040 #define DC_NETCFG_RX_ALLMULTI 0x00000080 #define DC_NETCFG_FULLDUPLEX 0x00000200 #define DC_NETCFG_LOOPBACK 0x00000C00 #define DC_NETCFG_FORCECOLL 0x00001000 #define DC_NETCFG_TX_ON 0x00002000 #define DC_NETCFG_TX_THRESH 0x0000C000 #define DC_NETCFG_TX_BACKOFF 0x00020000 #define DC_NETCFG_PORTSEL 0x00040000 /* 0 == 10, 1 == 100 */ #define DC_NETCFG_HEARTBEAT 0x00080000 #define DC_NETCFG_STORENFWD 0x00200000 #define DC_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */ #define DC_NETCFG_PCS 0x00800000 #define DC_NETCFG_SCRAMBLER 0x01000000 #define DC_NETCFG_NO_RXCRC 0x02000000 #define DC_NETCFG_RX_ALL 0x40000000 #define DC_NETCFG_CAPEFFECT 0x80000000 #define DC_OPMODE_NORM 0x00000000 #define DC_OPMODE_INTLOOP 0x00000400 #define DC_OPMODE_EXTLOOP 0x00000800 #if 0 #define DC_TXTHRESH_72BYTES 0x00000000 #define DC_TXTHRESH_96BYTES 0x00004000 #define DC_TXTHRESH_128BYTES 0x00008000 #define DC_TXTHRESH_160BYTES 0x0000C000 #endif #define DC_TXTHRESH_MIN 0x00000000 #define DC_TXTHRESH_INC 0x00004000 #define DC_TXTHRESH_MAX 0x0000C000 /* * Interrupt mask bits. */ #define DC_IMR_TX_OK 0x00000001 #define DC_IMR_TX_IDLE 0x00000002 #define DC_IMR_TX_NOBUF 0x00000004 #define DC_IMR_TX_JABBERTIMEO 0x00000008 #define DC_IMR_LINKGOOD 0x00000010 #define DC_IMR_TX_UNDERRUN 0x00000020 #define DC_IMR_RX_OK 0x00000040 #define DC_IMR_RX_NOBUF 0x00000080 #define DC_IMR_RX_READ 0x00000100 #define DC_IMR_RX_WATDOGTIMEO 0x00000200 #define DC_IMR_TX_EARLY 0x00000400 #define DC_IMR_TIMER_EXPIRED 0x00000800 #define DC_IMR_LINKFAIL 0x00001000 #define DC_IMR_BUS_ERR 0x00002000 #define DC_IMR_RX_EARLY 0x00004000 #define DC_IMR_ABNORMAL 0x00008000 #define DC_IMR_NORMAL 0x00010000 #define DC_IMR_100MBPSLINK 0x08000000 #define DC_IMR_MAGICKPACK 0x10000000 #define DC_INTRS \ (DC_IMR_RX_OK|DC_IMR_TX_OK|DC_IMR_RX_NOBUF|DC_IMR_RX_WATDOGTIMEO|\ DC_IMR_TX_NOBUF|DC_IMR_TX_UNDERRUN|DC_IMR_BUS_ERR| \ DC_IMR_ABNORMAL|DC_IMR_NORMAL/*|DC_IMR_TX_EARLY*/) /* * Serial I/O (EEPROM/ROM) bits. */ #define DC_SIO_EE_CS 0x00000001 /* EEPROM chip select */ #define DC_SIO_EE_CLK 0x00000002 /* EEPROM clock */ #define DC_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */ #define DC_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */ #define DC_SIO_ROMDATA4 0x00000010 #define DC_SIO_ROMDATA5 0x00000020 #define DC_SIO_ROMDATA6 0x00000040 #define DC_SIO_ROMDATA7 0x00000080 #define DC_SIO_EESEL 0x00000800 #define DC_SIO_ROMSEL 0x00001000 #define DC_SIO_ROMCTL_WRITE 0x00002000 #define DC_SIO_ROMCTL_READ 0x00004000 #define DC_SIO_MII_CLK 0x00010000 /* MDIO clock */ #define DC_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */ #define DC_SIO_MII_DIR 0x00040000 /* MDIO dir */ #define DC_SIO_MII_DATAIN 0x00080000 /* MDIO data in */ #define DC_EECMD_WRITE 0x140 #define DC_EECMD_READ 0x180 #define DC_EECMD_ERASE 0x1c0 #define DC_EE_NODEADDR_OFFSET 0x70 #define DC_EE_NODEADDR 10 /* * General purpose timer register */ #define DC_TIMER_VALUE 0x0000FFFF #define DC_TIMER_CONTINUOUS 0x00010000 /* * 10baseT status register */ #define DC_TSTAT_MIIACT 0x00000001 /* MII port activity */ #define DC_TSTAT_LS100 0x00000002 /* link status of 100baseTX */ #define DC_TSTAT_LS10 0x00000004 /* link status of 10baseT */ #define DC_TSTAT_AUTOPOLARITY 0x00000008 #define DC_TSTAT_AUIACT 0x00000100 /* AUI activity */ #define DC_TSTAT_10BTACT 0x00000200 /* 10baseT activity */ #define DC_TSTAT_NSN 0x00000400 /* non-stable FLPs detected */ #define DC_TSTAT_REMFAULT 0x00000800 #define DC_TSTAT_ANEGSTAT 0x00007000 #define DC_TSTAT_LP_CAN_NWAY 0x00008000 /* link partner supports NWAY */ #define DC_TSTAT_LPCODEWORD 0xFFFF0000 /* link partner's code word */ #define DC_ASTAT_DISABLE 0x00000000 #define DC_ASTAT_TXDISABLE 0x00001000 #define DC_ASTAT_ABDETECT 0x00002000 #define DC_ASTAT_ACKDETECT 0x00003000 #define DC_ASTAT_CMPACKDETECT 0x00004000 #define DC_ASTAT_AUTONEGCMP 0x00005000 #define DC_ASTAT_LINKCHECK 0x00006000 /* * PHY reset register */ #define DC_SIA_RESET 0x00000001 #define DC_SIA_AUI 0x00000008 /* AUI or 10baseT */ /* * 10baseT control register */ #define DC_TCTL_ENCODER_ENB 0x00000001 #define DC_TCTL_LOOPBACK 0x00000002 #define DC_TCTL_DRIVER_ENB 0x00000004 #define DC_TCTL_LNKPULSE_ENB 0x00000008 #define DC_TCTL_HALFDUPLEX 0x00000040 #define DC_TCTL_AUTONEGENBL 0x00000080 #define DC_TCTL_RX_SQUELCH 0x00000100 #define DC_TCTL_COLL_SQUELCH 0x00000200 #define DC_TCTL_COLL_DETECT 0x00000400 #define DC_TCTL_SQE_ENB 0x00000800 #define DC_TCTL_LINKTEST 0x00001000 #define DC_TCTL_AUTOPOLARITY 0x00002000 #define DC_TCTL_SET_POL_PLUS 0x00004000 #define DC_TCTL_AUTOSENSE 0x00008000 /* 10bt/AUI autosense */ #define DC_TCTL_100BTXHALF 0x00010000 #define DC_TCTL_100BTXFULL 0x00020000 #define DC_TCTL_100BT4 0x00040000 /* * Watchdog timer register */ #define DC_WDOG_JABBERDIS 0x00000001 #define DC_WDOG_HOSTUNJAB 0x00000002 #define DC_WDOG_JABBERCLK 0x00000004 #define DC_WDOG_RXWDOGDIS 0x00000010 #define DC_WDOG_RXWDOGCLK 0x00000020 #define DC_WDOG_MUSTBEZERO 0x00000100 #define DC_WDOG_AUIBNC 0x00100000 #define DC_WDOG_ACTIVITY 0x00200000 #define DC_WDOG_RX_MATCH 0x00400000 #define DC_WDOG_LINK 0x00800000 #define DC_WDOG_CTLWREN 0x08000000 /* * SIA and General Purpose Port register (X3201) */ #define DC_SIAGP_RXMATCH 0x40000000 #define DC_SIAGP_INT1 0x20000000 #define DC_SIAGP_INT0 0x10000000 #define DC_SIAGP_WRITE_EN 0x08000000 #define DC_SIAGP_RXMATCH_EN 0x04000000 #define DC_SIAGP_INT1_EN 0x02000000 #define DC_SIAGP_INT0_EN 0x01000000 #define DC_SIAGP_LED3 0x00800000 #define DC_SIAGP_LED2 0x00400000 #define DC_SIAGP_LED1 0x00200000 #define DC_SIAGP_LED0 0x00100000 #define DC_SIAGP_MD_GP3_OUTPUT 0x00080000 #define DC_SIAGP_MD_GP2_OUTPUT 0x00040000 #define DC_SIAGP_MD_GP1_OUTPUT 0x00020000 #define DC_SIAGP_MD_GP0_OUTPUT 0x00010000 /* * Size of a setup frame. */ #define DC_SFRAME_LEN 192 /* * 21x4x TX/RX list structure. */ struct dc_desc { u_int32_t dc_status; u_int32_t dc_ctl; u_int32_t dc_ptr1; u_int32_t dc_ptr2; }; #define dc_data dc_ptr1 #define dc_next dc_ptr2 #define DC_RXSTAT_FIFOOFLOW 0x00000001 #define DC_RXSTAT_CRCERR 0x00000002 #define DC_RXSTAT_DRIBBLE 0x00000004 #define DC_RXSTAT_MIIERE 0x00000008 #define DC_RXSTAT_WATCHDOG 0x00000010 #define DC_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */ #define DC_RXSTAT_COLLSEEN 0x00000040 #define DC_RXSTAT_GIANT 0x00000080 #define DC_RXSTAT_LASTFRAG 0x00000100 #define DC_RXSTAT_FIRSTFRAG 0x00000200 #define DC_RXSTAT_MULTICAST 0x00000400 #define DC_RXSTAT_RUNT 0x00000800 #define DC_RXSTAT_RXTYPE 0x00003000 #define DC_RXSTAT_DE 0x00004000 #define DC_RXSTAT_RXERR 0x00008000 #define DC_RXSTAT_RXLEN 0x3FFF0000 #define DC_RXSTAT_OWN 0x80000000 #define DC_RXBYTES(x) ((x & DC_RXSTAT_RXLEN) >> 16) #define DC_RXSTAT (DC_RXSTAT_FIRSTFRAG|DC_RXSTAT_LASTFRAG|DC_RXSTAT_OWN) #define DC_RXCTL_BUFLEN1 0x00000FFF #define DC_RXCTL_BUFLEN2 0x00FFF000 #define DC_RXCTL_RLINK 0x01000000 #define DC_RXCTL_RLAST 0x02000000 #define DC_TXSTAT_DEFER 0x00000001 #define DC_TXSTAT_UNDERRUN 0x00000002 #define DC_TXSTAT_LINKFAIL 0x00000003 #define DC_TXSTAT_COLLCNT 0x00000078 #define DC_TXSTAT_SQE 0x00000080 #define DC_TXSTAT_EXCESSCOLL 0x00000100 #define DC_TXSTAT_LATECOLL 0x00000200 #define DC_TXSTAT_NOCARRIER 0x00000400 #define DC_TXSTAT_CARRLOST 0x00000800 #define DC_TXSTAT_JABTIMEO 0x00004000 #define DC_TXSTAT_ERRSUM 0x00008000 #define DC_TXSTAT_OWN 0x80000000 #define DC_TXCTL_BUFLEN1 0x000007FF #define DC_TXCTL_BUFLEN2 0x003FF800 #define DC_TXCTL_FILTTYPE0 0x00400000 #define DC_TXCTL_PAD 0x00800000 #define DC_TXCTL_TLINK 0x01000000 #define DC_TXCTL_TLAST 0x02000000 #define DC_TXCTL_NOCRC 0x04000000 #define DC_TXCTL_SETUP 0x08000000 #define DC_TXCTL_FILTTYPE1 0x10000000 #define DC_TXCTL_FIRSTFRAG 0x20000000 #define DC_TXCTL_LASTFRAG 0x40000000 #define DC_TXCTL_FINT 0x80000000 #define DC_FILTER_PERFECT 0x00000000 #define DC_FILTER_HASHPERF 0x00400000 #define DC_FILTER_INVERSE 0x10000000 #define DC_FILTER_HASHONLY 0x10400000 #define DC_MAXFRAGS 16 #ifdef DEVICE_POLLING #define DC_RX_LIST_CNT 192 #else #define DC_RX_LIST_CNT 64 #endif #define DC_TX_LIST_CNT 256 #define DC_MIN_FRAMELEN 60 #define DC_RXLEN 1536 #define DC_INC(x, y) (x) = (x + 1) % y /* Macros to easily get the DMA address of a descriptor. */ #define DC_RXDESC(sc, i) (sc->dc_laddr + \ (uintptr_t)(sc->dc_ldata->dc_rx_list + i) - (uintptr_t)sc->dc_ldata) #define DC_TXDESC(sc, i) (sc->dc_laddr + \ (uintptr_t)(sc->dc_ldata->dc_tx_list + i) - (uintptr_t)sc->dc_ldata) #if BYTE_ORDER == BIG_ENDIAN #define DC_SP_MAC(x) ((x) << 16) #else #define DC_SP_MAC(x) (x) #endif struct dc_list_data { struct dc_desc dc_rx_list[DC_RX_LIST_CNT]; struct dc_desc dc_tx_list[DC_TX_LIST_CNT]; }; struct dc_chain_data { struct mbuf *dc_rx_chain[DC_RX_LIST_CNT]; struct mbuf *dc_tx_chain[DC_TX_LIST_CNT]; bus_dmamap_t dc_rx_map[DC_RX_LIST_CNT]; bus_dmamap_t dc_tx_map[DC_TX_LIST_CNT]; u_int32_t *dc_sbuf; u_int8_t dc_pad[DC_MIN_FRAMELEN]; int dc_tx_err; int dc_tx_first; int dc_tx_prod; int dc_tx_cons; int dc_tx_cnt; int dc_rx_err; int dc_rx_cur; int dc_rx_prod; }; struct dc_mediainfo { int dc_media; u_int8_t *dc_gp_ptr; u_int8_t dc_gp_len; u_int8_t *dc_reset_ptr; u_int8_t dc_reset_len; struct dc_mediainfo *dc_next; }; struct dc_type { u_int16_t dc_vid; u_int16_t dc_did; char *dc_name; }; struct dc_mii_frame { u_int8_t mii_stdelim; u_int8_t mii_opcode; u_int8_t mii_phyaddr; u_int8_t mii_regaddr; u_int8_t mii_turnaround; u_int16_t mii_data; }; /* * MII constants */ #define DC_MII_STARTDELIM 0x01 #define DC_MII_READOP 0x02 #define DC_MII_WRITEOP 0x01 #define DC_MII_TURNAROUND 0x02 /* * Registers specific to clone devices. * This mainly relates to RX filter programming: not all 21x4x clones * use the standard DEC filter programming mechanism. */ /* * ADMtek specific registers and constants for the AL981 and AN985. * The AN985 doesn't use the magic PHY registers. */ #define DC_AL_CR 0x88 /* command register */ #define DC_AL_PAR0 0xA4 /* station address */ #define DC_AL_PAR1 0xA8 /* station address */ #define DC_AL_MAR0 0xAC /* multicast hash filter */ #define DC_AL_MAR1 0xB0 /* multicast hash filter */ #define DC_AL_BMCR 0xB4 /* built in PHY control */ #define DC_AL_BMSR 0xB8 /* built in PHY status */ #define DC_AL_VENID 0xBC /* built in PHY ID0 */ #define DC_AL_DEVID 0xC0 /* built in PHY ID1 */ #define DC_AL_ANAR 0xC4 /* built in PHY autoneg advert */ #define DC_AL_LPAR 0xC8 /* bnilt in PHY link part. ability */ #define DC_AL_ANER 0xCC /* built in PHY autoneg expansion */ #define DC_AL_CR_ATUR 0x00000001 /* automatic TX underrun recovery */ #define DC_ADMTEK_PHYADDR 0x1 #define DC_AL_EE_NODEADDR 4 /* End of ADMtek specific registers */ /* * ASIX specific registers. */ #define DC_AX_FILTIDX 0x68 /* RX filter index */ #define DC_AX_FILTDATA 0x70 /* RX filter data */ /* * Special ASIX-specific bits in the ASIX NETCFG register (CSR6). */ #define DC_AX_NETCFG_RX_BROAD 0x00000100 /* * RX Filter Index Register values */ #define DC_AX_FILTIDX_PAR0 0x00000000 #define DC_AX_FILTIDX_PAR1 0x00000001 #define DC_AX_FILTIDX_MAR0 0x00000002 #define DC_AX_FILTIDX_MAR1 0x00000003 /* End of ASIX specific registers */ /* * Macronix specific registers. The Macronix chips have a special * register for reading the NWAY status, which we don't use, plus * a magic packet register, which we need to tweak a bit per the * Macronix application notes. */ #define DC_MX_MAGICPACKET 0x80 #define DC_MX_NWAYSTAT 0xA0 /* * Magic packet register */ #define DC_MX_MPACK_DISABLE 0x00400000 /* * NWAY status register. */ #define DC_MX_NWAY_10BTHALF 0x08000000 #define DC_MX_NWAY_10BTFULL 0x10000000 #define DC_MX_NWAY_100BTHALF 0x20000000 #define DC_MX_NWAY_100BTFULL 0x40000000 #define DC_MX_NWAY_100BT4 0x80000000 /* * These are magic values that must be written into CSR16 * (DC_MX_MAGICPACKET) in order to put the chip into proper * operating mode. The magic numbers are documented in the * Macronix 98715 application notes. */ #define DC_MX_MAGIC_98713 0x0F370000 #define DC_MX_MAGIC_98713A 0x0B3C0000 #define DC_MX_MAGIC_98715 0x0B3C0000 #define DC_MX_MAGIC_98725 0x0B3C0000 /* End of Macronix specific registers */ /* * PNIC 82c168/82c169 specific registers. * The PNIC has its own special NWAY support, which doesn't work, * and shortcut ways of reading the EEPROM and MII bus. */ #define DC_PN_GPIO 0x60 /* general purpose pins control */ #define DC_PN_PWRUP_CFG 0x90 /* config register, set by EEPROM */ #define DC_PN_SIOCTL 0x98 /* serial EEPROM control register */ #define DC_PN_MII 0xA0 /* MII access register */ #define DC_PN_NWAY 0xB8 /* Internal NWAY register */ /* Serial I/O EEPROM register */ #define DC_PN_SIOCTL_DATA 0x0000003F #define DC_PN_SIOCTL_OPCODE 0x00000300 #define DC_PN_SIOCTL_BUSY 0x80000000 #define DC_PN_EEOPCODE_ERASE 0x00000300 #define DC_PN_EEOPCODE_READ 0x00000600 #define DC_PN_EEOPCODE_WRITE 0x00000100 /* * The first two general purpose pins control speed selection and * 100Mbps loopback on the 82c168 chip. The control bits should always * be set (to make the data pins outputs) and the speed selction and * loopback bits set accordingly when changing media. Physically, this * will set the state of a relay mounted on the card. */ #define DC_PN_GPIO_DATA0 0x000000001 #define DC_PN_GPIO_DATA1 0x000000002 #define DC_PN_GPIO_DATA2 0x000000004 #define DC_PN_GPIO_DATA3 0x000000008 #define DC_PN_GPIO_CTL0 0x000000010 #define DC_PN_GPIO_CTL1 0x000000020 #define DC_PN_GPIO_CTL2 0x000000040 #define DC_PN_GPIO_CTL3 0x000000080 #define DC_PN_GPIO_SPEEDSEL DC_PN_GPIO_DATA0/* 1 == 100Mbps, 0 == 10Mbps */ #define DC_PN_GPIO_100TX_LOOP DC_PN_GPIO_DATA1/* 1 == normal, 0 == loop */ #define DC_PN_GPIO_BNC_ENB DC_PN_GPIO_DATA2 #define DC_PN_GPIO_100TX_LNK DC_PN_GPIO_DATA3 #define DC_PN_GPIO_SETBIT(sc, r) \ DC_SETBIT(sc, DC_PN_GPIO, ((r) | (r << 4))) #define DC_PN_GPIO_CLRBIT(sc, r) \ { \ DC_SETBIT(sc, DC_PN_GPIO, ((r) << 4)); \ DC_CLRBIT(sc, DC_PN_GPIO, (r)); \ } /* shortcut MII access register */ #define DC_PN_MII_DATA 0x0000FFFF #define DC_PN_MII_RESERVER 0x00020000 #define DC_PN_MII_REGADDR 0x007C0000 #define DC_PN_MII_PHYADDR 0x0F800000 #define DC_PN_MII_OPCODE 0x30000000 #define DC_PN_MII_BUSY 0x80000000 #define DC_PN_MIIOPCODE_READ 0x60020000 #define DC_PN_MIIOPCODE_WRITE 0x50020000 /* Internal NWAY bits */ #define DC_PN_NWAY_RESET 0x00000001 /* reset */ #define DC_PN_NWAY_PDOWN 0x00000002 /* power down */ #define DC_PN_NWAY_BYPASS 0x00000004 /* bypass */ #define DC_PN_NWAY_AUILOWCUR 0x00000008 /* AUI low current */ #define DC_PN_NWAY_TPEXTEND 0x00000010 /* low squelch voltage */ #define DC_PN_NWAY_POLARITY 0x00000020 /* 0 == on, 1 == off */ #define DC_PN_NWAY_TP 0x00000040 /* 1 == tp, 0 == AUI */ #define DC_PN_NWAY_AUIVOLT 0x00000080 /* 1 == full, 0 == half */ #define DC_PN_NWAY_DUPLEX 0x00000100 /* LED, 1 == full, 0 == half */ #define DC_PN_NWAY_LINKTEST 0x00000200 /* 0 == on, 1 == off */ #define DC_PN_NWAY_AUTODETECT 0x00000400 /* 1 == off, 0 == on */ #define DC_PN_NWAY_SPEEDSEL 0x00000800 /* LED, 0 = 10, 1 == 100 */ #define DC_PN_NWAY_NWAY_ENB 0x00001000 /* 0 == off, 1 == on */ #define DC_PN_NWAY_CAP10HDX 0x00002000 #define DC_PN_NWAY_CAP10FDX 0x00004000 #define DC_PN_NWAY_CAP100FDX 0x00008000 #define DC_PN_NWAY_CAP100HDX 0x00010000 #define DC_PN_NWAY_CAP100T4 0x00020000 #define DC_PN_NWAY_ANEGRESTART 0x02000000 /* resets when aneg done */ #define DC_PN_NWAY_REMFAULT 0x04000000 #define DC_PN_NWAY_LPAR10HDX 0x08000000 #define DC_PN_NWAY_LPAR10FDX 0x10000000 #define DC_PN_NWAY_LPAR100FDX 0x20000000 #define DC_PN_NWAY_LPAR100HDX 0x40000000 #define DC_PN_NWAY_LPAR100T4 0x80000000 /* End of PNIC specific registers */ /* * CONEXANT specific registers. */ #define DC_CONEXANT_PHYADDR 0x1 #define DC_CONEXANT_EE_NODEADDR 0x19A /* End of CONEXANT specific registers */ struct dc_softc { struct arpcom arpcom; /* interface info */ bus_space_handle_t dc_bhandle; /* bus space handle */ bus_space_tag_t dc_btag; /* bus space tag */ bus_dma_tag_t dc_ltag; /* tag for descriptor ring */ bus_dmamap_t dc_lmap; /* map for descriptor ring */ u_int32_t dc_laddr; /* DMA address of dc_ldata */ bus_dma_tag_t dc_mtag; /* tag for mbufs */ bus_dmamap_t dc_sparemap; bus_dma_tag_t dc_stag; /* tag for the setup frame */ bus_dmamap_t dc_smap; /* map for the setup frame */ u_int32_t dc_saddr; /* DMA address of setup frame */ void *dc_intrhand; struct resource *dc_irq; struct resource *dc_res; struct dc_type *dc_info; /* adapter info */ device_t dc_miibus; u_int8_t dc_unit; /* interface number */ u_int8_t dc_type; u_int8_t dc_pmode; u_int8_t dc_link; u_int8_t dc_cachesize; int dc_romwidth; int dc_pnic_rx_bug_save; unsigned char *dc_pnic_rx_buf; int dc_if_flags; int dc_if_media; u_int32_t dc_flags; u_int32_t dc_txthresh; u_int8_t *dc_srom; struct dc_mediainfo *dc_mi; struct dc_list_data *dc_ldata; struct dc_chain_data dc_cdata; struct callout dc_stat_ch; #ifdef SRM_MEDIA int dc_srm_media; #endif struct mtx dc_mtx; #ifdef DEVICE_POLLING int rxcycles; /* ... when polling */ #endif int suspended; /* 0 = normal 1 = suspended */ u_int32_t saved_maps[5]; /* pci data */ u_int32_t saved_biosaddr; u_int8_t saved_intline; u_int8_t saved_cachelnsz; u_int8_t saved_lattimer; }; #define DC_LOCK(_sc) mtx_lock(&(_sc)->dc_mtx) #define DC_UNLOCK(_sc) mtx_unlock(&(_sc)->dc_mtx) #define DC_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->dc_mtx, MA_OWNED) #define DC_TX_POLL 0x00000001 #define DC_TX_COALESCE 0x00000002 #define DC_TX_ADMTEK_WAR 0x00000004 #define DC_TX_USE_TX_INTR 0x00000008 #define DC_RX_FILTER_TULIP 0x00000010 #define DC_TX_INTR_FIRSTFRAG 0x00000020 #define DC_PNIC_RX_BUG_WAR 0x00000040 #define DC_TX_FIXED_RING 0x00000080 #define DC_TX_STORENFWD 0x00000100 #define DC_REDUCED_MII_POLL 0x00000200 #define DC_TX_INTR_ALWAYS 0x00000400 #define DC_21143_NWAY 0x00000800 #define DC_128BIT_HASH 0x00001000 #define DC_64BIT_HASH 0x00002000 #define DC_TULIP_LEDS 0x00004000 #define DC_TX_ONE 0x00008000 #define DC_TX_ALIGN 0x00010000 /* align mbuf on tx */ /* * register space access macros */ #define CSR_WRITE_4(sc, reg, val) \ bus_space_write_4(sc->dc_btag, sc->dc_bhandle, reg, val) #define CSR_READ_4(sc, reg) \ bus_space_read_4(sc->dc_btag, sc->dc_bhandle, reg) #define DC_TIMEOUT 1000 #define ETHER_ALIGN 2 /* * General constants that are fun to know. */ /* * DEC PCI vendor ID */ #define DC_VENDORID_DEC 0x1011 /* * DEC/Intel 21143 PCI device ID */ #define DC_DEVICEID_21143 0x0019 /* * Macronix PCI vendor ID */ #define DC_VENDORID_MX 0x10D9 /* * Macronix PMAC device IDs. */ #define DC_DEVICEID_98713 0x0512 #define DC_DEVICEID_987x5 0x0531 #define DC_DEVICEID_98727 0x0532 #define DC_DEVICEID_98732 0x0532 /* Macronix PCI revision codes. */ #define DC_REVISION_98713 0x00 #define DC_REVISION_98713A 0x10 #define DC_REVISION_98715 0x20 #define DC_REVISION_98715AEC_C 0x25 #define DC_REVISION_98725 0x30 /* * Compex PCI vendor ID. */ #define DC_VENDORID_CP 0x11F6 /* * Compex PMAC PCI device IDs. */ #define DC_DEVICEID_98713_CP 0x9881 /* * Lite-On PNIC PCI vendor ID */ #define DC_VENDORID_LO 0x11AD /* * 82c168/82c169 PNIC device IDs. Both chips have the same device * ID but different revisions. Revision 0x10 is the 82c168, and * 0x20 is the 82c169. */ #define DC_DEVICEID_82C168 0x0002 #define DC_REVISION_82C168 0x10 #define DC_REVISION_82C169 0x20 /* * Lite-On PNIC II device ID. Note: this is actually a Macronix 98715A * with wake on lan/magic packet support. */ #define DC_DEVICEID_82C115 0xc115 /* * Davicom vendor ID. */ #define DC_VENDORID_DAVICOM 0x1282 /* * Davicom device IDs. */ #define DC_DEVICEID_DM9009 0x9009 #define DC_DEVICEID_DM9100 0x9100 #define DC_DEVICEID_DM9102 0x9102 /* * The DM9102A has the same PCI device ID as the DM9102, * but a higher revision code. */ #define DC_REVISION_DM9102 0x10 #define DC_REVISION_DM9102A 0x30 /* * ADMtek vendor ID. */ #define DC_VENDORID_ADMTEK 0x1317 /* * ADMtek device IDs. */ #define DC_DEVICEID_AL981 0x0981 #define DC_DEVICEID_AN985 0x0985 #define DC_DEVICEID_FA511 0x1985 #define DC_DEVICEID_ADM9511 0x9511 #define DC_DEVICEID_ADM9513 0x9513 /* * 3COM PCI vendor ID */ #define DC_VENDORID_3COM 0x10b7 /* * 3COM OfficeConnect 10/100B (3CSOHO100B-TX) */ #define DC_DEVICEID_3CSOHOB 0x9300 /* * ASIX vendor ID. */ #define DC_VENDORID_ASIX 0x125B /* * ASIX device IDs. */ #define DC_DEVICEID_AX88140A 0x1400 /* * The ASIX AX88140 and ASIX AX88141 have the same vendor and * device IDs but different revision values. */ #define DC_REVISION_88140 0x00 #define DC_REVISION_88141 0x10 /* * Accton vendor ID. */ #define DC_VENDORID_ACCTON 0x1113 /* * Accton device IDs. */ #define DC_DEVICEID_EN1217 0x1217 #define DC_DEVICEID_EN2242 0x1216 /* * Xircom vendor ID */ #define DC_VENDORID_XIRCOM 0x115d /* * Xircom device IDs. */ #define DC_DEVICEID_X3201 0x0003 /* * Abocom vendor ID */ #define DC_VENDORID_ABOCOM 0x13d1 /* * Abocom device IDs. */ #define DC_DEVICEID_FE2500 0xAB02 +#define DC_DEVICEID_FE2500MX 0xab08 /* * Conexant vendor ID. */ #define DC_VENDORID_CONEXANT 0x14f1 /* * Conexant device IDs. */ #define DC_DEVICEID_RS7112 0x1803 /* * Planex vendor ID */ #define DC_VENDORID_PLANEX 0x14ea /* * Planex device IDs. */ #define DC_DEVICEID_FNW3602T 0xab08 /* * Not sure who this vendor should be, so we'll go with HAWKING until * I can locate the right one. */ #define DC_VENDORID_HAWKING 0x17b3 /* * Sure looks like an abocom device ID, but it found on my hawking PN672TX * card. Use that for now, and upgrade later. */ #define DC_DEVICEID_HAWKING_PN672TX 0xab08 /* * Microsoft device ID. */ #define DC_VENDORID_MICROSOFT 0x1414 /* * Supported Microsoft PCI and cardbus NICs. These are really * ADMtek parts in disguise. */ #define DC_DEVICEID_MSMN120 0x0001 #define DC_DEVICEID_MSMN130 0x0002 #define DC_DEVICEID_MSMN130_FAKE 0xFFF2 /* * PCI low memory base and low I/O base register, and * other PCI registers. */ #define DC_PCI_CFID 0x00 /* Id */ #define DC_PCI_CFCS 0x04 /* Command and status */ #define DC_PCI_CFRV 0x08 /* Revision */ #define DC_PCI_CFLT 0x0C /* Latency timer */ #define DC_PCI_CFBIO 0x10 /* Base I/O address */ #define DC_PCI_CFBMA 0x14 /* Base memory address */ #define DC_PCI_CCIS 0x28 /* Card info struct */ #define DC_PCI_CSID 0x2C /* Subsystem ID */ #define DC_PCI_CBER 0x30 /* Expansion ROM base address */ #define DC_PCI_CCAP 0x34 /* Caps pointer - PD/TD chip only */ #define DC_PCI_CFIT 0x3C /* Interrupt */ #define DC_PCI_CFDD 0x40 /* Device and driver area */ #define DC_PCI_CWUA0 0x44 /* Wake-Up LAN addr 0 */ #define DC_PCI_CWUA1 0x48 /* Wake-Up LAN addr 1 */ #define DC_PCI_SOP0 0x4C /* SecureON passwd 0 */ #define DC_PCI_SOP1 0x50 /* SecureON passwd 1 */ #define DC_PCI_CWUC 0x54 /* Configuration Wake-Up cmd */ #define DC_PCI_CCID 0xDC /* Capability ID - PD/TD only */ #define DC_PCI_CPMC 0xE0 /* Pwrmgmt ctl & sts - PD/TD only */ /* PCI ID register */ #define DC_CFID_VENDOR 0x0000FFFF #define DC_CFID_DEVICE 0xFFFF0000 /* PCI command/status register */ #define DC_CFCS_IOSPACE 0x00000001 /* I/O space enable */ #define DC_CFCS_MEMSPACE 0x00000002 /* memory space enable */ #define DC_CFCS_BUSMASTER 0x00000004 /* bus master enable */ #define DC_CFCS_MWI_ENB 0x00000010 /* mem write and inval enable */ #define DC_CFCS_PARITYERR_ENB 0x00000040 /* parity error enable */ #define DC_CFCS_SYSERR_ENB 0x00000100 /* system error enable */ #define DC_CFCS_NEWCAPS 0x00100000 /* new capabilities */ #define DC_CFCS_FAST_B2B 0x00800000 /* fast back-to-back capable */ #define DC_CFCS_DATAPARITY 0x01000000 /* Parity error report */ #define DC_CFCS_DEVSELTIM 0x06000000 /* devsel timing */ #define DC_CFCS_TGTABRT 0x10000000 /* received target abort */ #define DC_CFCS_MASTERABRT 0x20000000 /* received master abort */ #define DC_CFCS_SYSERR 0x40000000 /* asserted system error */ #define DC_CFCS_PARITYERR 0x80000000 /* asserted parity error */ /* PCI revision register */ #define DC_CFRV_STEPPING 0x0000000F #define DC_CFRV_REVISION 0x000000F0 #define DC_CFRV_SUBCLASS 0x00FF0000 #define DC_CFRV_BASECLASS 0xFF000000 #define DC_21143_PB_REV 0x00000030 #define DC_21143_TB_REV 0x00000030 #define DC_21143_PC_REV 0x00000030 #define DC_21143_TC_REV 0x00000030 #define DC_21143_PD_REV 0x00000041 #define DC_21143_TD_REV 0x00000041 /* PCI latency timer register */ #define DC_CFLT_CACHELINESIZE 0x000000FF #define DC_CFLT_LATENCYTIMER 0x0000FF00 /* PCI subsystem ID register */ #define DC_CSID_VENDOR 0x0000FFFF #define DC_CSID_DEVICE 0xFFFF0000 /* PCI cababilities pointer */ #define DC_CCAP_OFFSET 0x000000FF /* PCI interrupt config register */ #define DC_CFIT_INTLINE 0x000000FF #define DC_CFIT_INTPIN 0x0000FF00 #define DC_CFIT_MIN_GNT 0x00FF0000 #define DC_CFIT_MAX_LAT 0xFF000000 /* PCI capability register */ #define DC_CCID_CAPID 0x000000FF #define DC_CCID_NEXTPTR 0x0000FF00 #define DC_CCID_PM_VERS 0x00070000 #define DC_CCID_PME_CLK 0x00080000 #define DC_CCID_DVSPEC_INT 0x00200000 #define DC_CCID_STATE_D1 0x02000000 #define DC_CCID_STATE_D2 0x04000000 #define DC_CCID_PME_D0 0x08000000 #define DC_CCID_PME_D1 0x10000000 #define DC_CCID_PME_D2 0x20000000 #define DC_CCID_PME_D3HOT 0x40000000 #define DC_CCID_PME_D3COLD 0x80000000 /* PCI power management control/status register */ #define DC_CPMC_STATE 0x00000003 #define DC_CPMC_PME_ENB 0x00000100 #define DC_CPMC_PME_STS 0x00008000 #define DC_PSTATE_D0 0x0 #define DC_PSTATE_D1 0x1 #define DC_PSTATE_D2 0x2 #define DC_PSTATE_D3 0x3 /* Device specific region */ /* Configuration and driver area */ #define DC_CFDD_DRVUSE 0x0000FFFF #define DC_CFDD_SNOOZE_MODE 0x40000000 #define DC_CFDD_SLEEP_MODE 0x80000000 /* Configuration wake-up command register */ #define DC_CWUC_MUST_BE_ZERO 0x00000001 #define DC_CWUC_SECUREON_ENB 0x00000002 #define DC_CWUC_FORCE_WUL 0x00000004 #define DC_CWUC_BNC_ABILITY 0x00000008 #define DC_CWUC_AUI_ABILITY 0x00000010 #define DC_CWUC_TP10_ABILITY 0x00000020 #define DC_CWUC_MII_ABILITY 0x00000040 #define DC_CWUC_SYM_ABILITY 0x00000080 #define DC_CWUC_LOCK 0x00000100 /* * SROM nonsense. */ #define DC_IB_CTLRCNT 0x13 #define DC_IB_LEAF0_CNUM 0x1A #define DC_IB_LEAF0_OFFSET 0x1B struct dc_info_leaf { u_int16_t dc_conntype; u_int8_t dc_blkcnt; u_int8_t dc_rsvd; u_int16_t dc_infoblk; }; #define DC_CTYPE_10BT 0x0000 #define DC_CTYPE_10BT_NWAY 0x0100 #define DC_CTYPE_10BT_FDX 0x0204 #define DC_CTYPE_10B2 0x0001 #define DC_CTYPE_10B5 0x0002 #define DC_CTYPE_100BT 0x0003 #define DC_CTYPE_100BT_FDX 0x0205 #define DC_CTYPE_100T4 0x0006 #define DC_CTYPE_100FX 0x0007 #define DC_CTYPE_100FX_FDX 0x0208 #define DC_CTYPE_MII_10BT 0x0009 #define DC_CTYPE_MII_10BT_FDX 0x020A #define DC_CTYPE_MII_100BT 0x000D #define DC_CTYPE_MII_100BT_FDX 0x020E #define DC_CTYPE_MII_100T4 0x000F #define DC_CTYPE_MII_100FX 0x0010 #define DC_CTYPE_MII_100FX_FDX 0x0211 #define DC_CTYPE_DYN_PUP_AUTOSENSE 0x0800 #define DC_CTYPE_PUP_AUTOSENSE 0x8800 #define DC_CTYPE_NOMEDIA 0xFFFF #define DC_EBLOCK_SIA 0x0002 #define DC_EBLOCK_MII 0x0003 #define DC_EBLOCK_SYM 0x0004 #define DC_EBLOCK_RESET 0x0005 #define DC_EBLOCK_PHY_SHUTDOWN 0x0006 struct dc_leaf_hdr { u_int16_t dc_mtype; u_int8_t dc_mcnt; u_int8_t dc_rsvd; }; struct dc_eblock_hdr { u_int8_t dc_len; u_int8_t dc_type; }; struct dc_eblock_sia { struct dc_eblock_hdr dc_sia_hdr; u_int8_t dc_sia_code; union { struct dc_sia_ext { /* if (dc_sia_code & DC_SIA_CODE_EXT) */ u_int8_t dc_sia_mediaspec[6]; /* CSR13, CSR14, CSR15 */ u_int8_t dc_sia_gpio_ctl[2]; u_int8_t dc_sia_gpio_dat[2]; } dc_sia_ext; struct dc_sia_noext { u_int8_t dc_sia_gpio_ctl[2]; u_int8_t dc_sia_gpio_dat[2]; } dc_sia_noext; } dc_un; }; #define DC_SIA_CODE_10BT 0x00 #define DC_SIA_CODE_10B2 0x01 #define DC_SIA_CODE_10B5 0x02 #define DC_SIA_CODE_10BT_FDX 0x04 #define DC_SIA_CODE_EXT 0x40 /* * Note that the first word in the gpr and reset * sequences is always a control word. */ struct dc_eblock_mii { struct dc_eblock_hdr dc_mii_hdr; u_int8_t dc_mii_phynum; u_int8_t dc_gpr_len; /* u_int16_t dc_gpr_dat[n]; */ /* u_int8_t dc_reset_len; */ /* u_int16_t dc_reset_dat[n]; */ /* There are other fields after these, but we don't * care about them since they can be determined by looking * at the PHY. */ }; struct dc_eblock_sym { struct dc_eblock_hdr dc_sym_hdr; u_int8_t dc_sym_code; u_int8_t dc_sym_gpio_ctl[2]; u_int8_t dc_sym_gpio_dat[2]; u_int8_t dc_sym_cmd[2]; }; #define DC_SYM_CODE_100BT 0x03 #define DC_SYM_CODE_100BT_FDX 0x05 #define DC_SYM_CODE_100T4 0x06 #define DC_SYM_CODE_100FX 0x07 #define DC_SYM_CODE_100FX_FDX 0x08 struct dc_eblock_reset { struct dc_eblock_hdr dc_reset_hdr; u_int8_t dc_reset_len; /* u_int16_t dc_reset_dat[n]; */ }; Index: head/sys/pci/if_dc.c =================================================================== --- head/sys/pci/if_dc.c (revision 123165) +++ head/sys/pci/if_dc.c (revision 123166) @@ -1,3866 +1,3868 @@ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * DEC "tulip" clone ethernet driver. Supports the DEC/Intel 21143 * series chips and several workalikes including the following: * * Macronix 98713/98715/98725/98727/98732 PMAC (www.macronix.com) * Macronix/Lite-On 82c115 PNIC II (www.macronix.com) * Lite-On 82c168/82c169 PNIC (www.litecom.com) * ASIX Electronics AX88140A (www.asix.com.tw) * ASIX Electronics AX88141 (www.asix.com.tw) * ADMtek AL981 (www.admtek.com.tw) * ADMtek AN985 (www.admtek.com.tw) * Netgear FA511 (www.netgear.com) Appears to be rebadged ADMTek AN985 * Davicom DM9100, DM9102, DM9102A (www.davicom8.com) * Accton EN1217 (www.accton.com) * Xircom X3201 (www.xircom.com) * Abocom FE2500 * Conexant LANfinity (www.conexant.com) * 3Com OfficeConnect 10/100B 3CSOHO100B (www.3com.com) * * Datasheets for the 21143 are available at developer.intel.com. * Datasheets for the clone parts can be found at their respective sites. * (Except for the PNIC; see www.freebsd.org/~wpaul/PNIC/pnic.ps.gz.) * The PNIC II is essentially a Macronix 98715A chip; the only difference * worth noting is that its multicast hash table is only 128 bits wide * instead of 512. * * Written by Bill Paul * Electrical Engineering Department * Columbia University, New York City */ /* * The Intel 21143 is the successor to the DEC 21140. It is basically * the same as the 21140 but with a few new features. The 21143 supports * three kinds of media attachments: * * o MII port, for 10Mbps and 100Mbps support and NWAY * autonegotiation provided by an external PHY. * o SYM port, for symbol mode 100Mbps support. * o 10baseT port. * o AUI/BNC port. * * The 100Mbps SYM port and 10baseT port can be used together in * combination with the internal NWAY support to create a 10/100 * autosensing configuration. * * Note that not all tulip workalikes are handled in this driver: we only * deal with those which are relatively well behaved. The Winbond is * handled separately due to its different register offsets and the * special handling needed for its various bugs. The PNIC is handled * here, but I'm not thrilled about it. * * All of the workalike chips use some form of MII transceiver support * with the exception of the Macronix chips, which also have a SYM port. * The ASIX AX88140A is also documented to have a SYM port, but all * the cards I've seen use an MII transceiver, probably because the * AX88140A doesn't support internal NWAY. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DC_USEIOSPACE #ifdef __alpha__ #define SRM_MEDIA #endif #include MODULE_DEPEND(dc, pci, 1, 1, 1); MODULE_DEPEND(dc, ether, 1, 1, 1); MODULE_DEPEND(dc, miibus, 1, 1, 1); /* "controller miibus0" required. See GENERIC if you get errors here. */ #include "miibus_if.h" /* * Various supported device vendors/types and their names. */ static struct dc_type dc_devs[] = { { DC_VENDORID_DEC, DC_DEVICEID_21143, "Intel 21143 10/100BaseTX" }, { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9009, "Davicom DM9009 10/100BaseTX" }, { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9100, "Davicom DM9100 10/100BaseTX" }, { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102, "Davicom DM9102 10/100BaseTX" }, { DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102, "Davicom DM9102A 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_AL981, "ADMtek AL981 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_AN985, "ADMtek AN985 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_ADM9511, "ADMtek ADM9511 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_ADM9513, "ADMtek ADM9513 10/100BaseTX" }, { DC_VENDORID_ADMTEK, DC_DEVICEID_FA511, "Netgear FA511 10/100BaseTX" }, { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A, "ASIX AX88140A 10/100BaseTX" }, { DC_VENDORID_ASIX, DC_DEVICEID_AX88140A, "ASIX AX88141 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_98713, "Macronix 98713 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_98713, "Macronix 98713A 10/100BaseTX" }, { DC_VENDORID_CP, DC_DEVICEID_98713_CP, "Compex RL100-TX 10/100BaseTX" }, { DC_VENDORID_CP, DC_DEVICEID_98713_CP, "Compex RL100-TX 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_987x5, "Macronix 98715/98715A 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_987x5, "Macronix 98715AEC-C 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_987x5, "Macronix 98725 10/100BaseTX" }, { DC_VENDORID_MX, DC_DEVICEID_98727, "Macronix 98727/98732 10/100BaseTX" }, { DC_VENDORID_LO, DC_DEVICEID_82C115, "LC82C115 PNIC II 10/100BaseTX" }, { DC_VENDORID_LO, DC_DEVICEID_82C168, "82c168 PNIC 10/100BaseTX" }, { DC_VENDORID_LO, DC_DEVICEID_82C168, "82c169 PNIC 10/100BaseTX" }, { DC_VENDORID_ACCTON, DC_DEVICEID_EN1217, "Accton EN1217 10/100BaseTX" }, { DC_VENDORID_ACCTON, DC_DEVICEID_EN2242, "Accton EN2242 MiniPCI 10/100BaseTX" }, { DC_VENDORID_XIRCOM, DC_DEVICEID_X3201, "Xircom X3201 10/100BaseTX" }, { DC_VENDORID_ABOCOM, DC_DEVICEID_FE2500, "Abocom FE2500 10/100BaseTX" }, + { DC_VENDORID_ABOCOM, DC_DEVICEID_FE2500MX, + "Abocom FE2500MX 10/100BaseTX" }, { DC_VENDORID_CONEXANT, DC_DEVICEID_RS7112, "Conexant LANfinity MiniPCI 10/100BaseTX" }, { DC_VENDORID_HAWKING, DC_DEVICEID_HAWKING_PN672TX, "Hawking CB102 CardBus 10/100" }, { DC_VENDORID_PLANEX, DC_DEVICEID_FNW3602T, "PlaneX FNW-3602-T CardBus 10/100" }, { DC_VENDORID_3COM, DC_DEVICEID_3CSOHOB, "3Com OfficeConnect 10/100B" }, { DC_VENDORID_MICROSOFT, DC_DEVICEID_MSMN120, "Microsoft MN-120 CardBus 10/100" }, { DC_VENDORID_MICROSOFT, DC_DEVICEID_MSMN130, "Microsoft MN-130 10/100" }, { DC_VENDORID_MICROSOFT, DC_DEVICEID_MSMN130_FAKE, "Microsoft MN-130 10/100" }, { 0, 0, NULL } }; static int dc_probe (device_t); static int dc_attach (device_t); static int dc_detach (device_t); static int dc_suspend (device_t); static int dc_resume (device_t); #ifndef BURN_BRIDGES static void dc_acpi (device_t); #endif static struct dc_type *dc_devtype (device_t); static int dc_newbuf (struct dc_softc *, int, int); static int dc_encap (struct dc_softc *, struct mbuf **); static void dc_pnic_rx_bug_war (struct dc_softc *, int); static int dc_rx_resync (struct dc_softc *); static void dc_rxeof (struct dc_softc *); static void dc_txeof (struct dc_softc *); static void dc_tick (void *); static void dc_tx_underrun (struct dc_softc *); static void dc_intr (void *); static void dc_start (struct ifnet *); static int dc_ioctl (struct ifnet *, u_long, caddr_t); static void dc_init (void *); static void dc_stop (struct dc_softc *); static void dc_watchdog (struct ifnet *); static void dc_shutdown (device_t); static int dc_ifmedia_upd (struct ifnet *); static void dc_ifmedia_sts (struct ifnet *, struct ifmediareq *); static void dc_delay (struct dc_softc *); static void dc_eeprom_idle (struct dc_softc *); static void dc_eeprom_putbyte (struct dc_softc *, int); static void dc_eeprom_getword (struct dc_softc *, int, u_int16_t *); static void dc_eeprom_getword_pnic (struct dc_softc *, int, u_int16_t *); static void dc_eeprom_getword_xircom (struct dc_softc *, int, u_int16_t *); static void dc_eeprom_width (struct dc_softc *); static void dc_read_eeprom (struct dc_softc *, caddr_t, int, int, int); static void dc_mii_writebit (struct dc_softc *, int); static int dc_mii_readbit (struct dc_softc *); static void dc_mii_sync (struct dc_softc *); static void dc_mii_send (struct dc_softc *, u_int32_t, int); static int dc_mii_readreg (struct dc_softc *, struct dc_mii_frame *); static int dc_mii_writereg (struct dc_softc *, struct dc_mii_frame *); static int dc_miibus_readreg (device_t, int, int); static int dc_miibus_writereg (device_t, int, int, int); static void dc_miibus_statchg (device_t); static void dc_miibus_mediainit (device_t); static void dc_setcfg (struct dc_softc *, int); static uint32_t dc_mchash_le (struct dc_softc *, const uint8_t *); static uint32_t dc_mchash_be (const uint8_t *); static void dc_setfilt_21143 (struct dc_softc *); static void dc_setfilt_asix (struct dc_softc *); static void dc_setfilt_admtek (struct dc_softc *); static void dc_setfilt_xircom (struct dc_softc *); static void dc_setfilt (struct dc_softc *); static void dc_reset (struct dc_softc *); static int dc_list_rx_init (struct dc_softc *); static int dc_list_tx_init (struct dc_softc *); static void dc_read_srom (struct dc_softc *, int); static void dc_parse_21143_srom (struct dc_softc *); static void dc_decode_leaf_sia (struct dc_softc *, struct dc_eblock_sia *); static void dc_decode_leaf_mii (struct dc_softc *, struct dc_eblock_mii *); static void dc_decode_leaf_sym (struct dc_softc *, struct dc_eblock_sym *); static void dc_apply_fixup (struct dc_softc *, int); static void dc_dma_map_txbuf (void *, bus_dma_segment_t *, int, bus_size_t, int); static void dc_dma_map_rxbuf (void *, bus_dma_segment_t *, int, bus_size_t, int); #ifdef DC_USEIOSPACE #define DC_RES SYS_RES_IOPORT #define DC_RID DC_PCI_CFBIO #else #define DC_RES SYS_RES_MEMORY #define DC_RID DC_PCI_CFBMA #endif static device_method_t dc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, dc_probe), DEVMETHOD(device_attach, dc_attach), DEVMETHOD(device_detach, dc_detach), DEVMETHOD(device_suspend, dc_suspend), DEVMETHOD(device_resume, dc_resume), DEVMETHOD(device_shutdown, dc_shutdown), /* bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), /* MII interface */ DEVMETHOD(miibus_readreg, dc_miibus_readreg), DEVMETHOD(miibus_writereg, dc_miibus_writereg), DEVMETHOD(miibus_statchg, dc_miibus_statchg), DEVMETHOD(miibus_mediainit, dc_miibus_mediainit), { 0, 0 } }; static driver_t dc_driver = { "dc", dc_methods, sizeof(struct dc_softc) }; static devclass_t dc_devclass; #ifdef __i386__ static int dc_quick = 1; SYSCTL_INT(_hw, OID_AUTO, dc_quick, CTLFLAG_RW, &dc_quick, 0, "do not m_devget() in dc driver"); #endif DRIVER_MODULE(dc, cardbus, dc_driver, dc_devclass, 0, 0); DRIVER_MODULE(dc, pci, dc_driver, dc_devclass, 0, 0); DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0); #define DC_SETBIT(sc, reg, x) \ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x)) #define DC_CLRBIT(sc, reg, x) \ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x)) #define SIO_SET(x) DC_SETBIT(sc, DC_SIO, (x)) #define SIO_CLR(x) DC_CLRBIT(sc, DC_SIO, (x)) #define IS_MPSAFE 0 static void dc_delay(struct dc_softc *sc) { int idx; for (idx = (300 / 33) + 1; idx > 0; idx--) CSR_READ_4(sc, DC_BUSCTL); } static void dc_eeprom_width(struct dc_softc *sc) { int i; /* Force EEPROM to idle state. */ dc_eeprom_idle(sc); /* Enter EEPROM access mode. */ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); for (i = 3; i--;) { if (6 & (1 << i)) DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); else DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); } for (i = 1; i <= 12; i++) { DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); if (!(CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT)) { DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); break; } DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); } /* Turn off EEPROM access mode. */ dc_eeprom_idle(sc); if (i < 4 || i > 12) sc->dc_romwidth = 6; else sc->dc_romwidth = i; /* Enter EEPROM access mode. */ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); /* Turn off EEPROM access mode. */ dc_eeprom_idle(sc); } static void dc_eeprom_idle(struct dc_softc *sc) { int i; CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); for (i = 0; i < 25; i++) { DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); } DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); CSR_WRITE_4(sc, DC_SIO, 0x00000000); } /* * Send a read command and address to the EEPROM, check for ACK. */ static void dc_eeprom_putbyte(struct dc_softc *sc, int addr) { int d, i; d = DC_EECMD_READ >> 6; for (i = 3; i--; ) { if (d & (1 << i)) DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); else DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); } /* * Feed in each bit and strobe the clock. */ for (i = sc->dc_romwidth; i--;) { if (addr & (1 << i)) { SIO_SET(DC_SIO_EE_DATAIN); } else { SIO_CLR(DC_SIO_EE_DATAIN); } dc_delay(sc); SIO_SET(DC_SIO_EE_CLK); dc_delay(sc); SIO_CLR(DC_SIO_EE_CLK); dc_delay(sc); } } /* * Read a word of data stored in the EEPROM at address 'addr.' * The PNIC 82c168/82c169 has its own non-standard way to read * the EEPROM. */ static void dc_eeprom_getword_pnic(struct dc_softc *sc, int addr, u_int16_t *dest) { int i; u_int32_t r; CSR_WRITE_4(sc, DC_PN_SIOCTL, DC_PN_EEOPCODE_READ | addr); for (i = 0; i < DC_TIMEOUT; i++) { DELAY(1); r = CSR_READ_4(sc, DC_SIO); if (!(r & DC_PN_SIOCTL_BUSY)) { *dest = (u_int16_t)(r & 0xFFFF); return; } } } /* * Read a word of data stored in the EEPROM at address 'addr.' * The Xircom X3201 has its own non-standard way to read * the EEPROM, too. */ static void dc_eeprom_getword_xircom(struct dc_softc *sc, int addr, u_int16_t *dest) { SIO_SET(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ); addr *= 2; CSR_WRITE_4(sc, DC_ROM, addr | 0x160); *dest = (u_int16_t)CSR_READ_4(sc, DC_SIO) & 0xff; addr += 1; CSR_WRITE_4(sc, DC_ROM, addr | 0x160); *dest |= ((u_int16_t)CSR_READ_4(sc, DC_SIO) & 0xff) << 8; SIO_CLR(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ); } /* * Read a word of data stored in the EEPROM at address 'addr.' */ static void dc_eeprom_getword(struct dc_softc *sc, int addr, u_int16_t *dest) { int i; u_int16_t word = 0; /* Force EEPROM to idle state. */ dc_eeprom_idle(sc); /* Enter EEPROM access mode. */ CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); dc_delay(sc); DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); dc_delay(sc); DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); dc_delay(sc); /* * Send address of word we want to read. */ dc_eeprom_putbyte(sc, addr); /* * Start reading bits from EEPROM. */ for (i = 0x8000; i; i >>= 1) { SIO_SET(DC_SIO_EE_CLK); dc_delay(sc); if (CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT) word |= i; dc_delay(sc); SIO_CLR(DC_SIO_EE_CLK); dc_delay(sc); } /* Turn off EEPROM access mode. */ dc_eeprom_idle(sc); *dest = word; } /* * Read a sequence of words from the EEPROM. */ static void dc_read_eeprom(struct dc_softc *sc, caddr_t dest, int off, int cnt, int swap) { int i; u_int16_t word = 0, *ptr; for (i = 0; i < cnt; i++) { if (DC_IS_PNIC(sc)) dc_eeprom_getword_pnic(sc, off + i, &word); else if (DC_IS_XIRCOM(sc)) dc_eeprom_getword_xircom(sc, off + i, &word); else dc_eeprom_getword(sc, off + i, &word); ptr = (u_int16_t *)(dest + (i * 2)); if (swap) *ptr = ntohs(word); else *ptr = word; } } /* * The following two routines are taken from the Macronix 98713 * Application Notes pp.19-21. */ /* * Write a bit to the MII bus. */ static void dc_mii_writebit(struct dc_softc *sc, int bit) { if (bit) CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE | DC_SIO_MII_DATAOUT); else CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE); DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK); DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK); } /* * Read a bit from the MII bus. */ static int dc_mii_readbit(struct dc_softc *sc) { CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_READ | DC_SIO_MII_DIR); CSR_READ_4(sc, DC_SIO); DC_SETBIT(sc, DC_SIO, DC_SIO_MII_CLK); DC_CLRBIT(sc, DC_SIO, DC_SIO_MII_CLK); if (CSR_READ_4(sc, DC_SIO) & DC_SIO_MII_DATAIN) return (1); return (0); } /* * Sync the PHYs by setting data bit and strobing the clock 32 times. */ static void dc_mii_sync(struct dc_softc *sc) { int i; CSR_WRITE_4(sc, DC_SIO, DC_SIO_ROMCTL_WRITE); for (i = 0; i < 32; i++) dc_mii_writebit(sc, 1); } /* * Clock a series of bits through the MII. */ static void dc_mii_send(struct dc_softc *sc, u_int32_t bits, int cnt) { int i; for (i = (0x1 << (cnt - 1)); i; i >>= 1) dc_mii_writebit(sc, bits & i); } /* * Read an PHY register through the MII. */ static int dc_mii_readreg(struct dc_softc *sc, struct dc_mii_frame *frame) { int i, ack; DC_LOCK(sc); /* * Set up frame for RX. */ frame->mii_stdelim = DC_MII_STARTDELIM; frame->mii_opcode = DC_MII_READOP; frame->mii_turnaround = 0; frame->mii_data = 0; /* * Sync the PHYs. */ dc_mii_sync(sc); /* * Send command/address info. */ dc_mii_send(sc, frame->mii_stdelim, 2); dc_mii_send(sc, frame->mii_opcode, 2); dc_mii_send(sc, frame->mii_phyaddr, 5); dc_mii_send(sc, frame->mii_regaddr, 5); #ifdef notdef /* Idle bit */ dc_mii_writebit(sc, 1); dc_mii_writebit(sc, 0); #endif /* Check for ack. */ ack = dc_mii_readbit(sc); /* * Now try reading data bits. If the ack failed, we still * need to clock through 16 cycles to keep the PHY(s) in sync. */ if (ack) { for (i = 0; i < 16; i++) dc_mii_readbit(sc); goto fail; } for (i = 0x8000; i; i >>= 1) { if (!ack) { if (dc_mii_readbit(sc)) frame->mii_data |= i; } } fail: dc_mii_writebit(sc, 0); dc_mii_writebit(sc, 0); DC_UNLOCK(sc); if (ack) return (1); return (0); } /* * Write to a PHY register through the MII. */ static int dc_mii_writereg(struct dc_softc *sc, struct dc_mii_frame *frame) { DC_LOCK(sc); /* * Set up frame for TX. */ frame->mii_stdelim = DC_MII_STARTDELIM; frame->mii_opcode = DC_MII_WRITEOP; frame->mii_turnaround = DC_MII_TURNAROUND; /* * Sync the PHYs. */ dc_mii_sync(sc); dc_mii_send(sc, frame->mii_stdelim, 2); dc_mii_send(sc, frame->mii_opcode, 2); dc_mii_send(sc, frame->mii_phyaddr, 5); dc_mii_send(sc, frame->mii_regaddr, 5); dc_mii_send(sc, frame->mii_turnaround, 2); dc_mii_send(sc, frame->mii_data, 16); /* Idle bit. */ dc_mii_writebit(sc, 0); dc_mii_writebit(sc, 0); DC_UNLOCK(sc); return (0); } static int dc_miibus_readreg(device_t dev, int phy, int reg) { struct dc_mii_frame frame; struct dc_softc *sc; int i, rval, phy_reg = 0; sc = device_get_softc(dev); bzero(&frame, sizeof(frame)); /* * Note: both the AL981 and AN985 have internal PHYs, * however the AL981 provides direct access to the PHY * registers while the AN985 uses a serial MII interface. * The AN985's MII interface is also buggy in that you * can read from any MII address (0 to 31), but only address 1 * behaves normally. To deal with both cases, we pretend * that the PHY is at MII address 1. */ if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR) return (0); /* * Note: the ukphy probes of the RS7112 report a PHY at * MII address 0 (possibly HomePNA?) and 1 (ethernet) * so we only respond to correct one. */ if (DC_IS_CONEXANT(sc) && phy != DC_CONEXANT_PHYADDR) return (0); if (sc->dc_pmode != DC_PMODE_MII) { if (phy == (MII_NPHY - 1)) { switch (reg) { case MII_BMSR: /* * Fake something to make the probe * code think there's a PHY here. */ return (BMSR_MEDIAMASK); break; case MII_PHYIDR1: if (DC_IS_PNIC(sc)) return (DC_VENDORID_LO); return (DC_VENDORID_DEC); break; case MII_PHYIDR2: if (DC_IS_PNIC(sc)) return (DC_DEVICEID_82C168); return (DC_DEVICEID_21143); break; default: return (0); break; } } else return (0); } if (DC_IS_PNIC(sc)) { CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_READ | (phy << 23) | (reg << 18)); for (i = 0; i < DC_TIMEOUT; i++) { DELAY(1); rval = CSR_READ_4(sc, DC_PN_MII); if (!(rval & DC_PN_MII_BUSY)) { rval &= 0xFFFF; return (rval == 0xFFFF ? 0 : rval); } } return (0); } if (DC_IS_COMET(sc)) { switch (reg) { case MII_BMCR: phy_reg = DC_AL_BMCR; break; case MII_BMSR: phy_reg = DC_AL_BMSR; break; case MII_PHYIDR1: phy_reg = DC_AL_VENID; break; case MII_PHYIDR2: phy_reg = DC_AL_DEVID; break; case MII_ANAR: phy_reg = DC_AL_ANAR; break; case MII_ANLPAR: phy_reg = DC_AL_LPAR; break; case MII_ANER: phy_reg = DC_AL_ANER; break; default: printf("dc%d: phy_read: bad phy register %x\n", sc->dc_unit, reg); return (0); break; } rval = CSR_READ_4(sc, phy_reg) & 0x0000FFFF; if (rval == 0xFFFF) return (0); return (rval); } frame.mii_phyaddr = phy; frame.mii_regaddr = reg; if (sc->dc_type == DC_TYPE_98713) { phy_reg = CSR_READ_4(sc, DC_NETCFG); CSR_WRITE_4(sc, DC_NETCFG, phy_reg & ~DC_NETCFG_PORTSEL); } dc_mii_readreg(sc, &frame); if (sc->dc_type == DC_TYPE_98713) CSR_WRITE_4(sc, DC_NETCFG, phy_reg); return (frame.mii_data); } static int dc_miibus_writereg(device_t dev, int phy, int reg, int data) { struct dc_softc *sc; struct dc_mii_frame frame; int i, phy_reg = 0; sc = device_get_softc(dev); bzero(&frame, sizeof(frame)); if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR) return (0); if (DC_IS_CONEXANT(sc) && phy != DC_CONEXANT_PHYADDR) return (0); if (DC_IS_PNIC(sc)) { CSR_WRITE_4(sc, DC_PN_MII, DC_PN_MIIOPCODE_WRITE | (phy << 23) | (reg << 10) | data); for (i = 0; i < DC_TIMEOUT; i++) { if (!(CSR_READ_4(sc, DC_PN_MII) & DC_PN_MII_BUSY)) break; } return (0); } if (DC_IS_COMET(sc)) { switch (reg) { case MII_BMCR: phy_reg = DC_AL_BMCR; break; case MII_BMSR: phy_reg = DC_AL_BMSR; break; case MII_PHYIDR1: phy_reg = DC_AL_VENID; break; case MII_PHYIDR2: phy_reg = DC_AL_DEVID; break; case MII_ANAR: phy_reg = DC_AL_ANAR; break; case MII_ANLPAR: phy_reg = DC_AL_LPAR; break; case MII_ANER: phy_reg = DC_AL_ANER; break; default: printf("dc%d: phy_write: bad phy register %x\n", sc->dc_unit, reg); return (0); break; } CSR_WRITE_4(sc, phy_reg, data); return (0); } frame.mii_phyaddr = phy; frame.mii_regaddr = reg; frame.mii_data = data; if (sc->dc_type == DC_TYPE_98713) { phy_reg = CSR_READ_4(sc, DC_NETCFG); CSR_WRITE_4(sc, DC_NETCFG, phy_reg & ~DC_NETCFG_PORTSEL); } dc_mii_writereg(sc, &frame); if (sc->dc_type == DC_TYPE_98713) CSR_WRITE_4(sc, DC_NETCFG, phy_reg); return (0); } static void dc_miibus_statchg(device_t dev) { struct dc_softc *sc; struct mii_data *mii; struct ifmedia *ifm; sc = device_get_softc(dev); if (DC_IS_ADMTEK(sc)) return; mii = device_get_softc(sc->dc_miibus); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc) && IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) { dc_setcfg(sc, ifm->ifm_media); sc->dc_if_media = ifm->ifm_media; } else { dc_setcfg(sc, mii->mii_media_active); sc->dc_if_media = mii->mii_media_active; } } /* * Special support for DM9102A cards with HomePNA PHYs. Note: * with the Davicom DM9102A/DM9801 eval board that I have, it seems * to be impossible to talk to the management interface of the DM9801 * PHY (its MDIO pin is not connected to anything). Consequently, * the driver has to just 'know' about the additional mode and deal * with it itself. *sigh* */ static void dc_miibus_mediainit(device_t dev) { struct dc_softc *sc; struct mii_data *mii; struct ifmedia *ifm; int rev; rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF; sc = device_get_softc(dev); mii = device_get_softc(sc->dc_miibus); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc) && rev >= DC_REVISION_DM9102A) ifmedia_add(ifm, IFM_ETHER | IFM_HPNA_1, 0, NULL); } #define DC_POLY 0xEDB88320 #define DC_BITS_512 9 #define DC_BITS_128 7 #define DC_BITS_64 6 static uint32_t dc_mchash_le(struct dc_softc *sc, const uint8_t *addr) { uint32_t crc; int idx, bit; uint8_t data; /* Compute CRC for the address value. */ crc = 0xFFFFFFFF; /* initial value */ for (idx = 0; idx < 6; idx++) { for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) crc = (crc >> 1) ^ (((crc ^ data) & 1) ? DC_POLY : 0); } /* * The hash table on the PNIC II and the MX98715AEC-C/D/E * chips is only 128 bits wide. */ if (sc->dc_flags & DC_128BIT_HASH) return (crc & ((1 << DC_BITS_128) - 1)); /* The hash table on the MX98715BEC is only 64 bits wide. */ if (sc->dc_flags & DC_64BIT_HASH) return (crc & ((1 << DC_BITS_64) - 1)); /* Xircom's hash filtering table is different (read: weird) */ /* Xircom uses the LEAST significant bits */ if (DC_IS_XIRCOM(sc)) { if ((crc & 0x180) == 0x180) return ((crc & 0x0F) + (crc & 0x70) * 3 + (14 << 4)); else return ((crc & 0x1F) + ((crc >> 1) & 0xF0) * 3 + (12 << 4)); } return (crc & ((1 << DC_BITS_512) - 1)); } /* * Calculate CRC of a multicast group address, return the lower 6 bits. */ static uint32_t dc_mchash_be(const uint8_t *addr) { uint32_t crc, carry; int idx, bit; uint8_t data; /* Compute CRC for the address value. */ crc = 0xFFFFFFFF; /* initial value */ for (idx = 0; idx < 6; idx++) { for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) { carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01); data >>= 1; crc <<= 1; if (carry) crc = (crc ^ 0x04c11db6) | carry; } } /* Return the filter bit position. */ return ((crc >> 26) & 0x0000003F); } /* * 21143-style RX filter setup routine. Filter programming is done by * downloading a special setup frame into the TX engine. 21143, Macronix, * PNIC, PNIC II and Davicom chips are programmed this way. * * We always program the chip using 'hash perfect' mode, i.e. one perfect * address (our node address) and a 512-bit hash filter for multicast * frames. We also sneak the broadcast address into the hash filter since * we need that too. */ static void dc_setfilt_21143(struct dc_softc *sc) { struct dc_desc *sframe; u_int32_t h, *sp; struct ifmultiaddr *ifma; struct ifnet *ifp; int i; ifp = &sc->arpcom.ac_if; i = sc->dc_cdata.dc_tx_prod; DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT); sc->dc_cdata.dc_tx_cnt++; sframe = &sc->dc_ldata->dc_tx_list[i]; sp = sc->dc_cdata.dc_sbuf; bzero(sp, DC_SFRAME_LEN); sframe->dc_data = htole32(sc->dc_saddr); sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK | DC_FILTER_HASHPERF | DC_TXCTL_FINT); sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)sc->dc_cdata.dc_sbuf; /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); if (ifp->if_flags & IFF_ALLMULTI) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); sp[h >> 4] |= htole32(1 << (h & 0xF)); } if (ifp->if_flags & IFF_BROADCAST) { h = dc_mchash_le(sc, ifp->if_broadcastaddr); sp[h >> 4] |= htole32(1 << (h & 0xF)); } /* Set our MAC address */ sp[39] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[0]); sp[40] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[1]); sp[41] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[2]); sframe->dc_status = htole32(DC_TXSTAT_OWN); CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); /* * The PNIC takes an exceedingly long time to process its * setup frame; wait 10ms after posting the setup frame * before proceeding, just so it has time to swallow its * medicine. */ DELAY(10000); ifp->if_timer = 5; } static void dc_setfilt_admtek(struct dc_softc *sc) { struct ifnet *ifp; struct ifmultiaddr *ifma; int h = 0; u_int32_t hashes[2] = { 0, 0 }; ifp = &sc->arpcom.ac_if; /* Init our MAC address. */ CSR_WRITE_4(sc, DC_AL_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0])); CSR_WRITE_4(sc, DC_AL_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4])); /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); if (ifp->if_flags & IFF_ALLMULTI) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); /* First, zot all the existing hash bits. */ CSR_WRITE_4(sc, DC_AL_MAR0, 0); CSR_WRITE_4(sc, DC_AL_MAR1, 0); /* * If we're already in promisc or allmulti mode, we * don't have to bother programming the multicast filter. */ if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) return; /* Now program new ones. */ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; if (DC_IS_CENTAUR(sc)) h = dc_mchash_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); else h = dc_mchash_be( LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); } CSR_WRITE_4(sc, DC_AL_MAR0, hashes[0]); CSR_WRITE_4(sc, DC_AL_MAR1, hashes[1]); } static void dc_setfilt_asix(struct dc_softc *sc) { struct ifnet *ifp; struct ifmultiaddr *ifma; int h = 0; u_int32_t hashes[2] = { 0, 0 }; ifp = &sc->arpcom.ac_if; /* Init our MAC address */ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR0); CSR_WRITE_4(sc, DC_AX_FILTDATA, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0])); CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR1); CSR_WRITE_4(sc, DC_AX_FILTDATA, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4])); /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); if (ifp->if_flags & IFF_ALLMULTI) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); /* * The ASIX chip has a special bit to enable reception * of broadcast frames. */ if (ifp->if_flags & IFF_BROADCAST) DC_SETBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD); else DC_CLRBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD); /* first, zot all the existing hash bits */ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0); CSR_WRITE_4(sc, DC_AX_FILTDATA, 0); CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1); CSR_WRITE_4(sc, DC_AX_FILTDATA, 0); /* * If we're already in promisc or allmulti mode, we * don't have to bother programming the multicast filter. */ if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) return; /* now program new ones */ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); if (h < 32) hashes[0] |= (1 << h); else hashes[1] |= (1 << (h - 32)); } CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0); CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[0]); CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1); CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[1]); } static void dc_setfilt_xircom(struct dc_softc *sc) { struct ifnet *ifp; struct ifmultiaddr *ifma; struct dc_desc *sframe; u_int32_t h, *sp; int i; ifp = &sc->arpcom.ac_if; DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON)); i = sc->dc_cdata.dc_tx_prod; DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT); sc->dc_cdata.dc_tx_cnt++; sframe = &sc->dc_ldata->dc_tx_list[i]; sp = sc->dc_cdata.dc_sbuf; bzero(sp, DC_SFRAME_LEN); sframe->dc_data = htole32(sc->dc_saddr); sframe->dc_ctl = htole32(DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK | DC_FILTER_HASHPERF | DC_TXCTL_FINT); sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)sc->dc_cdata.dc_sbuf; /* If we want promiscuous mode, set the allframes bit. */ if (ifp->if_flags & IFF_PROMISC) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); if (ifp->if_flags & IFF_ALLMULTI) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; h = dc_mchash_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); sp[h >> 4] |= htole32(1 << (h & 0xF)); } if (ifp->if_flags & IFF_BROADCAST) { h = dc_mchash_le(sc, ifp->if_broadcastaddr); sp[h >> 4] |= htole32(1 << (h & 0xF)); } /* Set our MAC address */ sp[0] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[0]); sp[1] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[1]); sp[2] = DC_SP_MAC(((u_int16_t *)sc->arpcom.ac_enaddr)[2]); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON); ifp->if_flags |= IFF_RUNNING; sframe->dc_status = htole32(DC_TXSTAT_OWN); CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); /* * Wait some time... */ DELAY(1000); ifp->if_timer = 5; } static void dc_setfilt(struct dc_softc *sc) { if (DC_IS_INTEL(sc) || DC_IS_MACRONIX(sc) || DC_IS_PNIC(sc) || DC_IS_PNICII(sc) || DC_IS_DAVICOM(sc) || DC_IS_CONEXANT(sc)) dc_setfilt_21143(sc); if (DC_IS_ASIX(sc)) dc_setfilt_asix(sc); if (DC_IS_ADMTEK(sc)) dc_setfilt_admtek(sc); if (DC_IS_XIRCOM(sc)) dc_setfilt_xircom(sc); } /* * In order to fiddle with the 'full-duplex' and '100Mbps' bits in * the netconfig register, we first have to put the transmit and/or * receive logic in the idle state. */ static void dc_setcfg(struct dc_softc *sc, int media) { int i, restart = 0, watchdogreg; u_int32_t isr; if (IFM_SUBTYPE(media) == IFM_NONE) return; if (CSR_READ_4(sc, DC_NETCFG) & (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON)) { restart = 1; DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON)); for (i = 0; i < DC_TIMEOUT; i++) { isr = CSR_READ_4(sc, DC_ISR); if (isr & DC_ISR_TX_IDLE && ((isr & DC_ISR_RX_STATE) == DC_RXSTATE_STOPPED || (isr & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT)) break; DELAY(10); } if (i == DC_TIMEOUT) printf("dc%d: failed to force tx and " "rx to idle state\n", sc->dc_unit); } if (IFM_SUBTYPE(media) == IFM_100_TX) { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT); if (sc->dc_pmode == DC_PMODE_MII) { if (DC_IS_INTEL(sc)) { /* There's a write enable bit here that reads as 1. */ watchdogreg = CSR_READ_4(sc, DC_WATCHDOG); watchdogreg &= ~DC_WDOG_CTLWREN; watchdogreg |= DC_WDOG_JABBERDIS; CSR_WRITE_4(sc, DC_WATCHDOG, watchdogreg); } else { DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS); } DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS | DC_NETCFG_PORTSEL | DC_NETCFG_SCRAMBLER)); if (sc->dc_type == DC_TYPE_98713) DC_SETBIT(sc, DC_NETCFG, (DC_NETCFG_PCS | DC_NETCFG_SCRAMBLER)); if (!DC_IS_DAVICOM(sc)) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); if (DC_IS_INTEL(sc)) dc_apply_fixup(sc, IFM_AUTO); } else { if (DC_IS_PNIC(sc)) { DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_SPEEDSEL); DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP); DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL); } DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER); if (DC_IS_INTEL(sc)) dc_apply_fixup(sc, (media & IFM_GMASK) == IFM_FDX ? IFM_100_TX | IFM_FDX : IFM_100_TX); } } if (IFM_SUBTYPE(media) == IFM_10_T) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SPEEDSEL); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_HEARTBEAT); if (sc->dc_pmode == DC_PMODE_MII) { /* There's a write enable bit here that reads as 1. */ if (DC_IS_INTEL(sc)) { watchdogreg = CSR_READ_4(sc, DC_WATCHDOG); watchdogreg &= ~DC_WDOG_CTLWREN; watchdogreg |= DC_WDOG_JABBERDIS; CSR_WRITE_4(sc, DC_WATCHDOG, watchdogreg); } else { DC_SETBIT(sc, DC_WATCHDOG, DC_WDOG_JABBERDIS); } DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_PCS | DC_NETCFG_PORTSEL | DC_NETCFG_SCRAMBLER)); if (sc->dc_type == DC_TYPE_98713) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS); if (!DC_IS_DAVICOM(sc)) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); if (DC_IS_INTEL(sc)) dc_apply_fixup(sc, IFM_AUTO); } else { if (DC_IS_PNIC(sc)) { DC_PN_GPIO_CLRBIT(sc, DC_PN_GPIO_SPEEDSEL); DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_100TX_LOOP); DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_SPEEDSEL); } DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PCS); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER); if (DC_IS_INTEL(sc)) { DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); if ((media & IFM_GMASK) == IFM_FDX) DC_SETBIT(sc, DC_10BTCTRL, 0x7F3D); else DC_SETBIT(sc, DC_10BTCTRL, 0x7F3F); DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); DC_CLRBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); dc_apply_fixup(sc, (media & IFM_GMASK) == IFM_FDX ? IFM_10_T | IFM_FDX : IFM_10_T); DELAY(20000); } } } /* * If this is a Davicom DM9102A card with a DM9801 HomePNA * PHY and we want HomePNA mode, set the portsel bit to turn * on the external MII port. */ if (DC_IS_DAVICOM(sc)) { if (IFM_SUBTYPE(media) == IFM_HPNA_1) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); sc->dc_link = 1; } else { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); } } if ((media & IFM_GMASK) == IFM_FDX) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc)) DC_SETBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX); } else { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); if (sc->dc_pmode == DC_PMODE_SYM && DC_IS_PNIC(sc)) DC_CLRBIT(sc, DC_PN_NWAY, DC_PN_NWAY_DUPLEX); } if (restart) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON | DC_NETCFG_RX_ON); } static void dc_reset(struct dc_softc *sc) { int i; DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET); for (i = 0; i < DC_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_4(sc, DC_BUSCTL) & DC_BUSCTL_RESET)) break; } if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc) || DC_IS_CONEXANT(sc) || DC_IS_XIRCOM(sc) || DC_IS_INTEL(sc)) { DELAY(10000); DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET); i = 0; } if (i == DC_TIMEOUT) printf("dc%d: reset never completed!\n", sc->dc_unit); /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); CSR_WRITE_4(sc, DC_IMR, 0x00000000); CSR_WRITE_4(sc, DC_BUSCTL, 0x00000000); CSR_WRITE_4(sc, DC_NETCFG, 0x00000000); /* * Bring the SIA out of reset. In some cases, it looks * like failing to unreset the SIA soon enough gets it * into a state where it will never come out of reset * until we reset the whole chip again. */ if (DC_IS_INTEL(sc)) { DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); CSR_WRITE_4(sc, DC_10BTCTRL, 0); CSR_WRITE_4(sc, DC_WATCHDOG, 0); } } static struct dc_type * dc_devtype(device_t dev) { struct dc_type *t; u_int32_t rev; t = dc_devs; while (t->dc_name != NULL) { if ((pci_get_vendor(dev) == t->dc_vid) && (pci_get_device(dev) == t->dc_did)) { /* Check the PCI revision */ rev = pci_read_config(dev, DC_PCI_CFRV, 4) & 0xFF; if (t->dc_did == DC_DEVICEID_98713 && rev >= DC_REVISION_98713A) t++; if (t->dc_did == DC_DEVICEID_98713_CP && rev >= DC_REVISION_98713A) t++; if (t->dc_did == DC_DEVICEID_987x5 && rev >= DC_REVISION_98715AEC_C) t++; if (t->dc_did == DC_DEVICEID_987x5 && rev >= DC_REVISION_98725) t++; if (t->dc_did == DC_DEVICEID_AX88140A && rev >= DC_REVISION_88141) t++; if (t->dc_did == DC_DEVICEID_82C168 && rev >= DC_REVISION_82C169) t++; if (t->dc_did == DC_DEVICEID_DM9102 && rev >= DC_REVISION_DM9102A) t++; /* * The Microsoft MN-130 has a device ID of 0x0002, * which happens to be the same as the PNIC 82c168. * To keep dc_attach() from getting confused, we * pretend its ID is something different. * XXX: ideally, dc_attach() should be checking * vendorid+deviceid together to avoid such * collisions. */ if (t->dc_vid == DC_VENDORID_MICROSOFT && t->dc_did == DC_DEVICEID_MSMN130) t++; return (t); } t++; } return (NULL); } /* * Probe for a 21143 or clone chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. * We do a little bit of extra work to identify the exact type of * chip. The MX98713 and MX98713A have the same PCI vendor/device ID, * but different revision IDs. The same is true for 98715/98715A * chips and the 98725, as well as the ASIX and ADMtek chips. In some * cases, the exact chip revision affects driver behavior. */ static int dc_probe(device_t dev) { struct dc_type *t; t = dc_devtype(dev); if (t != NULL) { device_set_desc(dev, t->dc_name); return (0); } return (ENXIO); } #ifndef BURN_BRIDGES static void dc_acpi(device_t dev) { int unit; u_int32_t iobase, membase, irq; unit = device_get_unit(dev); if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { /* Save important PCI config data. */ iobase = pci_read_config(dev, DC_PCI_CFBIO, 4); membase = pci_read_config(dev, DC_PCI_CFBMA, 4); irq = pci_read_config(dev, DC_PCI_CFIT, 4); /* Reset the power state. */ printf("dc%d: chip is in D%d power mode " "-- setting to D0\n", unit, pci_get_powerstate(dev)); pci_set_powerstate(dev, PCI_POWERSTATE_D0); /* Restore PCI config data. */ pci_write_config(dev, DC_PCI_CFBIO, iobase, 4); pci_write_config(dev, DC_PCI_CFBMA, membase, 4); pci_write_config(dev, DC_PCI_CFIT, irq, 4); } } #endif static void dc_apply_fixup(struct dc_softc *sc, int media) { struct dc_mediainfo *m; u_int8_t *p; int i; u_int32_t reg; m = sc->dc_mi; while (m != NULL) { if (m->dc_media == media) break; m = m->dc_next; } if (m == NULL) return; for (i = 0, p = m->dc_reset_ptr; i < m->dc_reset_len; i++, p += 2) { reg = (p[0] | (p[1] << 8)) << 16; CSR_WRITE_4(sc, DC_WATCHDOG, reg); } for (i = 0, p = m->dc_gp_ptr; i < m->dc_gp_len; i++, p += 2) { reg = (p[0] | (p[1] << 8)) << 16; CSR_WRITE_4(sc, DC_WATCHDOG, reg); } } static void dc_decode_leaf_sia(struct dc_softc *sc, struct dc_eblock_sia *l) { struct dc_mediainfo *m; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); switch (l->dc_sia_code & ~DC_SIA_CODE_EXT) { case DC_SIA_CODE_10BT: m->dc_media = IFM_10_T; break; case DC_SIA_CODE_10BT_FDX: m->dc_media = IFM_10_T | IFM_FDX; break; case DC_SIA_CODE_10B2: m->dc_media = IFM_10_2; break; case DC_SIA_CODE_10B5: m->dc_media = IFM_10_5; break; default: break; } /* * We need to ignore CSR13, CSR14, CSR15 for SIA mode. * Things apparently already work for cards that do * supply Media Specific Data. */ if (l->dc_sia_code & DC_SIA_CODE_EXT) { m->dc_gp_len = 2; m->dc_gp_ptr = (u_int8_t *)&l->dc_un.dc_sia_ext.dc_sia_gpio_ctl; } else { m->dc_gp_len = 2; m->dc_gp_ptr = (u_int8_t *)&l->dc_un.dc_sia_noext.dc_sia_gpio_ctl; } m->dc_next = sc->dc_mi; sc->dc_mi = m; sc->dc_pmode = DC_PMODE_SIA; } static void dc_decode_leaf_sym(struct dc_softc *sc, struct dc_eblock_sym *l) { struct dc_mediainfo *m; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); if (l->dc_sym_code == DC_SYM_CODE_100BT) m->dc_media = IFM_100_TX; if (l->dc_sym_code == DC_SYM_CODE_100BT_FDX) m->dc_media = IFM_100_TX | IFM_FDX; m->dc_gp_len = 2; m->dc_gp_ptr = (u_int8_t *)&l->dc_sym_gpio_ctl; m->dc_next = sc->dc_mi; sc->dc_mi = m; sc->dc_pmode = DC_PMODE_SYM; } static void dc_decode_leaf_mii(struct dc_softc *sc, struct dc_eblock_mii *l) { struct dc_mediainfo *m; u_int8_t *p; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); /* We abuse IFM_AUTO to represent MII. */ m->dc_media = IFM_AUTO; m->dc_gp_len = l->dc_gpr_len; p = (u_int8_t *)l; p += sizeof(struct dc_eblock_mii); m->dc_gp_ptr = p; p += 2 * l->dc_gpr_len; m->dc_reset_len = *p; p++; m->dc_reset_ptr = p; m->dc_next = sc->dc_mi; sc->dc_mi = m; } static void dc_read_srom(struct dc_softc *sc, int bits) { int size; size = 2 << bits; sc->dc_srom = malloc(size, M_DEVBUF, M_NOWAIT); dc_read_eeprom(sc, (caddr_t)sc->dc_srom, 0, (size / 2), 0); } static void dc_parse_21143_srom(struct dc_softc *sc) { struct dc_leaf_hdr *lhdr; struct dc_eblock_hdr *hdr; int have_mii, i, loff; char *ptr; have_mii = 0; loff = sc->dc_srom[27]; lhdr = (struct dc_leaf_hdr *)&(sc->dc_srom[loff]); ptr = (char *)lhdr; ptr += sizeof(struct dc_leaf_hdr) - 1; /* * Look if we got a MII media block. */ for (i = 0; i < lhdr->dc_mcnt; i++) { hdr = (struct dc_eblock_hdr *)ptr; if (hdr->dc_type == DC_EBLOCK_MII) have_mii++; ptr += (hdr->dc_len & 0x7F); ptr++; } /* * Do the same thing again. Only use SIA and SYM media * blocks if no MII media block is available. */ ptr = (char *)lhdr; ptr += sizeof(struct dc_leaf_hdr) - 1; for (i = 0; i < lhdr->dc_mcnt; i++) { hdr = (struct dc_eblock_hdr *)ptr; switch (hdr->dc_type) { case DC_EBLOCK_MII: dc_decode_leaf_mii(sc, (struct dc_eblock_mii *)hdr); break; case DC_EBLOCK_SIA: if (! have_mii) dc_decode_leaf_sia(sc, (struct dc_eblock_sia *)hdr); break; case DC_EBLOCK_SYM: if (! have_mii) dc_decode_leaf_sym(sc, (struct dc_eblock_sym *)hdr); break; default: /* Don't care. Yet. */ break; } ptr += (hdr->dc_len & 0x7F); ptr++; } } static void dc_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) { u_int32_t *paddr; KASSERT(nseg == 1, ("wrong number of segments, should be 1")); paddr = arg; *paddr = segs->ds_addr; } /* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */ static int dc_attach(device_t dev) { int tmp = 0; u_char eaddr[ETHER_ADDR_LEN]; u_int32_t command; struct dc_softc *sc; struct ifnet *ifp; u_int32_t revision; int unit, error = 0, rid, mac_offset; int i; u_int8_t *mac; sc = device_get_softc(dev); unit = device_get_unit(dev); mtx_init(&sc->dc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF | MTX_RECURSE); #ifndef BURN_BRIDGES /* * Handle power management nonsense. */ dc_acpi(dev); #endif /* * Map control/status registers. */ pci_enable_busmaster(dev); rid = DC_RID; sc->dc_res = bus_alloc_resource(dev, DC_RES, &rid, 0, ~0, 1, RF_ACTIVE); if (sc->dc_res == NULL) { printf("dc%d: couldn't map ports/memory\n", unit); error = ENXIO; goto fail; } sc->dc_btag = rman_get_bustag(sc->dc_res); sc->dc_bhandle = rman_get_bushandle(sc->dc_res); /* Allocate interrupt. */ rid = 0; sc->dc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->dc_irq == NULL) { printf("dc%d: couldn't map interrupt\n", unit); error = ENXIO; goto fail; } /* Need this info to decide on a chip type. */ sc->dc_info = dc_devtype(dev); revision = pci_read_config(dev, DC_PCI_CFRV, 4) & 0x000000FF; /* Get the eeprom width, but PNIC and XIRCOM have diff eeprom */ if (sc->dc_info->dc_did != DC_DEVICEID_82C168 && sc->dc_info->dc_did != DC_DEVICEID_X3201) dc_eeprom_width(sc); switch (sc->dc_info->dc_did) { case DC_DEVICEID_21143: sc->dc_type = DC_TYPE_21143; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; sc->dc_flags |= DC_REDUCED_MII_POLL; /* Save EEPROM contents so we can parse them later. */ dc_read_srom(sc, sc->dc_romwidth); break; case DC_DEVICEID_DM9009: case DC_DEVICEID_DM9100: case DC_DEVICEID_DM9102: sc->dc_type = DC_TYPE_DM9102; sc->dc_flags |= DC_TX_COALESCE | DC_TX_INTR_ALWAYS; sc->dc_flags |= DC_REDUCED_MII_POLL | DC_TX_STORENFWD; sc->dc_flags |= DC_TX_ALIGN; sc->dc_pmode = DC_PMODE_MII; /* Increase the latency timer value. */ command = pci_read_config(dev, DC_PCI_CFLT, 4); command &= 0xFFFF00FF; command |= 0x00008000; pci_write_config(dev, DC_PCI_CFLT, command, 4); break; case DC_DEVICEID_AL981: sc->dc_type = DC_TYPE_AL981; sc->dc_flags |= DC_TX_USE_TX_INTR; sc->dc_flags |= DC_TX_ADMTEK_WAR; sc->dc_pmode = DC_PMODE_MII; dc_read_srom(sc, sc->dc_romwidth); break; case DC_DEVICEID_AN985: case DC_DEVICEID_ADM9511: case DC_DEVICEID_ADM9513: case DC_DEVICEID_FA511: case DC_DEVICEID_FE2500: case DC_DEVICEID_EN2242: case DC_DEVICEID_HAWKING_PN672TX: case DC_DEVICEID_3CSOHOB: case DC_DEVICEID_MSMN120: case DC_DEVICEID_MSMN130_FAKE: /* XXX avoid collision with PNIC*/ sc->dc_type = DC_TYPE_AN985; sc->dc_flags |= DC_64BIT_HASH; sc->dc_flags |= DC_TX_USE_TX_INTR; sc->dc_flags |= DC_TX_ADMTEK_WAR; sc->dc_pmode = DC_PMODE_MII; /* Don't read SROM for - auto-loaded on reset */ break; case DC_DEVICEID_98713: case DC_DEVICEID_98713_CP: if (revision < DC_REVISION_98713A) { sc->dc_type = DC_TYPE_98713; } if (revision >= DC_REVISION_98713A) { sc->dc_type = DC_TYPE_98713A; sc->dc_flags |= DC_21143_NWAY; } sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; break; case DC_DEVICEID_987x5: case DC_DEVICEID_EN1217: /* * Macronix MX98715AEC-C/D/E parts have only a * 128-bit hash table. We need to deal with these * in the same manner as the PNIC II so that we * get the right number of bits out of the * CRC routine. */ if (revision >= DC_REVISION_98715AEC_C && revision < DC_REVISION_98725) sc->dc_flags |= DC_128BIT_HASH; sc->dc_type = DC_TYPE_987x5; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; sc->dc_flags |= DC_REDUCED_MII_POLL | DC_21143_NWAY; break; case DC_DEVICEID_98727: sc->dc_type = DC_TYPE_987x5; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR; sc->dc_flags |= DC_REDUCED_MII_POLL | DC_21143_NWAY; break; case DC_DEVICEID_82C115: sc->dc_type = DC_TYPE_PNICII; sc->dc_flags |= DC_TX_POLL | DC_TX_USE_TX_INTR | DC_128BIT_HASH; sc->dc_flags |= DC_REDUCED_MII_POLL | DC_21143_NWAY; break; case DC_DEVICEID_82C168: sc->dc_type = DC_TYPE_PNIC; sc->dc_flags |= DC_TX_STORENFWD | DC_TX_INTR_ALWAYS; sc->dc_flags |= DC_PNIC_RX_BUG_WAR; sc->dc_pnic_rx_buf = malloc(DC_RXLEN * 5, M_DEVBUF, M_NOWAIT); if (revision < DC_REVISION_82C169) sc->dc_pmode = DC_PMODE_SYM; break; case DC_DEVICEID_AX88140A: sc->dc_type = DC_TYPE_ASIX; sc->dc_flags |= DC_TX_USE_TX_INTR | DC_TX_INTR_FIRSTFRAG; sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_pmode = DC_PMODE_MII; break; case DC_DEVICEID_X3201: sc->dc_type = DC_TYPE_XIRCOM; sc->dc_flags |= DC_TX_INTR_ALWAYS | DC_TX_COALESCE | DC_TX_ALIGN; /* * We don't actually need to coalesce, but we're doing * it to obtain a double word aligned buffer. * The DC_TX_COALESCE flag is required. */ sc->dc_pmode = DC_PMODE_MII; break; case DC_DEVICEID_RS7112: sc->dc_type = DC_TYPE_CONEXANT; sc->dc_flags |= DC_TX_INTR_ALWAYS; sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_pmode = DC_PMODE_MII; dc_read_srom(sc, sc->dc_romwidth); break; default: printf("dc%d: unknown device: %x\n", sc->dc_unit, sc->dc_info->dc_did); break; } /* Save the cache line size. */ if (DC_IS_DAVICOM(sc)) sc->dc_cachesize = 0; else sc->dc_cachesize = pci_read_config(dev, DC_PCI_CFLT, 4) & 0xFF; /* Reset the adapter. */ dc_reset(sc); /* Take 21143 out of snooze mode */ if (DC_IS_INTEL(sc) || DC_IS_XIRCOM(sc)) { command = pci_read_config(dev, DC_PCI_CFDD, 4); command &= ~(DC_CFDD_SNOOZE_MODE | DC_CFDD_SLEEP_MODE); pci_write_config(dev, DC_PCI_CFDD, command, 4); } /* * Try to learn something about the supported media. * We know that ASIX and ADMtek and Davicom devices * will *always* be using MII media, so that's a no-brainer. * The tricky ones are the Macronix/PNIC II and the * Intel 21143. */ if (DC_IS_INTEL(sc)) dc_parse_21143_srom(sc); else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) { if (sc->dc_type == DC_TYPE_98713) sc->dc_pmode = DC_PMODE_MII; else sc->dc_pmode = DC_PMODE_SYM; } else if (!sc->dc_pmode) sc->dc_pmode = DC_PMODE_MII; /* * Get station address from the EEPROM. */ switch(sc->dc_type) { case DC_TYPE_98713: case DC_TYPE_98713A: case DC_TYPE_987x5: case DC_TYPE_PNICII: dc_read_eeprom(sc, (caddr_t)&mac_offset, (DC_EE_NODEADDR_OFFSET / 2), 1, 0); dc_read_eeprom(sc, (caddr_t)&eaddr, (mac_offset / 2), 3, 0); break; case DC_TYPE_PNIC: dc_read_eeprom(sc, (caddr_t)&eaddr, 0, 3, 1); break; case DC_TYPE_DM9102: case DC_TYPE_21143: case DC_TYPE_ASIX: dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0); break; case DC_TYPE_AL981: case DC_TYPE_AN985: *(u_int32_t *)(&eaddr[0]) = CSR_READ_4(sc, DC_AL_PAR0); *(u_int16_t *)(&eaddr[4]) = CSR_READ_4(sc, DC_AL_PAR1); break; case DC_TYPE_CONEXANT: bcopy(sc->dc_srom + DC_CONEXANT_EE_NODEADDR, &eaddr, ETHER_ADDR_LEN); break; case DC_TYPE_XIRCOM: /* The MAC comes from the CIS. */ mac = pci_get_ether(dev); if (!mac) { device_printf(dev, "No station address in CIS!\n"); error = ENXIO; goto fail; } bcopy(mac, eaddr, ETHER_ADDR_LEN); break; default: dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0); break; } /* * A 21143 or clone chip was detected. Inform the world. */ printf("dc%d: Ethernet address: %6D\n", unit, eaddr, ":"); sc->dc_unit = unit; bcopy(eaddr, &sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, sizeof(struct dc_list_data), 1, sizeof(struct dc_list_data), 0, NULL, NULL, &sc->dc_ltag); if (error) { printf("dc%d: failed to allocate busdma tag\n", unit); error = ENXIO; goto fail; } error = bus_dmamem_alloc(sc->dc_ltag, (void **)&sc->dc_ldata, BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sc->dc_lmap); if (error) { printf("dc%d: failed to allocate DMA safe memory\n", unit); error = ENXIO; goto fail; } error = bus_dmamap_load(sc->dc_ltag, sc->dc_lmap, sc->dc_ldata, sizeof(struct dc_list_data), dc_dma_map_addr, &sc->dc_laddr, BUS_DMA_NOWAIT); if (error) { printf("dc%d: cannot get address of the descriptors\n", unit); error = ENXIO; goto fail; } /* * Allocate a busdma tag and DMA safe memory for the multicast * setup frame. */ error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, DC_SFRAME_LEN + DC_MIN_FRAMELEN, 1, DC_SFRAME_LEN + DC_MIN_FRAMELEN, 0, NULL, NULL, &sc->dc_stag); if (error) { printf("dc%d: failed to allocate busdma tag\n", unit); error = ENXIO; goto fail; } error = bus_dmamem_alloc(sc->dc_stag, (void **)&sc->dc_cdata.dc_sbuf, BUS_DMA_NOWAIT, &sc->dc_smap); if (error) { printf("dc%d: failed to allocate DMA safe memory\n", unit); error = ENXIO; goto fail; } error = bus_dmamap_load(sc->dc_stag, sc->dc_smap, sc->dc_cdata.dc_sbuf, DC_SFRAME_LEN, dc_dma_map_addr, &sc->dc_saddr, BUS_DMA_NOWAIT); if (error) { printf("dc%d: cannot get address of the descriptors\n", unit); error = ENXIO; goto fail; } /* Allocate a busdma tag for mbufs. */ error = bus_dma_tag_create(NULL, PAGE_SIZE, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES * DC_TX_LIST_CNT, DC_TX_LIST_CNT, MCLBYTES, 0, NULL, NULL, &sc->dc_mtag); if (error) { printf("dc%d: failed to allocate busdma tag\n", unit); error = ENXIO; goto fail; } /* Create the TX/RX busdma maps. */ for (i = 0; i < DC_TX_LIST_CNT; i++) { error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_cdata.dc_tx_map[i]); if (error) { printf("dc%d: failed to init TX ring\n", unit); error = ENXIO; goto fail; } } for (i = 0; i < DC_RX_LIST_CNT; i++) { error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_cdata.dc_rx_map[i]); if (error) { printf("dc%d: failed to init RX ring\n", unit); error = ENXIO; goto fail; } } error = bus_dmamap_create(sc->dc_mtag, 0, &sc->dc_sparemap); if (error) { printf("dc%d: failed to init RX ring\n", unit); error = ENXIO; goto fail; } ifp = &sc->arpcom.ac_if; ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); /* XXX: bleah, MTU gets overwritten in ether_ifattach() */ ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = dc_ioctl; ifp->if_start = dc_start; ifp->if_watchdog = dc_watchdog; ifp->if_init = dc_init; ifp->if_baudrate = 10000000; ifp->if_snd.ifq_maxlen = DC_TX_LIST_CNT - 1; /* * Do MII setup. If this is a 21143, check for a PHY on the * MII bus after applying any necessary fixups to twiddle the * GPIO bits. If we don't end up finding a PHY, restore the * old selection (SIA only or SIA/SYM) and attach the dcphy * driver instead. */ if (DC_IS_INTEL(sc)) { dc_apply_fixup(sc, IFM_AUTO); tmp = sc->dc_pmode; sc->dc_pmode = DC_PMODE_MII; } error = mii_phy_probe(dev, &sc->dc_miibus, dc_ifmedia_upd, dc_ifmedia_sts); if (error && DC_IS_INTEL(sc)) { sc->dc_pmode = tmp; if (sc->dc_pmode != DC_PMODE_SIA) sc->dc_pmode = DC_PMODE_SYM; sc->dc_flags |= DC_21143_NWAY; mii_phy_probe(dev, &sc->dc_miibus, dc_ifmedia_upd, dc_ifmedia_sts); /* * For non-MII cards, we need to have the 21143 * drive the LEDs. Except there are some systems * like the NEC VersaPro NoteBook PC which have no * LEDs, and twiddling these bits has adverse effects * on them. (I.e. you suddenly can't get a link.) */ if (pci_read_config(dev, DC_PCI_CSID, 4) != 0x80281033) sc->dc_flags |= DC_TULIP_LEDS; error = 0; } if (error) { printf("dc%d: MII without any PHY!\n", sc->dc_unit); goto fail; } if (DC_IS_XIRCOM(sc)) { /* * setup General Purpose Port mode and data so the tulip * can talk to the MII. */ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN | DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); DELAY(10); CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN | DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); DELAY(10); } if (DC_IS_ADMTEK(sc)) { /* * Set automatic TX underrun recovery for the ADMtek chips */ DC_SETBIT(sc, DC_AL_CR, DC_AL_CR_ATUR); } /* * Tell the upper layer(s) we support long frames. */ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities |= IFCAP_VLAN_MTU; callout_init(&sc->dc_stat_ch, IS_MPSAFE ? CALLOUT_MPSAFE : 0); #ifdef SRM_MEDIA sc->dc_srm_media = 0; /* Remember the SRM console media setting */ if (DC_IS_INTEL(sc)) { command = pci_read_config(dev, DC_PCI_CFDD, 4); command &= ~(DC_CFDD_SNOOZE_MODE | DC_CFDD_SLEEP_MODE); switch ((command >> 8) & 0xff) { case 3: sc->dc_srm_media = IFM_10_T; break; case 4: sc->dc_srm_media = IFM_10_T | IFM_FDX; break; case 5: sc->dc_srm_media = IFM_100_TX; break; case 6: sc->dc_srm_media = IFM_100_TX | IFM_FDX; break; } if (sc->dc_srm_media) sc->dc_srm_media |= IFM_ACTIVE | IFM_ETHER; } #endif /* * Call MI attach routine. */ ether_ifattach(ifp, eaddr); /* Hook interrupt last to avoid having to lock softc */ error = bus_setup_intr(dev, sc->dc_irq, INTR_TYPE_NET | (IS_MPSAFE ? INTR_MPSAFE : 0), dc_intr, sc, &sc->dc_intrhand); if (error) { printf("dc%d: couldn't set up irq\n", unit); ether_ifdetach(ifp); goto fail; } fail: if (error) dc_detach(dev); return (error); } /* * Shutdown hardware and free up resources. This can be called any * time after the mutex has been initialized. It is called in both * the error case in attach and the normal detach case so it needs * to be careful about only freeing resources that have actually been * allocated. */ static int dc_detach(device_t dev) { struct dc_softc *sc; struct ifnet *ifp; struct dc_mediainfo *m; int i; sc = device_get_softc(dev); KASSERT(mtx_initialized(&sc->dc_mtx), ("dc mutex not initialized")); DC_LOCK(sc); ifp = &sc->arpcom.ac_if; /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { dc_stop(sc); ether_ifdetach(ifp); } if (sc->dc_miibus) device_delete_child(dev, sc->dc_miibus); bus_generic_detach(dev); if (sc->dc_intrhand) bus_teardown_intr(dev, sc->dc_irq, sc->dc_intrhand); if (sc->dc_irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->dc_irq); if (sc->dc_res) bus_release_resource(dev, DC_RES, DC_RID, sc->dc_res); if (sc->dc_cdata.dc_sbuf != NULL) bus_dmamem_free(sc->dc_stag, sc->dc_cdata.dc_sbuf, sc->dc_smap); if (sc->dc_ldata != NULL) bus_dmamem_free(sc->dc_ltag, sc->dc_ldata, sc->dc_lmap); for (i = 0; i < DC_TX_LIST_CNT; i++) bus_dmamap_destroy(sc->dc_mtag, sc->dc_cdata.dc_tx_map[i]); for (i = 0; i < DC_RX_LIST_CNT; i++) bus_dmamap_destroy(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i]); bus_dmamap_destroy(sc->dc_mtag, sc->dc_sparemap); if (sc->dc_stag) bus_dma_tag_destroy(sc->dc_stag); if (sc->dc_mtag) bus_dma_tag_destroy(sc->dc_mtag); if (sc->dc_ltag) bus_dma_tag_destroy(sc->dc_ltag); free(sc->dc_pnic_rx_buf, M_DEVBUF); while (sc->dc_mi != NULL) { m = sc->dc_mi->dc_next; free(sc->dc_mi, M_DEVBUF); sc->dc_mi = m; } free(sc->dc_srom, M_DEVBUF); DC_UNLOCK(sc); mtx_destroy(&sc->dc_mtx); return (0); } /* * Initialize the transmit descriptors. */ static int dc_list_tx_init(struct dc_softc *sc) { struct dc_chain_data *cd; struct dc_list_data *ld; int i, nexti; cd = &sc->dc_cdata; ld = sc->dc_ldata; for (i = 0; i < DC_TX_LIST_CNT; i++) { if (i == DC_TX_LIST_CNT - 1) nexti = 0; else nexti = i + 1; ld->dc_tx_list[i].dc_next = htole32(DC_TXDESC(sc, nexti)); cd->dc_tx_chain[i] = NULL; ld->dc_tx_list[i].dc_data = 0; ld->dc_tx_list[i].dc_ctl = 0; } cd->dc_tx_prod = cd->dc_tx_cons = cd->dc_tx_cnt = 0; bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); return (0); } /* * Initialize the RX descriptors and allocate mbufs for them. Note that * we arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */ static int dc_list_rx_init(struct dc_softc *sc) { struct dc_chain_data *cd; struct dc_list_data *ld; int i, nexti; cd = &sc->dc_cdata; ld = sc->dc_ldata; for (i = 0; i < DC_RX_LIST_CNT; i++) { if (dc_newbuf(sc, i, 1) != 0) return (ENOBUFS); if (i == DC_RX_LIST_CNT - 1) nexti = 0; else nexti = i + 1; ld->dc_rx_list[i].dc_next = htole32(DC_RXDESC(sc, nexti)); } cd->dc_rx_prod = 0; bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); return (0); } static void dc_dma_map_rxbuf(arg, segs, nseg, mapsize, error) void *arg; bus_dma_segment_t *segs; int nseg; bus_size_t mapsize; int error; { struct dc_softc *sc; struct dc_desc *c; sc = arg; c = &sc->dc_ldata->dc_rx_list[sc->dc_cdata.dc_rx_cur]; if (error) { sc->dc_cdata.dc_rx_err = error; return; } KASSERT(nseg == 1, ("wrong number of segments, should be 1")); sc->dc_cdata.dc_rx_err = 0; c->dc_data = htole32(segs->ds_addr); } /* * Initialize an RX descriptor and attach an MBUF cluster. */ static int dc_newbuf(struct dc_softc *sc, int i, int alloc) { struct mbuf *m_new; bus_dmamap_t tmp; int error; if (alloc) { m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); if (m_new == NULL) return (ENOBUFS); } else { m_new = sc->dc_cdata.dc_rx_chain[i]; m_new->m_data = m_new->m_ext.ext_buf; } m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; m_adj(m_new, sizeof(u_int64_t)); /* * If this is a PNIC chip, zero the buffer. This is part * of the workaround for the receive bug in the 82c168 and * 82c169 chips. */ if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) bzero(mtod(m_new, char *), m_new->m_len); /* No need to remap the mbuf if we're reusing it. */ if (alloc) { sc->dc_cdata.dc_rx_cur = i; error = bus_dmamap_load_mbuf(sc->dc_mtag, sc->dc_sparemap, m_new, dc_dma_map_rxbuf, sc, 0); if (error) { m_freem(m_new); return (error); } if (sc->dc_cdata.dc_rx_err != 0) { m_freem(m_new); return (sc->dc_cdata.dc_rx_err); } bus_dmamap_unload(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i]); tmp = sc->dc_cdata.dc_rx_map[i]; sc->dc_cdata.dc_rx_map[i] = sc->dc_sparemap; sc->dc_sparemap = tmp; sc->dc_cdata.dc_rx_chain[i] = m_new; } sc->dc_ldata->dc_rx_list[i].dc_ctl = htole32(DC_RXCTL_RLINK | DC_RXLEN); sc->dc_ldata->dc_rx_list[i].dc_status = htole32(DC_RXSTAT_OWN); bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i], BUS_DMASYNC_PREREAD); bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); return (0); } /* * Grrrrr. * The PNIC chip has a terrible bug in it that manifests itself during * periods of heavy activity. The exact mode of failure if difficult to * pinpoint: sometimes it only happens in promiscuous mode, sometimes it * will happen on slow machines. The bug is that sometimes instead of * uploading one complete frame during reception, it uploads what looks * like the entire contents of its FIFO memory. The frame we want is at * the end of the whole mess, but we never know exactly how much data has * been uploaded, so salvaging the frame is hard. * * There is only one way to do it reliably, and it's disgusting. * Here's what we know: * * - We know there will always be somewhere between one and three extra * descriptors uploaded. * * - We know the desired received frame will always be at the end of the * total data upload. * * - We know the size of the desired received frame because it will be * provided in the length field of the status word in the last descriptor. * * Here's what we do: * * - When we allocate buffers for the receive ring, we bzero() them. * This means that we know that the buffer contents should be all * zeros, except for data uploaded by the chip. * * - We also force the PNIC chip to upload frames that include the * ethernet CRC at the end. * * - We gather all of the bogus frame data into a single buffer. * * - We then position a pointer at the end of this buffer and scan * backwards until we encounter the first non-zero byte of data. * This is the end of the received frame. We know we will encounter * some data at the end of the frame because the CRC will always be * there, so even if the sender transmits a packet of all zeros, * we won't be fooled. * * - We know the size of the actual received frame, so we subtract * that value from the current pointer location. This brings us * to the start of the actual received packet. * * - We copy this into an mbuf and pass it on, along with the actual * frame length. * * The performance hit is tremendous, but it beats dropping frames all * the time. */ #define DC_WHOLEFRAME (DC_RXSTAT_FIRSTFRAG | DC_RXSTAT_LASTFRAG) static void dc_pnic_rx_bug_war(struct dc_softc *sc, int idx) { struct dc_desc *cur_rx; struct dc_desc *c = NULL; struct mbuf *m = NULL; unsigned char *ptr; int i, total_len; u_int32_t rxstat = 0; i = sc->dc_pnic_rx_bug_save; cur_rx = &sc->dc_ldata->dc_rx_list[idx]; ptr = sc->dc_pnic_rx_buf; bzero(ptr, DC_RXLEN * 5); /* Copy all the bytes from the bogus buffers. */ while (1) { c = &sc->dc_ldata->dc_rx_list[i]; rxstat = le32toh(c->dc_status); m = sc->dc_cdata.dc_rx_chain[i]; bcopy(mtod(m, char *), ptr, DC_RXLEN); ptr += DC_RXLEN; /* If this is the last buffer, break out. */ if (i == idx || rxstat & DC_RXSTAT_LASTFRAG) break; dc_newbuf(sc, i, 0); DC_INC(i, DC_RX_LIST_CNT); } /* Find the length of the actual receive frame. */ total_len = DC_RXBYTES(rxstat); /* Scan backwards until we hit a non-zero byte. */ while (*ptr == 0x00) ptr--; /* Round off. */ if ((uintptr_t)(ptr) & 0x3) ptr -= 1; /* Now find the start of the frame. */ ptr -= total_len; if (ptr < sc->dc_pnic_rx_buf) ptr = sc->dc_pnic_rx_buf; /* * Now copy the salvaged frame to the last mbuf and fake up * the status word to make it look like a successful * frame reception. */ dc_newbuf(sc, i, 0); bcopy(ptr, mtod(m, char *), total_len); cur_rx->dc_status = htole32(rxstat | DC_RXSTAT_FIRSTFRAG); } /* * This routine searches the RX ring for dirty descriptors in the * event that the rxeof routine falls out of sync with the chip's * current descriptor pointer. This may happen sometimes as a result * of a "no RX buffer available" condition that happens when the chip * consumes all of the RX buffers before the driver has a chance to * process the RX ring. This routine may need to be called more than * once to bring the driver back in sync with the chip, however we * should still be getting RX DONE interrupts to drive the search * for new packets in the RX ring, so we should catch up eventually. */ static int dc_rx_resync(struct dc_softc *sc) { struct dc_desc *cur_rx; int i, pos; pos = sc->dc_cdata.dc_rx_prod; for (i = 0; i < DC_RX_LIST_CNT; i++) { cur_rx = &sc->dc_ldata->dc_rx_list[pos]; if (!(le32toh(cur_rx->dc_status) & DC_RXSTAT_OWN)) break; DC_INC(pos, DC_RX_LIST_CNT); } /* If the ring really is empty, then just return. */ if (i == DC_RX_LIST_CNT) return (0); /* We've fallen behing the chip: catch it. */ sc->dc_cdata.dc_rx_prod = pos; return (EAGAIN); } /* * A frame has been uploaded: pass the resulting mbuf chain up to * the higher level protocols. */ static void dc_rxeof(struct dc_softc *sc) { struct mbuf *m; struct ifnet *ifp; struct dc_desc *cur_rx; int i, total_len = 0; u_int32_t rxstat; DC_LOCK_ASSERT(sc); ifp = &sc->arpcom.ac_if; i = sc->dc_cdata.dc_rx_prod; bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_POSTREAD); while (!(le32toh(sc->dc_ldata->dc_rx_list[i].dc_status) & DC_RXSTAT_OWN)) { #ifdef DEVICE_POLLING if (ifp->if_flags & IFF_POLLING) { if (sc->rxcycles <= 0) break; sc->rxcycles--; } #endif cur_rx = &sc->dc_ldata->dc_rx_list[i]; rxstat = le32toh(cur_rx->dc_status); m = sc->dc_cdata.dc_rx_chain[i]; bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_rx_map[i], BUS_DMASYNC_POSTREAD); total_len = DC_RXBYTES(rxstat); if (sc->dc_flags & DC_PNIC_RX_BUG_WAR) { if ((rxstat & DC_WHOLEFRAME) != DC_WHOLEFRAME) { if (rxstat & DC_RXSTAT_FIRSTFRAG) sc->dc_pnic_rx_bug_save = i; if ((rxstat & DC_RXSTAT_LASTFRAG) == 0) { DC_INC(i, DC_RX_LIST_CNT); continue; } dc_pnic_rx_bug_war(sc, i); rxstat = le32toh(cur_rx->dc_status); total_len = DC_RXBYTES(rxstat); } } /* * If an error occurs, update stats, clear the * status word and leave the mbuf cluster in place: * it should simply get re-used next time this descriptor * comes up in the ring. However, don't report long * frames as errors since they could be vlans. */ if ((rxstat & DC_RXSTAT_RXERR)) { if (!(rxstat & DC_RXSTAT_GIANT) || (rxstat & (DC_RXSTAT_CRCERR | DC_RXSTAT_DRIBBLE | DC_RXSTAT_MIIERE | DC_RXSTAT_COLLSEEN | DC_RXSTAT_RUNT | DC_RXSTAT_DE))) { ifp->if_ierrors++; if (rxstat & DC_RXSTAT_COLLSEEN) ifp->if_collisions++; dc_newbuf(sc, i, 0); if (rxstat & DC_RXSTAT_CRCERR) { DC_INC(i, DC_RX_LIST_CNT); continue; } else { dc_init(sc); return; } } } /* No errors; receive the packet. */ total_len -= ETHER_CRC_LEN; #ifdef __i386__ /* * On the x86 we do not have alignment problems, so try to * allocate a new buffer for the receive ring, and pass up * the one where the packet is already, saving the expensive * copy done in m_devget(). * If we are on an architecture with alignment problems, or * if the allocation fails, then use m_devget and leave the * existing buffer in the receive ring. */ if (dc_quick && dc_newbuf(sc, i, 1) == 0) { m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = total_len; DC_INC(i, DC_RX_LIST_CNT); } else #endif { struct mbuf *m0; m0 = m_devget(mtod(m, char *), total_len, ETHER_ALIGN, ifp, NULL); dc_newbuf(sc, i, 0); DC_INC(i, DC_RX_LIST_CNT); if (m0 == NULL) { ifp->if_ierrors++; continue; } m = m0; } ifp->if_ipackets++; DC_UNLOCK(sc); (*ifp->if_input)(ifp, m); DC_LOCK(sc); } sc->dc_cdata.dc_rx_prod = i; } /* * A frame was downloaded to the chip. It's safe for us to clean up * the list buffers. */ static void dc_txeof(struct dc_softc *sc) { struct dc_desc *cur_tx = NULL; struct ifnet *ifp; int idx; u_int32_t ctl, txstat; ifp = &sc->arpcom.ac_if; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_POSTREAD); idx = sc->dc_cdata.dc_tx_cons; while (idx != sc->dc_cdata.dc_tx_prod) { cur_tx = &sc->dc_ldata->dc_tx_list[idx]; txstat = le32toh(cur_tx->dc_status); ctl = le32toh(cur_tx->dc_ctl); if (txstat & DC_TXSTAT_OWN) break; if (!(ctl & DC_TXCTL_FIRSTFRAG) || ctl & DC_TXCTL_SETUP) { if (ctl & DC_TXCTL_SETUP) { /* * Yes, the PNIC is so brain damaged * that it will sometimes generate a TX * underrun error while DMAing the RX * filter setup frame. If we detect this, * we have to send the setup frame again, * or else the filter won't be programmed * correctly. */ if (DC_IS_PNIC(sc)) { if (txstat & DC_TXSTAT_ERRSUM) dc_setfilt(sc); } sc->dc_cdata.dc_tx_chain[idx] = NULL; } sc->dc_cdata.dc_tx_cnt--; DC_INC(idx, DC_TX_LIST_CNT); continue; } if (DC_IS_XIRCOM(sc) || DC_IS_CONEXANT(sc)) { /* * XXX: Why does my Xircom taunt me so? * For some reason it likes setting the CARRLOST flag * even when the carrier is there. wtf?!? * Who knows, but Conexant chips have the * same problem. Maybe they took lessons * from Xircom. */ if (/*sc->dc_type == DC_TYPE_21143 &&*/ sc->dc_pmode == DC_PMODE_MII && ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM | DC_TXSTAT_NOCARRIER))) txstat &= ~DC_TXSTAT_ERRSUM; } else { if (/*sc->dc_type == DC_TYPE_21143 &&*/ sc->dc_pmode == DC_PMODE_MII && ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM | DC_TXSTAT_NOCARRIER | DC_TXSTAT_CARRLOST))) txstat &= ~DC_TXSTAT_ERRSUM; } if (txstat & DC_TXSTAT_ERRSUM) { ifp->if_oerrors++; if (txstat & DC_TXSTAT_EXCESSCOLL) ifp->if_collisions++; if (txstat & DC_TXSTAT_LATECOLL) ifp->if_collisions++; if (!(txstat & DC_TXSTAT_UNDERRUN)) { dc_init(sc); return; } } ifp->if_collisions += (txstat & DC_TXSTAT_COLLCNT) >> 3; ifp->if_opackets++; if (sc->dc_cdata.dc_tx_chain[idx] != NULL) { bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx]); m_freem(sc->dc_cdata.dc_tx_chain[idx]); sc->dc_cdata.dc_tx_chain[idx] = NULL; } sc->dc_cdata.dc_tx_cnt--; DC_INC(idx, DC_TX_LIST_CNT); } if (idx != sc->dc_cdata.dc_tx_cons) { /* Some buffers have been freed. */ sc->dc_cdata.dc_tx_cons = idx; ifp->if_flags &= ~IFF_OACTIVE; } ifp->if_timer = (sc->dc_cdata.dc_tx_cnt == 0) ? 0 : 5; } static void dc_tick(void *xsc) { struct dc_softc *sc; struct mii_data *mii; struct ifnet *ifp; u_int32_t r; sc = xsc; DC_LOCK(sc); ifp = &sc->arpcom.ac_if; mii = device_get_softc(sc->dc_miibus); if (sc->dc_flags & DC_REDUCED_MII_POLL) { if (sc->dc_flags & DC_21143_NWAY) { r = CSR_READ_4(sc, DC_10BTSTAT); if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX && (r & DC_TSTAT_LS100)) { sc->dc_link = 0; mii_mediachg(mii); } if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T && (r & DC_TSTAT_LS10)) { sc->dc_link = 0; mii_mediachg(mii); } if (sc->dc_link == 0) mii_tick(mii); } else { r = CSR_READ_4(sc, DC_ISR); if ((r & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT && sc->dc_cdata.dc_tx_cnt == 0) { mii_tick(mii); if (!(mii->mii_media_status & IFM_ACTIVE)) sc->dc_link = 0; } } } else mii_tick(mii); /* * When the init routine completes, we expect to be able to send * packets right away, and in fact the network code will send a * gratuitous ARP the moment the init routine marks the interface * as running. However, even though the MAC may have been initialized, * there may be a delay of a few seconds before the PHY completes * autonegotiation and the link is brought up. Any transmissions * made during that delay will be lost. Dealing with this is tricky: * we can't just pause in the init routine while waiting for the * PHY to come ready since that would bring the whole system to * a screeching halt for several seconds. * * What we do here is prevent the TX start routine from sending * any packets until a link has been established. After the * interface has been initialized, the tick routine will poll * the state of the PHY until the IFM_ACTIVE flag is set. Until * that time, packets will stay in the send queue, and once the * link comes up, they will be flushed out to the wire. */ if (!sc->dc_link && mii->mii_media_status & IFM_ACTIVE && IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { sc->dc_link++; if (ifp->if_snd.ifq_head != NULL) dc_start(ifp); } if (sc->dc_flags & DC_21143_NWAY && !sc->dc_link) callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc); else callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc); DC_UNLOCK(sc); } /* * A transmit underrun has occurred. Back off the transmit threshold, * or switch to store and forward mode if we have to. */ static void dc_tx_underrun(struct dc_softc *sc) { u_int32_t isr; int i; if (DC_IS_DAVICOM(sc)) dc_init(sc); if (DC_IS_INTEL(sc)) { /* * The real 21143 requires that the transmitter be idle * in order to change the transmit threshold or store * and forward state. */ DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); for (i = 0; i < DC_TIMEOUT; i++) { isr = CSR_READ_4(sc, DC_ISR); if (isr & DC_ISR_TX_IDLE) break; DELAY(10); } if (i == DC_TIMEOUT) { printf("dc%d: failed to force tx to idle state\n", sc->dc_unit); dc_init(sc); } } printf("dc%d: TX underrun -- ", sc->dc_unit); sc->dc_txthresh += DC_TXTHRESH_INC; if (sc->dc_txthresh > DC_TXTHRESH_MAX) { printf("using store and forward mode\n"); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); } else { printf("increasing TX threshold\n"); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH); DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh); } if (DC_IS_INTEL(sc)) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); } #ifdef DEVICE_POLLING static poll_handler_t dc_poll; static void dc_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct dc_softc *sc = ifp->if_softc; if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ /* Re-enable interrupts. */ CSR_WRITE_4(sc, DC_IMR, DC_INTRS); return; } DC_LOCK(sc); sc->rxcycles = count; dc_rxeof(sc); dc_txeof(sc); if (ifp->if_snd.ifq_head != NULL && !(ifp->if_flags & IFF_OACTIVE)) dc_start(ifp); if (cmd == POLL_AND_CHECK_STATUS) { /* also check status register */ u_int32_t status; status = CSR_READ_4(sc, DC_ISR); status &= (DC_ISR_RX_WATDOGTIMEO | DC_ISR_RX_NOBUF | DC_ISR_TX_NOBUF | DC_ISR_TX_IDLE | DC_ISR_TX_UNDERRUN | DC_ISR_BUS_ERR); if (!status) { DC_UNLOCK(sc); return; } /* ack what we have */ CSR_WRITE_4(sc, DC_ISR, status); if (status & (DC_ISR_RX_WATDOGTIMEO | DC_ISR_RX_NOBUF)) { u_int32_t r = CSR_READ_4(sc, DC_FRAMESDISCARDED); ifp->if_ierrors += (r & 0xffff) + ((r >> 17) & 0x7ff); if (dc_rx_resync(sc)) dc_rxeof(sc); } /* restart transmit unit if necessary */ if (status & DC_ISR_TX_IDLE && sc->dc_cdata.dc_tx_cnt) CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); if (status & DC_ISR_TX_UNDERRUN) dc_tx_underrun(sc); if (status & DC_ISR_BUS_ERR) { printf("dc_poll: dc%d bus error\n", sc->dc_unit); dc_reset(sc); dc_init(sc); } } DC_UNLOCK(sc); } #endif /* DEVICE_POLLING */ static void dc_intr(void *arg) { struct dc_softc *sc; struct ifnet *ifp; u_int32_t status; sc = arg; if (sc->suspended) return; if ((CSR_READ_4(sc, DC_ISR) & DC_INTRS) == 0) return; DC_LOCK(sc); ifp = &sc->arpcom.ac_if; #ifdef DEVICE_POLLING if (ifp->if_flags & IFF_POLLING) goto done; if (ether_poll_register(dc_poll, ifp)) { /* ok, disable interrupts */ CSR_WRITE_4(sc, DC_IMR, 0x00000000); goto done; } #endif /* Suppress unwanted interrupts */ if (!(ifp->if_flags & IFF_UP)) { if (CSR_READ_4(sc, DC_ISR) & DC_INTRS) dc_stop(sc); DC_UNLOCK(sc); return; } /* Disable interrupts. */ CSR_WRITE_4(sc, DC_IMR, 0x00000000); while (((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) && status != 0xFFFFFFFF) { CSR_WRITE_4(sc, DC_ISR, status); if (status & DC_ISR_RX_OK) { int curpkts; curpkts = ifp->if_ipackets; dc_rxeof(sc); if (curpkts == ifp->if_ipackets) { while (dc_rx_resync(sc)) dc_rxeof(sc); } } if (status & (DC_ISR_TX_OK | DC_ISR_TX_NOBUF)) dc_txeof(sc); if (status & DC_ISR_TX_IDLE) { dc_txeof(sc); if (sc->dc_cdata.dc_tx_cnt) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); } } if (status & DC_ISR_TX_UNDERRUN) dc_tx_underrun(sc); if ((status & DC_ISR_RX_WATDOGTIMEO) || (status & DC_ISR_RX_NOBUF)) { int curpkts; curpkts = ifp->if_ipackets; dc_rxeof(sc); if (curpkts == ifp->if_ipackets) { while (dc_rx_resync(sc)) dc_rxeof(sc); } } if (status & DC_ISR_BUS_ERR) { dc_reset(sc); dc_init(sc); } } /* Re-enable interrupts. */ CSR_WRITE_4(sc, DC_IMR, DC_INTRS); if (ifp->if_snd.ifq_head != NULL) dc_start(ifp); #ifdef DEVICE_POLLING done: #endif DC_UNLOCK(sc); } static void dc_dma_map_txbuf(arg, segs, nseg, mapsize, error) void *arg; bus_dma_segment_t *segs; int nseg; bus_size_t mapsize; int error; { struct dc_softc *sc; struct dc_desc *f; int cur, first, frag, i; sc = arg; if (error) { sc->dc_cdata.dc_tx_err = error; return; } first = cur = frag = sc->dc_cdata.dc_tx_prod; for (i = 0; i < nseg; i++) { if ((sc->dc_flags & DC_TX_ADMTEK_WAR) && (frag == (DC_TX_LIST_CNT - 1)) && (first != sc->dc_cdata.dc_tx_first)) { bus_dmamap_unload(sc->dc_mtag, sc->dc_cdata.dc_tx_map[first]); sc->dc_cdata.dc_tx_err = ENOBUFS; return; } f = &sc->dc_ldata->dc_tx_list[frag]; f->dc_ctl = htole32(DC_TXCTL_TLINK | segs[i].ds_len); if (i == 0) { f->dc_status = 0; f->dc_ctl |= htole32(DC_TXCTL_FIRSTFRAG); } else f->dc_status = htole32(DC_TXSTAT_OWN); f->dc_data = htole32(segs[i].ds_addr); cur = frag; DC_INC(frag, DC_TX_LIST_CNT); } sc->dc_cdata.dc_tx_err = 0; sc->dc_cdata.dc_tx_prod = frag; sc->dc_cdata.dc_tx_cnt += nseg; sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG); if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG) sc->dc_ldata->dc_tx_list[first].dc_ctl |= htole32(DC_TXCTL_FINT); if (sc->dc_flags & DC_TX_INTR_ALWAYS) sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT); if (sc->dc_flags & DC_TX_USE_TX_INTR && sc->dc_cdata.dc_tx_cnt > 64) sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_FINT); sc->dc_ldata->dc_tx_list[first].dc_status = htole32(DC_TXSTAT_OWN); } /* * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ static int dc_encap(struct dc_softc *sc, struct mbuf **m_head) { struct mbuf *m; int error, idx, chainlen = 0; /* * If there's no way we can send any packets, return now. */ if (DC_TX_LIST_CNT - sc->dc_cdata.dc_tx_cnt < 6) return (ENOBUFS); /* * Count the number of frags in this chain to see if * we need to m_defrag. Since the descriptor list is shared * by all packets, we'll m_defrag long chains so that they * do not use up the entire list, even if they would fit. */ for (m = *m_head; m != NULL; m = m->m_next) chainlen++; if ((chainlen > DC_TX_LIST_CNT / 4) || ((DC_TX_LIST_CNT - (chainlen + sc->dc_cdata.dc_tx_cnt)) < 6)) { m = m_defrag(*m_head, M_DONTWAIT); if (m == NULL) return (ENOBUFS); *m_head = m; } /* * Start packing the mbufs in this chain into * the fragment pointers. Stop when we run out * of fragments or hit the end of the mbuf chain. */ idx = sc->dc_cdata.dc_tx_prod; error = bus_dmamap_load_mbuf(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], *m_head, dc_dma_map_txbuf, sc, 0); if (error) return (error); if (sc->dc_cdata.dc_tx_err != 0) return (sc->dc_cdata.dc_tx_err); sc->dc_cdata.dc_tx_chain[idx] = *m_head; bus_dmamap_sync(sc->dc_mtag, sc->dc_cdata.dc_tx_map[idx], BUS_DMASYNC_PREWRITE); bus_dmamap_sync(sc->dc_ltag, sc->dc_lmap, BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); return (0); } /* * Main transmit routine. To avoid having to do mbuf copies, we put pointers * to the mbuf data regions directly in the transmit lists. We also save a * copy of the pointers since the transmit list fragment pointers are * physical addresses. */ static void dc_start(struct ifnet *ifp) { struct dc_softc *sc; struct mbuf *m_head = NULL, *m; int idx; sc = ifp->if_softc; DC_LOCK(sc); if (!sc->dc_link && ifp->if_snd.ifq_len < 10) { DC_UNLOCK(sc); return; } if (ifp->if_flags & IFF_OACTIVE) { DC_UNLOCK(sc); return; } idx = sc->dc_cdata.dc_tx_first = sc->dc_cdata.dc_tx_prod; while (sc->dc_cdata.dc_tx_chain[idx] == NULL) { IF_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; if (sc->dc_flags & DC_TX_COALESCE && (m_head->m_next != NULL || sc->dc_flags & DC_TX_ALIGN)) { m = m_defrag(m_head, M_DONTWAIT); if (m == NULL) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } else { m_head = m; } } if (dc_encap(sc, &m_head)) { IF_PREPEND(&ifp->if_snd, m_head); ifp->if_flags |= IFF_OACTIVE; break; } idx = sc->dc_cdata.dc_tx_prod; /* * If there's a BPF listener, bounce a copy of this frame * to him. */ BPF_MTAP(ifp, m_head); if (sc->dc_flags & DC_TX_ONE) { ifp->if_flags |= IFF_OACTIVE; break; } } /* Transmit */ if (!(sc->dc_flags & DC_TX_POLL)) CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); /* * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; DC_UNLOCK(sc); } static void dc_init(void *xsc) { struct dc_softc *sc = xsc; struct ifnet *ifp = &sc->arpcom.ac_if; struct mii_data *mii; DC_LOCK(sc); mii = device_get_softc(sc->dc_miibus); /* * Cancel pending I/O and free all RX/TX buffers. */ dc_stop(sc); dc_reset(sc); /* * Set cache alignment and burst length. */ if (DC_IS_ASIX(sc) || DC_IS_DAVICOM(sc)) CSR_WRITE_4(sc, DC_BUSCTL, 0); else CSR_WRITE_4(sc, DC_BUSCTL, DC_BUSCTL_MRME | DC_BUSCTL_MRLE); /* * Evenly share the bus between receive and transmit process. */ if (DC_IS_INTEL(sc)) DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_ARBITRATION); if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc)) { DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_USECA); } else { DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_16LONG); } if (sc->dc_flags & DC_TX_POLL) DC_SETBIT(sc, DC_BUSCTL, DC_TXPOLL_1); switch(sc->dc_cachesize) { case 32: DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_32LONG); break; case 16: DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_16LONG); break; case 8: DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_8LONG); break; case 0: default: DC_SETBIT(sc, DC_BUSCTL, DC_CACHEALIGN_NONE); break; } if (sc->dc_flags & DC_TX_STORENFWD) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); else { if (sc->dc_txthresh > DC_TXTHRESH_MAX) { DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); } else { DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_STORENFWD); DC_SETBIT(sc, DC_NETCFG, sc->dc_txthresh); } } DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_NO_RXCRC); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_BACKOFF); if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) { /* * The app notes for the 98713 and 98715A say that * in order to have the chips operate properly, a magic * number must be written to CSR16. Macronix does not * document the meaning of these bits so there's no way * to know exactly what they do. The 98713 has a magic * number all its own; the rest all use a different one. */ DC_CLRBIT(sc, DC_MX_MAGICPACKET, 0xFFFF0000); if (sc->dc_type == DC_TYPE_98713) DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98713); else DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98715); } if (DC_IS_XIRCOM(sc)) { /* * setup General Purpose Port mode and data so the tulip * can talk to the MII. */ CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN | DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); DELAY(10); CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN | DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); DELAY(10); } DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH); DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_MIN); /* Init circular RX list. */ if (dc_list_rx_init(sc) == ENOBUFS) { printf("dc%d: initialization failed: no " "memory for rx buffers\n", sc->dc_unit); dc_stop(sc); DC_UNLOCK(sc); return; } /* * Init TX descriptors. */ dc_list_tx_init(sc); /* * Load the address of the RX list. */ CSR_WRITE_4(sc, DC_RXADDR, DC_RXDESC(sc, 0)); CSR_WRITE_4(sc, DC_TXADDR, DC_TXDESC(sc, 0)); /* * Enable interrupts. */ #ifdef DEVICE_POLLING /* * ... but only if we are not polling, and make sure they are off in * the case of polling. Some cards (e.g. fxp) turn interrupts on * after a reset. */ if (ifp->if_flags & IFF_POLLING) CSR_WRITE_4(sc, DC_IMR, 0x00000000); else #endif CSR_WRITE_4(sc, DC_IMR, DC_INTRS); CSR_WRITE_4(sc, DC_ISR, 0xFFFFFFFF); /* Enable transmitter. */ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); /* * If this is an Intel 21143 and we're not using the * MII port, program the LED control pins so we get * link and activity indications. */ if (sc->dc_flags & DC_TULIP_LEDS) { CSR_WRITE_4(sc, DC_WATCHDOG, DC_WDOG_CTLWREN | DC_WDOG_LINK | DC_WDOG_ACTIVITY); CSR_WRITE_4(sc, DC_WATCHDOG, 0); } /* * Load the RX/multicast filter. We do this sort of late * because the filter programming scheme on the 21143 and * some clones requires DMAing a setup frame via the TX * engine, and we need the transmitter enabled for that. */ dc_setfilt(sc); /* Enable receiver. */ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON); CSR_WRITE_4(sc, DC_RXSTART, 0xFFFFFFFF); mii_mediachg(mii); dc_setcfg(sc, sc->dc_if_media); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; /* Don't start the ticker if this is a homePNA link. */ if (IFM_SUBTYPE(mii->mii_media.ifm_media) == IFM_HPNA_1) sc->dc_link = 1; else { if (sc->dc_flags & DC_21143_NWAY) callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc); else callout_reset(&sc->dc_stat_ch, hz, dc_tick, sc); } #ifdef SRM_MEDIA if(sc->dc_srm_media) { struct ifreq ifr; ifr.ifr_media = sc->dc_srm_media; ifmedia_ioctl(ifp, &ifr, &mii->mii_media, SIOCSIFMEDIA); sc->dc_srm_media = 0; } #endif DC_UNLOCK(sc); } /* * Set media options. */ static int dc_ifmedia_upd(struct ifnet *ifp) { struct dc_softc *sc; struct mii_data *mii; struct ifmedia *ifm; sc = ifp->if_softc; mii = device_get_softc(sc->dc_miibus); mii_mediachg(mii); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc) && IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) dc_setcfg(sc, ifm->ifm_media); else sc->dc_link = 0; return (0); } /* * Report current media status. */ static void dc_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct dc_softc *sc; struct mii_data *mii; struct ifmedia *ifm; sc = ifp->if_softc; mii = device_get_softc(sc->dc_miibus); mii_pollstat(mii); ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc)) { if (IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) { ifmr->ifm_active = ifm->ifm_media; ifmr->ifm_status = 0; return; } } ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; } static int dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct dc_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; struct mii_data *mii; int error = 0; DC_LOCK(sc); switch (command) { case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { int need_setfilt = (ifp->if_flags ^ sc->dc_if_flags) & (IFF_PROMISC | IFF_ALLMULTI); if (ifp->if_flags & IFF_RUNNING) { if (need_setfilt) dc_setfilt(sc); } else { sc->dc_txthresh = 0; dc_init(sc); } } else { if (ifp->if_flags & IFF_RUNNING) dc_stop(sc); } sc->dc_if_flags = ifp->if_flags; error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: dc_setfilt(sc); error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: mii = device_get_softc(sc->dc_miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); #ifdef SRM_MEDIA if (sc->dc_srm_media) sc->dc_srm_media = 0; #endif break; default: error = ether_ioctl(ifp, command, data); break; } DC_UNLOCK(sc); return (error); } static void dc_watchdog(struct ifnet *ifp) { struct dc_softc *sc; sc = ifp->if_softc; DC_LOCK(sc); ifp->if_oerrors++; printf("dc%d: watchdog timeout\n", sc->dc_unit); dc_stop(sc); dc_reset(sc); dc_init(sc); if (ifp->if_snd.ifq_head != NULL) dc_start(ifp); DC_UNLOCK(sc); } /* * Stop the adapter and free any mbufs allocated to the * RX and TX lists. */ static void dc_stop(struct dc_softc *sc) { struct ifnet *ifp; struct dc_list_data *ld; struct dc_chain_data *cd; int i; u_int32_t ctl; DC_LOCK(sc); ifp = &sc->arpcom.ac_if; ifp->if_timer = 0; ld = sc->dc_ldata; cd = &sc->dc_cdata; callout_stop(&sc->dc_stat_ch); ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); #ifdef DEVICE_POLLING ether_poll_deregister(ifp); #endif DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON | DC_NETCFG_TX_ON)); CSR_WRITE_4(sc, DC_IMR, 0x00000000); CSR_WRITE_4(sc, DC_TXADDR, 0x00000000); CSR_WRITE_4(sc, DC_RXADDR, 0x00000000); sc->dc_link = 0; /* * Free data in the RX lists. */ for (i = 0; i < DC_RX_LIST_CNT; i++) { if (cd->dc_rx_chain[i] != NULL) { m_freem(cd->dc_rx_chain[i]); cd->dc_rx_chain[i] = NULL; } } bzero(&ld->dc_rx_list, sizeof(ld->dc_rx_list)); /* * Free the TX list buffers. */ for (i = 0; i < DC_TX_LIST_CNT; i++) { if (cd->dc_tx_chain[i] != NULL) { ctl = le32toh(ld->dc_tx_list[i].dc_ctl); if ((ctl & DC_TXCTL_SETUP) || !(ctl & DC_TXCTL_FIRSTFRAG)) { cd->dc_tx_chain[i] = NULL; continue; } bus_dmamap_unload(sc->dc_mtag, cd->dc_tx_map[i]); m_freem(cd->dc_tx_chain[i]); cd->dc_tx_chain[i] = NULL; } } bzero(&ld->dc_tx_list, sizeof(ld->dc_tx_list)); DC_UNLOCK(sc); } /* * Device suspend routine. Stop the interface and save some PCI * settings in case the BIOS doesn't restore them properly on * resume. */ static int dc_suspend(device_t dev) { struct dc_softc *sc; int i, s; s = splimp(); sc = device_get_softc(dev); dc_stop(sc); for (i = 0; i < 5; i++) sc->saved_maps[i] = pci_read_config(dev, PCIR_BAR(i), 4); sc->saved_biosaddr = pci_read_config(dev, PCIR_BIOS, 4); sc->saved_intline = pci_read_config(dev, PCIR_INTLINE, 1); sc->saved_cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); sc->saved_lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); sc->suspended = 1; splx(s); return (0); } /* * Device resume routine. Restore some PCI settings in case the BIOS * doesn't, re-enable busmastering, and restart the interface if * appropriate. */ static int dc_resume(device_t dev) { struct dc_softc *sc; struct ifnet *ifp; int i, s; s = splimp(); sc = device_get_softc(dev); ifp = &sc->arpcom.ac_if; #ifndef BURN_BRIDGES dc_acpi(dev); #endif /* better way to do this? */ for (i = 0; i < 5; i++) pci_write_config(dev, PCIR_BAR(i), sc->saved_maps[i], 4); pci_write_config(dev, PCIR_BIOS, sc->saved_biosaddr, 4); pci_write_config(dev, PCIR_INTLINE, sc->saved_intline, 1); pci_write_config(dev, PCIR_CACHELNSZ, sc->saved_cachelnsz, 1); pci_write_config(dev, PCIR_LATTIMER, sc->saved_lattimer, 1); /* reenable busmastering */ pci_enable_busmaster(dev); pci_enable_io(dev, DC_RES); /* reinitialize interface if necessary */ if (ifp->if_flags & IFF_UP) dc_init(sc); sc->suspended = 0; splx(s); return (0); } /* * Stop all chip I/O so that the kernel's probe routines don't * get confused by errant DMAs when rebooting. */ static void dc_shutdown(device_t dev) { struct dc_softc *sc; sc = device_get_softc(dev); dc_stop(sc); } Index: head/sys/pci/if_dcreg.h =================================================================== --- head/sys/pci/if_dcreg.h (revision 123165) +++ head/sys/pci/if_dcreg.h (revision 123166) @@ -1,1229 +1,1230 @@ /* * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * 21143 and clone common register definitions. */ #define DC_BUSCTL 0x00 /* bus control */ #define DC_TXSTART 0x08 /* tx start demand */ #define DC_RXSTART 0x10 /* rx start demand */ #define DC_RXADDR 0x18 /* rx descriptor list start addr */ #define DC_TXADDR 0x20 /* tx descriptor list start addr */ #define DC_ISR 0x28 /* interrupt status register */ #define DC_NETCFG 0x30 /* network config register */ #define DC_IMR 0x38 /* interrupt mask */ #define DC_FRAMESDISCARDED 0x40 /* # of discarded frames */ #define DC_SIO 0x48 /* MII and ROM/EEPROM access */ #define DC_ROM 0x50 /* ROM programming address */ #define DC_TIMER 0x58 /* general timer */ #define DC_10BTSTAT 0x60 /* SIA status */ #define DC_SIARESET 0x68 /* SIA connectivity */ #define DC_10BTCTRL 0x70 /* SIA transmit and receive */ #define DC_WATCHDOG 0x78 /* SIA and general purpose port */ #define DC_SIAGP 0x78 /* SIA and general purpose port (X3201) */ /* * There are two general 'types' of MX chips that we need to be * concerned with. One is the original 98713, which has its internal * NWAY support controlled via the MDIO bits in the serial I/O * register. The other is everything else (from the 98713A on up), * which has its internal NWAY controlled via CSR13, CSR14 and CSR15, * just like the 21143. This type setting also governs which of the * 'magic' numbers we write to CSR16. The PNIC II falls into the * 98713A/98715/98715A/98725 category. */ #define DC_TYPE_98713 0x1 #define DC_TYPE_98713A 0x2 #define DC_TYPE_987x5 0x3 /* Other type of supported chips. */ #define DC_TYPE_21143 0x4 /* Intel 21143 */ #define DC_TYPE_ASIX 0x5 /* ASIX AX88140A/AX88141 */ #define DC_TYPE_AL981 0x6 /* ADMtek AL981 Comet */ #define DC_TYPE_AN985 0x7 /* ADMtek AN985 Centaur */ #define DC_TYPE_DM9102 0x8 /* Davicom DM9102 */ #define DC_TYPE_PNICII 0x9 /* 82c115 PNIC II */ #define DC_TYPE_PNIC 0xA /* 82c168/82c169 PNIC I */ #define DC_TYPE_XIRCOM 0xB /* Xircom X3201 */ #define DC_TYPE_CONEXANT 0xC /* Conexant LANfinity RS7112 */ #define DC_IS_MACRONIX(x) \ (x->dc_type == DC_TYPE_98713 || \ x->dc_type == DC_TYPE_98713A || \ x->dc_type == DC_TYPE_987x5) #define DC_IS_ADMTEK(x) \ (x->dc_type == DC_TYPE_AL981 || \ x->dc_type == DC_TYPE_AN985) #define DC_IS_INTEL(x) (x->dc_type == DC_TYPE_21143) #define DC_IS_ASIX(x) (x->dc_type == DC_TYPE_ASIX) #define DC_IS_COMET(x) (x->dc_type == DC_TYPE_AL981) #define DC_IS_CENTAUR(x) (x->dc_type == DC_TYPE_AN985) #define DC_IS_DAVICOM(x) (x->dc_type == DC_TYPE_DM9102) #define DC_IS_PNICII(x) (x->dc_type == DC_TYPE_PNICII) #define DC_IS_PNIC(x) (x->dc_type == DC_TYPE_PNIC) #define DC_IS_XIRCOM(x) (x->dc_type == DC_TYPE_XIRCOM) #define DC_IS_CONEXANT(x) (x->dc_type == DC_TYPE_CONEXANT) /* MII/symbol mode port types */ #define DC_PMODE_MII 0x1 #define DC_PMODE_SYM 0x2 #define DC_PMODE_SIA 0x3 /* * Bus control bits. */ #define DC_BUSCTL_RESET 0x00000001 #define DC_BUSCTL_ARBITRATION 0x00000002 #define DC_BUSCTL_SKIPLEN 0x0000007C #define DC_BUSCTL_BUF_BIGENDIAN 0x00000080 #define DC_BUSCTL_BURSTLEN 0x00003F00 #define DC_BUSCTL_CACHEALIGN 0x0000C000 #define DC_BUSCTL_TXPOLL 0x000E0000 #define DC_BUSCTL_DBO 0x00100000 #define DC_BUSCTL_MRME 0x00200000 #define DC_BUSCTL_MRLE 0x00800000 #define DC_BUSCTL_MWIE 0x01000000 #define DC_BUSCTL_ONNOW_ENB 0x04000000 #define DC_SKIPLEN_1LONG 0x00000004 #define DC_SKIPLEN_2LONG 0x00000008 #define DC_SKIPLEN_3LONG 0x00000010 #define DC_SKIPLEN_4LONG 0x00000020 #define DC_SKIPLEN_5LONG 0x00000040 #define DC_CACHEALIGN_NONE 0x00000000 #define DC_CACHEALIGN_8LONG 0x00004000 #define DC_CACHEALIGN_16LONG 0x00008000 #define DC_CACHEALIGN_32LONG 0x0000C000 #define DC_BURSTLEN_USECA 0x00000000 #define DC_BURSTLEN_1LONG 0x00000100 #define DC_BURSTLEN_2LONG 0x00000200 #define DC_BURSTLEN_4LONG 0x00000400 #define DC_BURSTLEN_8LONG 0x00000800 #define DC_BURSTLEN_16LONG 0x00001000 #define DC_BURSTLEN_32LONG 0x00002000 #define DC_TXPOLL_OFF 0x00000000 #define DC_TXPOLL_1 0x00020000 #define DC_TXPOLL_2 0x00040000 #define DC_TXPOLL_3 0x00060000 #define DC_TXPOLL_4 0x00080000 #define DC_TXPOLL_5 0x000A0000 #define DC_TXPOLL_6 0x000C0000 #define DC_TXPOLL_7 0x000E0000 /* * Interrupt status bits. */ #define DC_ISR_TX_OK 0x00000001 #define DC_ISR_TX_IDLE 0x00000002 #define DC_ISR_TX_NOBUF 0x00000004 #define DC_ISR_TX_JABBERTIMEO 0x00000008 #define DC_ISR_LINKGOOD 0x00000010 #define DC_ISR_TX_UNDERRUN 0x00000020 #define DC_ISR_RX_OK 0x00000040 #define DC_ISR_RX_NOBUF 0x00000080 #define DC_ISR_RX_READ 0x00000100 #define DC_ISR_RX_WATDOGTIMEO 0x00000200 #define DC_ISR_TX_EARLY 0x00000400 #define DC_ISR_TIMER_EXPIRED 0x00000800 #define DC_ISR_LINKFAIL 0x00001000 #define DC_ISR_BUS_ERR 0x00002000 #define DC_ISR_RX_EARLY 0x00004000 #define DC_ISR_ABNORMAL 0x00008000 #define DC_ISR_NORMAL 0x00010000 #define DC_ISR_RX_STATE 0x000E0000 #define DC_ISR_TX_STATE 0x00700000 #define DC_ISR_BUSERRTYPE 0x03800000 #define DC_ISR_100MBPSLINK 0x08000000 #define DC_ISR_MAGICKPACK 0x10000000 #define DC_RXSTATE_STOPPED 0x00000000 /* 000 - Stopped */ #define DC_RXSTATE_FETCH 0x00020000 /* 001 - Fetching descriptor */ #define DC_RXSTATE_ENDCHECK 0x00040000 /* 010 - check for rx end */ #define DC_RXSTATE_WAIT 0x00060000 /* 011 - waiting for packet */ #define DC_RXSTATE_SUSPEND 0x00080000 /* 100 - suspend rx */ #define DC_RXSTATE_CLOSE 0x000A0000 /* 101 - close tx desc */ #define DC_RXSTATE_FLUSH 0x000C0000 /* 110 - flush from FIFO */ #define DC_RXSTATE_DEQUEUE 0x000E0000 /* 111 - dequeue from FIFO */ #define DC_TXSTATE_RESET 0x00000000 /* 000 - reset */ #define DC_TXSTATE_FETCH 0x00100000 /* 001 - fetching descriptor */ #define DC_TXSTATE_WAITEND 0x00200000 /* 010 - wait for tx end */ #define DC_TXSTATE_READING 0x00300000 /* 011 - read and enqueue */ #define DC_TXSTATE_RSVD 0x00400000 /* 100 - reserved */ #define DC_TXSTATE_SETUP 0x00500000 /* 101 - setup packet */ #define DC_TXSTATE_SUSPEND 0x00600000 /* 110 - suspend tx */ #define DC_TXSTATE_CLOSE 0x00700000 /* 111 - close tx desc */ /* * Network config bits. */ #define DC_NETCFG_RX_HASHPERF 0x00000001 #define DC_NETCFG_RX_ON 0x00000002 #define DC_NETCFG_RX_HASHONLY 0x00000004 #define DC_NETCFG_RX_BADFRAMES 0x00000008 #define DC_NETCFG_RX_INVFILT 0x00000010 #define DC_NETCFG_BACKOFFCNT 0x00000020 #define DC_NETCFG_RX_PROMISC 0x00000040 #define DC_NETCFG_RX_ALLMULTI 0x00000080 #define DC_NETCFG_FULLDUPLEX 0x00000200 #define DC_NETCFG_LOOPBACK 0x00000C00 #define DC_NETCFG_FORCECOLL 0x00001000 #define DC_NETCFG_TX_ON 0x00002000 #define DC_NETCFG_TX_THRESH 0x0000C000 #define DC_NETCFG_TX_BACKOFF 0x00020000 #define DC_NETCFG_PORTSEL 0x00040000 /* 0 == 10, 1 == 100 */ #define DC_NETCFG_HEARTBEAT 0x00080000 #define DC_NETCFG_STORENFWD 0x00200000 #define DC_NETCFG_SPEEDSEL 0x00400000 /* 1 == 10, 0 == 100 */ #define DC_NETCFG_PCS 0x00800000 #define DC_NETCFG_SCRAMBLER 0x01000000 #define DC_NETCFG_NO_RXCRC 0x02000000 #define DC_NETCFG_RX_ALL 0x40000000 #define DC_NETCFG_CAPEFFECT 0x80000000 #define DC_OPMODE_NORM 0x00000000 #define DC_OPMODE_INTLOOP 0x00000400 #define DC_OPMODE_EXTLOOP 0x00000800 #if 0 #define DC_TXTHRESH_72BYTES 0x00000000 #define DC_TXTHRESH_96BYTES 0x00004000 #define DC_TXTHRESH_128BYTES 0x00008000 #define DC_TXTHRESH_160BYTES 0x0000C000 #endif #define DC_TXTHRESH_MIN 0x00000000 #define DC_TXTHRESH_INC 0x00004000 #define DC_TXTHRESH_MAX 0x0000C000 /* * Interrupt mask bits. */ #define DC_IMR_TX_OK 0x00000001 #define DC_IMR_TX_IDLE 0x00000002 #define DC_IMR_TX_NOBUF 0x00000004 #define DC_IMR_TX_JABBERTIMEO 0x00000008 #define DC_IMR_LINKGOOD 0x00000010 #define DC_IMR_TX_UNDERRUN 0x00000020 #define DC_IMR_RX_OK 0x00000040 #define DC_IMR_RX_NOBUF 0x00000080 #define DC_IMR_RX_READ 0x00000100 #define DC_IMR_RX_WATDOGTIMEO 0x00000200 #define DC_IMR_TX_EARLY 0x00000400 #define DC_IMR_TIMER_EXPIRED 0x00000800 #define DC_IMR_LINKFAIL 0x00001000 #define DC_IMR_BUS_ERR 0x00002000 #define DC_IMR_RX_EARLY 0x00004000 #define DC_IMR_ABNORMAL 0x00008000 #define DC_IMR_NORMAL 0x00010000 #define DC_IMR_100MBPSLINK 0x08000000 #define DC_IMR_MAGICKPACK 0x10000000 #define DC_INTRS \ (DC_IMR_RX_OK|DC_IMR_TX_OK|DC_IMR_RX_NOBUF|DC_IMR_RX_WATDOGTIMEO|\ DC_IMR_TX_NOBUF|DC_IMR_TX_UNDERRUN|DC_IMR_BUS_ERR| \ DC_IMR_ABNORMAL|DC_IMR_NORMAL/*|DC_IMR_TX_EARLY*/) /* * Serial I/O (EEPROM/ROM) bits. */ #define DC_SIO_EE_CS 0x00000001 /* EEPROM chip select */ #define DC_SIO_EE_CLK 0x00000002 /* EEPROM clock */ #define DC_SIO_EE_DATAIN 0x00000004 /* EEPROM data output */ #define DC_SIO_EE_DATAOUT 0x00000008 /* EEPROM data input */ #define DC_SIO_ROMDATA4 0x00000010 #define DC_SIO_ROMDATA5 0x00000020 #define DC_SIO_ROMDATA6 0x00000040 #define DC_SIO_ROMDATA7 0x00000080 #define DC_SIO_EESEL 0x00000800 #define DC_SIO_ROMSEL 0x00001000 #define DC_SIO_ROMCTL_WRITE 0x00002000 #define DC_SIO_ROMCTL_READ 0x00004000 #define DC_SIO_MII_CLK 0x00010000 /* MDIO clock */ #define DC_SIO_MII_DATAOUT 0x00020000 /* MDIO data out */ #define DC_SIO_MII_DIR 0x00040000 /* MDIO dir */ #define DC_SIO_MII_DATAIN 0x00080000 /* MDIO data in */ #define DC_EECMD_WRITE 0x140 #define DC_EECMD_READ 0x180 #define DC_EECMD_ERASE 0x1c0 #define DC_EE_NODEADDR_OFFSET 0x70 #define DC_EE_NODEADDR 10 /* * General purpose timer register */ #define DC_TIMER_VALUE 0x0000FFFF #define DC_TIMER_CONTINUOUS 0x00010000 /* * 10baseT status register */ #define DC_TSTAT_MIIACT 0x00000001 /* MII port activity */ #define DC_TSTAT_LS100 0x00000002 /* link status of 100baseTX */ #define DC_TSTAT_LS10 0x00000004 /* link status of 10baseT */ #define DC_TSTAT_AUTOPOLARITY 0x00000008 #define DC_TSTAT_AUIACT 0x00000100 /* AUI activity */ #define DC_TSTAT_10BTACT 0x00000200 /* 10baseT activity */ #define DC_TSTAT_NSN 0x00000400 /* non-stable FLPs detected */ #define DC_TSTAT_REMFAULT 0x00000800 #define DC_TSTAT_ANEGSTAT 0x00007000 #define DC_TSTAT_LP_CAN_NWAY 0x00008000 /* link partner supports NWAY */ #define DC_TSTAT_LPCODEWORD 0xFFFF0000 /* link partner's code word */ #define DC_ASTAT_DISABLE 0x00000000 #define DC_ASTAT_TXDISABLE 0x00001000 #define DC_ASTAT_ABDETECT 0x00002000 #define DC_ASTAT_ACKDETECT 0x00003000 #define DC_ASTAT_CMPACKDETECT 0x00004000 #define DC_ASTAT_AUTONEGCMP 0x00005000 #define DC_ASTAT_LINKCHECK 0x00006000 /* * PHY reset register */ #define DC_SIA_RESET 0x00000001 #define DC_SIA_AUI 0x00000008 /* AUI or 10baseT */ /* * 10baseT control register */ #define DC_TCTL_ENCODER_ENB 0x00000001 #define DC_TCTL_LOOPBACK 0x00000002 #define DC_TCTL_DRIVER_ENB 0x00000004 #define DC_TCTL_LNKPULSE_ENB 0x00000008 #define DC_TCTL_HALFDUPLEX 0x00000040 #define DC_TCTL_AUTONEGENBL 0x00000080 #define DC_TCTL_RX_SQUELCH 0x00000100 #define DC_TCTL_COLL_SQUELCH 0x00000200 #define DC_TCTL_COLL_DETECT 0x00000400 #define DC_TCTL_SQE_ENB 0x00000800 #define DC_TCTL_LINKTEST 0x00001000 #define DC_TCTL_AUTOPOLARITY 0x00002000 #define DC_TCTL_SET_POL_PLUS 0x00004000 #define DC_TCTL_AUTOSENSE 0x00008000 /* 10bt/AUI autosense */ #define DC_TCTL_100BTXHALF 0x00010000 #define DC_TCTL_100BTXFULL 0x00020000 #define DC_TCTL_100BT4 0x00040000 /* * Watchdog timer register */ #define DC_WDOG_JABBERDIS 0x00000001 #define DC_WDOG_HOSTUNJAB 0x00000002 #define DC_WDOG_JABBERCLK 0x00000004 #define DC_WDOG_RXWDOGDIS 0x00000010 #define DC_WDOG_RXWDOGCLK 0x00000020 #define DC_WDOG_MUSTBEZERO 0x00000100 #define DC_WDOG_AUIBNC 0x00100000 #define DC_WDOG_ACTIVITY 0x00200000 #define DC_WDOG_RX_MATCH 0x00400000 #define DC_WDOG_LINK 0x00800000 #define DC_WDOG_CTLWREN 0x08000000 /* * SIA and General Purpose Port register (X3201) */ #define DC_SIAGP_RXMATCH 0x40000000 #define DC_SIAGP_INT1 0x20000000 #define DC_SIAGP_INT0 0x10000000 #define DC_SIAGP_WRITE_EN 0x08000000 #define DC_SIAGP_RXMATCH_EN 0x04000000 #define DC_SIAGP_INT1_EN 0x02000000 #define DC_SIAGP_INT0_EN 0x01000000 #define DC_SIAGP_LED3 0x00800000 #define DC_SIAGP_LED2 0x00400000 #define DC_SIAGP_LED1 0x00200000 #define DC_SIAGP_LED0 0x00100000 #define DC_SIAGP_MD_GP3_OUTPUT 0x00080000 #define DC_SIAGP_MD_GP2_OUTPUT 0x00040000 #define DC_SIAGP_MD_GP1_OUTPUT 0x00020000 #define DC_SIAGP_MD_GP0_OUTPUT 0x00010000 /* * Size of a setup frame. */ #define DC_SFRAME_LEN 192 /* * 21x4x TX/RX list structure. */ struct dc_desc { u_int32_t dc_status; u_int32_t dc_ctl; u_int32_t dc_ptr1; u_int32_t dc_ptr2; }; #define dc_data dc_ptr1 #define dc_next dc_ptr2 #define DC_RXSTAT_FIFOOFLOW 0x00000001 #define DC_RXSTAT_CRCERR 0x00000002 #define DC_RXSTAT_DRIBBLE 0x00000004 #define DC_RXSTAT_MIIERE 0x00000008 #define DC_RXSTAT_WATCHDOG 0x00000010 #define DC_RXSTAT_FRAMETYPE 0x00000020 /* 0 == IEEE 802.3 */ #define DC_RXSTAT_COLLSEEN 0x00000040 #define DC_RXSTAT_GIANT 0x00000080 #define DC_RXSTAT_LASTFRAG 0x00000100 #define DC_RXSTAT_FIRSTFRAG 0x00000200 #define DC_RXSTAT_MULTICAST 0x00000400 #define DC_RXSTAT_RUNT 0x00000800 #define DC_RXSTAT_RXTYPE 0x00003000 #define DC_RXSTAT_DE 0x00004000 #define DC_RXSTAT_RXERR 0x00008000 #define DC_RXSTAT_RXLEN 0x3FFF0000 #define DC_RXSTAT_OWN 0x80000000 #define DC_RXBYTES(x) ((x & DC_RXSTAT_RXLEN) >> 16) #define DC_RXSTAT (DC_RXSTAT_FIRSTFRAG|DC_RXSTAT_LASTFRAG|DC_RXSTAT_OWN) #define DC_RXCTL_BUFLEN1 0x00000FFF #define DC_RXCTL_BUFLEN2 0x00FFF000 #define DC_RXCTL_RLINK 0x01000000 #define DC_RXCTL_RLAST 0x02000000 #define DC_TXSTAT_DEFER 0x00000001 #define DC_TXSTAT_UNDERRUN 0x00000002 #define DC_TXSTAT_LINKFAIL 0x00000003 #define DC_TXSTAT_COLLCNT 0x00000078 #define DC_TXSTAT_SQE 0x00000080 #define DC_TXSTAT_EXCESSCOLL 0x00000100 #define DC_TXSTAT_LATECOLL 0x00000200 #define DC_TXSTAT_NOCARRIER 0x00000400 #define DC_TXSTAT_CARRLOST 0x00000800 #define DC_TXSTAT_JABTIMEO 0x00004000 #define DC_TXSTAT_ERRSUM 0x00008000 #define DC_TXSTAT_OWN 0x80000000 #define DC_TXCTL_BUFLEN1 0x000007FF #define DC_TXCTL_BUFLEN2 0x003FF800 #define DC_TXCTL_FILTTYPE0 0x00400000 #define DC_TXCTL_PAD 0x00800000 #define DC_TXCTL_TLINK 0x01000000 #define DC_TXCTL_TLAST 0x02000000 #define DC_TXCTL_NOCRC 0x04000000 #define DC_TXCTL_SETUP 0x08000000 #define DC_TXCTL_FILTTYPE1 0x10000000 #define DC_TXCTL_FIRSTFRAG 0x20000000 #define DC_TXCTL_LASTFRAG 0x40000000 #define DC_TXCTL_FINT 0x80000000 #define DC_FILTER_PERFECT 0x00000000 #define DC_FILTER_HASHPERF 0x00400000 #define DC_FILTER_INVERSE 0x10000000 #define DC_FILTER_HASHONLY 0x10400000 #define DC_MAXFRAGS 16 #ifdef DEVICE_POLLING #define DC_RX_LIST_CNT 192 #else #define DC_RX_LIST_CNT 64 #endif #define DC_TX_LIST_CNT 256 #define DC_MIN_FRAMELEN 60 #define DC_RXLEN 1536 #define DC_INC(x, y) (x) = (x + 1) % y /* Macros to easily get the DMA address of a descriptor. */ #define DC_RXDESC(sc, i) (sc->dc_laddr + \ (uintptr_t)(sc->dc_ldata->dc_rx_list + i) - (uintptr_t)sc->dc_ldata) #define DC_TXDESC(sc, i) (sc->dc_laddr + \ (uintptr_t)(sc->dc_ldata->dc_tx_list + i) - (uintptr_t)sc->dc_ldata) #if BYTE_ORDER == BIG_ENDIAN #define DC_SP_MAC(x) ((x) << 16) #else #define DC_SP_MAC(x) (x) #endif struct dc_list_data { struct dc_desc dc_rx_list[DC_RX_LIST_CNT]; struct dc_desc dc_tx_list[DC_TX_LIST_CNT]; }; struct dc_chain_data { struct mbuf *dc_rx_chain[DC_RX_LIST_CNT]; struct mbuf *dc_tx_chain[DC_TX_LIST_CNT]; bus_dmamap_t dc_rx_map[DC_RX_LIST_CNT]; bus_dmamap_t dc_tx_map[DC_TX_LIST_CNT]; u_int32_t *dc_sbuf; u_int8_t dc_pad[DC_MIN_FRAMELEN]; int dc_tx_err; int dc_tx_first; int dc_tx_prod; int dc_tx_cons; int dc_tx_cnt; int dc_rx_err; int dc_rx_cur; int dc_rx_prod; }; struct dc_mediainfo { int dc_media; u_int8_t *dc_gp_ptr; u_int8_t dc_gp_len; u_int8_t *dc_reset_ptr; u_int8_t dc_reset_len; struct dc_mediainfo *dc_next; }; struct dc_type { u_int16_t dc_vid; u_int16_t dc_did; char *dc_name; }; struct dc_mii_frame { u_int8_t mii_stdelim; u_int8_t mii_opcode; u_int8_t mii_phyaddr; u_int8_t mii_regaddr; u_int8_t mii_turnaround; u_int16_t mii_data; }; /* * MII constants */ #define DC_MII_STARTDELIM 0x01 #define DC_MII_READOP 0x02 #define DC_MII_WRITEOP 0x01 #define DC_MII_TURNAROUND 0x02 /* * Registers specific to clone devices. * This mainly relates to RX filter programming: not all 21x4x clones * use the standard DEC filter programming mechanism. */ /* * ADMtek specific registers and constants for the AL981 and AN985. * The AN985 doesn't use the magic PHY registers. */ #define DC_AL_CR 0x88 /* command register */ #define DC_AL_PAR0 0xA4 /* station address */ #define DC_AL_PAR1 0xA8 /* station address */ #define DC_AL_MAR0 0xAC /* multicast hash filter */ #define DC_AL_MAR1 0xB0 /* multicast hash filter */ #define DC_AL_BMCR 0xB4 /* built in PHY control */ #define DC_AL_BMSR 0xB8 /* built in PHY status */ #define DC_AL_VENID 0xBC /* built in PHY ID0 */ #define DC_AL_DEVID 0xC0 /* built in PHY ID1 */ #define DC_AL_ANAR 0xC4 /* built in PHY autoneg advert */ #define DC_AL_LPAR 0xC8 /* bnilt in PHY link part. ability */ #define DC_AL_ANER 0xCC /* built in PHY autoneg expansion */ #define DC_AL_CR_ATUR 0x00000001 /* automatic TX underrun recovery */ #define DC_ADMTEK_PHYADDR 0x1 #define DC_AL_EE_NODEADDR 4 /* End of ADMtek specific registers */ /* * ASIX specific registers. */ #define DC_AX_FILTIDX 0x68 /* RX filter index */ #define DC_AX_FILTDATA 0x70 /* RX filter data */ /* * Special ASIX-specific bits in the ASIX NETCFG register (CSR6). */ #define DC_AX_NETCFG_RX_BROAD 0x00000100 /* * RX Filter Index Register values */ #define DC_AX_FILTIDX_PAR0 0x00000000 #define DC_AX_FILTIDX_PAR1 0x00000001 #define DC_AX_FILTIDX_MAR0 0x00000002 #define DC_AX_FILTIDX_MAR1 0x00000003 /* End of ASIX specific registers */ /* * Macronix specific registers. The Macronix chips have a special * register for reading the NWAY status, which we don't use, plus * a magic packet register, which we need to tweak a bit per the * Macronix application notes. */ #define DC_MX_MAGICPACKET 0x80 #define DC_MX_NWAYSTAT 0xA0 /* * Magic packet register */ #define DC_MX_MPACK_DISABLE 0x00400000 /* * NWAY status register. */ #define DC_MX_NWAY_10BTHALF 0x08000000 #define DC_MX_NWAY_10BTFULL 0x10000000 #define DC_MX_NWAY_100BTHALF 0x20000000 #define DC_MX_NWAY_100BTFULL 0x40000000 #define DC_MX_NWAY_100BT4 0x80000000 /* * These are magic values that must be written into CSR16 * (DC_MX_MAGICPACKET) in order to put the chip into proper * operating mode. The magic numbers are documented in the * Macronix 98715 application notes. */ #define DC_MX_MAGIC_98713 0x0F370000 #define DC_MX_MAGIC_98713A 0x0B3C0000 #define DC_MX_MAGIC_98715 0x0B3C0000 #define DC_MX_MAGIC_98725 0x0B3C0000 /* End of Macronix specific registers */ /* * PNIC 82c168/82c169 specific registers. * The PNIC has its own special NWAY support, which doesn't work, * and shortcut ways of reading the EEPROM and MII bus. */ #define DC_PN_GPIO 0x60 /* general purpose pins control */ #define DC_PN_PWRUP_CFG 0x90 /* config register, set by EEPROM */ #define DC_PN_SIOCTL 0x98 /* serial EEPROM control register */ #define DC_PN_MII 0xA0 /* MII access register */ #define DC_PN_NWAY 0xB8 /* Internal NWAY register */ /* Serial I/O EEPROM register */ #define DC_PN_SIOCTL_DATA 0x0000003F #define DC_PN_SIOCTL_OPCODE 0x00000300 #define DC_PN_SIOCTL_BUSY 0x80000000 #define DC_PN_EEOPCODE_ERASE 0x00000300 #define DC_PN_EEOPCODE_READ 0x00000600 #define DC_PN_EEOPCODE_WRITE 0x00000100 /* * The first two general purpose pins control speed selection and * 100Mbps loopback on the 82c168 chip. The control bits should always * be set (to make the data pins outputs) and the speed selction and * loopback bits set accordingly when changing media. Physically, this * will set the state of a relay mounted on the card. */ #define DC_PN_GPIO_DATA0 0x000000001 #define DC_PN_GPIO_DATA1 0x000000002 #define DC_PN_GPIO_DATA2 0x000000004 #define DC_PN_GPIO_DATA3 0x000000008 #define DC_PN_GPIO_CTL0 0x000000010 #define DC_PN_GPIO_CTL1 0x000000020 #define DC_PN_GPIO_CTL2 0x000000040 #define DC_PN_GPIO_CTL3 0x000000080 #define DC_PN_GPIO_SPEEDSEL DC_PN_GPIO_DATA0/* 1 == 100Mbps, 0 == 10Mbps */ #define DC_PN_GPIO_100TX_LOOP DC_PN_GPIO_DATA1/* 1 == normal, 0 == loop */ #define DC_PN_GPIO_BNC_ENB DC_PN_GPIO_DATA2 #define DC_PN_GPIO_100TX_LNK DC_PN_GPIO_DATA3 #define DC_PN_GPIO_SETBIT(sc, r) \ DC_SETBIT(sc, DC_PN_GPIO, ((r) | (r << 4))) #define DC_PN_GPIO_CLRBIT(sc, r) \ { \ DC_SETBIT(sc, DC_PN_GPIO, ((r) << 4)); \ DC_CLRBIT(sc, DC_PN_GPIO, (r)); \ } /* shortcut MII access register */ #define DC_PN_MII_DATA 0x0000FFFF #define DC_PN_MII_RESERVER 0x00020000 #define DC_PN_MII_REGADDR 0x007C0000 #define DC_PN_MII_PHYADDR 0x0F800000 #define DC_PN_MII_OPCODE 0x30000000 #define DC_PN_MII_BUSY 0x80000000 #define DC_PN_MIIOPCODE_READ 0x60020000 #define DC_PN_MIIOPCODE_WRITE 0x50020000 /* Internal NWAY bits */ #define DC_PN_NWAY_RESET 0x00000001 /* reset */ #define DC_PN_NWAY_PDOWN 0x00000002 /* power down */ #define DC_PN_NWAY_BYPASS 0x00000004 /* bypass */ #define DC_PN_NWAY_AUILOWCUR 0x00000008 /* AUI low current */ #define DC_PN_NWAY_TPEXTEND 0x00000010 /* low squelch voltage */ #define DC_PN_NWAY_POLARITY 0x00000020 /* 0 == on, 1 == off */ #define DC_PN_NWAY_TP 0x00000040 /* 1 == tp, 0 == AUI */ #define DC_PN_NWAY_AUIVOLT 0x00000080 /* 1 == full, 0 == half */ #define DC_PN_NWAY_DUPLEX 0x00000100 /* LED, 1 == full, 0 == half */ #define DC_PN_NWAY_LINKTEST 0x00000200 /* 0 == on, 1 == off */ #define DC_PN_NWAY_AUTODETECT 0x00000400 /* 1 == off, 0 == on */ #define DC_PN_NWAY_SPEEDSEL 0x00000800 /* LED, 0 = 10, 1 == 100 */ #define DC_PN_NWAY_NWAY_ENB 0x00001000 /* 0 == off, 1 == on */ #define DC_PN_NWAY_CAP10HDX 0x00002000 #define DC_PN_NWAY_CAP10FDX 0x00004000 #define DC_PN_NWAY_CAP100FDX 0x00008000 #define DC_PN_NWAY_CAP100HDX 0x00010000 #define DC_PN_NWAY_CAP100T4 0x00020000 #define DC_PN_NWAY_ANEGRESTART 0x02000000 /* resets when aneg done */ #define DC_PN_NWAY_REMFAULT 0x04000000 #define DC_PN_NWAY_LPAR10HDX 0x08000000 #define DC_PN_NWAY_LPAR10FDX 0x10000000 #define DC_PN_NWAY_LPAR100FDX 0x20000000 #define DC_PN_NWAY_LPAR100HDX 0x40000000 #define DC_PN_NWAY_LPAR100T4 0x80000000 /* End of PNIC specific registers */ /* * CONEXANT specific registers. */ #define DC_CONEXANT_PHYADDR 0x1 #define DC_CONEXANT_EE_NODEADDR 0x19A /* End of CONEXANT specific registers */ struct dc_softc { struct arpcom arpcom; /* interface info */ bus_space_handle_t dc_bhandle; /* bus space handle */ bus_space_tag_t dc_btag; /* bus space tag */ bus_dma_tag_t dc_ltag; /* tag for descriptor ring */ bus_dmamap_t dc_lmap; /* map for descriptor ring */ u_int32_t dc_laddr; /* DMA address of dc_ldata */ bus_dma_tag_t dc_mtag; /* tag for mbufs */ bus_dmamap_t dc_sparemap; bus_dma_tag_t dc_stag; /* tag for the setup frame */ bus_dmamap_t dc_smap; /* map for the setup frame */ u_int32_t dc_saddr; /* DMA address of setup frame */ void *dc_intrhand; struct resource *dc_irq; struct resource *dc_res; struct dc_type *dc_info; /* adapter info */ device_t dc_miibus; u_int8_t dc_unit; /* interface number */ u_int8_t dc_type; u_int8_t dc_pmode; u_int8_t dc_link; u_int8_t dc_cachesize; int dc_romwidth; int dc_pnic_rx_bug_save; unsigned char *dc_pnic_rx_buf; int dc_if_flags; int dc_if_media; u_int32_t dc_flags; u_int32_t dc_txthresh; u_int8_t *dc_srom; struct dc_mediainfo *dc_mi; struct dc_list_data *dc_ldata; struct dc_chain_data dc_cdata; struct callout dc_stat_ch; #ifdef SRM_MEDIA int dc_srm_media; #endif struct mtx dc_mtx; #ifdef DEVICE_POLLING int rxcycles; /* ... when polling */ #endif int suspended; /* 0 = normal 1 = suspended */ u_int32_t saved_maps[5]; /* pci data */ u_int32_t saved_biosaddr; u_int8_t saved_intline; u_int8_t saved_cachelnsz; u_int8_t saved_lattimer; }; #define DC_LOCK(_sc) mtx_lock(&(_sc)->dc_mtx) #define DC_UNLOCK(_sc) mtx_unlock(&(_sc)->dc_mtx) #define DC_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->dc_mtx, MA_OWNED) #define DC_TX_POLL 0x00000001 #define DC_TX_COALESCE 0x00000002 #define DC_TX_ADMTEK_WAR 0x00000004 #define DC_TX_USE_TX_INTR 0x00000008 #define DC_RX_FILTER_TULIP 0x00000010 #define DC_TX_INTR_FIRSTFRAG 0x00000020 #define DC_PNIC_RX_BUG_WAR 0x00000040 #define DC_TX_FIXED_RING 0x00000080 #define DC_TX_STORENFWD 0x00000100 #define DC_REDUCED_MII_POLL 0x00000200 #define DC_TX_INTR_ALWAYS 0x00000400 #define DC_21143_NWAY 0x00000800 #define DC_128BIT_HASH 0x00001000 #define DC_64BIT_HASH 0x00002000 #define DC_TULIP_LEDS 0x00004000 #define DC_TX_ONE 0x00008000 #define DC_TX_ALIGN 0x00010000 /* align mbuf on tx */ /* * register space access macros */ #define CSR_WRITE_4(sc, reg, val) \ bus_space_write_4(sc->dc_btag, sc->dc_bhandle, reg, val) #define CSR_READ_4(sc, reg) \ bus_space_read_4(sc->dc_btag, sc->dc_bhandle, reg) #define DC_TIMEOUT 1000 #define ETHER_ALIGN 2 /* * General constants that are fun to know. */ /* * DEC PCI vendor ID */ #define DC_VENDORID_DEC 0x1011 /* * DEC/Intel 21143 PCI device ID */ #define DC_DEVICEID_21143 0x0019 /* * Macronix PCI vendor ID */ #define DC_VENDORID_MX 0x10D9 /* * Macronix PMAC device IDs. */ #define DC_DEVICEID_98713 0x0512 #define DC_DEVICEID_987x5 0x0531 #define DC_DEVICEID_98727 0x0532 #define DC_DEVICEID_98732 0x0532 /* Macronix PCI revision codes. */ #define DC_REVISION_98713 0x00 #define DC_REVISION_98713A 0x10 #define DC_REVISION_98715 0x20 #define DC_REVISION_98715AEC_C 0x25 #define DC_REVISION_98725 0x30 /* * Compex PCI vendor ID. */ #define DC_VENDORID_CP 0x11F6 /* * Compex PMAC PCI device IDs. */ #define DC_DEVICEID_98713_CP 0x9881 /* * Lite-On PNIC PCI vendor ID */ #define DC_VENDORID_LO 0x11AD /* * 82c168/82c169 PNIC device IDs. Both chips have the same device * ID but different revisions. Revision 0x10 is the 82c168, and * 0x20 is the 82c169. */ #define DC_DEVICEID_82C168 0x0002 #define DC_REVISION_82C168 0x10 #define DC_REVISION_82C169 0x20 /* * Lite-On PNIC II device ID. Note: this is actually a Macronix 98715A * with wake on lan/magic packet support. */ #define DC_DEVICEID_82C115 0xc115 /* * Davicom vendor ID. */ #define DC_VENDORID_DAVICOM 0x1282 /* * Davicom device IDs. */ #define DC_DEVICEID_DM9009 0x9009 #define DC_DEVICEID_DM9100 0x9100 #define DC_DEVICEID_DM9102 0x9102 /* * The DM9102A has the same PCI device ID as the DM9102, * but a higher revision code. */ #define DC_REVISION_DM9102 0x10 #define DC_REVISION_DM9102A 0x30 /* * ADMtek vendor ID. */ #define DC_VENDORID_ADMTEK 0x1317 /* * ADMtek device IDs. */ #define DC_DEVICEID_AL981 0x0981 #define DC_DEVICEID_AN985 0x0985 #define DC_DEVICEID_FA511 0x1985 #define DC_DEVICEID_ADM9511 0x9511 #define DC_DEVICEID_ADM9513 0x9513 /* * 3COM PCI vendor ID */ #define DC_VENDORID_3COM 0x10b7 /* * 3COM OfficeConnect 10/100B (3CSOHO100B-TX) */ #define DC_DEVICEID_3CSOHOB 0x9300 /* * ASIX vendor ID. */ #define DC_VENDORID_ASIX 0x125B /* * ASIX device IDs. */ #define DC_DEVICEID_AX88140A 0x1400 /* * The ASIX AX88140 and ASIX AX88141 have the same vendor and * device IDs but different revision values. */ #define DC_REVISION_88140 0x00 #define DC_REVISION_88141 0x10 /* * Accton vendor ID. */ #define DC_VENDORID_ACCTON 0x1113 /* * Accton device IDs. */ #define DC_DEVICEID_EN1217 0x1217 #define DC_DEVICEID_EN2242 0x1216 /* * Xircom vendor ID */ #define DC_VENDORID_XIRCOM 0x115d /* * Xircom device IDs. */ #define DC_DEVICEID_X3201 0x0003 /* * Abocom vendor ID */ #define DC_VENDORID_ABOCOM 0x13d1 /* * Abocom device IDs. */ #define DC_DEVICEID_FE2500 0xAB02 +#define DC_DEVICEID_FE2500MX 0xab08 /* * Conexant vendor ID. */ #define DC_VENDORID_CONEXANT 0x14f1 /* * Conexant device IDs. */ #define DC_DEVICEID_RS7112 0x1803 /* * Planex vendor ID */ #define DC_VENDORID_PLANEX 0x14ea /* * Planex device IDs. */ #define DC_DEVICEID_FNW3602T 0xab08 /* * Not sure who this vendor should be, so we'll go with HAWKING until * I can locate the right one. */ #define DC_VENDORID_HAWKING 0x17b3 /* * Sure looks like an abocom device ID, but it found on my hawking PN672TX * card. Use that for now, and upgrade later. */ #define DC_DEVICEID_HAWKING_PN672TX 0xab08 /* * Microsoft device ID. */ #define DC_VENDORID_MICROSOFT 0x1414 /* * Supported Microsoft PCI and cardbus NICs. These are really * ADMtek parts in disguise. */ #define DC_DEVICEID_MSMN120 0x0001 #define DC_DEVICEID_MSMN130 0x0002 #define DC_DEVICEID_MSMN130_FAKE 0xFFF2 /* * PCI low memory base and low I/O base register, and * other PCI registers. */ #define DC_PCI_CFID 0x00 /* Id */ #define DC_PCI_CFCS 0x04 /* Command and status */ #define DC_PCI_CFRV 0x08 /* Revision */ #define DC_PCI_CFLT 0x0C /* Latency timer */ #define DC_PCI_CFBIO 0x10 /* Base I/O address */ #define DC_PCI_CFBMA 0x14 /* Base memory address */ #define DC_PCI_CCIS 0x28 /* Card info struct */ #define DC_PCI_CSID 0x2C /* Subsystem ID */ #define DC_PCI_CBER 0x30 /* Expansion ROM base address */ #define DC_PCI_CCAP 0x34 /* Caps pointer - PD/TD chip only */ #define DC_PCI_CFIT 0x3C /* Interrupt */ #define DC_PCI_CFDD 0x40 /* Device and driver area */ #define DC_PCI_CWUA0 0x44 /* Wake-Up LAN addr 0 */ #define DC_PCI_CWUA1 0x48 /* Wake-Up LAN addr 1 */ #define DC_PCI_SOP0 0x4C /* SecureON passwd 0 */ #define DC_PCI_SOP1 0x50 /* SecureON passwd 1 */ #define DC_PCI_CWUC 0x54 /* Configuration Wake-Up cmd */ #define DC_PCI_CCID 0xDC /* Capability ID - PD/TD only */ #define DC_PCI_CPMC 0xE0 /* Pwrmgmt ctl & sts - PD/TD only */ /* PCI ID register */ #define DC_CFID_VENDOR 0x0000FFFF #define DC_CFID_DEVICE 0xFFFF0000 /* PCI command/status register */ #define DC_CFCS_IOSPACE 0x00000001 /* I/O space enable */ #define DC_CFCS_MEMSPACE 0x00000002 /* memory space enable */ #define DC_CFCS_BUSMASTER 0x00000004 /* bus master enable */ #define DC_CFCS_MWI_ENB 0x00000010 /* mem write and inval enable */ #define DC_CFCS_PARITYERR_ENB 0x00000040 /* parity error enable */ #define DC_CFCS_SYSERR_ENB 0x00000100 /* system error enable */ #define DC_CFCS_NEWCAPS 0x00100000 /* new capabilities */ #define DC_CFCS_FAST_B2B 0x00800000 /* fast back-to-back capable */ #define DC_CFCS_DATAPARITY 0x01000000 /* Parity error report */ #define DC_CFCS_DEVSELTIM 0x06000000 /* devsel timing */ #define DC_CFCS_TGTABRT 0x10000000 /* received target abort */ #define DC_CFCS_MASTERABRT 0x20000000 /* received master abort */ #define DC_CFCS_SYSERR 0x40000000 /* asserted system error */ #define DC_CFCS_PARITYERR 0x80000000 /* asserted parity error */ /* PCI revision register */ #define DC_CFRV_STEPPING 0x0000000F #define DC_CFRV_REVISION 0x000000F0 #define DC_CFRV_SUBCLASS 0x00FF0000 #define DC_CFRV_BASECLASS 0xFF000000 #define DC_21143_PB_REV 0x00000030 #define DC_21143_TB_REV 0x00000030 #define DC_21143_PC_REV 0x00000030 #define DC_21143_TC_REV 0x00000030 #define DC_21143_PD_REV 0x00000041 #define DC_21143_TD_REV 0x00000041 /* PCI latency timer register */ #define DC_CFLT_CACHELINESIZE 0x000000FF #define DC_CFLT_LATENCYTIMER 0x0000FF00 /* PCI subsystem ID register */ #define DC_CSID_VENDOR 0x0000FFFF #define DC_CSID_DEVICE 0xFFFF0000 /* PCI cababilities pointer */ #define DC_CCAP_OFFSET 0x000000FF /* PCI interrupt config register */ #define DC_CFIT_INTLINE 0x000000FF #define DC_CFIT_INTPIN 0x0000FF00 #define DC_CFIT_MIN_GNT 0x00FF0000 #define DC_CFIT_MAX_LAT 0xFF000000 /* PCI capability register */ #define DC_CCID_CAPID 0x000000FF #define DC_CCID_NEXTPTR 0x0000FF00 #define DC_CCID_PM_VERS 0x00070000 #define DC_CCID_PME_CLK 0x00080000 #define DC_CCID_DVSPEC_INT 0x00200000 #define DC_CCID_STATE_D1 0x02000000 #define DC_CCID_STATE_D2 0x04000000 #define DC_CCID_PME_D0 0x08000000 #define DC_CCID_PME_D1 0x10000000 #define DC_CCID_PME_D2 0x20000000 #define DC_CCID_PME_D3HOT 0x40000000 #define DC_CCID_PME_D3COLD 0x80000000 /* PCI power management control/status register */ #define DC_CPMC_STATE 0x00000003 #define DC_CPMC_PME_ENB 0x00000100 #define DC_CPMC_PME_STS 0x00008000 #define DC_PSTATE_D0 0x0 #define DC_PSTATE_D1 0x1 #define DC_PSTATE_D2 0x2 #define DC_PSTATE_D3 0x3 /* Device specific region */ /* Configuration and driver area */ #define DC_CFDD_DRVUSE 0x0000FFFF #define DC_CFDD_SNOOZE_MODE 0x40000000 #define DC_CFDD_SLEEP_MODE 0x80000000 /* Configuration wake-up command register */ #define DC_CWUC_MUST_BE_ZERO 0x00000001 #define DC_CWUC_SECUREON_ENB 0x00000002 #define DC_CWUC_FORCE_WUL 0x00000004 #define DC_CWUC_BNC_ABILITY 0x00000008 #define DC_CWUC_AUI_ABILITY 0x00000010 #define DC_CWUC_TP10_ABILITY 0x00000020 #define DC_CWUC_MII_ABILITY 0x00000040 #define DC_CWUC_SYM_ABILITY 0x00000080 #define DC_CWUC_LOCK 0x00000100 /* * SROM nonsense. */ #define DC_IB_CTLRCNT 0x13 #define DC_IB_LEAF0_CNUM 0x1A #define DC_IB_LEAF0_OFFSET 0x1B struct dc_info_leaf { u_int16_t dc_conntype; u_int8_t dc_blkcnt; u_int8_t dc_rsvd; u_int16_t dc_infoblk; }; #define DC_CTYPE_10BT 0x0000 #define DC_CTYPE_10BT_NWAY 0x0100 #define DC_CTYPE_10BT_FDX 0x0204 #define DC_CTYPE_10B2 0x0001 #define DC_CTYPE_10B5 0x0002 #define DC_CTYPE_100BT 0x0003 #define DC_CTYPE_100BT_FDX 0x0205 #define DC_CTYPE_100T4 0x0006 #define DC_CTYPE_100FX 0x0007 #define DC_CTYPE_100FX_FDX 0x0208 #define DC_CTYPE_MII_10BT 0x0009 #define DC_CTYPE_MII_10BT_FDX 0x020A #define DC_CTYPE_MII_100BT 0x000D #define DC_CTYPE_MII_100BT_FDX 0x020E #define DC_CTYPE_MII_100T4 0x000F #define DC_CTYPE_MII_100FX 0x0010 #define DC_CTYPE_MII_100FX_FDX 0x0211 #define DC_CTYPE_DYN_PUP_AUTOSENSE 0x0800 #define DC_CTYPE_PUP_AUTOSENSE 0x8800 #define DC_CTYPE_NOMEDIA 0xFFFF #define DC_EBLOCK_SIA 0x0002 #define DC_EBLOCK_MII 0x0003 #define DC_EBLOCK_SYM 0x0004 #define DC_EBLOCK_RESET 0x0005 #define DC_EBLOCK_PHY_SHUTDOWN 0x0006 struct dc_leaf_hdr { u_int16_t dc_mtype; u_int8_t dc_mcnt; u_int8_t dc_rsvd; }; struct dc_eblock_hdr { u_int8_t dc_len; u_int8_t dc_type; }; struct dc_eblock_sia { struct dc_eblock_hdr dc_sia_hdr; u_int8_t dc_sia_code; union { struct dc_sia_ext { /* if (dc_sia_code & DC_SIA_CODE_EXT) */ u_int8_t dc_sia_mediaspec[6]; /* CSR13, CSR14, CSR15 */ u_int8_t dc_sia_gpio_ctl[2]; u_int8_t dc_sia_gpio_dat[2]; } dc_sia_ext; struct dc_sia_noext { u_int8_t dc_sia_gpio_ctl[2]; u_int8_t dc_sia_gpio_dat[2]; } dc_sia_noext; } dc_un; }; #define DC_SIA_CODE_10BT 0x00 #define DC_SIA_CODE_10B2 0x01 #define DC_SIA_CODE_10B5 0x02 #define DC_SIA_CODE_10BT_FDX 0x04 #define DC_SIA_CODE_EXT 0x40 /* * Note that the first word in the gpr and reset * sequences is always a control word. */ struct dc_eblock_mii { struct dc_eblock_hdr dc_mii_hdr; u_int8_t dc_mii_phynum; u_int8_t dc_gpr_len; /* u_int16_t dc_gpr_dat[n]; */ /* u_int8_t dc_reset_len; */ /* u_int16_t dc_reset_dat[n]; */ /* There are other fields after these, but we don't * care about them since they can be determined by looking * at the PHY. */ }; struct dc_eblock_sym { struct dc_eblock_hdr dc_sym_hdr; u_int8_t dc_sym_code; u_int8_t dc_sym_gpio_ctl[2]; u_int8_t dc_sym_gpio_dat[2]; u_int8_t dc_sym_cmd[2]; }; #define DC_SYM_CODE_100BT 0x03 #define DC_SYM_CODE_100BT_FDX 0x05 #define DC_SYM_CODE_100T4 0x06 #define DC_SYM_CODE_100FX 0x07 #define DC_SYM_CODE_100FX_FDX 0x08 struct dc_eblock_reset { struct dc_eblock_hdr dc_reset_hdr; u_int8_t dc_reset_len; /* u_int16_t dc_reset_dat[n]; */ };