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