167196661SRafal Jaworowski /*- 267196661SRafal Jaworowski * Copyright (C) 2006-2008 Semihalf 367196661SRafal Jaworowski * All rights reserved. 467196661SRafal Jaworowski * 567196661SRafal Jaworowski * Written by: Piotr Kruszynski <ppk@semihalf.com> 667196661SRafal Jaworowski * 767196661SRafal Jaworowski * Redistribution and use in source and binary forms, with or without 867196661SRafal Jaworowski * modification, are permitted provided that the following conditions 967196661SRafal Jaworowski * are met: 1067196661SRafal Jaworowski * 1. Redistributions of source code must retain the above copyright 1167196661SRafal Jaworowski * notice, this list of conditions and the following disclaimer. 1267196661SRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright 1367196661SRafal Jaworowski * notice, this list of conditions and the following disclaimer in the 1467196661SRafal Jaworowski * documentation and/or other materials provided with the distribution. 1567196661SRafal Jaworowski * 3. The name of the author may not be used to endorse or promote products 1667196661SRafal Jaworowski * derived from this software without specific prior written permission. 1767196661SRafal Jaworowski * 1867196661SRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1967196661SRafal Jaworowski * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2067196661SRafal Jaworowski * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 2167196661SRafal Jaworowski * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2267196661SRafal Jaworowski * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2367196661SRafal Jaworowski * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2467196661SRafal Jaworowski * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 2567196661SRafal Jaworowski * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2667196661SRafal Jaworowski * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2767196661SRafal Jaworowski * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2867196661SRafal Jaworowski */ 2967196661SRafal Jaworowski 3067196661SRafal Jaworowski /* 3167196661SRafal Jaworowski * Freescale integrated Three-Speed Ethernet Controller (TSEC) driver. 3267196661SRafal Jaworowski */ 3367196661SRafal Jaworowski #include <sys/cdefs.h> 3467196661SRafal Jaworowski __FBSDID("$FreeBSD$"); 3567196661SRafal Jaworowski 3667196661SRafal Jaworowski #include <sys/param.h> 3767196661SRafal Jaworowski #include <sys/systm.h> 3867196661SRafal Jaworowski #include <sys/endian.h> 3967196661SRafal Jaworowski #include <sys/mbuf.h> 4067196661SRafal Jaworowski #include <sys/kernel.h> 4167196661SRafal Jaworowski #include <sys/module.h> 4267196661SRafal Jaworowski #include <sys/socket.h> 4367196661SRafal Jaworowski #include <sys/sysctl.h> 4467196661SRafal Jaworowski 4567196661SRafal Jaworowski #include <net/if.h> 4667196661SRafal Jaworowski #include <net/if_dl.h> 4767196661SRafal Jaworowski #include <net/if_media.h> 4867196661SRafal Jaworowski 4967196661SRafal Jaworowski #include <net/bpf.h> 5067196661SRafal Jaworowski #include <sys/sockio.h> 5167196661SRafal Jaworowski #include <sys/bus.h> 5267196661SRafal Jaworowski #include <machine/bus.h> 5367196661SRafal Jaworowski #include <sys/rman.h> 5467196661SRafal Jaworowski #include <machine/resource.h> 5567196661SRafal Jaworowski 5667196661SRafal Jaworowski #include <net/ethernet.h> 5767196661SRafal Jaworowski #include <net/if_arp.h> 5867196661SRafal Jaworowski 5967196661SRafal Jaworowski #include <net/if_types.h> 6067196661SRafal Jaworowski #include <net/if_vlan_var.h> 6167196661SRafal Jaworowski 6267196661SRafal Jaworowski #include <dev/mii/mii.h> 6367196661SRafal Jaworowski #include <dev/mii/miivar.h> 6467196661SRafal Jaworowski 6567196661SRafal Jaworowski #include <machine/ocpbus.h> 6667196661SRafal Jaworowski 6767196661SRafal Jaworowski #include <dev/tsec/if_tsec.h> 6867196661SRafal Jaworowski #include <dev/tsec/if_tsecreg.h> 6967196661SRafal Jaworowski 7067196661SRafal Jaworowski #include "miibus_if.h" 7167196661SRafal Jaworowski 7267196661SRafal Jaworowski #define TSEC_DEBUG 7367196661SRafal Jaworowski 7467196661SRafal Jaworowski #ifdef TSEC_DEBUG 7567196661SRafal Jaworowski #define PDEBUG(a) {printf("%s:%d: ", __func__, __LINE__), printf a; printf("\n");} 7667196661SRafal Jaworowski #else 7767196661SRafal Jaworowski #define PDEBUG(a) /* nop */ 7867196661SRafal Jaworowski #endif 7967196661SRafal Jaworowski 8067196661SRafal Jaworowski static int tsec_probe(device_t dev); 8167196661SRafal Jaworowski static int tsec_attach(device_t dev); 8267196661SRafal Jaworowski static int tsec_setup_intr(device_t dev, struct resource **ires, 8367196661SRafal Jaworowski void **ihand, int *irid, driver_intr_t handler, const char *iname); 8467196661SRafal Jaworowski static void tsec_release_intr(device_t dev, struct resource *ires, 8567196661SRafal Jaworowski void *ihand, int irid, const char *iname); 8667196661SRafal Jaworowski static void tsec_free_dma(struct tsec_softc *sc); 8767196661SRafal Jaworowski static int tsec_detach(device_t dev); 8867196661SRafal Jaworowski static void tsec_shutdown(device_t dev); 8967196661SRafal Jaworowski static int tsec_suspend(device_t dev); /* XXX */ 9067196661SRafal Jaworowski static int tsec_resume(device_t dev); /* XXX */ 9167196661SRafal Jaworowski 9267196661SRafal Jaworowski static void tsec_init(void *xsc); 9367196661SRafal Jaworowski static void tsec_init_locked(struct tsec_softc *sc); 9467196661SRafal Jaworowski static void tsec_set_mac_address(struct tsec_softc *sc); 9567196661SRafal Jaworowski static void tsec_dma_ctl(struct tsec_softc *sc, int state); 9667196661SRafal Jaworowski static void tsec_intrs_ctl(struct tsec_softc *sc, int state); 9767196661SRafal Jaworowski static void tsec_reset_mac(struct tsec_softc *sc); 9867196661SRafal Jaworowski 99772619e1SRafal Jaworowski static void tsec_watchdog(struct tsec_softc *sc); 10067196661SRafal Jaworowski static void tsec_start(struct ifnet *ifp); 10167196661SRafal Jaworowski static void tsec_start_locked(struct ifnet *ifp); 10267196661SRafal Jaworowski static int tsec_encap(struct tsec_softc *sc, 10367196661SRafal Jaworowski struct mbuf *m_head); 10467196661SRafal Jaworowski static void tsec_setfilter(struct tsec_softc *sc); 10567196661SRafal Jaworowski static int tsec_ioctl(struct ifnet *ifp, u_long command, 10667196661SRafal Jaworowski caddr_t data); 10767196661SRafal Jaworowski static int tsec_ifmedia_upd(struct ifnet *ifp); 10867196661SRafal Jaworowski static void tsec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 10967196661SRafal Jaworowski static int tsec_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, 11067196661SRafal Jaworowski struct mbuf **mbufp, uint32_t *paddr); 11167196661SRafal Jaworowski static void tsec_map_dma_addr(void *arg, bus_dma_segment_t *segs, 11267196661SRafal Jaworowski int nseg, int error); 11367196661SRafal Jaworowski static int tsec_alloc_dma_desc(device_t dev, bus_dma_tag_t *dtag, 11467196661SRafal Jaworowski bus_dmamap_t *dmap, bus_size_t dsize, void **vaddr, void *raddr, 11567196661SRafal Jaworowski const char *dname); 11667196661SRafal Jaworowski static void tsec_free_dma_desc(bus_dma_tag_t dtag, bus_dmamap_t dmap, 11767196661SRafal Jaworowski void *vaddr); 11867196661SRafal Jaworowski 11967196661SRafal Jaworowski static void tsec_stop(struct tsec_softc *sc); 12067196661SRafal Jaworowski 12167196661SRafal Jaworowski static void tsec_receive_intr(void *arg); 12267196661SRafal Jaworowski static void tsec_transmit_intr(void *arg); 12367196661SRafal Jaworowski static void tsec_error_intr(void *arg); 12467196661SRafal Jaworowski 12567196661SRafal Jaworowski static void tsec_tick(void *arg); 12667196661SRafal Jaworowski static int tsec_miibus_readreg(device_t dev, int phy, int reg); 12767196661SRafal Jaworowski static void tsec_miibus_writereg(device_t dev, int phy, int reg, int value); 12867196661SRafal Jaworowski static void tsec_miibus_statchg(device_t dev); 12967196661SRafal Jaworowski 13067196661SRafal Jaworowski static struct tsec_softc *tsec0_sc = NULL; /* XXX ugly hack! */ 13167196661SRafal Jaworowski 13267196661SRafal Jaworowski static device_method_t tsec_methods[] = { 13367196661SRafal Jaworowski /* Device interface */ 13467196661SRafal Jaworowski DEVMETHOD(device_probe, tsec_probe), 13567196661SRafal Jaworowski DEVMETHOD(device_attach, tsec_attach), 13667196661SRafal Jaworowski DEVMETHOD(device_detach, tsec_detach), 13767196661SRafal Jaworowski DEVMETHOD(device_shutdown, tsec_shutdown), 13867196661SRafal Jaworowski DEVMETHOD(device_suspend, tsec_suspend), 13967196661SRafal Jaworowski DEVMETHOD(device_resume, tsec_resume), 14067196661SRafal Jaworowski 14167196661SRafal Jaworowski /* bus interface */ 14267196661SRafal Jaworowski DEVMETHOD(bus_print_child, bus_generic_print_child), 14367196661SRafal Jaworowski DEVMETHOD(bus_driver_added, bus_generic_driver_added), 14467196661SRafal Jaworowski 14567196661SRafal Jaworowski /* MII interface */ 14667196661SRafal Jaworowski DEVMETHOD(miibus_readreg, tsec_miibus_readreg), 14767196661SRafal Jaworowski DEVMETHOD(miibus_writereg, tsec_miibus_writereg), 14867196661SRafal Jaworowski DEVMETHOD(miibus_statchg, tsec_miibus_statchg), 14967196661SRafal Jaworowski { 0, 0 } 15067196661SRafal Jaworowski }; 15167196661SRafal Jaworowski 15267196661SRafal Jaworowski static driver_t tsec_driver = { 15367196661SRafal Jaworowski "tsec", 15467196661SRafal Jaworowski tsec_methods, 15567196661SRafal Jaworowski sizeof(struct tsec_softc), 15667196661SRafal Jaworowski }; 15767196661SRafal Jaworowski 15867196661SRafal Jaworowski static devclass_t tsec_devclass; 15967196661SRafal Jaworowski 16067196661SRafal Jaworowski DRIVER_MODULE(tsec, ocpbus, tsec_driver, tsec_devclass, 0, 0); 16167196661SRafal Jaworowski DRIVER_MODULE(miibus, tsec, miibus_driver, miibus_devclass, 0, 0); 16267196661SRafal Jaworowski MODULE_DEPEND(tsec, ether, 1, 1, 1); 16367196661SRafal Jaworowski MODULE_DEPEND(tsec, miibus, 1, 1, 1); 16467196661SRafal Jaworowski 16567196661SRafal Jaworowski static void 16667196661SRafal Jaworowski tsec_get_hwaddr(struct tsec_softc *sc, uint8_t *addr) 16767196661SRafal Jaworowski { 16867196661SRafal Jaworowski union { 16967196661SRafal Jaworowski uint32_t reg[2]; 17067196661SRafal Jaworowski uint8_t addr[6]; 17167196661SRafal Jaworowski } curmac; 17267196661SRafal Jaworowski uint32_t a[6]; 173ecb1ab17SRafal Jaworowski device_t parent; 174ecb1ab17SRafal Jaworowski uintptr_t macaddr; 175ecb1ab17SRafal Jaworowski int i; 17667196661SRafal Jaworowski 177ecb1ab17SRafal Jaworowski parent = device_get_parent(sc->dev); 178ecb1ab17SRafal Jaworowski if (BUS_READ_IVAR(parent, sc->dev, OCPBUS_IVAR_MACADDR, 179ecb1ab17SRafal Jaworowski &macaddr) == 0) { 180ecb1ab17SRafal Jaworowski bcopy((uint8_t *)macaddr, addr, 6); 181ecb1ab17SRafal Jaworowski return; 182ecb1ab17SRafal Jaworowski } 183ecb1ab17SRafal Jaworowski 184ecb1ab17SRafal Jaworowski /* 185ecb1ab17SRafal Jaworowski * Fall back -- use the currently programmed address in the hope that 186ecb1ab17SRafal Jaworowski * it was set be firmware... 187ecb1ab17SRafal Jaworowski */ 18867196661SRafal Jaworowski curmac.reg[0] = TSEC_READ(sc, TSEC_REG_MACSTNADDR1); 18967196661SRafal Jaworowski curmac.reg[1] = TSEC_READ(sc, TSEC_REG_MACSTNADDR2); 19067196661SRafal Jaworowski for (i = 0; i < 6; i++) 19167196661SRafal Jaworowski a[5-i] = curmac.addr[i]; 19267196661SRafal Jaworowski 19367196661SRafal Jaworowski addr[0] = a[0]; 19467196661SRafal Jaworowski addr[1] = a[1]; 19567196661SRafal Jaworowski addr[2] = a[2]; 19667196661SRafal Jaworowski addr[3] = a[3]; 19767196661SRafal Jaworowski addr[4] = a[4]; 19867196661SRafal Jaworowski addr[5] = a[5]; 19967196661SRafal Jaworowski } 20067196661SRafal Jaworowski 20167196661SRafal Jaworowski static void 20267196661SRafal Jaworowski tsec_init(void *xsc) 20367196661SRafal Jaworowski { 20467196661SRafal Jaworowski struct tsec_softc *sc = xsc; 20567196661SRafal Jaworowski 20667196661SRafal Jaworowski TSEC_GLOBAL_LOCK(sc); 20767196661SRafal Jaworowski tsec_init_locked(sc); 20867196661SRafal Jaworowski TSEC_GLOBAL_UNLOCK(sc); 20967196661SRafal Jaworowski } 21067196661SRafal Jaworowski 21167196661SRafal Jaworowski static void 21267196661SRafal Jaworowski tsec_init_locked(struct tsec_softc *sc) 21367196661SRafal Jaworowski { 21467196661SRafal Jaworowski struct tsec_desc *tx_desc = sc->tsec_tx_vaddr; 21567196661SRafal Jaworowski struct tsec_desc *rx_desc = sc->tsec_rx_vaddr; 21667196661SRafal Jaworowski struct ifnet *ifp = sc->tsec_ifp; 21767196661SRafal Jaworowski uint32_t timeout; 21867196661SRafal Jaworowski uint32_t val; 21967196661SRafal Jaworowski uint32_t i; 22067196661SRafal Jaworowski 22167196661SRafal Jaworowski TSEC_GLOBAL_LOCK_ASSERT(sc); 22267196661SRafal Jaworowski tsec_stop(sc); 22367196661SRafal Jaworowski 22467196661SRafal Jaworowski /* 22567196661SRafal Jaworowski * These steps are according to the MPC8555E PowerQUICCIII RM: 22667196661SRafal Jaworowski * 14.7 Initialization/Application Information 22767196661SRafal Jaworowski */ 22867196661SRafal Jaworowski 22967196661SRafal Jaworowski /* Step 1: soft reset MAC */ 23067196661SRafal Jaworowski tsec_reset_mac(sc); 23167196661SRafal Jaworowski 23267196661SRafal Jaworowski /* Step 2: Initialize MACCFG2 */ 23367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG2, 23467196661SRafal Jaworowski TSEC_MACCFG2_FULLDUPLEX | /* Full Duplex = 1 */ 23567196661SRafal Jaworowski TSEC_MACCFG2_PADCRC | /* PAD/CRC append */ 23667196661SRafal Jaworowski TSEC_MACCFG2_GMII | /* I/F Mode bit */ 23767196661SRafal Jaworowski TSEC_MACCFG2_PRECNT /* Preamble count = 7 */ 23867196661SRafal Jaworowski ); 23967196661SRafal Jaworowski 24067196661SRafal Jaworowski /* Step 3: Initialize ECNTRL 24167196661SRafal Jaworowski * While the documentation states that R100M is ignored if RPM is 24267196661SRafal Jaworowski * not set, it does seem to be needed to get the orange boxes to 24367196661SRafal Jaworowski * work (which have a Marvell 88E1111 PHY). Go figure. 24467196661SRafal Jaworowski */ 24567196661SRafal Jaworowski 24667196661SRafal Jaworowski /* 24767196661SRafal Jaworowski * XXX kludge - use circumstancial evidence to program ECNTRL 24867196661SRafal Jaworowski * correctly. Ideally we need some board information to guide 24967196661SRafal Jaworowski * us here. 25067196661SRafal Jaworowski */ 25167196661SRafal Jaworowski i = TSEC_READ(sc, TSEC_REG_ID2); 25267196661SRafal Jaworowski val = (i & 0xffff) 25367196661SRafal Jaworowski ? (TSEC_ECNTRL_TBIM | TSEC_ECNTRL_SGMIIM) /* Sumatra */ 25467196661SRafal Jaworowski : TSEC_ECNTRL_R100M; /* Orange + CDS */ 25567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_ECNTRL, TSEC_ECNTRL_STEN | val); 25667196661SRafal Jaworowski 25767196661SRafal Jaworowski /* Step 4: Initialize MAC station address */ 25867196661SRafal Jaworowski tsec_set_mac_address(sc); 25967196661SRafal Jaworowski 26067196661SRafal Jaworowski /* 26167196661SRafal Jaworowski * Step 5: Assign a Physical address to the TBI so as to not conflict 26267196661SRafal Jaworowski * with the external PHY physical address 26367196661SRafal Jaworowski */ 26467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TBIPA, 5); 26567196661SRafal Jaworowski 26667196661SRafal Jaworowski /* Step 6: Reset the management interface */ 26767196661SRafal Jaworowski TSEC_WRITE(tsec0_sc, TSEC_REG_MIIMCFG, TSEC_MIIMCFG_RESETMGMT); 26867196661SRafal Jaworowski 26967196661SRafal Jaworowski /* Step 7: Setup the MII Mgmt clock speed */ 27067196661SRafal Jaworowski TSEC_WRITE(tsec0_sc, TSEC_REG_MIIMCFG, TSEC_MIIMCFG_CLKDIV28); 27167196661SRafal Jaworowski 27267196661SRafal Jaworowski /* Step 8: Read MII Mgmt indicator register and check for Busy = 0 */ 27367196661SRafal Jaworowski timeout = TSEC_READ_RETRY; 27467196661SRafal Jaworowski while (--timeout && (TSEC_READ(tsec0_sc, TSEC_REG_MIIMIND) & 27567196661SRafal Jaworowski TSEC_MIIMIND_BUSY)) 27667196661SRafal Jaworowski DELAY(TSEC_READ_DELAY); 27767196661SRafal Jaworowski if (timeout == 0) { 27867196661SRafal Jaworowski if_printf(ifp, "tsec_init_locked(): Mgmt busy timeout\n"); 27967196661SRafal Jaworowski return; 28067196661SRafal Jaworowski } 28167196661SRafal Jaworowski 28267196661SRafal Jaworowski /* Step 9: Setup the MII Mgmt */ 28367196661SRafal Jaworowski mii_mediachg(sc->tsec_mii); 28467196661SRafal Jaworowski 28567196661SRafal Jaworowski /* Step 10: Clear IEVENT register */ 28667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, 0xffffffff); 28767196661SRafal Jaworowski 28867196661SRafal Jaworowski /* Step 11: Initialize IMASK */ 28967196661SRafal Jaworowski tsec_intrs_ctl(sc, 1); 29067196661SRafal Jaworowski 29167196661SRafal Jaworowski /* Step 12: Initialize IADDRn */ 29267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR0, 0); 29367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR1, 0); 29467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR2, 0); 29567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR3, 0); 29667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR4, 0); 29767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR5, 0); 29867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR6, 0); 29967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR7, 0); 30067196661SRafal Jaworowski 30167196661SRafal Jaworowski /* Step 13: Initialize GADDRn */ 30267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR0, 0); 30367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR1, 0); 30467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR2, 0); 30567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR3, 0); 30667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR4, 0); 30767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR5, 0); 30867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR6, 0); 30967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR7, 0); 31067196661SRafal Jaworowski 31167196661SRafal Jaworowski /* Step 14: Initialize RCTRL */ 31267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_RCTRL, 0); 31367196661SRafal Jaworowski 31467196661SRafal Jaworowski /* Step 15: Initialize DMACTRL */ 31567196661SRafal Jaworowski tsec_dma_ctl(sc, 1); 31667196661SRafal Jaworowski 31767196661SRafal Jaworowski /* Step 16: Initialize FIFO_PAUSE_CTRL */ 31867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_FIFO_PAUSE_CTRL, TSEC_FIFO_PAUSE_CTRL_EN); 31967196661SRafal Jaworowski 32067196661SRafal Jaworowski /* 32167196661SRafal Jaworowski * Step 17: Initialize transmit/receive descriptor rings. 32267196661SRafal Jaworowski * Initialize TBASE and RBASE. 32367196661SRafal Jaworowski */ 32467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TBASE, sc->tsec_tx_raddr); 32567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_RBASE, sc->tsec_rx_raddr); 32667196661SRafal Jaworowski 32767196661SRafal Jaworowski for (i = 0; i < TSEC_TX_NUM_DESC; i++) { 32867196661SRafal Jaworowski tx_desc[i].bufptr = 0; 32967196661SRafal Jaworowski tx_desc[i].length = 0; 33067196661SRafal Jaworowski tx_desc[i].flags = ((i == TSEC_TX_NUM_DESC-1) ? TSEC_TXBD_W : 0); 33167196661SRafal Jaworowski } 33267196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, BUS_DMASYNC_PREREAD | 33367196661SRafal Jaworowski BUS_DMASYNC_PREWRITE); 33467196661SRafal Jaworowski 33567196661SRafal Jaworowski for (i = 0; i < TSEC_RX_NUM_DESC; i++) { 33667196661SRafal Jaworowski rx_desc[i].bufptr = sc->rx_data[i].paddr; 33767196661SRafal Jaworowski rx_desc[i].length = 0; 33867196661SRafal Jaworowski rx_desc[i].flags = TSEC_RXBD_E | TSEC_RXBD_I | 33967196661SRafal Jaworowski ((i == TSEC_RX_NUM_DESC-1) ? TSEC_RXBD_W : 0); 34067196661SRafal Jaworowski } 34167196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_rx_dtag, sc->tsec_rx_dmap, BUS_DMASYNC_PREREAD | 34267196661SRafal Jaworowski BUS_DMASYNC_PREWRITE); 34367196661SRafal Jaworowski 34467196661SRafal Jaworowski /* Step 18: Initialize the maximum and minimum receive buffer length */ 34567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MRBLR, TSEC_DEFAULT_MAX_RX_BUFFER_SIZE); 34667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MINFLR, TSEC_DEFAULT_MIN_RX_BUFFER_SIZE); 34767196661SRafal Jaworowski 34867196661SRafal Jaworowski /* Step 19: Enable Rx and RxBD sdata snooping */ 34967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_ATTR, TSEC_ATTR_RDSEN | TSEC_ATTR_RBDSEN); 35067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_ATTRELI, 0); 35167196661SRafal Jaworowski 35267196661SRafal Jaworowski /* Step 20: Reset collision counters in hardware */ 35367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TSCL, 0); 35467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TMCL, 0); 35567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TLCL, 0); 35667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TXCL, 0); 35767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TNCL, 0); 35867196661SRafal Jaworowski 35967196661SRafal Jaworowski /* Step 21: Mask all CAM interrupts */ 36067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_CAM1, 0xffffffff); 36167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_CAM2, 0xffffffff); 36267196661SRafal Jaworowski 36367196661SRafal Jaworowski /* Step 22: Enable Rx and Tx */ 36467196661SRafal Jaworowski val = TSEC_READ(sc, TSEC_REG_MACCFG1); 36567196661SRafal Jaworowski val |= (TSEC_MACCFG1_RX_EN | TSEC_MACCFG1_TX_EN); 36667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG1, val); 36767196661SRafal Jaworowski 36867196661SRafal Jaworowski /* Step 23: Reset TSEC counters for Tx and Rx rings */ 36967196661SRafal Jaworowski TSEC_TX_RX_COUNTERS_INIT(sc); 37067196661SRafal Jaworowski 3715432bd9fSRafal Jaworowski /* Step 24: Activate network interface */ 37267196661SRafal Jaworowski ifp->if_drv_flags |= IFF_DRV_RUNNING; 37367196661SRafal Jaworowski ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 37467196661SRafal Jaworowski sc->tsec_if_flags = ifp->if_flags; 3755432bd9fSRafal Jaworowski sc->tsec_watchdog = 0; 376772619e1SRafal Jaworowski 377772619e1SRafal Jaworowski /* Schedule watchdog timeout */ 3785432bd9fSRafal Jaworowski callout_reset(&sc->tsec_callout, hz, tsec_tick, sc); 37967196661SRafal Jaworowski } 38067196661SRafal Jaworowski 38167196661SRafal Jaworowski static void 38267196661SRafal Jaworowski tsec_set_mac_address(struct tsec_softc *sc) 38367196661SRafal Jaworowski { 38467196661SRafal Jaworowski uint32_t macbuf[2] = { 0, 0 }; 38567196661SRafal Jaworowski int i; 38667196661SRafal Jaworowski char *macbufp; 38767196661SRafal Jaworowski char *curmac; 38867196661SRafal Jaworowski 38967196661SRafal Jaworowski TSEC_GLOBAL_LOCK_ASSERT(sc); 39067196661SRafal Jaworowski 39167196661SRafal Jaworowski KASSERT((ETHER_ADDR_LEN <= sizeof(macbuf)), 39267196661SRafal Jaworowski ("tsec_set_mac_address: (%d <= %d", 39367196661SRafal Jaworowski ETHER_ADDR_LEN, sizeof(macbuf))); 39467196661SRafal Jaworowski 39567196661SRafal Jaworowski macbufp = (char *)macbuf; 39667196661SRafal Jaworowski curmac = (char *)IF_LLADDR(sc->tsec_ifp); 39767196661SRafal Jaworowski 39867196661SRafal Jaworowski /* Correct order of MAC address bytes */ 39967196661SRafal Jaworowski for (i = 1; i <= ETHER_ADDR_LEN; i++) 40067196661SRafal Jaworowski macbufp[ETHER_ADDR_LEN-i] = curmac[i-1]; 40167196661SRafal Jaworowski 40267196661SRafal Jaworowski /* Initialize MAC station address MACSTNADDR2 and MACSTNADDR1 */ 40367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACSTNADDR2, macbuf[1]); 40467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACSTNADDR1, macbuf[0]); 40567196661SRafal Jaworowski } 40667196661SRafal Jaworowski 40767196661SRafal Jaworowski /* 40867196661SRafal Jaworowski * DMA control function, if argument state is: 40967196661SRafal Jaworowski * 0 - DMA engine will be disabled 41067196661SRafal Jaworowski * 1 - DMA engine will be enabled 41167196661SRafal Jaworowski */ 41267196661SRafal Jaworowski static void 41367196661SRafal Jaworowski tsec_dma_ctl(struct tsec_softc *sc, int state) 41467196661SRafal Jaworowski { 41567196661SRafal Jaworowski device_t dev; 41667196661SRafal Jaworowski uint32_t dma_flags; 41767196661SRafal Jaworowski uint32_t timeout; 41867196661SRafal Jaworowski 41967196661SRafal Jaworowski dev = sc->dev; 42067196661SRafal Jaworowski 42167196661SRafal Jaworowski dma_flags = TSEC_READ(sc, TSEC_REG_DMACTRL); 42267196661SRafal Jaworowski 42367196661SRafal Jaworowski switch (state) { 42467196661SRafal Jaworowski case 0: 42567196661SRafal Jaworowski /* Temporarily clear stop graceful stop bits. */ 42667196661SRafal Jaworowski tsec_dma_ctl(sc, 1000); 42767196661SRafal Jaworowski 42867196661SRafal Jaworowski /* Set it again */ 42967196661SRafal Jaworowski dma_flags |= (TSEC_DMACTRL_GRS | TSEC_DMACTRL_GTS); 43067196661SRafal Jaworowski break; 43167196661SRafal Jaworowski case 1000: 43267196661SRafal Jaworowski case 1: 43367196661SRafal Jaworowski /* Set write with response (WWR), wait (WOP) and snoop bits */ 43467196661SRafal Jaworowski dma_flags |= (TSEC_DMACTRL_TDSEN | TSEC_DMACTRL_TBDSEN | 43567196661SRafal Jaworowski DMACTRL_WWR | DMACTRL_WOP); 43667196661SRafal Jaworowski 43767196661SRafal Jaworowski /* Clear graceful stop bits */ 43867196661SRafal Jaworowski dma_flags &= ~(TSEC_DMACTRL_GRS | TSEC_DMACTRL_GTS); 43967196661SRafal Jaworowski break; 44067196661SRafal Jaworowski default: 44167196661SRafal Jaworowski device_printf(dev, "tsec_dma_ctl(): unknown state value: %d\n", 44267196661SRafal Jaworowski state); 44367196661SRafal Jaworowski } 44467196661SRafal Jaworowski 44567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_DMACTRL, dma_flags); 44667196661SRafal Jaworowski 44767196661SRafal Jaworowski switch (state) { 44867196661SRafal Jaworowski case 0: 44967196661SRafal Jaworowski /* Wait for DMA stop */ 45067196661SRafal Jaworowski timeout = TSEC_READ_RETRY; 45167196661SRafal Jaworowski while (--timeout && (!(TSEC_READ(sc, TSEC_REG_IEVENT) & 45267196661SRafal Jaworowski (TSEC_IEVENT_GRSC | TSEC_IEVENT_GTSC)))) 45367196661SRafal Jaworowski DELAY(TSEC_READ_DELAY); 45467196661SRafal Jaworowski 45567196661SRafal Jaworowski if (timeout == 0) 45667196661SRafal Jaworowski device_printf(dev, "tsec_dma_ctl(): timeout!\n"); 45767196661SRafal Jaworowski break; 45867196661SRafal Jaworowski case 1: 45967196661SRafal Jaworowski /* Restart transmission function */ 46067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TSTAT, TSEC_TSTAT_THLT); 46167196661SRafal Jaworowski } 46267196661SRafal Jaworowski } 46367196661SRafal Jaworowski 46467196661SRafal Jaworowski /* 46567196661SRafal Jaworowski * Interrupts control function, if argument state is: 46667196661SRafal Jaworowski * 0 - all TSEC interrupts will be masked 46767196661SRafal Jaworowski * 1 - all TSEC interrupts will be unmasked 46867196661SRafal Jaworowski */ 46967196661SRafal Jaworowski static void 47067196661SRafal Jaworowski tsec_intrs_ctl(struct tsec_softc *sc, int state) 47167196661SRafal Jaworowski { 47267196661SRafal Jaworowski device_t dev; 47367196661SRafal Jaworowski 47467196661SRafal Jaworowski dev = sc->dev; 47567196661SRafal Jaworowski 47667196661SRafal Jaworowski switch (state) { 47767196661SRafal Jaworowski case 0: 47867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IMASK, 0); 47967196661SRafal Jaworowski break; 48067196661SRafal Jaworowski case 1: 48167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IMASK, TSEC_IMASK_BREN | 48267196661SRafal Jaworowski TSEC_IMASK_RXCEN | TSEC_IMASK_BSYEN | 48367196661SRafal Jaworowski TSEC_IMASK_EBERREN | TSEC_IMASK_BTEN | 48467196661SRafal Jaworowski TSEC_IMASK_TXEEN | TSEC_IMASK_TXBEN | 48567196661SRafal Jaworowski TSEC_IMASK_TXFEN | TSEC_IMASK_XFUNEN | 48667196661SRafal Jaworowski TSEC_IMASK_RXFEN 48767196661SRafal Jaworowski ); 48867196661SRafal Jaworowski break; 48967196661SRafal Jaworowski default: 49067196661SRafal Jaworowski device_printf(dev, "tsec_intrs_ctl(): unknown state value: %d\n", 49167196661SRafal Jaworowski state); 49267196661SRafal Jaworowski } 49367196661SRafal Jaworowski } 49467196661SRafal Jaworowski 49567196661SRafal Jaworowski static void 49667196661SRafal Jaworowski tsec_reset_mac(struct tsec_softc *sc) 49767196661SRafal Jaworowski { 49867196661SRafal Jaworowski uint32_t maccfg1_flags; 49967196661SRafal Jaworowski 50067196661SRafal Jaworowski /* Set soft reset bit */ 50167196661SRafal Jaworowski maccfg1_flags = TSEC_READ(sc, TSEC_REG_MACCFG1); 50267196661SRafal Jaworowski maccfg1_flags |= TSEC_MACCFG1_SOFT_RESET; 50367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG1, maccfg1_flags); 50467196661SRafal Jaworowski 50567196661SRafal Jaworowski /* Clear soft reset bit */ 50667196661SRafal Jaworowski maccfg1_flags = TSEC_READ(sc, TSEC_REG_MACCFG1); 50767196661SRafal Jaworowski maccfg1_flags &= ~TSEC_MACCFG1_SOFT_RESET; 50867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG1, maccfg1_flags); 50967196661SRafal Jaworowski } 51067196661SRafal Jaworowski 51167196661SRafal Jaworowski static void 512772619e1SRafal Jaworowski tsec_watchdog(struct tsec_softc *sc) 51367196661SRafal Jaworowski { 514772619e1SRafal Jaworowski struct ifnet *ifp; 51567196661SRafal Jaworowski 516772619e1SRafal Jaworowski TSEC_GLOBAL_LOCK_ASSERT(sc); 51767196661SRafal Jaworowski 5185432bd9fSRafal Jaworowski if (sc->tsec_watchdog == 0 || --sc->tsec_watchdog > 0) 519772619e1SRafal Jaworowski return; 520772619e1SRafal Jaworowski 521772619e1SRafal Jaworowski ifp = sc->tsec_ifp; 52267196661SRafal Jaworowski ifp->if_oerrors++; 52367196661SRafal Jaworowski if_printf(ifp, "watchdog timeout\n"); 52467196661SRafal Jaworowski 52567196661SRafal Jaworowski tsec_stop(sc); 52667196661SRafal Jaworowski tsec_init_locked(sc); 52767196661SRafal Jaworowski } 52867196661SRafal Jaworowski 52967196661SRafal Jaworowski static void 53067196661SRafal Jaworowski tsec_start(struct ifnet *ifp) 53167196661SRafal Jaworowski { 53267196661SRafal Jaworowski struct tsec_softc *sc = ifp->if_softc; 53367196661SRafal Jaworowski 53467196661SRafal Jaworowski TSEC_TRANSMIT_LOCK(sc); 53567196661SRafal Jaworowski tsec_start_locked(ifp); 53667196661SRafal Jaworowski TSEC_TRANSMIT_UNLOCK(sc); 53767196661SRafal Jaworowski } 53867196661SRafal Jaworowski 53967196661SRafal Jaworowski static void 54067196661SRafal Jaworowski tsec_start_locked(struct ifnet *ifp) 54167196661SRafal Jaworowski { 54267196661SRafal Jaworowski struct tsec_softc *sc; 54367196661SRafal Jaworowski struct mbuf *m0; 54467196661SRafal Jaworowski struct mbuf *mtmp; 54567196661SRafal Jaworowski unsigned int queued = 0; 54667196661SRafal Jaworowski 54767196661SRafal Jaworowski sc = ifp->if_softc; 54867196661SRafal Jaworowski 54967196661SRafal Jaworowski TSEC_TRANSMIT_LOCK_ASSERT(sc); 55067196661SRafal Jaworowski 55167196661SRafal Jaworowski if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 55267196661SRafal Jaworowski IFF_DRV_RUNNING) 55367196661SRafal Jaworowski return; 55467196661SRafal Jaworowski 55567196661SRafal Jaworowski if (sc->tsec_link == 0) 55667196661SRafal Jaworowski return; 55767196661SRafal Jaworowski 55867196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, 55967196661SRafal Jaworowski BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 56067196661SRafal Jaworowski 56167196661SRafal Jaworowski for (;;) { 56267196661SRafal Jaworowski /* Get packet from the queue */ 56367196661SRafal Jaworowski IF_DEQUEUE(&ifp->if_snd, m0); 56467196661SRafal Jaworowski if (m0 == NULL) 56567196661SRafal Jaworowski break; 56667196661SRafal Jaworowski 56767196661SRafal Jaworowski mtmp = m_defrag(m0, M_DONTWAIT); 56867196661SRafal Jaworowski if (mtmp) 56967196661SRafal Jaworowski m0 = mtmp; 57067196661SRafal Jaworowski 57167196661SRafal Jaworowski if (tsec_encap(sc, m0)) { 57267196661SRafal Jaworowski IF_PREPEND(&ifp->if_snd, m0); 57367196661SRafal Jaworowski ifp->if_drv_flags |= IFF_DRV_OACTIVE; 57467196661SRafal Jaworowski break; 57567196661SRafal Jaworowski } 57667196661SRafal Jaworowski queued++; 57767196661SRafal Jaworowski BPF_MTAP(ifp, m0); 57867196661SRafal Jaworowski } 57967196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, 58067196661SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 58167196661SRafal Jaworowski 58267196661SRafal Jaworowski if (queued) { 58367196661SRafal Jaworowski /* Enable transmitter and watchdog timer */ 58467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TSTAT, TSEC_TSTAT_THLT); 5855432bd9fSRafal Jaworowski sc->tsec_watchdog = 5; 58667196661SRafal Jaworowski } 58767196661SRafal Jaworowski } 58867196661SRafal Jaworowski 58967196661SRafal Jaworowski static int 59067196661SRafal Jaworowski tsec_encap(struct tsec_softc *sc, struct mbuf *m0) 59167196661SRafal Jaworowski { 59267196661SRafal Jaworowski struct tsec_desc *tx_desc = NULL; 59367196661SRafal Jaworowski struct ifnet *ifp; 59467196661SRafal Jaworowski bus_dma_segment_t segs[TSEC_TX_NUM_DESC]; 59567196661SRafal Jaworowski bus_dmamap_t *mapp; 59667196661SRafal Jaworowski int error; 59767196661SRafal Jaworowski int seg, nsegs; 59867196661SRafal Jaworowski 59967196661SRafal Jaworowski TSEC_TRANSMIT_LOCK_ASSERT(sc); 60067196661SRafal Jaworowski 60167196661SRafal Jaworowski ifp = sc->tsec_ifp; 60267196661SRafal Jaworowski 60367196661SRafal Jaworowski if (TSEC_FREE_TX_DESC(sc) == 0) { 60467196661SRafal Jaworowski /* No free descriptors */ 60567196661SRafal Jaworowski return (-1); 60667196661SRafal Jaworowski } 60767196661SRafal Jaworowski 60867196661SRafal Jaworowski /* Fetch unused map */ 60967196661SRafal Jaworowski mapp = TSEC_ALLOC_TX_MAP(sc); 61067196661SRafal Jaworowski 61167196661SRafal Jaworowski /* Create mapping in DMA memory */ 61267196661SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(sc->tsec_tx_mtag, 61367196661SRafal Jaworowski *mapp, m0, segs, &nsegs, BUS_DMA_NOWAIT); 61467196661SRafal Jaworowski if (error != 0 || nsegs > TSEC_FREE_TX_DESC(sc) || nsegs <= 0) { 61567196661SRafal Jaworowski bus_dmamap_unload(sc->tsec_tx_mtag, *mapp); 61667196661SRafal Jaworowski TSEC_FREE_TX_MAP(sc, mapp); 61767196661SRafal Jaworowski return ((error != 0) ? error : -1); 61867196661SRafal Jaworowski } 61967196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_mtag, *mapp, BUS_DMASYNC_PREWRITE); 62067196661SRafal Jaworowski 62167196661SRafal Jaworowski if ((ifp->if_flags & IFF_DEBUG) && (nsegs > 1)) 62267196661SRafal Jaworowski if_printf(ifp, "TX buffer has %d segments\n", nsegs); 62367196661SRafal Jaworowski 62467196661SRafal Jaworowski /* Everything is ok, now we can send buffers */ 62567196661SRafal Jaworowski for (seg = 0; seg < nsegs; seg++) { 62667196661SRafal Jaworowski tx_desc = TSEC_GET_CUR_TX_DESC(sc); 62767196661SRafal Jaworowski 62867196661SRafal Jaworowski tx_desc->length = segs[seg].ds_len; 62967196661SRafal Jaworowski tx_desc->bufptr = segs[seg].ds_addr; 63067196661SRafal Jaworowski 63167196661SRafal Jaworowski tx_desc->flags = 63267196661SRafal Jaworowski (tx_desc->flags & TSEC_TXBD_W) | /* wrap */ 63367196661SRafal Jaworowski TSEC_TXBD_I | /* interrupt */ 63467196661SRafal Jaworowski TSEC_TXBD_R | /* ready to send */ 63567196661SRafal Jaworowski TSEC_TXBD_TC | /* transmit the CRC sequence 63667196661SRafal Jaworowski * after the last data byte */ 63767196661SRafal Jaworowski ((seg == nsegs-1) ? TSEC_TXBD_L : 0);/* last in frame */ 63867196661SRafal Jaworowski } 63967196661SRafal Jaworowski 64067196661SRafal Jaworowski /* Save mbuf and DMA mapping for release at later stage */ 64167196661SRafal Jaworowski TSEC_PUT_TX_MBUF(sc, m0); 64267196661SRafal Jaworowski TSEC_PUT_TX_MAP(sc, mapp); 64367196661SRafal Jaworowski 64467196661SRafal Jaworowski return (0); 64567196661SRafal Jaworowski } 64667196661SRafal Jaworowski 64767196661SRafal Jaworowski static void 64867196661SRafal Jaworowski tsec_setfilter(struct tsec_softc *sc) 64967196661SRafal Jaworowski { 65067196661SRafal Jaworowski struct ifnet *ifp; 65167196661SRafal Jaworowski uint32_t flags; 65267196661SRafal Jaworowski 65367196661SRafal Jaworowski ifp = sc->tsec_ifp; 65467196661SRafal Jaworowski flags = TSEC_READ(sc, TSEC_REG_RCTRL); 65567196661SRafal Jaworowski 65667196661SRafal Jaworowski /* Promiscuous mode */ 65767196661SRafal Jaworowski if (ifp->if_flags & IFF_PROMISC) 65867196661SRafal Jaworowski flags |= TSEC_RCTRL_PROM; 65967196661SRafal Jaworowski else 66067196661SRafal Jaworowski flags &= ~TSEC_RCTRL_PROM; 66167196661SRafal Jaworowski 66267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_RCTRL, flags); 66367196661SRafal Jaworowski } 66467196661SRafal Jaworowski 66567196661SRafal Jaworowski static int 66667196661SRafal Jaworowski tsec_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 66767196661SRafal Jaworowski { 66867196661SRafal Jaworowski struct tsec_softc *sc = ifp->if_softc; 66967196661SRafal Jaworowski struct ifreq *ifr = (struct ifreq *)data; 67067196661SRafal Jaworowski device_t dev; 67167196661SRafal Jaworowski int error = 0; 67267196661SRafal Jaworowski 67367196661SRafal Jaworowski dev = sc->dev; 67467196661SRafal Jaworowski 67567196661SRafal Jaworowski switch (command) { 67667196661SRafal Jaworowski case SIOCSIFFLAGS: 67767196661SRafal Jaworowski TSEC_GLOBAL_LOCK(sc); 67867196661SRafal Jaworowski if (ifp->if_flags & IFF_UP) { 67967196661SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 68067196661SRafal Jaworowski if ((sc->tsec_if_flags ^ ifp->if_flags) & 68167196661SRafal Jaworowski IFF_PROMISC) 68267196661SRafal Jaworowski tsec_setfilter(sc); 68367196661SRafal Jaworowski } else 68467196661SRafal Jaworowski tsec_init_locked(sc); 68567196661SRafal Jaworowski } else { 68667196661SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) 68767196661SRafal Jaworowski tsec_stop(sc); 68867196661SRafal Jaworowski } 68967196661SRafal Jaworowski sc->tsec_if_flags = ifp->if_flags; 69067196661SRafal Jaworowski TSEC_GLOBAL_UNLOCK(sc); 69167196661SRafal Jaworowski break; 69267196661SRafal Jaworowski case SIOCGIFMEDIA: 69367196661SRafal Jaworowski case SIOCSIFMEDIA: 69467196661SRafal Jaworowski error = ifmedia_ioctl(ifp, ifr, &sc->tsec_mii->mii_media, 69567196661SRafal Jaworowski command); 69667196661SRafal Jaworowski break; 69767196661SRafal Jaworowski default: 69867196661SRafal Jaworowski error = ether_ioctl(ifp, command, data); 69967196661SRafal Jaworowski } 70067196661SRafal Jaworowski 70167196661SRafal Jaworowski /* Flush buffers if not empty */ 70267196661SRafal Jaworowski if (ifp->if_flags & IFF_UP) 70367196661SRafal Jaworowski tsec_start(ifp); 70467196661SRafal Jaworowski return (error); 70567196661SRafal Jaworowski } 70667196661SRafal Jaworowski 70767196661SRafal Jaworowski static int 70867196661SRafal Jaworowski tsec_ifmedia_upd(struct ifnet *ifp) 70967196661SRafal Jaworowski { 71067196661SRafal Jaworowski struct tsec_softc *sc = ifp->if_softc; 71167196661SRafal Jaworowski struct mii_data *mii; 71267196661SRafal Jaworowski 71367196661SRafal Jaworowski TSEC_TRANSMIT_LOCK(sc); 71467196661SRafal Jaworowski 71567196661SRafal Jaworowski mii = sc->tsec_mii; 71667196661SRafal Jaworowski mii_mediachg(mii); 71767196661SRafal Jaworowski 71867196661SRafal Jaworowski TSEC_TRANSMIT_UNLOCK(sc); 71967196661SRafal Jaworowski return (0); 72067196661SRafal Jaworowski } 72167196661SRafal Jaworowski 72267196661SRafal Jaworowski static void 72367196661SRafal Jaworowski tsec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 72467196661SRafal Jaworowski { 72567196661SRafal Jaworowski struct tsec_softc *sc = ifp->if_softc; 72667196661SRafal Jaworowski struct mii_data *mii; 72767196661SRafal Jaworowski 72867196661SRafal Jaworowski TSEC_TRANSMIT_LOCK(sc); 72967196661SRafal Jaworowski 73067196661SRafal Jaworowski mii = sc->tsec_mii; 73167196661SRafal Jaworowski mii_pollstat(mii); 73267196661SRafal Jaworowski 73367196661SRafal Jaworowski ifmr->ifm_active = mii->mii_media_active; 73467196661SRafal Jaworowski ifmr->ifm_status = mii->mii_media_status; 73567196661SRafal Jaworowski 73667196661SRafal Jaworowski TSEC_TRANSMIT_UNLOCK(sc); 73767196661SRafal Jaworowski } 73867196661SRafal Jaworowski 73967196661SRafal Jaworowski static int 74067196661SRafal Jaworowski tsec_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp, 74167196661SRafal Jaworowski uint32_t *paddr) 74267196661SRafal Jaworowski { 74367196661SRafal Jaworowski struct mbuf *new_mbuf; 74467196661SRafal Jaworowski bus_dma_segment_t seg[1]; 74567196661SRafal Jaworowski int error; 74667196661SRafal Jaworowski int nsegs; 74767196661SRafal Jaworowski 74867196661SRafal Jaworowski KASSERT(mbufp != NULL, ("NULL mbuf pointer!")); 74967196661SRafal Jaworowski 75067196661SRafal Jaworowski new_mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 75167196661SRafal Jaworowski if (new_mbuf == NULL) 75267196661SRafal Jaworowski return (ENOBUFS); 75367196661SRafal Jaworowski new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size; 75467196661SRafal Jaworowski 75567196661SRafal Jaworowski if (*mbufp) { 75667196661SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD); 75767196661SRafal Jaworowski bus_dmamap_unload(tag, map); 75867196661SRafal Jaworowski } 75967196661SRafal Jaworowski 76067196661SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs, 76167196661SRafal Jaworowski BUS_DMA_NOWAIT); 76267196661SRafal Jaworowski KASSERT(nsegs == 1, ("Too many segments returned!")); 76367196661SRafal Jaworowski if (nsegs != 1 || error) 76467196661SRafal Jaworowski panic("tsec_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error); 76567196661SRafal Jaworowski 76667196661SRafal Jaworowski #if 0 76767196661SRafal Jaworowski if (error) { 76867196661SRafal Jaworowski printf("tsec: bus_dmamap_load_mbuf_sg() returned: %d!\n", 76967196661SRafal Jaworowski error); 77067196661SRafal Jaworowski m_freem(new_mbuf); 77167196661SRafal Jaworowski return (ENOBUFS); 77267196661SRafal Jaworowski } 77367196661SRafal Jaworowski #endif 77467196661SRafal Jaworowski 77567196661SRafal Jaworowski #if 0 77667196661SRafal Jaworowski KASSERT(((seg->ds_addr) & (TSEC_RXBUFFER_ALIGNMENT-1)) == 0, 77767196661SRafal Jaworowski ("Wrong alignment of RX buffer!")); 77867196661SRafal Jaworowski #endif 77967196661SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD); 78067196661SRafal Jaworowski 78167196661SRafal Jaworowski (*mbufp) = new_mbuf; 78267196661SRafal Jaworowski (*paddr) = seg->ds_addr; 78367196661SRafal Jaworowski return (0); 78467196661SRafal Jaworowski } 78567196661SRafal Jaworowski 78667196661SRafal Jaworowski static void 78767196661SRafal Jaworowski tsec_map_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 78867196661SRafal Jaworowski { 78967196661SRafal Jaworowski u_int32_t *paddr; 79067196661SRafal Jaworowski 79167196661SRafal Jaworowski KASSERT(nseg == 1, ("wrong number of segments, should be 1")); 79267196661SRafal Jaworowski paddr = arg; 79367196661SRafal Jaworowski *paddr = segs->ds_addr; 79467196661SRafal Jaworowski } 79567196661SRafal Jaworowski 79667196661SRafal Jaworowski static int 79767196661SRafal Jaworowski tsec_alloc_dma_desc(device_t dev, bus_dma_tag_t *dtag, bus_dmamap_t *dmap, 79867196661SRafal Jaworowski bus_size_t dsize, void **vaddr, void *raddr, const char *dname) 79967196661SRafal Jaworowski { 80067196661SRafal Jaworowski int error; 80167196661SRafal Jaworowski 80267196661SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ 80367196661SRafal Jaworowski error = bus_dma_tag_create(NULL, /* parent */ 80467196661SRafal Jaworowski PAGE_SIZE, 0, /* alignment, boundary */ 80567196661SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 80667196661SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 80767196661SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 80867196661SRafal Jaworowski dsize, 1, /* maxsize, nsegments */ 80967196661SRafal Jaworowski dsize, 0, /* maxsegsz, flags */ 81067196661SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 81167196661SRafal Jaworowski dtag); /* dmat */ 81267196661SRafal Jaworowski 81367196661SRafal Jaworowski if (error) { 81467196661SRafal Jaworowski device_printf(dev, "failed to allocate busdma %s tag\n", dname); 81567196661SRafal Jaworowski (*vaddr) = NULL; 81667196661SRafal Jaworowski return (ENXIO); 81767196661SRafal Jaworowski } 81867196661SRafal Jaworowski 81967196661SRafal Jaworowski error = bus_dmamem_alloc(*dtag, vaddr, BUS_DMA_NOWAIT | BUS_DMA_ZERO, 82067196661SRafal Jaworowski dmap); 82167196661SRafal Jaworowski if (error) { 82267196661SRafal Jaworowski device_printf(dev, "failed to allocate %s DMA safe memory\n", 82367196661SRafal Jaworowski dname); 82467196661SRafal Jaworowski bus_dma_tag_destroy(*dtag); 82567196661SRafal Jaworowski (*vaddr) = NULL; 82667196661SRafal Jaworowski return (ENXIO); 82767196661SRafal Jaworowski } 82867196661SRafal Jaworowski 82967196661SRafal Jaworowski error = bus_dmamap_load(*dtag, *dmap, *vaddr, dsize, tsec_map_dma_addr, 83067196661SRafal Jaworowski raddr, BUS_DMA_NOWAIT); 83167196661SRafal Jaworowski if (error) { 83267196661SRafal Jaworowski device_printf(dev, "cannot get address of the %s descriptors\n", 83367196661SRafal Jaworowski dname); 83467196661SRafal Jaworowski bus_dmamem_free(*dtag, *vaddr, *dmap); 83567196661SRafal Jaworowski bus_dma_tag_destroy(*dtag); 83667196661SRafal Jaworowski (*vaddr) = NULL; 83767196661SRafal Jaworowski return (ENXIO); 83867196661SRafal Jaworowski } 83967196661SRafal Jaworowski 84067196661SRafal Jaworowski return (0); 84167196661SRafal Jaworowski } 84267196661SRafal Jaworowski 84367196661SRafal Jaworowski static void 84467196661SRafal Jaworowski tsec_free_dma_desc(bus_dma_tag_t dtag, bus_dmamap_t dmap, void *vaddr) 84567196661SRafal Jaworowski { 84667196661SRafal Jaworowski 84767196661SRafal Jaworowski if (vaddr == NULL) 84867196661SRafal Jaworowski return; 84967196661SRafal Jaworowski 85067196661SRafal Jaworowski /* Unmap descriptors from DMA memory */ 85167196661SRafal Jaworowski bus_dmamap_sync(dtag, dmap, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 85267196661SRafal Jaworowski bus_dmamap_unload(dtag, dmap); 85367196661SRafal Jaworowski 85467196661SRafal Jaworowski /* Free descriptors memory */ 85567196661SRafal Jaworowski bus_dmamem_free(dtag, vaddr, dmap); 85667196661SRafal Jaworowski 85767196661SRafal Jaworowski /* Destroy descriptors tag */ 85867196661SRafal Jaworowski bus_dma_tag_destroy(dtag); 85967196661SRafal Jaworowski } 86067196661SRafal Jaworowski 86167196661SRafal Jaworowski static int 86267196661SRafal Jaworowski tsec_probe(device_t dev) 86367196661SRafal Jaworowski { 86467196661SRafal Jaworowski struct tsec_softc *sc; 86567196661SRafal Jaworowski device_t parent; 86667196661SRafal Jaworowski uintptr_t devtype; 86767196661SRafal Jaworowski int error; 86867196661SRafal Jaworowski uint32_t id; 86967196661SRafal Jaworowski 87067196661SRafal Jaworowski parent = device_get_parent(dev); 87167196661SRafal Jaworowski 87267196661SRafal Jaworowski error = BUS_READ_IVAR(parent, dev, OCPBUS_IVAR_DEVTYPE, &devtype); 87367196661SRafal Jaworowski if (error) 87467196661SRafal Jaworowski return (error); 87567196661SRafal Jaworowski if (devtype != OCPBUS_DEVTYPE_TSEC) 87667196661SRafal Jaworowski return (ENXIO); 87767196661SRafal Jaworowski 87867196661SRafal Jaworowski sc = device_get_softc(dev); 87967196661SRafal Jaworowski 88067196661SRafal Jaworowski sc->sc_rrid = 0; 88167196661SRafal Jaworowski sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid, 88267196661SRafal Jaworowski 0ul, ~0ul, TSEC_IO_SIZE, RF_ACTIVE); 88367196661SRafal Jaworowski if (sc->sc_rres == NULL) 88467196661SRafal Jaworowski return (ENXIO); 88567196661SRafal Jaworowski 88667196661SRafal Jaworowski sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); 88767196661SRafal Jaworowski sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); 88867196661SRafal Jaworowski 88967196661SRafal Jaworowski /* Check that we actually have a TSEC at this address */ 89067196661SRafal Jaworowski id = TSEC_READ(sc, TSEC_REG_ID) | TSEC_READ(sc, TSEC_REG_ID2); 89167196661SRafal Jaworowski 89267196661SRafal Jaworowski bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres); 89367196661SRafal Jaworowski 89467196661SRafal Jaworowski if (id == 0) 89567196661SRafal Jaworowski return (ENXIO); 89667196661SRafal Jaworowski 89767196661SRafal Jaworowski device_set_desc(dev, "Three-Speed Ethernet Controller"); 89867196661SRafal Jaworowski return (BUS_PROBE_DEFAULT); 89967196661SRafal Jaworowski } 90067196661SRafal Jaworowski 90167196661SRafal Jaworowski static int 90267196661SRafal Jaworowski tsec_attach(device_t dev) 90367196661SRafal Jaworowski { 90467196661SRafal Jaworowski uint8_t hwaddr[ETHER_ADDR_LEN]; 90567196661SRafal Jaworowski struct tsec_softc *sc; 90667196661SRafal Jaworowski struct ifnet *ifp; 90767196661SRafal Jaworowski bus_dmamap_t *map_ptr; 90867196661SRafal Jaworowski bus_dmamap_t **map_pptr; 90967196661SRafal Jaworowski int error = 0; 91067196661SRafal Jaworowski int i; 91167196661SRafal Jaworowski 91267196661SRafal Jaworowski sc = device_get_softc(dev); 91367196661SRafal Jaworowski sc->dev = dev; 91467196661SRafal Jaworowski 91567196661SRafal Jaworowski if (device_get_unit(dev) == 0) 91667196661SRafal Jaworowski tsec0_sc = sc; /* XXX */ 91767196661SRafal Jaworowski 9185432bd9fSRafal Jaworowski callout_init(&sc->tsec_callout, 1); 91967196661SRafal Jaworowski mtx_init(&sc->transmit_lock, device_get_nameunit(dev), "TSEC TX lock", 92067196661SRafal Jaworowski MTX_DEF); 92167196661SRafal Jaworowski mtx_init(&sc->receive_lock, device_get_nameunit(dev), "TSEC RX lock", 92267196661SRafal Jaworowski MTX_DEF); 92367196661SRafal Jaworowski 92467196661SRafal Jaworowski /* Reset all TSEC counters */ 92567196661SRafal Jaworowski TSEC_TX_RX_COUNTERS_INIT(sc); 92667196661SRafal Jaworowski 92767196661SRafal Jaworowski /* Allocate IO memory for TSEC registers */ 92867196661SRafal Jaworowski sc->sc_rrid = 0; 92967196661SRafal Jaworowski sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rrid, 93067196661SRafal Jaworowski 0ul, ~0ul, TSEC_IO_SIZE, RF_ACTIVE); 93167196661SRafal Jaworowski if (sc->sc_rres == NULL) { 93267196661SRafal Jaworowski device_printf(dev, "could not allocate IO memory range!\n"); 93367196661SRafal Jaworowski tsec_detach(dev); 93467196661SRafal Jaworowski return (ENXIO); 93567196661SRafal Jaworowski } 93667196661SRafal Jaworowski sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres); 93767196661SRafal Jaworowski sc->sc_bas.bst = rman_get_bustag(sc->sc_rres); 93867196661SRafal Jaworowski 93967196661SRafal Jaworowski /* Stop DMA engine if enabled by firmware */ 94067196661SRafal Jaworowski tsec_dma_ctl(sc, 0); 94167196661SRafal Jaworowski 94267196661SRafal Jaworowski /* Reset MAC */ 94367196661SRafal Jaworowski tsec_reset_mac(sc); 94467196661SRafal Jaworowski 94567196661SRafal Jaworowski /* Disable interrupts for now */ 94667196661SRafal Jaworowski tsec_intrs_ctl(sc, 0); 94767196661SRafal Jaworowski 94867196661SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for TX descriptors. */ 94967196661SRafal Jaworowski error = tsec_alloc_dma_desc(dev, &sc->tsec_tx_dtag, &sc->tsec_tx_dmap, 95067196661SRafal Jaworowski sizeof(*sc->tsec_tx_vaddr) * TSEC_TX_NUM_DESC, 95167196661SRafal Jaworowski (void **)&sc->tsec_tx_vaddr, &sc->tsec_tx_raddr, "TX"); 95267196661SRafal Jaworowski if (error) { 95367196661SRafal Jaworowski tsec_detach(dev); 95467196661SRafal Jaworowski return (ENXIO); 95567196661SRafal Jaworowski } 95667196661SRafal Jaworowski 95767196661SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for RX descriptors. */ 95867196661SRafal Jaworowski error = tsec_alloc_dma_desc(dev, &sc->tsec_rx_dtag, &sc->tsec_rx_dmap, 95967196661SRafal Jaworowski sizeof(*sc->tsec_rx_vaddr) * TSEC_RX_NUM_DESC, 96067196661SRafal Jaworowski (void **)&sc->tsec_rx_vaddr, &sc->tsec_rx_raddr, "RX"); 96167196661SRafal Jaworowski if (error) { 96267196661SRafal Jaworowski tsec_detach(dev); 96367196661SRafal Jaworowski return (ENXIO); 96467196661SRafal Jaworowski } 96567196661SRafal Jaworowski 96667196661SRafal Jaworowski /* Allocate a busdma tag for TX mbufs. */ 96767196661SRafal Jaworowski error = bus_dma_tag_create(NULL, /* parent */ 96867196661SRafal Jaworowski TSEC_TXBUFFER_ALIGNMENT, 0, /* alignment, boundary */ 96967196661SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 97067196661SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 97167196661SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 97267196661SRafal Jaworowski MCLBYTES * (TSEC_TX_NUM_DESC - 1), /* maxsize */ 97367196661SRafal Jaworowski TSEC_TX_NUM_DESC - 1, /* nsegments */ 97467196661SRafal Jaworowski MCLBYTES, 0, /* maxsegsz, flags */ 97567196661SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 97667196661SRafal Jaworowski &sc->tsec_tx_mtag); /* dmat */ 97767196661SRafal Jaworowski if (error) { 97867196661SRafal Jaworowski device_printf(dev, "failed to allocate busdma tag(tx mbufs)\n"); 97967196661SRafal Jaworowski tsec_detach(dev); 98067196661SRafal Jaworowski return (ENXIO); 98167196661SRafal Jaworowski } 98267196661SRafal Jaworowski 98367196661SRafal Jaworowski /* Allocate a busdma tag for RX mbufs. */ 98467196661SRafal Jaworowski error = bus_dma_tag_create(NULL, /* parent */ 98567196661SRafal Jaworowski TSEC_RXBUFFER_ALIGNMENT, 0, /* alignment, boundary */ 98667196661SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 98767196661SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 98867196661SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 98967196661SRafal Jaworowski MCLBYTES, /* maxsize */ 99067196661SRafal Jaworowski 1, /* nsegments */ 99167196661SRafal Jaworowski MCLBYTES, 0, /* maxsegsz, flags */ 99267196661SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 99367196661SRafal Jaworowski &sc->tsec_rx_mtag); /* dmat */ 99467196661SRafal Jaworowski if (error) { 99567196661SRafal Jaworowski device_printf(dev, "failed to allocate busdma tag(rx mbufs)\n"); 99667196661SRafal Jaworowski tsec_detach(dev); 99767196661SRafal Jaworowski return (ENXIO); 99867196661SRafal Jaworowski } 99967196661SRafal Jaworowski 100067196661SRafal Jaworowski /* Create TX busdma maps */ 100167196661SRafal Jaworowski map_ptr = sc->tx_map_data; 100267196661SRafal Jaworowski map_pptr = sc->tx_map_unused_data; 100367196661SRafal Jaworowski 100467196661SRafal Jaworowski for (i = 0; i < TSEC_TX_NUM_DESC; i++) { 100567196661SRafal Jaworowski map_pptr[i] = &map_ptr[i]; 100667196661SRafal Jaworowski error = bus_dmamap_create(sc->tsec_tx_mtag, 0, 100767196661SRafal Jaworowski map_pptr[i]); 100867196661SRafal Jaworowski if (error) { 100967196661SRafal Jaworowski device_printf(dev, "failed to init TX ring\n"); 101067196661SRafal Jaworowski tsec_detach(dev); 101167196661SRafal Jaworowski return (ENXIO); 101267196661SRafal Jaworowski } 101367196661SRafal Jaworowski } 101467196661SRafal Jaworowski 101567196661SRafal Jaworowski /* Create RX busdma maps and zero mbuf handlers */ 101667196661SRafal Jaworowski for (i = 0; i < TSEC_RX_NUM_DESC; i++) { 101767196661SRafal Jaworowski error = bus_dmamap_create(sc->tsec_rx_mtag, 0, 101867196661SRafal Jaworowski &sc->rx_data[i].map); 101967196661SRafal Jaworowski if (error) { 102067196661SRafal Jaworowski device_printf(dev, "failed to init RX ring\n"); 102167196661SRafal Jaworowski tsec_detach(dev); 102267196661SRafal Jaworowski return (ENXIO); 102367196661SRafal Jaworowski } 102467196661SRafal Jaworowski sc->rx_data[i].mbuf = NULL; 102567196661SRafal Jaworowski } 102667196661SRafal Jaworowski 102767196661SRafal Jaworowski /* Create mbufs for RX buffers */ 102867196661SRafal Jaworowski for (i = 0; i < TSEC_RX_NUM_DESC; i++) { 102967196661SRafal Jaworowski error = tsec_new_rxbuf(sc->tsec_rx_mtag, sc->rx_data[i].map, 103067196661SRafal Jaworowski &sc->rx_data[i].mbuf, &sc->rx_data[i].paddr); 103167196661SRafal Jaworowski if (error) { 103267196661SRafal Jaworowski device_printf(dev, "can't load rx DMA map %d, error = " 103367196661SRafal Jaworowski "%d\n", i, error); 103467196661SRafal Jaworowski tsec_detach(dev); 103567196661SRafal Jaworowski return (error); 103667196661SRafal Jaworowski } 103767196661SRafal Jaworowski } 103867196661SRafal Jaworowski 103967196661SRafal Jaworowski /* Create network interface for upper layers */ 104067196661SRafal Jaworowski ifp = sc->tsec_ifp = if_alloc(IFT_ETHER); 104167196661SRafal Jaworowski if (ifp == NULL) { 104267196661SRafal Jaworowski device_printf(dev, "if_alloc() failed\n"); 104367196661SRafal Jaworowski tsec_detach(dev); 104467196661SRafal Jaworowski return (ENOMEM); 104567196661SRafal Jaworowski } 104667196661SRafal Jaworowski 104767196661SRafal Jaworowski ifp->if_softc = sc; 104867196661SRafal Jaworowski if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 104967196661SRafal Jaworowski ifp->if_mtu = ETHERMTU; 105067196661SRafal Jaworowski ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST; 105167196661SRafal Jaworowski ifp->if_init = tsec_init; 105267196661SRafal Jaworowski ifp->if_start = tsec_start; 105367196661SRafal Jaworowski ifp->if_ioctl = tsec_ioctl; 105467196661SRafal Jaworowski 105567196661SRafal Jaworowski IFQ_SET_MAXLEN(&ifp->if_snd, TSEC_TX_NUM_DESC - 1); 105667196661SRafal Jaworowski ifp->if_snd.ifq_drv_maxlen = TSEC_TX_NUM_DESC - 1; 105767196661SRafal Jaworowski IFQ_SET_READY(&ifp->if_snd); 105867196661SRafal Jaworowski 105967196661SRafal Jaworowski /* XXX No special features of TSEC are supported currently */ 106067196661SRafal Jaworowski ifp->if_capabilities = 0; 106167196661SRafal Jaworowski ifp->if_capenable = ifp->if_capabilities; 106267196661SRafal Jaworowski 106367196661SRafal Jaworowski /* Probe PHY(s) */ 106467196661SRafal Jaworowski error = mii_phy_probe(dev, &sc->tsec_miibus, tsec_ifmedia_upd, 106567196661SRafal Jaworowski tsec_ifmedia_sts); 106667196661SRafal Jaworowski if (error) { 106767196661SRafal Jaworowski device_printf(dev, "MII failed to find PHY!\n"); 106867196661SRafal Jaworowski if_free(ifp); 106967196661SRafal Jaworowski sc->tsec_ifp = NULL; 107067196661SRafal Jaworowski tsec_detach(dev); 107167196661SRafal Jaworowski return (error); 107267196661SRafal Jaworowski } 107367196661SRafal Jaworowski sc->tsec_mii = device_get_softc(sc->tsec_miibus); 107467196661SRafal Jaworowski 107567196661SRafal Jaworowski tsec_get_hwaddr(sc, hwaddr); 107667196661SRafal Jaworowski ether_ifattach(ifp, hwaddr); 107767196661SRafal Jaworowski 107867196661SRafal Jaworowski /* Interrupts configuration (TX/RX/ERR) */ 107967196661SRafal Jaworowski sc->sc_transmit_irid = OCP_TSEC_RID_TXIRQ; 108067196661SRafal Jaworowski error = tsec_setup_intr(dev, &sc->sc_transmit_ires, 108167196661SRafal Jaworowski &sc->sc_transmit_ihand, &sc->sc_transmit_irid, 108267196661SRafal Jaworowski tsec_transmit_intr, "TX"); 108367196661SRafal Jaworowski if (error) { 108467196661SRafal Jaworowski tsec_detach(dev); 108567196661SRafal Jaworowski return (error); 108667196661SRafal Jaworowski } 108767196661SRafal Jaworowski 108867196661SRafal Jaworowski sc->sc_receive_irid = OCP_TSEC_RID_RXIRQ; 108967196661SRafal Jaworowski error = tsec_setup_intr(dev, &sc->sc_receive_ires, 109067196661SRafal Jaworowski &sc->sc_receive_ihand, &sc->sc_receive_irid, 109167196661SRafal Jaworowski tsec_receive_intr, "RX"); 109267196661SRafal Jaworowski if (error) { 109367196661SRafal Jaworowski tsec_detach(dev); 109467196661SRafal Jaworowski return (error); 109567196661SRafal Jaworowski } 109667196661SRafal Jaworowski 109767196661SRafal Jaworowski sc->sc_error_irid = OCP_TSEC_RID_ERRIRQ; 109867196661SRafal Jaworowski error = tsec_setup_intr(dev, &sc->sc_error_ires, 109967196661SRafal Jaworowski &sc->sc_error_ihand, &sc->sc_error_irid, 110067196661SRafal Jaworowski tsec_error_intr, "ERR"); 110167196661SRafal Jaworowski if (error) { 110267196661SRafal Jaworowski tsec_detach(dev); 110367196661SRafal Jaworowski return (error); 110467196661SRafal Jaworowski } 110567196661SRafal Jaworowski 110667196661SRafal Jaworowski return (0); 110767196661SRafal Jaworowski } 110867196661SRafal Jaworowski 110967196661SRafal Jaworowski static int 111067196661SRafal Jaworowski tsec_setup_intr(device_t dev, struct resource **ires, void **ihand, int *irid, 111167196661SRafal Jaworowski driver_intr_t handler, const char *iname) 111267196661SRafal Jaworowski { 111367196661SRafal Jaworowski struct tsec_softc *sc; 111467196661SRafal Jaworowski int error; 111567196661SRafal Jaworowski 111667196661SRafal Jaworowski sc = device_get_softc(dev); 111767196661SRafal Jaworowski 111867196661SRafal Jaworowski (*ires) = bus_alloc_resource_any(dev, SYS_RES_IRQ, irid, RF_ACTIVE); 111967196661SRafal Jaworowski if ((*ires) == NULL) { 112067196661SRafal Jaworowski device_printf(dev, "could not allocate %s IRQ\n", iname); 112167196661SRafal Jaworowski return (ENXIO); 112267196661SRafal Jaworowski } 112367196661SRafal Jaworowski error = bus_setup_intr(dev, *ires, INTR_TYPE_NET | INTR_MPSAFE, 112467196661SRafal Jaworowski NULL, handler, sc, ihand); 112567196661SRafal Jaworowski if (error) { 112667196661SRafal Jaworowski device_printf(dev, "failed to set up %s IRQ\n", iname); 112767196661SRafal Jaworowski if (bus_release_resource(dev, SYS_RES_IRQ, *irid, *ires)) 112867196661SRafal Jaworowski device_printf(dev, "could not release %s IRQ\n", iname); 112967196661SRafal Jaworowski (*ires) = NULL; 113067196661SRafal Jaworowski return (error); 113167196661SRafal Jaworowski } 113267196661SRafal Jaworowski return (0); 113367196661SRafal Jaworowski } 113467196661SRafal Jaworowski 113567196661SRafal Jaworowski static void 113667196661SRafal Jaworowski tsec_release_intr(device_t dev, struct resource *ires, void *ihand, int irid, 113767196661SRafal Jaworowski const char *iname) 113867196661SRafal Jaworowski { 113967196661SRafal Jaworowski int error; 114067196661SRafal Jaworowski 114167196661SRafal Jaworowski if (ires == NULL) 114267196661SRafal Jaworowski return; 114367196661SRafal Jaworowski 114467196661SRafal Jaworowski error = bus_teardown_intr(dev, ires, ihand); 114567196661SRafal Jaworowski if (error) 114667196661SRafal Jaworowski device_printf(dev, "bus_teardown_intr() failed for %s intr" 114767196661SRafal Jaworowski ", error %d\n", iname, error); 114867196661SRafal Jaworowski 114967196661SRafal Jaworowski error = bus_release_resource(dev, SYS_RES_IRQ, irid, ires); 115067196661SRafal Jaworowski if (error) 115167196661SRafal Jaworowski device_printf(dev, "bus_release_resource() failed for %s intr" 115267196661SRafal Jaworowski ", error %d\n", iname, error); 115367196661SRafal Jaworowski } 115467196661SRafal Jaworowski 115567196661SRafal Jaworowski static void 115667196661SRafal Jaworowski tsec_free_dma(struct tsec_softc *sc) 115767196661SRafal Jaworowski { 115867196661SRafal Jaworowski int i; 115967196661SRafal Jaworowski 116067196661SRafal Jaworowski /* Free TX maps */ 116167196661SRafal Jaworowski for (i = 0; i < TSEC_TX_NUM_DESC; i++) 116267196661SRafal Jaworowski if (sc->tx_map_data[i] != NULL) 116367196661SRafal Jaworowski bus_dmamap_destroy(sc->tsec_tx_mtag, 116467196661SRafal Jaworowski sc->tx_map_data[i]); 116567196661SRafal Jaworowski /* Destroy tag for Tx mbufs */ 116667196661SRafal Jaworowski bus_dma_tag_destroy(sc->tsec_tx_mtag); 116767196661SRafal Jaworowski 116867196661SRafal Jaworowski /* Free RX mbufs and maps */ 116967196661SRafal Jaworowski for (i = 0; i < TSEC_RX_NUM_DESC; i++) { 117067196661SRafal Jaworowski if (sc->rx_data[i].mbuf) { 117167196661SRafal Jaworowski /* Unload buffer from DMA */ 117267196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_rx_mtag, sc->rx_data[i].map, 117367196661SRafal Jaworowski BUS_DMASYNC_POSTREAD); 117467196661SRafal Jaworowski bus_dmamap_unload(sc->tsec_rx_mtag, sc->rx_data[i].map); 117567196661SRafal Jaworowski 117667196661SRafal Jaworowski /* Free buffer */ 117767196661SRafal Jaworowski m_freem(sc->rx_data[i].mbuf); 117867196661SRafal Jaworowski } 117967196661SRafal Jaworowski /* Destroy map for this buffer */ 118067196661SRafal Jaworowski if (sc->rx_data[i].map != NULL) 118167196661SRafal Jaworowski bus_dmamap_destroy(sc->tsec_rx_mtag, 118267196661SRafal Jaworowski sc->rx_data[i].map); 118367196661SRafal Jaworowski } 118467196661SRafal Jaworowski /* Destroy tag for Rx mbufs */ 118567196661SRafal Jaworowski bus_dma_tag_destroy(sc->tsec_rx_mtag); 118667196661SRafal Jaworowski 118767196661SRafal Jaworowski /* Unload TX/RX descriptors */ 118867196661SRafal Jaworowski tsec_free_dma_desc(sc->tsec_tx_dtag, sc->tsec_tx_dmap, 118967196661SRafal Jaworowski sc->tsec_tx_vaddr); 119067196661SRafal Jaworowski tsec_free_dma_desc(sc->tsec_rx_dtag, sc->tsec_rx_dmap, 119167196661SRafal Jaworowski sc->tsec_rx_vaddr); 119267196661SRafal Jaworowski } 119367196661SRafal Jaworowski 119467196661SRafal Jaworowski static int 119567196661SRafal Jaworowski tsec_detach(device_t dev) 119667196661SRafal Jaworowski { 119767196661SRafal Jaworowski struct tsec_softc *sc; 119867196661SRafal Jaworowski int error; 119967196661SRafal Jaworowski 120067196661SRafal Jaworowski sc = device_get_softc(dev); 120167196661SRafal Jaworowski 120267196661SRafal Jaworowski /* Stop TSEC controller and free TX queue */ 120367196661SRafal Jaworowski if (sc->sc_rres && sc->tsec_ifp) 120467196661SRafal Jaworowski tsec_shutdown(dev); 120567196661SRafal Jaworowski 120667196661SRafal Jaworowski /* Wait for stopping TSEC ticks */ 12075432bd9fSRafal Jaworowski callout_drain(&sc->tsec_callout); 120867196661SRafal Jaworowski 120967196661SRafal Jaworowski /* Stop and release all interrupts */ 121067196661SRafal Jaworowski tsec_release_intr(dev, sc->sc_transmit_ires, sc->sc_transmit_ihand, 121167196661SRafal Jaworowski sc->sc_transmit_irid, "TX"); 121267196661SRafal Jaworowski tsec_release_intr(dev, sc->sc_receive_ires, sc->sc_receive_ihand, 121367196661SRafal Jaworowski sc->sc_receive_irid, "RX"); 121467196661SRafal Jaworowski tsec_release_intr(dev, sc->sc_error_ires, sc->sc_error_ihand, 121567196661SRafal Jaworowski sc->sc_error_irid, "ERR"); 121667196661SRafal Jaworowski 121767196661SRafal Jaworowski /* Detach network interface */ 121867196661SRafal Jaworowski if (sc->tsec_ifp) { 121967196661SRafal Jaworowski ether_ifdetach(sc->tsec_ifp); 122067196661SRafal Jaworowski if_free(sc->tsec_ifp); 122167196661SRafal Jaworowski sc->tsec_ifp = NULL; 122267196661SRafal Jaworowski } 122367196661SRafal Jaworowski 122467196661SRafal Jaworowski /* Free DMA resources */ 122567196661SRafal Jaworowski tsec_free_dma(sc); 122667196661SRafal Jaworowski 122767196661SRafal Jaworowski /* Free IO memory handler */ 122867196661SRafal Jaworowski if (sc->sc_rres) { 122967196661SRafal Jaworowski error = bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, 123067196661SRafal Jaworowski sc->sc_rres); 123167196661SRafal Jaworowski if (error) 123267196661SRafal Jaworowski device_printf(dev, "bus_release_resource() failed for" 123367196661SRafal Jaworowski " IO memory, error %d\n", error); 123467196661SRafal Jaworowski } 123567196661SRafal Jaworowski 123667196661SRafal Jaworowski /* Destroy locks */ 123767196661SRafal Jaworowski mtx_destroy(&sc->receive_lock); 123867196661SRafal Jaworowski mtx_destroy(&sc->transmit_lock); 123967196661SRafal Jaworowski return (0); 124067196661SRafal Jaworowski } 124167196661SRafal Jaworowski 124267196661SRafal Jaworowski static void 124367196661SRafal Jaworowski tsec_shutdown(device_t dev) 124467196661SRafal Jaworowski { 124567196661SRafal Jaworowski struct tsec_softc *sc; 124667196661SRafal Jaworowski 124767196661SRafal Jaworowski sc = device_get_softc(dev); 124867196661SRafal Jaworowski 124967196661SRafal Jaworowski TSEC_GLOBAL_LOCK(sc); 125067196661SRafal Jaworowski tsec_stop(sc); 125167196661SRafal Jaworowski TSEC_GLOBAL_UNLOCK(sc); 125267196661SRafal Jaworowski } 125367196661SRafal Jaworowski 125467196661SRafal Jaworowski static int 125567196661SRafal Jaworowski tsec_suspend(device_t dev) 125667196661SRafal Jaworowski { 125767196661SRafal Jaworowski 125867196661SRafal Jaworowski /* TODO not implemented! */ 125967196661SRafal Jaworowski return (ENODEV); 126067196661SRafal Jaworowski } 126167196661SRafal Jaworowski 126267196661SRafal Jaworowski static int 126367196661SRafal Jaworowski tsec_resume(device_t dev) 126467196661SRafal Jaworowski { 126567196661SRafal Jaworowski 126667196661SRafal Jaworowski /* TODO not implemented! */ 126767196661SRafal Jaworowski return (ENODEV); 126867196661SRafal Jaworowski } 126967196661SRafal Jaworowski 127067196661SRafal Jaworowski static void 127167196661SRafal Jaworowski tsec_stop(struct tsec_softc *sc) 127267196661SRafal Jaworowski { 127367196661SRafal Jaworowski struct ifnet *ifp; 127467196661SRafal Jaworowski struct mbuf *m0; 127567196661SRafal Jaworowski bus_dmamap_t *mapp; 127667196661SRafal Jaworowski uint32_t tmpval; 127767196661SRafal Jaworowski 127867196661SRafal Jaworowski TSEC_GLOBAL_LOCK_ASSERT(sc); 127967196661SRafal Jaworowski 128067196661SRafal Jaworowski ifp = sc->tsec_ifp; 128167196661SRafal Jaworowski 12825432bd9fSRafal Jaworowski /* Stop tick engine */ 12835432bd9fSRafal Jaworowski callout_stop(&sc->tsec_callout); 128467196661SRafal Jaworowski 128567196661SRafal Jaworowski /* Disable interface and watchdog timer */ 128667196661SRafal Jaworowski ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 12875432bd9fSRafal Jaworowski sc->tsec_watchdog = 0; 128867196661SRafal Jaworowski 128967196661SRafal Jaworowski /* Disable all interrupts and stop DMA */ 129067196661SRafal Jaworowski tsec_intrs_ctl(sc, 0); 129167196661SRafal Jaworowski tsec_dma_ctl(sc, 0); 129267196661SRafal Jaworowski 129367196661SRafal Jaworowski /* Remove pending data from TX queue */ 129467196661SRafal Jaworowski while (!TSEC_EMPTYQ_TX_MBUF(sc)) { 129567196661SRafal Jaworowski m0 = TSEC_GET_TX_MBUF(sc); 129667196661SRafal Jaworowski mapp = TSEC_GET_TX_MAP(sc); 129767196661SRafal Jaworowski 129867196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_mtag, *mapp, BUS_DMASYNC_POSTWRITE); 129967196661SRafal Jaworowski bus_dmamap_unload(sc->tsec_tx_mtag, *mapp); 130067196661SRafal Jaworowski 130167196661SRafal Jaworowski TSEC_FREE_TX_MAP(sc, mapp); 130267196661SRafal Jaworowski m_freem(m0); 130367196661SRafal Jaworowski } 130467196661SRafal Jaworowski 130567196661SRafal Jaworowski /* Disable Rx and Tx */ 130667196661SRafal Jaworowski tmpval = TSEC_READ(sc, TSEC_REG_MACCFG1); 130767196661SRafal Jaworowski tmpval &= ~(TSEC_MACCFG1_RX_EN | TSEC_MACCFG1_TX_EN); 130867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG1, tmpval); 130967196661SRafal Jaworowski DELAY(10); 131067196661SRafal Jaworowski } 131167196661SRafal Jaworowski 131267196661SRafal Jaworowski static void 131367196661SRafal Jaworowski tsec_receive_intr(void *arg) 131467196661SRafal Jaworowski { 131567196661SRafal Jaworowski struct mbuf *rcv_mbufs[TSEC_RX_NUM_DESC]; 131667196661SRafal Jaworowski struct tsec_softc *sc = arg; 131767196661SRafal Jaworowski struct tsec_desc *rx_desc; 131867196661SRafal Jaworowski struct ifnet *ifp; 131967196661SRafal Jaworowski struct rx_data_type *rx_data; 132067196661SRafal Jaworowski struct mbuf *m; 132167196661SRafal Jaworowski device_t dev; 132267196661SRafal Jaworowski uint32_t i; 132367196661SRafal Jaworowski int count; 132467196661SRafal Jaworowski int c1 = 0; 132567196661SRafal Jaworowski int c2; 132667196661SRafal Jaworowski uint16_t flags; 132767196661SRafal Jaworowski uint16_t length; 132867196661SRafal Jaworowski 132967196661SRafal Jaworowski ifp = sc->tsec_ifp; 133067196661SRafal Jaworowski rx_data = sc->rx_data; 133167196661SRafal Jaworowski dev = sc->dev; 133267196661SRafal Jaworowski 133367196661SRafal Jaworowski /* Confirm the interrupt was received by driver */ 133467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, TSEC_IEVENT_RXB | TSEC_IEVENT_RXF); 133567196661SRafal Jaworowski 133667196661SRafal Jaworowski TSEC_RECEIVE_LOCK(sc); 133767196661SRafal Jaworowski 133867196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_rx_dtag, sc->tsec_rx_dmap, BUS_DMASYNC_POSTREAD | 133967196661SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 134067196661SRafal Jaworowski 134167196661SRafal Jaworowski for (count = 0; /* count < TSEC_RX_NUM_DESC */; count++) { 134267196661SRafal Jaworowski rx_desc = TSEC_GET_CUR_RX_DESC(sc); 134367196661SRafal Jaworowski flags = rx_desc->flags; 134467196661SRafal Jaworowski 134567196661SRafal Jaworowski /* Check if there is anything to receive */ 134667196661SRafal Jaworowski if ((flags & TSEC_RXBD_E) || (count >= TSEC_RX_NUM_DESC)) { 134767196661SRafal Jaworowski /* 134867196661SRafal Jaworowski * Avoid generating another interrupt 134967196661SRafal Jaworowski */ 135067196661SRafal Jaworowski if (flags & TSEC_RXBD_E) 135167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, 135267196661SRafal Jaworowski TSEC_IEVENT_RXB | TSEC_IEVENT_RXF); 135367196661SRafal Jaworowski /* 135467196661SRafal Jaworowski * We didn't consume current descriptor and have to 135567196661SRafal Jaworowski * return it to the queue 135667196661SRafal Jaworowski */ 135767196661SRafal Jaworowski TSEC_BACK_CUR_RX_DESC(sc); 135867196661SRafal Jaworowski break; 135967196661SRafal Jaworowski } 136067196661SRafal Jaworowski 136167196661SRafal Jaworowski if (flags & (TSEC_RXBD_LG | TSEC_RXBD_SH | TSEC_RXBD_NO | 136267196661SRafal Jaworowski TSEC_RXBD_CR | TSEC_RXBD_OV | TSEC_RXBD_TR)) { 136367196661SRafal Jaworowski rx_desc->length = 0; 136467196661SRafal Jaworowski rx_desc->flags = (rx_desc->flags & 136567196661SRafal Jaworowski ~TSEC_RXBD_ZEROONINIT) | TSEC_RXBD_E | TSEC_RXBD_I; 136667196661SRafal Jaworowski continue; 136767196661SRafal Jaworowski } 136867196661SRafal Jaworowski 136967196661SRafal Jaworowski if ((flags & TSEC_RXBD_L) == 0) 137067196661SRafal Jaworowski device_printf(dev, "buf is not the last in frame!\n"); 137167196661SRafal Jaworowski 137267196661SRafal Jaworowski /* Ok... process frame */ 137367196661SRafal Jaworowski length = rx_desc->length - ETHER_CRC_LEN; 137467196661SRafal Jaworowski i = TSEC_GET_CUR_RX_DESC_CNT(sc); 137567196661SRafal Jaworowski 137667196661SRafal Jaworowski m = rx_data[i].mbuf; 137767196661SRafal Jaworowski 137867196661SRafal Jaworowski if (tsec_new_rxbuf(sc->tsec_rx_mtag, rx_data[i].map, 137967196661SRafal Jaworowski &rx_data[i].mbuf, &rx_data[i].paddr)) { 138067196661SRafal Jaworowski ifp->if_ierrors++; 138167196661SRafal Jaworowski continue; 138267196661SRafal Jaworowski } 138367196661SRafal Jaworowski /* Attach new buffer to descriptor, and clear flags */ 138467196661SRafal Jaworowski rx_desc->bufptr = rx_data[i].paddr; 138567196661SRafal Jaworowski rx_desc->length = 0; 138667196661SRafal Jaworowski rx_desc->flags = (rx_desc->flags & ~TSEC_RXBD_ZEROONINIT) | 138767196661SRafal Jaworowski TSEC_RXBD_E | TSEC_RXBD_I; 138867196661SRafal Jaworowski 138967196661SRafal Jaworowski /* Prepare buffer for upper layers */ 139067196661SRafal Jaworowski m->m_pkthdr.rcvif = ifp; 139167196661SRafal Jaworowski m->m_pkthdr.len = m->m_len = length; 139267196661SRafal Jaworowski 139367196661SRafal Jaworowski /* Save it for push */ 139467196661SRafal Jaworowski rcv_mbufs[c1++] = m; 139567196661SRafal Jaworowski } 139667196661SRafal Jaworowski 139767196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_rx_dtag, sc->tsec_rx_dmap, 139867196661SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 139967196661SRafal Jaworowski 140067196661SRafal Jaworowski TSEC_RECEIVE_UNLOCK(sc); 140167196661SRafal Jaworowski 140267196661SRafal Jaworowski /* Push it now */ 140367196661SRafal Jaworowski for (c2 = 0; c2 < c1; c2++) 140467196661SRafal Jaworowski (*ifp->if_input)(ifp, rcv_mbufs[c2]); 140567196661SRafal Jaworowski } 140667196661SRafal Jaworowski 140767196661SRafal Jaworowski static void 140867196661SRafal Jaworowski tsec_transmit_intr(void *arg) 140967196661SRafal Jaworowski { 141067196661SRafal Jaworowski struct tsec_softc *sc = arg; 141167196661SRafal Jaworowski struct tsec_desc *tx_desc; 141267196661SRafal Jaworowski struct ifnet *ifp; 141367196661SRafal Jaworowski struct mbuf *m0; 141467196661SRafal Jaworowski bus_dmamap_t *mapp; 141567196661SRafal Jaworowski int send = 0; 141667196661SRafal Jaworowski 141767196661SRafal Jaworowski ifp = sc->tsec_ifp; 141867196661SRafal Jaworowski 141967196661SRafal Jaworowski /* Confirm the interrupt was received by driver */ 142067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, TSEC_IEVENT_TXB | TSEC_IEVENT_TXF); 142167196661SRafal Jaworowski 142267196661SRafal Jaworowski TSEC_TRANSMIT_LOCK(sc); 142367196661SRafal Jaworowski 142467196661SRafal Jaworowski /* Update collision statistics */ 142567196661SRafal Jaworowski ifp->if_collisions += TSEC_READ(sc, TSEC_REG_MON_TNCL); 142667196661SRafal Jaworowski 142767196661SRafal Jaworowski /* Reset collision counters in hardware */ 142867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TSCL, 0); 142967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TMCL, 0); 143067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TLCL, 0); 143167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TXCL, 0); 143267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TNCL, 0); 143367196661SRafal Jaworowski 143467196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, BUS_DMASYNC_POSTREAD | 143567196661SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 143667196661SRafal Jaworowski 143767196661SRafal Jaworowski while (TSEC_CUR_DIFF_DIRTY_TX_DESC(sc)) { 143867196661SRafal Jaworowski tx_desc = TSEC_GET_DIRTY_TX_DESC(sc); 143967196661SRafal Jaworowski if (tx_desc->flags & TSEC_TXBD_R) { 144067196661SRafal Jaworowski TSEC_BACK_DIRTY_TX_DESC(sc); 144167196661SRafal Jaworowski break; 144267196661SRafal Jaworowski } 144367196661SRafal Jaworowski 144467196661SRafal Jaworowski if ((tx_desc->flags & TSEC_TXBD_L) == 0) 144567196661SRafal Jaworowski continue; 144667196661SRafal Jaworowski 144767196661SRafal Jaworowski /* 144867196661SRafal Jaworowski * This is the last buf in this packet, so unmap and free it. 144967196661SRafal Jaworowski */ 145067196661SRafal Jaworowski m0 = TSEC_GET_TX_MBUF(sc); 145167196661SRafal Jaworowski mapp = TSEC_GET_TX_MAP(sc); 145267196661SRafal Jaworowski 145367196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_mtag, *mapp, BUS_DMASYNC_POSTWRITE); 145467196661SRafal Jaworowski bus_dmamap_unload(sc->tsec_tx_mtag, *mapp); 145567196661SRafal Jaworowski 145667196661SRafal Jaworowski TSEC_FREE_TX_MAP(sc, mapp); 145767196661SRafal Jaworowski m_freem(m0); 145867196661SRafal Jaworowski 145967196661SRafal Jaworowski ifp->if_opackets++; 146067196661SRafal Jaworowski send = 1; 146167196661SRafal Jaworowski } 146267196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, 146367196661SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 146467196661SRafal Jaworowski 146567196661SRafal Jaworowski if (send) { 146667196661SRafal Jaworowski /* Now send anything that was pending */ 146767196661SRafal Jaworowski ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 146867196661SRafal Jaworowski tsec_start_locked(ifp); 146967196661SRafal Jaworowski 1470772619e1SRafal Jaworowski /* Stop watchdog if all sent */ 147167196661SRafal Jaworowski if (TSEC_EMPTYQ_TX_MBUF(sc)) 14725432bd9fSRafal Jaworowski sc->tsec_watchdog = 0; 147367196661SRafal Jaworowski } 147467196661SRafal Jaworowski TSEC_TRANSMIT_UNLOCK(sc); 147567196661SRafal Jaworowski } 147667196661SRafal Jaworowski 147767196661SRafal Jaworowski static void 147867196661SRafal Jaworowski tsec_error_intr(void *arg) 147967196661SRafal Jaworowski { 148067196661SRafal Jaworowski struct tsec_softc *sc = arg; 148167196661SRafal Jaworowski struct ifnet *ifp; 148267196661SRafal Jaworowski uint32_t eflags; 148367196661SRafal Jaworowski 148467196661SRafal Jaworowski ifp = sc->tsec_ifp; 148567196661SRafal Jaworowski 148667196661SRafal Jaworowski eflags = TSEC_READ(sc, TSEC_REG_IEVENT); 148767196661SRafal Jaworowski 148867196661SRafal Jaworowski if (ifp->if_flags & IFF_DEBUG) 148967196661SRafal Jaworowski if_printf(ifp, "tsec_error_intr(): event flags: 0x%x\n", eflags); 149067196661SRafal Jaworowski 149167196661SRafal Jaworowski /* Clear events bits in hardware */ 149267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, TSEC_IEVENT_RXC | TSEC_IEVENT_BSY | 149367196661SRafal Jaworowski TSEC_IEVENT_EBERR | TSEC_IEVENT_MSRO | TSEC_IEVENT_BABT | 149467196661SRafal Jaworowski TSEC_IEVENT_TXC | TSEC_IEVENT_TXE | TSEC_IEVENT_LC | 149567196661SRafal Jaworowski TSEC_IEVENT_CRL | TSEC_IEVENT_XFUN); 149667196661SRafal Jaworowski 149767196661SRafal Jaworowski if (eflags & TSEC_IEVENT_EBERR) 149867196661SRafal Jaworowski if_printf(ifp, "System bus error occurred during" 149967196661SRafal Jaworowski " a DMA transaction (flags: 0x%x)\n", eflags); 150067196661SRafal Jaworowski 150167196661SRafal Jaworowski /* Check transmitter errors */ 150267196661SRafal Jaworowski if (eflags & TSEC_IEVENT_TXE) { 150367196661SRafal Jaworowski ifp->if_oerrors++; 150467196661SRafal Jaworowski 150567196661SRafal Jaworowski if (eflags & TSEC_IEVENT_LC) 150667196661SRafal Jaworowski ifp->if_collisions++; 150767196661SRafal Jaworowski 150867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TSTAT, TSEC_TSTAT_THLT); 150967196661SRafal Jaworowski } 151067196661SRafal Jaworowski if (eflags & TSEC_IEVENT_BABT) 151167196661SRafal Jaworowski ifp->if_oerrors++; 151267196661SRafal Jaworowski 151367196661SRafal Jaworowski /* Check receiver errors */ 151467196661SRafal Jaworowski if (eflags & TSEC_IEVENT_BSY) { 151567196661SRafal Jaworowski ifp->if_ierrors++; 151667196661SRafal Jaworowski ifp->if_iqdrops++; 151767196661SRafal Jaworowski 151867196661SRafal Jaworowski /* Get data from RX buffers */ 151967196661SRafal Jaworowski tsec_receive_intr(arg); 152067196661SRafal Jaworowski 152167196661SRafal Jaworowski /* Make receiver again active */ 152267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_RSTAT, TSEC_RSTAT_QHLT); 152367196661SRafal Jaworowski } 152467196661SRafal Jaworowski if (eflags & TSEC_IEVENT_BABR) 152567196661SRafal Jaworowski ifp->if_ierrors++; 152667196661SRafal Jaworowski } 152767196661SRafal Jaworowski 152867196661SRafal Jaworowski static void 1529772619e1SRafal Jaworowski tsec_tick(void *xsc) 153067196661SRafal Jaworowski { 1531772619e1SRafal Jaworowski struct tsec_softc *sc = xsc; 153267196661SRafal Jaworowski struct ifnet *ifp; 153367196661SRafal Jaworowski int link; 153467196661SRafal Jaworowski 1535772619e1SRafal Jaworowski TSEC_GLOBAL_LOCK(sc); 1536772619e1SRafal Jaworowski 1537772619e1SRafal Jaworowski tsec_watchdog(sc); 153867196661SRafal Jaworowski 153967196661SRafal Jaworowski ifp = sc->tsec_ifp; 154067196661SRafal Jaworowski link = sc->tsec_link; 154167196661SRafal Jaworowski 154267196661SRafal Jaworowski mii_tick(sc->tsec_mii); 154367196661SRafal Jaworowski 154467196661SRafal Jaworowski if (link == 0 && sc->tsec_link == 1 && (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))) 154567196661SRafal Jaworowski tsec_start_locked(ifp); 154667196661SRafal Jaworowski 1547772619e1SRafal Jaworowski /* Schedule another timeout one second from now. */ 15485432bd9fSRafal Jaworowski callout_reset(&sc->tsec_callout, hz, tsec_tick, sc); 1549772619e1SRafal Jaworowski 1550772619e1SRafal Jaworowski TSEC_GLOBAL_UNLOCK(sc); 155167196661SRafal Jaworowski } 155267196661SRafal Jaworowski 155367196661SRafal Jaworowski static int 155467196661SRafal Jaworowski tsec_miibus_readreg(device_t dev, int phy, int reg) 155567196661SRafal Jaworowski { 155667196661SRafal Jaworowski struct tsec_softc *sc; 155767196661SRafal Jaworowski uint32_t timeout; 155867196661SRafal Jaworowski 155967196661SRafal Jaworowski sc = device_get_softc(dev); 156067196661SRafal Jaworowski 156167196661SRafal Jaworowski if (device_get_unit(dev) != phy) 156267196661SRafal Jaworowski return (0); 156367196661SRafal Jaworowski 156467196661SRafal Jaworowski sc = tsec0_sc; 156567196661SRafal Jaworowski 156667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMADD, (phy << 8) | reg); 156767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMCOM, 0); 156867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMCOM, TSEC_MIIMCOM_READCYCLE); 156967196661SRafal Jaworowski 157067196661SRafal Jaworowski timeout = TSEC_READ_RETRY; 157167196661SRafal Jaworowski while (--timeout && TSEC_READ(sc, TSEC_REG_MIIMIND) & 157267196661SRafal Jaworowski (TSEC_MIIMIND_NOTVALID | TSEC_MIIMIND_BUSY)) 157367196661SRafal Jaworowski DELAY(TSEC_READ_DELAY); 157467196661SRafal Jaworowski 157567196661SRafal Jaworowski if (timeout == 0) 157667196661SRafal Jaworowski device_printf(dev, "Timeout while reading from PHY!\n"); 157767196661SRafal Jaworowski 157867196661SRafal Jaworowski return (TSEC_READ(sc, TSEC_REG_MIIMSTAT)); 157967196661SRafal Jaworowski } 158067196661SRafal Jaworowski 158167196661SRafal Jaworowski static void 158267196661SRafal Jaworowski tsec_miibus_writereg(device_t dev, int phy, int reg, int value) 158367196661SRafal Jaworowski { 158467196661SRafal Jaworowski struct tsec_softc *sc; 158567196661SRafal Jaworowski uint32_t timeout; 158667196661SRafal Jaworowski 158767196661SRafal Jaworowski sc = device_get_softc(dev); 158867196661SRafal Jaworowski 158967196661SRafal Jaworowski if (device_get_unit(dev) != phy) 159067196661SRafal Jaworowski device_printf(dev, "Trying to write to an alien PHY(%d)\n", phy); 159167196661SRafal Jaworowski 159267196661SRafal Jaworowski sc = tsec0_sc; 159367196661SRafal Jaworowski 159467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMADD, (phy << 8) | reg); 159567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMCON, value); 159667196661SRafal Jaworowski 159767196661SRafal Jaworowski timeout = TSEC_READ_RETRY; 159867196661SRafal Jaworowski while (--timeout && (TSEC_READ(sc, TSEC_REG_MIIMIND) & TSEC_MIIMIND_BUSY)) 159967196661SRafal Jaworowski DELAY(TSEC_READ_DELAY); 160067196661SRafal Jaworowski 160167196661SRafal Jaworowski if (timeout == 0) 160267196661SRafal Jaworowski device_printf(dev, "Timeout while writing to PHY!\n"); 160367196661SRafal Jaworowski } 160467196661SRafal Jaworowski 160567196661SRafal Jaworowski static void 160667196661SRafal Jaworowski tsec_miibus_statchg(device_t dev) 160767196661SRafal Jaworowski { 160867196661SRafal Jaworowski struct tsec_softc *sc; 160967196661SRafal Jaworowski struct mii_data *mii; 161067196661SRafal Jaworowski uint32_t ecntrl, id, tmp; 161167196661SRafal Jaworowski int link; 161267196661SRafal Jaworowski 161367196661SRafal Jaworowski sc = device_get_softc(dev); 161467196661SRafal Jaworowski mii = sc->tsec_mii; 161567196661SRafal Jaworowski link = ((mii->mii_media_status & IFM_ACTIVE) ? 1 : 0); 161667196661SRafal Jaworowski 161767196661SRafal Jaworowski tmp = TSEC_READ(sc, TSEC_REG_MACCFG2) & ~TSEC_MACCFG2_IF; 161867196661SRafal Jaworowski 161967196661SRafal Jaworowski if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 162067196661SRafal Jaworowski tmp |= TSEC_MACCFG2_FULLDUPLEX; 162167196661SRafal Jaworowski else 162267196661SRafal Jaworowski tmp &= ~TSEC_MACCFG2_FULLDUPLEX; 162367196661SRafal Jaworowski 162467196661SRafal Jaworowski switch (IFM_SUBTYPE(mii->mii_media_active)) { 162567196661SRafal Jaworowski case IFM_1000_T: 162667196661SRafal Jaworowski case IFM_1000_SX: 162767196661SRafal Jaworowski tmp |= TSEC_MACCFG2_GMII; 162867196661SRafal Jaworowski sc->tsec_link = link; 162967196661SRafal Jaworowski break; 163067196661SRafal Jaworowski case IFM_100_TX: 163167196661SRafal Jaworowski case IFM_10_T: 163267196661SRafal Jaworowski tmp |= TSEC_MACCFG2_MII; 163367196661SRafal Jaworowski sc->tsec_link = link; 163467196661SRafal Jaworowski break; 163567196661SRafal Jaworowski case IFM_NONE: 163667196661SRafal Jaworowski if (link) 163767196661SRafal Jaworowski device_printf(dev, "No speed selected but link active!\n"); 163867196661SRafal Jaworowski sc->tsec_link = 0; 163967196661SRafal Jaworowski return; 164067196661SRafal Jaworowski default: 164167196661SRafal Jaworowski sc->tsec_link = 0; 164267196661SRafal Jaworowski device_printf(dev, "Unknown speed (%d), link %s!\n", 164367196661SRafal Jaworowski IFM_SUBTYPE(mii->mii_media_active), 164467196661SRafal Jaworowski ((link) ? "up" : "down")); 164567196661SRafal Jaworowski return; 164667196661SRafal Jaworowski } 164767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG2, tmp); 164867196661SRafal Jaworowski 164967196661SRafal Jaworowski /* XXX kludge - use circumstantial evidence for reduced mode. */ 165067196661SRafal Jaworowski id = TSEC_READ(sc, TSEC_REG_ID2); 165167196661SRafal Jaworowski if (id & 0xffff) { 165267196661SRafal Jaworowski ecntrl = TSEC_READ(sc, TSEC_REG_ECNTRL) & ~TSEC_ECNTRL_R100M; 165367196661SRafal Jaworowski ecntrl |= (tmp & TSEC_MACCFG2_MII) ? TSEC_ECNTRL_R100M : 0; 165467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_ECNTRL, ecntrl); 165567196661SRafal Jaworowski } 165667196661SRafal Jaworowski } 1657