if_patm.c revision 148887
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: head/sys/dev/patm/if_patm.c 148887 2005-08-09 10:20:02Z rwatson $"); 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 <sys/endian.h> 53117632Sharti#include <vm/uma.h> 54117632Sharti 55117632Sharti#include <sys/sockio.h> 56117632Sharti#include <sys/mbuf.h> 57117632Sharti#include <sys/socket.h> 58117632Sharti 59117632Sharti#include <net/if.h> 60117632Sharti#include <net/if_media.h> 61117632Sharti#include <net/if_atm.h> 62117632Sharti#include <net/route.h> 63117632Sharti#include <netinet/in.h> 64117632Sharti#include <netinet/if_atm.h> 65117632Sharti 66117632Sharti#include <machine/bus.h> 67117632Sharti#include <machine/resource.h> 68117632Sharti#include <sys/bus.h> 69117632Sharti#include <sys/rman.h> 70117632Sharti#include <sys/mbpool.h> 71117632Sharti 72117632Sharti#include <dev/utopia/utopia.h> 73117632Sharti#include <dev/patm/idt77252reg.h> 74117632Sharti#include <dev/patm/if_patmvar.h> 75117632Sharti 76117632Shartistatic void patm_tst_init(struct patm_softc *sc); 77117632Shartistatic void patm_scd_init(struct patm_softc *sc); 78117632Sharti 79117632Sharti/* 80117632Sharti * Start the card. This assumes the mutex to be held 81117632Sharti */ 82117632Shartivoid 83117632Shartipatm_initialize(struct patm_softc *sc) 84117632Sharti{ 85117632Sharti uint32_t cfg; 86117632Sharti u_int i; 87117632Sharti 88117632Sharti patm_debug(sc, ATTACH, "configuring..."); 89117632Sharti 90117632Sharti /* clear SRAM */ 91117632Sharti for (i = 0; i < sc->mmap->sram * 1024; i += 4) 92117632Sharti patm_sram_write4(sc, i, 0, 0, 0, 0); 93117632Sharti patm_scd_init(sc); 94117632Sharti 95117632Sharti /* configuration register. Setting NOIDLE makes the timing wrong! */ 96117632Sharti cfg = IDT_CFG_TXFIFO9 | IDT_CFG_RXQ512 | PATM_CFG_VPI | 97117632Sharti /* IDT_CFG_NOIDLE | */ sc->mmap->rxtab; 98117632Sharti if (!(sc->flags & PATM_UNASS)) 99117632Sharti cfg |= IDT_CFG_IDLECLP; 100117632Sharti patm_nor_write(sc, IDT_NOR_CFG, cfg); 101117632Sharti 102117632Sharti /* clean all the status queues and the Raw handle */ 103117632Sharti memset(sc->tsq, 0, sc->sq_size); 104117632Sharti 105117632Sharti /* initialize RSQ */ 106117632Sharti patm_debug(sc, ATTACH, "RSQ %llx", (unsigned long long)sc->rsq_phy); 107117632Sharti patm_nor_write(sc, IDT_NOR_RSQB, sc->rsq_phy); 108117632Sharti patm_nor_write(sc, IDT_NOR_RSQT, sc->rsq_phy); 109117632Sharti patm_nor_write(sc, IDT_NOR_RSQH, 0); 110117632Sharti sc->rsq_last = PATM_RSQ_SIZE - 1; 111117632Sharti 112117632Sharti /* initialize TSTB */ 113117632Sharti patm_nor_write(sc, IDT_NOR_TSTB, sc->mmap->tst1base << 2); 114117632Sharti patm_tst_init(sc); 115117632Sharti 116117632Sharti /* initialize TSQ */ 117117632Sharti for (i = 0; i < IDT_TSQ_SIZE; i++) 118117632Sharti sc->tsq[i].stamp = htole32(IDT_TSQE_EMPTY); 119117632Sharti patm_nor_write(sc, IDT_NOR_TSQB, sc->tsq_phy); 120117632Sharti patm_nor_write(sc, IDT_NOR_TSQH, 0); 121117632Sharti patm_nor_write(sc, IDT_NOR_TSQT, 0); 122117632Sharti sc->tsq_next = sc->tsq; 123117632Sharti 124117632Sharti /* GP */ 125117632Sharti#if BYTE_ORDER == BIG_ENDIAN && 0 126117632Sharti patm_nor_write(sc, IDT_NOR_GP, IDT_GP_BIGE); 127117632Sharti#else 128117632Sharti patm_nor_write(sc, IDT_NOR_GP, 0); 129117632Sharti#endif 130117632Sharti 131117632Sharti /* VPM */ 132117632Sharti patm_nor_write(sc, IDT_NOR_VPM, 0); 133117632Sharti 134117632Sharti /* RxFIFO */ 135117632Sharti patm_nor_write(sc, IDT_NOR_RXFD, 136117632Sharti IDT_RXFD(sc->mmap->rxfifo_addr, sc->mmap->rxfifo_code)); 137117632Sharti patm_nor_write(sc, IDT_NOR_RXFT, 0); 138117632Sharti patm_nor_write(sc, IDT_NOR_RXFH, 0); 139117632Sharti 140117632Sharti /* RAWHND */ 141117632Sharti patm_debug(sc, ATTACH, "RWH %llx", 142117632Sharti (unsigned long long)sc->rawhnd_phy); 143117632Sharti patm_nor_write(sc, IDT_NOR_RAWHND, sc->rawhnd_phy); 144117632Sharti 145117632Sharti /* ABRSTD */ 146117632Sharti patm_nor_write(sc, IDT_NOR_ABRSTD, 147117632Sharti IDT_ABRSTD(sc->mmap->abrstd_addr, sc->mmap->abrstd_code)); 148117632Sharti for (i = 0; i < sc->mmap->abrstd_size; i++) 149117632Sharti patm_sram_write(sc, sc->mmap->abrstd_addr + i, 0); 150117632Sharti patm_nor_write(sc, IDT_NOR_ABRRQ, 0); 151117632Sharti patm_nor_write(sc, IDT_NOR_VBRRQ, 0); 152117632Sharti 153117632Sharti /* rate tables */ 154117632Sharti if (sc->flags & PATM_25M) { 155117632Sharti for (i = 0; i < patm_rtables_size; i++) 156117632Sharti patm_sram_write(sc, sc->mmap->rtables + i, 157117632Sharti patm_rtables25[i]); 158117632Sharti } else { 159117632Sharti for (i = 0; i < patm_rtables_size; i++) 160117632Sharti patm_sram_write(sc, sc->mmap->rtables + i, 161117632Sharti patm_rtables155[i]); 162117632Sharti } 163117632Sharti patm_nor_write(sc, IDT_NOR_RTBL, sc->mmap->rtables << 2); 164117632Sharti 165117632Sharti /* Maximum deficit */ 166117632Sharti patm_nor_write(sc, IDT_NOR_MXDFCT, 32 | IDT_MDFCT_LCI | IDT_MDFCT_LNI); 167117632Sharti 168117632Sharti /* Free buffer queues */ 169117632Sharti patm_nor_write(sc, IDT_NOR_FBQP0, 0); 170117632Sharti patm_nor_write(sc, IDT_NOR_FBQP1, 0); 171117632Sharti patm_nor_write(sc, IDT_NOR_FBQP2, 0); 172117632Sharti patm_nor_write(sc, IDT_NOR_FBQP3, 0); 173117632Sharti 174117632Sharti patm_nor_write(sc, IDT_NOR_FBQWP0, 0); 175117632Sharti patm_nor_write(sc, IDT_NOR_FBQWP1, 0); 176117632Sharti patm_nor_write(sc, IDT_NOR_FBQWP2, 0); 177117632Sharti patm_nor_write(sc, IDT_NOR_FBQWP3, 0); 178117632Sharti 179117632Sharti patm_nor_write(sc, IDT_NOR_FBQS0, 180117632Sharti (SMBUF_THRESHOLD << 28) | 181117632Sharti (SMBUF_NI_THRESH << 24) | 182117632Sharti (SMBUF_CI_THRESH << 20) | 183117632Sharti SMBUF_CELLS); 184117632Sharti patm_nor_write(sc, IDT_NOR_FBQS1, 185117632Sharti (LMBUF_THRESHOLD << 28) | 186117632Sharti (LMBUF_NI_THRESH << 24) | 187117632Sharti (LMBUF_CI_THRESH << 20) | 188117632Sharti LMBUF_CELLS); 189117632Sharti patm_nor_write(sc, IDT_NOR_FBQS2, 190117632Sharti (VMBUF_THRESHOLD << 28) | VMBUF_CELLS); 191117632Sharti patm_nor_write(sc, IDT_NOR_FBQS3, 0); 192117632Sharti 193117632Sharti /* make SCD0 for UBR0 */ 194117632Sharti if ((sc->scd0 = patm_scd_alloc(sc)) == NULL) { 195117632Sharti patm_printf(sc, "cannot create UBR0 SCD\n"); 196117632Sharti patm_reset(sc); 197117632Sharti return; 198117632Sharti } 199117632Sharti sc->scd0->q.ifq_maxlen = PATM_DLFT_MAXQ; 200117632Sharti 201117632Sharti patm_scd_setup(sc, sc->scd0); 202117632Sharti patm_tct_setup(sc, sc->scd0, NULL); 203117632Sharti 204117632Sharti patm_debug(sc, ATTACH, "go..."); 205117632Sharti 206117632Sharti sc->utopia.flags &= ~UTP_FL_POLL_CARRIER; 207148887Srwatson sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 208117632Sharti 209117632Sharti /* enable interrupts, Tx and Rx paths */ 210117632Sharti cfg |= IDT_CFG_RXPTH | IDT_CFG_RXIIMM | IDT_CFG_RAWIE | IDT_CFG_RQFIE | 211117632Sharti IDT_CFG_TIMOIE | IDT_CFG_FBIE | IDT_CFG_TXENB | IDT_CFG_TXINT | 212117632Sharti IDT_CFG_TXUIE | IDT_CFG_TXSFI | IDT_CFG_PHYIE; 213117632Sharti patm_nor_write(sc, IDT_NOR_CFG, cfg); 214118158Sharti 215118601Sharti for (i = 0; i < sc->mmap->max_conn; i++) 216118601Sharti if (sc->vccs[i] != NULL) 217118601Sharti patm_load_vc(sc, sc->vccs[i], 1); 218118601Sharti 219147256Sbrooks ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp), 220118158Sharti sc->utopia.carrier == UTP_CARR_OK); 221117632Sharti} 222117632Sharti 223117632Sharti/* 224117632Sharti * External callable start function 225117632Sharti */ 226117632Shartivoid 227117632Shartipatm_init(void *p) 228117632Sharti{ 229117632Sharti struct patm_softc *sc = p; 230117632Sharti 231117632Sharti mtx_lock(&sc->mtx); 232117632Sharti patm_stop(sc); 233117632Sharti patm_initialize(sc); 234117632Sharti mtx_unlock(&sc->mtx); 235117632Sharti} 236117632Sharti 237117632Sharti/* 238117632Sharti * Stop the interface 239117632Sharti */ 240117632Shartivoid 241117632Shartipatm_stop(struct patm_softc *sc) 242117632Sharti{ 243117632Sharti u_int i; 244117632Sharti struct mbuf *m; 245117632Sharti struct patm_txmap *map; 246117632Sharti struct patm_scd *scd; 247117632Sharti 248148887Srwatson sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 249117632Sharti sc->utopia.flags |= UTP_FL_POLL_CARRIER; 250117632Sharti 251117632Sharti patm_reset(sc); 252117632Sharti 253117632Sharti mtx_lock(&sc->tst_lock); 254117632Sharti i = sc->tst_state; 255117632Sharti sc->tst_state = 0; 256117632Sharti callout_stop(&sc->tst_callout); 257117632Sharti mtx_unlock(&sc->tst_lock); 258117632Sharti 259117632Sharti if (i != 0) { 260117632Sharti /* this means we are just entering or leaving the timeout. 261117632Sharti * wait a little bit. Doing this correctly would be more 262117632Sharti * involved */ 263117632Sharti DELAY(1000); 264117632Sharti } 265117632Sharti 266117632Sharti /* 267117632Sharti * Give any waiters on closing a VCC a chance. They will stop 268148887Srwatson * to wait if they see that IFF_DRV_RUNNING disappeared. 269117632Sharti */ 270126396Sscottl cv_broadcast(&sc->vcc_cv); 271117632Sharti 272117632Sharti /* free large buffers */ 273117632Sharti patm_debug(sc, ATTACH, "freeing large buffers..."); 274117632Sharti for (i = 0; i < sc->lbuf_max; i++) 275117632Sharti if (sc->lbufs[i].m != NULL) 276117632Sharti patm_lbuf_free(sc, &sc->lbufs[i]); 277117632Sharti 278117632Sharti /* free small buffers that are on the card */ 279117632Sharti patm_debug(sc, ATTACH, "freeing small buffers..."); 280117632Sharti mbp_card_free(sc->sbuf_pool); 281117632Sharti 282117632Sharti /* free aal0 buffers that are on the card */ 283117632Sharti patm_debug(sc, ATTACH, "freeing aal0 buffers..."); 284117632Sharti mbp_card_free(sc->vbuf_pool); 285117632Sharti 286117632Sharti /* freeing partial receive chains and reset vcc state */ 287117632Sharti for (i = 0; i < sc->mmap->max_conn; i++) { 288117632Sharti if (sc->vccs[i] != NULL) { 289118601Sharti if (sc->vccs[i]->chain != NULL) { 290117632Sharti m_freem(sc->vccs[i]->chain); 291118601Sharti sc->vccs[i]->chain = NULL; 292118601Sharti sc->vccs[i]->last = NULL; 293118601Sharti } 294117632Sharti 295118601Sharti if (sc->vccs[i]->vflags & (PATM_VCC_RX_CLOSING | 296118601Sharti PATM_VCC_TX_CLOSING)) { 297117632Sharti uma_zfree(sc->vcc_zone, sc->vccs[i]); 298117632Sharti sc->vccs[i] = NULL; 299117632Sharti } else { 300118601Sharti /* keep */ 301118601Sharti sc->vccs[i]->vflags &= ~PATM_VCC_OPEN; 302118601Sharti sc->vccs[i]->cps = 0; 303118601Sharti sc->vccs[i]->scd = NULL; 304117632Sharti } 305117632Sharti } 306117632Sharti } 307117632Sharti 308117632Sharti /* stop all active SCDs */ 309117632Sharti while ((scd = LIST_FIRST(&sc->scd_list)) != NULL) { 310117632Sharti /* free queue packets */ 311117632Sharti for (;;) { 312117632Sharti _IF_DEQUEUE(&scd->q, m); 313117632Sharti if (m == NULL) 314117632Sharti break; 315117632Sharti m_freem(m); 316117632Sharti } 317117632Sharti 318117632Sharti /* free transmitting packets */ 319117632Sharti for (i = 0; i < IDT_TSQE_TAG_SPACE; i++) { 320117632Sharti if ((m = scd->on_card[i]) != NULL) { 321117632Sharti scd->on_card[i] = 0; 322117632Sharti map = m->m_pkthdr.header; 323117632Sharti 324117632Sharti bus_dmamap_unload(sc->tx_tag, map->map); 325117632Sharti SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 326117632Sharti m_freem(m); 327117632Sharti } 328117632Sharti } 329117632Sharti patm_scd_free(sc, scd); 330117632Sharti } 331117632Sharti sc->scd0 = NULL; 332117632Sharti 333117632Sharti sc->flags &= ~PATM_CLR; 334117632Sharti 335117632Sharti /* reset raw cell queue */ 336117632Sharti sc->rawh = NULL; 337118158Sharti 338147256Sbrooks ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp), 339118158Sharti sc->utopia.carrier == UTP_CARR_OK); 340117632Sharti} 341117632Sharti 342117632Sharti/* 343117632Sharti * Stop the card and reset it 344117632Sharti */ 345117632Shartivoid 346117632Shartipatm_reset(struct patm_softc *sc) 347117632Sharti{ 348117632Sharti 349117632Sharti patm_debug(sc, ATTACH, "resetting..."); 350117632Sharti 351117632Sharti patm_nor_write(sc, IDT_NOR_CFG, IDT_CFG_SWRST); 352117632Sharti DELAY(200); 353117632Sharti patm_nor_write(sc, IDT_NOR_CFG, 0); 354117632Sharti DELAY(200); 355117632Sharti 356117632Sharti patm_nor_write(sc, IDT_NOR_RSQH, 0); 357117632Sharti patm_nor_write(sc, IDT_NOR_TSQH, 0); 358117632Sharti 359117632Sharti patm_nor_write(sc, IDT_NOR_GP, IDT_GP_PHY_RST); 360117632Sharti DELAY(50); 361117632Sharti patm_nor_write(sc, IDT_NOR_GP, IDT_GP_EEDO | IDT_GP_EECS); 362117632Sharti DELAY(50); 363117632Sharti} 364117632Sharti 365117632Sharti/* 366117632Sharti * Initialize the soft TST to contain only ABR scheduling and 367117632Sharti * write it to SRAM 368117632Sharti */ 369117632Shartistatic void 370117632Shartipatm_tst_init(struct patm_softc *sc) 371117632Sharti{ 372117632Sharti u_int i; 373117632Sharti u_int base, idle; 374117632Sharti 375117632Sharti base = sc->mmap->tst1base; 376117632Sharti idle = sc->mmap->tst1base + sc->mmap->tst_size; 377117632Sharti 378117632Sharti /* soft */ 379117632Sharti for (i = 0; i < sc->mmap->tst_size - 1; i++) 380117632Sharti sc->tst_soft[i] = IDT_TST_VBR; 381117632Sharti 382117632Sharti sc->tst_state = 0; 383117632Sharti sc->tst_jump[0] = base + sc->mmap->tst_size - 1; 384117632Sharti sc->tst_jump[1] = idle + sc->mmap->tst_size - 1; 385117632Sharti sc->tst_base[0] = base; 386117632Sharti sc->tst_base[1] = idle; 387117632Sharti 388117632Sharti /* TST1 */ 389117632Sharti for (i = 0; i < sc->mmap->tst_size - 1; i++) 390117632Sharti patm_sram_write(sc, base + i, IDT_TST_VBR); 391117632Sharti patm_sram_write(sc, sc->tst_jump[0], IDT_TST_BR | (base << 2)); 392117632Sharti 393117632Sharti /* TST2 */ 394117632Sharti for (i = 0; i < sc->mmap->tst_size - 1; i++) 395117632Sharti patm_sram_write(sc, idle + i, IDT_TST_VBR); 396117632Sharti patm_sram_write(sc, sc->tst_jump[1], IDT_TST_BR | (idle << 2)); 397117632Sharti 398117632Sharti sc->tst_free = sc->mmap->tst_size - 1; 399117632Sharti sc->tst_reserve = sc->tst_free * PATM_TST_RESERVE / 100; 400147256Sbrooks sc->bwrem = IFP2IFATM(sc->ifp)->mib.pcr; 401117632Sharti} 402117632Sharti 403117632Sharti/* 404117632Sharti * Initialize the SCDs. This is done by building a list of all free 405117632Sharti * SCDs in SRAM. The first word of each potential SCD is used as a 406117632Sharti * link to the next free SCD. The list is rooted in softc. 407117632Sharti */ 408117632Shartistatic void 409117632Shartipatm_scd_init(struct patm_softc *sc) 410117632Sharti{ 411117632Sharti u_int s; /* SRAM address of current SCD */ 412117632Sharti 413117632Sharti sc->scd_free = 0; 414117632Sharti for (s = sc->mmap->scd_base; s + 12 <= sc->mmap->tst1base; s += 12) { 415117632Sharti patm_sram_write(sc, s, sc->scd_free); 416117632Sharti sc->scd_free = s; 417117632Sharti } 418117632Sharti} 419117632Sharti 420117632Sharti/* 421117632Sharti * allocate an SCQ 422117632Sharti */ 423117632Shartistruct patm_scd * 424117632Shartipatm_scd_alloc(struct patm_softc *sc) 425117632Sharti{ 426117632Sharti u_int sram, next; /* SRAM address of this and next SCD */ 427117632Sharti int error; 428117632Sharti void *p; 429117632Sharti struct patm_scd *scd; 430117632Sharti bus_dmamap_t map; 431117632Sharti bus_addr_t phy; 432117632Sharti 433117632Sharti /* get an SCD from the free list */ 434117632Sharti if ((sram = sc->scd_free) == 0) 435117632Sharti return (NULL); 436117632Sharti next = patm_sram_read(sc, sram); 437117632Sharti 438117632Sharti /* allocate memory for the queue and our host stuff */ 439117632Sharti error = bus_dmamem_alloc(sc->scd_tag, &p, BUS_DMA_NOWAIT, &map); 440117632Sharti if (error != 0) 441117632Sharti return (NULL); 442117632Sharti phy = 0x3ff; 443117632Sharti error = bus_dmamap_load(sc->scd_tag, map, p, sizeof(scd->scq), 444117632Sharti patm_load_callback, &phy, BUS_DMA_NOWAIT); 445117632Sharti if (error != 0) { 446117632Sharti bus_dmamem_free(sc->scd_tag, p, map); 447117632Sharti return (NULL); 448117632Sharti } 449117632Sharti KASSERT((phy & 0x1ff) == 0, ("SCD not aligned %lx", (u_long)phy)); 450117632Sharti 451117632Sharti scd = p; 452117632Sharti bzero(scd, sizeof(*scd)); 453117632Sharti 454117632Sharti scd->sram = sram; 455117632Sharti scd->phy = phy; 456117632Sharti scd->map = map; 457117632Sharti scd->space = IDT_SCQ_SIZE; 458117632Sharti scd->last_tag = IDT_TSQE_TAG_SPACE - 1; 459117632Sharti scd->q.ifq_maxlen = PATM_TX_IFQLEN; 460117632Sharti 461117632Sharti /* remove the scd from the free list */ 462117632Sharti sc->scd_free = next; 463117632Sharti LIST_INSERT_HEAD(&sc->scd_list, scd, link); 464117632Sharti 465117632Sharti return (scd); 466117632Sharti} 467117632Sharti 468117632Sharti/* 469117632Sharti * Free an SCD 470117632Sharti */ 471117632Shartivoid 472117632Shartipatm_scd_free(struct patm_softc *sc, struct patm_scd *scd) 473117632Sharti{ 474117632Sharti 475117632Sharti LIST_REMOVE(scd, link); 476117632Sharti 477117632Sharti /* clear SCD and insert link word */ 478117632Sharti patm_sram_write4(sc, scd->sram, sc->scd_free, 0, 0, 0); 479117632Sharti patm_sram_write4(sc, scd->sram, 0, 0, 0, 0); 480117632Sharti patm_sram_write4(sc, scd->sram, 0, 0, 0, 0); 481117632Sharti 482117632Sharti /* put on free list */ 483117632Sharti sc->scd_free = scd->sram; 484117632Sharti 485117632Sharti /* free memory */ 486117632Sharti bus_dmamap_unload(sc->scd_tag, scd->map); 487117632Sharti bus_dmamem_free(sc->scd_tag, scd, scd->map); 488117632Sharti} 489117632Sharti 490117632Sharti/* 491117632Sharti * DMA loading helper function. This function handles the loading of 492117632Sharti * all one segment DMA maps. The argument is a pointer to a bus_addr_t 493117632Sharti * which must contain the desired alignment of the address as a bitmap. 494117632Sharti */ 495117632Shartivoid 496117632Shartipatm_load_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 497117632Sharti{ 498117632Sharti bus_addr_t *phy = arg; 499117632Sharti 500117632Sharti if (error) 501117632Sharti return; 502117632Sharti 503117632Sharti KASSERT(nsegs == 1, 504117632Sharti ("too many segments for DMA: %d", nsegs)); 505117632Sharti KASSERT(segs[0].ds_addr <= 0xffffffffUL, 506117632Sharti ("phys addr too large %lx", (u_long)segs[0].ds_addr)); 507117632Sharti KASSERT((segs[0].ds_addr & *phy) == 0, 508117632Sharti ("bad alignment %lx:%lx", (u_long)segs[0].ds_addr, (u_long)*phy)); 509117632Sharti 510117632Sharti *phy = segs[0].ds_addr; 511117632Sharti} 512