1178173Simp/* $NetBSD: if_admsw.c,v 1.3 2007/04/22 19:26:25 dyoung Exp $ */ 2178173Simp 3178173Simp/*- 4178173Simp * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. 5178173Simp * All rights reserved. 6178173Simp * 7178173Simp * Redistribution and use in source and binary forms, with or 8178173Simp * without modification, are permitted provided that the following 9178173Simp * conditions are met: 10178173Simp * 1. Redistributions of source code must retain the above copyright 11178173Simp * notice, this list of conditions and the following disclaimer. 12178173Simp * 2. Redistributions in binary form must reproduce the above 13178173Simp * copyright notice, this list of conditions and the following 14178173Simp * disclaimer in the documentation and/or other materials provided 15178173Simp * with the distribution. 16178173Simp * 3. The names of the authors may not be used to endorse or promote 17178173Simp * products derived from this software without specific prior 18178173Simp * written permission. 19178173Simp * 20178173Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY 21178173Simp * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22178173Simp * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23178173Simp * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 24178173Simp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 25178173Simp * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26178173Simp * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 27178173Simp * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28178173Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 29178173Simp * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30178173Simp * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 31178173Simp * OF SUCH DAMAGE. 32178173Simp */ 33178173Simp/* 34178173Simp * Copyright (c) 2001 Wasabi Systems, Inc. 35178173Simp * All rights reserved. 36178173Simp * 37178173Simp * Written by Jason R. Thorpe for Wasabi Systems, Inc. 38178173Simp * 39178173Simp * Redistribution and use in source and binary forms, with or without 40178173Simp * modification, are permitted provided that the following conditions 41178173Simp * are met: 42178173Simp * 1. Redistributions of source code must retain the above copyright 43178173Simp * notice, this list of conditions and the following disclaimer. 44178173Simp * 2. Redistributions in binary form must reproduce the above copyright 45178173Simp * notice, this list of conditions and the following disclaimer in the 46178173Simp * documentation and/or other materials provided with the distribution. 47178173Simp * 3. All advertising materials mentioning features or use of this software 48178173Simp * must display the following acknowledgement: 49178173Simp * This product includes software developed for the NetBSD Project by 50178173Simp * Wasabi Systems, Inc. 51178173Simp * 4. The name of Wasabi Systems, Inc. may not be used to endorse 52178173Simp * or promote products derived from this software without specific prior 53178173Simp * written permission. 54178173Simp * 55178173Simp * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 56178173Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 57178173Simp * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 58178173Simp * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 59178173Simp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60178173Simp * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61178173Simp * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62178173Simp * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63178173Simp * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64178173Simp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65178173Simp * POSSIBILITY OF SUCH DAMAGE. 66178173Simp */ 67178173Simp 68178173Simp/* 69178173Simp * Device driver for Alchemy Semiconductor Au1x00 Ethernet Media 70178173Simp * Access Controller. 71178173Simp * 72178173Simp * TODO: 73178173Simp * 74178173Simp * Better Rx buffer management; we want to get new Rx buffers 75178173Simp * to the chip more quickly than we currently do. 76178173Simp */ 77178173Simp 78178173Simp#include <sys/cdefs.h> 79178173Simp__FBSDID("$FreeBSD$"); 80178173Simp 81178173Simp#include <sys/param.h> 82178173Simp#include <sys/systm.h> 83178173Simp#include <sys/bus.h> 84178173Simp#include <sys/kernel.h> 85178173Simp#include <sys/mbuf.h> 86178173Simp#include <sys/malloc.h> 87178173Simp#include <sys/module.h> 88178173Simp#include <sys/rman.h> 89178173Simp#include <sys/socket.h> 90178173Simp#include <sys/sockio.h> 91178173Simp#include <sys/sysctl.h> 92178173Simp#include <machine/bus.h> 93178173Simp 94178173Simp#include <net/ethernet.h> 95178173Simp#include <net/if.h> 96178173Simp#include <net/if_arp.h> 97178173Simp#include <net/if_dl.h> 98178173Simp#include <net/if_media.h> 99178173Simp#include <net/if_mib.h> 100178173Simp#include <net/if_types.h> 101178173Simp 102178173Simp#ifdef INET 103178173Simp#include <netinet/in.h> 104178173Simp#include <netinet/in_systm.h> 105178173Simp#include <netinet/in_var.h> 106178173Simp#include <netinet/ip.h> 107178173Simp#endif 108178173Simp 109178173Simp#include <net/bpf.h> 110178173Simp#include <net/bpfdesc.h> 111178173Simp 112182901Sgonzo#include <mips/adm5120/adm5120reg.h> 113182901Sgonzo#include <mips/adm5120/if_admswreg.h> 114182901Sgonzo#include <mips/adm5120/if_admswvar.h> 115178173Simp 116178173Simp/* TODO: add locking */ 117178173Simp#define ADMSW_LOCK(sc) do {} while(0); 118178173Simp#define ADMSW_UNLOCK(sc) do {} while(0); 119178173Simp 120178173Simpstatic uint8_t vlan_matrix[SW_DEVS] = { 121178173Simp (1 << 6) | (1 << 0), /* CPU + port0 */ 122178173Simp (1 << 6) | (1 << 1), /* CPU + port1 */ 123178173Simp (1 << 6) | (1 << 2), /* CPU + port2 */ 124178173Simp (1 << 6) | (1 << 3), /* CPU + port3 */ 125178173Simp (1 << 6) | (1 << 4), /* CPU + port4 */ 126178173Simp (1 << 6) | (1 << 5), /* CPU + port5 */ 127178173Simp}; 128178173Simp 129178173Simp/* ifnet entry points */ 130178173Simpstatic void admsw_start(struct ifnet *); 131199762Sjhbstatic void admsw_watchdog(void *); 132178173Simpstatic int admsw_ioctl(struct ifnet *, u_long, caddr_t); 133178173Simpstatic void admsw_init(void *); 134178173Simpstatic void admsw_stop(struct ifnet *, int); 135178173Simp 136178173Simpstatic void admsw_reset(struct admsw_softc *); 137178173Simpstatic void admsw_set_filter(struct admsw_softc *); 138178173Simp 139178173Simpstatic void admsw_txintr(struct admsw_softc *, int); 140178173Simpstatic void admsw_rxintr(struct admsw_softc *, int); 141178173Simpstatic int admsw_add_rxbuf(struct admsw_softc *, int, int); 142178173Simp#define admsw_add_rxhbuf(sc, idx) admsw_add_rxbuf(sc, idx, 1) 143178173Simp#define admsw_add_rxlbuf(sc, idx) admsw_add_rxbuf(sc, idx, 0) 144178173Simp 145178173Simpstatic int admsw_mediachange(struct ifnet *); 146178173Simpstatic void admsw_mediastatus(struct ifnet *, struct ifmediareq *); 147178173Simp 148178173Simpstatic int admsw_intr(void *); 149178173Simp 150178173Simp/* bus entry points */ 151178173Simpstatic int admsw_probe(device_t dev); 152178173Simpstatic int admsw_attach(device_t dev); 153178173Simpstatic int admsw_detach(device_t dev); 154194342Sbzstatic int admsw_shutdown(device_t dev); 155178173Simp 156178173Simpstatic void 157178173Simpadmsw_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 158178173Simp{ 159178173Simp uint32_t *addr; 160178173Simp 161178173Simp if (error) 162178173Simp return; 163178173Simp 164178173Simp KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 165178173Simp addr = arg; 166178173Simp *addr = segs->ds_addr; 167178173Simp} 168178173Simp 169178173Simpstatic void 170178173Simpadmsw_rxbuf_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 171178173Simp{ 172178173Simp struct admsw_descsoft *ds; 173178173Simp 174178173Simp if (error) 175178173Simp return; 176178173Simp 177178173Simp KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 178178173Simp 179178173Simp ds = arg; 180178173Simp ds->ds_nsegs = nseg; 181178173Simp ds->ds_addr[0] = segs[0].ds_addr; 182178173Simp ds->ds_len[0] = segs[0].ds_len; 183178173Simp 184178173Simp} 185178173Simp 186178173Simpstatic void 187178173Simpadmsw_mbuf_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, 188178173Simp bus_size_t mapsize, int error) 189178173Simp{ 190178173Simp struct admsw_descsoft *ds; 191178173Simp 192178173Simp if (error) 193178173Simp return; 194178173Simp 195178173Simp ds = arg; 196178173Simp 197178173Simp if((nseg != 1) && (nseg != 2)) 198178173Simp panic("%s: nseg == %d\n", __func__, nseg); 199178173Simp 200178173Simp ds->ds_nsegs = nseg; 201178173Simp ds->ds_addr[0] = segs[0].ds_addr; 202178173Simp ds->ds_len[0] = segs[0].ds_len; 203178173Simp 204178173Simp if(nseg > 1) { 205178173Simp ds->ds_addr[1] = segs[1].ds_addr; 206178173Simp ds->ds_len[1] = segs[1].ds_len; 207178173Simp } 208178173Simp} 209178173Simp 210178173Simp 211178173Simp 212178173Simpstatic int 213178173Simpadmsw_probe(device_t dev) 214178173Simp{ 215178173Simp 216178173Simp device_set_desc(dev, "ADM5120 Switch Engine"); 217178173Simp return (0); 218178173Simp} 219178173Simp 220178173Simp#define REG_READ(o) bus_read_4((sc)->mem_res, (o)) 221178173Simp#define REG_WRITE(o,v) bus_write_4((sc)->mem_res, (o),(v)) 222178173Simp 223178173Simpstatic void 224178173Simpadmsw_init_bufs(struct admsw_softc *sc) 225178173Simp{ 226178173Simp int i; 227178173Simp struct admsw_desc *desc; 228178173Simp 229178173Simp for (i = 0; i < ADMSW_NTXHDESC; i++) { 230178173Simp if (sc->sc_txhsoft[i].ds_mbuf != NULL) { 231178173Simp m_freem(sc->sc_txhsoft[i].ds_mbuf); 232178173Simp sc->sc_txhsoft[i].ds_mbuf = NULL; 233178173Simp } 234178173Simp desc = &sc->sc_txhdescs[i]; 235178173Simp desc->data = 0; 236178173Simp desc->cntl = 0; 237178173Simp desc->len = MAC_BUFLEN; 238178173Simp desc->status = 0; 239178173Simp ADMSW_CDTXHSYNC(sc, i, 240178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 241178173Simp } 242178173Simp sc->sc_txhdescs[ADMSW_NTXHDESC - 1].data |= ADM5120_DMA_RINGEND; 243178173Simp ADMSW_CDTXHSYNC(sc, ADMSW_NTXHDESC - 1, 244178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 245178173Simp 246178173Simp for (i = 0; i < ADMSW_NRXHDESC; i++) { 247178173Simp if (sc->sc_rxhsoft[i].ds_mbuf == NULL) { 248178173Simp if (admsw_add_rxhbuf(sc, i) != 0) 249178173Simp panic("admsw_init_bufs\n"); 250178173Simp } else 251178173Simp ADMSW_INIT_RXHDESC(sc, i); 252178173Simp } 253178173Simp 254178173Simp for (i = 0; i < ADMSW_NTXLDESC; i++) { 255178173Simp if (sc->sc_txlsoft[i].ds_mbuf != NULL) { 256178173Simp m_freem(sc->sc_txlsoft[i].ds_mbuf); 257178173Simp sc->sc_txlsoft[i].ds_mbuf = NULL; 258178173Simp } 259178173Simp desc = &sc->sc_txldescs[i]; 260178173Simp desc->data = 0; 261178173Simp desc->cntl = 0; 262178173Simp desc->len = MAC_BUFLEN; 263178173Simp desc->status = 0; 264178173Simp ADMSW_CDTXLSYNC(sc, i, 265178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 266178173Simp } 267178173Simp sc->sc_txldescs[ADMSW_NTXLDESC - 1].data |= ADM5120_DMA_RINGEND; 268178173Simp ADMSW_CDTXLSYNC(sc, ADMSW_NTXLDESC - 1, 269178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 270178173Simp 271178173Simp for (i = 0; i < ADMSW_NRXLDESC; i++) { 272178173Simp if (sc->sc_rxlsoft[i].ds_mbuf == NULL) { 273178173Simp if (admsw_add_rxlbuf(sc, i) != 0) 274178173Simp panic("admsw_init_bufs\n"); 275178173Simp } else 276178173Simp ADMSW_INIT_RXLDESC(sc, i); 277178173Simp } 278178173Simp 279178173Simp REG_WRITE(SEND_HBADDR_REG, ADMSW_CDTXHADDR(sc, 0)); 280178173Simp REG_WRITE(SEND_LBADDR_REG, ADMSW_CDTXLADDR(sc, 0)); 281178173Simp REG_WRITE(RECV_HBADDR_REG, ADMSW_CDRXHADDR(sc, 0)); 282178173Simp REG_WRITE(RECV_LBADDR_REG, ADMSW_CDRXLADDR(sc, 0)); 283178173Simp 284178173Simp sc->sc_txfree = ADMSW_NTXLDESC; 285178173Simp sc->sc_txnext = 0; 286178173Simp sc->sc_txdirty = 0; 287178173Simp sc->sc_rxptr = 0; 288178173Simp} 289178173Simp 290178173Simpstatic void 291178173Simpadmsw_setvlan(struct admsw_softc *sc, char matrix[6]) 292178173Simp{ 293178173Simp uint32_t i; 294178173Simp 295178173Simp i = matrix[0] + (matrix[1] << 8) + (matrix[2] << 16) + (matrix[3] << 24); 296178173Simp REG_WRITE(VLAN_G1_REG, i); 297178173Simp i = matrix[4] + (matrix[5] << 8); 298178173Simp REG_WRITE(VLAN_G2_REG, i); 299178173Simp} 300178173Simp 301178173Simpstatic void 302178173Simpadmsw_reset(struct admsw_softc *sc) 303178173Simp{ 304178173Simp uint32_t wdog1; 305178173Simp int i; 306178173Simp 307178173Simp REG_WRITE(PORT_CONF0_REG, 308178173Simp REG_READ(PORT_CONF0_REG) | PORT_CONF0_DP_MASK); 309178173Simp REG_WRITE(CPUP_CONF_REG, 310178173Simp REG_READ(CPUP_CONF_REG) | CPUP_CONF_DCPUP); 311178173Simp 312178173Simp /* Wait for DMA to complete. Overkill. In 3ms, we can 313178173Simp * send at least two entire 1500-byte packets at 10 Mb/s. 314178173Simp */ 315178173Simp DELAY(3000); 316178173Simp 317178173Simp /* The datasheet recommends that we move all PHYs to reset 318178173Simp * state prior to software reset. 319178173Simp */ 320178173Simp REG_WRITE(PHY_CNTL2_REG, 321178173Simp REG_READ(PHY_CNTL2_REG) & ~PHY_CNTL2_PHYR_MASK); 322178173Simp 323178173Simp /* Reset the switch. */ 324178173Simp REG_WRITE(ADMSW_SW_RES, 0x1); 325178173Simp 326178173Simp DELAY(100 * 1000); 327178173Simp 328178173Simp REG_WRITE(ADMSW_BOOT_DONE, ADMSW_BOOT_DONE_BO); 329178173Simp 330178173Simp /* begin old code */ 331178173Simp REG_WRITE(CPUP_CONF_REG, 332178173Simp CPUP_CONF_DCPUP | CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK | 333178173Simp CPUP_CONF_DMCP_MASK); 334178173Simp 335178173Simp REG_WRITE(PORT_CONF0_REG, PORT_CONF0_EMCP_MASK | PORT_CONF0_EMBP_MASK); 336178173Simp 337178173Simp REG_WRITE(PHY_CNTL2_REG, 338178173Simp REG_READ(PHY_CNTL2_REG) | PHY_CNTL2_ANE_MASK | PHY_CNTL2_PHYR_MASK | 339178173Simp PHY_CNTL2_AMDIX_MASK); 340178173Simp 341178173Simp REG_WRITE(PHY_CNTL3_REG, REG_READ(PHY_CNTL3_REG) | PHY_CNTL3_RNT); 342178173Simp 343178173Simp REG_WRITE(ADMSW_INT_MASK, INT_MASK); 344178173Simp REG_WRITE(ADMSW_INT_ST, INT_MASK); 345178173Simp 346178173Simp /* 347178173Simp * While in DDB, we stop servicing interrupts, RX ring 348178173Simp * fills up and when free block counter falls behind FC 349178173Simp * threshold, the switch starts to emit 802.3x PAUSE 350178173Simp * frames. This can upset peer switches. 351178173Simp * 352178173Simp * Stop this from happening by disabling FC and D2 353178173Simp * thresholds. 354178173Simp */ 355178173Simp REG_WRITE(FC_TH_REG, 356178173Simp REG_READ(FC_TH_REG) & ~(FC_TH_FCS_MASK | FC_TH_D2S_MASK)); 357178173Simp 358178173Simp admsw_setvlan(sc, vlan_matrix); 359178173Simp 360178173Simp for (i = 0; i < SW_DEVS; i++) { 361178173Simp REG_WRITE(MAC_WT1_REG, 362178173Simp sc->sc_enaddr[2] | 363178173Simp (sc->sc_enaddr[3]<<8) | 364178173Simp (sc->sc_enaddr[4]<<16) | 365178173Simp ((sc->sc_enaddr[5]+i)<<24)); 366178173Simp REG_WRITE(MAC_WT0_REG, (i<<MAC_WT0_VLANID_SHIFT) | 367178173Simp (sc->sc_enaddr[0]<<16) | (sc->sc_enaddr[1]<<24) | 368178173Simp MAC_WT0_WRITE | MAC_WT0_VLANID_EN); 369178173Simp 370178173Simp while (!(REG_READ(MAC_WT0_REG) & MAC_WT0_WRITE_DONE)); 371178173Simp } 372178173Simp 373178173Simp wdog1 = REG_READ(ADM5120_WDOG1); 374178173Simp REG_WRITE(ADM5120_WDOG1, wdog1 & ~ADM5120_WDOG1_WDE); 375178173Simp} 376178173Simp 377178173Simpstatic int 378178173Simpadmsw_attach(device_t dev) 379178173Simp{ 380178173Simp uint8_t enaddr[ETHER_ADDR_LEN]; 381178173Simp struct admsw_softc *sc = (struct admsw_softc *) device_get_softc(dev); 382178173Simp struct ifnet *ifp; 383178173Simp int error, i, rid; 384178173Simp 385178173Simp sc->sc_dev = dev; 386178173Simp device_printf(dev, "ADM5120 Switch Engine, %d ports\n", SW_DEVS); 387178173Simp sc->ndevs = 0; 388178173Simp 389178173Simp /* XXXMIPS: fix it */ 390178173Simp enaddr[0] = 0x00; 391178173Simp enaddr[1] = 0x0C; 392178173Simp enaddr[2] = 0x42; 393178173Simp enaddr[3] = 0x07; 394178173Simp enaddr[4] = 0xB2; 395178173Simp enaddr[5] = 0x4E; 396178173Simp 397178173Simp memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr)); 398178173Simp 399178173Simp device_printf(sc->sc_dev, "base Ethernet address %s\n", 400178173Simp ether_sprintf(enaddr)); 401199762Sjhb callout_init(&sc->sc_watchdog, 1); 402178173Simp 403178173Simp rid = 0; 404178173Simp if ((sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 405178173Simp RF_ACTIVE)) == NULL) { 406178173Simp device_printf(dev, "unable to allocate memory resource\n"); 407178173Simp return (ENXIO); 408178173Simp } 409178173Simp 410178173Simp /* Hook up the interrupt handler. */ 411178173Simp rid = 0; 412178173Simp if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 413178173Simp RF_SHAREABLE | RF_ACTIVE)) == NULL) { 414178173Simp device_printf(dev, "unable to allocate IRQ resource\n"); 415178173Simp return (ENXIO); 416178173Simp } 417178173Simp 418178173Simp if ((error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, 419178173Simp admsw_intr, NULL, sc, &sc->sc_ih)) != 0) { 420178173Simp device_printf(dev, 421178173Simp "WARNING: unable to register interrupt handler\n"); 422178173Simp return (error); 423178173Simp } 424178173Simp 425178173Simp /* 426178173Simp * Allocate the control data structures, and create and load the 427178173Simp * DMA map for it. 428178173Simp */ 429178173Simp if ((error = bus_dma_tag_create(NULL, 4, 0, 430178173Simp BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 431178173Simp NULL, NULL, sizeof(struct admsw_control_data), 1, 432178173Simp sizeof(struct admsw_control_data), 0, NULL, NULL, 433178173Simp &sc->sc_control_dmat)) != 0) { 434178173Simp device_printf(sc->sc_dev, 435178173Simp "unable to create control data DMA map, error = %d\n", 436178173Simp error); 437178173Simp return (error); 438178173Simp } 439178173Simp 440178173Simp if ((error = bus_dmamem_alloc(sc->sc_control_dmat, 441178173Simp (void **)&sc->sc_control_data, BUS_DMA_NOWAIT, 442178173Simp &sc->sc_cddmamap)) != 0) { 443178173Simp device_printf(sc->sc_dev, 444178173Simp "unable to allocate control data, error = %d\n", error); 445178173Simp return (error); 446178173Simp } 447178173Simp 448178173Simp if ((error = bus_dmamap_load(sc->sc_control_dmat, sc->sc_cddmamap, 449178173Simp sc->sc_control_data, sizeof(struct admsw_control_data), 450178173Simp admsw_dma_map_addr, &sc->sc_cddma, 0)) != 0) { 451178173Simp device_printf(sc->sc_dev, 452178173Simp "unable to load control data DMA map, error = %d\n", error); 453178173Simp return (error); 454178173Simp } 455178173Simp 456178173Simp /* 457178173Simp * Create the transmit buffer DMA maps. 458178173Simp */ 459178173Simp if ((error = bus_dma_tag_create(NULL, 1, 0, 460178173Simp BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 461178173Simp NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, NULL, 462178173Simp &sc->sc_bufs_dmat)) != 0) { 463178173Simp device_printf(sc->sc_dev, 464178173Simp "unable to create control data DMA map, error = %d\n", 465178173Simp error); 466178173Simp return (error); 467178173Simp } 468178173Simp 469178173Simp for (i = 0; i < ADMSW_NTXHDESC; i++) { 470178173Simp if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0, 471178173Simp &sc->sc_txhsoft[i].ds_dmamap)) != 0) { 472178173Simp device_printf(sc->sc_dev, 473178173Simp "unable to create txh DMA map %d, error = %d\n", 474178173Simp i, error); 475178173Simp return (error); 476178173Simp } 477178173Simp sc->sc_txhsoft[i].ds_mbuf = NULL; 478178173Simp } 479178173Simp 480178173Simp for (i = 0; i < ADMSW_NTXLDESC; i++) { 481178173Simp if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0, 482178173Simp &sc->sc_txlsoft[i].ds_dmamap)) != 0) { 483178173Simp device_printf(sc->sc_dev, 484178173Simp "unable to create txl DMA map %d, error = %d\n", 485178173Simp i, error); 486178173Simp return (error); 487178173Simp } 488178173Simp sc->sc_txlsoft[i].ds_mbuf = NULL; 489178173Simp } 490178173Simp 491178173Simp /* 492178173Simp * Create the receive buffer DMA maps. 493178173Simp */ 494178173Simp for (i = 0; i < ADMSW_NRXHDESC; i++) { 495178173Simp if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0, 496178173Simp &sc->sc_rxhsoft[i].ds_dmamap)) != 0) { 497178173Simp device_printf(sc->sc_dev, 498178173Simp "unable to create rxh DMA map %d, error = %d\n", 499178173Simp i, error); 500178173Simp return (error); 501178173Simp } 502178173Simp sc->sc_rxhsoft[i].ds_mbuf = NULL; 503178173Simp } 504178173Simp 505178173Simp for (i = 0; i < ADMSW_NRXLDESC; i++) { 506178173Simp if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0, 507178173Simp &sc->sc_rxlsoft[i].ds_dmamap)) != 0) { 508178173Simp device_printf(sc->sc_dev, 509178173Simp "unable to create rxl DMA map %d, error = %d\n", 510178173Simp i, error); 511178173Simp return (error); 512178173Simp } 513178173Simp sc->sc_rxlsoft[i].ds_mbuf = NULL; 514178173Simp } 515178173Simp 516178173Simp admsw_init_bufs(sc); 517178173Simp admsw_reset(sc); 518178173Simp 519178173Simp for (i = 0; i < SW_DEVS; i++) { 520178173Simp ifmedia_init(&sc->sc_ifmedia[i], 0, admsw_mediachange, 521178173Simp admsw_mediastatus); 522178173Simp ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T, 0, NULL); 523178173Simp ifmedia_add(&sc->sc_ifmedia[i], 524178173Simp IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 525178173Simp ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX, 0, NULL); 526178173Simp ifmedia_add(&sc->sc_ifmedia[i], 527178173Simp IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 528178173Simp ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO, 0, NULL); 529178173Simp ifmedia_set(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO); 530178173Simp 531208022Simp ifp = sc->sc_ifnet[i] = if_alloc(IFT_ETHER); 532178173Simp 533178173Simp /* Setup interface parameters */ 534178173Simp ifp->if_softc = sc; 535178173Simp if_initname(ifp, device_get_name(dev), i); 536178173Simp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 537178173Simp ifp->if_ioctl = admsw_ioctl; 538178173Simp ifp->if_output = ether_output; 539178173Simp ifp->if_start = admsw_start; 540178173Simp ifp->if_init = admsw_init; 541178173Simp ifp->if_mtu = ETHERMTU; 542178173Simp ifp->if_baudrate = IF_Mbps(100); 543207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, max(ADMSW_NTXLDESC, ifqmaxlen)); 544207554Ssobomax ifp->if_snd.ifq_drv_maxlen = max(ADMSW_NTXLDESC, ifqmaxlen); 545178173Simp IFQ_SET_READY(&ifp->if_snd); 546178173Simp ifp->if_capabilities |= IFCAP_VLAN_MTU; 547178173Simp 548178173Simp /* Attach the interface. */ 549178173Simp ether_ifattach(ifp, enaddr); 550178173Simp enaddr[5]++; 551178173Simp } 552178173Simp 553178173Simp /* XXX: admwdog_attach(sc); */ 554178173Simp 555178173Simp /* leave interrupts and cpu port disabled */ 556178173Simp return (0); 557178173Simp} 558178173Simp 559178173Simpstatic int 560178173Simpadmsw_detach(device_t dev) 561178173Simp{ 562178173Simp 563178173Simp printf("TODO: DETACH\n"); 564178173Simp return (0); 565178173Simp} 566178173Simp 567178173Simp/* 568178173Simp * admsw_shutdown: 569178173Simp * 570178173Simp * Make sure the interface is stopped at reboot time. 571178173Simp */ 572194342Sbzstatic int 573194342Sbzadmsw_shutdown(device_t dev) 574178173Simp{ 575194342Sbz struct admsw_softc *sc; 576178173Simp int i; 577178173Simp 578194342Sbz sc = device_get_softc(dev); 579178173Simp for (i = 0; i < SW_DEVS; i++) 580178173Simp admsw_stop(sc->sc_ifnet[i], 1); 581194342Sbz 582194342Sbz return (0); 583178173Simp} 584178173Simp 585178173Simp/* 586178173Simp * admsw_start: [ifnet interface function] 587178173Simp * 588178173Simp * Start packet transmission on the interface. 589178173Simp */ 590178173Simpstatic void 591178173Simpadmsw_start(struct ifnet *ifp) 592178173Simp{ 593178173Simp struct admsw_softc *sc = ifp->if_softc; 594178173Simp struct mbuf *m0, *m; 595178173Simp struct admsw_descsoft *ds; 596178173Simp struct admsw_desc *desc; 597178173Simp bus_dmamap_t dmamap; 598178173Simp struct ether_header *eh; 599178173Simp int error, nexttx, len, i; 600178173Simp static int vlan = 0; 601178173Simp 602178173Simp /* 603178173Simp * Loop through the send queues, setting up transmit descriptors 604178173Simp * unitl we drain the queues, or use up all available transmit 605178173Simp * descriptors. 606178173Simp */ 607178173Simp for (;;) { 608178173Simp vlan++; 609178173Simp if (vlan == SW_DEVS) 610178173Simp vlan = 0; 611178173Simp i = vlan; 612178173Simp for (;;) { 613178173Simp ifp = sc->sc_ifnet[i]; 614178173Simp if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) 615178173Simp == IFF_DRV_RUNNING) { 616178173Simp /* Grab a packet off the queue. */ 617178173Simp IF_DEQUEUE(&ifp->if_snd, m0); 618178173Simp if (m0 != NULL) 619178173Simp break; 620178173Simp } 621178173Simp i++; 622178173Simp if (i == SW_DEVS) 623178173Simp i = 0; 624178173Simp if (i == vlan) 625178173Simp return; 626178173Simp } 627178173Simp vlan = i; 628178173Simp m = NULL; 629178173Simp 630178173Simp /* Get a spare descriptor. */ 631178173Simp if (sc->sc_txfree == 0) { 632178173Simp /* No more slots left; notify upper layer. */ 633178173Simp ifp->if_drv_flags |= IFF_DRV_OACTIVE; 634178173Simp break; 635178173Simp } 636178173Simp nexttx = sc->sc_txnext; 637178173Simp desc = &sc->sc_txldescs[nexttx]; 638178173Simp ds = &sc->sc_txlsoft[nexttx]; 639178173Simp dmamap = ds->ds_dmamap; 640178173Simp 641178173Simp /* 642178173Simp * Load the DMA map. If this fails, the packet either 643178173Simp * didn't fit in the alloted number of segments, or we 644178173Simp * were short on resources. In this case, we'll copy 645178173Simp * and try again. 646178173Simp */ 647178173Simp if (m0->m_pkthdr.len < ETHER_MIN_LEN || 648178173Simp bus_dmamap_load_mbuf(sc->sc_bufs_dmat, dmamap, m0, 649178173Simp admsw_mbuf_map_addr, ds, BUS_DMA_NOWAIT) != 0) { 650243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 651178173Simp if (m == NULL) { 652178173Simp device_printf(sc->sc_dev, 653178173Simp "unable to allocate Tx mbuf\n"); 654178173Simp break; 655178173Simp } 656178173Simp if (m0->m_pkthdr.len > MHLEN) { 657243882Sglebius MCLGET(m, M_NOWAIT); 658178173Simp if ((m->m_flags & M_EXT) == 0) { 659178173Simp device_printf(sc->sc_dev, 660178173Simp "unable to allocate Tx cluster\n"); 661178173Simp m_freem(m); 662178173Simp break; 663178173Simp } 664178173Simp } 665178173Simp m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags; 666178173Simp m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *)); 667178173Simp m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; 668178173Simp if (m->m_pkthdr.len < ETHER_MIN_LEN) { 669178173Simp if (M_TRAILINGSPACE(m) < ETHER_MIN_LEN - m->m_pkthdr.len) 670178173Simp panic("admsw_start: M_TRAILINGSPACE\n"); 671178173Simp memset(mtod(m, uint8_t *) + m->m_pkthdr.len, 0, 672178173Simp ETHER_MIN_LEN - ETHER_CRC_LEN - m->m_pkthdr.len); 673178173Simp m->m_pkthdr.len = m->m_len = ETHER_MIN_LEN; 674178173Simp } 675178173Simp error = bus_dmamap_load_mbuf(sc->sc_bufs_dmat, 676178173Simp dmamap, m, admsw_mbuf_map_addr, ds, BUS_DMA_NOWAIT); 677178173Simp if (error) { 678178173Simp device_printf(sc->sc_dev, 679178173Simp "unable to load Tx buffer, error = %d\n", 680178173Simp error); 681178173Simp break; 682178173Simp } 683178173Simp } 684178173Simp 685178173Simp if (m != NULL) { 686178173Simp m_freem(m0); 687178173Simp m0 = m; 688178173Simp } 689178173Simp 690178173Simp /* 691178173Simp * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. 692178173Simp */ 693178173Simp 694178173Simp /* Sync the DMA map. */ 695178173Simp bus_dmamap_sync(sc->sc_bufs_dmat, dmamap, BUS_DMASYNC_PREWRITE); 696178173Simp 697178173Simp if (ds->ds_nsegs != 1 && ds->ds_nsegs != 2) 698178173Simp panic("admsw_start: nsegs == %d\n", ds->ds_nsegs); 699178173Simp desc->data = ds->ds_addr[0]; 700178173Simp desc->len = len = ds->ds_len[0]; 701178173Simp if (ds->ds_nsegs > 1) { 702178173Simp len += ds->ds_len[1]; 703178173Simp desc->cntl = ds->ds_addr[1] | ADM5120_DMA_BUF2ENABLE; 704178173Simp } else 705178173Simp desc->cntl = 0; 706178173Simp desc->status = (len << ADM5120_DMA_LENSHIFT) | (1 << vlan); 707178173Simp eh = mtod(m0, struct ether_header *); 708178173Simp if (ntohs(eh->ether_type) == ETHERTYPE_IP && 709178173Simp m0->m_pkthdr.csum_flags & CSUM_IP) 710178173Simp desc->status |= ADM5120_DMA_CSUM; 711178173Simp if (nexttx == ADMSW_NTXLDESC - 1) 712178173Simp desc->data |= ADM5120_DMA_RINGEND; 713178173Simp desc->data |= ADM5120_DMA_OWN; 714178173Simp 715178173Simp /* Sync the descriptor. */ 716178173Simp ADMSW_CDTXLSYNC(sc, nexttx, 717178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 718178173Simp 719178173Simp REG_WRITE(SEND_TRIG_REG, 1); 720178173Simp /* printf("send slot %d\n",nexttx); */ 721178173Simp 722178173Simp /* 723178173Simp * Store a pointer to the packet so we can free it later. 724178173Simp */ 725178173Simp ds->ds_mbuf = m0; 726178173Simp 727178173Simp /* Advance the Tx pointer. */ 728178173Simp sc->sc_txfree--; 729178173Simp sc->sc_txnext = ADMSW_NEXTTXL(nexttx); 730178173Simp 731178173Simp /* Pass the packet to any BPF listeners. */ 732178173Simp BPF_MTAP(ifp, m0); 733178173Simp 734178173Simp /* Set a watchdog timer in case the chip flakes out. */ 735199762Sjhb sc->sc_timer = 5; 736178173Simp } 737178173Simp} 738178173Simp 739178173Simp/* 740178173Simp * admsw_watchdog: [ifnet interface function] 741178173Simp * 742178173Simp * Watchdog timer handler. 743178173Simp */ 744178173Simpstatic void 745199762Sjhbadmsw_watchdog(void *arg) 746178173Simp{ 747199762Sjhb struct admsw_softc *sc = arg; 748200484Sbz struct ifnet *ifp; 749178173Simp int vlan; 750178173Simp 751200484Sbz callout_reset(&sc->sc_watchdog, hz, admsw_watchdog, sc); 752200484Sbz if (sc->sc_timer == 0 || --sc->sc_timer > 0) 753199762Sjhb return; 754199762Sjhb 755178173Simp /* Check if an interrupt was lost. */ 756178173Simp if (sc->sc_txfree == ADMSW_NTXLDESC) { 757178173Simp device_printf(sc->sc_dev, "watchdog false alarm\n"); 758178173Simp return; 759178173Simp } 760199762Sjhb if (sc->sc_timer != 0) 761178173Simp device_printf(sc->sc_dev, "watchdog timer is %d!\n", 762199762Sjhb sc->sc_timer); 763178173Simp admsw_txintr(sc, 0); 764178173Simp if (sc->sc_txfree == ADMSW_NTXLDESC) { 765178173Simp device_printf(sc->sc_dev, "tx IRQ lost (queue empty)\n"); 766178173Simp return; 767178173Simp } 768199762Sjhb if (sc->sc_timer != 0) { 769178173Simp device_printf(sc->sc_dev, "tx IRQ lost (timer recharged)\n"); 770178173Simp return; 771178173Simp } 772178173Simp 773178173Simp device_printf(sc->sc_dev, "device timeout, txfree = %d\n", 774178173Simp sc->sc_txfree); 775178173Simp for (vlan = 0; vlan < SW_DEVS; vlan++) 776178173Simp admsw_stop(sc->sc_ifnet[vlan], 0); 777178173Simp admsw_init(sc); 778178173Simp 779200484Sbz ifp = sc->sc_ifnet[0]; 780200484Sbz 781178173Simp /* Try to get more packets going. */ 782178173Simp admsw_start(ifp); 783178173Simp} 784178173Simp 785178173Simp/* 786178173Simp * admsw_ioctl: [ifnet interface function] 787178173Simp * 788178173Simp * Handle control requests from the operator. 789178173Simp */ 790178173Simpstatic int 791178173Simpadmsw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 792178173Simp{ 793178173Simp struct admsw_softc *sc = ifp->if_softc; 794178173Simp struct ifdrv *ifd; 795178173Simp int error, port; 796178173Simp 797178173Simp ADMSW_LOCK(sc); 798178173Simp 799178173Simp switch (cmd) { 800178173Simp case SIOCSIFMEDIA: 801178173Simp case SIOCGIFMEDIA: 802178173Simp port = 0; 803178173Simp while(port < SW_DEVS) 804178173Simp if(ifp == sc->sc_ifnet[port]) 805178173Simp break; 806178173Simp else 807178173Simp port++; 808178173Simp if (port >= SW_DEVS) 809178173Simp error = EOPNOTSUPP; 810178173Simp else 811178173Simp error = ifmedia_ioctl(ifp, (struct ifreq *)data, 812178173Simp &sc->sc_ifmedia[port], cmd); 813178173Simp break; 814178173Simp 815178173Simp case SIOCGDRVSPEC: 816178173Simp case SIOCSDRVSPEC: 817178173Simp ifd = (struct ifdrv *) data; 818178173Simp if (ifd->ifd_cmd != 0 || ifd->ifd_len != sizeof(vlan_matrix)) { 819178173Simp error = EINVAL; 820178173Simp break; 821178173Simp } 822178173Simp if (cmd == SIOCGDRVSPEC) { 823178173Simp error = copyout(vlan_matrix, ifd->ifd_data, 824178173Simp sizeof(vlan_matrix)); 825178173Simp } else { 826178173Simp error = copyin(ifd->ifd_data, vlan_matrix, 827178173Simp sizeof(vlan_matrix)); 828178173Simp admsw_setvlan(sc, vlan_matrix); 829178173Simp } 830178173Simp break; 831178173Simp 832178173Simp default: 833178173Simp error = ether_ioctl(ifp, cmd, data); 834178173Simp if (error == ENETRESET) { 835178173Simp /* 836178173Simp * Multicast list has changed; set the hardware filter 837178173Simp * accordingly. 838178173Simp */ 839178173Simp admsw_set_filter(sc); 840178173Simp error = 0; 841178173Simp } 842178173Simp break; 843178173Simp } 844178173Simp 845178173Simp /* Try to get more packets going. */ 846178173Simp admsw_start(ifp); 847178173Simp 848178173Simp ADMSW_UNLOCK(sc); 849178173Simp return (error); 850178173Simp} 851178173Simp 852178173Simp 853178173Simp/* 854178173Simp * admsw_intr: 855178173Simp * 856178173Simp * Interrupt service routine. 857178173Simp */ 858178173Simpstatic int 859178173Simpadmsw_intr(void *arg) 860178173Simp{ 861178173Simp struct admsw_softc *sc = arg; 862178173Simp uint32_t pending; 863178173Simp 864178173Simp pending = REG_READ(ADMSW_INT_ST); 865178173Simp REG_WRITE(ADMSW_INT_ST, pending); 866178173Simp 867178173Simp if (sc->ndevs == 0) 868178173Simp return (FILTER_STRAY); 869178173Simp 870178173Simp if ((pending & ADMSW_INTR_RHD) != 0) 871178173Simp admsw_rxintr(sc, 1); 872178173Simp 873178173Simp if ((pending & ADMSW_INTR_RLD) != 0) 874178173Simp admsw_rxintr(sc, 0); 875178173Simp 876178173Simp if ((pending & ADMSW_INTR_SHD) != 0) 877178173Simp admsw_txintr(sc, 1); 878178173Simp 879178173Simp if ((pending & ADMSW_INTR_SLD) != 0) 880178173Simp admsw_txintr(sc, 0); 881178173Simp 882178173Simp return (FILTER_HANDLED); 883178173Simp} 884178173Simp 885178173Simp/* 886178173Simp * admsw_txintr: 887178173Simp * 888178173Simp * Helper; handle transmit interrupts. 889178173Simp */ 890178173Simpstatic void 891178173Simpadmsw_txintr(struct admsw_softc *sc, int prio) 892178173Simp{ 893178173Simp struct ifnet *ifp; 894178173Simp struct admsw_desc *desc; 895178173Simp struct admsw_descsoft *ds; 896178173Simp int i, vlan; 897178173Simp int gotone = 0; 898178173Simp 899178173Simp /* printf("txintr: txdirty: %d, txfree: %d\n",sc->sc_txdirty, sc->sc_txfree); */ 900178173Simp for (i = sc->sc_txdirty; sc->sc_txfree != ADMSW_NTXLDESC; 901178173Simp i = ADMSW_NEXTTXL(i)) { 902178173Simp 903178173Simp ADMSW_CDTXLSYNC(sc, i, 904178173Simp BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 905178173Simp 906178173Simp desc = &sc->sc_txldescs[i]; 907178173Simp ds = &sc->sc_txlsoft[i]; 908178173Simp if (desc->data & ADM5120_DMA_OWN) { 909178173Simp ADMSW_CDTXLSYNC(sc, i, 910178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 911178173Simp break; 912178173Simp } 913178173Simp 914178173Simp bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, 915178173Simp BUS_DMASYNC_POSTWRITE); 916178173Simp bus_dmamap_unload(sc->sc_bufs_dmat, ds->ds_dmamap); 917178173Simp m_freem(ds->ds_mbuf); 918178173Simp ds->ds_mbuf = NULL; 919178173Simp 920178173Simp vlan = ffs(desc->status & 0x3f) - 1; 921178173Simp if (vlan < 0 || vlan >= SW_DEVS) 922178173Simp panic("admsw_txintr: bad vlan\n"); 923178173Simp ifp = sc->sc_ifnet[vlan]; 924178173Simp gotone = 1; 925178173Simp /* printf("clear tx slot %d\n",i); */ 926178173Simp 927178173Simp ifp->if_opackets++; 928178173Simp 929178173Simp sc->sc_txfree++; 930178173Simp } 931178173Simp 932178173Simp if (gotone) { 933178173Simp sc->sc_txdirty = i; 934178173Simp for (vlan = 0; vlan < SW_DEVS; vlan++) 935178173Simp sc->sc_ifnet[vlan]->if_drv_flags &= ~IFF_DRV_OACTIVE; 936178173Simp 937178173Simp ifp = sc->sc_ifnet[0]; 938178173Simp 939178173Simp /* Try to queue more packets. */ 940178173Simp admsw_start(ifp); 941178173Simp 942178173Simp /* 943178173Simp * If there are no more pending transmissions, 944178173Simp * cancel the watchdog timer. 945178173Simp */ 946178173Simp if (sc->sc_txfree == ADMSW_NTXLDESC) 947199762Sjhb sc->sc_timer = 0; 948178173Simp 949178173Simp } 950178173Simp 951178173Simp /* printf("txintr end: txdirty: %d, txfree: %d\n",sc->sc_txdirty, sc->sc_txfree); */ 952178173Simp} 953178173Simp 954178173Simp/* 955178173Simp * admsw_rxintr: 956178173Simp * 957178173Simp * Helper; handle receive interrupts. 958178173Simp */ 959178173Simpstatic void 960178173Simpadmsw_rxintr(struct admsw_softc *sc, int high) 961178173Simp{ 962178173Simp struct ifnet *ifp; 963178173Simp struct admsw_descsoft *ds; 964178173Simp struct mbuf *m; 965178173Simp uint32_t stat; 966178173Simp int i, len, port, vlan; 967178173Simp 968178173Simp /* printf("rxintr\n"); */ 969178173Simp 970178173Simp if (high) 971178173Simp panic("admsw_rxintr: high priority packet\n"); 972178173Simp 973178173Simp#if 1 974178173Simp ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 975178173Simp BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 976178173Simp if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0) 977178173Simp ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 978178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 979178173Simp else { 980178173Simp i = sc->sc_rxptr; 981178173Simp do { 982178173Simp ADMSW_CDRXLSYNC(sc, i, 983178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 984178173Simp i = ADMSW_NEXTRXL(i); 985178173Simp /* the ring is empty, just return. */ 986178173Simp if (i == sc->sc_rxptr) 987178173Simp return; 988178173Simp ADMSW_CDRXLSYNC(sc, i, 989178173Simp BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 990178173Simp } while (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN); 991178173Simp 992178173Simp ADMSW_CDRXLSYNC(sc, i, 993178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 994178173Simp 995178173Simp ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 996178173Simp BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 997178173Simp 998178173Simp if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0) 999178173Simp ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 1000178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 1001178173Simp else { 1002178173Simp ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, 1003178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 1004178173Simp /* We've fallen behind the chip: catch it. */ 1005178173Simp#if 0 1006178173Simp device_printf(sc->sc_dev, 1007178173Simp "RX ring resync, base=%x, work=%x, %d -> %d\n", 1008178173Simp REG_READ(RECV_LBADDR_REG), 1009178173Simp REG_READ(RECV_LWADDR_REG), sc->sc_rxptr, i); 1010178173Simp#endif 1011178173Simp sc->sc_rxptr = i; 1012178173Simp /* ADMSW_EVCNT_INCR(&sc->sc_ev_rxsync); */ 1013178173Simp } 1014178173Simp } 1015178173Simp#endif 1016178173Simp for (i = sc->sc_rxptr;; i = ADMSW_NEXTRXL(i)) { 1017178173Simp ds = &sc->sc_rxlsoft[i]; 1018178173Simp 1019178173Simp ADMSW_CDRXLSYNC(sc, i, 1020178173Simp BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 1021178173Simp 1022178173Simp if (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN) { 1023178173Simp ADMSW_CDRXLSYNC(sc, i, 1024178173Simp BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); 1025178173Simp break; 1026178173Simp } 1027178173Simp 1028178173Simp /* printf("process slot %d\n",i); */ 1029178173Simp 1030178173Simp bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, 1031178173Simp BUS_DMASYNC_POSTREAD); 1032178173Simp 1033178173Simp stat = sc->sc_rxldescs[i].status; 1034178173Simp len = (stat & ADM5120_DMA_LEN) >> ADM5120_DMA_LENSHIFT; 1035178173Simp len -= ETHER_CRC_LEN; 1036178173Simp port = (stat & ADM5120_DMA_PORTID) >> ADM5120_DMA_PORTSHIFT; 1037178173Simp 1038178173Simp for (vlan = 0; vlan < SW_DEVS; vlan++) 1039178173Simp if ((1 << port) & vlan_matrix[vlan]) 1040178173Simp break; 1041178173Simp 1042178173Simp if (vlan == SW_DEVS) 1043178173Simp vlan = 0; 1044178173Simp 1045178173Simp ifp = sc->sc_ifnet[vlan]; 1046178173Simp 1047178173Simp m = ds->ds_mbuf; 1048178173Simp if (admsw_add_rxlbuf(sc, i) != 0) { 1049178173Simp ifp->if_ierrors++; 1050178173Simp ADMSW_INIT_RXLDESC(sc, i); 1051178173Simp bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, 1052178173Simp BUS_DMASYNC_PREREAD); 1053178173Simp continue; 1054178173Simp } 1055178173Simp 1056178173Simp m->m_pkthdr.rcvif = ifp; 1057178173Simp m->m_pkthdr.len = m->m_len = len; 1058178173Simp if ((stat & ADM5120_DMA_TYPE) == ADM5120_DMA_TYPE_IP) { 1059178173Simp m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 1060178173Simp if (!(stat & ADM5120_DMA_CSUMFAIL)) 1061178173Simp m->m_pkthdr.csum_flags |= CSUM_IP_VALID; 1062178173Simp } 1063178173Simp 1064178173Simp BPF_MTAP(ifp, m); 1065178173Simp 1066178173Simp /* Pass it on. */ 1067178173Simp (*ifp->if_input)(ifp, m); 1068178173Simp ifp->if_ipackets++; 1069178173Simp } 1070178173Simp 1071178173Simp /* Update the receive pointer. */ 1072178173Simp sc->sc_rxptr = i; 1073178173Simp} 1074178173Simp 1075178173Simp/* 1076178173Simp * admsw_init: [ifnet interface function] 1077178173Simp * 1078183427Simp * Initialize the interface. 1079178173Simp */ 1080178173Simpstatic void 1081178173Simpadmsw_init(void *xsc) 1082178173Simp{ 1083178173Simp struct admsw_softc *sc = xsc; 1084178173Simp struct ifnet *ifp; 1085178173Simp int i; 1086178173Simp 1087178173Simp for (i = 0; i < SW_DEVS; i++) { 1088178173Simp ifp = sc->sc_ifnet[i]; 1089178173Simp if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1090178173Simp if (sc->ndevs == 0) { 1091178173Simp admsw_init_bufs(sc); 1092178173Simp admsw_reset(sc); 1093178173Simp REG_WRITE(CPUP_CONF_REG, 1094178173Simp CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK | 1095178173Simp CPUP_CONF_DMCP_MASK); 1096178173Simp /* clear all pending interrupts */ 1097178173Simp REG_WRITE(ADMSW_INT_ST, INT_MASK); 1098178173Simp 1099178173Simp /* enable needed interrupts */ 1100178173Simp REG_WRITE(ADMSW_INT_MASK, 1101178173Simp REG_READ(ADMSW_INT_MASK) & 1102178173Simp ~(ADMSW_INTR_SHD | ADMSW_INTR_SLD | 1103178173Simp ADMSW_INTR_RHD | ADMSW_INTR_RLD | 1104178173Simp ADMSW_INTR_HDF | ADMSW_INTR_LDF)); 1105199762Sjhb 1106199762Sjhb callout_reset(&sc->sc_watchdog, hz, 1107199762Sjhb admsw_watchdog, sc); 1108178173Simp } 1109178173Simp sc->ndevs++; 1110178173Simp } 1111178173Simp 1112178173Simp 1113178173Simp /* mark iface as running */ 1114178173Simp ifp->if_drv_flags |= IFF_DRV_RUNNING; 1115178173Simp ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1116178173Simp } 1117178173Simp 1118178173Simp /* Set the receive filter. */ 1119178173Simp admsw_set_filter(sc); 1120178173Simp} 1121178173Simp 1122178173Simp/* 1123178173Simp * admsw_stop: [ifnet interface function] 1124178173Simp * 1125178173Simp * Stop transmission on the interface. 1126178173Simp */ 1127178173Simpstatic void 1128178173Simpadmsw_stop(struct ifnet *ifp, int disable) 1129178173Simp{ 1130178173Simp struct admsw_softc *sc = ifp->if_softc; 1131178173Simp 1132178173Simp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1133178173Simp return; 1134178173Simp 1135178173Simp if (--sc->ndevs == 0) { 1136178173Simp /* printf("debug: de-initializing hardware\n"); */ 1137178173Simp 1138178173Simp /* disable cpu port */ 1139178173Simp REG_WRITE(CPUP_CONF_REG, 1140178173Simp CPUP_CONF_DCPUP | CPUP_CONF_CRCP | 1141178173Simp CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK); 1142178173Simp 1143178173Simp /* XXX We should disable, then clear? --dyoung */ 1144178173Simp /* clear all pending interrupts */ 1145178173Simp REG_WRITE(ADMSW_INT_ST, INT_MASK); 1146178173Simp 1147178173Simp /* disable interrupts */ 1148178173Simp REG_WRITE(ADMSW_INT_MASK, INT_MASK); 1149199762Sjhb 1150199762Sjhb /* Cancel the watchdog timer. */ 1151199762Sjhb sc->sc_timer = 0; 1152199762Sjhb callout_stop(&sc->sc_watchdog); 1153178173Simp } 1154178173Simp 1155199762Sjhb /* Mark the interface as down. */ 1156178173Simp ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1157178173Simp 1158178173Simp return; 1159178173Simp} 1160178173Simp 1161178173Simp/* 1162178173Simp * admsw_set_filter: 1163178173Simp * 1164178173Simp * Set up the receive filter. 1165178173Simp */ 1166178173Simpstatic void 1167178173Simpadmsw_set_filter(struct admsw_softc *sc) 1168178173Simp{ 1169178173Simp int i; 1170178173Simp uint32_t allmc, anymc, conf, promisc; 1171178173Simp struct ifnet *ifp; 1172178173Simp struct ifmultiaddr *ifma; 1173178173Simp 1174178173Simp /* Find which ports should be operated in promisc mode. */ 1175178173Simp allmc = anymc = promisc = 0; 1176178173Simp for (i = 0; i < SW_DEVS; i++) { 1177178173Simp ifp = sc->sc_ifnet[i]; 1178178173Simp if (ifp->if_flags & IFF_PROMISC) 1179178173Simp promisc |= vlan_matrix[i]; 1180178173Simp 1181178173Simp ifp->if_flags &= ~IFF_ALLMULTI; 1182178173Simp 1183195049Srwatson if_maddr_rlock(ifp); 1184178173Simp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 1185178173Simp { 1186178173Simp if (ifma->ifma_addr->sa_family != AF_LINK) 1187178173Simp continue; 1188178173Simp 1189178173Simp anymc |= vlan_matrix[i]; 1190178173Simp } 1191195049Srwatson if_maddr_runlock(ifp); 1192178173Simp } 1193178173Simp 1194178173Simp conf = REG_READ(CPUP_CONF_REG); 1195178173Simp /* 1 Disable forwarding of unknown & multicast packets to 1196178173Simp * CPU on all ports. 1197178173Simp * 2 Enable forwarding of unknown & multicast packets to 1198178173Simp * CPU on ports where IFF_PROMISC or IFF_ALLMULTI is set. 1199178173Simp */ 1200178173Simp conf |= CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK; 1201178173Simp /* Enable forwarding of unknown packets to CPU on selected ports. */ 1202178173Simp conf ^= ((promisc << CPUP_CONF_DUNP_SHIFT) & CPUP_CONF_DUNP_MASK); 1203178173Simp conf ^= ((allmc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK); 1204178173Simp conf ^= ((anymc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK); 1205178173Simp REG_WRITE(CPUP_CONF_REG, conf); 1206178173Simp} 1207178173Simp 1208178173Simp/* 1209178173Simp * admsw_add_rxbuf: 1210178173Simp * 1211178173Simp * Add a receive buffer to the indicated descriptor. 1212178173Simp */ 1213178173Simpint 1214178173Simpadmsw_add_rxbuf(struct admsw_softc *sc, int idx, int high) 1215178173Simp{ 1216178173Simp struct admsw_descsoft *ds; 1217178173Simp struct mbuf *m; 1218178173Simp int error; 1219178173Simp 1220178173Simp if (high) 1221178173Simp ds = &sc->sc_rxhsoft[idx]; 1222178173Simp else 1223178173Simp ds = &sc->sc_rxlsoft[idx]; 1224178173Simp 1225243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 1226178173Simp if (m == NULL) 1227178173Simp return (ENOBUFS); 1228178173Simp 1229243882Sglebius MCLGET(m, M_NOWAIT); 1230178173Simp if ((m->m_flags & M_EXT) == 0) { 1231178173Simp m_freem(m); 1232178173Simp return (ENOBUFS); 1233178173Simp } 1234178173Simp 1235178173Simp if (ds->ds_mbuf != NULL) 1236178173Simp bus_dmamap_unload(sc->sc_bufs_dmat, ds->ds_dmamap); 1237178173Simp 1238178173Simp ds->ds_mbuf = m; 1239178173Simp 1240178173Simp error = bus_dmamap_load(sc->sc_bufs_dmat, ds->ds_dmamap, 1241178173Simp m->m_ext.ext_buf, m->m_ext.ext_size, admsw_rxbuf_map_addr, 1242178173Simp ds, BUS_DMA_NOWAIT); 1243178173Simp if (error) { 1244178173Simp device_printf(sc->sc_dev, 1245178173Simp "can't load rx DMA map %d, error = %d\n", idx, error); 1246178173Simp panic("admsw_add_rxbuf"); /* XXX */ 1247178173Simp } 1248178173Simp 1249178173Simp bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, BUS_DMASYNC_PREREAD); 1250178173Simp 1251178173Simp if (high) 1252178173Simp ADMSW_INIT_RXHDESC(sc, idx); 1253178173Simp else 1254178173Simp ADMSW_INIT_RXLDESC(sc, idx); 1255178173Simp 1256178173Simp return (0); 1257178173Simp} 1258178173Simp 1259178173Simpint 1260178173Simpadmsw_mediachange(struct ifnet *ifp) 1261178173Simp{ 1262178173Simp struct admsw_softc *sc = ifp->if_softc; 1263178173Simp int port = 0; 1264178173Simp struct ifmedia *ifm; 1265178173Simp int old, new, val; 1266178173Simp 1267178173Simp while(port < SW_DEVS) { 1268178173Simp if(ifp == sc->sc_ifnet[port]) 1269178173Simp break; 1270178173Simp else 1271178173Simp port++; 1272178173Simp } 1273178173Simp 1274178173Simp ifm = &sc->sc_ifmedia[port]; 1275178173Simp 1276178173Simp if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1277178173Simp return (EINVAL); 1278178173Simp 1279178173Simp if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { 1280178173Simp val = PHY_CNTL2_AUTONEG|PHY_CNTL2_100M|PHY_CNTL2_FDX; 1281178173Simp } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) { 1282178173Simp if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 1283178173Simp val = PHY_CNTL2_100M|PHY_CNTL2_FDX; 1284178173Simp else 1285178173Simp val = PHY_CNTL2_100M; 1286178173Simp } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) { 1287178173Simp if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 1288178173Simp val = PHY_CNTL2_FDX; 1289178173Simp else 1290178173Simp val = 0; 1291178173Simp } else 1292178173Simp return (EINVAL); 1293178173Simp 1294178173Simp old = REG_READ(PHY_CNTL2_REG); 1295178173Simp new = old & ~((PHY_CNTL2_AUTONEG|PHY_CNTL2_100M|PHY_CNTL2_FDX) << port); 1296178173Simp new |= (val << port); 1297178173Simp 1298178173Simp if (new != old) 1299178173Simp REG_WRITE(PHY_CNTL2_REG, new); 1300178173Simp 1301178173Simp return (0); 1302178173Simp} 1303178173Simp 1304178173Simpvoid 1305178173Simpadmsw_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1306178173Simp{ 1307178173Simp struct admsw_softc *sc = ifp->if_softc; 1308178173Simp int port = 0; 1309178173Simp int status; 1310178173Simp 1311178173Simp while(port < SW_DEVS) { 1312178173Simp if(ifp == sc->sc_ifnet[port]) 1313178173Simp break; 1314178173Simp else 1315178173Simp port++; 1316178173Simp } 1317178173Simp 1318178173Simp ifmr->ifm_status = IFM_AVALID; 1319178173Simp ifmr->ifm_active = IFM_ETHER; 1320178173Simp 1321178173Simp status = REG_READ(PHY_ST_REG) >> port; 1322178173Simp 1323178173Simp if ((status & PHY_ST_LINKUP) == 0) { 1324178173Simp ifmr->ifm_active |= IFM_NONE; 1325178173Simp return; 1326178173Simp } 1327178173Simp 1328178173Simp ifmr->ifm_status |= IFM_ACTIVE; 1329178173Simp ifmr->ifm_active |= (status & PHY_ST_100M) ? IFM_100_TX : IFM_10_T; 1330178173Simp if (status & PHY_ST_FDX) 1331178173Simp ifmr->ifm_active |= IFM_FDX; 1332178173Simp} 1333178173Simp 1334178173Simpstatic device_method_t admsw_methods[] = { 1335178173Simp /* Device interface */ 1336178173Simp DEVMETHOD(device_probe, admsw_probe), 1337178173Simp DEVMETHOD(device_attach, admsw_attach), 1338178173Simp DEVMETHOD(device_detach, admsw_detach), 1339178173Simp DEVMETHOD(device_shutdown, admsw_shutdown), 1340178173Simp 1341178173Simp { 0, 0 } 1342178173Simp}; 1343178173Simp 1344178173Simpstatic devclass_t admsw_devclass; 1345178173Simp 1346178173Simpstatic driver_t admsw_driver = { 1347178173Simp "admsw", 1348178173Simp admsw_methods, 1349178173Simp sizeof(struct admsw_softc), 1350178173Simp}; 1351178173Simp 1352178173SimpDRIVER_MODULE(admsw, obio, admsw_driver, admsw_devclass, 0, 0); 1353178173SimpMODULE_DEPEND(admsw, ether, 1, 1, 1); 1354