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