113bca4c6SSepherosa Ziehau /* 213bca4c6SSepherosa Ziehau * Copyright (c) 2004 313bca4c6SSepherosa Ziehau * Bill Paul <wpaul@windriver.com>. All rights reserved. 413bca4c6SSepherosa Ziehau * 513bca4c6SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 613bca4c6SSepherosa Ziehau * modification, are permitted provided that the following conditions 713bca4c6SSepherosa Ziehau * are met: 813bca4c6SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 913bca4c6SSepherosa Ziehau * notice, this list of conditions and the following disclaimer. 1013bca4c6SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 1113bca4c6SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 1213bca4c6SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 1313bca4c6SSepherosa Ziehau * 3. All advertising materials mentioning features or use of this software 1413bca4c6SSepherosa Ziehau * must display the following acknowledgement: 1513bca4c6SSepherosa Ziehau * This product includes software developed by Bill Paul. 1613bca4c6SSepherosa Ziehau * 4. Neither the name of the author nor the names of any co-contributors 1713bca4c6SSepherosa Ziehau * may be used to endorse or promote products derived from this software 1813bca4c6SSepherosa Ziehau * without specific prior written permission. 1913bca4c6SSepherosa Ziehau * 2013bca4c6SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2113bca4c6SSepherosa Ziehau * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2213bca4c6SSepherosa Ziehau * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2313bca4c6SSepherosa Ziehau * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2413bca4c6SSepherosa Ziehau * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2513bca4c6SSepherosa Ziehau * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2613bca4c6SSepherosa Ziehau * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2713bca4c6SSepherosa Ziehau * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2813bca4c6SSepherosa Ziehau * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2913bca4c6SSepherosa Ziehau * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3013bca4c6SSepherosa Ziehau * THE POSSIBILITY OF SUCH DAMAGE. 3113bca4c6SSepherosa Ziehau * 3213bca4c6SSepherosa Ziehau * $FreeBSD: src/sys/dev/vge/if_vge.c,v 1.24 2006/02/14 12:44:56 glebius Exp $ 33*f3e7c70dSSepherosa Ziehau * $DragonFly: src/sys/dev/netif/vge/if_vge.c,v 1.4 2007/03/24 08:42:42 sephe Exp $ 3413bca4c6SSepherosa Ziehau */ 3513bca4c6SSepherosa Ziehau 3613bca4c6SSepherosa Ziehau /* 3713bca4c6SSepherosa Ziehau * VIA Networking Technologies VT612x PCI gigabit ethernet NIC driver. 3813bca4c6SSepherosa Ziehau * 3913bca4c6SSepherosa Ziehau * Written by Bill Paul <wpaul@windriver.com> 4013bca4c6SSepherosa Ziehau * Senior Networking Software Engineer 4113bca4c6SSepherosa Ziehau * Wind River Systems 4213bca4c6SSepherosa Ziehau */ 4313bca4c6SSepherosa Ziehau 4413bca4c6SSepherosa Ziehau /* 4513bca4c6SSepherosa Ziehau * The VIA Networking VT6122 is a 32bit, 33/66Mhz PCI device that 4613bca4c6SSepherosa Ziehau * combines a tri-speed ethernet MAC and PHY, with the following 4713bca4c6SSepherosa Ziehau * features: 4813bca4c6SSepherosa Ziehau * 4913bca4c6SSepherosa Ziehau * o Jumbo frame support up to 16K 5013bca4c6SSepherosa Ziehau * o Transmit and receive flow control 5113bca4c6SSepherosa Ziehau * o IPv4 checksum offload 5213bca4c6SSepherosa Ziehau * o VLAN tag insertion and stripping 5313bca4c6SSepherosa Ziehau * o TCP large send 5413bca4c6SSepherosa Ziehau * o 64-bit multicast hash table filter 5513bca4c6SSepherosa Ziehau * o 64 entry CAM filter 5613bca4c6SSepherosa Ziehau * o 16K RX FIFO and 48K TX FIFO memory 5713bca4c6SSepherosa Ziehau * o Interrupt moderation 5813bca4c6SSepherosa Ziehau * 5913bca4c6SSepherosa Ziehau * The VT6122 supports up to four transmit DMA queues. The descriptors 6013bca4c6SSepherosa Ziehau * in the transmit ring can address up to 7 data fragments; frames which 6113bca4c6SSepherosa Ziehau * span more than 7 data buffers must be coalesced, but in general the 6213bca4c6SSepherosa Ziehau * BSD TCP/IP stack rarely generates frames more than 2 or 3 fragments 6313bca4c6SSepherosa Ziehau * long. The receive descriptors address only a single buffer. 6413bca4c6SSepherosa Ziehau * 6513bca4c6SSepherosa Ziehau * There are two peculiar design issues with the VT6122. One is that 6613bca4c6SSepherosa Ziehau * receive data buffers must be aligned on a 32-bit boundary. This is 6713bca4c6SSepherosa Ziehau * not a problem where the VT6122 is used as a LOM device in x86-based 6813bca4c6SSepherosa Ziehau * systems, but on architectures that generate unaligned access traps, we 6913bca4c6SSepherosa Ziehau * have to do some copying. 7013bca4c6SSepherosa Ziehau * 7113bca4c6SSepherosa Ziehau * The other issue has to do with the way 64-bit addresses are handled. 7213bca4c6SSepherosa Ziehau * The DMA descriptors only allow you to specify 48 bits of addressing 7313bca4c6SSepherosa Ziehau * information. The remaining 16 bits are specified using one of the 7413bca4c6SSepherosa Ziehau * I/O registers. If you only have a 32-bit system, then this isn't 7513bca4c6SSepherosa Ziehau * an issue, but if you have a 64-bit system and more than 4GB of 7613bca4c6SSepherosa Ziehau * memory, you must have to make sure your network data buffers reside 7713bca4c6SSepherosa Ziehau * in the same 48-bit 'segment.' 7813bca4c6SSepherosa Ziehau * 7913bca4c6SSepherosa Ziehau * Special thanks to Ryan Fu at VIA Networking for providing documentation 8013bca4c6SSepherosa Ziehau * and sample NICs for testing. 8113bca4c6SSepherosa Ziehau */ 8213bca4c6SSepherosa Ziehau 8313bca4c6SSepherosa Ziehau #include "opt_polling.h" 8413bca4c6SSepherosa Ziehau 8513bca4c6SSepherosa Ziehau #include <sys/param.h> 8613bca4c6SSepherosa Ziehau #include <sys/endian.h> 8713bca4c6SSepherosa Ziehau #include <sys/systm.h> 8813bca4c6SSepherosa Ziehau #include <sys/sockio.h> 8913bca4c6SSepherosa Ziehau #include <sys/mbuf.h> 9013bca4c6SSepherosa Ziehau #include <sys/malloc.h> 9113bca4c6SSepherosa Ziehau #include <sys/module.h> 9213bca4c6SSepherosa Ziehau #include <sys/kernel.h> 9313bca4c6SSepherosa Ziehau #include <sys/socket.h> 9413bca4c6SSepherosa Ziehau #include <sys/serialize.h> 9513bca4c6SSepherosa Ziehau #include <sys/proc.h> 961f7ab7c9SMatthew Dillon #include <sys/bus.h> 971f7ab7c9SMatthew Dillon #include <sys/rman.h> 9813bca4c6SSepherosa Ziehau 9913bca4c6SSepherosa Ziehau #include <net/if.h> 10013bca4c6SSepherosa Ziehau #include <net/if_arp.h> 10113bca4c6SSepherosa Ziehau #include <net/ethernet.h> 10213bca4c6SSepherosa Ziehau #include <net/if_dl.h> 10313bca4c6SSepherosa Ziehau #include <net/if_media.h> 10413bca4c6SSepherosa Ziehau #include <net/ifq_var.h> 10513bca4c6SSepherosa Ziehau #include <net/if_types.h> 10613bca4c6SSepherosa Ziehau #include <net/vlan/if_vlan_var.h> 10713bca4c6SSepherosa Ziehau 10813bca4c6SSepherosa Ziehau #include <net/bpf.h> 10913bca4c6SSepherosa Ziehau 11013bca4c6SSepherosa Ziehau #include <dev/netif/mii_layer/mii.h> 11113bca4c6SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h> 11213bca4c6SSepherosa Ziehau 11313bca4c6SSepherosa Ziehau #include <bus/pci/pcireg.h> 11413bca4c6SSepherosa Ziehau #include <bus/pci/pcivar.h> 11513bca4c6SSepherosa Ziehau #include <bus/pci/pcidevs.h> 11613bca4c6SSepherosa Ziehau 11713bca4c6SSepherosa Ziehau #include "miibus_if.h" 11813bca4c6SSepherosa Ziehau 11913bca4c6SSepherosa Ziehau #include <dev/netif/vge/if_vgereg.h> 12013bca4c6SSepherosa Ziehau #include <dev/netif/vge/if_vgevar.h> 12113bca4c6SSepherosa Ziehau 12213bca4c6SSepherosa Ziehau #define VGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 12313bca4c6SSepherosa Ziehau 12413bca4c6SSepherosa Ziehau /* 12513bca4c6SSepherosa Ziehau * Various supported device vendors/types and their names. 12613bca4c6SSepherosa Ziehau */ 12713bca4c6SSepherosa Ziehau static const struct vge_type vge_devs[] = { 12813bca4c6SSepherosa Ziehau { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT612X, 12913bca4c6SSepherosa Ziehau "VIA Networking Gigabit Ethernet" }, 13013bca4c6SSepherosa Ziehau { 0, 0, NULL } 13113bca4c6SSepherosa Ziehau }; 13213bca4c6SSepherosa Ziehau 13313bca4c6SSepherosa Ziehau static int vge_probe (device_t); 13413bca4c6SSepherosa Ziehau static int vge_attach (device_t); 13513bca4c6SSepherosa Ziehau static int vge_detach (device_t); 13613bca4c6SSepherosa Ziehau 13713bca4c6SSepherosa Ziehau static int vge_encap (struct vge_softc *, struct mbuf *, int); 13813bca4c6SSepherosa Ziehau 13913bca4c6SSepherosa Ziehau static void vge_dma_map_addr (void *, bus_dma_segment_t *, int, int); 14013bca4c6SSepherosa Ziehau static void vge_dma_map_rx_desc (void *, bus_dma_segment_t *, int, 14113bca4c6SSepherosa Ziehau bus_size_t, int); 14213bca4c6SSepherosa Ziehau static void vge_dma_map_tx_desc (void *, bus_dma_segment_t *, int, 14313bca4c6SSepherosa Ziehau bus_size_t, int); 14413bca4c6SSepherosa Ziehau static int vge_dma_alloc (device_t); 14513bca4c6SSepherosa Ziehau static void vge_dma_free (struct vge_softc *); 14613bca4c6SSepherosa Ziehau static int vge_newbuf (struct vge_softc *, int, struct mbuf *); 14713bca4c6SSepherosa Ziehau static int vge_rx_list_init (struct vge_softc *); 14813bca4c6SSepherosa Ziehau static int vge_tx_list_init (struct vge_softc *); 14913bca4c6SSepherosa Ziehau #ifdef VGE_FIXUP_RX 15013bca4c6SSepherosa Ziehau static __inline void vge_fixup_rx 15113bca4c6SSepherosa Ziehau (struct mbuf *); 15213bca4c6SSepherosa Ziehau #endif 15313bca4c6SSepherosa Ziehau static void vge_rxeof (struct vge_softc *, int); 15413bca4c6SSepherosa Ziehau static void vge_txeof (struct vge_softc *); 15513bca4c6SSepherosa Ziehau static void vge_intr (void *); 15613bca4c6SSepherosa Ziehau static void vge_tick (struct vge_softc *); 15713bca4c6SSepherosa Ziehau static void vge_start (struct ifnet *); 15813bca4c6SSepherosa Ziehau static int vge_ioctl (struct ifnet *, u_long, caddr_t, 15913bca4c6SSepherosa Ziehau struct ucred *); 16013bca4c6SSepherosa Ziehau static void vge_init (void *); 16113bca4c6SSepherosa Ziehau static void vge_stop (struct vge_softc *); 16213bca4c6SSepherosa Ziehau static void vge_watchdog (struct ifnet *); 16313bca4c6SSepherosa Ziehau static int vge_suspend (device_t); 16413bca4c6SSepherosa Ziehau static int vge_resume (device_t); 16513bca4c6SSepherosa Ziehau static void vge_shutdown (device_t); 16613bca4c6SSepherosa Ziehau static int vge_ifmedia_upd (struct ifnet *); 16713bca4c6SSepherosa Ziehau static void vge_ifmedia_sts (struct ifnet *, struct ifmediareq *); 16813bca4c6SSepherosa Ziehau 16913bca4c6SSepherosa Ziehau #ifdef VGE_EEPROM 17013bca4c6SSepherosa Ziehau static void vge_eeprom_getword (struct vge_softc *, int, u_int16_t *); 17113bca4c6SSepherosa Ziehau #endif 17213bca4c6SSepherosa Ziehau static void vge_read_eeprom (struct vge_softc *, uint8_t *, int, int, int); 17313bca4c6SSepherosa Ziehau 17413bca4c6SSepherosa Ziehau static void vge_miipoll_start (struct vge_softc *); 17513bca4c6SSepherosa Ziehau static void vge_miipoll_stop (struct vge_softc *); 17613bca4c6SSepherosa Ziehau static int vge_miibus_readreg (device_t, int, int); 17713bca4c6SSepherosa Ziehau static int vge_miibus_writereg (device_t, int, int, int); 17813bca4c6SSepherosa Ziehau static void vge_miibus_statchg (device_t); 17913bca4c6SSepherosa Ziehau 18013bca4c6SSepherosa Ziehau static void vge_cam_clear (struct vge_softc *); 18113bca4c6SSepherosa Ziehau static int vge_cam_set (struct vge_softc *, uint8_t *); 18213bca4c6SSepherosa Ziehau static void vge_setmulti (struct vge_softc *); 18313bca4c6SSepherosa Ziehau static void vge_reset (struct vge_softc *); 18413bca4c6SSepherosa Ziehau 18513bca4c6SSepherosa Ziehau #ifdef DEVICE_POLLING 18613bca4c6SSepherosa Ziehau static void vge_poll(struct ifnet *, enum poll_cmd, int); 18713bca4c6SSepherosa Ziehau static void vge_disable_intr(struct vge_softc *); 18813bca4c6SSepherosa Ziehau #endif 18913bca4c6SSepherosa Ziehau static void vge_enable_intr(struct vge_softc *, uint32_t); 19013bca4c6SSepherosa Ziehau 19113bca4c6SSepherosa Ziehau #define VGE_PCI_LOIO 0x10 19213bca4c6SSepherosa Ziehau #define VGE_PCI_LOMEM 0x14 19313bca4c6SSepherosa Ziehau 19413bca4c6SSepherosa Ziehau static device_method_t vge_methods[] = { 19513bca4c6SSepherosa Ziehau /* Device interface */ 19613bca4c6SSepherosa Ziehau DEVMETHOD(device_probe, vge_probe), 19713bca4c6SSepherosa Ziehau DEVMETHOD(device_attach, vge_attach), 19813bca4c6SSepherosa Ziehau DEVMETHOD(device_detach, vge_detach), 19913bca4c6SSepherosa Ziehau DEVMETHOD(device_suspend, vge_suspend), 20013bca4c6SSepherosa Ziehau DEVMETHOD(device_resume, vge_resume), 20113bca4c6SSepherosa Ziehau DEVMETHOD(device_shutdown, vge_shutdown), 20213bca4c6SSepherosa Ziehau 20313bca4c6SSepherosa Ziehau /* bus interface */ 20413bca4c6SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child), 20513bca4c6SSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added), 20613bca4c6SSepherosa Ziehau 20713bca4c6SSepherosa Ziehau /* MII interface */ 20813bca4c6SSepherosa Ziehau DEVMETHOD(miibus_readreg, vge_miibus_readreg), 20913bca4c6SSepherosa Ziehau DEVMETHOD(miibus_writereg, vge_miibus_writereg), 21013bca4c6SSepherosa Ziehau DEVMETHOD(miibus_statchg, vge_miibus_statchg), 21113bca4c6SSepherosa Ziehau 21213bca4c6SSepherosa Ziehau { 0, 0 } 21313bca4c6SSepherosa Ziehau }; 21413bca4c6SSepherosa Ziehau 21513bca4c6SSepherosa Ziehau static driver_t vge_driver = { 21613bca4c6SSepherosa Ziehau "vge", 21713bca4c6SSepherosa Ziehau vge_methods, 21813bca4c6SSepherosa Ziehau sizeof(struct vge_softc) 21913bca4c6SSepherosa Ziehau }; 22013bca4c6SSepherosa Ziehau 22113bca4c6SSepherosa Ziehau static devclass_t vge_devclass; 22213bca4c6SSepherosa Ziehau 22313bca4c6SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_vge); 22413bca4c6SSepherosa Ziehau MODULE_DEPEND(if_vge, miibus, 1, 1, 1); 22513bca4c6SSepherosa Ziehau DRIVER_MODULE(if_vge, pci, vge_driver, vge_devclass, 0, 0); 22613bca4c6SSepherosa Ziehau DRIVER_MODULE(if_vge, cardbus, vge_driver, vge_devclass, 0, 0); 22713bca4c6SSepherosa Ziehau DRIVER_MODULE(miibus, vge, miibus_driver, miibus_devclass, 0, 0); 22813bca4c6SSepherosa Ziehau 22913bca4c6SSepherosa Ziehau #ifdef VGE_EEPROM 23013bca4c6SSepherosa Ziehau /* 23113bca4c6SSepherosa Ziehau * Read a word of data stored in the EEPROM at address 'addr.' 23213bca4c6SSepherosa Ziehau */ 23313bca4c6SSepherosa Ziehau static void 23413bca4c6SSepherosa Ziehau vge_eeprom_getword(struct vge_softc *sc, int addr, uint16_t dest) 23513bca4c6SSepherosa Ziehau { 23613bca4c6SSepherosa Ziehau uint16_t word = 0; 23713bca4c6SSepherosa Ziehau int i; 23813bca4c6SSepherosa Ziehau 23913bca4c6SSepherosa Ziehau /* 24013bca4c6SSepherosa Ziehau * Enter EEPROM embedded programming mode. In order to 24113bca4c6SSepherosa Ziehau * access the EEPROM at all, we first have to set the 24213bca4c6SSepherosa Ziehau * EELOAD bit in the CHIPCFG2 register. 24313bca4c6SSepherosa Ziehau */ 24413bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CHIPCFG2, VGE_CHIPCFG2_EELOAD); 24513bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_EECSR, VGE_EECSR_EMBP/*|VGE_EECSR_ECS*/); 24613bca4c6SSepherosa Ziehau 24713bca4c6SSepherosa Ziehau /* Select the address of the word we want to read */ 24813bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_EEADDR, addr); 24913bca4c6SSepherosa Ziehau 25013bca4c6SSepherosa Ziehau /* Issue read command */ 25113bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_EECMD, VGE_EECMD_ERD); 25213bca4c6SSepherosa Ziehau 25313bca4c6SSepherosa Ziehau /* Wait for the done bit to be set. */ 25413bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 25513bca4c6SSepherosa Ziehau if (CSR_READ_1(sc, VGE_EECMD) & VGE_EECMD_EDONE) 25613bca4c6SSepherosa Ziehau break; 25713bca4c6SSepherosa Ziehau } 25813bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) { 25913bca4c6SSepherosa Ziehau device_printf(sc->vge_dev, "EEPROM read timed out\n"); 26013bca4c6SSepherosa Ziehau *dest = 0; 26113bca4c6SSepherosa Ziehau return; 26213bca4c6SSepherosa Ziehau } 26313bca4c6SSepherosa Ziehau 26413bca4c6SSepherosa Ziehau /* Read the result */ 26513bca4c6SSepherosa Ziehau word = CSR_READ_2(sc, VGE_EERDDAT); 26613bca4c6SSepherosa Ziehau 26713bca4c6SSepherosa Ziehau /* Turn off EEPROM access mode. */ 26813bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_EECSR, VGE_EECSR_EMBP/*|VGE_EECSR_ECS*/); 26913bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CHIPCFG2, VGE_CHIPCFG2_EELOAD); 27013bca4c6SSepherosa Ziehau 27113bca4c6SSepherosa Ziehau *dest = word; 27213bca4c6SSepherosa Ziehau } 27313bca4c6SSepherosa Ziehau #endif 27413bca4c6SSepherosa Ziehau 27513bca4c6SSepherosa Ziehau /* 27613bca4c6SSepherosa Ziehau * Read a sequence of words from the EEPROM. 27713bca4c6SSepherosa Ziehau */ 27813bca4c6SSepherosa Ziehau static void 27913bca4c6SSepherosa Ziehau vge_read_eeprom(struct vge_softc *sc, uint8_t *dest, int off, int cnt, int swap) 28013bca4c6SSepherosa Ziehau { 28113bca4c6SSepherosa Ziehau int i; 28213bca4c6SSepherosa Ziehau #ifdef VGE_EEPROM 28313bca4c6SSepherosa Ziehau uint16_t word = 0, *ptr; 28413bca4c6SSepherosa Ziehau 28513bca4c6SSepherosa Ziehau for (i = 0; i < cnt; i++) { 28613bca4c6SSepherosa Ziehau vge_eeprom_getword(sc, off + i, &word); 28713bca4c6SSepherosa Ziehau ptr = (uint16_t *)(dest + (i * 2)); 28813bca4c6SSepherosa Ziehau if (swap) 28913bca4c6SSepherosa Ziehau *ptr = ntohs(word); 29013bca4c6SSepherosa Ziehau else 29113bca4c6SSepherosa Ziehau *ptr = word; 29213bca4c6SSepherosa Ziehau } 29313bca4c6SSepherosa Ziehau #else 29413bca4c6SSepherosa Ziehau for (i = 0; i < ETHER_ADDR_LEN; i++) 29513bca4c6SSepherosa Ziehau dest[i] = CSR_READ_1(sc, VGE_PAR0 + i); 29613bca4c6SSepherosa Ziehau #endif 29713bca4c6SSepherosa Ziehau } 29813bca4c6SSepherosa Ziehau 29913bca4c6SSepherosa Ziehau static void 30013bca4c6SSepherosa Ziehau vge_miipoll_stop(struct vge_softc *sc) 30113bca4c6SSepherosa Ziehau { 30213bca4c6SSepherosa Ziehau int i; 30313bca4c6SSepherosa Ziehau 30413bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_MIICMD, 0); 30513bca4c6SSepherosa Ziehau 30613bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 30713bca4c6SSepherosa Ziehau DELAY(1); 30813bca4c6SSepherosa Ziehau if (CSR_READ_1(sc, VGE_MIISTS) & VGE_MIISTS_IIDL) 30913bca4c6SSepherosa Ziehau break; 31013bca4c6SSepherosa Ziehau } 31113bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) 31213bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "failed to idle MII autopoll\n"); 31313bca4c6SSepherosa Ziehau } 31413bca4c6SSepherosa Ziehau 31513bca4c6SSepherosa Ziehau static void 31613bca4c6SSepherosa Ziehau vge_miipoll_start(struct vge_softc *sc) 31713bca4c6SSepherosa Ziehau { 31813bca4c6SSepherosa Ziehau int i; 31913bca4c6SSepherosa Ziehau 32013bca4c6SSepherosa Ziehau /* First, make sure we're idle. */ 32113bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_MIICMD, 0); 32213bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_MIIADDR, VGE_MIIADDR_SWMPL); 32313bca4c6SSepherosa Ziehau 32413bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 32513bca4c6SSepherosa Ziehau DELAY(1); 32613bca4c6SSepherosa Ziehau if (CSR_READ_1(sc, VGE_MIISTS) & VGE_MIISTS_IIDL) 32713bca4c6SSepherosa Ziehau break; 32813bca4c6SSepherosa Ziehau } 32913bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) { 33013bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "failed to idle MII autopoll\n"); 33113bca4c6SSepherosa Ziehau return; 33213bca4c6SSepherosa Ziehau } 33313bca4c6SSepherosa Ziehau 33413bca4c6SSepherosa Ziehau /* Now enable auto poll mode. */ 33513bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_MIICMD, VGE_MIICMD_MAUTO); 33613bca4c6SSepherosa Ziehau 33713bca4c6SSepherosa Ziehau /* And make sure it started. */ 33813bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 33913bca4c6SSepherosa Ziehau DELAY(1); 34013bca4c6SSepherosa Ziehau if ((CSR_READ_1(sc, VGE_MIISTS) & VGE_MIISTS_IIDL) == 0) 34113bca4c6SSepherosa Ziehau break; 34213bca4c6SSepherosa Ziehau } 34313bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) 34413bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "failed to start MII autopoll\n"); 34513bca4c6SSepherosa Ziehau } 34613bca4c6SSepherosa Ziehau 34713bca4c6SSepherosa Ziehau static int 34813bca4c6SSepherosa Ziehau vge_miibus_readreg(device_t dev, int phy, int reg) 34913bca4c6SSepherosa Ziehau { 35013bca4c6SSepherosa Ziehau struct vge_softc *sc; 35113bca4c6SSepherosa Ziehau int i; 35213bca4c6SSepherosa Ziehau uint16_t rval = 0; 35313bca4c6SSepherosa Ziehau 35413bca4c6SSepherosa Ziehau sc = device_get_softc(dev); 35513bca4c6SSepherosa Ziehau 35613bca4c6SSepherosa Ziehau if (phy != (CSR_READ_1(sc, VGE_MIICFG) & 0x1F)) 35713bca4c6SSepherosa Ziehau return(0); 35813bca4c6SSepherosa Ziehau 35913bca4c6SSepherosa Ziehau vge_miipoll_stop(sc); 36013bca4c6SSepherosa Ziehau 36113bca4c6SSepherosa Ziehau /* Specify the register we want to read. */ 36213bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_MIIADDR, reg); 36313bca4c6SSepherosa Ziehau 36413bca4c6SSepherosa Ziehau /* Issue read command. */ 36513bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_MIICMD, VGE_MIICMD_RCMD); 36613bca4c6SSepherosa Ziehau 36713bca4c6SSepherosa Ziehau /* Wait for the read command bit to self-clear. */ 36813bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 36913bca4c6SSepherosa Ziehau DELAY(1); 37013bca4c6SSepherosa Ziehau if ((CSR_READ_1(sc, VGE_MIICMD) & VGE_MIICMD_RCMD) == 0) 37113bca4c6SSepherosa Ziehau break; 37213bca4c6SSepherosa Ziehau } 37313bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) 37413bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "MII read timed out\n"); 37513bca4c6SSepherosa Ziehau else 37613bca4c6SSepherosa Ziehau rval = CSR_READ_2(sc, VGE_MIIDATA); 37713bca4c6SSepherosa Ziehau 37813bca4c6SSepherosa Ziehau vge_miipoll_start(sc); 37913bca4c6SSepherosa Ziehau 38013bca4c6SSepherosa Ziehau return (rval); 38113bca4c6SSepherosa Ziehau } 38213bca4c6SSepherosa Ziehau 38313bca4c6SSepherosa Ziehau static int 38413bca4c6SSepherosa Ziehau vge_miibus_writereg(device_t dev, int phy, int reg, int data) 38513bca4c6SSepherosa Ziehau { 38613bca4c6SSepherosa Ziehau struct vge_softc *sc; 38713bca4c6SSepherosa Ziehau int i, rval = 0; 38813bca4c6SSepherosa Ziehau 38913bca4c6SSepherosa Ziehau sc = device_get_softc(dev); 39013bca4c6SSepherosa Ziehau 39113bca4c6SSepherosa Ziehau if (phy != (CSR_READ_1(sc, VGE_MIICFG) & 0x1F)) 39213bca4c6SSepherosa Ziehau return(0); 39313bca4c6SSepherosa Ziehau 39413bca4c6SSepherosa Ziehau vge_miipoll_stop(sc); 39513bca4c6SSepherosa Ziehau 39613bca4c6SSepherosa Ziehau /* Specify the register we want to write. */ 39713bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_MIIADDR, reg); 39813bca4c6SSepherosa Ziehau 39913bca4c6SSepherosa Ziehau /* Specify the data we want to write. */ 40013bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_MIIDATA, data); 40113bca4c6SSepherosa Ziehau 40213bca4c6SSepherosa Ziehau /* Issue write command. */ 40313bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_MIICMD, VGE_MIICMD_WCMD); 40413bca4c6SSepherosa Ziehau 40513bca4c6SSepherosa Ziehau /* Wait for the write command bit to self-clear. */ 40613bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 40713bca4c6SSepherosa Ziehau DELAY(1); 40813bca4c6SSepherosa Ziehau if ((CSR_READ_1(sc, VGE_MIICMD) & VGE_MIICMD_WCMD) == 0) 40913bca4c6SSepherosa Ziehau break; 41013bca4c6SSepherosa Ziehau } 41113bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) { 41213bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "MII write timed out\n"); 41313bca4c6SSepherosa Ziehau rval = EIO; 41413bca4c6SSepherosa Ziehau } 41513bca4c6SSepherosa Ziehau 41613bca4c6SSepherosa Ziehau vge_miipoll_start(sc); 41713bca4c6SSepherosa Ziehau 41813bca4c6SSepherosa Ziehau return (rval); 41913bca4c6SSepherosa Ziehau } 42013bca4c6SSepherosa Ziehau 42113bca4c6SSepherosa Ziehau static void 42213bca4c6SSepherosa Ziehau vge_cam_clear(struct vge_softc *sc) 42313bca4c6SSepherosa Ziehau { 42413bca4c6SSepherosa Ziehau int i; 42513bca4c6SSepherosa Ziehau 42613bca4c6SSepherosa Ziehau /* 42713bca4c6SSepherosa Ziehau * Turn off all the mask bits. This tells the chip 42813bca4c6SSepherosa Ziehau * that none of the entries in the CAM filter are valid. 42913bca4c6SSepherosa Ziehau * desired entries will be enabled as we fill the filter in. 43013bca4c6SSepherosa Ziehau */ 43113bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_PAGESEL); 43213bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_PAGESEL_CAMMASK); 43313bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CAMADDR, VGE_CAMADDR_ENABLE); 43413bca4c6SSepherosa Ziehau for (i = 0; i < 8; i++) 43513bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CAM0 + i, 0); 43613bca4c6SSepherosa Ziehau 43713bca4c6SSepherosa Ziehau /* Clear the VLAN filter too. */ 43813bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CAMADDR, VGE_CAMADDR_ENABLE|VGE_CAMADDR_AVSEL|0); 43913bca4c6SSepherosa Ziehau for (i = 0; i < 8; i++) 44013bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CAM0 + i, 0); 44113bca4c6SSepherosa Ziehau 44213bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CAMADDR, 0); 44313bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_PAGESEL); 44413bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_PAGESEL_MAR); 44513bca4c6SSepherosa Ziehau 44613bca4c6SSepherosa Ziehau sc->vge_camidx = 0; 44713bca4c6SSepherosa Ziehau } 44813bca4c6SSepherosa Ziehau 44913bca4c6SSepherosa Ziehau static int 45013bca4c6SSepherosa Ziehau vge_cam_set(struct vge_softc *sc, uint8_t *addr) 45113bca4c6SSepherosa Ziehau { 45213bca4c6SSepherosa Ziehau int i, error = 0; 45313bca4c6SSepherosa Ziehau 45413bca4c6SSepherosa Ziehau if (sc->vge_camidx == VGE_CAM_MAXADDRS) 45513bca4c6SSepherosa Ziehau return(ENOSPC); 45613bca4c6SSepherosa Ziehau 45713bca4c6SSepherosa Ziehau /* Select the CAM data page. */ 45813bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_PAGESEL); 45913bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_PAGESEL_CAMDATA); 46013bca4c6SSepherosa Ziehau 46113bca4c6SSepherosa Ziehau /* Set the filter entry we want to update and enable writing. */ 46213bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CAMADDR, VGE_CAMADDR_ENABLE|sc->vge_camidx); 46313bca4c6SSepherosa Ziehau 46413bca4c6SSepherosa Ziehau /* Write the address to the CAM registers */ 46513bca4c6SSepherosa Ziehau for (i = 0; i < ETHER_ADDR_LEN; i++) 46613bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CAM0 + i, addr[i]); 46713bca4c6SSepherosa Ziehau 46813bca4c6SSepherosa Ziehau /* Issue a write command. */ 46913bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_WRITE); 47013bca4c6SSepherosa Ziehau 47113bca4c6SSepherosa Ziehau /* Wake for it to clear. */ 47213bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 47313bca4c6SSepherosa Ziehau DELAY(1); 47413bca4c6SSepherosa Ziehau if ((CSR_READ_1(sc, VGE_CAMCTL) & VGE_CAMCTL_WRITE) == 0) 47513bca4c6SSepherosa Ziehau break; 47613bca4c6SSepherosa Ziehau } 47713bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) { 47813bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "setting CAM filter failed\n"); 47913bca4c6SSepherosa Ziehau error = EIO; 48013bca4c6SSepherosa Ziehau goto fail; 48113bca4c6SSepherosa Ziehau } 48213bca4c6SSepherosa Ziehau 48313bca4c6SSepherosa Ziehau /* Select the CAM mask page. */ 48413bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_PAGESEL); 48513bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_PAGESEL_CAMMASK); 48613bca4c6SSepherosa Ziehau 48713bca4c6SSepherosa Ziehau /* Set the mask bit that enables this filter. */ 48813bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAM0 + (sc->vge_camidx/8), 48913bca4c6SSepherosa Ziehau 1<<(sc->vge_camidx & 7)); 49013bca4c6SSepherosa Ziehau 49113bca4c6SSepherosa Ziehau sc->vge_camidx++; 49213bca4c6SSepherosa Ziehau 49313bca4c6SSepherosa Ziehau fail: 49413bca4c6SSepherosa Ziehau /* Turn off access to CAM. */ 49513bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CAMADDR, 0); 49613bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_PAGESEL); 49713bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_PAGESEL_MAR); 49813bca4c6SSepherosa Ziehau 49913bca4c6SSepherosa Ziehau return (error); 50013bca4c6SSepherosa Ziehau } 50113bca4c6SSepherosa Ziehau 50213bca4c6SSepherosa Ziehau /* 50313bca4c6SSepherosa Ziehau * Program the multicast filter. We use the 64-entry CAM filter 50413bca4c6SSepherosa Ziehau * for perfect filtering. If there's more than 64 multicast addresses, 50513bca4c6SSepherosa Ziehau * we use the hash filter insted. 50613bca4c6SSepherosa Ziehau */ 50713bca4c6SSepherosa Ziehau static void 50813bca4c6SSepherosa Ziehau vge_setmulti(struct vge_softc *sc) 50913bca4c6SSepherosa Ziehau { 51013bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 51113bca4c6SSepherosa Ziehau int error = 0; 51213bca4c6SSepherosa Ziehau struct ifmultiaddr *ifma; 51313bca4c6SSepherosa Ziehau uint32_t h, hashes[2] = { 0, 0 }; 51413bca4c6SSepherosa Ziehau 51513bca4c6SSepherosa Ziehau /* First, zot all the multicast entries. */ 51613bca4c6SSepherosa Ziehau vge_cam_clear(sc); 51713bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_MAR0, 0); 51813bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_MAR1, 0); 51913bca4c6SSepherosa Ziehau 52013bca4c6SSepherosa Ziehau /* 52113bca4c6SSepherosa Ziehau * If the user wants allmulti or promisc mode, enable reception 52213bca4c6SSepherosa Ziehau * of all multicast frames. 52313bca4c6SSepherosa Ziehau */ 52413bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 52513bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_MAR0, 0xFFFFFFFF); 52613bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_MAR1, 0xFFFFFFFF); 52713bca4c6SSepherosa Ziehau return; 52813bca4c6SSepherosa Ziehau } 52913bca4c6SSepherosa Ziehau 53013bca4c6SSepherosa Ziehau /* Now program new ones */ 53113bca4c6SSepherosa Ziehau LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 53213bca4c6SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 53313bca4c6SSepherosa Ziehau continue; 53413bca4c6SSepherosa Ziehau error = vge_cam_set(sc, 53513bca4c6SSepherosa Ziehau LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 53613bca4c6SSepherosa Ziehau if (error) 53713bca4c6SSepherosa Ziehau break; 53813bca4c6SSepherosa Ziehau } 53913bca4c6SSepherosa Ziehau 54013bca4c6SSepherosa Ziehau /* If there were too many addresses, use the hash filter. */ 54113bca4c6SSepherosa Ziehau if (error) { 54213bca4c6SSepherosa Ziehau vge_cam_clear(sc); 54313bca4c6SSepherosa Ziehau 54413bca4c6SSepherosa Ziehau LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 54513bca4c6SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK) 54613bca4c6SSepherosa Ziehau continue; 54713bca4c6SSepherosa Ziehau h = ether_crc32_be(LLADDR((struct sockaddr_dl *) 54813bca4c6SSepherosa Ziehau ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; 54913bca4c6SSepherosa Ziehau if (h < 32) 55013bca4c6SSepherosa Ziehau hashes[0] |= (1 << h); 55113bca4c6SSepherosa Ziehau else 55213bca4c6SSepherosa Ziehau hashes[1] |= (1 << (h - 32)); 55313bca4c6SSepherosa Ziehau } 55413bca4c6SSepherosa Ziehau 55513bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_MAR0, hashes[0]); 55613bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_MAR1, hashes[1]); 55713bca4c6SSepherosa Ziehau } 55813bca4c6SSepherosa Ziehau } 55913bca4c6SSepherosa Ziehau 56013bca4c6SSepherosa Ziehau static void 56113bca4c6SSepherosa Ziehau vge_reset(struct vge_softc *sc) 56213bca4c6SSepherosa Ziehau { 56313bca4c6SSepherosa Ziehau int i; 56413bca4c6SSepherosa Ziehau 56513bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS1, VGE_CR1_SOFTRESET); 56613bca4c6SSepherosa Ziehau 56713bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 56813bca4c6SSepherosa Ziehau DELAY(5); 56913bca4c6SSepherosa Ziehau if ((CSR_READ_1(sc, VGE_CRS1) & VGE_CR1_SOFTRESET) == 0) 57013bca4c6SSepherosa Ziehau break; 57113bca4c6SSepherosa Ziehau } 57213bca4c6SSepherosa Ziehau 57313bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) { 57413bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "soft reset timed out"); 57513bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_STOP_FORCE); 57613bca4c6SSepherosa Ziehau DELAY(2000); 57713bca4c6SSepherosa Ziehau } 57813bca4c6SSepherosa Ziehau 57913bca4c6SSepherosa Ziehau DELAY(5000); 58013bca4c6SSepherosa Ziehau 58113bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_EECSR, VGE_EECSR_RELOAD); 58213bca4c6SSepherosa Ziehau 58313bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TIMEOUT; i++) { 58413bca4c6SSepherosa Ziehau DELAY(5); 58513bca4c6SSepherosa Ziehau if ((CSR_READ_1(sc, VGE_EECSR) & VGE_EECSR_RELOAD) == 0) 58613bca4c6SSepherosa Ziehau break; 58713bca4c6SSepherosa Ziehau } 58813bca4c6SSepherosa Ziehau if (i == VGE_TIMEOUT) { 58913bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "EEPROM reload timed out\n"); 59013bca4c6SSepherosa Ziehau return; 59113bca4c6SSepherosa Ziehau } 59213bca4c6SSepherosa Ziehau 59313bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CHIPCFG0, VGE_CHIPCFG0_PACPI); 59413bca4c6SSepherosa Ziehau } 59513bca4c6SSepherosa Ziehau 59613bca4c6SSepherosa Ziehau /* 59713bca4c6SSepherosa Ziehau * Probe for a VIA gigabit chip. Check the PCI vendor and device 59813bca4c6SSepherosa Ziehau * IDs against our list and return a device name if we find a match. 59913bca4c6SSepherosa Ziehau */ 60013bca4c6SSepherosa Ziehau static int 60113bca4c6SSepherosa Ziehau vge_probe(device_t dev) 60213bca4c6SSepherosa Ziehau { 60313bca4c6SSepherosa Ziehau const struct vge_type *t; 60413bca4c6SSepherosa Ziehau uint16_t did, vid; 60513bca4c6SSepherosa Ziehau 60613bca4c6SSepherosa Ziehau did = pci_get_device(dev); 60713bca4c6SSepherosa Ziehau vid = pci_get_vendor(dev); 60813bca4c6SSepherosa Ziehau for (t = vge_devs; t->vge_name != NULL; ++t) { 60913bca4c6SSepherosa Ziehau if (vid == t->vge_vid && did == t->vge_did) { 61013bca4c6SSepherosa Ziehau device_set_desc(dev, t->vge_name); 61113bca4c6SSepherosa Ziehau return 0; 61213bca4c6SSepherosa Ziehau } 61313bca4c6SSepherosa Ziehau } 61413bca4c6SSepherosa Ziehau return (ENXIO); 61513bca4c6SSepherosa Ziehau } 61613bca4c6SSepherosa Ziehau 61713bca4c6SSepherosa Ziehau static void 61813bca4c6SSepherosa Ziehau vge_dma_map_rx_desc(void *arg, bus_dma_segment_t *segs, int nseg, 61913bca4c6SSepherosa Ziehau bus_size_t mapsize, int error) 62013bca4c6SSepherosa Ziehau { 62113bca4c6SSepherosa Ziehau 62213bca4c6SSepherosa Ziehau struct vge_dmaload_arg *ctx; 62313bca4c6SSepherosa Ziehau struct vge_rx_desc *d = NULL; 62413bca4c6SSepherosa Ziehau 62513bca4c6SSepherosa Ziehau if (error) 62613bca4c6SSepherosa Ziehau return; 62713bca4c6SSepherosa Ziehau 62813bca4c6SSepherosa Ziehau ctx = arg; 62913bca4c6SSepherosa Ziehau 63013bca4c6SSepherosa Ziehau /* Signal error to caller if there's too many segments */ 63113bca4c6SSepherosa Ziehau if (nseg > ctx->vge_maxsegs) { 63213bca4c6SSepherosa Ziehau ctx->vge_maxsegs = 0; 63313bca4c6SSepherosa Ziehau return; 63413bca4c6SSepherosa Ziehau } 63513bca4c6SSepherosa Ziehau 63613bca4c6SSepherosa Ziehau /* 63713bca4c6SSepherosa Ziehau * Map the segment array into descriptors. 63813bca4c6SSepherosa Ziehau */ 63913bca4c6SSepherosa Ziehau d = &ctx->sc->vge_ldata.vge_rx_list[ctx->vge_idx]; 64013bca4c6SSepherosa Ziehau 64113bca4c6SSepherosa Ziehau /* If this descriptor is still owned by the chip, bail. */ 64213bca4c6SSepherosa Ziehau if (le32toh(d->vge_sts) & VGE_RDSTS_OWN) { 64313bca4c6SSepherosa Ziehau if_printf(&ctx->sc->arpcom.ac_if, 64413bca4c6SSepherosa Ziehau "tried to map busy descriptor\n"); 64513bca4c6SSepherosa Ziehau ctx->vge_maxsegs = 0; 64613bca4c6SSepherosa Ziehau return; 64713bca4c6SSepherosa Ziehau } 64813bca4c6SSepherosa Ziehau 64913bca4c6SSepherosa Ziehau d->vge_buflen = htole16(VGE_BUFLEN(segs[0].ds_len) | VGE_RXDESC_I); 65013bca4c6SSepherosa Ziehau d->vge_addrlo = htole32(VGE_ADDR_LO(segs[0].ds_addr)); 65113bca4c6SSepherosa Ziehau d->vge_addrhi = htole16(VGE_ADDR_HI(segs[0].ds_addr) & 0xFFFF); 65213bca4c6SSepherosa Ziehau d->vge_sts = 0; 65313bca4c6SSepherosa Ziehau d->vge_ctl = 0; 65413bca4c6SSepherosa Ziehau 65513bca4c6SSepherosa Ziehau ctx->vge_maxsegs = 1; 65613bca4c6SSepherosa Ziehau } 65713bca4c6SSepherosa Ziehau 65813bca4c6SSepherosa Ziehau static void 65913bca4c6SSepherosa Ziehau vge_dma_map_tx_desc(void *arg, bus_dma_segment_t *segs, int nseg, 66013bca4c6SSepherosa Ziehau bus_size_t mapsize, int error) 66113bca4c6SSepherosa Ziehau { 66213bca4c6SSepherosa Ziehau struct vge_dmaload_arg *ctx; 66313bca4c6SSepherosa Ziehau struct vge_tx_desc *d = NULL; 66413bca4c6SSepherosa Ziehau struct vge_tx_frag *f; 66513bca4c6SSepherosa Ziehau int i = 0; 66613bca4c6SSepherosa Ziehau 66713bca4c6SSepherosa Ziehau if (error) 66813bca4c6SSepherosa Ziehau return; 66913bca4c6SSepherosa Ziehau 67013bca4c6SSepherosa Ziehau ctx = arg; 67113bca4c6SSepherosa Ziehau 67213bca4c6SSepherosa Ziehau /* Signal error to caller if there's too many segments */ 67313bca4c6SSepherosa Ziehau if (nseg > ctx->vge_maxsegs) { 67413bca4c6SSepherosa Ziehau ctx->vge_maxsegs = 0; 67513bca4c6SSepherosa Ziehau return; 67613bca4c6SSepherosa Ziehau } 67713bca4c6SSepherosa Ziehau 67813bca4c6SSepherosa Ziehau /* Map the segment array into descriptors. */ 67913bca4c6SSepherosa Ziehau d = &ctx->sc->vge_ldata.vge_tx_list[ctx->vge_idx]; 68013bca4c6SSepherosa Ziehau 68113bca4c6SSepherosa Ziehau /* If this descriptor is still owned by the chip, bail. */ 68213bca4c6SSepherosa Ziehau if (le32toh(d->vge_sts) & VGE_TDSTS_OWN) { 68313bca4c6SSepherosa Ziehau ctx->vge_maxsegs = 0; 68413bca4c6SSepherosa Ziehau return; 68513bca4c6SSepherosa Ziehau } 68613bca4c6SSepherosa Ziehau 68713bca4c6SSepherosa Ziehau for (i = 0; i < nseg; i++) { 68813bca4c6SSepherosa Ziehau f = &d->vge_frag[i]; 68913bca4c6SSepherosa Ziehau f->vge_buflen = htole16(VGE_BUFLEN(segs[i].ds_len)); 69013bca4c6SSepherosa Ziehau f->vge_addrlo = htole32(VGE_ADDR_LO(segs[i].ds_addr)); 69113bca4c6SSepherosa Ziehau f->vge_addrhi = htole16(VGE_ADDR_HI(segs[i].ds_addr) & 0xFFFF); 69213bca4c6SSepherosa Ziehau } 69313bca4c6SSepherosa Ziehau 69413bca4c6SSepherosa Ziehau /* Argh. This chip does not autopad short frames */ 69513bca4c6SSepherosa Ziehau if (ctx->vge_m0->m_pkthdr.len < VGE_MIN_FRAMELEN) { 69613bca4c6SSepherosa Ziehau f = &d->vge_frag[i]; 69713bca4c6SSepherosa Ziehau f->vge_buflen = htole16(VGE_BUFLEN(VGE_MIN_FRAMELEN - 69813bca4c6SSepherosa Ziehau ctx->vge_m0->m_pkthdr.len)); 69913bca4c6SSepherosa Ziehau f->vge_addrlo = htole32(VGE_ADDR_LO(segs[0].ds_addr)); 70013bca4c6SSepherosa Ziehau f->vge_addrhi = htole16(VGE_ADDR_HI(segs[0].ds_addr) & 0xFFFF); 70113bca4c6SSepherosa Ziehau ctx->vge_m0->m_pkthdr.len = VGE_MIN_FRAMELEN; 70213bca4c6SSepherosa Ziehau i++; 70313bca4c6SSepherosa Ziehau } 70413bca4c6SSepherosa Ziehau 70513bca4c6SSepherosa Ziehau /* 70613bca4c6SSepherosa Ziehau * When telling the chip how many segments there are, we 70713bca4c6SSepherosa Ziehau * must use nsegs + 1 instead of just nsegs. Darned if I 70813bca4c6SSepherosa Ziehau * know why. 70913bca4c6SSepherosa Ziehau */ 71013bca4c6SSepherosa Ziehau i++; 71113bca4c6SSepherosa Ziehau 71213bca4c6SSepherosa Ziehau d->vge_sts = ctx->vge_m0->m_pkthdr.len << 16; 71313bca4c6SSepherosa Ziehau d->vge_ctl = ctx->vge_flags|(i << 28)|VGE_TD_LS_NORM; 71413bca4c6SSepherosa Ziehau 71513bca4c6SSepherosa Ziehau if (ctx->vge_m0->m_pkthdr.len > ETHERMTU + ETHER_HDR_LEN) 71613bca4c6SSepherosa Ziehau d->vge_ctl |= VGE_TDCTL_JUMBO; 71713bca4c6SSepherosa Ziehau 71813bca4c6SSepherosa Ziehau ctx->vge_maxsegs = nseg; 71913bca4c6SSepherosa Ziehau } 72013bca4c6SSepherosa Ziehau 72113bca4c6SSepherosa Ziehau /* 72213bca4c6SSepherosa Ziehau * Map a single buffer address. 72313bca4c6SSepherosa Ziehau */ 72413bca4c6SSepherosa Ziehau 72513bca4c6SSepherosa Ziehau static void 72613bca4c6SSepherosa Ziehau vge_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 72713bca4c6SSepherosa Ziehau { 72813bca4c6SSepherosa Ziehau if (error) 72913bca4c6SSepherosa Ziehau return; 73013bca4c6SSepherosa Ziehau 73113bca4c6SSepherosa Ziehau KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 73213bca4c6SSepherosa Ziehau *((bus_addr_t *)arg) = segs->ds_addr; 73313bca4c6SSepherosa Ziehau } 73413bca4c6SSepherosa Ziehau 73513bca4c6SSepherosa Ziehau static int 73613bca4c6SSepherosa Ziehau vge_dma_alloc(device_t dev) 73713bca4c6SSepherosa Ziehau { 73813bca4c6SSepherosa Ziehau struct vge_softc *sc = device_get_softc(dev); 73913bca4c6SSepherosa Ziehau int error, nseg, i, tx_pos = 0, rx_pos = 0; 74013bca4c6SSepherosa Ziehau 74113bca4c6SSepherosa Ziehau /* 74213bca4c6SSepherosa Ziehau * Allocate the parent bus DMA tag appropriate for PCI. 74313bca4c6SSepherosa Ziehau */ 74413bca4c6SSepherosa Ziehau #define VGE_NSEG_NEW 32 74513bca4c6SSepherosa Ziehau error = bus_dma_tag_create(NULL, /* parent */ 74613bca4c6SSepherosa Ziehau 1, 0, /* alignment, boundary */ 74713bca4c6SSepherosa Ziehau BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 74813bca4c6SSepherosa Ziehau BUS_SPACE_MAXADDR, /* highaddr */ 74913bca4c6SSepherosa Ziehau NULL, NULL, /* filter, filterarg */ 75013bca4c6SSepherosa Ziehau MAXBSIZE, VGE_NSEG_NEW, /* maxsize, nsegments */ 75113bca4c6SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 75213bca4c6SSepherosa Ziehau BUS_DMA_ALLOCNOW, /* flags */ 75313bca4c6SSepherosa Ziehau &sc->vge_parent_tag); 75413bca4c6SSepherosa Ziehau if (error) { 75513bca4c6SSepherosa Ziehau device_printf(dev, "can't create parent dma tag\n"); 75613bca4c6SSepherosa Ziehau return error; 75713bca4c6SSepherosa Ziehau } 75813bca4c6SSepherosa Ziehau 75913bca4c6SSepherosa Ziehau /* 76013bca4c6SSepherosa Ziehau * Allocate map for RX mbufs. 76113bca4c6SSepherosa Ziehau */ 76213bca4c6SSepherosa Ziehau nseg = 32; 76313bca4c6SSepherosa Ziehau error = bus_dma_tag_create(sc->vge_parent_tag, ETHER_ALIGN, 0, 76413bca4c6SSepherosa Ziehau BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 76513bca4c6SSepherosa Ziehau NULL, NULL, 76613bca4c6SSepherosa Ziehau MCLBYTES * nseg, nseg, MCLBYTES, 76713bca4c6SSepherosa Ziehau BUS_DMA_ALLOCNOW, &sc->vge_ldata.vge_mtag); 76813bca4c6SSepherosa Ziehau if (error) { 76913bca4c6SSepherosa Ziehau device_printf(dev, "could not allocate mbuf dma tag\n"); 77013bca4c6SSepherosa Ziehau return error; 77113bca4c6SSepherosa Ziehau } 77213bca4c6SSepherosa Ziehau 77313bca4c6SSepherosa Ziehau /* 77413bca4c6SSepherosa Ziehau * Allocate map for TX descriptor list. 77513bca4c6SSepherosa Ziehau */ 77613bca4c6SSepherosa Ziehau error = bus_dma_tag_create(sc->vge_parent_tag, VGE_RING_ALIGN, 0, 77713bca4c6SSepherosa Ziehau BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 77813bca4c6SSepherosa Ziehau NULL, NULL, 77913bca4c6SSepherosa Ziehau VGE_TX_LIST_SZ, 1, VGE_TX_LIST_SZ, 78013bca4c6SSepherosa Ziehau BUS_DMA_ALLOCNOW, 78113bca4c6SSepherosa Ziehau &sc->vge_ldata.vge_tx_list_tag); 78213bca4c6SSepherosa Ziehau if (error) { 78313bca4c6SSepherosa Ziehau device_printf(dev, "could not allocate tx list dma tag\n"); 78413bca4c6SSepherosa Ziehau return error; 78513bca4c6SSepherosa Ziehau } 78613bca4c6SSepherosa Ziehau 78713bca4c6SSepherosa Ziehau /* Allocate DMA'able memory for the TX ring */ 78813bca4c6SSepherosa Ziehau error = bus_dmamem_alloc(sc->vge_ldata.vge_tx_list_tag, 78913bca4c6SSepherosa Ziehau (void **)&sc->vge_ldata.vge_tx_list, 79013bca4c6SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 79113bca4c6SSepherosa Ziehau &sc->vge_ldata.vge_tx_list_map); 79213bca4c6SSepherosa Ziehau if (error) { 79313bca4c6SSepherosa Ziehau device_printf(dev, "could not allocate tx list dma memory\n"); 79413bca4c6SSepherosa Ziehau return error; 79513bca4c6SSepherosa Ziehau } 79613bca4c6SSepherosa Ziehau 79713bca4c6SSepherosa Ziehau /* Load the map for the TX ring. */ 79813bca4c6SSepherosa Ziehau error = bus_dmamap_load(sc->vge_ldata.vge_tx_list_tag, 79913bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list_map, 80013bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list, VGE_TX_LIST_SZ, 80113bca4c6SSepherosa Ziehau vge_dma_map_addr, 80213bca4c6SSepherosa Ziehau &sc->vge_ldata.vge_tx_list_addr, 80313bca4c6SSepherosa Ziehau BUS_DMA_WAITOK); 80413bca4c6SSepherosa Ziehau if (error) { 80513bca4c6SSepherosa Ziehau device_printf(dev, "could not load tx list\n"); 80613bca4c6SSepherosa Ziehau bus_dmamem_free(sc->vge_ldata.vge_tx_list_tag, 80713bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list, 80813bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list_map); 80913bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list = NULL; 81013bca4c6SSepherosa Ziehau return error; 81113bca4c6SSepherosa Ziehau } 81213bca4c6SSepherosa Ziehau 81313bca4c6SSepherosa Ziehau /* Create DMA maps for TX buffers */ 81413bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TX_DESC_CNT; i++) { 81513bca4c6SSepherosa Ziehau error = bus_dmamap_create(sc->vge_ldata.vge_mtag, 0, 81613bca4c6SSepherosa Ziehau &sc->vge_ldata.vge_tx_dmamap[i]); 81713bca4c6SSepherosa Ziehau if (error) { 81813bca4c6SSepherosa Ziehau device_printf(dev, "can't create DMA map for TX\n"); 81913bca4c6SSepherosa Ziehau tx_pos = i; 82013bca4c6SSepherosa Ziehau goto map_fail; 82113bca4c6SSepherosa Ziehau } 82213bca4c6SSepherosa Ziehau } 82313bca4c6SSepherosa Ziehau tx_pos = VGE_TX_DESC_CNT; 82413bca4c6SSepherosa Ziehau 82513bca4c6SSepherosa Ziehau /* 82613bca4c6SSepherosa Ziehau * Allocate map for RX descriptor list. 82713bca4c6SSepherosa Ziehau */ 82813bca4c6SSepherosa Ziehau error = bus_dma_tag_create(sc->vge_parent_tag, VGE_RING_ALIGN, 0, 82913bca4c6SSepherosa Ziehau BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 83013bca4c6SSepherosa Ziehau NULL, NULL, 83113bca4c6SSepherosa Ziehau VGE_TX_LIST_SZ, 1, VGE_TX_LIST_SZ, 83213bca4c6SSepherosa Ziehau BUS_DMA_ALLOCNOW, 83313bca4c6SSepherosa Ziehau &sc->vge_ldata.vge_rx_list_tag); 83413bca4c6SSepherosa Ziehau if (error) { 83513bca4c6SSepherosa Ziehau device_printf(dev, "could not allocate rx list dma tag\n"); 83613bca4c6SSepherosa Ziehau return error; 83713bca4c6SSepherosa Ziehau } 83813bca4c6SSepherosa Ziehau 83913bca4c6SSepherosa Ziehau /* Allocate DMA'able memory for the RX ring */ 84013bca4c6SSepherosa Ziehau error = bus_dmamem_alloc(sc->vge_ldata.vge_rx_list_tag, 84113bca4c6SSepherosa Ziehau (void **)&sc->vge_ldata.vge_rx_list, 84213bca4c6SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO, 84313bca4c6SSepherosa Ziehau &sc->vge_ldata.vge_rx_list_map); 84413bca4c6SSepherosa Ziehau if (error) { 84513bca4c6SSepherosa Ziehau device_printf(dev, "could not allocate rx list dma memory\n"); 84613bca4c6SSepherosa Ziehau return error; 84713bca4c6SSepherosa Ziehau } 84813bca4c6SSepherosa Ziehau 84913bca4c6SSepherosa Ziehau /* Load the map for the RX ring. */ 85013bca4c6SSepherosa Ziehau error = bus_dmamap_load(sc->vge_ldata.vge_rx_list_tag, 85113bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list_map, 85213bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list, VGE_TX_LIST_SZ, 85313bca4c6SSepherosa Ziehau vge_dma_map_addr, 85413bca4c6SSepherosa Ziehau &sc->vge_ldata.vge_rx_list_addr, 85513bca4c6SSepherosa Ziehau BUS_DMA_WAITOK); 85613bca4c6SSepherosa Ziehau if (error) { 85713bca4c6SSepherosa Ziehau device_printf(dev, "could not load rx list\n"); 85813bca4c6SSepherosa Ziehau bus_dmamem_free(sc->vge_ldata.vge_rx_list_tag, 85913bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list, 86013bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list_map); 86113bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list = NULL; 86213bca4c6SSepherosa Ziehau return error; 86313bca4c6SSepherosa Ziehau } 86413bca4c6SSepherosa Ziehau 86513bca4c6SSepherosa Ziehau /* Create DMA maps for RX buffers */ 86613bca4c6SSepherosa Ziehau for (i = 0; i < VGE_RX_DESC_CNT; i++) { 86713bca4c6SSepherosa Ziehau error = bus_dmamap_create(sc->vge_ldata.vge_mtag, 0, 86813bca4c6SSepherosa Ziehau &sc->vge_ldata.vge_rx_dmamap[i]); 86913bca4c6SSepherosa Ziehau if (error) { 87013bca4c6SSepherosa Ziehau device_printf(dev, "can't create DMA map for RX\n"); 87113bca4c6SSepherosa Ziehau rx_pos = i; 87213bca4c6SSepherosa Ziehau goto map_fail; 87313bca4c6SSepherosa Ziehau } 87413bca4c6SSepherosa Ziehau } 87513bca4c6SSepherosa Ziehau return (0); 87613bca4c6SSepherosa Ziehau 87713bca4c6SSepherosa Ziehau map_fail: 87813bca4c6SSepherosa Ziehau for (i = 0; i < tx_pos; ++i) { 87913bca4c6SSepherosa Ziehau error = bus_dmamap_destroy(sc->vge_ldata.vge_mtag, 88013bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_dmamap[i]); 88113bca4c6SSepherosa Ziehau } 88213bca4c6SSepherosa Ziehau for (i = 0; i < rx_pos; ++i) { 88313bca4c6SSepherosa Ziehau error = bus_dmamap_destroy(sc->vge_ldata.vge_mtag, 88413bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_dmamap[i]); 88513bca4c6SSepherosa Ziehau } 88613bca4c6SSepherosa Ziehau bus_dma_tag_destroy(sc->vge_ldata.vge_mtag); 88713bca4c6SSepherosa Ziehau sc->vge_ldata.vge_mtag = NULL; 88813bca4c6SSepherosa Ziehau 88913bca4c6SSepherosa Ziehau return error; 89013bca4c6SSepherosa Ziehau } 89113bca4c6SSepherosa Ziehau 89213bca4c6SSepherosa Ziehau static void 89313bca4c6SSepherosa Ziehau vge_dma_free(struct vge_softc *sc) 89413bca4c6SSepherosa Ziehau { 89513bca4c6SSepherosa Ziehau /* Unload and free the RX DMA ring memory and map */ 89613bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_rx_list_tag) { 89713bca4c6SSepherosa Ziehau bus_dmamap_unload(sc->vge_ldata.vge_rx_list_tag, 89813bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list_map); 89913bca4c6SSepherosa Ziehau bus_dmamem_free(sc->vge_ldata.vge_rx_list_tag, 90013bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list, 90113bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list_map); 90213bca4c6SSepherosa Ziehau } 90313bca4c6SSepherosa Ziehau 90413bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_rx_list_tag) 90513bca4c6SSepherosa Ziehau bus_dma_tag_destroy(sc->vge_ldata.vge_rx_list_tag); 90613bca4c6SSepherosa Ziehau 90713bca4c6SSepherosa Ziehau /* Unload and free the TX DMA ring memory and map */ 90813bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_tx_list_tag) { 90913bca4c6SSepherosa Ziehau bus_dmamap_unload(sc->vge_ldata.vge_tx_list_tag, 91013bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list_map); 91113bca4c6SSepherosa Ziehau bus_dmamem_free(sc->vge_ldata.vge_tx_list_tag, 91213bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list, 91313bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list_map); 91413bca4c6SSepherosa Ziehau } 91513bca4c6SSepherosa Ziehau 91613bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_tx_list_tag) 91713bca4c6SSepherosa Ziehau bus_dma_tag_destroy(sc->vge_ldata.vge_tx_list_tag); 91813bca4c6SSepherosa Ziehau 91913bca4c6SSepherosa Ziehau /* Destroy all the RX and TX buffer maps */ 92013bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_mtag) { 92113bca4c6SSepherosa Ziehau int i; 92213bca4c6SSepherosa Ziehau 92313bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TX_DESC_CNT; i++) { 92413bca4c6SSepherosa Ziehau bus_dmamap_destroy(sc->vge_ldata.vge_mtag, 92513bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_dmamap[i]); 92613bca4c6SSepherosa Ziehau } 92713bca4c6SSepherosa Ziehau for (i = 0; i < VGE_RX_DESC_CNT; i++) { 92813bca4c6SSepherosa Ziehau bus_dmamap_destroy(sc->vge_ldata.vge_mtag, 92913bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_dmamap[i]); 93013bca4c6SSepherosa Ziehau } 93113bca4c6SSepherosa Ziehau bus_dma_tag_destroy(sc->vge_ldata.vge_mtag); 93213bca4c6SSepherosa Ziehau } 93313bca4c6SSepherosa Ziehau 93413bca4c6SSepherosa Ziehau if (sc->vge_parent_tag) 93513bca4c6SSepherosa Ziehau bus_dma_tag_destroy(sc->vge_parent_tag); 93613bca4c6SSepherosa Ziehau } 93713bca4c6SSepherosa Ziehau 93813bca4c6SSepherosa Ziehau /* 93913bca4c6SSepherosa Ziehau * Attach the interface. Allocate softc structures, do ifmedia 94013bca4c6SSepherosa Ziehau * setup and ethernet/BPF attach. 94113bca4c6SSepherosa Ziehau */ 94213bca4c6SSepherosa Ziehau static int 94313bca4c6SSepherosa Ziehau vge_attach(device_t dev) 94413bca4c6SSepherosa Ziehau { 94513bca4c6SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN]; 94613bca4c6SSepherosa Ziehau struct vge_softc *sc; 94713bca4c6SSepherosa Ziehau struct ifnet *ifp; 94813bca4c6SSepherosa Ziehau int error = 0; 94913bca4c6SSepherosa Ziehau 95013bca4c6SSepherosa Ziehau sc = device_get_softc(dev); 95113bca4c6SSepherosa Ziehau ifp = &sc->arpcom.ac_if; 95213bca4c6SSepherosa Ziehau 95313bca4c6SSepherosa Ziehau /* Initialize if_xname early, so if_printf() can be used */ 95413bca4c6SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 95513bca4c6SSepherosa Ziehau 95613bca4c6SSepherosa Ziehau /* 95713bca4c6SSepherosa Ziehau * Map control/status registers. 95813bca4c6SSepherosa Ziehau */ 95913bca4c6SSepherosa Ziehau pci_enable_busmaster(dev); 96013bca4c6SSepherosa Ziehau 96113bca4c6SSepherosa Ziehau sc->vge_res_rid = VGE_PCI_LOMEM; 96213bca4c6SSepherosa Ziehau sc->vge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 96313bca4c6SSepherosa Ziehau &sc->vge_res_rid, RF_ACTIVE); 96413bca4c6SSepherosa Ziehau if (sc->vge_res == NULL) { 96513bca4c6SSepherosa Ziehau device_printf(dev, "couldn't map ports/memory\n"); 96613bca4c6SSepherosa Ziehau return ENXIO; 96713bca4c6SSepherosa Ziehau } 96813bca4c6SSepherosa Ziehau 96913bca4c6SSepherosa Ziehau sc->vge_btag = rman_get_bustag(sc->vge_res); 97013bca4c6SSepherosa Ziehau sc->vge_bhandle = rman_get_bushandle(sc->vge_res); 97113bca4c6SSepherosa Ziehau 97213bca4c6SSepherosa Ziehau /* Allocate interrupt */ 97313bca4c6SSepherosa Ziehau sc->vge_irq_rid = 0; 97413bca4c6SSepherosa Ziehau sc->vge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->vge_irq_rid, 97513bca4c6SSepherosa Ziehau RF_SHAREABLE | RF_ACTIVE); 97613bca4c6SSepherosa Ziehau if (sc->vge_irq == NULL) { 97713bca4c6SSepherosa Ziehau device_printf(dev, "couldn't map interrupt\n"); 97813bca4c6SSepherosa Ziehau error = ENXIO; 97913bca4c6SSepherosa Ziehau goto fail; 98013bca4c6SSepherosa Ziehau } 98113bca4c6SSepherosa Ziehau 98213bca4c6SSepherosa Ziehau /* Reset the adapter. */ 98313bca4c6SSepherosa Ziehau vge_reset(sc); 98413bca4c6SSepherosa Ziehau 98513bca4c6SSepherosa Ziehau /* 98613bca4c6SSepherosa Ziehau * Get station address from the EEPROM. 98713bca4c6SSepherosa Ziehau */ 98813bca4c6SSepherosa Ziehau vge_read_eeprom(sc, eaddr, VGE_EE_EADDR, 3, 0); 98913bca4c6SSepherosa Ziehau 99013bca4c6SSepherosa Ziehau /* Allocate DMA related stuffs */ 99113bca4c6SSepherosa Ziehau error = vge_dma_alloc(dev); 99213bca4c6SSepherosa Ziehau if (error) 99313bca4c6SSepherosa Ziehau goto fail; 99413bca4c6SSepherosa Ziehau 99513bca4c6SSepherosa Ziehau /* Do MII setup */ 99613bca4c6SSepherosa Ziehau error = mii_phy_probe(dev, &sc->vge_miibus, vge_ifmedia_upd, 99713bca4c6SSepherosa Ziehau vge_ifmedia_sts); 99813bca4c6SSepherosa Ziehau if (error) { 99913bca4c6SSepherosa Ziehau device_printf(dev, "MII without any phy!\n"); 100013bca4c6SSepherosa Ziehau goto fail; 100113bca4c6SSepherosa Ziehau } 100213bca4c6SSepherosa Ziehau 100313bca4c6SSepherosa Ziehau ifp->if_softc = sc; 100413bca4c6SSepherosa Ziehau ifp->if_mtu = ETHERMTU; 100513bca4c6SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 100613bca4c6SSepherosa Ziehau ifp->if_init = vge_init; 100713bca4c6SSepherosa Ziehau ifp->if_start = vge_start; 100813bca4c6SSepherosa Ziehau ifp->if_watchdog = vge_watchdog; 100913bca4c6SSepherosa Ziehau ifp->if_ioctl = vge_ioctl; 101013bca4c6SSepherosa Ziehau #ifdef DEVICE_POLLING 101113bca4c6SSepherosa Ziehau ifp->if_poll = vge_poll; 101213bca4c6SSepherosa Ziehau #endif 101313bca4c6SSepherosa Ziehau ifp->if_hwassist = VGE_CSUM_FEATURES; 101413bca4c6SSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_MTU | 101513bca4c6SSepherosa Ziehau IFCAP_HWCSUM | 101613bca4c6SSepherosa Ziehau IFCAP_VLAN_HWTAGGING; 101713bca4c6SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities; 101813bca4c6SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, VGE_IFQ_MAXLEN); 101913bca4c6SSepherosa Ziehau ifq_set_ready(&ifp->if_snd); 102013bca4c6SSepherosa Ziehau 102113bca4c6SSepherosa Ziehau /* 102213bca4c6SSepherosa Ziehau * Call MI attach routine. 102313bca4c6SSepherosa Ziehau */ 102413bca4c6SSepherosa Ziehau ether_ifattach(ifp, eaddr, NULL); 102513bca4c6SSepherosa Ziehau 102613bca4c6SSepherosa Ziehau /* Hook interrupt last to avoid having to lock softc */ 102713bca4c6SSepherosa Ziehau error = bus_setup_intr(dev, sc->vge_irq, INTR_MPSAFE, vge_intr, sc, 102813bca4c6SSepherosa Ziehau &sc->vge_intrhand, ifp->if_serializer); 102913bca4c6SSepherosa Ziehau if (error) { 103013bca4c6SSepherosa Ziehau device_printf(dev, "couldn't set up irq\n"); 103113bca4c6SSepherosa Ziehau ether_ifdetach(ifp); 103213bca4c6SSepherosa Ziehau goto fail; 103313bca4c6SSepherosa Ziehau } 103413bca4c6SSepherosa Ziehau 103513bca4c6SSepherosa Ziehau return 0; 103613bca4c6SSepherosa Ziehau fail: 103713bca4c6SSepherosa Ziehau vge_detach(dev); 103813bca4c6SSepherosa Ziehau return error; 103913bca4c6SSepherosa Ziehau } 104013bca4c6SSepherosa Ziehau 104113bca4c6SSepherosa Ziehau /* 104213bca4c6SSepherosa Ziehau * Shutdown hardware and free up resources. This can be called any 104313bca4c6SSepherosa Ziehau * time after the mutex has been initialized. It is called in both 104413bca4c6SSepherosa Ziehau * the error case in attach and the normal detach case so it needs 104513bca4c6SSepherosa Ziehau * to be careful about only freeing resources that have actually been 104613bca4c6SSepherosa Ziehau * allocated. 104713bca4c6SSepherosa Ziehau */ 104813bca4c6SSepherosa Ziehau static int 104913bca4c6SSepherosa Ziehau vge_detach(device_t dev) 105013bca4c6SSepherosa Ziehau { 105113bca4c6SSepherosa Ziehau struct vge_softc *sc = device_get_softc(dev); 105213bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 105313bca4c6SSepherosa Ziehau 105413bca4c6SSepherosa Ziehau /* These should only be active if attach succeeded */ 105513bca4c6SSepherosa Ziehau if (device_is_attached(dev)) { 105613bca4c6SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 105713bca4c6SSepherosa Ziehau 105813bca4c6SSepherosa Ziehau vge_stop(sc); 105913bca4c6SSepherosa Ziehau bus_teardown_intr(dev, sc->vge_irq, sc->vge_intrhand); 106013bca4c6SSepherosa Ziehau /* 106113bca4c6SSepherosa Ziehau * Force off the IFF_UP flag here, in case someone 106213bca4c6SSepherosa Ziehau * still had a BPF descriptor attached to this 106313bca4c6SSepherosa Ziehau * interface. If they do, ether_ifattach() will cause 106413bca4c6SSepherosa Ziehau * the BPF code to try and clear the promisc mode 106513bca4c6SSepherosa Ziehau * flag, which will bubble down to vge_ioctl(), 106613bca4c6SSepherosa Ziehau * which will try to call vge_init() again. This will 106713bca4c6SSepherosa Ziehau * turn the NIC back on and restart the MII ticker, 106813bca4c6SSepherosa Ziehau * which will panic the system when the kernel tries 106913bca4c6SSepherosa Ziehau * to invoke the vge_tick() function that isn't there 107013bca4c6SSepherosa Ziehau * anymore. 107113bca4c6SSepherosa Ziehau */ 107213bca4c6SSepherosa Ziehau ifp->if_flags &= ~IFF_UP; 107313bca4c6SSepherosa Ziehau 107413bca4c6SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 107513bca4c6SSepherosa Ziehau 107613bca4c6SSepherosa Ziehau ether_ifdetach(ifp); 107713bca4c6SSepherosa Ziehau } 107813bca4c6SSepherosa Ziehau 107913bca4c6SSepherosa Ziehau if (sc->vge_miibus) 108013bca4c6SSepherosa Ziehau device_delete_child(dev, sc->vge_miibus); 108113bca4c6SSepherosa Ziehau bus_generic_detach(dev); 108213bca4c6SSepherosa Ziehau 108313bca4c6SSepherosa Ziehau if (sc->vge_irq) { 108413bca4c6SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->vge_irq_rid, 108513bca4c6SSepherosa Ziehau sc->vge_irq); 108613bca4c6SSepherosa Ziehau } 108713bca4c6SSepherosa Ziehau 108813bca4c6SSepherosa Ziehau if (sc->vge_res) { 108913bca4c6SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->vge_res_rid, 109013bca4c6SSepherosa Ziehau sc->vge_res); 109113bca4c6SSepherosa Ziehau } 109213bca4c6SSepherosa Ziehau 109313bca4c6SSepherosa Ziehau vge_dma_free(sc); 109413bca4c6SSepherosa Ziehau return (0); 109513bca4c6SSepherosa Ziehau } 109613bca4c6SSepherosa Ziehau 109713bca4c6SSepherosa Ziehau static int 109813bca4c6SSepherosa Ziehau vge_newbuf(struct vge_softc *sc, int idx, struct mbuf *m) 109913bca4c6SSepherosa Ziehau { 110013bca4c6SSepherosa Ziehau struct vge_dmaload_arg arg; 110113bca4c6SSepherosa Ziehau struct mbuf *n = NULL; 110213bca4c6SSepherosa Ziehau int i, error; 110313bca4c6SSepherosa Ziehau 110413bca4c6SSepherosa Ziehau if (m == NULL) { 110513bca4c6SSepherosa Ziehau n = m_getcl(MB_DONTWAIT, MT_DATA, M_PKTHDR); 110613bca4c6SSepherosa Ziehau if (n == NULL) 110713bca4c6SSepherosa Ziehau return (ENOBUFS); 110813bca4c6SSepherosa Ziehau m = n; 110913bca4c6SSepherosa Ziehau } else { 111013bca4c6SSepherosa Ziehau m->m_data = m->m_ext.ext_buf; 111113bca4c6SSepherosa Ziehau } 111213bca4c6SSepherosa Ziehau 111313bca4c6SSepherosa Ziehau 111413bca4c6SSepherosa Ziehau #ifdef VGE_FIXUP_RX 111513bca4c6SSepherosa Ziehau /* 111613bca4c6SSepherosa Ziehau * This is part of an evil trick to deal with non-x86 platforms. 111713bca4c6SSepherosa Ziehau * The VIA chip requires RX buffers to be aligned on 32-bit 111813bca4c6SSepherosa Ziehau * boundaries, but that will hose non-x86 machines. To get around 111913bca4c6SSepherosa Ziehau * this, we leave some empty space at the start of each buffer 112013bca4c6SSepherosa Ziehau * and for non-x86 hosts, we copy the buffer back two bytes 112113bca4c6SSepherosa Ziehau * to achieve word alignment. This is slightly more efficient 112213bca4c6SSepherosa Ziehau * than allocating a new buffer, copying the contents, and 112313bca4c6SSepherosa Ziehau * discarding the old buffer. 112413bca4c6SSepherosa Ziehau */ 112513bca4c6SSepherosa Ziehau m->m_len = m->m_pkthdr.len = MCLBYTES - VGE_ETHER_ALIGN; 112613bca4c6SSepherosa Ziehau m_adj(m, VGE_ETHER_ALIGN); 112713bca4c6SSepherosa Ziehau #else 112813bca4c6SSepherosa Ziehau m->m_len = m->m_pkthdr.len = MCLBYTES; 112913bca4c6SSepherosa Ziehau #endif 113013bca4c6SSepherosa Ziehau 113113bca4c6SSepherosa Ziehau arg.sc = sc; 113213bca4c6SSepherosa Ziehau arg.vge_idx = idx; 113313bca4c6SSepherosa Ziehau arg.vge_maxsegs = 1; 113413bca4c6SSepherosa Ziehau arg.vge_flags = 0; 113513bca4c6SSepherosa Ziehau 113613bca4c6SSepherosa Ziehau error = bus_dmamap_load_mbuf(sc->vge_ldata.vge_mtag, 113713bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_dmamap[idx], m, 113813bca4c6SSepherosa Ziehau vge_dma_map_rx_desc, &arg, BUS_DMA_NOWAIT); 113913bca4c6SSepherosa Ziehau if (error || arg.vge_maxsegs != 1) { 114013bca4c6SSepherosa Ziehau if (n != NULL) 114113bca4c6SSepherosa Ziehau m_freem(n); 114213bca4c6SSepherosa Ziehau return (ENOMEM); 114313bca4c6SSepherosa Ziehau } 114413bca4c6SSepherosa Ziehau 114513bca4c6SSepherosa Ziehau /* 114613bca4c6SSepherosa Ziehau * Note: the manual fails to document the fact that for 114713bca4c6SSepherosa Ziehau * proper opration, the driver needs to replentish the RX 114813bca4c6SSepherosa Ziehau * DMA ring 4 descriptors at a time (rather than one at a 114913bca4c6SSepherosa Ziehau * time, like most chips). We can allocate the new buffers 115013bca4c6SSepherosa Ziehau * but we should not set the OWN bits until we're ready 115113bca4c6SSepherosa Ziehau * to hand back 4 of them in one shot. 115213bca4c6SSepherosa Ziehau */ 115313bca4c6SSepherosa Ziehau 115413bca4c6SSepherosa Ziehau #define VGE_RXCHUNK 4 115513bca4c6SSepherosa Ziehau sc->vge_rx_consumed++; 115613bca4c6SSepherosa Ziehau if (sc->vge_rx_consumed == VGE_RXCHUNK) { 115713bca4c6SSepherosa Ziehau for (i = idx; i != idx - sc->vge_rx_consumed; i--) { 115813bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list[i].vge_sts |= 115913bca4c6SSepherosa Ziehau htole32(VGE_RDSTS_OWN); 116013bca4c6SSepherosa Ziehau } 116113bca4c6SSepherosa Ziehau sc->vge_rx_consumed = 0; 116213bca4c6SSepherosa Ziehau } 116313bca4c6SSepherosa Ziehau 116413bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_mbuf[idx] = m; 116513bca4c6SSepherosa Ziehau 116613bca4c6SSepherosa Ziehau bus_dmamap_sync(sc->vge_ldata.vge_mtag, 116713bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_dmamap[idx], BUS_DMASYNC_PREREAD); 116813bca4c6SSepherosa Ziehau 116913bca4c6SSepherosa Ziehau return (0); 117013bca4c6SSepherosa Ziehau } 117113bca4c6SSepherosa Ziehau 117213bca4c6SSepherosa Ziehau static int 11737b9f668cSSascha Wildner vge_tx_list_init(struct vge_softc *sc) 117413bca4c6SSepherosa Ziehau { 117513bca4c6SSepherosa Ziehau bzero ((char *)sc->vge_ldata.vge_tx_list, VGE_TX_LIST_SZ); 117613bca4c6SSepherosa Ziehau bzero ((char *)&sc->vge_ldata.vge_tx_mbuf, 117713bca4c6SSepherosa Ziehau (VGE_TX_DESC_CNT * sizeof(struct mbuf *))); 117813bca4c6SSepherosa Ziehau 117913bca4c6SSepherosa Ziehau bus_dmamap_sync(sc->vge_ldata.vge_tx_list_tag, 118013bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list_map, BUS_DMASYNC_PREWRITE); 118113bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_prodidx = 0; 118213bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_considx = 0; 118313bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_free = VGE_TX_DESC_CNT; 118413bca4c6SSepherosa Ziehau 118513bca4c6SSepherosa Ziehau return (0); 118613bca4c6SSepherosa Ziehau } 118713bca4c6SSepherosa Ziehau 118813bca4c6SSepherosa Ziehau static int 118913bca4c6SSepherosa Ziehau vge_rx_list_init(struct vge_softc *sc) 119013bca4c6SSepherosa Ziehau { 119113bca4c6SSepherosa Ziehau int i; 119213bca4c6SSepherosa Ziehau 119313bca4c6SSepherosa Ziehau bzero(sc->vge_ldata.vge_rx_list, VGE_RX_LIST_SZ); 119413bca4c6SSepherosa Ziehau bzero(&sc->vge_ldata.vge_rx_mbuf, 119513bca4c6SSepherosa Ziehau VGE_RX_DESC_CNT * sizeof(struct mbuf *)); 119613bca4c6SSepherosa Ziehau 119713bca4c6SSepherosa Ziehau sc->vge_rx_consumed = 0; 119813bca4c6SSepherosa Ziehau 119913bca4c6SSepherosa Ziehau for (i = 0; i < VGE_RX_DESC_CNT; i++) { 120013bca4c6SSepherosa Ziehau if (vge_newbuf(sc, i, NULL) == ENOBUFS) 120113bca4c6SSepherosa Ziehau return (ENOBUFS); 120213bca4c6SSepherosa Ziehau } 120313bca4c6SSepherosa Ziehau 120413bca4c6SSepherosa Ziehau /* Flush the RX descriptors */ 120513bca4c6SSepherosa Ziehau bus_dmamap_sync(sc->vge_ldata.vge_rx_list_tag, 120613bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list_map, 120713bca4c6SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 120813bca4c6SSepherosa Ziehau 120913bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_prodidx = 0; 121013bca4c6SSepherosa Ziehau sc->vge_rx_consumed = 0; 121113bca4c6SSepherosa Ziehau sc->vge_head = sc->vge_tail = NULL; 121213bca4c6SSepherosa Ziehau return (0); 121313bca4c6SSepherosa Ziehau } 121413bca4c6SSepherosa Ziehau 121513bca4c6SSepherosa Ziehau #ifdef VGE_FIXUP_RX 121613bca4c6SSepherosa Ziehau static __inline void 121713bca4c6SSepherosa Ziehau vge_fixup_rx(struct mbuf *m) 121813bca4c6SSepherosa Ziehau { 121913bca4c6SSepherosa Ziehau uint16_t *src, *dst; 122013bca4c6SSepherosa Ziehau int i; 122113bca4c6SSepherosa Ziehau 122213bca4c6SSepherosa Ziehau src = mtod(m, uint16_t *); 122313bca4c6SSepherosa Ziehau dst = src - 1; 122413bca4c6SSepherosa Ziehau 122513bca4c6SSepherosa Ziehau for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 122613bca4c6SSepherosa Ziehau *dst++ = *src++; 122713bca4c6SSepherosa Ziehau 122813bca4c6SSepherosa Ziehau m->m_data -= ETHER_ALIGN; 122913bca4c6SSepherosa Ziehau } 123013bca4c6SSepherosa Ziehau #endif 123113bca4c6SSepherosa Ziehau 123213bca4c6SSepherosa Ziehau /* 123313bca4c6SSepherosa Ziehau * RX handler. We support the reception of jumbo frames that have 123413bca4c6SSepherosa Ziehau * been fragmented across multiple 2K mbuf cluster buffers. 123513bca4c6SSepherosa Ziehau */ 123613bca4c6SSepherosa Ziehau static void 123713bca4c6SSepherosa Ziehau vge_rxeof(struct vge_softc *sc, int count) 123813bca4c6SSepherosa Ziehau { 123913bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 124013bca4c6SSepherosa Ziehau struct mbuf *m; 124113bca4c6SSepherosa Ziehau int i, total_len, lim = 0; 124213bca4c6SSepherosa Ziehau struct vge_rx_desc *cur_rx; 124313bca4c6SSepherosa Ziehau uint32_t rxstat, rxctl; 124413bca4c6SSepherosa Ziehau 124513bca4c6SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 124613bca4c6SSepherosa Ziehau 124713bca4c6SSepherosa Ziehau i = sc->vge_ldata.vge_rx_prodidx; 124813bca4c6SSepherosa Ziehau 124913bca4c6SSepherosa Ziehau /* Invalidate the descriptor memory */ 125013bca4c6SSepherosa Ziehau 125113bca4c6SSepherosa Ziehau bus_dmamap_sync(sc->vge_ldata.vge_rx_list_tag, 125213bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list_map, BUS_DMASYNC_POSTREAD); 125313bca4c6SSepherosa Ziehau 125413bca4c6SSepherosa Ziehau while (!VGE_OWN(&sc->vge_ldata.vge_rx_list[i])) { 125513bca4c6SSepherosa Ziehau #ifdef DEVICE_POLLING 125613bca4c6SSepherosa Ziehau if (count >= 0 && count-- == 0) 125713bca4c6SSepherosa Ziehau break; 125813bca4c6SSepherosa Ziehau #endif 125913bca4c6SSepherosa Ziehau 126013bca4c6SSepherosa Ziehau cur_rx = &sc->vge_ldata.vge_rx_list[i]; 126113bca4c6SSepherosa Ziehau m = sc->vge_ldata.vge_rx_mbuf[i]; 126213bca4c6SSepherosa Ziehau total_len = VGE_RXBYTES(cur_rx); 126313bca4c6SSepherosa Ziehau rxstat = le32toh(cur_rx->vge_sts); 126413bca4c6SSepherosa Ziehau rxctl = le32toh(cur_rx->vge_ctl); 126513bca4c6SSepherosa Ziehau 126613bca4c6SSepherosa Ziehau /* Invalidate the RX mbuf and unload its map */ 126713bca4c6SSepherosa Ziehau bus_dmamap_sync(sc->vge_ldata.vge_mtag, 126813bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_dmamap[i], 126913bca4c6SSepherosa Ziehau BUS_DMASYNC_POSTWRITE); 127013bca4c6SSepherosa Ziehau bus_dmamap_unload(sc->vge_ldata.vge_mtag, 127113bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_dmamap[i]); 127213bca4c6SSepherosa Ziehau 127313bca4c6SSepherosa Ziehau /* 127413bca4c6SSepherosa Ziehau * If the 'start of frame' bit is set, this indicates 127513bca4c6SSepherosa Ziehau * either the first fragment in a multi-fragment receive, 127613bca4c6SSepherosa Ziehau * or an intermediate fragment. Either way, we want to 127713bca4c6SSepherosa Ziehau * accumulate the buffers. 127813bca4c6SSepherosa Ziehau */ 127913bca4c6SSepherosa Ziehau if (rxstat & VGE_RXPKT_SOF) { 128013bca4c6SSepherosa Ziehau m->m_len = MCLBYTES - VGE_ETHER_ALIGN; 128113bca4c6SSepherosa Ziehau if (sc->vge_head == NULL) { 128213bca4c6SSepherosa Ziehau sc->vge_head = sc->vge_tail = m; 128313bca4c6SSepherosa Ziehau } else { 128413bca4c6SSepherosa Ziehau m->m_flags &= ~M_PKTHDR; 128513bca4c6SSepherosa Ziehau sc->vge_tail->m_next = m; 128613bca4c6SSepherosa Ziehau sc->vge_tail = m; 128713bca4c6SSepherosa Ziehau } 128813bca4c6SSepherosa Ziehau vge_newbuf(sc, i, NULL); 128913bca4c6SSepherosa Ziehau VGE_RX_DESC_INC(i); 129013bca4c6SSepherosa Ziehau continue; 129113bca4c6SSepherosa Ziehau } 129213bca4c6SSepherosa Ziehau 129313bca4c6SSepherosa Ziehau /* 129413bca4c6SSepherosa Ziehau * Bad/error frames will have the RXOK bit cleared. 129513bca4c6SSepherosa Ziehau * However, there's one error case we want to allow: 129613bca4c6SSepherosa Ziehau * if a VLAN tagged frame arrives and the chip can't 129713bca4c6SSepherosa Ziehau * match it against the CAM filter, it considers this 129813bca4c6SSepherosa Ziehau * a 'VLAN CAM filter miss' and clears the 'RXOK' bit. 129913bca4c6SSepherosa Ziehau * We don't want to drop the frame though: our VLAN 130013bca4c6SSepherosa Ziehau * filtering is done in software. 130113bca4c6SSepherosa Ziehau */ 130213bca4c6SSepherosa Ziehau if (!(rxstat & VGE_RDSTS_RXOK) && !(rxstat & VGE_RDSTS_VIDM) && 130313bca4c6SSepherosa Ziehau !(rxstat & VGE_RDSTS_CSUMERR)) { 130413bca4c6SSepherosa Ziehau ifp->if_ierrors++; 130513bca4c6SSepherosa Ziehau /* 130613bca4c6SSepherosa Ziehau * If this is part of a multi-fragment packet, 130713bca4c6SSepherosa Ziehau * discard all the pieces. 130813bca4c6SSepherosa Ziehau */ 130913bca4c6SSepherosa Ziehau if (sc->vge_head != NULL) { 131013bca4c6SSepherosa Ziehau m_freem(sc->vge_head); 131113bca4c6SSepherosa Ziehau sc->vge_head = sc->vge_tail = NULL; 131213bca4c6SSepherosa Ziehau } 131313bca4c6SSepherosa Ziehau vge_newbuf(sc, i, m); 131413bca4c6SSepherosa Ziehau VGE_RX_DESC_INC(i); 131513bca4c6SSepherosa Ziehau continue; 131613bca4c6SSepherosa Ziehau } 131713bca4c6SSepherosa Ziehau 131813bca4c6SSepherosa Ziehau /* 131913bca4c6SSepherosa Ziehau * If allocating a replacement mbuf fails, 132013bca4c6SSepherosa Ziehau * reload the current one. 132113bca4c6SSepherosa Ziehau */ 132213bca4c6SSepherosa Ziehau if (vge_newbuf(sc, i, NULL)) { 132313bca4c6SSepherosa Ziehau ifp->if_ierrors++; 132413bca4c6SSepherosa Ziehau if (sc->vge_head != NULL) { 132513bca4c6SSepherosa Ziehau m_freem(sc->vge_head); 132613bca4c6SSepherosa Ziehau sc->vge_head = sc->vge_tail = NULL; 132713bca4c6SSepherosa Ziehau } 132813bca4c6SSepherosa Ziehau vge_newbuf(sc, i, m); 132913bca4c6SSepherosa Ziehau VGE_RX_DESC_INC(i); 133013bca4c6SSepherosa Ziehau continue; 133113bca4c6SSepherosa Ziehau } 133213bca4c6SSepherosa Ziehau 133313bca4c6SSepherosa Ziehau VGE_RX_DESC_INC(i); 133413bca4c6SSepherosa Ziehau 133513bca4c6SSepherosa Ziehau if (sc->vge_head != NULL) { 133613bca4c6SSepherosa Ziehau m->m_len = total_len % (MCLBYTES - VGE_ETHER_ALIGN); 133713bca4c6SSepherosa Ziehau /* 133813bca4c6SSepherosa Ziehau * Special case: if there's 4 bytes or less 133913bca4c6SSepherosa Ziehau * in this buffer, the mbuf can be discarded: 134013bca4c6SSepherosa Ziehau * the last 4 bytes is the CRC, which we don't 134113bca4c6SSepherosa Ziehau * care about anyway. 134213bca4c6SSepherosa Ziehau */ 134313bca4c6SSepherosa Ziehau if (m->m_len <= ETHER_CRC_LEN) { 134413bca4c6SSepherosa Ziehau sc->vge_tail->m_len -= 134513bca4c6SSepherosa Ziehau (ETHER_CRC_LEN - m->m_len); 134613bca4c6SSepherosa Ziehau m_freem(m); 134713bca4c6SSepherosa Ziehau } else { 134813bca4c6SSepherosa Ziehau m->m_len -= ETHER_CRC_LEN; 134913bca4c6SSepherosa Ziehau m->m_flags &= ~M_PKTHDR; 135013bca4c6SSepherosa Ziehau sc->vge_tail->m_next = m; 135113bca4c6SSepherosa Ziehau } 135213bca4c6SSepherosa Ziehau m = sc->vge_head; 135313bca4c6SSepherosa Ziehau sc->vge_head = sc->vge_tail = NULL; 135413bca4c6SSepherosa Ziehau m->m_pkthdr.len = total_len - ETHER_CRC_LEN; 135513bca4c6SSepherosa Ziehau } else { 135613bca4c6SSepherosa Ziehau m->m_pkthdr.len = m->m_len = 135713bca4c6SSepherosa Ziehau (total_len - ETHER_CRC_LEN); 135813bca4c6SSepherosa Ziehau } 135913bca4c6SSepherosa Ziehau 136013bca4c6SSepherosa Ziehau #ifdef VGE_FIXUP_RX 136113bca4c6SSepherosa Ziehau vge_fixup_rx(m); 136213bca4c6SSepherosa Ziehau #endif 136313bca4c6SSepherosa Ziehau ifp->if_ipackets++; 136413bca4c6SSepherosa Ziehau m->m_pkthdr.rcvif = ifp; 136513bca4c6SSepherosa Ziehau 136613bca4c6SSepherosa Ziehau /* Do RX checksumming if enabled */ 136713bca4c6SSepherosa Ziehau if (ifp->if_capenable & IFCAP_RXCSUM) { 136813bca4c6SSepherosa Ziehau /* Check IP header checksum */ 136913bca4c6SSepherosa Ziehau if (rxctl & VGE_RDCTL_IPPKT) 137013bca4c6SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 137113bca4c6SSepherosa Ziehau if (rxctl & VGE_RDCTL_IPCSUMOK) 137213bca4c6SSepherosa Ziehau m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 137313bca4c6SSepherosa Ziehau 137413bca4c6SSepherosa Ziehau /* Check TCP/UDP checksum */ 137513bca4c6SSepherosa Ziehau if (rxctl & (VGE_RDCTL_TCPPKT|VGE_RDCTL_UDPPKT) && 137613bca4c6SSepherosa Ziehau rxctl & VGE_RDCTL_PROTOCSUMOK) { 137713bca4c6SSepherosa Ziehau m->m_pkthdr.csum_flags |= 137813bca4c6SSepherosa Ziehau CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 137913bca4c6SSepherosa Ziehau m->m_pkthdr.csum_data = 0xffff; 138013bca4c6SSepherosa Ziehau } 138113bca4c6SSepherosa Ziehau } 138213bca4c6SSepherosa Ziehau 138313bca4c6SSepherosa Ziehau if (rxstat & VGE_RDSTS_VTAG) 138413bca4c6SSepherosa Ziehau VLAN_INPUT_TAG(m, ntohs((rxctl & VGE_RDCTL_VLANID))); 138513bca4c6SSepherosa Ziehau else 138613bca4c6SSepherosa Ziehau ifp->if_input(ifp, m); 138713bca4c6SSepherosa Ziehau 138813bca4c6SSepherosa Ziehau lim++; 138913bca4c6SSepherosa Ziehau if (lim == VGE_RX_DESC_CNT) 139013bca4c6SSepherosa Ziehau break; 139113bca4c6SSepherosa Ziehau } 139213bca4c6SSepherosa Ziehau 139313bca4c6SSepherosa Ziehau /* Flush the RX DMA ring */ 139413bca4c6SSepherosa Ziehau bus_dmamap_sync(sc->vge_ldata.vge_rx_list_tag, 139513bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_list_map, 139613bca4c6SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 139713bca4c6SSepherosa Ziehau 139813bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_prodidx = i; 139913bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_RXDESC_RESIDUECNT, lim); 140013bca4c6SSepherosa Ziehau } 140113bca4c6SSepherosa Ziehau 140213bca4c6SSepherosa Ziehau static void 140313bca4c6SSepherosa Ziehau vge_txeof(struct vge_softc *sc) 140413bca4c6SSepherosa Ziehau { 140513bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 140613bca4c6SSepherosa Ziehau uint32_t txstat; 140713bca4c6SSepherosa Ziehau int idx; 140813bca4c6SSepherosa Ziehau 140913bca4c6SSepherosa Ziehau idx = sc->vge_ldata.vge_tx_considx; 141013bca4c6SSepherosa Ziehau 141113bca4c6SSepherosa Ziehau /* Invalidate the TX descriptor list */ 141213bca4c6SSepherosa Ziehau 141313bca4c6SSepherosa Ziehau bus_dmamap_sync(sc->vge_ldata.vge_tx_list_tag, 141413bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list_map, BUS_DMASYNC_POSTREAD); 141513bca4c6SSepherosa Ziehau 141613bca4c6SSepherosa Ziehau while (idx != sc->vge_ldata.vge_tx_prodidx) { 141713bca4c6SSepherosa Ziehau 141813bca4c6SSepherosa Ziehau txstat = le32toh(sc->vge_ldata.vge_tx_list[idx].vge_sts); 141913bca4c6SSepherosa Ziehau if (txstat & VGE_TDSTS_OWN) 142013bca4c6SSepherosa Ziehau break; 142113bca4c6SSepherosa Ziehau 142213bca4c6SSepherosa Ziehau m_freem(sc->vge_ldata.vge_tx_mbuf[idx]); 142313bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_mbuf[idx] = NULL; 142413bca4c6SSepherosa Ziehau bus_dmamap_unload(sc->vge_ldata.vge_mtag, 142513bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_dmamap[idx]); 142613bca4c6SSepherosa Ziehau if (txstat & (VGE_TDSTS_EXCESSCOLL|VGE_TDSTS_COLL)) 142713bca4c6SSepherosa Ziehau ifp->if_collisions++; 142813bca4c6SSepherosa Ziehau if (txstat & VGE_TDSTS_TXERR) 142913bca4c6SSepherosa Ziehau ifp->if_oerrors++; 143013bca4c6SSepherosa Ziehau else 143113bca4c6SSepherosa Ziehau ifp->if_opackets++; 143213bca4c6SSepherosa Ziehau 143313bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_free++; 143413bca4c6SSepherosa Ziehau VGE_TX_DESC_INC(idx); 143513bca4c6SSepherosa Ziehau } 143613bca4c6SSepherosa Ziehau 143713bca4c6SSepherosa Ziehau /* No changes made to the TX ring, so no flush needed */ 143813bca4c6SSepherosa Ziehau if (idx != sc->vge_ldata.vge_tx_considx) { 143913bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_considx = idx; 144013bca4c6SSepherosa Ziehau ifp->if_flags &= ~IFF_OACTIVE; 144113bca4c6SSepherosa Ziehau ifp->if_timer = 0; 144213bca4c6SSepherosa Ziehau } 144313bca4c6SSepherosa Ziehau 144413bca4c6SSepherosa Ziehau /* 144513bca4c6SSepherosa Ziehau * If not all descriptors have been released reaped yet, 144613bca4c6SSepherosa Ziehau * reload the timer so that we will eventually get another 144713bca4c6SSepherosa Ziehau * interrupt that will cause us to re-enter this routine. 144813bca4c6SSepherosa Ziehau * This is done in case the transmitter has gone idle. 144913bca4c6SSepherosa Ziehau */ 145013bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_tx_free != VGE_TX_DESC_CNT) 145113bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS1, VGE_CR1_TIMER0_ENABLE); 145213bca4c6SSepherosa Ziehau } 145313bca4c6SSepherosa Ziehau 145413bca4c6SSepherosa Ziehau static void 145513bca4c6SSepherosa Ziehau vge_tick(struct vge_softc *sc) 145613bca4c6SSepherosa Ziehau { 145713bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 145813bca4c6SSepherosa Ziehau struct mii_data *mii; 145913bca4c6SSepherosa Ziehau 146013bca4c6SSepherosa Ziehau mii = device_get_softc(sc->vge_miibus); 146113bca4c6SSepherosa Ziehau 146213bca4c6SSepherosa Ziehau mii_tick(mii); 146313bca4c6SSepherosa Ziehau if (sc->vge_link) { 1464*f3e7c70dSSepherosa Ziehau if (!(mii->mii_media_status & IFM_ACTIVE)) 146513bca4c6SSepherosa Ziehau sc->vge_link = 0; 146613bca4c6SSepherosa Ziehau } else { 146713bca4c6SSepherosa Ziehau if (mii->mii_media_status & IFM_ACTIVE && 146813bca4c6SSepherosa Ziehau IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 146913bca4c6SSepherosa Ziehau sc->vge_link = 1; 147013bca4c6SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 147113bca4c6SSepherosa Ziehau ifp->if_start(ifp); 147213bca4c6SSepherosa Ziehau } 147313bca4c6SSepherosa Ziehau } 147413bca4c6SSepherosa Ziehau } 147513bca4c6SSepherosa Ziehau 147613bca4c6SSepherosa Ziehau #ifdef DEVICE_POLLING 147713bca4c6SSepherosa Ziehau static void 147813bca4c6SSepherosa Ziehau vge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 147913bca4c6SSepherosa Ziehau { 148013bca4c6SSepherosa Ziehau struct vge_softc *sc = ifp->if_softc; 148113bca4c6SSepherosa Ziehau 148213bca4c6SSepherosa Ziehau sc->rxcycles = count; 148313bca4c6SSepherosa Ziehau 148413bca4c6SSepherosa Ziehau switch (cmd) { 148513bca4c6SSepherosa Ziehau case POLL_REGISTER: 148613bca4c6SSepherosa Ziehau vge_disable_intr(sc); 148713bca4c6SSepherosa Ziehau break; 148813bca4c6SSepherosa Ziehau case POLL_DEREGISTER: 148913bca4c6SSepherosa Ziehau vge_enable_intr(sc, 0xffffffff); 149013bca4c6SSepherosa Ziehau break; 149113bca4c6SSepherosa Ziehau case POLL_ONLY: 149213bca4c6SSepherosa Ziehau case POLL_AND_CHECK_STATUS: 149313bca4c6SSepherosa Ziehau vge_rxeof(sc, count); 149413bca4c6SSepherosa Ziehau vge_txeof(sc); 149513bca4c6SSepherosa Ziehau 149613bca4c6SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 149713bca4c6SSepherosa Ziehau ifp->if_start(ifp); 149813bca4c6SSepherosa Ziehau 149913bca4c6SSepherosa Ziehau /* XXX copy & paste from vge_intr */ 150013bca4c6SSepherosa Ziehau if (cmd == POLL_AND_CHECK_STATUS) { 150113bca4c6SSepherosa Ziehau uint32_t status = 0; 150213bca4c6SSepherosa Ziehau 150313bca4c6SSepherosa Ziehau status = CSR_READ_4(sc, VGE_ISR); 150413bca4c6SSepherosa Ziehau if (status == 0xffffffff) 150513bca4c6SSepherosa Ziehau break; 150613bca4c6SSepherosa Ziehau 150713bca4c6SSepherosa Ziehau if (status) 150813bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_ISR, status); 150913bca4c6SSepherosa Ziehau 151013bca4c6SSepherosa Ziehau if (status & (VGE_ISR_TXDMA_STALL | 151113bca4c6SSepherosa Ziehau VGE_ISR_RXDMA_STALL)) 151213bca4c6SSepherosa Ziehau vge_init(sc); 151313bca4c6SSepherosa Ziehau 151413bca4c6SSepherosa Ziehau if (status & (VGE_ISR_RXOFLOW | VGE_ISR_RXNODESC)) { 151513bca4c6SSepherosa Ziehau ifp->if_ierrors++; 151613bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXQCSRS, VGE_RXQCSR_RUN); 151713bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXQCSRS, VGE_RXQCSR_WAK); 151813bca4c6SSepherosa Ziehau } 151913bca4c6SSepherosa Ziehau } 152013bca4c6SSepherosa Ziehau break; 152113bca4c6SSepherosa Ziehau } 152213bca4c6SSepherosa Ziehau 152313bca4c6SSepherosa Ziehau } 152413bca4c6SSepherosa Ziehau #endif /* DEVICE_POLLING */ 152513bca4c6SSepherosa Ziehau 152613bca4c6SSepherosa Ziehau static void 152713bca4c6SSepherosa Ziehau vge_intr(void *arg) 152813bca4c6SSepherosa Ziehau { 152913bca4c6SSepherosa Ziehau struct vge_softc *sc = arg; 153013bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 153113bca4c6SSepherosa Ziehau uint32_t status; 153213bca4c6SSepherosa Ziehau 153313bca4c6SSepherosa Ziehau if (sc->suspended || !(ifp->if_flags & IFF_UP)) 153413bca4c6SSepherosa Ziehau return; 153513bca4c6SSepherosa Ziehau 153613bca4c6SSepherosa Ziehau /* Disable interrupts */ 153713bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); 153813bca4c6SSepherosa Ziehau 153913bca4c6SSepherosa Ziehau for (;;) { 154013bca4c6SSepherosa Ziehau status = CSR_READ_4(sc, VGE_ISR); 154113bca4c6SSepherosa Ziehau /* If the card has gone away the read returns 0xffff. */ 154213bca4c6SSepherosa Ziehau if (status == 0xFFFFFFFF) 154313bca4c6SSepherosa Ziehau break; 154413bca4c6SSepherosa Ziehau 154513bca4c6SSepherosa Ziehau if (status) 154613bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_ISR, status); 154713bca4c6SSepherosa Ziehau 154813bca4c6SSepherosa Ziehau if ((status & VGE_INTRS) == 0) 154913bca4c6SSepherosa Ziehau break; 155013bca4c6SSepherosa Ziehau 155113bca4c6SSepherosa Ziehau if (status & (VGE_ISR_RXOK|VGE_ISR_RXOK_HIPRIO)) 155213bca4c6SSepherosa Ziehau vge_rxeof(sc, -1); 155313bca4c6SSepherosa Ziehau 155413bca4c6SSepherosa Ziehau if (status & (VGE_ISR_RXOFLOW|VGE_ISR_RXNODESC)) { 155513bca4c6SSepherosa Ziehau vge_rxeof(sc, -1); 155613bca4c6SSepherosa Ziehau ifp->if_ierrors++; 155713bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXQCSRS, VGE_RXQCSR_RUN); 155813bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXQCSRS, VGE_RXQCSR_WAK); 155913bca4c6SSepherosa Ziehau } 156013bca4c6SSepherosa Ziehau 156113bca4c6SSepherosa Ziehau if (status & (VGE_ISR_TXOK0|VGE_ISR_TIMER0)) 156213bca4c6SSepherosa Ziehau vge_txeof(sc); 156313bca4c6SSepherosa Ziehau 156413bca4c6SSepherosa Ziehau if (status & (VGE_ISR_TXDMA_STALL|VGE_ISR_RXDMA_STALL)) 156513bca4c6SSepherosa Ziehau vge_init(sc); 156613bca4c6SSepherosa Ziehau 156713bca4c6SSepherosa Ziehau if (status & VGE_ISR_LINKSTS) 156813bca4c6SSepherosa Ziehau vge_tick(sc); 156913bca4c6SSepherosa Ziehau } 157013bca4c6SSepherosa Ziehau 157113bca4c6SSepherosa Ziehau /* Re-enable interrupts */ 157213bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK); 157313bca4c6SSepherosa Ziehau 157413bca4c6SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd)) 157513bca4c6SSepherosa Ziehau ifp->if_start(ifp); 157613bca4c6SSepherosa Ziehau } 157713bca4c6SSepherosa Ziehau 157813bca4c6SSepherosa Ziehau static int 157913bca4c6SSepherosa Ziehau vge_encap(struct vge_softc *sc, struct mbuf *m_head, int idx) 158013bca4c6SSepherosa Ziehau { 158113bca4c6SSepherosa Ziehau struct vge_dmaload_arg arg; 158213bca4c6SSepherosa Ziehau bus_dmamap_t map; 158313bca4c6SSepherosa Ziehau int error; 158413bca4c6SSepherosa Ziehau 158513bca4c6SSepherosa Ziehau arg.vge_flags = 0; 158613bca4c6SSepherosa Ziehau 158713bca4c6SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_IP) 158813bca4c6SSepherosa Ziehau arg.vge_flags |= VGE_TDCTL_IPCSUM; 158913bca4c6SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_TCP) 159013bca4c6SSepherosa Ziehau arg.vge_flags |= VGE_TDCTL_TCPCSUM; 159113bca4c6SSepherosa Ziehau if (m_head->m_pkthdr.csum_flags & CSUM_UDP) 159213bca4c6SSepherosa Ziehau arg.vge_flags |= VGE_TDCTL_UDPCSUM; 159313bca4c6SSepherosa Ziehau 159413bca4c6SSepherosa Ziehau arg.sc = sc; 159513bca4c6SSepherosa Ziehau arg.vge_idx = idx; 159613bca4c6SSepherosa Ziehau arg.vge_m0 = m_head; 159713bca4c6SSepherosa Ziehau arg.vge_maxsegs = VGE_TX_FRAGS; 159813bca4c6SSepherosa Ziehau 159913bca4c6SSepherosa Ziehau map = sc->vge_ldata.vge_tx_dmamap[idx]; 160013bca4c6SSepherosa Ziehau error = bus_dmamap_load_mbuf(sc->vge_ldata.vge_mtag, map, m_head, 160113bca4c6SSepherosa Ziehau vge_dma_map_tx_desc, &arg, BUS_DMA_NOWAIT); 160213bca4c6SSepherosa Ziehau if (error && error != EFBIG) { 160313bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, "can't map mbuf (error %d)\n", 160413bca4c6SSepherosa Ziehau error); 160513bca4c6SSepherosa Ziehau goto fail; 160613bca4c6SSepherosa Ziehau } 160713bca4c6SSepherosa Ziehau 160813bca4c6SSepherosa Ziehau /* Too many segments to map, coalesce into a single mbuf */ 160913bca4c6SSepherosa Ziehau if (error || arg.vge_maxsegs == 0) { 161013bca4c6SSepherosa Ziehau struct mbuf *m_new; 161113bca4c6SSepherosa Ziehau 161213bca4c6SSepherosa Ziehau m_new = m_defrag(m_head, MB_DONTWAIT); 161313bca4c6SSepherosa Ziehau if (m_new == NULL) { 161413bca4c6SSepherosa Ziehau error = ENOBUFS; 161513bca4c6SSepherosa Ziehau goto fail; 161613bca4c6SSepherosa Ziehau } else { 161713bca4c6SSepherosa Ziehau m_head = m_new; 161813bca4c6SSepherosa Ziehau } 161913bca4c6SSepherosa Ziehau 162013bca4c6SSepherosa Ziehau arg.sc = sc; 162113bca4c6SSepherosa Ziehau arg.vge_m0 = m_head; 162213bca4c6SSepherosa Ziehau arg.vge_idx = idx; 162313bca4c6SSepherosa Ziehau arg.vge_maxsegs = 1; 162413bca4c6SSepherosa Ziehau 162513bca4c6SSepherosa Ziehau error = bus_dmamap_load_mbuf(sc->vge_ldata.vge_mtag, map, 162613bca4c6SSepherosa Ziehau m_head, vge_dma_map_tx_desc, &arg, 162713bca4c6SSepherosa Ziehau BUS_DMA_NOWAIT); 162813bca4c6SSepherosa Ziehau if (error) { 162913bca4c6SSepherosa Ziehau if_printf(&sc->arpcom.ac_if, 163013bca4c6SSepherosa Ziehau "can't map mbuf (error %d)\n", error); 163113bca4c6SSepherosa Ziehau goto fail; 163213bca4c6SSepherosa Ziehau } 163313bca4c6SSepherosa Ziehau } 163413bca4c6SSepherosa Ziehau 163513bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_mbuf[idx] = m_head; 163613bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_free--; 163713bca4c6SSepherosa Ziehau 163813bca4c6SSepherosa Ziehau /* 163913bca4c6SSepherosa Ziehau * Set up hardware VLAN tagging. 164013bca4c6SSepherosa Ziehau */ 164113bca4c6SSepherosa Ziehau if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && 164213bca4c6SSepherosa Ziehau m_head->m_pkthdr.rcvif != NULL && 164313bca4c6SSepherosa Ziehau m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN) { 164413bca4c6SSepherosa Ziehau struct ifvlan *ifv = m_head->m_pkthdr.rcvif->if_softc; 164513bca4c6SSepherosa Ziehau 164613bca4c6SSepherosa Ziehau if (ifv != NULL) { 164713bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list[idx].vge_ctl |= 164813bca4c6SSepherosa Ziehau htole32(htons(ifv->ifv_tag) | VGE_TDCTL_VTAG); 164913bca4c6SSepherosa Ziehau } 165013bca4c6SSepherosa Ziehau } 165113bca4c6SSepherosa Ziehau 165213bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list[idx].vge_sts |= htole32(VGE_TDSTS_OWN); 165313bca4c6SSepherosa Ziehau return (0); 165413bca4c6SSepherosa Ziehau 165513bca4c6SSepherosa Ziehau fail: 165613bca4c6SSepherosa Ziehau m_freem(m_head); 165713bca4c6SSepherosa Ziehau return error; 165813bca4c6SSepherosa Ziehau } 165913bca4c6SSepherosa Ziehau 166013bca4c6SSepherosa Ziehau /* 166113bca4c6SSepherosa Ziehau * Main transmit routine. 166213bca4c6SSepherosa Ziehau */ 166313bca4c6SSepherosa Ziehau 166413bca4c6SSepherosa Ziehau static void 166513bca4c6SSepherosa Ziehau vge_start(struct ifnet *ifp) 166613bca4c6SSepherosa Ziehau { 166713bca4c6SSepherosa Ziehau struct vge_softc *sc = ifp->if_softc; 166813bca4c6SSepherosa Ziehau struct mbuf *m_head = NULL; 166913bca4c6SSepherosa Ziehau int idx, pidx = 0; 167013bca4c6SSepherosa Ziehau 167113bca4c6SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 167213bca4c6SSepherosa Ziehau 167313bca4c6SSepherosa Ziehau if (!sc->vge_link || (ifp->if_flags & IFF_OACTIVE)) 167413bca4c6SSepherosa Ziehau return; 167513bca4c6SSepherosa Ziehau 167613bca4c6SSepherosa Ziehau if (ifq_is_empty(&ifp->if_snd)) 167713bca4c6SSepherosa Ziehau return; 167813bca4c6SSepherosa Ziehau 167913bca4c6SSepherosa Ziehau idx = sc->vge_ldata.vge_tx_prodidx; 168013bca4c6SSepherosa Ziehau 168113bca4c6SSepherosa Ziehau pidx = idx - 1; 168213bca4c6SSepherosa Ziehau if (pidx < 0) 168313bca4c6SSepherosa Ziehau pidx = VGE_TX_DESC_CNT - 1; 168413bca4c6SSepherosa Ziehau 168513bca4c6SSepherosa Ziehau while (sc->vge_ldata.vge_tx_mbuf[idx] == NULL) { 168613bca4c6SSepherosa Ziehau m_head = ifq_poll(&ifp->if_snd); 168713bca4c6SSepherosa Ziehau if (m_head == NULL) 168813bca4c6SSepherosa Ziehau break; 168913bca4c6SSepherosa Ziehau 169013bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_tx_free <= 2) { 169113bca4c6SSepherosa Ziehau ifp->if_flags |= IFF_OACTIVE; 169213bca4c6SSepherosa Ziehau break; 169313bca4c6SSepherosa Ziehau } 169413bca4c6SSepherosa Ziehau 169513bca4c6SSepherosa Ziehau m_head = ifq_dequeue(&ifp->if_snd, m_head); 169613bca4c6SSepherosa Ziehau 169713bca4c6SSepherosa Ziehau if (vge_encap(sc, m_head, idx)) { 169813bca4c6SSepherosa Ziehau /* If vge_encap() failed, it will free m_head for us */ 169913bca4c6SSepherosa Ziehau ifp->if_flags |= IFF_OACTIVE; 170013bca4c6SSepherosa Ziehau break; 170113bca4c6SSepherosa Ziehau } 170213bca4c6SSepherosa Ziehau 170313bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list[pidx].vge_frag[0].vge_buflen |= 170413bca4c6SSepherosa Ziehau htole16(VGE_TXDESC_Q); 170513bca4c6SSepherosa Ziehau 170613bca4c6SSepherosa Ziehau pidx = idx; 170713bca4c6SSepherosa Ziehau VGE_TX_DESC_INC(idx); 170813bca4c6SSepherosa Ziehau 170913bca4c6SSepherosa Ziehau /* 171013bca4c6SSepherosa Ziehau * If there's a BPF listener, bounce a copy of this frame 171113bca4c6SSepherosa Ziehau * to him. 171213bca4c6SSepherosa Ziehau */ 171313bca4c6SSepherosa Ziehau BPF_MTAP(ifp, m_head); 171413bca4c6SSepherosa Ziehau } 171513bca4c6SSepherosa Ziehau 171613bca4c6SSepherosa Ziehau if (idx == sc->vge_ldata.vge_tx_prodidx) 171713bca4c6SSepherosa Ziehau return; 171813bca4c6SSepherosa Ziehau 171913bca4c6SSepherosa Ziehau /* Flush the TX descriptors */ 172013bca4c6SSepherosa Ziehau bus_dmamap_sync(sc->vge_ldata.vge_tx_list_tag, 172113bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_list_map, 172213bca4c6SSepherosa Ziehau BUS_DMASYNC_PREWRITE); 172313bca4c6SSepherosa Ziehau 172413bca4c6SSepherosa Ziehau /* Issue a transmit command. */ 172513bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_TXQCSRS, VGE_TXQCSR_WAK0); 172613bca4c6SSepherosa Ziehau 172713bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_prodidx = idx; 172813bca4c6SSepherosa Ziehau 172913bca4c6SSepherosa Ziehau /* 173013bca4c6SSepherosa Ziehau * Use the countdown timer for interrupt moderation. 173113bca4c6SSepherosa Ziehau * 'TX done' interrupts are disabled. Instead, we reset the 173213bca4c6SSepherosa Ziehau * countdown timer, which will begin counting until it hits 173313bca4c6SSepherosa Ziehau * the value in the SSTIMER register, and then trigger an 173413bca4c6SSepherosa Ziehau * interrupt. Each time we set the TIMER0_ENABLE bit, the 173513bca4c6SSepherosa Ziehau * the timer count is reloaded. Only when the transmitter 173613bca4c6SSepherosa Ziehau * is idle will the timer hit 0 and an interrupt fire. 173713bca4c6SSepherosa Ziehau */ 173813bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS1, VGE_CR1_TIMER0_ENABLE); 173913bca4c6SSepherosa Ziehau 174013bca4c6SSepherosa Ziehau /* 174113bca4c6SSepherosa Ziehau * Set a timeout in case the chip goes out to lunch. 174213bca4c6SSepherosa Ziehau */ 174313bca4c6SSepherosa Ziehau ifp->if_timer = 5; 174413bca4c6SSepherosa Ziehau } 174513bca4c6SSepherosa Ziehau 174613bca4c6SSepherosa Ziehau static void 174713bca4c6SSepherosa Ziehau vge_init(void *xsc) 174813bca4c6SSepherosa Ziehau { 174913bca4c6SSepherosa Ziehau struct vge_softc *sc = xsc; 175013bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 175113bca4c6SSepherosa Ziehau struct mii_data *mii; 175213bca4c6SSepherosa Ziehau int i; 175313bca4c6SSepherosa Ziehau 175413bca4c6SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 175513bca4c6SSepherosa Ziehau 175613bca4c6SSepherosa Ziehau mii = device_get_softc(sc->vge_miibus); 175713bca4c6SSepherosa Ziehau 175813bca4c6SSepherosa Ziehau /* 175913bca4c6SSepherosa Ziehau * Cancel pending I/O and free all RX/TX buffers. 176013bca4c6SSepherosa Ziehau */ 176113bca4c6SSepherosa Ziehau vge_stop(sc); 176213bca4c6SSepherosa Ziehau vge_reset(sc); 176313bca4c6SSepherosa Ziehau 176413bca4c6SSepherosa Ziehau /* 176513bca4c6SSepherosa Ziehau * Initialize the RX and TX descriptors and mbufs. 176613bca4c6SSepherosa Ziehau */ 176713bca4c6SSepherosa Ziehau vge_rx_list_init(sc); 176813bca4c6SSepherosa Ziehau vge_tx_list_init(sc); 176913bca4c6SSepherosa Ziehau 177013bca4c6SSepherosa Ziehau /* Set our station address */ 177113bca4c6SSepherosa Ziehau for (i = 0; i < ETHER_ADDR_LEN; i++) 177213bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_PAR0 + i, IF_LLADDR(ifp)[i]); 177313bca4c6SSepherosa Ziehau 177413bca4c6SSepherosa Ziehau /* 177513bca4c6SSepherosa Ziehau * Set receive FIFO threshold. Also allow transmission and 177613bca4c6SSepherosa Ziehau * reception of VLAN tagged frames. 177713bca4c6SSepherosa Ziehau */ 177813bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_RXCFG, VGE_RXCFG_FIFO_THR|VGE_RXCFG_VTAGOPT); 177913bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_RXCFG, VGE_RXFIFOTHR_128BYTES|VGE_VTAG_OPT2); 178013bca4c6SSepherosa Ziehau 178113bca4c6SSepherosa Ziehau /* Set DMA burst length */ 178213bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_DMACFG0, VGE_DMACFG0_BURSTLEN); 178313bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_DMACFG0, VGE_DMABURST_128); 178413bca4c6SSepherosa Ziehau 178513bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_TXCFG, VGE_TXCFG_ARB_PRIO|VGE_TXCFG_NONBLK); 178613bca4c6SSepherosa Ziehau 178713bca4c6SSepherosa Ziehau /* Set collision backoff algorithm */ 178813bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CHIPCFG1, VGE_CHIPCFG1_CRANDOM| 178913bca4c6SSepherosa Ziehau VGE_CHIPCFG1_CAP|VGE_CHIPCFG1_MBA|VGE_CHIPCFG1_BAKOPT); 179013bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CHIPCFG1, VGE_CHIPCFG1_OFSET); 179113bca4c6SSepherosa Ziehau 179213bca4c6SSepherosa Ziehau /* Disable LPSEL field in priority resolution */ 179313bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_LPSEL_DIS); 179413bca4c6SSepherosa Ziehau 179513bca4c6SSepherosa Ziehau /* 179613bca4c6SSepherosa Ziehau * Load the addresses of the DMA queues into the chip. 179713bca4c6SSepherosa Ziehau * Note that we only use one transmit queue. 179813bca4c6SSepherosa Ziehau */ 179913bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_TXDESC_ADDR_LO0, 180013bca4c6SSepherosa Ziehau VGE_ADDR_LO(sc->vge_ldata.vge_tx_list_addr)); 180113bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_TXDESCNUM, VGE_TX_DESC_CNT - 1); 180213bca4c6SSepherosa Ziehau 180313bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_RXDESC_ADDR_LO, 180413bca4c6SSepherosa Ziehau VGE_ADDR_LO(sc->vge_ldata.vge_rx_list_addr)); 180513bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_RXDESCNUM, VGE_RX_DESC_CNT - 1); 180613bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_RXDESC_RESIDUECNT, VGE_RX_DESC_CNT); 180713bca4c6SSepherosa Ziehau 180813bca4c6SSepherosa Ziehau /* Enable and wake up the RX descriptor queue */ 180913bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXQCSRS, VGE_RXQCSR_RUN); 181013bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXQCSRS, VGE_RXQCSR_WAK); 181113bca4c6SSepherosa Ziehau 181213bca4c6SSepherosa Ziehau /* Enable the TX descriptor queue */ 181313bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_TXQCSRS, VGE_TXQCSR_RUN0); 181413bca4c6SSepherosa Ziehau 181513bca4c6SSepherosa Ziehau /* Set up the receive filter -- allow large frames for VLANs. */ 181613bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXCTL, VGE_RXCTL_RX_UCAST|VGE_RXCTL_RX_GIANT); 181713bca4c6SSepherosa Ziehau 181813bca4c6SSepherosa Ziehau /* If we want promiscuous mode, set the allframes bit. */ 181913bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_PROMISC) 182013bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_RXCTL, VGE_RXCTL_RX_PROMISC); 182113bca4c6SSepherosa Ziehau 182213bca4c6SSepherosa Ziehau /* Set capture broadcast bit to capture broadcast frames. */ 182313bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_BROADCAST) 182413bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_RXCTL, VGE_RXCTL_RX_BCAST); 182513bca4c6SSepherosa Ziehau 182613bca4c6SSepherosa Ziehau /* Set multicast bit to capture multicast frames. */ 182713bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_MULTICAST) 182813bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_RXCTL, VGE_RXCTL_RX_MCAST); 182913bca4c6SSepherosa Ziehau 183013bca4c6SSepherosa Ziehau /* Init the cam filter. */ 183113bca4c6SSepherosa Ziehau vge_cam_clear(sc); 183213bca4c6SSepherosa Ziehau 183313bca4c6SSepherosa Ziehau /* Init the multicast filter. */ 183413bca4c6SSepherosa Ziehau vge_setmulti(sc); 183513bca4c6SSepherosa Ziehau 183613bca4c6SSepherosa Ziehau /* Enable flow control */ 183713bca4c6SSepherosa Ziehau 183813bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS2, 0x8B); 183913bca4c6SSepherosa Ziehau 184013bca4c6SSepherosa Ziehau /* Enable jumbo frame reception (if desired) */ 184113bca4c6SSepherosa Ziehau 184213bca4c6SSepherosa Ziehau /* Start the MAC. */ 184313bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRC0, VGE_CR0_STOP); 184413bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS1, VGE_CR1_NOPOLL); 184513bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS0, 184613bca4c6SSepherosa Ziehau VGE_CR0_TX_ENABLE|VGE_CR0_RX_ENABLE|VGE_CR0_START); 184713bca4c6SSepherosa Ziehau 184813bca4c6SSepherosa Ziehau /* 184913bca4c6SSepherosa Ziehau * Configure one-shot timer for microsecond 185013bca4c6SSepherosa Ziehau * resulution and load it for 500 usecs. 185113bca4c6SSepherosa Ziehau */ 185213bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_TIMER0_RES); 185313bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_SSTIMER, 400); 185413bca4c6SSepherosa Ziehau 185513bca4c6SSepherosa Ziehau /* 185613bca4c6SSepherosa Ziehau * Configure interrupt moderation for receive. Enable 185713bca4c6SSepherosa Ziehau * the holdoff counter and load it, and set the RX 185813bca4c6SSepherosa Ziehau * suppression count to the number of descriptors we 185913bca4c6SSepherosa Ziehau * want to allow before triggering an interrupt. 186013bca4c6SSepherosa Ziehau * The holdoff timer is in units of 20 usecs. 186113bca4c6SSepherosa Ziehau */ 186213bca4c6SSepherosa Ziehau 186313bca4c6SSepherosa Ziehau #ifdef notyet 186413bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_INTCTL1, VGE_INTCTL_TXINTSUP_DISABLE); 186513bca4c6SSepherosa Ziehau /* Select the interrupt holdoff timer page. */ 186613bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_PAGESEL); 186713bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_PAGESEL_INTHLDOFF); 186813bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_INTHOLDOFF, 10); /* ~200 usecs */ 186913bca4c6SSepherosa Ziehau 187013bca4c6SSepherosa Ziehau /* Enable use of the holdoff timer. */ 187113bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_HOLDOFF); 187213bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_INTCTL1, VGE_INTCTL_SC_RELOAD); 187313bca4c6SSepherosa Ziehau 187413bca4c6SSepherosa Ziehau /* Select the RX suppression threshold page. */ 187513bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_PAGESEL); 187613bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_PAGESEL_RXSUPPTHR); 187713bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXSUPPTHR, 64); /* interrupt after 64 packets */ 187813bca4c6SSepherosa Ziehau 187913bca4c6SSepherosa Ziehau /* Restore the page select bits. */ 188013bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_CAMCTL, VGE_CAMCTL_PAGESEL); 188113bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_CAMCTL, VGE_PAGESEL_MAR); 188213bca4c6SSepherosa Ziehau #endif 188313bca4c6SSepherosa Ziehau 188413bca4c6SSepherosa Ziehau #ifdef DEVICE_POLLING 188513bca4c6SSepherosa Ziehau /* Disable intr if polling(4) is enabled */ 188613bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_POLLING) 188713bca4c6SSepherosa Ziehau vge_disable_intr(sc); 188813bca4c6SSepherosa Ziehau else 188913bca4c6SSepherosa Ziehau #endif 189013bca4c6SSepherosa Ziehau vge_enable_intr(sc, 0); 189113bca4c6SSepherosa Ziehau 189213bca4c6SSepherosa Ziehau mii_mediachg(mii); 189313bca4c6SSepherosa Ziehau 189413bca4c6SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING; 189513bca4c6SSepherosa Ziehau ifp->if_flags &= ~IFF_OACTIVE; 189613bca4c6SSepherosa Ziehau 189713bca4c6SSepherosa Ziehau sc->vge_if_flags = 0; 189813bca4c6SSepherosa Ziehau sc->vge_link = 0; 189913bca4c6SSepherosa Ziehau } 190013bca4c6SSepherosa Ziehau 190113bca4c6SSepherosa Ziehau /* 190213bca4c6SSepherosa Ziehau * Set media options. 190313bca4c6SSepherosa Ziehau */ 190413bca4c6SSepherosa Ziehau static int 190513bca4c6SSepherosa Ziehau vge_ifmedia_upd(struct ifnet *ifp) 190613bca4c6SSepherosa Ziehau { 190713bca4c6SSepherosa Ziehau struct vge_softc *sc = ifp->if_softc; 190813bca4c6SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->vge_miibus); 190913bca4c6SSepherosa Ziehau 191013bca4c6SSepherosa Ziehau mii_mediachg(mii); 191113bca4c6SSepherosa Ziehau 191213bca4c6SSepherosa Ziehau return (0); 191313bca4c6SSepherosa Ziehau } 191413bca4c6SSepherosa Ziehau 191513bca4c6SSepherosa Ziehau /* 191613bca4c6SSepherosa Ziehau * Report current media status. 191713bca4c6SSepherosa Ziehau */ 191813bca4c6SSepherosa Ziehau static void 191913bca4c6SSepherosa Ziehau vge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 192013bca4c6SSepherosa Ziehau { 192113bca4c6SSepherosa Ziehau struct vge_softc *sc = ifp->if_softc; 192213bca4c6SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->vge_miibus); 192313bca4c6SSepherosa Ziehau 192413bca4c6SSepherosa Ziehau mii_pollstat(mii); 192513bca4c6SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active; 192613bca4c6SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status; 192713bca4c6SSepherosa Ziehau } 192813bca4c6SSepherosa Ziehau 192913bca4c6SSepherosa Ziehau static void 193013bca4c6SSepherosa Ziehau vge_miibus_statchg(device_t dev) 193113bca4c6SSepherosa Ziehau { 193213bca4c6SSepherosa Ziehau struct vge_softc *sc; 193313bca4c6SSepherosa Ziehau struct mii_data *mii; 193413bca4c6SSepherosa Ziehau struct ifmedia_entry *ife; 193513bca4c6SSepherosa Ziehau 193613bca4c6SSepherosa Ziehau sc = device_get_softc(dev); 193713bca4c6SSepherosa Ziehau mii = device_get_softc(sc->vge_miibus); 193813bca4c6SSepherosa Ziehau ife = mii->mii_media.ifm_cur; 193913bca4c6SSepherosa Ziehau 194013bca4c6SSepherosa Ziehau /* 194113bca4c6SSepherosa Ziehau * If the user manually selects a media mode, we need to turn 194213bca4c6SSepherosa Ziehau * on the forced MAC mode bit in the DIAGCTL register. If the 194313bca4c6SSepherosa Ziehau * user happens to choose a full duplex mode, we also need to 194413bca4c6SSepherosa Ziehau * set the 'force full duplex' bit. This applies only to 194513bca4c6SSepherosa Ziehau * 10Mbps and 100Mbps speeds. In autoselect mode, forced MAC 194613bca4c6SSepherosa Ziehau * mode is disabled, and in 1000baseT mode, full duplex is 194713bca4c6SSepherosa Ziehau * always implied, so we turn on the forced mode bit but leave 194813bca4c6SSepherosa Ziehau * the FDX bit cleared. 194913bca4c6SSepherosa Ziehau */ 195013bca4c6SSepherosa Ziehau 195113bca4c6SSepherosa Ziehau switch (IFM_SUBTYPE(ife->ifm_media)) { 195213bca4c6SSepherosa Ziehau case IFM_AUTO: 195313bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); 195413bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); 195513bca4c6SSepherosa Ziehau break; 195613bca4c6SSepherosa Ziehau case IFM_1000_T: 195713bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); 195813bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); 195913bca4c6SSepherosa Ziehau break; 196013bca4c6SSepherosa Ziehau case IFM_100_TX: 196113bca4c6SSepherosa Ziehau case IFM_10_T: 196213bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_MACFORCE); 196313bca4c6SSepherosa Ziehau if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) 196413bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); 196513bca4c6SSepherosa Ziehau else 196613bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_DIAGCTL, VGE_DIAGCTL_FDXFORCE); 196713bca4c6SSepherosa Ziehau break; 196813bca4c6SSepherosa Ziehau default: 196913bca4c6SSepherosa Ziehau device_printf(dev, "unknown media type: %x\n", 197013bca4c6SSepherosa Ziehau IFM_SUBTYPE(ife->ifm_media)); 197113bca4c6SSepherosa Ziehau break; 197213bca4c6SSepherosa Ziehau } 197313bca4c6SSepherosa Ziehau } 197413bca4c6SSepherosa Ziehau 197513bca4c6SSepherosa Ziehau static int 197613bca4c6SSepherosa Ziehau vge_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) 197713bca4c6SSepherosa Ziehau { 197813bca4c6SSepherosa Ziehau struct vge_softc *sc = ifp->if_softc; 197913bca4c6SSepherosa Ziehau struct ifreq *ifr = (struct ifreq *)data; 198013bca4c6SSepherosa Ziehau struct mii_data *mii; 198113bca4c6SSepherosa Ziehau int error = 0; 198213bca4c6SSepherosa Ziehau 198313bca4c6SSepherosa Ziehau switch (command) { 198413bca4c6SSepherosa Ziehau case SIOCSIFMTU: 198513bca4c6SSepherosa Ziehau if (ifr->ifr_mtu > VGE_JUMBO_MTU) 198613bca4c6SSepherosa Ziehau error = EINVAL; 198713bca4c6SSepherosa Ziehau ifp->if_mtu = ifr->ifr_mtu; 198813bca4c6SSepherosa Ziehau break; 198913bca4c6SSepherosa Ziehau case SIOCSIFFLAGS: 199013bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_UP) { 199113bca4c6SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) && 199213bca4c6SSepherosa Ziehau (ifp->if_flags & IFF_PROMISC) && 199313bca4c6SSepherosa Ziehau !(sc->vge_if_flags & IFF_PROMISC)) { 199413bca4c6SSepherosa Ziehau CSR_SETBIT_1(sc, VGE_RXCTL, 199513bca4c6SSepherosa Ziehau VGE_RXCTL_RX_PROMISC); 199613bca4c6SSepherosa Ziehau vge_setmulti(sc); 199713bca4c6SSepherosa Ziehau } else if ((ifp->if_flags & IFF_RUNNING) && 199813bca4c6SSepherosa Ziehau !(ifp->if_flags & IFF_PROMISC) && 199913bca4c6SSepherosa Ziehau (sc->vge_if_flags & IFF_PROMISC)) { 200013bca4c6SSepherosa Ziehau CSR_CLRBIT_1(sc, VGE_RXCTL, 200113bca4c6SSepherosa Ziehau VGE_RXCTL_RX_PROMISC); 200213bca4c6SSepherosa Ziehau vge_setmulti(sc); 200313bca4c6SSepherosa Ziehau } else { 200413bca4c6SSepherosa Ziehau vge_init(sc); 200513bca4c6SSepherosa Ziehau } 200613bca4c6SSepherosa Ziehau } else { 200713bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 200813bca4c6SSepherosa Ziehau vge_stop(sc); 200913bca4c6SSepherosa Ziehau } 201013bca4c6SSepherosa Ziehau sc->vge_if_flags = ifp->if_flags; 201113bca4c6SSepherosa Ziehau break; 201213bca4c6SSepherosa Ziehau case SIOCADDMULTI: 201313bca4c6SSepherosa Ziehau case SIOCDELMULTI: 201413bca4c6SSepherosa Ziehau vge_setmulti(sc); 201513bca4c6SSepherosa Ziehau break; 201613bca4c6SSepherosa Ziehau case SIOCGIFMEDIA: 201713bca4c6SSepherosa Ziehau case SIOCSIFMEDIA: 201813bca4c6SSepherosa Ziehau mii = device_get_softc(sc->vge_miibus); 201913bca4c6SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 202013bca4c6SSepherosa Ziehau break; 202113bca4c6SSepherosa Ziehau case SIOCSIFCAP: 202213bca4c6SSepherosa Ziehau { 202313bca4c6SSepherosa Ziehau uint32_t mask = ifr->ifr_reqcap ^ ifp->if_capenable; 202413bca4c6SSepherosa Ziehau 202513bca4c6SSepherosa Ziehau if (mask & IFCAP_HWCSUM) { 202613bca4c6SSepherosa Ziehau ifp->if_capenable |= ifr->ifr_reqcap & (IFCAP_HWCSUM); 202713bca4c6SSepherosa Ziehau if (ifp->if_capenable & IFCAP_TXCSUM) 202813bca4c6SSepherosa Ziehau ifp->if_hwassist = VGE_CSUM_FEATURES; 202913bca4c6SSepherosa Ziehau else 203013bca4c6SSepherosa Ziehau ifp->if_hwassist = 0; 203113bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) 203213bca4c6SSepherosa Ziehau vge_init(sc); 203313bca4c6SSepherosa Ziehau } 203413bca4c6SSepherosa Ziehau } 203513bca4c6SSepherosa Ziehau break; 203613bca4c6SSepherosa Ziehau default: 203713bca4c6SSepherosa Ziehau error = ether_ioctl(ifp, command, data); 203813bca4c6SSepherosa Ziehau break; 203913bca4c6SSepherosa Ziehau } 204013bca4c6SSepherosa Ziehau return (error); 204113bca4c6SSepherosa Ziehau } 204213bca4c6SSepherosa Ziehau 204313bca4c6SSepherosa Ziehau static void 204413bca4c6SSepherosa Ziehau vge_watchdog(struct ifnet *ifp) 204513bca4c6SSepherosa Ziehau { 204613bca4c6SSepherosa Ziehau struct vge_softc *sc = ifp->if_softc; 204713bca4c6SSepherosa Ziehau 204813bca4c6SSepherosa Ziehau if_printf(ifp, "watchdog timeout\n"); 204913bca4c6SSepherosa Ziehau ifp->if_oerrors++; 205013bca4c6SSepherosa Ziehau 205113bca4c6SSepherosa Ziehau vge_txeof(sc); 205213bca4c6SSepherosa Ziehau vge_rxeof(sc, -1); 205313bca4c6SSepherosa Ziehau 205413bca4c6SSepherosa Ziehau vge_init(sc); 205513bca4c6SSepherosa Ziehau } 205613bca4c6SSepherosa Ziehau 205713bca4c6SSepherosa Ziehau /* 205813bca4c6SSepherosa Ziehau * Stop the adapter and free any mbufs allocated to the 205913bca4c6SSepherosa Ziehau * RX and TX lists. 206013bca4c6SSepherosa Ziehau */ 206113bca4c6SSepherosa Ziehau static void 206213bca4c6SSepherosa Ziehau vge_stop(struct vge_softc *sc) 206313bca4c6SSepherosa Ziehau { 206413bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 206513bca4c6SSepherosa Ziehau int i; 206613bca4c6SSepherosa Ziehau 206713bca4c6SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer); 206813bca4c6SSepherosa Ziehau 206913bca4c6SSepherosa Ziehau ifp->if_timer = 0; 207013bca4c6SSepherosa Ziehau 207113bca4c6SSepherosa Ziehau ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 207213bca4c6SSepherosa Ziehau 207313bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); 207413bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS0, VGE_CR0_STOP); 207513bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF); 207613bca4c6SSepherosa Ziehau CSR_WRITE_2(sc, VGE_TXQCSRC, 0xFFFF); 207713bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_RXQCSRC, 0xFF); 207813bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_RXDESC_ADDR_LO, 0); 207913bca4c6SSepherosa Ziehau 208013bca4c6SSepherosa Ziehau if (sc->vge_head != NULL) { 208113bca4c6SSepherosa Ziehau m_freem(sc->vge_head); 208213bca4c6SSepherosa Ziehau sc->vge_head = sc->vge_tail = NULL; 208313bca4c6SSepherosa Ziehau } 208413bca4c6SSepherosa Ziehau 208513bca4c6SSepherosa Ziehau /* Free the TX list buffers. */ 208613bca4c6SSepherosa Ziehau for (i = 0; i < VGE_TX_DESC_CNT; i++) { 208713bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_tx_mbuf[i] != NULL) { 208813bca4c6SSepherosa Ziehau bus_dmamap_unload(sc->vge_ldata.vge_mtag, 208913bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_dmamap[i]); 209013bca4c6SSepherosa Ziehau m_freem(sc->vge_ldata.vge_tx_mbuf[i]); 209113bca4c6SSepherosa Ziehau sc->vge_ldata.vge_tx_mbuf[i] = NULL; 209213bca4c6SSepherosa Ziehau } 209313bca4c6SSepherosa Ziehau } 209413bca4c6SSepherosa Ziehau 209513bca4c6SSepherosa Ziehau /* Free the RX list buffers. */ 209613bca4c6SSepherosa Ziehau for (i = 0; i < VGE_RX_DESC_CNT; i++) { 209713bca4c6SSepherosa Ziehau if (sc->vge_ldata.vge_rx_mbuf[i] != NULL) { 209813bca4c6SSepherosa Ziehau bus_dmamap_unload(sc->vge_ldata.vge_mtag, 209913bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_dmamap[i]); 210013bca4c6SSepherosa Ziehau m_freem(sc->vge_ldata.vge_rx_mbuf[i]); 210113bca4c6SSepherosa Ziehau sc->vge_ldata.vge_rx_mbuf[i] = NULL; 210213bca4c6SSepherosa Ziehau } 210313bca4c6SSepherosa Ziehau } 210413bca4c6SSepherosa Ziehau } 210513bca4c6SSepherosa Ziehau 210613bca4c6SSepherosa Ziehau /* 210713bca4c6SSepherosa Ziehau * Device suspend routine. Stop the interface and save some PCI 210813bca4c6SSepherosa Ziehau * settings in case the BIOS doesn't restore them properly on 210913bca4c6SSepherosa Ziehau * resume. 211013bca4c6SSepherosa Ziehau */ 211113bca4c6SSepherosa Ziehau static int 211213bca4c6SSepherosa Ziehau vge_suspend(device_t dev) 211313bca4c6SSepherosa Ziehau { 211413bca4c6SSepherosa Ziehau struct vge_softc *sc = device_get_softc(dev); 211513bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 211613bca4c6SSepherosa Ziehau 211713bca4c6SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 211813bca4c6SSepherosa Ziehau vge_stop(sc); 211913bca4c6SSepherosa Ziehau sc->suspended = 1; 212013bca4c6SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 212113bca4c6SSepherosa Ziehau 212213bca4c6SSepherosa Ziehau return (0); 212313bca4c6SSepherosa Ziehau } 212413bca4c6SSepherosa Ziehau 212513bca4c6SSepherosa Ziehau /* 212613bca4c6SSepherosa Ziehau * Device resume routine. Restore some PCI settings in case the BIOS 212713bca4c6SSepherosa Ziehau * doesn't, re-enable busmastering, and restart the interface if 212813bca4c6SSepherosa Ziehau * appropriate. 212913bca4c6SSepherosa Ziehau */ 213013bca4c6SSepherosa Ziehau static int 213113bca4c6SSepherosa Ziehau vge_resume(device_t dev) 213213bca4c6SSepherosa Ziehau { 213313bca4c6SSepherosa Ziehau struct vge_softc *sc = device_get_softc(dev); 213413bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 213513bca4c6SSepherosa Ziehau 213613bca4c6SSepherosa Ziehau /* reenable busmastering */ 213713bca4c6SSepherosa Ziehau pci_enable_busmaster(dev); 213813bca4c6SSepherosa Ziehau pci_enable_io(dev, SYS_RES_MEMORY); 213913bca4c6SSepherosa Ziehau 214013bca4c6SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 214113bca4c6SSepherosa Ziehau /* reinitialize interface if necessary */ 214213bca4c6SSepherosa Ziehau if (ifp->if_flags & IFF_UP) 214313bca4c6SSepherosa Ziehau vge_init(sc); 214413bca4c6SSepherosa Ziehau 214513bca4c6SSepherosa Ziehau sc->suspended = 0; 214613bca4c6SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 214713bca4c6SSepherosa Ziehau 214813bca4c6SSepherosa Ziehau return (0); 214913bca4c6SSepherosa Ziehau } 215013bca4c6SSepherosa Ziehau 215113bca4c6SSepherosa Ziehau /* 215213bca4c6SSepherosa Ziehau * Stop all chip I/O so that the kernel's probe routines don't 215313bca4c6SSepherosa Ziehau * get confused by errant DMAs when rebooting. 215413bca4c6SSepherosa Ziehau */ 215513bca4c6SSepherosa Ziehau static void 215613bca4c6SSepherosa Ziehau vge_shutdown(device_t dev) 215713bca4c6SSepherosa Ziehau { 215813bca4c6SSepherosa Ziehau struct vge_softc *sc = device_get_softc(dev); 215913bca4c6SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if; 216013bca4c6SSepherosa Ziehau 216113bca4c6SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer); 216213bca4c6SSepherosa Ziehau vge_stop(sc); 216313bca4c6SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer); 216413bca4c6SSepherosa Ziehau } 216513bca4c6SSepherosa Ziehau 216613bca4c6SSepherosa Ziehau static void 216713bca4c6SSepherosa Ziehau vge_enable_intr(struct vge_softc *sc, uint32_t isr) 216813bca4c6SSepherosa Ziehau { 216913bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS); 217013bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_ISR, isr); 217113bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK); 217213bca4c6SSepherosa Ziehau } 217313bca4c6SSepherosa Ziehau 217413bca4c6SSepherosa Ziehau #ifdef DEVICE_POLLING 217513bca4c6SSepherosa Ziehau static void 217613bca4c6SSepherosa Ziehau vge_disable_intr(struct vge_softc *sc) 217713bca4c6SSepherosa Ziehau { 217813bca4c6SSepherosa Ziehau CSR_WRITE_4(sc, VGE_IMR, 0); 217913bca4c6SSepherosa Ziehau CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK); 218013bca4c6SSepherosa Ziehau } 218113bca4c6SSepherosa Ziehau #endif 2182