167196661SRafal Jaworowski /*- 2321e12c8SRafal Jaworowski * Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com> 3321e12c8SRafal Jaworowski * Copyright (C) 2006-2007 Semihalf, Piotr Kruszynski <ppk@semihalf.com> 467196661SRafal Jaworowski * All rights reserved. 567196661SRafal Jaworowski * 667196661SRafal Jaworowski * Redistribution and use in source and binary forms, with or without 767196661SRafal Jaworowski * modification, are permitted provided that the following conditions 867196661SRafal Jaworowski * are met: 967196661SRafal Jaworowski * 1. Redistributions of source code must retain the above copyright 1067196661SRafal Jaworowski * notice, this list of conditions and the following disclaimer. 1167196661SRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright 1267196661SRafal Jaworowski * notice, this list of conditions and the following disclaimer in the 1367196661SRafal Jaworowski * documentation and/or other materials provided with the distribution. 1467196661SRafal Jaworowski * 1567196661SRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1667196661SRafal Jaworowski * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1767196661SRafal Jaworowski * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 1867196661SRafal Jaworowski * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1967196661SRafal Jaworowski * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2067196661SRafal Jaworowski * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2167196661SRafal Jaworowski * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 2267196661SRafal Jaworowski * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2367196661SRafal Jaworowski * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2467196661SRafal Jaworowski * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2567196661SRafal Jaworowski */ 2667196661SRafal Jaworowski 2767196661SRafal Jaworowski /* 2867196661SRafal Jaworowski * Freescale integrated Three-Speed Ethernet Controller (TSEC) driver. 2967196661SRafal Jaworowski */ 3067196661SRafal Jaworowski #include <sys/cdefs.h> 3167196661SRafal Jaworowski __FBSDID("$FreeBSD$"); 3267196661SRafal Jaworowski 3367196661SRafal Jaworowski #include <sys/param.h> 3467196661SRafal Jaworowski #include <sys/systm.h> 35321e12c8SRafal Jaworowski #include <sys/bus.h> 3667196661SRafal Jaworowski #include <sys/endian.h> 3767196661SRafal Jaworowski #include <sys/mbuf.h> 3867196661SRafal Jaworowski #include <sys/kernel.h> 3967196661SRafal Jaworowski #include <sys/module.h> 4067196661SRafal Jaworowski #include <sys/socket.h> 41321e12c8SRafal Jaworowski #include <sys/sockio.h> 4267196661SRafal Jaworowski #include <sys/sysctl.h> 4367196661SRafal Jaworowski 44321e12c8SRafal Jaworowski #include <net/bpf.h> 45321e12c8SRafal Jaworowski #include <net/ethernet.h> 4667196661SRafal Jaworowski #include <net/if.h> 47321e12c8SRafal Jaworowski #include <net/if_arp.h> 4867196661SRafal Jaworowski #include <net/if_dl.h> 4967196661SRafal Jaworowski #include <net/if_media.h> 5067196661SRafal Jaworowski #include <net/if_types.h> 5167196661SRafal Jaworowski #include <net/if_vlan_var.h> 5267196661SRafal Jaworowski 53321e12c8SRafal Jaworowski #include <machine/bus.h> 54321e12c8SRafal Jaworowski 5567196661SRafal Jaworowski #include <dev/mii/mii.h> 5667196661SRafal Jaworowski #include <dev/mii/miivar.h> 5767196661SRafal Jaworowski 5867196661SRafal Jaworowski #include <dev/tsec/if_tsec.h> 5967196661SRafal Jaworowski #include <dev/tsec/if_tsecreg.h> 6067196661SRafal Jaworowski 61321e12c8SRafal Jaworowski static int tsec_alloc_dma_desc(device_t dev, bus_dma_tag_t *dtag, 62321e12c8SRafal Jaworowski bus_dmamap_t *dmap, bus_size_t dsize, void **vaddr, void *raddr, 63321e12c8SRafal Jaworowski const char *dname); 6467196661SRafal Jaworowski static void tsec_dma_ctl(struct tsec_softc *sc, int state); 65321e12c8SRafal Jaworowski static int tsec_encap(struct tsec_softc *sc, struct mbuf *m_head); 66321e12c8SRafal Jaworowski static void tsec_free_dma(struct tsec_softc *sc); 67321e12c8SRafal Jaworowski static void tsec_free_dma_desc(bus_dma_tag_t dtag, bus_dmamap_t dmap, void *vaddr); 6867196661SRafal Jaworowski static int tsec_ifmedia_upd(struct ifnet *ifp); 6967196661SRafal Jaworowski static void tsec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); 7067196661SRafal Jaworowski static int tsec_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, 7167196661SRafal Jaworowski struct mbuf **mbufp, uint32_t *paddr); 7267196661SRafal Jaworowski static void tsec_map_dma_addr(void *arg, bus_dma_segment_t *segs, 7367196661SRafal Jaworowski int nseg, int error); 74321e12c8SRafal Jaworowski static void tsec_intrs_ctl(struct tsec_softc *sc, int state); 75321e12c8SRafal Jaworowski static void tsec_init(void *xsc); 76321e12c8SRafal Jaworowski static void tsec_init_locked(struct tsec_softc *sc); 77321e12c8SRafal Jaworowski static int tsec_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 78321e12c8SRafal Jaworowski static void tsec_reset_mac(struct tsec_softc *sc); 79321e12c8SRafal Jaworowski static void tsec_setfilter(struct tsec_softc *sc); 80321e12c8SRafal Jaworowski static void tsec_set_mac_address(struct tsec_softc *sc); 81321e12c8SRafal Jaworowski static void tsec_start(struct ifnet *ifp); 82321e12c8SRafal Jaworowski static void tsec_start_locked(struct ifnet *ifp); 8367196661SRafal Jaworowski static void tsec_stop(struct tsec_softc *sc); 8467196661SRafal Jaworowski static void tsec_tick(void *arg); 85321e12c8SRafal Jaworowski static void tsec_watchdog(struct tsec_softc *sc); 8667196661SRafal Jaworowski 87321e12c8SRafal Jaworowski struct tsec_softc *tsec0_sc = NULL; /* XXX ugly hack! */ 8867196661SRafal Jaworowski 89321e12c8SRafal Jaworowski devclass_t tsec_devclass; 9067196661SRafal Jaworowski DRIVER_MODULE(miibus, tsec, miibus_driver, miibus_devclass, 0, 0); 9167196661SRafal Jaworowski MODULE_DEPEND(tsec, ether, 1, 1, 1); 9267196661SRafal Jaworowski MODULE_DEPEND(tsec, miibus, 1, 1, 1); 9367196661SRafal Jaworowski 94321e12c8SRafal Jaworowski int 95321e12c8SRafal Jaworowski tsec_attach(struct tsec_softc *sc) 9667196661SRafal Jaworowski { 97321e12c8SRafal Jaworowski uint8_t hwaddr[ETHER_ADDR_LEN]; 98321e12c8SRafal Jaworowski struct ifnet *ifp; 99321e12c8SRafal Jaworowski bus_dmamap_t *map_ptr; 100321e12c8SRafal Jaworowski bus_dmamap_t **map_pptr; 101321e12c8SRafal Jaworowski int error = 0; 102ecb1ab17SRafal Jaworowski int i; 10367196661SRafal Jaworowski 104321e12c8SRafal Jaworowski /* Reset all TSEC counters */ 105321e12c8SRafal Jaworowski TSEC_TX_RX_COUNTERS_INIT(sc); 106321e12c8SRafal Jaworowski 107321e12c8SRafal Jaworowski /* Stop DMA engine if enabled by firmware */ 108321e12c8SRafal Jaworowski tsec_dma_ctl(sc, 0); 109321e12c8SRafal Jaworowski 110321e12c8SRafal Jaworowski /* Reset MAC */ 111321e12c8SRafal Jaworowski tsec_reset_mac(sc); 112321e12c8SRafal Jaworowski 113321e12c8SRafal Jaworowski /* Disable interrupts for now */ 114321e12c8SRafal Jaworowski tsec_intrs_ctl(sc, 0); 115321e12c8SRafal Jaworowski 116321e12c8SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for TX descriptors. */ 117321e12c8SRafal Jaworowski error = tsec_alloc_dma_desc(sc->dev, &sc->tsec_tx_dtag, &sc->tsec_tx_dmap, 118321e12c8SRafal Jaworowski sizeof(*sc->tsec_tx_vaddr) * TSEC_TX_NUM_DESC, 119321e12c8SRafal Jaworowski (void **)&sc->tsec_tx_vaddr, &sc->tsec_tx_raddr, "TX"); 120321e12c8SRafal Jaworowski if (error) { 121321e12c8SRafal Jaworowski tsec_detach(sc); 122321e12c8SRafal Jaworowski return (ENXIO); 123ecb1ab17SRafal Jaworowski } 124ecb1ab17SRafal Jaworowski 125321e12c8SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for RX descriptors. */ 126321e12c8SRafal Jaworowski error = tsec_alloc_dma_desc(sc->dev, &sc->tsec_rx_dtag, &sc->tsec_rx_dmap, 127321e12c8SRafal Jaworowski sizeof(*sc->tsec_rx_vaddr) * TSEC_RX_NUM_DESC, 128321e12c8SRafal Jaworowski (void **)&sc->tsec_rx_vaddr, &sc->tsec_rx_raddr, "RX"); 129321e12c8SRafal Jaworowski if (error) { 130321e12c8SRafal Jaworowski tsec_detach(sc); 131321e12c8SRafal Jaworowski return (ENXIO); 132321e12c8SRafal Jaworowski } 13367196661SRafal Jaworowski 134321e12c8SRafal Jaworowski /* Allocate a busdma tag for TX mbufs. */ 135321e12c8SRafal Jaworowski error = bus_dma_tag_create(NULL, /* parent */ 136321e12c8SRafal Jaworowski TSEC_TXBUFFER_ALIGNMENT, 0, /* alignment, boundary */ 137321e12c8SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 138321e12c8SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 139321e12c8SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 140321e12c8SRafal Jaworowski MCLBYTES * (TSEC_TX_NUM_DESC - 1),/* maxsize */ 141321e12c8SRafal Jaworowski TSEC_TX_NUM_DESC - 1, /* nsegments */ 142321e12c8SRafal Jaworowski MCLBYTES, 0, /* maxsegsz, flags */ 143321e12c8SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 144321e12c8SRafal Jaworowski &sc->tsec_tx_mtag); /* dmat */ 145321e12c8SRafal Jaworowski if (error) { 146321e12c8SRafal Jaworowski device_printf(sc->dev, "failed to allocate busdma tag(tx mbufs)\n"); 147321e12c8SRafal Jaworowski tsec_detach(sc); 148321e12c8SRafal Jaworowski return (ENXIO); 149321e12c8SRafal Jaworowski } 150321e12c8SRafal Jaworowski 151321e12c8SRafal Jaworowski /* Allocate a busdma tag for RX mbufs. */ 152321e12c8SRafal Jaworowski error = bus_dma_tag_create(NULL, /* parent */ 153321e12c8SRafal Jaworowski TSEC_RXBUFFER_ALIGNMENT, 0, /* alignment, boundary */ 154321e12c8SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 155321e12c8SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 156321e12c8SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 157321e12c8SRafal Jaworowski MCLBYTES, /* maxsize */ 158321e12c8SRafal Jaworowski 1, /* nsegments */ 159321e12c8SRafal Jaworowski MCLBYTES, 0, /* maxsegsz, flags */ 160321e12c8SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 161321e12c8SRafal Jaworowski &sc->tsec_rx_mtag); /* dmat */ 162321e12c8SRafal Jaworowski if (error) { 163321e12c8SRafal Jaworowski device_printf(sc->dev, "failed to allocate busdma tag(rx mbufs)\n"); 164321e12c8SRafal Jaworowski tsec_detach(sc); 165321e12c8SRafal Jaworowski return (ENXIO); 166321e12c8SRafal Jaworowski } 167321e12c8SRafal Jaworowski 168321e12c8SRafal Jaworowski /* Create TX busdma maps */ 169321e12c8SRafal Jaworowski map_ptr = sc->tx_map_data; 170321e12c8SRafal Jaworowski map_pptr = sc->tx_map_unused_data; 171321e12c8SRafal Jaworowski 172321e12c8SRafal Jaworowski for (i = 0; i < TSEC_TX_NUM_DESC; i++) { 173321e12c8SRafal Jaworowski map_pptr[i] = &map_ptr[i]; 174321e12c8SRafal Jaworowski error = bus_dmamap_create(sc->tsec_tx_mtag, 0, map_pptr[i]); 175321e12c8SRafal Jaworowski if (error) { 176321e12c8SRafal Jaworowski device_printf(sc->dev, "failed to init TX ring\n"); 177321e12c8SRafal Jaworowski tsec_detach(sc); 178321e12c8SRafal Jaworowski return (ENXIO); 179321e12c8SRafal Jaworowski } 180321e12c8SRafal Jaworowski } 181321e12c8SRafal Jaworowski 182321e12c8SRafal Jaworowski /* Create RX busdma maps and zero mbuf handlers */ 183321e12c8SRafal Jaworowski for (i = 0; i < TSEC_RX_NUM_DESC; i++) { 184321e12c8SRafal Jaworowski error = bus_dmamap_create(sc->tsec_rx_mtag, 0, &sc->rx_data[i].map); 185321e12c8SRafal Jaworowski if (error) { 186321e12c8SRafal Jaworowski device_printf(sc->dev, "failed to init RX ring\n"); 187321e12c8SRafal Jaworowski tsec_detach(sc); 188321e12c8SRafal Jaworowski return (ENXIO); 189321e12c8SRafal Jaworowski } 190321e12c8SRafal Jaworowski sc->rx_data[i].mbuf = NULL; 191321e12c8SRafal Jaworowski } 192321e12c8SRafal Jaworowski 193321e12c8SRafal Jaworowski /* Create mbufs for RX buffers */ 194321e12c8SRafal Jaworowski for (i = 0; i < TSEC_RX_NUM_DESC; i++) { 195321e12c8SRafal Jaworowski error = tsec_new_rxbuf(sc->tsec_rx_mtag, sc->rx_data[i].map, 196321e12c8SRafal Jaworowski &sc->rx_data[i].mbuf, &sc->rx_data[i].paddr); 197321e12c8SRafal Jaworowski if (error) { 198321e12c8SRafal Jaworowski device_printf(sc->dev, "can't load rx DMA map %d, error = " 199321e12c8SRafal Jaworowski "%d\n", i, error); 200321e12c8SRafal Jaworowski tsec_detach(sc); 201321e12c8SRafal Jaworowski return (error); 202321e12c8SRafal Jaworowski } 203321e12c8SRafal Jaworowski } 204321e12c8SRafal Jaworowski 205321e12c8SRafal Jaworowski /* Create network interface for upper layers */ 206321e12c8SRafal Jaworowski ifp = sc->tsec_ifp = if_alloc(IFT_ETHER); 207321e12c8SRafal Jaworowski if (ifp == NULL) { 208321e12c8SRafal Jaworowski device_printf(sc->dev, "if_alloc() failed\n"); 209321e12c8SRafal Jaworowski tsec_detach(sc); 210321e12c8SRafal Jaworowski return (ENOMEM); 211321e12c8SRafal Jaworowski } 212321e12c8SRafal Jaworowski 213321e12c8SRafal Jaworowski ifp->if_softc = sc; 214321e12c8SRafal Jaworowski if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev)); 215321e12c8SRafal Jaworowski ifp->if_mtu = ETHERMTU; 216321e12c8SRafal Jaworowski ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST; 217321e12c8SRafal Jaworowski ifp->if_init = tsec_init; 218321e12c8SRafal Jaworowski ifp->if_start = tsec_start; 219321e12c8SRafal Jaworowski ifp->if_ioctl = tsec_ioctl; 220321e12c8SRafal Jaworowski 221321e12c8SRafal Jaworowski IFQ_SET_MAXLEN(&ifp->if_snd, TSEC_TX_NUM_DESC - 1); 222321e12c8SRafal Jaworowski ifp->if_snd.ifq_drv_maxlen = TSEC_TX_NUM_DESC - 1; 223321e12c8SRafal Jaworowski IFQ_SET_READY(&ifp->if_snd); 224321e12c8SRafal Jaworowski 225321e12c8SRafal Jaworowski /* XXX No special features of TSEC are supported currently */ 226321e12c8SRafal Jaworowski ifp->if_capabilities = 0; 227321e12c8SRafal Jaworowski ifp->if_capenable = ifp->if_capabilities; 228321e12c8SRafal Jaworowski 229321e12c8SRafal Jaworowski /* Probe PHY(s) */ 230321e12c8SRafal Jaworowski error = mii_phy_probe(sc->dev, &sc->tsec_miibus, tsec_ifmedia_upd, 231321e12c8SRafal Jaworowski tsec_ifmedia_sts); 232321e12c8SRafal Jaworowski if (error) { 233321e12c8SRafal Jaworowski device_printf(sc->dev, "MII failed to find PHY!\n"); 234321e12c8SRafal Jaworowski if_free(ifp); 235321e12c8SRafal Jaworowski sc->tsec_ifp = NULL; 236321e12c8SRafal Jaworowski tsec_detach(sc); 237321e12c8SRafal Jaworowski return (error); 238321e12c8SRafal Jaworowski } 239321e12c8SRafal Jaworowski sc->tsec_mii = device_get_softc(sc->tsec_miibus); 240321e12c8SRafal Jaworowski 241321e12c8SRafal Jaworowski /* Set MAC address */ 242321e12c8SRafal Jaworowski tsec_get_hwaddr(sc, hwaddr); 243321e12c8SRafal Jaworowski ether_ifattach(ifp, hwaddr); 244321e12c8SRafal Jaworowski 245321e12c8SRafal Jaworowski return (0); 246321e12c8SRafal Jaworowski } 247321e12c8SRafal Jaworowski 248321e12c8SRafal Jaworowski int 249321e12c8SRafal Jaworowski tsec_detach(struct tsec_softc *sc) 250321e12c8SRafal Jaworowski { 251321e12c8SRafal Jaworowski 252321e12c8SRafal Jaworowski /* Stop TSEC controller and free TX queue */ 253321e12c8SRafal Jaworowski if (sc->sc_rres && sc->tsec_ifp) 254321e12c8SRafal Jaworowski tsec_shutdown(sc->dev); 255321e12c8SRafal Jaworowski 256321e12c8SRafal Jaworowski /* Detach network interface */ 257321e12c8SRafal Jaworowski if (sc->tsec_ifp) { 258321e12c8SRafal Jaworowski ether_ifdetach(sc->tsec_ifp); 259321e12c8SRafal Jaworowski if_free(sc->tsec_ifp); 260321e12c8SRafal Jaworowski sc->tsec_ifp = NULL; 261321e12c8SRafal Jaworowski } 262321e12c8SRafal Jaworowski 263321e12c8SRafal Jaworowski /* Free DMA resources */ 264321e12c8SRafal Jaworowski tsec_free_dma(sc); 265321e12c8SRafal Jaworowski 266321e12c8SRafal Jaworowski return (0); 267321e12c8SRafal Jaworowski } 268321e12c8SRafal Jaworowski 269321e12c8SRafal Jaworowski void 270321e12c8SRafal Jaworowski tsec_shutdown(device_t dev) 271321e12c8SRafal Jaworowski { 272321e12c8SRafal Jaworowski struct tsec_softc *sc; 273321e12c8SRafal Jaworowski 274321e12c8SRafal Jaworowski sc = device_get_softc(dev); 275321e12c8SRafal Jaworowski 276321e12c8SRafal Jaworowski TSEC_GLOBAL_LOCK(sc); 277321e12c8SRafal Jaworowski tsec_stop(sc); 278321e12c8SRafal Jaworowski TSEC_GLOBAL_UNLOCK(sc); 279321e12c8SRafal Jaworowski } 280321e12c8SRafal Jaworowski 281321e12c8SRafal Jaworowski int 282321e12c8SRafal Jaworowski tsec_suspend(device_t dev) 283321e12c8SRafal Jaworowski { 284321e12c8SRafal Jaworowski 285321e12c8SRafal Jaworowski /* TODO not implemented! */ 286321e12c8SRafal Jaworowski return (0); 287321e12c8SRafal Jaworowski } 288321e12c8SRafal Jaworowski 289321e12c8SRafal Jaworowski int 290321e12c8SRafal Jaworowski tsec_resume(device_t dev) 291321e12c8SRafal Jaworowski { 292321e12c8SRafal Jaworowski 293321e12c8SRafal Jaworowski /* TODO not implemented! */ 294321e12c8SRafal Jaworowski return (0); 29567196661SRafal Jaworowski } 29667196661SRafal Jaworowski 29767196661SRafal Jaworowski static void 29867196661SRafal Jaworowski tsec_init(void *xsc) 29967196661SRafal Jaworowski { 30067196661SRafal Jaworowski struct tsec_softc *sc = xsc; 30167196661SRafal Jaworowski 30267196661SRafal Jaworowski TSEC_GLOBAL_LOCK(sc); 30367196661SRafal Jaworowski tsec_init_locked(sc); 30467196661SRafal Jaworowski TSEC_GLOBAL_UNLOCK(sc); 30567196661SRafal Jaworowski } 30667196661SRafal Jaworowski 30767196661SRafal Jaworowski static void 30867196661SRafal Jaworowski tsec_init_locked(struct tsec_softc *sc) 30967196661SRafal Jaworowski { 31067196661SRafal Jaworowski struct tsec_desc *tx_desc = sc->tsec_tx_vaddr; 31167196661SRafal Jaworowski struct tsec_desc *rx_desc = sc->tsec_rx_vaddr; 31267196661SRafal Jaworowski struct ifnet *ifp = sc->tsec_ifp; 31367196661SRafal Jaworowski uint32_t timeout; 31467196661SRafal Jaworowski uint32_t val; 31567196661SRafal Jaworowski uint32_t i; 31667196661SRafal Jaworowski 31767196661SRafal Jaworowski TSEC_GLOBAL_LOCK_ASSERT(sc); 31867196661SRafal Jaworowski tsec_stop(sc); 31967196661SRafal Jaworowski 32067196661SRafal Jaworowski /* 32167196661SRafal Jaworowski * These steps are according to the MPC8555E PowerQUICCIII RM: 32267196661SRafal Jaworowski * 14.7 Initialization/Application Information 32367196661SRafal Jaworowski */ 32467196661SRafal Jaworowski 32567196661SRafal Jaworowski /* Step 1: soft reset MAC */ 32667196661SRafal Jaworowski tsec_reset_mac(sc); 32767196661SRafal Jaworowski 32867196661SRafal Jaworowski /* Step 2: Initialize MACCFG2 */ 32967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG2, 33067196661SRafal Jaworowski TSEC_MACCFG2_FULLDUPLEX | /* Full Duplex = 1 */ 33167196661SRafal Jaworowski TSEC_MACCFG2_PADCRC | /* PAD/CRC append */ 33267196661SRafal Jaworowski TSEC_MACCFG2_GMII | /* I/F Mode bit */ 33367196661SRafal Jaworowski TSEC_MACCFG2_PRECNT /* Preamble count = 7 */ 33467196661SRafal Jaworowski ); 33567196661SRafal Jaworowski 33667196661SRafal Jaworowski /* Step 3: Initialize ECNTRL 33767196661SRafal Jaworowski * While the documentation states that R100M is ignored if RPM is 33867196661SRafal Jaworowski * not set, it does seem to be needed to get the orange boxes to 33967196661SRafal Jaworowski * work (which have a Marvell 88E1111 PHY). Go figure. 34067196661SRafal Jaworowski */ 34167196661SRafal Jaworowski 34267196661SRafal Jaworowski /* 34367196661SRafal Jaworowski * XXX kludge - use circumstancial evidence to program ECNTRL 34467196661SRafal Jaworowski * correctly. Ideally we need some board information to guide 34567196661SRafal Jaworowski * us here. 34667196661SRafal Jaworowski */ 34767196661SRafal Jaworowski i = TSEC_READ(sc, TSEC_REG_ID2); 34867196661SRafal Jaworowski val = (i & 0xffff) 34967196661SRafal Jaworowski ? (TSEC_ECNTRL_TBIM | TSEC_ECNTRL_SGMIIM) /* Sumatra */ 35067196661SRafal Jaworowski : TSEC_ECNTRL_R100M; /* Orange + CDS */ 35167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_ECNTRL, TSEC_ECNTRL_STEN | val); 35267196661SRafal Jaworowski 35367196661SRafal Jaworowski /* Step 4: Initialize MAC station address */ 35467196661SRafal Jaworowski tsec_set_mac_address(sc); 35567196661SRafal Jaworowski 35667196661SRafal Jaworowski /* 35767196661SRafal Jaworowski * Step 5: Assign a Physical address to the TBI so as to not conflict 35867196661SRafal Jaworowski * with the external PHY physical address 35967196661SRafal Jaworowski */ 36067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TBIPA, 5); 36167196661SRafal Jaworowski 36267196661SRafal Jaworowski /* Step 6: Reset the management interface */ 36367196661SRafal Jaworowski TSEC_WRITE(tsec0_sc, TSEC_REG_MIIMCFG, TSEC_MIIMCFG_RESETMGMT); 36467196661SRafal Jaworowski 36567196661SRafal Jaworowski /* Step 7: Setup the MII Mgmt clock speed */ 36667196661SRafal Jaworowski TSEC_WRITE(tsec0_sc, TSEC_REG_MIIMCFG, TSEC_MIIMCFG_CLKDIV28); 36767196661SRafal Jaworowski 36867196661SRafal Jaworowski /* Step 8: Read MII Mgmt indicator register and check for Busy = 0 */ 36967196661SRafal Jaworowski timeout = TSEC_READ_RETRY; 37067196661SRafal Jaworowski while (--timeout && (TSEC_READ(tsec0_sc, TSEC_REG_MIIMIND) & 37167196661SRafal Jaworowski TSEC_MIIMIND_BUSY)) 37267196661SRafal Jaworowski DELAY(TSEC_READ_DELAY); 37367196661SRafal Jaworowski if (timeout == 0) { 37467196661SRafal Jaworowski if_printf(ifp, "tsec_init_locked(): Mgmt busy timeout\n"); 37567196661SRafal Jaworowski return; 37667196661SRafal Jaworowski } 37767196661SRafal Jaworowski 37867196661SRafal Jaworowski /* Step 9: Setup the MII Mgmt */ 37967196661SRafal Jaworowski mii_mediachg(sc->tsec_mii); 38067196661SRafal Jaworowski 38167196661SRafal Jaworowski /* Step 10: Clear IEVENT register */ 38267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, 0xffffffff); 38367196661SRafal Jaworowski 38467196661SRafal Jaworowski /* Step 11: Initialize IMASK */ 38567196661SRafal Jaworowski tsec_intrs_ctl(sc, 1); 38667196661SRafal Jaworowski 38767196661SRafal Jaworowski /* Step 12: Initialize IADDRn */ 38867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR0, 0); 38967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR1, 0); 39067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR2, 0); 39167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR3, 0); 39267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR4, 0); 39367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR5, 0); 39467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR6, 0); 39567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IADDR7, 0); 39667196661SRafal Jaworowski 39767196661SRafal Jaworowski /* Step 13: Initialize GADDRn */ 39867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR0, 0); 39967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR1, 0); 40067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR2, 0); 40167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR3, 0); 40267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR4, 0); 40367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR5, 0); 40467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR6, 0); 40567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_GADDR7, 0); 40667196661SRafal Jaworowski 40767196661SRafal Jaworowski /* Step 14: Initialize RCTRL */ 40867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_RCTRL, 0); 40967196661SRafal Jaworowski 41067196661SRafal Jaworowski /* Step 15: Initialize DMACTRL */ 41167196661SRafal Jaworowski tsec_dma_ctl(sc, 1); 41267196661SRafal Jaworowski 41367196661SRafal Jaworowski /* Step 16: Initialize FIFO_PAUSE_CTRL */ 41467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_FIFO_PAUSE_CTRL, TSEC_FIFO_PAUSE_CTRL_EN); 41567196661SRafal Jaworowski 41667196661SRafal Jaworowski /* 41767196661SRafal Jaworowski * Step 17: Initialize transmit/receive descriptor rings. 41867196661SRafal Jaworowski * Initialize TBASE and RBASE. 41967196661SRafal Jaworowski */ 42067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TBASE, sc->tsec_tx_raddr); 42167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_RBASE, sc->tsec_rx_raddr); 42267196661SRafal Jaworowski 42367196661SRafal Jaworowski for (i = 0; i < TSEC_TX_NUM_DESC; i++) { 42467196661SRafal Jaworowski tx_desc[i].bufptr = 0; 42567196661SRafal Jaworowski tx_desc[i].length = 0; 42667196661SRafal Jaworowski tx_desc[i].flags = ((i == TSEC_TX_NUM_DESC - 1) ? TSEC_TXBD_W : 0); 42767196661SRafal Jaworowski } 428321e12c8SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, 429321e12c8SRafal Jaworowski BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 43067196661SRafal Jaworowski 43167196661SRafal Jaworowski for (i = 0; i < TSEC_RX_NUM_DESC; i++) { 43267196661SRafal Jaworowski rx_desc[i].bufptr = sc->rx_data[i].paddr; 43367196661SRafal Jaworowski rx_desc[i].length = 0; 43467196661SRafal Jaworowski rx_desc[i].flags = TSEC_RXBD_E | TSEC_RXBD_I | 43567196661SRafal Jaworowski ((i == TSEC_RX_NUM_DESC - 1) ? TSEC_RXBD_W : 0); 43667196661SRafal Jaworowski } 43767196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_rx_dtag, sc->tsec_rx_dmap, BUS_DMASYNC_PREREAD | 43867196661SRafal Jaworowski BUS_DMASYNC_PREWRITE); 43967196661SRafal Jaworowski 44067196661SRafal Jaworowski /* Step 18: Initialize the maximum and minimum receive buffer length */ 44167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MRBLR, TSEC_DEFAULT_MAX_RX_BUFFER_SIZE); 44267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MINFLR, TSEC_DEFAULT_MIN_RX_BUFFER_SIZE); 44367196661SRafal Jaworowski 44467196661SRafal Jaworowski /* Step 19: Enable Rx and RxBD sdata snooping */ 44567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_ATTR, TSEC_ATTR_RDSEN | TSEC_ATTR_RBDSEN); 44667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_ATTRELI, 0); 44767196661SRafal Jaworowski 44867196661SRafal Jaworowski /* Step 20: Reset collision counters in hardware */ 44967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TSCL, 0); 45067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TMCL, 0); 45167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TLCL, 0); 45267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TXCL, 0); 45367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TNCL, 0); 45467196661SRafal Jaworowski 45567196661SRafal Jaworowski /* Step 21: Mask all CAM interrupts */ 45667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_CAM1, 0xffffffff); 45767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_CAM2, 0xffffffff); 45867196661SRafal Jaworowski 45967196661SRafal Jaworowski /* Step 22: Enable Rx and Tx */ 46067196661SRafal Jaworowski val = TSEC_READ(sc, TSEC_REG_MACCFG1); 46167196661SRafal Jaworowski val |= (TSEC_MACCFG1_RX_EN | TSEC_MACCFG1_TX_EN); 46267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG1, val); 46367196661SRafal Jaworowski 46467196661SRafal Jaworowski /* Step 23: Reset TSEC counters for Tx and Rx rings */ 46567196661SRafal Jaworowski TSEC_TX_RX_COUNTERS_INIT(sc); 46667196661SRafal Jaworowski 4675432bd9fSRafal Jaworowski /* Step 24: Activate network interface */ 46867196661SRafal Jaworowski ifp->if_drv_flags |= IFF_DRV_RUNNING; 46967196661SRafal Jaworowski ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 47067196661SRafal Jaworowski sc->tsec_if_flags = ifp->if_flags; 4715432bd9fSRafal Jaworowski sc->tsec_watchdog = 0; 472772619e1SRafal Jaworowski 473772619e1SRafal Jaworowski /* Schedule watchdog timeout */ 4745432bd9fSRafal Jaworowski callout_reset(&sc->tsec_callout, hz, tsec_tick, sc); 47567196661SRafal Jaworowski } 47667196661SRafal Jaworowski 47767196661SRafal Jaworowski static void 47867196661SRafal Jaworowski tsec_set_mac_address(struct tsec_softc *sc) 47967196661SRafal Jaworowski { 48067196661SRafal Jaworowski uint32_t macbuf[2] = { 0, 0 }; 48167196661SRafal Jaworowski char *macbufp; 48267196661SRafal Jaworowski char *curmac; 483321e12c8SRafal Jaworowski int i; 48467196661SRafal Jaworowski 48567196661SRafal Jaworowski TSEC_GLOBAL_LOCK_ASSERT(sc); 48667196661SRafal Jaworowski 48767196661SRafal Jaworowski KASSERT((ETHER_ADDR_LEN <= sizeof(macbuf)), 488321e12c8SRafal Jaworowski ("tsec_set_mac_address: (%d <= %d", ETHER_ADDR_LEN, sizeof(macbuf))); 48967196661SRafal Jaworowski 49067196661SRafal Jaworowski macbufp = (char *)macbuf; 49167196661SRafal Jaworowski curmac = (char *)IF_LLADDR(sc->tsec_ifp); 49267196661SRafal Jaworowski 49367196661SRafal Jaworowski /* Correct order of MAC address bytes */ 49467196661SRafal Jaworowski for (i = 1; i <= ETHER_ADDR_LEN; i++) 49567196661SRafal Jaworowski macbufp[ETHER_ADDR_LEN-i] = curmac[i-1]; 49667196661SRafal Jaworowski 49767196661SRafal Jaworowski /* Initialize MAC station address MACSTNADDR2 and MACSTNADDR1 */ 49867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACSTNADDR2, macbuf[1]); 49967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACSTNADDR1, macbuf[0]); 50067196661SRafal Jaworowski } 50167196661SRafal Jaworowski 50267196661SRafal Jaworowski /* 50367196661SRafal Jaworowski * DMA control function, if argument state is: 50467196661SRafal Jaworowski * 0 - DMA engine will be disabled 50567196661SRafal Jaworowski * 1 - DMA engine will be enabled 50667196661SRafal Jaworowski */ 50767196661SRafal Jaworowski static void 50867196661SRafal Jaworowski tsec_dma_ctl(struct tsec_softc *sc, int state) 50967196661SRafal Jaworowski { 51067196661SRafal Jaworowski device_t dev; 51167196661SRafal Jaworowski uint32_t dma_flags; 51267196661SRafal Jaworowski uint32_t timeout; 51367196661SRafal Jaworowski 51467196661SRafal Jaworowski dev = sc->dev; 51567196661SRafal Jaworowski 51667196661SRafal Jaworowski dma_flags = TSEC_READ(sc, TSEC_REG_DMACTRL); 51767196661SRafal Jaworowski 51867196661SRafal Jaworowski switch (state) { 51967196661SRafal Jaworowski case 0: 52067196661SRafal Jaworowski /* Temporarily clear stop graceful stop bits. */ 52167196661SRafal Jaworowski tsec_dma_ctl(sc, 1000); 52267196661SRafal Jaworowski 52367196661SRafal Jaworowski /* Set it again */ 52467196661SRafal Jaworowski dma_flags |= (TSEC_DMACTRL_GRS | TSEC_DMACTRL_GTS); 52567196661SRafal Jaworowski break; 52667196661SRafal Jaworowski case 1000: 52767196661SRafal Jaworowski case 1: 52867196661SRafal Jaworowski /* Set write with response (WWR), wait (WOP) and snoop bits */ 52967196661SRafal Jaworowski dma_flags |= (TSEC_DMACTRL_TDSEN | TSEC_DMACTRL_TBDSEN | 53067196661SRafal Jaworowski DMACTRL_WWR | DMACTRL_WOP); 53167196661SRafal Jaworowski 53267196661SRafal Jaworowski /* Clear graceful stop bits */ 53367196661SRafal Jaworowski dma_flags &= ~(TSEC_DMACTRL_GRS | TSEC_DMACTRL_GTS); 53467196661SRafal Jaworowski break; 53567196661SRafal Jaworowski default: 53667196661SRafal Jaworowski device_printf(dev, "tsec_dma_ctl(): unknown state value: %d\n", 53767196661SRafal Jaworowski state); 53867196661SRafal Jaworowski } 53967196661SRafal Jaworowski 54067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_DMACTRL, dma_flags); 54167196661SRafal Jaworowski 54267196661SRafal Jaworowski switch (state) { 54367196661SRafal Jaworowski case 0: 54467196661SRafal Jaworowski /* Wait for DMA stop */ 54567196661SRafal Jaworowski timeout = TSEC_READ_RETRY; 54667196661SRafal Jaworowski while (--timeout && (!(TSEC_READ(sc, TSEC_REG_IEVENT) & 54767196661SRafal Jaworowski (TSEC_IEVENT_GRSC | TSEC_IEVENT_GTSC)))) 54867196661SRafal Jaworowski DELAY(TSEC_READ_DELAY); 54967196661SRafal Jaworowski 55067196661SRafal Jaworowski if (timeout == 0) 55167196661SRafal Jaworowski device_printf(dev, "tsec_dma_ctl(): timeout!\n"); 55267196661SRafal Jaworowski break; 55367196661SRafal Jaworowski case 1: 55467196661SRafal Jaworowski /* Restart transmission function */ 55567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TSTAT, TSEC_TSTAT_THLT); 55667196661SRafal Jaworowski } 55767196661SRafal Jaworowski } 55867196661SRafal Jaworowski 55967196661SRafal Jaworowski /* 56067196661SRafal Jaworowski * Interrupts control function, if argument state is: 56167196661SRafal Jaworowski * 0 - all TSEC interrupts will be masked 56267196661SRafal Jaworowski * 1 - all TSEC interrupts will be unmasked 56367196661SRafal Jaworowski */ 56467196661SRafal Jaworowski static void 56567196661SRafal Jaworowski tsec_intrs_ctl(struct tsec_softc *sc, int state) 56667196661SRafal Jaworowski { 56767196661SRafal Jaworowski device_t dev; 56867196661SRafal Jaworowski 56967196661SRafal Jaworowski dev = sc->dev; 57067196661SRafal Jaworowski 57167196661SRafal Jaworowski switch (state) { 57267196661SRafal Jaworowski case 0: 57367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IMASK, 0); 57467196661SRafal Jaworowski break; 57567196661SRafal Jaworowski case 1: 576321e12c8SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IMASK, TSEC_IMASK_BREN | TSEC_IMASK_RXCEN | 577321e12c8SRafal Jaworowski TSEC_IMASK_BSYEN | TSEC_IMASK_EBERREN | TSEC_IMASK_BTEN | 578321e12c8SRafal Jaworowski TSEC_IMASK_TXEEN | TSEC_IMASK_TXBEN | TSEC_IMASK_TXFEN | 579321e12c8SRafal Jaworowski TSEC_IMASK_XFUNEN | TSEC_IMASK_RXFEN); 58067196661SRafal Jaworowski break; 58167196661SRafal Jaworowski default: 58267196661SRafal Jaworowski device_printf(dev, "tsec_intrs_ctl(): unknown state value: %d\n", 58367196661SRafal Jaworowski state); 58467196661SRafal Jaworowski } 58567196661SRafal Jaworowski } 58667196661SRafal Jaworowski 58767196661SRafal Jaworowski static void 58867196661SRafal Jaworowski tsec_reset_mac(struct tsec_softc *sc) 58967196661SRafal Jaworowski { 59067196661SRafal Jaworowski uint32_t maccfg1_flags; 59167196661SRafal Jaworowski 59267196661SRafal Jaworowski /* Set soft reset bit */ 59367196661SRafal Jaworowski maccfg1_flags = TSEC_READ(sc, TSEC_REG_MACCFG1); 59467196661SRafal Jaworowski maccfg1_flags |= TSEC_MACCFG1_SOFT_RESET; 59567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG1, maccfg1_flags); 59667196661SRafal Jaworowski 59767196661SRafal Jaworowski /* Clear soft reset bit */ 59867196661SRafal Jaworowski maccfg1_flags = TSEC_READ(sc, TSEC_REG_MACCFG1); 59967196661SRafal Jaworowski maccfg1_flags &= ~TSEC_MACCFG1_SOFT_RESET; 60067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG1, maccfg1_flags); 60167196661SRafal Jaworowski } 60267196661SRafal Jaworowski 60367196661SRafal Jaworowski static void 604772619e1SRafal Jaworowski tsec_watchdog(struct tsec_softc *sc) 60567196661SRafal Jaworowski { 606772619e1SRafal Jaworowski struct ifnet *ifp; 60767196661SRafal Jaworowski 608772619e1SRafal Jaworowski TSEC_GLOBAL_LOCK_ASSERT(sc); 60967196661SRafal Jaworowski 6105432bd9fSRafal Jaworowski if (sc->tsec_watchdog == 0 || --sc->tsec_watchdog > 0) 611772619e1SRafal Jaworowski return; 612772619e1SRafal Jaworowski 613772619e1SRafal Jaworowski ifp = sc->tsec_ifp; 61467196661SRafal Jaworowski ifp->if_oerrors++; 61567196661SRafal Jaworowski if_printf(ifp, "watchdog timeout\n"); 61667196661SRafal Jaworowski 61767196661SRafal Jaworowski tsec_stop(sc); 61867196661SRafal Jaworowski tsec_init_locked(sc); 61967196661SRafal Jaworowski } 62067196661SRafal Jaworowski 62167196661SRafal Jaworowski static void 62267196661SRafal Jaworowski tsec_start(struct ifnet *ifp) 62367196661SRafal Jaworowski { 62467196661SRafal Jaworowski struct tsec_softc *sc = ifp->if_softc; 62567196661SRafal Jaworowski 62667196661SRafal Jaworowski TSEC_TRANSMIT_LOCK(sc); 62767196661SRafal Jaworowski tsec_start_locked(ifp); 62867196661SRafal Jaworowski TSEC_TRANSMIT_UNLOCK(sc); 62967196661SRafal Jaworowski } 63067196661SRafal Jaworowski 63167196661SRafal Jaworowski static void 63267196661SRafal Jaworowski tsec_start_locked(struct ifnet *ifp) 63367196661SRafal Jaworowski { 63467196661SRafal Jaworowski struct tsec_softc *sc; 63567196661SRafal Jaworowski struct mbuf *m0; 63667196661SRafal Jaworowski struct mbuf *mtmp; 63767196661SRafal Jaworowski unsigned int queued = 0; 63867196661SRafal Jaworowski 63967196661SRafal Jaworowski sc = ifp->if_softc; 64067196661SRafal Jaworowski 64167196661SRafal Jaworowski TSEC_TRANSMIT_LOCK_ASSERT(sc); 64267196661SRafal Jaworowski 64367196661SRafal Jaworowski if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 64467196661SRafal Jaworowski IFF_DRV_RUNNING) 64567196661SRafal Jaworowski return; 64667196661SRafal Jaworowski 64767196661SRafal Jaworowski if (sc->tsec_link == 0) 64867196661SRafal Jaworowski return; 64967196661SRafal Jaworowski 650321e12c8SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, BUS_DMASYNC_POSTREAD | 651321e12c8SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 65267196661SRafal Jaworowski 65367196661SRafal Jaworowski for (;;) { 65467196661SRafal Jaworowski /* Get packet from the queue */ 65567196661SRafal Jaworowski IF_DEQUEUE(&ifp->if_snd, m0); 65667196661SRafal Jaworowski if (m0 == NULL) 65767196661SRafal Jaworowski break; 65867196661SRafal Jaworowski 65967196661SRafal Jaworowski mtmp = m_defrag(m0, M_DONTWAIT); 66067196661SRafal Jaworowski if (mtmp) 66167196661SRafal Jaworowski m0 = mtmp; 66267196661SRafal Jaworowski 66367196661SRafal Jaworowski if (tsec_encap(sc, m0)) { 66467196661SRafal Jaworowski IF_PREPEND(&ifp->if_snd, m0); 66567196661SRafal Jaworowski ifp->if_drv_flags |= IFF_DRV_OACTIVE; 66667196661SRafal Jaworowski break; 66767196661SRafal Jaworowski } 66867196661SRafal Jaworowski queued++; 66967196661SRafal Jaworowski BPF_MTAP(ifp, m0); 67067196661SRafal Jaworowski } 671321e12c8SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, BUS_DMASYNC_PREREAD | 672321e12c8SRafal Jaworowski BUS_DMASYNC_PREWRITE); 67367196661SRafal Jaworowski 67467196661SRafal Jaworowski if (queued) { 67567196661SRafal Jaworowski /* Enable transmitter and watchdog timer */ 67667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TSTAT, TSEC_TSTAT_THLT); 6775432bd9fSRafal Jaworowski sc->tsec_watchdog = 5; 67867196661SRafal Jaworowski } 67967196661SRafal Jaworowski } 68067196661SRafal Jaworowski 68167196661SRafal Jaworowski static int 68267196661SRafal Jaworowski tsec_encap(struct tsec_softc *sc, struct mbuf *m0) 68367196661SRafal Jaworowski { 68467196661SRafal Jaworowski struct tsec_desc *tx_desc = NULL; 68567196661SRafal Jaworowski struct ifnet *ifp; 68667196661SRafal Jaworowski bus_dma_segment_t segs[TSEC_TX_NUM_DESC]; 68767196661SRafal Jaworowski bus_dmamap_t *mapp; 68867196661SRafal Jaworowski int error; 68967196661SRafal Jaworowski int seg, nsegs; 69067196661SRafal Jaworowski 69167196661SRafal Jaworowski TSEC_TRANSMIT_LOCK_ASSERT(sc); 69267196661SRafal Jaworowski 69367196661SRafal Jaworowski ifp = sc->tsec_ifp; 69467196661SRafal Jaworowski 69567196661SRafal Jaworowski if (TSEC_FREE_TX_DESC(sc) == 0) { 69667196661SRafal Jaworowski /* No free descriptors */ 69767196661SRafal Jaworowski return (-1); 69867196661SRafal Jaworowski } 69967196661SRafal Jaworowski 70067196661SRafal Jaworowski /* Fetch unused map */ 70167196661SRafal Jaworowski mapp = TSEC_ALLOC_TX_MAP(sc); 70267196661SRafal Jaworowski 70367196661SRafal Jaworowski /* Create mapping in DMA memory */ 70467196661SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(sc->tsec_tx_mtag, 70567196661SRafal Jaworowski *mapp, m0, segs, &nsegs, BUS_DMA_NOWAIT); 70667196661SRafal Jaworowski if (error != 0 || nsegs > TSEC_FREE_TX_DESC(sc) || nsegs <= 0) { 70767196661SRafal Jaworowski bus_dmamap_unload(sc->tsec_tx_mtag, *mapp); 70867196661SRafal Jaworowski TSEC_FREE_TX_MAP(sc, mapp); 70967196661SRafal Jaworowski return ((error != 0) ? error : -1); 71067196661SRafal Jaworowski } 71167196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_mtag, *mapp, BUS_DMASYNC_PREWRITE); 71267196661SRafal Jaworowski 71367196661SRafal Jaworowski if ((ifp->if_flags & IFF_DEBUG) && (nsegs > 1)) 71467196661SRafal Jaworowski if_printf(ifp, "TX buffer has %d segments\n", nsegs); 71567196661SRafal Jaworowski 71667196661SRafal Jaworowski /* Everything is ok, now we can send buffers */ 71767196661SRafal Jaworowski for (seg = 0; seg < nsegs; seg++) { 71867196661SRafal Jaworowski tx_desc = TSEC_GET_CUR_TX_DESC(sc); 71967196661SRafal Jaworowski 72067196661SRafal Jaworowski tx_desc->length = segs[seg].ds_len; 72167196661SRafal Jaworowski tx_desc->bufptr = segs[seg].ds_addr; 72267196661SRafal Jaworowski 72367196661SRafal Jaworowski tx_desc->flags = 72467196661SRafal Jaworowski (tx_desc->flags & TSEC_TXBD_W) | /* wrap */ 72567196661SRafal Jaworowski TSEC_TXBD_I | /* interrupt */ 72667196661SRafal Jaworowski TSEC_TXBD_R | /* ready to send */ 72767196661SRafal Jaworowski TSEC_TXBD_TC | /* transmit the CRC sequence 72867196661SRafal Jaworowski * after the last data byte */ 72967196661SRafal Jaworowski ((seg == nsegs-1) ? TSEC_TXBD_L : 0);/* last in frame */ 73067196661SRafal Jaworowski } 73167196661SRafal Jaworowski 73267196661SRafal Jaworowski /* Save mbuf and DMA mapping for release at later stage */ 73367196661SRafal Jaworowski TSEC_PUT_TX_MBUF(sc, m0); 73467196661SRafal Jaworowski TSEC_PUT_TX_MAP(sc, mapp); 73567196661SRafal Jaworowski 73667196661SRafal Jaworowski return (0); 73767196661SRafal Jaworowski } 73867196661SRafal Jaworowski 73967196661SRafal Jaworowski static void 74067196661SRafal Jaworowski tsec_setfilter(struct tsec_softc *sc) 74167196661SRafal Jaworowski { 74267196661SRafal Jaworowski struct ifnet *ifp; 74367196661SRafal Jaworowski uint32_t flags; 74467196661SRafal Jaworowski 74567196661SRafal Jaworowski ifp = sc->tsec_ifp; 74667196661SRafal Jaworowski flags = TSEC_READ(sc, TSEC_REG_RCTRL); 74767196661SRafal Jaworowski 74867196661SRafal Jaworowski /* Promiscuous mode */ 74967196661SRafal Jaworowski if (ifp->if_flags & IFF_PROMISC) 75067196661SRafal Jaworowski flags |= TSEC_RCTRL_PROM; 75167196661SRafal Jaworowski else 75267196661SRafal Jaworowski flags &= ~TSEC_RCTRL_PROM; 75367196661SRafal Jaworowski 75467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_RCTRL, flags); 75567196661SRafal Jaworowski } 75667196661SRafal Jaworowski 75767196661SRafal Jaworowski static int 75867196661SRafal Jaworowski tsec_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 75967196661SRafal Jaworowski { 76067196661SRafal Jaworowski struct tsec_softc *sc = ifp->if_softc; 76167196661SRafal Jaworowski struct ifreq *ifr = (struct ifreq *)data; 76267196661SRafal Jaworowski device_t dev; 76367196661SRafal Jaworowski int error = 0; 76467196661SRafal Jaworowski 76567196661SRafal Jaworowski dev = sc->dev; 76667196661SRafal Jaworowski 76767196661SRafal Jaworowski switch (command) { 76867196661SRafal Jaworowski case SIOCSIFFLAGS: 76967196661SRafal Jaworowski TSEC_GLOBAL_LOCK(sc); 77067196661SRafal Jaworowski if (ifp->if_flags & IFF_UP) { 77167196661SRafal Jaworowski if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 772321e12c8SRafal Jaworowski if ((sc->tsec_if_flags ^ ifp->if_flags) & IFF_PROMISC) 77367196661SRafal Jaworowski tsec_setfilter(sc); 77467196661SRafal Jaworowski } else 77567196661SRafal Jaworowski tsec_init_locked(sc); 776321e12c8SRafal Jaworowski } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 77767196661SRafal Jaworowski tsec_stop(sc); 778321e12c8SRafal Jaworowski 77967196661SRafal Jaworowski sc->tsec_if_flags = ifp->if_flags; 78067196661SRafal Jaworowski TSEC_GLOBAL_UNLOCK(sc); 78167196661SRafal Jaworowski break; 78267196661SRafal Jaworowski case SIOCGIFMEDIA: 78367196661SRafal Jaworowski case SIOCSIFMEDIA: 784321e12c8SRafal Jaworowski error = ifmedia_ioctl(ifp, ifr, &sc->tsec_mii->mii_media, command); 78567196661SRafal Jaworowski break; 78667196661SRafal Jaworowski default: 78767196661SRafal Jaworowski error = ether_ioctl(ifp, command, data); 78867196661SRafal Jaworowski } 78967196661SRafal Jaworowski 79067196661SRafal Jaworowski /* Flush buffers if not empty */ 79167196661SRafal Jaworowski if (ifp->if_flags & IFF_UP) 79267196661SRafal Jaworowski tsec_start(ifp); 79367196661SRafal Jaworowski return (error); 79467196661SRafal Jaworowski } 79567196661SRafal Jaworowski 79667196661SRafal Jaworowski static int 79767196661SRafal Jaworowski tsec_ifmedia_upd(struct ifnet *ifp) 79867196661SRafal Jaworowski { 79967196661SRafal Jaworowski struct tsec_softc *sc = ifp->if_softc; 80067196661SRafal Jaworowski struct mii_data *mii; 80167196661SRafal Jaworowski 80267196661SRafal Jaworowski TSEC_TRANSMIT_LOCK(sc); 80367196661SRafal Jaworowski 80467196661SRafal Jaworowski mii = sc->tsec_mii; 80567196661SRafal Jaworowski mii_mediachg(mii); 80667196661SRafal Jaworowski 80767196661SRafal Jaworowski TSEC_TRANSMIT_UNLOCK(sc); 80867196661SRafal Jaworowski return (0); 80967196661SRafal Jaworowski } 81067196661SRafal Jaworowski 81167196661SRafal Jaworowski static void 81267196661SRafal Jaworowski tsec_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 81367196661SRafal Jaworowski { 81467196661SRafal Jaworowski struct tsec_softc *sc = ifp->if_softc; 81567196661SRafal Jaworowski struct mii_data *mii; 81667196661SRafal Jaworowski 81767196661SRafal Jaworowski TSEC_TRANSMIT_LOCK(sc); 81867196661SRafal Jaworowski 81967196661SRafal Jaworowski mii = sc->tsec_mii; 82067196661SRafal Jaworowski mii_pollstat(mii); 82167196661SRafal Jaworowski 82267196661SRafal Jaworowski ifmr->ifm_active = mii->mii_media_active; 82367196661SRafal Jaworowski ifmr->ifm_status = mii->mii_media_status; 82467196661SRafal Jaworowski 82567196661SRafal Jaworowski TSEC_TRANSMIT_UNLOCK(sc); 82667196661SRafal Jaworowski } 82767196661SRafal Jaworowski 82867196661SRafal Jaworowski static int 82967196661SRafal Jaworowski tsec_new_rxbuf(bus_dma_tag_t tag, bus_dmamap_t map, struct mbuf **mbufp, 83067196661SRafal Jaworowski uint32_t *paddr) 83167196661SRafal Jaworowski { 83267196661SRafal Jaworowski struct mbuf *new_mbuf; 83367196661SRafal Jaworowski bus_dma_segment_t seg[1]; 83467196661SRafal Jaworowski int error; 83567196661SRafal Jaworowski int nsegs; 83667196661SRafal Jaworowski 83767196661SRafal Jaworowski KASSERT(mbufp != NULL, ("NULL mbuf pointer!")); 83867196661SRafal Jaworowski 83967196661SRafal Jaworowski new_mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 84067196661SRafal Jaworowski if (new_mbuf == NULL) 84167196661SRafal Jaworowski return (ENOBUFS); 84267196661SRafal Jaworowski new_mbuf->m_len = new_mbuf->m_pkthdr.len = new_mbuf->m_ext.ext_size; 84367196661SRafal Jaworowski 84467196661SRafal Jaworowski if (*mbufp) { 84567196661SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_POSTREAD); 84667196661SRafal Jaworowski bus_dmamap_unload(tag, map); 84767196661SRafal Jaworowski } 84867196661SRafal Jaworowski 84967196661SRafal Jaworowski error = bus_dmamap_load_mbuf_sg(tag, map, new_mbuf, seg, &nsegs, 85067196661SRafal Jaworowski BUS_DMA_NOWAIT); 85167196661SRafal Jaworowski KASSERT(nsegs == 1, ("Too many segments returned!")); 85267196661SRafal Jaworowski if (nsegs != 1 || error) 85367196661SRafal Jaworowski panic("tsec_new_rxbuf(): nsegs(%d), error(%d)", nsegs, error); 85467196661SRafal Jaworowski 85567196661SRafal Jaworowski #if 0 85667196661SRafal Jaworowski if (error) { 85767196661SRafal Jaworowski printf("tsec: bus_dmamap_load_mbuf_sg() returned: %d!\n", 85867196661SRafal Jaworowski error); 85967196661SRafal Jaworowski m_freem(new_mbuf); 86067196661SRafal Jaworowski return (ENOBUFS); 86167196661SRafal Jaworowski } 86267196661SRafal Jaworowski #endif 86367196661SRafal Jaworowski 86467196661SRafal Jaworowski #if 0 86567196661SRafal Jaworowski KASSERT(((seg->ds_addr) & (TSEC_RXBUFFER_ALIGNMENT-1)) == 0, 86667196661SRafal Jaworowski ("Wrong alignment of RX buffer!")); 86767196661SRafal Jaworowski #endif 86867196661SRafal Jaworowski bus_dmamap_sync(tag, map, BUS_DMASYNC_PREREAD); 86967196661SRafal Jaworowski 87067196661SRafal Jaworowski (*mbufp) = new_mbuf; 87167196661SRafal Jaworowski (*paddr) = seg->ds_addr; 87267196661SRafal Jaworowski return (0); 87367196661SRafal Jaworowski } 87467196661SRafal Jaworowski 87567196661SRafal Jaworowski static void 87667196661SRafal Jaworowski tsec_map_dma_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 87767196661SRafal Jaworowski { 87867196661SRafal Jaworowski u_int32_t *paddr; 87967196661SRafal Jaworowski 88067196661SRafal Jaworowski KASSERT(nseg == 1, ("wrong number of segments, should be 1")); 88167196661SRafal Jaworowski paddr = arg; 88267196661SRafal Jaworowski *paddr = segs->ds_addr; 88367196661SRafal Jaworowski } 88467196661SRafal Jaworowski 88567196661SRafal Jaworowski static int 88667196661SRafal Jaworowski tsec_alloc_dma_desc(device_t dev, bus_dma_tag_t *dtag, bus_dmamap_t *dmap, 88767196661SRafal Jaworowski bus_size_t dsize, void **vaddr, void *raddr, const char *dname) 88867196661SRafal Jaworowski { 88967196661SRafal Jaworowski int error; 89067196661SRafal Jaworowski 89167196661SRafal Jaworowski /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ 89267196661SRafal Jaworowski error = bus_dma_tag_create(NULL, /* parent */ 89367196661SRafal Jaworowski PAGE_SIZE, 0, /* alignment, boundary */ 89467196661SRafal Jaworowski BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 89567196661SRafal Jaworowski BUS_SPACE_MAXADDR, /* highaddr */ 89667196661SRafal Jaworowski NULL, NULL, /* filtfunc, filtfuncarg */ 89767196661SRafal Jaworowski dsize, 1, /* maxsize, nsegments */ 89867196661SRafal Jaworowski dsize, 0, /* maxsegsz, flags */ 89967196661SRafal Jaworowski NULL, NULL, /* lockfunc, lockfuncarg */ 90067196661SRafal Jaworowski dtag); /* dmat */ 90167196661SRafal Jaworowski 90267196661SRafal Jaworowski if (error) { 90367196661SRafal Jaworowski device_printf(dev, "failed to allocate busdma %s tag\n", dname); 90467196661SRafal Jaworowski (*vaddr) = NULL; 90567196661SRafal Jaworowski return (ENXIO); 90667196661SRafal Jaworowski } 90767196661SRafal Jaworowski 90867196661SRafal Jaworowski error = bus_dmamem_alloc(*dtag, vaddr, BUS_DMA_NOWAIT | BUS_DMA_ZERO, 90967196661SRafal Jaworowski dmap); 91067196661SRafal Jaworowski if (error) { 91167196661SRafal Jaworowski device_printf(dev, "failed to allocate %s DMA safe memory\n", 91267196661SRafal Jaworowski dname); 91367196661SRafal Jaworowski bus_dma_tag_destroy(*dtag); 91467196661SRafal Jaworowski (*vaddr) = NULL; 91567196661SRafal Jaworowski return (ENXIO); 91667196661SRafal Jaworowski } 91767196661SRafal Jaworowski 91867196661SRafal Jaworowski error = bus_dmamap_load(*dtag, *dmap, *vaddr, dsize, tsec_map_dma_addr, 91967196661SRafal Jaworowski raddr, BUS_DMA_NOWAIT); 92067196661SRafal Jaworowski if (error) { 92167196661SRafal Jaworowski device_printf(dev, "cannot get address of the %s descriptors\n", 92267196661SRafal Jaworowski dname); 92367196661SRafal Jaworowski bus_dmamem_free(*dtag, *vaddr, *dmap); 92467196661SRafal Jaworowski bus_dma_tag_destroy(*dtag); 92567196661SRafal Jaworowski (*vaddr) = NULL; 92667196661SRafal Jaworowski return (ENXIO); 92767196661SRafal Jaworowski } 92867196661SRafal Jaworowski 92967196661SRafal Jaworowski return (0); 93067196661SRafal Jaworowski } 93167196661SRafal Jaworowski 93267196661SRafal Jaworowski static void 93367196661SRafal Jaworowski tsec_free_dma_desc(bus_dma_tag_t dtag, bus_dmamap_t dmap, void *vaddr) 93467196661SRafal Jaworowski { 93567196661SRafal Jaworowski 93667196661SRafal Jaworowski if (vaddr == NULL) 93767196661SRafal Jaworowski return; 93867196661SRafal Jaworowski 93967196661SRafal Jaworowski /* Unmap descriptors from DMA memory */ 94067196661SRafal Jaworowski bus_dmamap_sync(dtag, dmap, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 94167196661SRafal Jaworowski bus_dmamap_unload(dtag, dmap); 94267196661SRafal Jaworowski 94367196661SRafal Jaworowski /* Free descriptors memory */ 94467196661SRafal Jaworowski bus_dmamem_free(dtag, vaddr, dmap); 94567196661SRafal Jaworowski 94667196661SRafal Jaworowski /* Destroy descriptors tag */ 94767196661SRafal Jaworowski bus_dma_tag_destroy(dtag); 94867196661SRafal Jaworowski } 94967196661SRafal Jaworowski 95067196661SRafal Jaworowski static void 95167196661SRafal Jaworowski tsec_free_dma(struct tsec_softc *sc) 95267196661SRafal Jaworowski { 95367196661SRafal Jaworowski int i; 95467196661SRafal Jaworowski 95567196661SRafal Jaworowski /* Free TX maps */ 95667196661SRafal Jaworowski for (i = 0; i < TSEC_TX_NUM_DESC; i++) 95767196661SRafal Jaworowski if (sc->tx_map_data[i] != NULL) 958321e12c8SRafal Jaworowski bus_dmamap_destroy(sc->tsec_tx_mtag, sc->tx_map_data[i]); 95967196661SRafal Jaworowski /* Destroy tag for Tx mbufs */ 96067196661SRafal Jaworowski bus_dma_tag_destroy(sc->tsec_tx_mtag); 96167196661SRafal Jaworowski 96267196661SRafal Jaworowski /* Free RX mbufs and maps */ 96367196661SRafal Jaworowski for (i = 0; i < TSEC_RX_NUM_DESC; i++) { 96467196661SRafal Jaworowski if (sc->rx_data[i].mbuf) { 96567196661SRafal Jaworowski /* Unload buffer from DMA */ 96667196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_rx_mtag, sc->rx_data[i].map, 96767196661SRafal Jaworowski BUS_DMASYNC_POSTREAD); 96867196661SRafal Jaworowski bus_dmamap_unload(sc->tsec_rx_mtag, sc->rx_data[i].map); 96967196661SRafal Jaworowski 97067196661SRafal Jaworowski /* Free buffer */ 97167196661SRafal Jaworowski m_freem(sc->rx_data[i].mbuf); 97267196661SRafal Jaworowski } 97367196661SRafal Jaworowski /* Destroy map for this buffer */ 97467196661SRafal Jaworowski if (sc->rx_data[i].map != NULL) 97567196661SRafal Jaworowski bus_dmamap_destroy(sc->tsec_rx_mtag, 97667196661SRafal Jaworowski sc->rx_data[i].map); 97767196661SRafal Jaworowski } 97867196661SRafal Jaworowski /* Destroy tag for Rx mbufs */ 97967196661SRafal Jaworowski bus_dma_tag_destroy(sc->tsec_rx_mtag); 98067196661SRafal Jaworowski 98167196661SRafal Jaworowski /* Unload TX/RX descriptors */ 98267196661SRafal Jaworowski tsec_free_dma_desc(sc->tsec_tx_dtag, sc->tsec_tx_dmap, 98367196661SRafal Jaworowski sc->tsec_tx_vaddr); 98467196661SRafal Jaworowski tsec_free_dma_desc(sc->tsec_rx_dtag, sc->tsec_rx_dmap, 98567196661SRafal Jaworowski sc->tsec_rx_vaddr); 98667196661SRafal Jaworowski } 98767196661SRafal Jaworowski 98867196661SRafal Jaworowski static void 98967196661SRafal Jaworowski tsec_stop(struct tsec_softc *sc) 99067196661SRafal Jaworowski { 99167196661SRafal Jaworowski struct ifnet *ifp; 99267196661SRafal Jaworowski struct mbuf *m0; 99367196661SRafal Jaworowski bus_dmamap_t *mapp; 99467196661SRafal Jaworowski uint32_t tmpval; 99567196661SRafal Jaworowski 99667196661SRafal Jaworowski TSEC_GLOBAL_LOCK_ASSERT(sc); 99767196661SRafal Jaworowski 99867196661SRafal Jaworowski ifp = sc->tsec_ifp; 99967196661SRafal Jaworowski 10005432bd9fSRafal Jaworowski /* Stop tick engine */ 10015432bd9fSRafal Jaworowski callout_stop(&sc->tsec_callout); 100267196661SRafal Jaworowski 100367196661SRafal Jaworowski /* Disable interface and watchdog timer */ 100467196661SRafal Jaworowski ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 10055432bd9fSRafal Jaworowski sc->tsec_watchdog = 0; 100667196661SRafal Jaworowski 100767196661SRafal Jaworowski /* Disable all interrupts and stop DMA */ 100867196661SRafal Jaworowski tsec_intrs_ctl(sc, 0); 100967196661SRafal Jaworowski tsec_dma_ctl(sc, 0); 101067196661SRafal Jaworowski 101167196661SRafal Jaworowski /* Remove pending data from TX queue */ 101267196661SRafal Jaworowski while (!TSEC_EMPTYQ_TX_MBUF(sc)) { 101367196661SRafal Jaworowski m0 = TSEC_GET_TX_MBUF(sc); 101467196661SRafal Jaworowski mapp = TSEC_GET_TX_MAP(sc); 101567196661SRafal Jaworowski 101667196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_mtag, *mapp, BUS_DMASYNC_POSTWRITE); 101767196661SRafal Jaworowski bus_dmamap_unload(sc->tsec_tx_mtag, *mapp); 101867196661SRafal Jaworowski 101967196661SRafal Jaworowski TSEC_FREE_TX_MAP(sc, mapp); 102067196661SRafal Jaworowski m_freem(m0); 102167196661SRafal Jaworowski } 102267196661SRafal Jaworowski 102367196661SRafal Jaworowski /* Disable Rx and Tx */ 102467196661SRafal Jaworowski tmpval = TSEC_READ(sc, TSEC_REG_MACCFG1); 102567196661SRafal Jaworowski tmpval &= ~(TSEC_MACCFG1_RX_EN | TSEC_MACCFG1_TX_EN); 102667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG1, tmpval); 102767196661SRafal Jaworowski DELAY(10); 102867196661SRafal Jaworowski } 102967196661SRafal Jaworowski 1030321e12c8SRafal Jaworowski void 103167196661SRafal Jaworowski tsec_receive_intr(void *arg) 103267196661SRafal Jaworowski { 103367196661SRafal Jaworowski struct mbuf *rcv_mbufs[TSEC_RX_NUM_DESC]; 103467196661SRafal Jaworowski struct tsec_softc *sc = arg; 103567196661SRafal Jaworowski struct tsec_desc *rx_desc; 103667196661SRafal Jaworowski struct ifnet *ifp; 103767196661SRafal Jaworowski struct rx_data_type *rx_data; 103867196661SRafal Jaworowski struct mbuf *m; 103967196661SRafal Jaworowski device_t dev; 104067196661SRafal Jaworowski uint32_t i; 104167196661SRafal Jaworowski int count; 104267196661SRafal Jaworowski int c1 = 0; 104367196661SRafal Jaworowski int c2; 104467196661SRafal Jaworowski uint16_t flags; 104567196661SRafal Jaworowski uint16_t length; 104667196661SRafal Jaworowski 104767196661SRafal Jaworowski ifp = sc->tsec_ifp; 104867196661SRafal Jaworowski rx_data = sc->rx_data; 104967196661SRafal Jaworowski dev = sc->dev; 105067196661SRafal Jaworowski 105167196661SRafal Jaworowski /* Confirm the interrupt was received by driver */ 105267196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, TSEC_IEVENT_RXB | TSEC_IEVENT_RXF); 105367196661SRafal Jaworowski 105467196661SRafal Jaworowski TSEC_RECEIVE_LOCK(sc); 105567196661SRafal Jaworowski 105667196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_rx_dtag, sc->tsec_rx_dmap, BUS_DMASYNC_POSTREAD | 105767196661SRafal Jaworowski BUS_DMASYNC_POSTWRITE); 105867196661SRafal Jaworowski 105967196661SRafal Jaworowski for (count = 0; /* count < TSEC_RX_NUM_DESC */; count++) { 106067196661SRafal Jaworowski rx_desc = TSEC_GET_CUR_RX_DESC(sc); 106167196661SRafal Jaworowski flags = rx_desc->flags; 106267196661SRafal Jaworowski 106367196661SRafal Jaworowski /* Check if there is anything to receive */ 106467196661SRafal Jaworowski if ((flags & TSEC_RXBD_E) || (count >= TSEC_RX_NUM_DESC)) { 106567196661SRafal Jaworowski /* 106667196661SRafal Jaworowski * Avoid generating another interrupt 106767196661SRafal Jaworowski */ 106867196661SRafal Jaworowski if (flags & TSEC_RXBD_E) 106967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, 107067196661SRafal Jaworowski TSEC_IEVENT_RXB | TSEC_IEVENT_RXF); 107167196661SRafal Jaworowski /* 107267196661SRafal Jaworowski * We didn't consume current descriptor and have to 107367196661SRafal Jaworowski * return it to the queue 107467196661SRafal Jaworowski */ 107567196661SRafal Jaworowski TSEC_BACK_CUR_RX_DESC(sc); 107667196661SRafal Jaworowski break; 107767196661SRafal Jaworowski } 107867196661SRafal Jaworowski 107967196661SRafal Jaworowski if (flags & (TSEC_RXBD_LG | TSEC_RXBD_SH | TSEC_RXBD_NO | 108067196661SRafal Jaworowski TSEC_RXBD_CR | TSEC_RXBD_OV | TSEC_RXBD_TR)) { 1081321e12c8SRafal Jaworowski 108267196661SRafal Jaworowski rx_desc->length = 0; 1083321e12c8SRafal Jaworowski rx_desc->flags = (rx_desc->flags & ~TSEC_RXBD_ZEROONINIT) | 1084321e12c8SRafal Jaworowski TSEC_RXBD_E | TSEC_RXBD_I; 108567196661SRafal Jaworowski continue; 108667196661SRafal Jaworowski } 108767196661SRafal Jaworowski 108867196661SRafal Jaworowski if ((flags & TSEC_RXBD_L) == 0) 108967196661SRafal Jaworowski device_printf(dev, "buf is not the last in frame!\n"); 109067196661SRafal Jaworowski 109167196661SRafal Jaworowski /* Ok... process frame */ 109267196661SRafal Jaworowski length = rx_desc->length - ETHER_CRC_LEN; 109367196661SRafal Jaworowski i = TSEC_GET_CUR_RX_DESC_CNT(sc); 109467196661SRafal Jaworowski 109567196661SRafal Jaworowski m = rx_data[i].mbuf; 109667196661SRafal Jaworowski 109767196661SRafal Jaworowski if (tsec_new_rxbuf(sc->tsec_rx_mtag, rx_data[i].map, 109867196661SRafal Jaworowski &rx_data[i].mbuf, &rx_data[i].paddr)) { 109967196661SRafal Jaworowski ifp->if_ierrors++; 110067196661SRafal Jaworowski continue; 110167196661SRafal Jaworowski } 110267196661SRafal Jaworowski /* Attach new buffer to descriptor, and clear flags */ 110367196661SRafal Jaworowski rx_desc->bufptr = rx_data[i].paddr; 110467196661SRafal Jaworowski rx_desc->length = 0; 110567196661SRafal Jaworowski rx_desc->flags = (rx_desc->flags & ~TSEC_RXBD_ZEROONINIT) | 110667196661SRafal Jaworowski TSEC_RXBD_E | TSEC_RXBD_I; 110767196661SRafal Jaworowski 110867196661SRafal Jaworowski /* Prepare buffer for upper layers */ 110967196661SRafal Jaworowski m->m_pkthdr.rcvif = ifp; 111067196661SRafal Jaworowski m->m_pkthdr.len = m->m_len = length; 111167196661SRafal Jaworowski 111267196661SRafal Jaworowski /* Save it for push */ 111367196661SRafal Jaworowski rcv_mbufs[c1++] = m; 111467196661SRafal Jaworowski } 111567196661SRafal Jaworowski 1116321e12c8SRafal Jaworowski bus_dmamap_sync(sc->tsec_rx_dtag, sc->tsec_rx_dmap, BUS_DMASYNC_PREREAD | 1117321e12c8SRafal Jaworowski BUS_DMASYNC_PREWRITE); 111867196661SRafal Jaworowski 111967196661SRafal Jaworowski TSEC_RECEIVE_UNLOCK(sc); 112067196661SRafal Jaworowski 112167196661SRafal Jaworowski /* Push it now */ 112267196661SRafal Jaworowski for (c2 = 0; c2 < c1; c2++) 112367196661SRafal Jaworowski (*ifp->if_input)(ifp, rcv_mbufs[c2]); 112467196661SRafal Jaworowski } 112567196661SRafal Jaworowski 1126321e12c8SRafal Jaworowski void 112767196661SRafal Jaworowski tsec_transmit_intr(void *arg) 112867196661SRafal Jaworowski { 112967196661SRafal Jaworowski struct tsec_softc *sc = arg; 113067196661SRafal Jaworowski struct tsec_desc *tx_desc; 113167196661SRafal Jaworowski struct ifnet *ifp; 113267196661SRafal Jaworowski struct mbuf *m0; 113367196661SRafal Jaworowski bus_dmamap_t *mapp; 113467196661SRafal Jaworowski int send = 0; 113567196661SRafal Jaworowski 113667196661SRafal Jaworowski ifp = sc->tsec_ifp; 113767196661SRafal Jaworowski 113867196661SRafal Jaworowski /* Confirm the interrupt was received by driver */ 113967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, TSEC_IEVENT_TXB | TSEC_IEVENT_TXF); 114067196661SRafal Jaworowski 114167196661SRafal Jaworowski TSEC_TRANSMIT_LOCK(sc); 114267196661SRafal Jaworowski 114367196661SRafal Jaworowski /* Update collision statistics */ 114467196661SRafal Jaworowski ifp->if_collisions += TSEC_READ(sc, TSEC_REG_MON_TNCL); 114567196661SRafal Jaworowski 114667196661SRafal Jaworowski /* Reset collision counters in hardware */ 114767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TSCL, 0); 114867196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TMCL, 0); 114967196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TLCL, 0); 115067196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TXCL, 0); 115167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MON_TNCL, 0); 115267196661SRafal Jaworowski 1153321e12c8SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, 1154321e12c8SRafal Jaworowski BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 115567196661SRafal Jaworowski 115667196661SRafal Jaworowski while (TSEC_CUR_DIFF_DIRTY_TX_DESC(sc)) { 115767196661SRafal Jaworowski tx_desc = TSEC_GET_DIRTY_TX_DESC(sc); 115867196661SRafal Jaworowski if (tx_desc->flags & TSEC_TXBD_R) { 115967196661SRafal Jaworowski TSEC_BACK_DIRTY_TX_DESC(sc); 116067196661SRafal Jaworowski break; 116167196661SRafal Jaworowski } 116267196661SRafal Jaworowski 116367196661SRafal Jaworowski if ((tx_desc->flags & TSEC_TXBD_L) == 0) 116467196661SRafal Jaworowski continue; 116567196661SRafal Jaworowski 116667196661SRafal Jaworowski /* 116767196661SRafal Jaworowski * This is the last buf in this packet, so unmap and free it. 116867196661SRafal Jaworowski */ 116967196661SRafal Jaworowski m0 = TSEC_GET_TX_MBUF(sc); 117067196661SRafal Jaworowski mapp = TSEC_GET_TX_MAP(sc); 117167196661SRafal Jaworowski 117267196661SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_mtag, *mapp, BUS_DMASYNC_POSTWRITE); 117367196661SRafal Jaworowski bus_dmamap_unload(sc->tsec_tx_mtag, *mapp); 117467196661SRafal Jaworowski 117567196661SRafal Jaworowski TSEC_FREE_TX_MAP(sc, mapp); 117667196661SRafal Jaworowski m_freem(m0); 117767196661SRafal Jaworowski 117867196661SRafal Jaworowski ifp->if_opackets++; 117967196661SRafal Jaworowski send = 1; 118067196661SRafal Jaworowski } 1181321e12c8SRafal Jaworowski bus_dmamap_sync(sc->tsec_tx_dtag, sc->tsec_tx_dmap, BUS_DMASYNC_PREREAD | 1182321e12c8SRafal Jaworowski BUS_DMASYNC_PREWRITE); 118367196661SRafal Jaworowski 118467196661SRafal Jaworowski if (send) { 118567196661SRafal Jaworowski /* Now send anything that was pending */ 118667196661SRafal Jaworowski ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 118767196661SRafal Jaworowski tsec_start_locked(ifp); 118867196661SRafal Jaworowski 1189772619e1SRafal Jaworowski /* Stop watchdog if all sent */ 119067196661SRafal Jaworowski if (TSEC_EMPTYQ_TX_MBUF(sc)) 11915432bd9fSRafal Jaworowski sc->tsec_watchdog = 0; 119267196661SRafal Jaworowski } 119367196661SRafal Jaworowski TSEC_TRANSMIT_UNLOCK(sc); 119467196661SRafal Jaworowski } 119567196661SRafal Jaworowski 1196321e12c8SRafal Jaworowski void 119767196661SRafal Jaworowski tsec_error_intr(void *arg) 119867196661SRafal Jaworowski { 119967196661SRafal Jaworowski struct tsec_softc *sc = arg; 120067196661SRafal Jaworowski struct ifnet *ifp; 120167196661SRafal Jaworowski uint32_t eflags; 120267196661SRafal Jaworowski 120367196661SRafal Jaworowski ifp = sc->tsec_ifp; 120467196661SRafal Jaworowski 120567196661SRafal Jaworowski eflags = TSEC_READ(sc, TSEC_REG_IEVENT); 120667196661SRafal Jaworowski 120767196661SRafal Jaworowski if (ifp->if_flags & IFF_DEBUG) 120867196661SRafal Jaworowski if_printf(ifp, "tsec_error_intr(): event flags: 0x%x\n", eflags); 120967196661SRafal Jaworowski 121067196661SRafal Jaworowski /* Clear events bits in hardware */ 121167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_IEVENT, TSEC_IEVENT_RXC | TSEC_IEVENT_BSY | 121267196661SRafal Jaworowski TSEC_IEVENT_EBERR | TSEC_IEVENT_MSRO | TSEC_IEVENT_BABT | 121367196661SRafal Jaworowski TSEC_IEVENT_TXC | TSEC_IEVENT_TXE | TSEC_IEVENT_LC | 121467196661SRafal Jaworowski TSEC_IEVENT_CRL | TSEC_IEVENT_XFUN); 121567196661SRafal Jaworowski 121667196661SRafal Jaworowski if (eflags & TSEC_IEVENT_EBERR) 121767196661SRafal Jaworowski if_printf(ifp, "System bus error occurred during" 121867196661SRafal Jaworowski " a DMA transaction (flags: 0x%x)\n", eflags); 121967196661SRafal Jaworowski 122067196661SRafal Jaworowski /* Check transmitter errors */ 122167196661SRafal Jaworowski if (eflags & TSEC_IEVENT_TXE) { 122267196661SRafal Jaworowski ifp->if_oerrors++; 122367196661SRafal Jaworowski 122467196661SRafal Jaworowski if (eflags & TSEC_IEVENT_LC) 122567196661SRafal Jaworowski ifp->if_collisions++; 122667196661SRafal Jaworowski 122767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_TSTAT, TSEC_TSTAT_THLT); 122867196661SRafal Jaworowski } 122967196661SRafal Jaworowski if (eflags & TSEC_IEVENT_BABT) 123067196661SRafal Jaworowski ifp->if_oerrors++; 123167196661SRafal Jaworowski 123267196661SRafal Jaworowski /* Check receiver errors */ 123367196661SRafal Jaworowski if (eflags & TSEC_IEVENT_BSY) { 123467196661SRafal Jaworowski ifp->if_ierrors++; 123567196661SRafal Jaworowski ifp->if_iqdrops++; 123667196661SRafal Jaworowski 123767196661SRafal Jaworowski /* Get data from RX buffers */ 123867196661SRafal Jaworowski tsec_receive_intr(arg); 123967196661SRafal Jaworowski 124067196661SRafal Jaworowski /* Make receiver again active */ 124167196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_RSTAT, TSEC_RSTAT_QHLT); 124267196661SRafal Jaworowski } 124367196661SRafal Jaworowski if (eflags & TSEC_IEVENT_BABR) 124467196661SRafal Jaworowski ifp->if_ierrors++; 124567196661SRafal Jaworowski } 124667196661SRafal Jaworowski 124767196661SRafal Jaworowski static void 1248772619e1SRafal Jaworowski tsec_tick(void *xsc) 124967196661SRafal Jaworowski { 1250772619e1SRafal Jaworowski struct tsec_softc *sc = xsc; 125167196661SRafal Jaworowski struct ifnet *ifp; 125267196661SRafal Jaworowski int link; 125367196661SRafal Jaworowski 1254772619e1SRafal Jaworowski TSEC_GLOBAL_LOCK(sc); 1255772619e1SRafal Jaworowski 1256772619e1SRafal Jaworowski tsec_watchdog(sc); 125767196661SRafal Jaworowski 125867196661SRafal Jaworowski ifp = sc->tsec_ifp; 125967196661SRafal Jaworowski link = sc->tsec_link; 126067196661SRafal Jaworowski 126167196661SRafal Jaworowski mii_tick(sc->tsec_mii); 126267196661SRafal Jaworowski 126367196661SRafal Jaworowski if (link == 0 && sc->tsec_link == 1 && (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))) 126467196661SRafal Jaworowski tsec_start_locked(ifp); 126567196661SRafal Jaworowski 1266772619e1SRafal Jaworowski /* Schedule another timeout one second from now. */ 12675432bd9fSRafal Jaworowski callout_reset(&sc->tsec_callout, hz, tsec_tick, sc); 1268772619e1SRafal Jaworowski 1269772619e1SRafal Jaworowski TSEC_GLOBAL_UNLOCK(sc); 127067196661SRafal Jaworowski } 127167196661SRafal Jaworowski 1272321e12c8SRafal Jaworowski int 127367196661SRafal Jaworowski tsec_miibus_readreg(device_t dev, int phy, int reg) 127467196661SRafal Jaworowski { 127567196661SRafal Jaworowski struct tsec_softc *sc; 127667196661SRafal Jaworowski uint32_t timeout; 127767196661SRafal Jaworowski 127867196661SRafal Jaworowski sc = device_get_softc(dev); 127967196661SRafal Jaworowski 128067196661SRafal Jaworowski if (device_get_unit(dev) != phy) 128167196661SRafal Jaworowski return (0); 128267196661SRafal Jaworowski 128367196661SRafal Jaworowski sc = tsec0_sc; 128467196661SRafal Jaworowski 128567196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMADD, (phy << 8) | reg); 128667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMCOM, 0); 128767196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMCOM, TSEC_MIIMCOM_READCYCLE); 128867196661SRafal Jaworowski 128967196661SRafal Jaworowski timeout = TSEC_READ_RETRY; 129067196661SRafal Jaworowski while (--timeout && TSEC_READ(sc, TSEC_REG_MIIMIND) & 129167196661SRafal Jaworowski (TSEC_MIIMIND_NOTVALID | TSEC_MIIMIND_BUSY)) 129267196661SRafal Jaworowski DELAY(TSEC_READ_DELAY); 129367196661SRafal Jaworowski 129467196661SRafal Jaworowski if (timeout == 0) 129567196661SRafal Jaworowski device_printf(dev, "Timeout while reading from PHY!\n"); 129667196661SRafal Jaworowski 129767196661SRafal Jaworowski return (TSEC_READ(sc, TSEC_REG_MIIMSTAT)); 129867196661SRafal Jaworowski } 129967196661SRafal Jaworowski 1300321e12c8SRafal Jaworowski void 130167196661SRafal Jaworowski tsec_miibus_writereg(device_t dev, int phy, int reg, int value) 130267196661SRafal Jaworowski { 130367196661SRafal Jaworowski struct tsec_softc *sc; 130467196661SRafal Jaworowski uint32_t timeout; 130567196661SRafal Jaworowski 130667196661SRafal Jaworowski sc = device_get_softc(dev); 130767196661SRafal Jaworowski 130867196661SRafal Jaworowski if (device_get_unit(dev) != phy) 130967196661SRafal Jaworowski device_printf(dev, "Trying to write to an alien PHY(%d)\n", phy); 131067196661SRafal Jaworowski 131167196661SRafal Jaworowski sc = tsec0_sc; 131267196661SRafal Jaworowski 131367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMADD, (phy << 8) | reg); 131467196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MIIMCON, value); 131567196661SRafal Jaworowski 131667196661SRafal Jaworowski timeout = TSEC_READ_RETRY; 131767196661SRafal Jaworowski while (--timeout && (TSEC_READ(sc, TSEC_REG_MIIMIND) & TSEC_MIIMIND_BUSY)) 131867196661SRafal Jaworowski DELAY(TSEC_READ_DELAY); 131967196661SRafal Jaworowski 132067196661SRafal Jaworowski if (timeout == 0) 132167196661SRafal Jaworowski device_printf(dev, "Timeout while writing to PHY!\n"); 132267196661SRafal Jaworowski } 132367196661SRafal Jaworowski 1324321e12c8SRafal Jaworowski void 132567196661SRafal Jaworowski tsec_miibus_statchg(device_t dev) 132667196661SRafal Jaworowski { 132767196661SRafal Jaworowski struct tsec_softc *sc; 132867196661SRafal Jaworowski struct mii_data *mii; 132967196661SRafal Jaworowski uint32_t ecntrl, id, tmp; 133067196661SRafal Jaworowski int link; 133167196661SRafal Jaworowski 133267196661SRafal Jaworowski sc = device_get_softc(dev); 133367196661SRafal Jaworowski mii = sc->tsec_mii; 133467196661SRafal Jaworowski link = ((mii->mii_media_status & IFM_ACTIVE) ? 1 : 0); 133567196661SRafal Jaworowski 133667196661SRafal Jaworowski tmp = TSEC_READ(sc, TSEC_REG_MACCFG2) & ~TSEC_MACCFG2_IF; 133767196661SRafal Jaworowski 133867196661SRafal Jaworowski if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) 133967196661SRafal Jaworowski tmp |= TSEC_MACCFG2_FULLDUPLEX; 134067196661SRafal Jaworowski else 134167196661SRafal Jaworowski tmp &= ~TSEC_MACCFG2_FULLDUPLEX; 134267196661SRafal Jaworowski 134367196661SRafal Jaworowski switch (IFM_SUBTYPE(mii->mii_media_active)) { 134467196661SRafal Jaworowski case IFM_1000_T: 134567196661SRafal Jaworowski case IFM_1000_SX: 134667196661SRafal Jaworowski tmp |= TSEC_MACCFG2_GMII; 134767196661SRafal Jaworowski sc->tsec_link = link; 134867196661SRafal Jaworowski break; 134967196661SRafal Jaworowski case IFM_100_TX: 135067196661SRafal Jaworowski case IFM_10_T: 135167196661SRafal Jaworowski tmp |= TSEC_MACCFG2_MII; 135267196661SRafal Jaworowski sc->tsec_link = link; 135367196661SRafal Jaworowski break; 135467196661SRafal Jaworowski case IFM_NONE: 135567196661SRafal Jaworowski if (link) 135667196661SRafal Jaworowski device_printf(dev, "No speed selected but link active!\n"); 135767196661SRafal Jaworowski sc->tsec_link = 0; 135867196661SRafal Jaworowski return; 135967196661SRafal Jaworowski default: 136067196661SRafal Jaworowski sc->tsec_link = 0; 136167196661SRafal Jaworowski device_printf(dev, "Unknown speed (%d), link %s!\n", 136267196661SRafal Jaworowski IFM_SUBTYPE(mii->mii_media_active), 136367196661SRafal Jaworowski ((link) ? "up" : "down")); 136467196661SRafal Jaworowski return; 136567196661SRafal Jaworowski } 136667196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_MACCFG2, tmp); 136767196661SRafal Jaworowski 136867196661SRafal Jaworowski /* XXX kludge - use circumstantial evidence for reduced mode. */ 136967196661SRafal Jaworowski id = TSEC_READ(sc, TSEC_REG_ID2); 137067196661SRafal Jaworowski if (id & 0xffff) { 137167196661SRafal Jaworowski ecntrl = TSEC_READ(sc, TSEC_REG_ECNTRL) & ~TSEC_ECNTRL_R100M; 137267196661SRafal Jaworowski ecntrl |= (tmp & TSEC_MACCFG2_MII) ? TSEC_ECNTRL_R100M : 0; 137367196661SRafal Jaworowski TSEC_WRITE(sc, TSEC_REG_ECNTRL, ecntrl); 137467196661SRafal Jaworowski } 137567196661SRafal Jaworowski } 1376