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