1139749Simp/*- 2117632Sharti * Copyright (c) 2003 3117632Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4117632Sharti * All rights reserved. 5117632Sharti * 6117632Sharti * Redistribution and use in source and binary forms, with or without 7117632Sharti * modification, are permitted provided that the following conditions 8117632Sharti * are met: 9117632Sharti * 1. Redistributions of source code must retain the above copyright 10117632Sharti * notice, this list of conditions and the following disclaimer. 11117632Sharti * 2. Redistributions in binary form must reproduce the above copyright 12117632Sharti * notice, this list of conditions and the following disclaimer in the 13117632Sharti * documentation and/or other materials provided with the distribution. 14117632Sharti * 15117632Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16117632Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17117632Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18117632Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19117632Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20117632Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21117632Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22117632Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23117632Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24117632Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25117632Sharti * SUCH DAMAGE. 26117632Sharti * 27117632Sharti * Author: Hartmut Brandt <harti@freebsd.org> 28117632Sharti * 29117632Sharti * Driver for IDT77252 based cards like ProSum's. 30117632Sharti */ 31119418Sobrien 32117632Sharti#include <sys/cdefs.h> 33117632Sharti__FBSDID("$FreeBSD: releng/10.2/sys/dev/patm/if_patm_attach.c 232874 2012-03-12 18:15:08Z scottl $"); 34117632Sharti 35117632Sharti#include "opt_inet.h" 36117632Sharti#include "opt_natm.h" 37117632Sharti 38117632Sharti#include <sys/types.h> 39117632Sharti#include <sys/param.h> 40117632Sharti#include <sys/systm.h> 41117632Sharti#include <sys/malloc.h> 42117632Sharti#include <sys/kernel.h> 43117632Sharti#include <sys/bus.h> 44117632Sharti#include <sys/errno.h> 45117632Sharti#include <sys/conf.h> 46117632Sharti#include <sys/module.h> 47117632Sharti#include <sys/lock.h> 48117632Sharti#include <sys/mutex.h> 49117632Sharti#include <sys/sysctl.h> 50117632Sharti#include <sys/queue.h> 51117632Sharti#include <sys/condvar.h> 52117632Sharti#include <vm/uma.h> 53117632Sharti 54117632Sharti#include <sys/sockio.h> 55117632Sharti#include <sys/mbuf.h> 56117632Sharti#include <sys/socket.h> 57117632Sharti 58117632Sharti#include <net/if.h> 59117632Sharti#include <net/if_media.h> 60147256Sbrooks#include <net/if_types.h> 61117632Sharti#include <net/if_atm.h> 62117632Sharti#include <net/route.h> 63117632Sharti#ifdef ENABLE_BPF 64117632Sharti#include <net/bpf.h> 65117632Sharti#endif 66117632Sharti#include <netinet/in.h> 67117632Sharti#include <netinet/if_atm.h> 68117632Sharti 69117632Sharti#include <machine/bus.h> 70117632Sharti#include <machine/resource.h> 71117632Sharti#include <sys/bus.h> 72117632Sharti#include <sys/rman.h> 73117632Sharti#include <sys/mbpool.h> 74119285Simp#include <dev/pci/pcireg.h> 75119285Simp#include <dev/pci/pcivar.h> 76117632Sharti 77117632Sharti#include <dev/utopia/utopia.h> 78117632Sharti#include <dev/patm/idt77252reg.h> 79117632Sharti#include <dev/patm/if_patmvar.h> 80117632Sharti 81117632ShartiMODULE_DEPEND(patm, utopia, 1, 1, 1); 82117632ShartiMODULE_DEPEND(patm, pci, 1, 1, 1); 83117632ShartiMODULE_DEPEND(patm, atm, 1, 1, 1); 84117632ShartiMODULE_DEPEND(patm, libmbpool, 1, 1, 1); 85117632Sharti 86117632Shartidevclass_t patm_devclass; 87117632Sharti 88117632Shartistatic int patm_probe(device_t dev); 89117632Shartistatic int patm_attach(device_t dev); 90117632Shartistatic int patm_detach(device_t dev); 91117632Shartistatic device_method_t patm_methods[] = { 92117632Sharti DEVMETHOD(device_probe, patm_probe), 93117632Sharti DEVMETHOD(device_attach, patm_attach), 94117632Sharti DEVMETHOD(device_detach, patm_detach), 95117632Sharti {0,0} 96117632Sharti}; 97117632Shartistatic driver_t patm_driver = { 98117632Sharti "patm", 99117632Sharti patm_methods, 100117632Sharti sizeof(struct patm_softc), 101117632Sharti}; 102117632ShartiDRIVER_MODULE(patm, pci, patm_driver, patm_devclass, NULL, 0); 103117632Sharti 104117632Shartistatic const struct { 105117632Sharti u_int devid; 106117632Sharti const char *desc; 107117632Sharti} devs[] = { 108117632Sharti { PCI_DEVICE_IDT77252, "NICStAR (77222/77252) ATM adapter" }, 109117632Sharti { PCI_DEVICE_IDT77v252, "NICStAR (77v252) ATM adapter" }, 110117632Sharti { PCI_DEVICE_IDT77v222, "NICStAR (77v222) ATM adapter" }, 111117632Sharti { 0, NULL } 112117632Sharti}; 113117632Sharti 114117632ShartiSYSCTL_DECL(_hw_atm); 115117632Sharti 116117632Shartistatic int patm_phy_readregs(struct ifatm *, u_int, uint8_t *, u_int *); 117117632Shartistatic int patm_phy_writereg(struct ifatm *, u_int, u_int, u_int); 118117632Shartistatic const struct utopia_methods patm_utopia_methods = { 119117632Sharti patm_phy_readregs, 120117632Sharti patm_phy_writereg 121117632Sharti}; 122117632Sharti 123117632Shartistatic void patm_destroy(struct patm_softc *sc); 124117632Sharti 125117632Shartistatic int patm_sysctl_istats(SYSCTL_HANDLER_ARGS); 126117632Shartistatic int patm_sysctl_eeprom(SYSCTL_HANDLER_ARGS); 127117632Sharti 128117632Shartistatic void patm_read_eeprom(struct patm_softc *sc); 129117632Shartistatic int patm_sq_init(struct patm_softc *sc); 130117632Shartistatic int patm_rbuf_init(struct patm_softc *sc); 131117632Shartistatic int patm_txmap_init(struct patm_softc *sc); 132117632Sharti 133117632Shartistatic void patm_env_getuint(struct patm_softc *, u_int *, const char *); 134117632Sharti 135117632Sharti#ifdef PATM_DEBUG 136117632Shartistatic int patm_sysctl_regs(SYSCTL_HANDLER_ARGS); 137117632Shartistatic int patm_sysctl_tsq(SYSCTL_HANDLER_ARGS); 138117632Shartiint patm_dump_vc(u_int unit, u_int vc) __unused; 139117632Shartiint patm_dump_regs(u_int unit) __unused; 140117632Shartiint patm_dump_sram(u_int unit, u_int from, u_int words) __unused; 141117632Sharti#endif 142117632Sharti 143117632Sharti/* 144117632Sharti * Probe for a IDT77252 controller 145117632Sharti */ 146117632Shartistatic int 147117632Shartipatm_probe(device_t dev) 148117632Sharti{ 149117632Sharti u_int i; 150117632Sharti 151117632Sharti if (pci_get_vendor(dev) == PCI_VENDOR_IDT) { 152117632Sharti for (i = 0; devs[i].desc != NULL; i++) 153117632Sharti if (pci_get_device(dev) == devs[i].devid) { 154117632Sharti device_set_desc(dev, devs[i].desc); 155143158Simp return (BUS_PROBE_DEFAULT); 156117632Sharti } 157117632Sharti } 158117632Sharti return (ENXIO); 159117632Sharti} 160117632Sharti 161117632Sharti/* 162117632Sharti * Attach 163117632Sharti */ 164117632Shartistatic int 165117632Shartipatm_attach(device_t dev) 166117632Sharti{ 167117632Sharti struct patm_softc *sc; 168117632Sharti int error; 169117632Sharti struct ifnet *ifp; 170117632Sharti int rid; 171117632Sharti u_int a; 172117632Sharti 173117632Sharti static const struct idt_mmap idt_mmap[4] = IDT_MMAP; 174117632Sharti 175117632Sharti sc = device_get_softc(dev); 176117632Sharti 177117632Sharti sc->dev = dev; 178117632Sharti#ifdef IATM_DEBUG 179117632Sharti sc->debug = IATM_DEBUG; 180117632Sharti#endif 181147256Sbrooks ifp = sc->ifp = if_alloc(IFT_ATM); 182147256Sbrooks if (ifp == NULL) { 183147256Sbrooks return (ENOSPC); 184147256Sbrooks } 185117632Sharti 186147256Sbrooks IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_IDTABR25; 187147256Sbrooks IFP2IFATM(sc->ifp)->mib.serial = 0; 188147256Sbrooks IFP2IFATM(sc->ifp)->mib.hw_version = 0; 189147256Sbrooks IFP2IFATM(sc->ifp)->mib.sw_version = 0; 190147256Sbrooks IFP2IFATM(sc->ifp)->mib.vpi_bits = PATM_VPI_BITS; 191147256Sbrooks IFP2IFATM(sc->ifp)->mib.vci_bits = 0; /* set below */; 192147256Sbrooks IFP2IFATM(sc->ifp)->mib.max_vpcs = 0; 193147256Sbrooks IFP2IFATM(sc->ifp)->mib.max_vccs = 0; /* set below */ 194147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN; 195147256Sbrooks IFP2IFATM(sc->ifp)->phy = &sc->utopia; 196147256Sbrooks 197117632Sharti ifp->if_softc = sc; 198121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 199117632Sharti ifp->if_flags = IFF_SIMPLEX; 200117632Sharti ifp->if_init = patm_init; 201117632Sharti ifp->if_ioctl = patm_ioctl; 202117632Sharti ifp->if_start = patm_start; 203117632Sharti 204117632Sharti /* do this early so we can destroy unconditionally */ 205117632Sharti mtx_init(&sc->mtx, device_get_nameunit(dev), 206117632Sharti MTX_NETWORK_LOCK, MTX_DEF); 207117632Sharti mtx_init(&sc->tst_lock, "tst lock", NULL, MTX_DEF); 208117632Sharti cv_init(&sc->vcc_cv, "vcc_close"); 209117632Sharti 210119137Ssam callout_init(&sc->tst_callout, CALLOUT_MPSAFE); 211117632Sharti 212117632Sharti sysctl_ctx_init(&sc->sysctl_ctx); 213117632Sharti 214117632Sharti /* 215117632Sharti * Get revision 216117632Sharti */ 217117632Sharti sc->revision = pci_read_config(dev, PCIR_REVID, 4) & 0xf; 218117632Sharti 219117632Sharti /* 220117632Sharti * Enable PCI bus master and memory 221117632Sharti */ 222117632Sharti pci_enable_busmaster(dev); 223117632Sharti 224117632Sharti rid = IDT_PCI_REG_MEMBASE; 225127135Snjl sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 226127135Snjl RF_ACTIVE); 227117632Sharti if (sc->memres == NULL) { 228117632Sharti patm_printf(sc, "could not map memory\n"); 229117632Sharti error = ENXIO; 230117632Sharti goto fail; 231117632Sharti } 232117632Sharti sc->memh = rman_get_bushandle(sc->memres); 233117632Sharti sc->memt = rman_get_bustag(sc->memres); 234117632Sharti 235117632Sharti /* 236117632Sharti * Allocate the interrupt (enable it later) 237117632Sharti */ 238117632Sharti sc->irqid = 0; 239127135Snjl sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 240127135Snjl RF_SHAREABLE | RF_ACTIVE); 241117632Sharti if (sc->irqres == 0) { 242117632Sharti patm_printf(sc, "could not allocate irq\n"); 243117632Sharti error = ENXIO; 244117632Sharti goto fail; 245117632Sharti } 246117632Sharti 247117632Sharti /* 248117632Sharti * Construct the sysctl tree 249117632Sharti */ 250117632Sharti error = ENOMEM; 251117632Sharti if ((sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, 252117632Sharti SYSCTL_STATIC_CHILDREN(_hw_atm), OID_AUTO, 253117632Sharti device_get_nameunit(dev), CTLFLAG_RD, 0, "")) == NULL) 254117632Sharti goto fail; 255117632Sharti 256117632Sharti if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 257217556Smdf OID_AUTO, "istats", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, 258217556Smdf patm_sysctl_istats, "S", "internal statistics") == NULL) 259117632Sharti goto fail; 260117632Sharti 261117632Sharti if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 262217556Smdf OID_AUTO, "eeprom", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, 263217556Smdf patm_sysctl_eeprom, "S", "EEPROM contents") == NULL) 264117632Sharti goto fail; 265117632Sharti 266117632Sharti if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 267117632Sharti OID_AUTO, "lbuf_max", CTLFLAG_RD, &sc->lbuf_max, 268117632Sharti 0, "maximum number of large receive buffers") == NULL) 269117632Sharti goto fail; 270117632Sharti patm_env_getuint(sc, &sc->lbuf_max, "lbuf_max"); 271117632Sharti 272117632Sharti if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 273117632Sharti OID_AUTO, "max_txmaps", CTLFLAG_RW, &sc->tx_maxmaps, 274117632Sharti 0, "maximum number of TX DMA maps") == NULL) 275117632Sharti goto fail; 276117632Sharti patm_env_getuint(sc, &sc->tx_maxmaps, "tx_maxmaps"); 277117632Sharti 278117632Sharti#ifdef PATM_DEBUG 279117632Sharti if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 280117632Sharti OID_AUTO, "debug", CTLFLAG_RW, &sc->debug, 281117632Sharti 0, "debug flags") == NULL) 282117632Sharti goto fail; 283117632Sharti sc->debug = PATM_DEBUG; 284117632Sharti patm_env_getuint(sc, &sc->debug, "debug"); 285117632Sharti 286117632Sharti if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 287217566Smdf OID_AUTO, "regs", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, 288217566Smdf patm_sysctl_regs, "S", "registers") == NULL) 289117632Sharti goto fail; 290117632Sharti 291117632Sharti if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 292217566Smdf OID_AUTO, "tsq", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, 293217566Smdf patm_sysctl_tsq, "S", "TSQ") == NULL) 294117632Sharti goto fail; 295117632Sharti#endif 296117632Sharti 297117632Sharti patm_reset(sc); 298117632Sharti 299117632Sharti /* 300117632Sharti * Detect and attach the phy. 301117632Sharti */ 302117632Sharti patm_debug(sc, ATTACH, "attaching utopia"); 303147256Sbrooks IFP2IFATM(sc->ifp)->phy = &sc->utopia; 304147256Sbrooks utopia_attach(&sc->utopia, IFP2IFATM(sc->ifp), &sc->media, &sc->mtx, 305117632Sharti &sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), 306117632Sharti &patm_utopia_methods); 307117632Sharti 308117632Sharti /* 309117632Sharti * Start the PHY because we need the autodetection 310117632Sharti */ 311117632Sharti patm_debug(sc, ATTACH, "starting utopia"); 312117632Sharti mtx_lock(&sc->mtx); 313117632Sharti utopia_start(&sc->utopia); 314117632Sharti utopia_reset(&sc->utopia); 315117632Sharti mtx_unlock(&sc->mtx); 316117632Sharti 317117632Sharti /* Read EEPROM */ 318117632Sharti patm_read_eeprom(sc); 319117632Sharti 320117632Sharti /* analyze it */ 321117632Sharti if (strncmp(sc->eeprom + PATM_PROATM_NAME_OFFSET, PATM_PROATM_NAME, 322117632Sharti strlen(PATM_PROATM_NAME)) == 0) { 323117632Sharti if (sc->utopia.chip->type == UTP_TYPE_IDT77105) { 324147256Sbrooks IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_PROATM25; 325147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_25_6M; 326147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_25; 327117632Sharti sc->flags |= PATM_25M; 328117632Sharti patm_printf(sc, "ProATM 25 interface; "); 329117632Sharti 330117632Sharti } else { 331117632Sharti /* cannot really know which media */ 332147256Sbrooks IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_PROATM155; 333147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_155M; 334147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155; 335117632Sharti patm_printf(sc, "ProATM 155 interface; "); 336117632Sharti } 337117632Sharti 338147256Sbrooks bcopy(sc->eeprom + PATM_PROATM_MAC_OFFSET, IFP2IFATM(sc->ifp)->mib.esi, 339147256Sbrooks sizeof(IFP2IFATM(sc->ifp)->mib.esi)); 340117632Sharti 341117632Sharti } else { 342117632Sharti if (sc->utopia.chip->type == UTP_TYPE_IDT77105) { 343147256Sbrooks IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_IDTABR25; 344147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_25_6M; 345147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_25; 346117632Sharti sc->flags |= PATM_25M; 347117632Sharti patm_printf(sc, "IDT77252 25MBit interface; "); 348117632Sharti 349117632Sharti } else { 350117632Sharti /* cannot really know which media */ 351147256Sbrooks IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_IDTABR155; 352147256Sbrooks IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_155M; 353147256Sbrooks IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155; 354117632Sharti patm_printf(sc, "IDT77252 155MBit interface; "); 355117632Sharti } 356117632Sharti 357147256Sbrooks bcopy(sc->eeprom + PATM_IDT_MAC_OFFSET, IFP2IFATM(sc->ifp)->mib.esi, 358147256Sbrooks sizeof(IFP2IFATM(sc->ifp)->mib.esi)); 359117632Sharti } 360117632Sharti printf("idt77252 Rev. %c; %s PHY\n", 'A' + sc->revision, 361117632Sharti sc->utopia.chip->name); 362117632Sharti 363117632Sharti utopia_reset_media(&sc->utopia); 364117632Sharti utopia_init_media(&sc->utopia); 365117632Sharti 366117632Sharti /* 367117632Sharti * Determine RAM size 368117632Sharti */ 369117632Sharti for (a = 0; a < 0x20000; a++) 370117632Sharti patm_sram_write(sc, a, 0); 371117632Sharti patm_sram_write(sc, 0, 0xdeadbeef); 372117632Sharti if (patm_sram_read(sc, 0x4004) == 0xdeadbeef) 373117632Sharti sc->mmap = &idt_mmap[0]; 374117632Sharti else if (patm_sram_read(sc, 0x8000) == 0xdeadbeef) 375117632Sharti sc->mmap = &idt_mmap[1]; 376117632Sharti else if (patm_sram_read(sc, 0x20000) == 0xdeadbeef) 377117632Sharti sc->mmap = &idt_mmap[2]; 378117632Sharti else 379117632Sharti sc->mmap = &idt_mmap[3]; 380117632Sharti 381147256Sbrooks IFP2IFATM(sc->ifp)->mib.vci_bits = sc->mmap->vcbits - IFP2IFATM(sc->ifp)->mib.vpi_bits; 382147256Sbrooks IFP2IFATM(sc->ifp)->mib.max_vccs = sc->mmap->max_conn; 383117632Sharti patm_sram_write(sc, 0, 0); 384117632Sharti patm_printf(sc, "%uK x 32 SRAM; %u connections\n", sc->mmap->sram, 385117632Sharti sc->mmap->max_conn); 386117632Sharti 387117632Sharti /* initialize status queues */ 388117632Sharti error = patm_sq_init(sc); 389117632Sharti if (error != 0) 390117632Sharti goto fail; 391117632Sharti 392117632Sharti /* get TST */ 393117632Sharti sc->tst_soft = malloc(sizeof(uint32_t) * sc->mmap->tst_size, 394117632Sharti M_DEVBUF, M_WAITOK); 395117632Sharti 396117632Sharti /* allocate all the receive buffer stuff */ 397117632Sharti error = patm_rbuf_init(sc); 398117632Sharti if (error != 0) 399117632Sharti goto fail; 400117632Sharti 401117632Sharti /* 402117632Sharti * Allocate SCD tag 403117632Sharti * 404117632Sharti * Don't use BUS_DMA_ALLOCNOW, because we never need bouncing with 405117632Sharti * bus_dmamem_alloc() 406117632Sharti */ 407232874Sscottl error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0, 408117632Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 409117632Sharti NULL, NULL, sizeof(struct patm_scd), 1, 410117632Sharti sizeof(struct patm_scd), 0, NULL, NULL, &sc->scd_tag); 411117632Sharti if (error) { 412117632Sharti patm_printf(sc, "SCD DMA tag create %d\n", error); 413117632Sharti goto fail; 414117632Sharti } 415117632Sharti LIST_INIT(&sc->scd_list); 416117632Sharti 417117632Sharti /* allocate VCC zone and pointers */ 418117632Sharti if ((sc->vcc_zone = uma_zcreate("PATM vccs", sizeof(struct patm_vcc), 419117632Sharti NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0)) == NULL) { 420117632Sharti patm_printf(sc, "cannot allocate zone for vccs\n"); 421117632Sharti goto fail; 422117632Sharti } 423117632Sharti sc->vccs = malloc(sizeof(sc->vccs[0]) * sc->mmap->max_conn, 424117632Sharti M_DEVBUF, M_WAITOK | M_ZERO); 425117632Sharti 426117632Sharti /* allocate transmission resources */ 427117632Sharti error = patm_txmap_init(sc); 428117632Sharti if (error != 0) 429117632Sharti goto fail; 430117632Sharti 431117632Sharti /* poll while we are not running */ 432117632Sharti sc->utopia.flags |= UTP_FL_POLL_CARRIER; 433117632Sharti 434117632Sharti patm_debug(sc, ATTACH, "attaching interface"); 435117632Sharti atm_ifattach(ifp); 436117632Sharti 437117632Sharti#ifdef ENABLE_BPF 438117632Sharti bpfattach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc)); 439117632Sharti#endif 440117632Sharti 441117632Sharti patm_debug(sc, ATTACH, "attaching interrupt handler"); 442156949Sharti error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_NET | INTR_MPSAFE, 443166901Spiso NULL, patm_intr, sc, &sc->ih); 444117632Sharti if (error != 0) { 445117632Sharti patm_printf(sc, "could not setup interrupt\n"); 446147256Sbrooks atm_ifdetach(sc->ifp); 447147256Sbrooks if_free(sc->ifp); 448117632Sharti goto fail; 449117632Sharti } 450117632Sharti 451117632Sharti return (0); 452117632Sharti 453117632Sharti fail: 454117632Sharti patm_destroy(sc); 455117632Sharti return (error); 456117632Sharti} 457117632Sharti 458117632Sharti/* 459117632Sharti * Detach 460117632Sharti */ 461117632Shartistatic int 462117632Shartipatm_detach(device_t dev) 463117632Sharti{ 464117632Sharti struct patm_softc *sc; 465117632Sharti 466147721Sharti sc = device_get_softc(dev); 467117632Sharti 468117632Sharti mtx_lock(&sc->mtx); 469117632Sharti patm_stop(sc); 470117632Sharti if (sc->utopia.state & UTP_ST_ATTACHED) { 471117632Sharti patm_debug(sc, ATTACH, "detaching utopia"); 472117632Sharti utopia_stop(&sc->utopia); 473117632Sharti utopia_detach(&sc->utopia); 474117632Sharti } 475117632Sharti mtx_unlock(&sc->mtx); 476117632Sharti 477147256Sbrooks atm_ifdetach(sc->ifp); 478117632Sharti 479117632Sharti patm_destroy(sc); 480117632Sharti 481117632Sharti return (0); 482117632Sharti} 483117632Sharti 484117632Sharti/* 485117632Sharti * Destroy everything. Assume we are stopped. 486117632Sharti */ 487117632Shartistatic void 488117632Shartipatm_destroy(struct patm_softc *sc) 489117632Sharti{ 490117632Sharti u_int i; 491117632Sharti struct patm_txmap *map; 492117632Sharti 493117632Sharti if (sc->ih != NULL) 494117632Sharti bus_teardown_intr(sc->dev, sc->irqres, sc->ih); 495117632Sharti 496117632Sharti if (sc->tx_mapzone != NULL) { 497117632Sharti /* all maps must be free */ 498117632Sharti while ((map = SLIST_FIRST(&sc->tx_maps_free)) != NULL) { 499117632Sharti bus_dmamap_destroy(sc->tx_tag, map->map); 500117632Sharti SLIST_REMOVE_HEAD(&sc->tx_maps_free, link); 501117632Sharti uma_zfree(sc->tx_mapzone, map); 502117632Sharti } 503117632Sharti uma_zdestroy(sc->tx_mapzone); 504117632Sharti } 505117632Sharti 506117632Sharti if (sc->scd_tag != NULL) 507117632Sharti bus_dma_tag_destroy(sc->scd_tag); 508117632Sharti 509117632Sharti if (sc->tx_tag != NULL) 510117632Sharti bus_dma_tag_destroy(sc->scd_tag); 511117632Sharti 512117632Sharti if (sc->vccs != NULL) { 513117632Sharti for (i = 0; i < sc->mmap->max_conn; i++) 514117632Sharti if (sc->vccs[i] != NULL) 515117632Sharti uma_zfree(sc->vcc_zone, sc->vccs[i]); 516117632Sharti free(sc->vccs, M_DEVBUF); 517117632Sharti } 518117632Sharti if (sc->vcc_zone != NULL) 519117632Sharti uma_zdestroy(sc->vcc_zone); 520117632Sharti 521117632Sharti if (sc->lbufs != NULL) { 522117632Sharti for (i = 0; i < sc->lbuf_max; i++) 523117632Sharti bus_dmamap_destroy(sc->lbuf_tag, sc->lbufs[i].map); 524117632Sharti free(sc->lbufs, M_DEVBUF); 525117632Sharti } 526117632Sharti 527117632Sharti if (sc->lbuf_tag != NULL) 528117632Sharti bus_dma_tag_destroy(sc->lbuf_tag); 529117632Sharti 530117632Sharti if (sc->sbuf_pool != NULL) 531117632Sharti mbp_destroy(sc->sbuf_pool); 532117632Sharti if (sc->vbuf_pool != NULL) 533117632Sharti mbp_destroy(sc->vbuf_pool); 534117632Sharti 535117632Sharti if (sc->sbuf_tag != NULL) 536117632Sharti bus_dma_tag_destroy(sc->sbuf_tag); 537117632Sharti 538117632Sharti if (sc->tst_soft != NULL) 539117632Sharti free(sc->tst_soft, M_DEVBUF); 540117632Sharti 541117632Sharti /* 542117632Sharti * Free all status queue memory resources 543117632Sharti */ 544117632Sharti if (sc->tsq != NULL) { 545117632Sharti bus_dmamap_unload(sc->sq_tag, sc->sq_map); 546117632Sharti bus_dmamem_free(sc->sq_tag, sc->tsq, sc->sq_map); 547117632Sharti bus_dma_tag_destroy(sc->sq_tag); 548117632Sharti } 549117632Sharti 550117632Sharti if (sc->irqres != NULL) 551117632Sharti bus_release_resource(sc->dev, SYS_RES_IRQ, 552117632Sharti sc->irqid, sc->irqres); 553117632Sharti if (sc->memres != NULL) 554117632Sharti bus_release_resource(sc->dev, SYS_RES_MEMORY, 555117632Sharti IDT_PCI_REG_MEMBASE, sc->memres); 556117632Sharti 557117632Sharti /* this was initialize unconditionally */ 558117632Sharti sysctl_ctx_free(&sc->sysctl_ctx); 559117632Sharti cv_destroy(&sc->vcc_cv); 560117632Sharti mtx_destroy(&sc->tst_lock); 561117632Sharti mtx_destroy(&sc->mtx); 562150220Sru 563150220Sru if (sc->ifp != NULL) 564150220Sru if_free(sc->ifp); 565117632Sharti} 566117632Sharti 567117632Sharti/* 568117632Sharti * Try to find a variable in the environment and parse it as an unsigned 569117632Sharti * integer. 570117632Sharti */ 571117632Shartistatic void 572117632Shartipatm_env_getuint(struct patm_softc *sc, u_int *var, const char *name) 573117632Sharti{ 574117632Sharti char full[IFNAMSIZ + 3 + 20]; 575117632Sharti char *val, *end; 576117632Sharti u_long u; 577117632Sharti 578117632Sharti snprintf(full, sizeof(full), "hw.%s.%s", 579117632Sharti device_get_nameunit(sc->dev), name); 580117632Sharti 581117632Sharti if ((val = getenv(full)) != NULL) { 582117632Sharti u = strtoul(val, &end, 0); 583117632Sharti if (end > val && *end == '\0') { 584117632Sharti if (bootverbose) 585117632Sharti patm_printf(sc, "%s=%lu\n", full, u); 586117632Sharti *var = u; 587117632Sharti } 588117632Sharti freeenv(val); 589117632Sharti } 590117632Sharti} 591117632Sharti 592117632Sharti/* 593117632Sharti * Sysctl handler for internal statistics 594117632Sharti * 595117632Sharti * LOCK: unlocked, needed 596117632Sharti */ 597117632Shartistatic int 598117632Shartipatm_sysctl_istats(SYSCTL_HANDLER_ARGS) 599117632Sharti{ 600117632Sharti struct patm_softc *sc = arg1; 601117632Sharti uint32_t *ret; 602117632Sharti int error; 603117632Sharti 604117632Sharti ret = malloc(sizeof(sc->stats), M_TEMP, M_WAITOK); 605117632Sharti 606117632Sharti mtx_lock(&sc->mtx); 607117632Sharti bcopy(&sc->stats, ret, sizeof(sc->stats)); 608117632Sharti mtx_unlock(&sc->mtx); 609117632Sharti 610117632Sharti error = SYSCTL_OUT(req, ret, sizeof(sc->stats)); 611117632Sharti free(ret, M_TEMP); 612117632Sharti 613117632Sharti return (error); 614117632Sharti} 615117632Sharti 616117632Sharti/* 617117632Sharti * Sysctl handler for EEPROM 618117632Sharti * 619117632Sharti * LOCK: unlocked, needed 620117632Sharti */ 621117632Shartistatic int 622117632Shartipatm_sysctl_eeprom(SYSCTL_HANDLER_ARGS) 623117632Sharti{ 624117632Sharti struct patm_softc *sc = arg1; 625117632Sharti void *ret; 626117632Sharti int error; 627117632Sharti 628117632Sharti ret = malloc(sizeof(sc->eeprom), M_TEMP, M_WAITOK); 629117632Sharti 630117632Sharti mtx_lock(&sc->mtx); 631117632Sharti bcopy(sc->eeprom, ret, sizeof(sc->eeprom)); 632117632Sharti mtx_unlock(&sc->mtx); 633117632Sharti 634117632Sharti error = SYSCTL_OUT(req, ret, sizeof(sc->eeprom)); 635117632Sharti free(ret, M_TEMP); 636117632Sharti 637117632Sharti return (error); 638117632Sharti} 639117632Sharti 640117632Sharti/* 641117632Sharti * Read the EEPROM. We assume that this is a XIRCOM 25020 642117632Sharti */ 643117632Shartistatic void 644117632Shartipatm_read_eeprom(struct patm_softc *sc) 645117632Sharti{ 646117632Sharti u_int gp; 647117632Sharti uint8_t byte; 648117632Sharti int i, addr; 649117632Sharti 650117632Sharti static const uint32_t tab[] = { 651117632Sharti /* CS transition to reset the chip */ 652117632Sharti IDT_GP_EECS | IDT_GP_EESCLK, 0, 653117632Sharti /* read command 0x03 */ 654117632Sharti IDT_GP_EESCLK, 0, 655117632Sharti IDT_GP_EESCLK, 0, 656117632Sharti IDT_GP_EESCLK, 0, 657117632Sharti IDT_GP_EESCLK, 0, 658117632Sharti IDT_GP_EESCLK, 0, 659117632Sharti IDT_GP_EESCLK, IDT_GP_EEDO, 660117632Sharti IDT_GP_EESCLK | IDT_GP_EEDO, IDT_GP_EEDO, 661117632Sharti IDT_GP_EESCLK | IDT_GP_EEDO, 0, 662117632Sharti /* address 0x00 */ 663117632Sharti IDT_GP_EESCLK, 0, 664117632Sharti IDT_GP_EESCLK, 0, 665117632Sharti IDT_GP_EESCLK, 0, 666117632Sharti IDT_GP_EESCLK, 0, 667117632Sharti IDT_GP_EESCLK, 0, 668117632Sharti IDT_GP_EESCLK, 0, 669117632Sharti IDT_GP_EESCLK, 0, 670117632Sharti IDT_GP_EESCLK, 0, 671117632Sharti }; 672117632Sharti 673117632Sharti /* go to a known state (chip enabled) */ 674117632Sharti gp = patm_nor_read(sc, IDT_NOR_GP); 675117632Sharti gp &= ~(IDT_GP_EESCLK | IDT_GP_EECS | IDT_GP_EEDO); 676117632Sharti 677117632Sharti for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) { 678117632Sharti patm_nor_write(sc, IDT_NOR_GP, gp | tab[i]); 679117632Sharti DELAY(40); 680117632Sharti } 681117632Sharti 682117632Sharti /* read out the prom */ 683117632Sharti for (addr = 0; addr < 256; addr++) { 684117632Sharti byte = 0; 685117632Sharti for (i = 0; i < 8; i++) { 686117632Sharti byte <<= 1; 687117632Sharti if (patm_nor_read(sc, IDT_NOR_GP) & IDT_GP_EEDI) 688117632Sharti byte |= 1; 689117632Sharti /* rising CLK */ 690117632Sharti patm_nor_write(sc, IDT_NOR_GP, gp | IDT_GP_EESCLK); 691117632Sharti DELAY(40); 692117632Sharti /* falling clock */ 693117632Sharti patm_nor_write(sc, IDT_NOR_GP, gp); 694117632Sharti DELAY(40); 695117632Sharti } 696117632Sharti sc->eeprom[addr] = byte; 697117632Sharti } 698117632Sharti} 699117632Sharti 700117632Sharti/* 701117632Sharti * PHY access read 702117632Sharti */ 703117632Shartistatic int 704117632Shartipatm_phy_readregs(struct ifatm *ifatm, u_int reg, uint8_t *val, u_int *n) 705117632Sharti{ 706147256Sbrooks struct patm_softc *sc = ifatm->ifp->if_softc; 707117632Sharti u_int cnt = *n; 708117632Sharti 709117632Sharti if (reg >= 0x100) 710117632Sharti return (EINVAL); 711117632Sharti 712117632Sharti patm_cmd_wait(sc); 713117632Sharti while (reg < 0x100 && cnt > 0) { 714117632Sharti patm_nor_write(sc, IDT_NOR_CMD, IDT_MKCMD_RUTIL(1, 0, reg)); 715117632Sharti patm_cmd_wait(sc); 716117632Sharti *val = patm_nor_read(sc, IDT_NOR_D0); 717117632Sharti patm_debug(sc, PHY, "phy(%02x)=%02x", reg, *val); 718117632Sharti val++; 719117632Sharti reg++; 720117632Sharti cnt--; 721117632Sharti } 722117632Sharti *n = *n - cnt; 723117632Sharti return (0); 724117632Sharti} 725117632Sharti 726117632Sharti/* 727117632Sharti * Write PHY reg 728117632Sharti */ 729117632Shartistatic int 730117632Shartipatm_phy_writereg(struct ifatm *ifatm, u_int reg, u_int mask, u_int val) 731117632Sharti{ 732147256Sbrooks struct patm_softc *sc = ifatm->ifp->if_softc; 733117632Sharti u_int old, new; 734117632Sharti 735117632Sharti if (reg >= 0x100) 736117632Sharti return (EINVAL); 737117632Sharti 738117632Sharti patm_cmd_wait(sc); 739117632Sharti patm_nor_write(sc, IDT_NOR_CMD, IDT_MKCMD_RUTIL(1, 0, reg)); 740117632Sharti patm_cmd_wait(sc); 741117632Sharti 742117632Sharti old = patm_nor_read(sc, IDT_NOR_D0); 743117632Sharti new = (old & ~mask) | (val & mask); 744117632Sharti patm_debug(sc, PHY, "phy(%02x) %02x -> %02x", reg, old, new); 745117632Sharti 746117632Sharti patm_nor_write(sc, IDT_NOR_D0, new); 747117632Sharti patm_nor_write(sc, IDT_NOR_CMD, IDT_MKCMD_WUTIL(1, 0, reg)); 748117632Sharti patm_cmd_wait(sc); 749117632Sharti 750117632Sharti return (0); 751117632Sharti} 752117632Sharti 753117632Sharti/* 754117632Sharti * Allocate a large chunk of DMA able memory for the transmit 755117632Sharti * and receive status queues. We align this to a page boundary 756117632Sharti * to ensure the alignment. 757117632Sharti */ 758117632Shartistatic int 759117632Shartipatm_sq_init(struct patm_softc *sc) 760117632Sharti{ 761117632Sharti int error; 762117632Sharti void *p; 763117632Sharti 764117632Sharti /* compute size of the two queues */ 765117632Sharti sc->sq_size = IDT_TSQ_SIZE * IDT_TSQE_SIZE + 766117632Sharti PATM_RSQ_SIZE * IDT_RSQE_SIZE + 767117632Sharti IDT_RAWHND_SIZE; 768117632Sharti 769117632Sharti patm_debug(sc, ATTACH, 770117632Sharti "allocating status queues (%zu) ...", sc->sq_size); 771117632Sharti 772117632Sharti /* 773117632Sharti * allocate tag 774117632Sharti * Don't use BUS_DMA_ALLOCNOW, because we never need bouncing with 775117632Sharti * bus_dmamem_alloc() 776117632Sharti */ 777232874Sscottl error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 778232874Sscottl PATM_SQ_ALIGNMENT, 0, 779117632Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 780117632Sharti NULL, NULL, sc->sq_size, 1, sc->sq_size, 781117632Sharti 0, NULL, NULL, &sc->sq_tag); 782117632Sharti if (error) { 783117632Sharti patm_printf(sc, "memory DMA tag create %d\n", error); 784117632Sharti return (error); 785117632Sharti } 786117632Sharti 787117632Sharti /* allocate memory */ 788117632Sharti error = bus_dmamem_alloc(sc->sq_tag, &p, 0, &sc->sq_map); 789117632Sharti if (error) { 790117632Sharti patm_printf(sc, "memory DMA alloc %d\n", error); 791117632Sharti bus_dma_tag_destroy(sc->sq_tag); 792117632Sharti return (error); 793117632Sharti } 794117632Sharti 795117632Sharti /* map it */ 796117632Sharti sc->tsq_phy = 0x1fff; 797117632Sharti error = bus_dmamap_load(sc->sq_tag, sc->sq_map, p, 798117632Sharti sc->sq_size, patm_load_callback, &sc->tsq_phy, BUS_DMA_NOWAIT); 799117632Sharti if (error) { 800117632Sharti patm_printf(sc, "memory DMA map load %d\n", error); 801117632Sharti bus_dmamem_free(sc->sq_tag, p, sc->sq_map); 802117632Sharti bus_dma_tag_destroy(sc->sq_tag); 803117632Sharti return (error); 804117632Sharti } 805117632Sharti 806117632Sharti /* set queue start */ 807117632Sharti sc->tsq = p; 808117632Sharti sc->rsq = (void *)((char *)p + IDT_TSQ_SIZE * IDT_TSQE_SIZE); 809117632Sharti sc->rsq_phy = sc->tsq_phy + IDT_TSQ_SIZE * IDT_TSQE_SIZE; 810117632Sharti sc->rawhnd = (void *)((char *)sc->rsq + PATM_RSQ_SIZE * IDT_RSQE_SIZE); 811117632Sharti sc->rawhnd_phy = sc->rsq_phy + PATM_RSQ_SIZE * IDT_RSQE_SIZE; 812117632Sharti 813117632Sharti return (0); 814117632Sharti} 815117632Sharti 816117632Sharti/* 817117632Sharti * Initialize all receive buffer stuff 818117632Sharti */ 819117632Shartistatic int 820117632Shartipatm_rbuf_init(struct patm_softc *sc) 821117632Sharti{ 822117632Sharti u_int i; 823117632Sharti int error; 824117632Sharti 825117632Sharti patm_debug(sc, ATTACH, "allocating Rx buffer resources ..."); 826117632Sharti /* 827117632Sharti * Create a tag for small buffers. We allocate these page wise. 828117632Sharti * Don't use BUS_DMA_ALLOCNOW, because we never need bouncing with 829117632Sharti * bus_dmamem_alloc() 830117632Sharti */ 831232874Sscottl if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0, 832117632Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 833117632Sharti SMBUF_PAGE_SIZE, 1, SMBUF_PAGE_SIZE, 0, 834117632Sharti NULL, NULL, &sc->sbuf_tag)) != 0) { 835117632Sharti patm_printf(sc, "sbuf DMA tag create %d\n", error); 836117632Sharti return (error); 837117632Sharti } 838117632Sharti 839117632Sharti error = mbp_create(&sc->sbuf_pool, "patm sbufs", sc->sbuf_tag, 840117632Sharti SMBUF_MAX_PAGES, SMBUF_PAGE_SIZE, SMBUF_CHUNK_SIZE); 841117632Sharti if (error != 0) { 842117632Sharti patm_printf(sc, "smbuf pool create %d\n", error); 843117632Sharti return (error); 844117632Sharti } 845117632Sharti 846117632Sharti error = mbp_create(&sc->vbuf_pool, "patm vbufs", sc->sbuf_tag, 847117632Sharti VMBUF_MAX_PAGES, SMBUF_PAGE_SIZE, VMBUF_CHUNK_SIZE); 848117632Sharti if (error != 0) { 849117632Sharti patm_printf(sc, "vmbuf pool create %d\n", error); 850117632Sharti return (error); 851117632Sharti } 852117632Sharti 853117632Sharti /* 854117632Sharti * Create a tag for large buffers. 855117632Sharti * Don't use BUS_DMA_ALLOCNOW, because it makes no sense with multiple 856117632Sharti * maps using one tag. Rather use BUS_DMA_NOWAIT when loading the map 857117632Sharti * to prevent EINPROGRESS. 858117632Sharti */ 859232874Sscottl if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 4, 0, 860117632Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 861117632Sharti MCLBYTES, 1, MCLBYTES, 0, 862117632Sharti NULL, NULL, &sc->lbuf_tag)) != 0) { 863117632Sharti patm_printf(sc, "lbuf DMA tag create %d\n", error); 864117632Sharti return (error); 865117632Sharti } 866117632Sharti 867117632Sharti if (sc->lbuf_max < IDT_FBQ_SIZE) 868117632Sharti sc->lbuf_max = LMBUF_MAX; 869117632Sharti sc->lbufs = malloc(sizeof(sc->lbufs[0]) * sc->lbuf_max, 870117632Sharti M_DEVBUF, M_ZERO | M_WAITOK); 871117632Sharti 872117632Sharti SLIST_INIT(&sc->lbuf_free_list); 873117632Sharti for (i = 0; i < sc->lbuf_max; i++) { 874117632Sharti struct lmbuf *b = &sc->lbufs[i]; 875117632Sharti 876117632Sharti error = bus_dmamap_create(sc->lbuf_tag, 0, &b->map); 877117632Sharti if (error) { 878117632Sharti /* must deallocate here, because a test for NULL 879117632Sharti * does not work on most archs */ 880117632Sharti while (i-- > 0) 881117632Sharti bus_dmamap_destroy(sc->lbuf_tag, 882117632Sharti sc->lbufs[i].map); 883117632Sharti free(sc->lbufs, M_DEVBUF); 884117632Sharti sc->lbufs = NULL; 885117632Sharti return (error); 886117632Sharti } 887117632Sharti b->handle = i; 888117632Sharti SLIST_INSERT_HEAD(&sc->lbuf_free_list, b, link); 889117632Sharti } 890117632Sharti 891117632Sharti return (0); 892117632Sharti} 893117632Sharti 894117632Sharti/* 895117632Sharti * Allocate everything needed for the transmission maps. 896117632Sharti */ 897117632Shartistatic int 898117632Shartipatm_txmap_init(struct patm_softc *sc) 899117632Sharti{ 900117632Sharti int error; 901117632Sharti struct patm_txmap *map; 902117632Sharti 903117632Sharti /* get transmission tag */ 904232874Sscottl error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0, 905117632Sharti BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 906117632Sharti NULL, NULL, 65536, IDT_SCQ_SIZE - 1, 65536, 907117632Sharti 0, NULL, NULL, &sc->tx_tag); 908117632Sharti if (error) { 909117632Sharti patm_printf(sc, "cannot allocate TX tag %d\n", error); 910117632Sharti return (error); 911117632Sharti } 912117632Sharti 913117632Sharti if ((sc->tx_mapzone = uma_zcreate("PATM tx maps", 914117632Sharti sizeof(struct patm_txmap), NULL, NULL, NULL, NULL, 915117632Sharti UMA_ALIGN_PTR, 0)) == NULL) 916117632Sharti return (ENOMEM); 917117632Sharti 918117632Sharti if (sc->tx_maxmaps < PATM_CFG_TXMAPS_MAX) 919117632Sharti sc->tx_maxmaps = PATM_CFG_TXMAPS_MAX; 920117632Sharti sc->tx_nmaps = PATM_CFG_TXMAPS_INIT; 921117632Sharti 922117632Sharti for (sc->tx_nmaps = 0; sc->tx_nmaps < PATM_CFG_TXMAPS_INIT; 923117632Sharti sc->tx_nmaps++) { 924117632Sharti map = uma_zalloc(sc->tx_mapzone, M_WAITOK); 925117632Sharti error = bus_dmamap_create(sc->tx_tag, 0, &map->map); 926117632Sharti if (error) { 927117632Sharti uma_zfree(sc->tx_mapzone, map); 928117632Sharti return (ENOMEM); 929117632Sharti } 930117632Sharti SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 931117632Sharti } 932117632Sharti 933117632Sharti return (0); 934117632Sharti} 935117632Sharti 936117632Sharti#ifdef PATM_DEBUG 937117632Sharti 938117632Sharti/* 939117632Sharti * Sysctl handler for REGS 940117632Sharti * 941117632Sharti * LOCK: unlocked, needed 942117632Sharti */ 943117632Shartistatic int 944117632Shartipatm_sysctl_regs(SYSCTL_HANDLER_ARGS) 945117632Sharti{ 946117632Sharti struct patm_softc *sc = arg1; 947117632Sharti uint32_t *ret; 948117632Sharti int error, i; 949117632Sharti 950117632Sharti ret = malloc(IDT_NOR_END, M_TEMP, M_WAITOK); 951117632Sharti 952117632Sharti mtx_lock(&sc->mtx); 953117632Sharti for (i = 0; i < IDT_NOR_END; i += 4) 954117632Sharti ret[i / 4] = patm_nor_read(sc, i); 955117632Sharti mtx_unlock(&sc->mtx); 956117632Sharti 957117632Sharti error = SYSCTL_OUT(req, ret, IDT_NOR_END); 958117632Sharti free(ret, M_TEMP); 959117632Sharti 960117632Sharti return (error); 961117632Sharti} 962117632Sharti 963117632Sharti/* 964117632Sharti * Sysctl handler for TSQ 965117632Sharti * 966117632Sharti * LOCK: unlocked, needed 967117632Sharti */ 968117632Shartistatic int 969117632Shartipatm_sysctl_tsq(SYSCTL_HANDLER_ARGS) 970117632Sharti{ 971117632Sharti struct patm_softc *sc = arg1; 972117632Sharti void *ret; 973117632Sharti int error; 974117632Sharti 975117632Sharti ret = malloc(IDT_TSQ_SIZE * IDT_TSQE_SIZE, M_TEMP, M_WAITOK); 976117632Sharti 977117632Sharti mtx_lock(&sc->mtx); 978117632Sharti memcpy(ret, sc->tsq, IDT_TSQ_SIZE * IDT_TSQE_SIZE); 979117632Sharti mtx_unlock(&sc->mtx); 980117632Sharti 981117632Sharti error = SYSCTL_OUT(req, ret, IDT_TSQ_SIZE * IDT_TSQE_SIZE); 982117632Sharti free(ret, M_TEMP); 983117632Sharti 984117632Sharti return (error); 985117632Sharti} 986117632Sharti 987117632Sharti/* 988117632Sharti * debugging 989117632Sharti */ 990117632Shartistatic struct patm_softc * 991117632Shartipatm_dump_unit(u_int unit) 992117632Sharti{ 993117632Sharti devclass_t dc; 994117632Sharti struct patm_softc *sc; 995117632Sharti 996117632Sharti dc = devclass_find("patm"); 997117632Sharti if (dc == NULL) { 998117632Sharti printf("%s: can't find devclass\n", __func__); 999117632Sharti return (NULL); 1000117632Sharti } 1001117632Sharti sc = devclass_get_softc(dc, unit); 1002117632Sharti if (sc == NULL) { 1003117632Sharti printf("%s: invalid unit number: %d\n", __func__, unit); 1004117632Sharti return (NULL); 1005117632Sharti } 1006117632Sharti return (sc); 1007117632Sharti} 1008117632Sharti 1009117632Shartiint 1010117632Shartipatm_dump_vc(u_int unit, u_int vc) 1011117632Sharti{ 1012117632Sharti struct patm_softc *sc; 1013117632Sharti uint32_t tct[8]; 1014117632Sharti uint32_t rct[4]; 1015117632Sharti uint32_t scd[12]; 1016117632Sharti u_int i; 1017117632Sharti 1018117632Sharti if ((sc = patm_dump_unit(unit)) == NULL) 1019117632Sharti return (0); 1020117632Sharti 1021117632Sharti for (i = 0; i < 8; i++) 1022117632Sharti tct[i] = patm_sram_read(sc, vc * 8 + i); 1023117632Sharti for (i = 0; i < 4; i++) 1024117632Sharti rct[i] = patm_sram_read(sc, sc->mmap->rct + vc * 4 + i); 1025117632Sharti for (i = 0; i < 12; i++) 1026117632Sharti scd[i] = patm_sram_read(sc, (tct[0] & 0x7ffff) + i); 1027117632Sharti 1028117632Sharti printf("TCT%3u: %08x %08x %08x %08x %08x %08x %08x %08x\n", vc, 1029117632Sharti tct[0], tct[1], tct[2], tct[3], tct[4], tct[5], tct[6], tct[7]); 1030117632Sharti printf("RCT%3u: %08x %08x %08x %08x\n", vc, 1031117632Sharti rct[0], rct[1], rct[2], rct[3]); 1032117632Sharti printf("SCD%3u: %08x %08x %08x %08x %08x %08x %08x %08x\n", vc, 1033117632Sharti scd[0], scd[1], scd[2], scd[3], scd[4], scd[5], scd[6], scd[7]); 1034117632Sharti printf(" %08x %08x %08x %08x\n", 1035117632Sharti scd[8], scd[9], scd[10], scd[11]); 1036117632Sharti 1037117632Sharti return (0); 1038117632Sharti} 1039117632Sharti 1040117632Shartiint 1041117632Shartipatm_dump_regs(u_int unit) 1042117632Sharti{ 1043117632Sharti struct patm_softc *sc; 1044117632Sharti u_int i; 1045117632Sharti 1046117632Sharti if ((sc = patm_dump_unit(unit)) == NULL) 1047117632Sharti return (0); 1048117632Sharti 1049117632Sharti for (i = 0; i <= IDT_NOR_DNOW; i += 4) 1050117632Sharti printf("%x: %08x\n", i, patm_nor_read(sc, i)); 1051117632Sharti 1052117632Sharti return (0); 1053117632Sharti} 1054117632Sharti 1055117632Shartiint 1056117632Shartipatm_dump_sram(u_int unit, u_int from, u_int words) 1057117632Sharti{ 1058117632Sharti struct patm_softc *sc; 1059117632Sharti u_int i; 1060117632Sharti 1061117632Sharti if ((sc = patm_dump_unit(unit)) == NULL) 1062117632Sharti return (0); 1063117632Sharti 1064117632Sharti for (i = 0; i < words; i++) { 1065117632Sharti if (i % 8 == 0) 1066117632Sharti printf("%05x:", from + i); 1067117632Sharti printf(" %08x", patm_sram_read(sc, from + i)); 1068117632Sharti if (i % 8 == 7) 1069117632Sharti printf("\n"); 1070117632Sharti } 1071117632Sharti if (i % 8 != 0) 1072117632Sharti printf("\n"); 1073117632Sharti return (0); 1074117632Sharti} 1075117632Sharti#endif 1076