if_patm_tx.c revision 147256
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 * The TST allocation algorithm is from the IDT driver which is: 28117632Sharti * 29117632Sharti * Copyright (c) 2000, 2001 Richard Hodges and Matriplex, inc. 30117632Sharti * All rights reserved. 31117632Sharti * 32117632Sharti * Copyright (c) 1996, 1997, 1998, 1999 Mark Tinguely 33117632Sharti * All rights reserved. 34117632Sharti * 35117632Sharti * Author: Hartmut Brandt <harti@freebsd.org> 36117632Sharti * 37117632Sharti * Driver for IDT77252 based cards like ProSum's. 38117632Sharti */ 39119418Sobrien 40117632Sharti#include <sys/cdefs.h> 41117632Sharti__FBSDID("$FreeBSD: head/sys/dev/patm/if_patm_tx.c 147256 2005-06-10 16:49:24Z brooks $"); 42117632Sharti 43117632Sharti#include "opt_inet.h" 44117632Sharti#include "opt_natm.h" 45117632Sharti 46117632Sharti#include <sys/types.h> 47117632Sharti#include <sys/param.h> 48117632Sharti#include <sys/systm.h> 49117632Sharti#include <sys/malloc.h> 50117632Sharti#include <sys/kernel.h> 51117632Sharti#include <sys/bus.h> 52117632Sharti#include <sys/errno.h> 53117632Sharti#include <sys/conf.h> 54117632Sharti#include <sys/module.h> 55117632Sharti#include <sys/lock.h> 56117632Sharti#include <sys/mutex.h> 57117632Sharti#include <sys/sysctl.h> 58117632Sharti#include <sys/queue.h> 59117632Sharti#include <sys/condvar.h> 60117632Sharti#include <sys/endian.h> 61117632Sharti#include <vm/uma.h> 62117632Sharti 63117632Sharti#include <sys/sockio.h> 64117632Sharti#include <sys/mbuf.h> 65117632Sharti#include <sys/socket.h> 66117632Sharti 67117632Sharti#include <net/if.h> 68117632Sharti#include <net/if_media.h> 69117632Sharti#include <net/if_atm.h> 70117632Sharti#include <net/route.h> 71117632Sharti#ifdef ENABLE_BPF 72117632Sharti#include <net/bpf.h> 73117632Sharti#endif 74117632Sharti#include <netinet/in.h> 75117632Sharti#include <netinet/if_atm.h> 76117632Sharti 77117632Sharti#include <machine/bus.h> 78117632Sharti#include <machine/resource.h> 79117632Sharti#include <sys/bus.h> 80117632Sharti#include <sys/rman.h> 81117632Sharti#include <sys/mbpool.h> 82117632Sharti 83117632Sharti#include <dev/utopia/utopia.h> 84117632Sharti#include <dev/patm/idt77252reg.h> 85117632Sharti#include <dev/patm/if_patmvar.h> 86117632Sharti 87117632Shartistatic struct mbuf *patm_tx_pad(struct patm_softc *sc, struct mbuf *m0); 88117632Shartistatic void patm_launch(struct patm_softc *sc, struct patm_scd *scd); 89117632Sharti 90117632Shartistatic struct patm_txmap *patm_txmap_get(struct patm_softc *); 91117632Shartistatic void patm_load_txbuf(void *, bus_dma_segment_t *, int, 92117632Sharti bus_size_t, int); 93117632Sharti 94117632Shartistatic void patm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc); 95117632Shartistatic void patm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc); 96117632Shartistatic void patm_tst_timer(void *p); 97117632Shartistatic void patm_tst_update(struct patm_softc *); 98117632Sharti 99117632Shartistatic void patm_tct_start(struct patm_softc *sc, struct patm_vcc *); 100117632Sharti 101117632Shartistatic const char *dump_scd(struct patm_softc *sc, struct patm_scd *scd) 102117632Sharti __unused; 103117632Shartistatic void patm_tct_print(struct patm_softc *sc, u_int cid) __unused; 104117632Sharti 105117632Sharti/* 106117632Sharti * Structure for communication with the loader function for transmission 107117632Sharti */ 108117632Shartistruct txarg { 109117632Sharti struct patm_softc *sc; 110117632Sharti struct patm_scd *scd; /* scheduling channel */ 111117632Sharti struct patm_vcc *vcc; /* the VCC of this PDU */ 112117632Sharti struct mbuf *mbuf; 113117632Sharti u_int hdr; /* cell header */ 114117632Sharti}; 115117632Sharti 116117632Shartistatic __inline u_int 117117632Sharticbr2slots(struct patm_softc *sc, struct patm_vcc *vcc) 118117632Sharti{ 119117632Sharti /* compute the number of slots we need, make sure to get at least 120117632Sharti * the specified PCR */ 121117632Sharti return ((u_int)(((uint64_t)(sc->mmap->tst_size - 1) * 122147256Sbrooks vcc->vcc.tparam.pcr + IFP2IFATM(sc->ifp)->mib.pcr - 1) / IFP2IFATM(sc->ifp)->mib.pcr)); 123117632Sharti} 124117632Sharti 125117632Shartistatic __inline u_int 126117632Shartislots2cr(struct patm_softc *sc, u_int slots) 127117632Sharti{ 128147256Sbrooks return ((slots * IFP2IFATM(sc->ifp)->mib.pcr + sc->mmap->tst_size - 2) / 129117632Sharti (sc->mmap->tst_size - 1)); 130117632Sharti} 131117632Sharti 132117632Sharti/* check if we can open this one */ 133117632Shartiint 134117632Shartipatm_tx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc) 135117632Sharti{ 136117632Sharti 137117632Sharti /* check resources */ 138117632Sharti switch (vcc->vcc.traffic) { 139117632Sharti 140117632Sharti case ATMIO_TRAFFIC_CBR: 141117632Sharti { 142117632Sharti u_int slots = cbr2slots(sc, vcc); 143117632Sharti 144117632Sharti if (slots > sc->tst_free + sc->tst_reserve) 145117632Sharti return (EINVAL); 146117632Sharti break; 147117632Sharti } 148117632Sharti 149117632Sharti case ATMIO_TRAFFIC_VBR: 150117632Sharti if (vcc->vcc.tparam.scr > sc->bwrem) 151117632Sharti return (EINVAL); 152147256Sbrooks if (vcc->vcc.tparam.pcr > IFP2IFATM(sc->ifp)->mib.pcr) 153117632Sharti return (EINVAL); 154117632Sharti if (vcc->vcc.tparam.scr > vcc->vcc.tparam.pcr || 155117632Sharti vcc->vcc.tparam.mbs == 0) 156117632Sharti return (EINVAL); 157117632Sharti break; 158117632Sharti 159117632Sharti case ATMIO_TRAFFIC_ABR: 160117632Sharti if (vcc->vcc.tparam.tbe == 0 || 161117632Sharti vcc->vcc.tparam.nrm == 0) 162117632Sharti /* needed to compute CRM */ 163117632Sharti return (EINVAL); 164147256Sbrooks if (vcc->vcc.tparam.pcr > IFP2IFATM(sc->ifp)->mib.pcr || 165117632Sharti vcc->vcc.tparam.icr > vcc->vcc.tparam.pcr || 166117632Sharti vcc->vcc.tparam.mcr > vcc->vcc.tparam.icr) 167117632Sharti return (EINVAL); 168117632Sharti if (vcc->vcc.tparam.mcr > sc->bwrem || 169117632Sharti vcc->vcc.tparam.icr > sc->bwrem) 170117632Sharti return (EINVAL); 171117632Sharti break; 172117632Sharti } 173117632Sharti 174117632Sharti return (0); 175117632Sharti} 176117632Sharti 177117632Sharti#define NEXT_TAG(T) do { \ 178117632Sharti (T) = ((T) + 1) % IDT_TSQE_TAG_SPACE; \ 179117632Sharti } while (0) 180117632Sharti 181117632Sharti/* 182117632Sharti * open it 183117632Sharti */ 184117632Shartivoid 185117632Shartipatm_tx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc) 186117632Sharti{ 187117632Sharti struct patm_scd *scd; 188117632Sharti 189117632Sharti if (vcc->vcc.traffic == ATMIO_TRAFFIC_UBR) { 190117632Sharti /* we use UBR0 */ 191117632Sharti vcc->scd = sc->scd0; 192117632Sharti vcc->vflags |= PATM_VCC_TX_OPEN; 193117632Sharti return; 194117632Sharti } 195117632Sharti 196117632Sharti /* get an SCD */ 197117632Sharti scd = patm_scd_alloc(sc); 198117632Sharti if (scd == NULL) { 199117632Sharti /* should not happen */ 200117632Sharti patm_printf(sc, "out of SCDs\n"); 201117632Sharti return; 202117632Sharti } 203117632Sharti vcc->scd = scd; 204117632Sharti patm_scd_setup(sc, scd); 205117632Sharti patm_tct_setup(sc, scd, vcc); 206117632Sharti 207117632Sharti if (vcc->vcc.traffic != ATMIO_TRAFFIC_CBR) 208117632Sharti patm_tct_start(sc, vcc); 209117632Sharti 210117632Sharti vcc->vflags |= PATM_VCC_TX_OPEN; 211117632Sharti} 212117632Sharti 213117632Sharti/* 214117632Sharti * close the given vcc for transmission 215117632Sharti */ 216117632Shartivoid 217117632Shartipatm_tx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc) 218117632Sharti{ 219117632Sharti struct patm_scd *scd; 220117632Sharti struct mbuf *m; 221117632Sharti 222117632Sharti vcc->vflags |= PATM_VCC_TX_CLOSING; 223117632Sharti 224117632Sharti if (vcc->vcc.traffic == ATMIO_TRAFFIC_UBR) { 225117632Sharti /* let the queue PDUs go out */ 226117632Sharti vcc->scd = NULL; 227117632Sharti vcc->vflags &= ~(PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING); 228117632Sharti return; 229117632Sharti } 230117632Sharti scd = vcc->scd; 231117632Sharti 232117632Sharti /* empty the waitq */ 233117632Sharti for (;;) { 234117632Sharti _IF_DEQUEUE(&scd->q, m); 235117632Sharti if (m == NULL) 236117632Sharti break; 237117632Sharti m_freem(m); 238117632Sharti } 239117632Sharti 240117632Sharti if (scd->num_on_card == 0) { 241117632Sharti /* we are idle */ 242117632Sharti vcc->vflags &= ~PATM_VCC_TX_OPEN; 243117632Sharti 244117632Sharti if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR) 245117632Sharti patm_tst_free(sc, vcc); 246117632Sharti 247117632Sharti patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0); 248117632Sharti patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0); 249117632Sharti patm_scd_free(sc, scd); 250117632Sharti 251117632Sharti vcc->scd = NULL; 252117632Sharti vcc->vflags &= ~PATM_VCC_TX_CLOSING; 253117632Sharti 254117632Sharti return; 255117632Sharti } 256117632Sharti 257117632Sharti /* speed up transmission */ 258117632Sharti patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid, 0xff)); 259117632Sharti patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_ULACR(vcc->cid, 0xff)); 260117632Sharti 261117632Sharti /* wait for the interrupt to drop the number to 0 */ 262117632Sharti patm_debug(sc, VCC, "%u buffers still on card", scd->num_on_card); 263117632Sharti} 264117632Sharti 265117632Sharti/* transmission side finally closed */ 266117632Shartivoid 267117632Shartipatm_tx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc) 268117632Sharti{ 269117632Sharti 270117632Sharti patm_debug(sc, VCC, "%u.%u TX closed", vcc->vcc.vpi, vcc->vcc.vci); 271117632Sharti 272117632Sharti if (vcc->vcc.traffic == ATMIO_TRAFFIC_VBR) 273117632Sharti sc->bwrem += vcc->vcc.tparam.scr; 274117632Sharti} 275117632Sharti 276117632Sharti/* 277117632Sharti * Pull off packets from the interface queue and try to transmit them. 278117632Sharti * If the transmission fails because of a full transmit channel, we drop 279117632Sharti * packets for CBR and queue them for other channels up to limit. 280117632Sharti * This limit should depend on the CDVT for VBR and ABR, but it doesn't. 281117632Sharti */ 282117632Shartivoid 283117632Shartipatm_start(struct ifnet *ifp) 284117632Sharti{ 285117632Sharti struct patm_softc *sc = (struct patm_softc *)ifp->if_softc; 286117632Sharti struct mbuf *m; 287117632Sharti struct atm_pseudohdr *aph; 288117632Sharti u_int vpi, vci, cid; 289117632Sharti struct patm_vcc *vcc; 290117632Sharti 291117632Sharti mtx_lock(&sc->mtx); 292117632Sharti if (!(ifp->if_flags & IFF_RUNNING)) { 293117632Sharti mtx_unlock(&sc->mtx); 294117632Sharti return; 295117632Sharti } 296117632Sharti 297117632Sharti while (1) { 298117632Sharti /* get a new mbuf */ 299117632Sharti IF_DEQUEUE(&ifp->if_snd, m); 300117632Sharti if (m == NULL) 301117632Sharti break; 302117632Sharti 303117632Sharti /* split of pseudo header */ 304117632Sharti if (m->m_len < sizeof(*aph) && 305117632Sharti (m = m_pullup(m, sizeof(*aph))) == NULL) { 306147256Sbrooks sc->ifp->if_oerrors++; 307117632Sharti continue; 308117632Sharti } 309117632Sharti 310117632Sharti aph = mtod(m, struct atm_pseudohdr *); 311117632Sharti vci = ATM_PH_VCI(aph); 312117632Sharti vpi = ATM_PH_VPI(aph); 313117632Sharti m_adj(m, sizeof(*aph)); 314117632Sharti 315117632Sharti /* reject empty packets */ 316117632Sharti if (m->m_pkthdr.len == 0) { 317117632Sharti m_freem(m); 318147256Sbrooks sc->ifp->if_oerrors++; 319117632Sharti continue; 320117632Sharti } 321117632Sharti 322117632Sharti /* check whether this is a legal vcc */ 323117632Sharti if (!LEGAL_VPI(sc, vpi) || !LEGAL_VCI(sc, vci) || vci == 0) { 324117632Sharti m_freem(m); 325147256Sbrooks sc->ifp->if_oerrors++; 326117632Sharti continue; 327117632Sharti } 328117632Sharti cid = PATM_CID(sc, vpi, vci); 329117632Sharti vcc = sc->vccs[cid]; 330117632Sharti if (vcc == NULL) { 331117632Sharti m_freem(m); 332147256Sbrooks sc->ifp->if_oerrors++; 333117632Sharti continue; 334117632Sharti } 335117632Sharti 336117632Sharti /* must be multiple of 48 if not AAL5 */ 337117632Sharti if (vcc->vcc.aal == ATMIO_AAL_0 || 338117632Sharti vcc->vcc.aal == ATMIO_AAL_34) { 339117632Sharti /* XXX AAL3/4 format? */ 340117632Sharti if (m->m_pkthdr.len % 48 != 0 && 341117632Sharti (m = patm_tx_pad(sc, m)) == NULL) { 342147256Sbrooks sc->ifp->if_oerrors++; 343117632Sharti continue; 344117632Sharti } 345117632Sharti } else if (vcc->vcc.aal == ATMIO_AAL_RAW) { 346117632Sharti switch (vcc->vflags & PATM_RAW_FORMAT) { 347117632Sharti 348117632Sharti default: 349117632Sharti case PATM_RAW_CELL: 350117632Sharti if (m->m_pkthdr.len != 53) { 351147256Sbrooks sc->ifp->if_oerrors++; 352117632Sharti m_freem(m); 353117632Sharti continue; 354117632Sharti } 355117632Sharti break; 356117632Sharti 357117632Sharti case PATM_RAW_NOHEC: 358117632Sharti if (m->m_pkthdr.len != 52) { 359147256Sbrooks sc->ifp->if_oerrors++; 360117632Sharti m_freem(m); 361117632Sharti continue; 362117632Sharti } 363117632Sharti break; 364117632Sharti 365117632Sharti case PATM_RAW_CS: 366117632Sharti if (m->m_pkthdr.len != 64) { 367147256Sbrooks sc->ifp->if_oerrors++; 368117632Sharti m_freem(m); 369117632Sharti continue; 370117632Sharti } 371117632Sharti break; 372117632Sharti } 373117632Sharti } 374117632Sharti 375117632Sharti /* save data */ 376117632Sharti m->m_pkthdr.header = vcc; 377117632Sharti 378117632Sharti /* try to put it on the channels queue */ 379117632Sharti if (_IF_QFULL(&vcc->scd->q)) { 380147256Sbrooks sc->ifp->if_oerrors++; 381117632Sharti sc->stats.tx_qfull++; 382117632Sharti m_freem(m); 383117632Sharti continue; 384117632Sharti } 385117632Sharti _IF_ENQUEUE(&vcc->scd->q, m); 386117632Sharti 387117632Sharti#ifdef ENABLE_BPF 388117632Sharti if (!(vcc->vcc.flags & ATMIO_FLAG_NG) && 389118539Sharti (vcc->vcc.aal == ATMIO_AAL_5) && 390117632Sharti (vcc->vcc.flags & ATM_PH_LLCSNAP)) 391117632Sharti BPF_MTAP(ifp, m); 392117632Sharti#endif 393117632Sharti 394117632Sharti /* kick the channel to life */ 395117632Sharti patm_launch(sc, vcc->scd); 396117632Sharti 397117632Sharti } 398117632Sharti mtx_unlock(&sc->mtx); 399117632Sharti} 400117632Sharti 401117632Sharti/* 402117632Sharti * Pad non-AAL5 packet to a multiple of 48-byte. 403117632Sharti * We assume AAL0 only. We have still to decide on the format of AAL3/4. 404117632Sharti */ 405117632Shartistatic struct mbuf * 406117632Shartipatm_tx_pad(struct patm_softc *sc, struct mbuf *m0) 407117632Sharti{ 408117632Sharti struct mbuf *last, *m; 409117632Sharti u_int plen, pad, space; 410117632Sharti 411117632Sharti plen = m_length(m0, &last); 412117632Sharti if (plen != m0->m_pkthdr.len) { 413117632Sharti patm_printf(sc, "%s: mbuf length mismatch %d %u\n", __func__, 414117632Sharti m0->m_pkthdr.len, plen); 415117632Sharti m0->m_pkthdr.len = plen; 416117632Sharti if (plen == 0) { 417117632Sharti m_freem(m0); 418147256Sbrooks sc->ifp->if_oerrors++; 419117632Sharti return (NULL); 420117632Sharti } 421117632Sharti if (plen % 48 == 0) 422117632Sharti return (m0); 423117632Sharti } 424117632Sharti pad = 48 - plen % 48; 425117872Sharti m0->m_pkthdr.len += pad; 426117632Sharti if (M_WRITABLE(last)) { 427117632Sharti if (M_TRAILINGSPACE(last) >= pad) { 428117632Sharti bzero(last->m_data + last->m_len, pad); 429117632Sharti last->m_len += pad; 430117632Sharti return (m0); 431117632Sharti } 432117632Sharti space = M_LEADINGSPACE(last); 433117632Sharti if (space + M_TRAILINGSPACE(last) >= pad) { 434117632Sharti bcopy(last->m_data, last->m_data + space, last->m_len); 435117632Sharti last->m_data -= space; 436117632Sharti bzero(last->m_data + last->m_len, pad); 437117632Sharti last->m_len += pad; 438117632Sharti return (m0); 439117632Sharti } 440117632Sharti } 441117632Sharti MGET(m, M_DONTWAIT, MT_DATA); 442117632Sharti if (m == 0) { 443117632Sharti m_freem(m0); 444147256Sbrooks sc->ifp->if_oerrors++; 445117632Sharti return (NULL); 446117632Sharti } 447117632Sharti bzero(mtod(m, u_char *), pad); 448117632Sharti m->m_len = pad; 449117632Sharti last->m_next = m; 450117632Sharti 451117632Sharti return (m0); 452117632Sharti} 453117632Sharti 454117632Sharti/* 455117632Sharti * Try to put as many packets from the channels queue onto the channel 456117632Sharti */ 457117632Shartistatic void 458117632Shartipatm_launch(struct patm_softc *sc, struct patm_scd *scd) 459117632Sharti{ 460117632Sharti struct txarg a; 461117632Sharti struct mbuf *m, *tmp; 462117632Sharti u_int segs; 463117632Sharti struct patm_txmap *map; 464117632Sharti int error; 465117632Sharti 466117632Sharti a.sc = sc; 467117632Sharti a.scd = scd; 468117632Sharti 469117632Sharti /* limit the number of outstanding packets to the tag space */ 470117632Sharti while (scd->num_on_card < IDT_TSQE_TAG_SPACE) { 471117632Sharti /* get the next packet */ 472117632Sharti _IF_DEQUEUE(&scd->q, m); 473117632Sharti if (m == NULL) 474117632Sharti break; 475117632Sharti 476117632Sharti a.vcc = m->m_pkthdr.header; 477117632Sharti 478117632Sharti /* we must know the number of segments beforehand - count 479117632Sharti * this may actually give a wrong number of segments for 480117632Sharti * AAL_RAW where we still need to remove the cell header */ 481117632Sharti segs = 0; 482117632Sharti for (tmp = m; tmp != NULL; tmp = tmp->m_next) 483117632Sharti if (tmp->m_len != 0) 484117632Sharti segs++; 485117632Sharti 486117632Sharti /* check whether there is space in the queue */ 487117632Sharti if (segs >= scd->space) { 488117632Sharti /* put back */ 489117632Sharti _IF_PREPEND(&scd->q, m); 490117632Sharti sc->stats.tx_out_of_tbds++; 491117632Sharti break; 492117632Sharti } 493117632Sharti 494117632Sharti /* get a DMA map */ 495117632Sharti if ((map = patm_txmap_get(sc)) == NULL) { 496117632Sharti _IF_PREPEND(&scd->q, m); 497117632Sharti sc->stats.tx_out_of_maps++; 498117632Sharti break; 499117632Sharti } 500117632Sharti 501117632Sharti /* load the map */ 502117632Sharti m->m_pkthdr.header = map; 503117632Sharti a.mbuf = m; 504117632Sharti 505117632Sharti /* handle AAL_RAW */ 506117632Sharti if (a.vcc->vcc.aal == ATMIO_AAL_RAW) { 507117632Sharti u_char hdr[4]; 508117632Sharti 509117632Sharti m_copydata(m, 0, 4, hdr); 510117632Sharti a.hdr = (hdr[0] << 24) | (hdr[1] << 16) | 511117632Sharti (hdr[2] << 8) | hdr[3]; 512117632Sharti 513117632Sharti switch (a.vcc->vflags & PATM_RAW_FORMAT) { 514117632Sharti 515117632Sharti default: 516117632Sharti case PATM_RAW_CELL: 517117632Sharti m_adj(m, 5); 518117632Sharti break; 519117632Sharti 520117632Sharti case PATM_RAW_NOHEC: 521117632Sharti m_adj(m, 4); 522117632Sharti break; 523117632Sharti 524117632Sharti case PATM_RAW_CS: 525117632Sharti m_adj(m, 16); 526117632Sharti break; 527117632Sharti } 528117632Sharti } else 529117632Sharti a.hdr = IDT_TBD_HDR(a.vcc->vcc.vpi, a.vcc->vcc.vci, 530117632Sharti 0, 0); 531117632Sharti 532117632Sharti error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m, 533117632Sharti patm_load_txbuf, &a, BUS_DMA_NOWAIT); 534117632Sharti if (error == EFBIG) { 535117632Sharti if ((m = m_defrag(m, M_DONTWAIT)) == NULL) { 536147256Sbrooks sc->ifp->if_oerrors++; 537117632Sharti continue; 538117632Sharti } 539117632Sharti error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m, 540117632Sharti patm_load_txbuf, &a, BUS_DMA_NOWAIT); 541117632Sharti } 542117632Sharti if (error != 0) { 543117632Sharti sc->stats.tx_load_err++; 544147256Sbrooks sc->ifp->if_oerrors++; 545117632Sharti SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 546117632Sharti m_freem(m); 547117632Sharti continue; 548117632Sharti } 549117632Sharti 550147256Sbrooks sc->ifp->if_opackets++; 551117632Sharti } 552117632Sharti} 553117632Sharti 554117632Sharti/* 555117632Sharti * Load the DMA segments into the scheduling channel 556117632Sharti */ 557117632Shartistatic void 558117632Shartipatm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg, 559117632Sharti bus_size_t mapsize, int error) 560117632Sharti{ 561117632Sharti struct txarg *a= uarg; 562117632Sharti struct patm_scd *scd = a->scd; 563117632Sharti u_int w1, w3, cnt; 564117632Sharti struct idt_tbd *tbd = NULL; 565117632Sharti u_int rest = mapsize; 566117632Sharti 567117632Sharti if (error != 0) 568117632Sharti return; 569117632Sharti 570117632Sharti cnt = 0; 571117632Sharti while (nseg > 0) { 572117632Sharti if (segs->ds_len == 0) { 573117632Sharti /* transmit buffer length must be > 0 */ 574117632Sharti nseg--; 575117632Sharti segs++; 576117632Sharti continue; 577117632Sharti } 578117632Sharti /* rest after this buffer */ 579117632Sharti rest -= segs->ds_len; 580117632Sharti 581117632Sharti /* put together status word */ 582117632Sharti w1 = 0; 583117632Sharti if (rest < 48 /* && a->vcc->vcc.aal != ATMIO_AAL_5 */) 584117632Sharti /* last cell is in this buffer */ 585117632Sharti w1 |= IDT_TBD_EPDU; 586117632Sharti 587117632Sharti if (a->vcc->vcc.aal == ATMIO_AAL_5) 588117632Sharti w1 |= IDT_TBD_AAL5; 589117632Sharti else if (a->vcc->vcc.aal == ATMIO_AAL_34) 590117632Sharti w1 |= IDT_TBD_AAL34; 591117632Sharti else 592117632Sharti w1 |= IDT_TBD_AAL0; 593117632Sharti 594117632Sharti w1 |= segs->ds_len; 595117632Sharti 596117632Sharti /* AAL5 PDU length (unpadded) */ 597117632Sharti if (a->vcc->vcc.aal == ATMIO_AAL_5) 598117632Sharti w3 = mapsize; 599117632Sharti else 600117632Sharti w3 = 0; 601117632Sharti 602117632Sharti if (rest == 0) 603117632Sharti w1 |= IDT_TBD_TSIF | IDT_TBD_GTSI | 604117632Sharti (scd->tag << IDT_TBD_TAG_SHIFT); 605117632Sharti 606117632Sharti tbd = &scd->scq[scd->tail]; 607117632Sharti 608117632Sharti tbd->flags = htole32(w1); 609117632Sharti tbd->addr = htole32(segs->ds_addr); 610117632Sharti tbd->aal5 = htole32(w3); 611117632Sharti tbd->hdr = htole32(a->hdr); 612117632Sharti 613117632Sharti patm_debug(a->sc, TX, "TBD(%u): %08x %08x %08x %08x", 614117632Sharti scd->tail, w1, segs->ds_addr, w3, a->hdr); 615117632Sharti 616117632Sharti /* got to next entry */ 617117632Sharti if (++scd->tail == IDT_SCQ_SIZE) 618117632Sharti scd->tail = 0; 619117632Sharti cnt++; 620117632Sharti nseg--; 621117632Sharti segs++; 622117632Sharti } 623117632Sharti scd->space -= cnt; 624117632Sharti scd->num_on_card++; 625117632Sharti 626117632Sharti KASSERT(rest == 0, ("bad mbuf")); 627117632Sharti KASSERT(cnt > 0, ("no segs")); 628117632Sharti KASSERT(scd->space > 0, ("scq full")); 629117632Sharti 630117632Sharti KASSERT(scd->on_card[scd->tag] == NULL, 631117632Sharti ("scd on_card wedged %u%s", scd->tag, dump_scd(a->sc, scd))); 632117632Sharti scd->on_card[scd->tag] = a->mbuf; 633117632Sharti a->mbuf->m_pkthdr.csum_data = cnt; 634117632Sharti 635117632Sharti NEXT_TAG(scd->tag); 636117632Sharti 637117632Sharti patm_debug(a->sc, TX, "SCD tail %u (%lx:%lx)", scd->tail, 638117632Sharti (u_long)scd->phy, (u_long)scd->phy + (scd->tail << IDT_TBD_SHIFT)); 639117632Sharti patm_sram_write(a->sc, scd->sram, 640117632Sharti scd->phy + (scd->tail << IDT_TBD_SHIFT)); 641117632Sharti 642117632Sharti if (patm_sram_read(a->sc, a->vcc->cid * 8 + 3) & IDT_TCT_IDLE) { 643117632Sharti /* 644117632Sharti * if the connection is idle start it. We cannot rely 645117632Sharti * on a flag set by patm_tx_idle() here, because sometimes 646117632Sharti * the card seems to place an idle TSI into the TSQ but 647117632Sharti * forgets to raise an interrupt. 648117632Sharti */ 649117632Sharti patm_nor_write(a->sc, IDT_NOR_TCMDQ, 650117632Sharti IDT_TCMDQ_START(a->vcc->cid)); 651117632Sharti } 652117632Sharti} 653117632Sharti 654117632Sharti/* 655117632Sharti * packet transmitted 656117632Sharti */ 657117632Shartivoid 658117632Shartipatm_tx(struct patm_softc *sc, u_int stamp, u_int status) 659117632Sharti{ 660117632Sharti u_int cid, tag, last; 661117632Sharti struct mbuf *m; 662117632Sharti struct patm_vcc *vcc; 663117632Sharti struct patm_scd *scd; 664117632Sharti struct patm_txmap *map; 665117632Sharti 666117632Sharti /* get the connection */ 667117632Sharti cid = PATM_CID(sc, IDT_TBD_VPI(status), IDT_TBD_VCI(status)); 668117632Sharti if ((vcc = sc->vccs[cid]) == NULL) { 669117632Sharti /* closed UBR connection */ 670117632Sharti return; 671117632Sharti } 672117632Sharti scd = vcc->scd; 673117632Sharti 674117632Sharti tag = IDT_TSQE_TAG(stamp); 675117632Sharti 676117632Sharti last = scd->last_tag; 677117632Sharti if (tag == last) { 678117632Sharti patm_printf(sc, "same tag %u\n", tag); 679117632Sharti return; 680117632Sharti } 681117632Sharti 682117632Sharti /* Errata 12 requests us to free all entries up to the one 683117632Sharti * with the given tag. */ 684117632Sharti do { 685117632Sharti /* next tag to try */ 686117632Sharti NEXT_TAG(last); 687117632Sharti 688117632Sharti m = scd->on_card[last]; 689117632Sharti KASSERT(m != NULL, ("%stag=%u", dump_scd(sc, scd), tag)); 690117632Sharti scd->on_card[last] = NULL; 691117632Sharti patm_debug(sc, TX, "ok tag=%x", last); 692117632Sharti 693117632Sharti map = m->m_pkthdr.header; 694117632Sharti scd->space += m->m_pkthdr.csum_data; 695117632Sharti 696117632Sharti bus_dmamap_sync(sc->tx_tag, map->map, 697117632Sharti BUS_DMASYNC_POSTWRITE); 698117632Sharti bus_dmamap_unload(sc->tx_tag, map->map); 699117632Sharti m_freem(m); 700117632Sharti SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 701117632Sharti scd->num_on_card--; 702117632Sharti 703117632Sharti if (vcc->vflags & PATM_VCC_TX_CLOSING) { 704117632Sharti if (scd->num_on_card == 0) { 705117632Sharti /* done with this VCC */ 706117632Sharti if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR) 707117632Sharti patm_tst_free(sc, vcc); 708117632Sharti 709117632Sharti patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0); 710117632Sharti patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0); 711117632Sharti patm_scd_free(sc, scd); 712117632Sharti 713117632Sharti vcc->scd = NULL; 714117632Sharti vcc->vflags &= ~PATM_VCC_TX_CLOSING; 715117632Sharti 716118539Sharti if (vcc->vcc.flags & ATMIO_FLAG_ASYNC) { 717117632Sharti patm_tx_vcc_closed(sc, vcc); 718117632Sharti if (!(vcc->vflags & PATM_VCC_OPEN)) 719117632Sharti patm_vcc_closed(sc, vcc); 720117632Sharti } else 721117632Sharti cv_signal(&sc->vcc_cv); 722117632Sharti return; 723117632Sharti } 724117632Sharti patm_debug(sc, VCC, "%u buffers still on card", 725117632Sharti scd->num_on_card); 726117632Sharti 727117632Sharti if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) { 728117632Sharti /* insist on speeding up transmission for ABR */ 729117632Sharti patm_nor_write(sc, IDT_NOR_TCMDQ, 730117632Sharti IDT_TCMDQ_UIER(vcc->cid, 0xff)); 731117632Sharti patm_nor_write(sc, IDT_NOR_TCMDQ, 732117632Sharti IDT_TCMDQ_ULACR(vcc->cid, 0xff)); 733117632Sharti } 734117632Sharti } 735117632Sharti 736117632Sharti } while (last != tag); 737117632Sharti scd->last_tag = tag; 738117632Sharti 739117632Sharti if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) { 740117632Sharti u_int acri, cps; 741117632Sharti 742117632Sharti acri = (patm_sram_read(sc, 8 * cid + 2) >> IDT_TCT_ACRI_SHIFT) 743117632Sharti & 0x3fff; 744147256Sbrooks cps = IFP2IFATM(sc->ifp)->mib.pcr * 32 / 745117632Sharti ((1 << (acri >> 10)) * (acri & 0x3ff)); 746117632Sharti 747117632Sharti if (cps != vcc->cps) { 748117632Sharti patm_debug(sc, VCC, "ACRI=%04x CPS=%u", acri, cps); 749147256Sbrooks ATMEV_SEND_ACR_CHANGED(IFP2IFATM(sc->ifp), vcc->vcc.vpi, 750118158Sharti vcc->vcc.vci, cps); 751117632Sharti vcc->cps = cps; 752117632Sharti } 753117632Sharti } 754117632Sharti 755117632Sharti patm_launch(sc, scd); 756117632Sharti} 757117632Sharti 758117632Sharti/* 759117632Sharti * VBR/ABR connection went idle 760117632Sharti * Either restart it or set the idle flag. 761117632Sharti */ 762117632Shartivoid 763117632Shartipatm_tx_idle(struct patm_softc *sc, u_int cid) 764117632Sharti{ 765117632Sharti struct patm_vcc *vcc; 766117632Sharti 767117632Sharti patm_debug(sc, VCC, "idle %u", cid); 768117632Sharti 769117632Sharti if ((vcc = sc->vccs[cid]) != NULL && 770117632Sharti (vcc->vflags & (PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING)) != 0 && 771117632Sharti vcc->scd != NULL && (vcc->scd->num_on_card != 0 || 772117632Sharti _IF_QLEN(&vcc->scd->q) != 0)) { 773117632Sharti /* 774117632Sharti * If there is any packet outstanding in the SCD re-activate 775117632Sharti * the channel and kick it. 776117632Sharti */ 777117632Sharti patm_nor_write(sc, IDT_NOR_TCMDQ, 778117632Sharti IDT_TCMDQ_START(vcc->cid)); 779117632Sharti 780117632Sharti patm_launch(sc, vcc->scd); 781117632Sharti } 782117632Sharti} 783117632Sharti 784117632Sharti/* 785117632Sharti * Convert a (24bit) rate to the atm-forum form 786117632Sharti * Our rate is never larger than 19 bit. 787117632Sharti */ 788117632Shartistatic u_int 789117632Sharticps2atmf(u_int cps) 790117632Sharti{ 791117632Sharti u_int e; 792117632Sharti 793117632Sharti if (cps == 0) 794117632Sharti return (0); 795117632Sharti cps <<= 9; 796117632Sharti e = 0; 797117632Sharti while (cps > (1024 - 1)) { 798117632Sharti e++; 799117632Sharti cps >>= 1; 800117632Sharti } 801117632Sharti return ((1 << 14) | (e << 9) | (cps & 0x1ff)); 802117632Sharti} 803117632Sharti 804117632Sharti/* 805117632Sharti * Do a binary search on the log2rate table to convert the rate 806117632Sharti * to its log form. This assumes that the ATM-Forum form is monotonically 807117632Sharti * increasing with the plain cell rate. 808117632Sharti */ 809117632Shartistatic u_int 810117632Shartirate2log(struct patm_softc *sc, u_int rate) 811117632Sharti{ 812117632Sharti const uint32_t *tbl; 813117632Sharti u_int lower, upper, mid, done, val, afr; 814117632Sharti 815117632Sharti afr = cps2atmf(rate); 816117632Sharti 817117632Sharti if (sc->flags & PATM_25M) 818117632Sharti tbl = patm_rtables25; 819117632Sharti else 820117632Sharti tbl = patm_rtables155; 821117632Sharti 822117632Sharti lower = 0; 823117632Sharti upper = 255; 824117632Sharti done = 0; 825117632Sharti while (!done) { 826117632Sharti mid = (lower + upper) / 2; 827117632Sharti val = tbl[mid] >> 17; 828117632Sharti if (val == afr || upper == lower) 829117632Sharti break; 830117632Sharti if (afr > val) 831117632Sharti lower = mid + 1; 832117632Sharti else 833117632Sharti upper = mid - 1; 834117632Sharti } 835117632Sharti if (val > afr && mid > 0) 836117632Sharti mid--; 837117632Sharti return (mid); 838117632Sharti} 839117632Sharti 840117632Sharti/* 841117632Sharti * Return the table index for an increase table. The increase table 842117632Sharti * must be selected not by the RIF itself, but by PCR/2^RIF. Each table 843117632Sharti * represents an additive increase of a cell rate that can be computed 844117632Sharti * from the first table entry (the value in this entry will not be clamped 845117632Sharti * by the link rate). 846117632Sharti */ 847117632Shartistatic u_int 848117632Shartiget_air_table(struct patm_softc *sc, u_int rif, u_int pcr) 849117632Sharti{ 850117632Sharti const uint32_t *tbl; 851117632Sharti u_int increase, base, lair0, ret, t, cps; 852117632Sharti 853117632Sharti#define GET_ENTRY(TAB, IDX) (0xffff & ((IDX & 1) ? \ 854117632Sharti (tbl[512 + (IDX / 2) + 128 * (TAB)] >> 16) : \ 855117632Sharti (tbl[512 + (IDX / 2) + 128 * (TAB)]))) 856117632Sharti 857117632Sharti#define MANT_BITS 10 858117632Sharti#define FRAC_BITS 16 859117632Sharti 860117632Sharti#define DIFF_TO_FP(D) (((D) & ((1 << MANT_BITS) - 1)) << ((D) >> MANT_BITS)) 861117632Sharti#define AFR_TO_INT(A) ((1 << (((A) >> 9) & 0x1f)) * \ 862117632Sharti (512 + ((A) & 0x1ff)) / 512 * ((A) >> 14)) 863117632Sharti 864117632Sharti if (sc->flags & PATM_25M) 865117632Sharti tbl = patm_rtables25; 866117632Sharti else 867117632Sharti tbl = patm_rtables155; 868117632Sharti if (rif >= patm_rtables_ntab) 869117632Sharti rif = patm_rtables_ntab - 1; 870117632Sharti increase = pcr >> rif; 871117632Sharti 872117632Sharti ret = 0; 873117632Sharti for (t = 0; t < patm_rtables_ntab; t++) { 874117632Sharti /* get base rate of this table */ 875117632Sharti base = GET_ENTRY(t, 0); 876117632Sharti /* convert this to fixed point */ 877117632Sharti lair0 = DIFF_TO_FP(base) >> FRAC_BITS; 878117632Sharti 879117632Sharti /* get the CPS from the log2rate table */ 880117632Sharti cps = AFR_TO_INT(tbl[lair0] >> 17) - 10; 881117632Sharti 882117632Sharti if (increase >= cps) 883117632Sharti break; 884117632Sharti 885117632Sharti ret = t; 886117632Sharti } 887117632Sharti return (ret + 4); 888117632Sharti} 889117632Sharti 890117632Sharti/* 891117632Sharti * Setup the TCT 892117632Sharti */ 893117632Shartivoid 894117632Shartipatm_tct_setup(struct patm_softc *sc, struct patm_scd *scd, 895117632Sharti struct patm_vcc *vcc) 896117632Sharti{ 897117632Sharti uint32_t tct[8]; 898117632Sharti u_int sram; 899117632Sharti u_int mbs, token; 900117632Sharti u_int tmp, crm, rdf, cdf, air, mcr; 901117632Sharti 902117632Sharti bzero(tct, sizeof(tct)); 903117632Sharti if (vcc == NULL) { 904117632Sharti /* special case for UBR0 */ 905117632Sharti sram = 0; 906117632Sharti tct[0] = IDT_TCT_UBR | scd->sram; 907117632Sharti tct[7] = IDT_TCT_UBR_FLG; 908117632Sharti 909117632Sharti } else { 910117632Sharti sram = vcc->cid * 8; 911117632Sharti switch (vcc->vcc.traffic) { 912117632Sharti 913117632Sharti case ATMIO_TRAFFIC_CBR: 914117632Sharti patm_tst_alloc(sc, vcc); 915117632Sharti tct[0] = IDT_TCT_CBR | scd->sram; 916117632Sharti /* must account for what was really allocated */ 917117632Sharti break; 918117632Sharti 919117632Sharti case ATMIO_TRAFFIC_VBR: 920117632Sharti /* compute parameters for the TCT */ 921117632Sharti scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr); 922117632Sharti scd->lacr = rate2log(sc, vcc->vcc.tparam.scr); 923117632Sharti 924117632Sharti /* get the 16-bit fraction of SCR/PCR 925117632Sharti * both a 24 bit. Do it the simple way. */ 926117632Sharti token = (uint64_t)(vcc->vcc.tparam.scr << 16) / 927117632Sharti vcc->vcc.tparam.pcr; 928117632Sharti 929117632Sharti patm_debug(sc, VCC, "VBR: init_er=%u lacr=%u " 930117632Sharti "token=0x%04x\n", scd->init_er, scd->lacr, token); 931117632Sharti 932117632Sharti tct[0] = IDT_TCT_VBR | scd->sram; 933117632Sharti tct[2] = IDT_TCT_TSIF; 934117632Sharti tct[3] = IDT_TCT_IDLE | IDT_TCT_HALT; 935117632Sharti tct[4] = IDT_TCT_MAXIDLE; 936117632Sharti tct[5] = 0x01000000; 937117632Sharti if ((mbs = vcc->vcc.tparam.mbs) > 0xff) 938117632Sharti mbs = 0xff; 939117632Sharti tct[6] = (mbs << 16) | token; 940117632Sharti sc->bwrem -= vcc->vcc.tparam.scr; 941117632Sharti break; 942117632Sharti 943117632Sharti case ATMIO_TRAFFIC_ABR: 944117632Sharti scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr); 945117632Sharti scd->lacr = rate2log(sc, vcc->vcc.tparam.icr); 946117632Sharti mcr = rate2log(sc, vcc->vcc.tparam.mcr); 947117632Sharti 948117632Sharti /* compute CRM */ 949117632Sharti tmp = vcc->vcc.tparam.tbe / vcc->vcc.tparam.nrm; 950117632Sharti if (tmp * vcc->vcc.tparam.nrm < vcc->vcc.tparam.tbe) 951117632Sharti tmp++; 952117632Sharti for (crm = 1; tmp > (1 << crm); crm++) 953117632Sharti ; 954117632Sharti if (crm > 0x7) 955117632Sharti crm = 7; 956117632Sharti 957117632Sharti air = get_air_table(sc, vcc->vcc.tparam.rif, 958117632Sharti vcc->vcc.tparam.pcr); 959117632Sharti 960117632Sharti if ((rdf = vcc->vcc.tparam.rdf) >= patm_rtables_ntab) 961117632Sharti rdf = patm_rtables_ntab - 1; 962117632Sharti rdf += patm_rtables_ntab + 4; 963117632Sharti 964117632Sharti if ((cdf = vcc->vcc.tparam.cdf) >= patm_rtables_ntab) 965117632Sharti cdf = patm_rtables_ntab - 1; 966117632Sharti cdf += patm_rtables_ntab + 4; 967117632Sharti 968117632Sharti patm_debug(sc, VCC, "ABR: init_er=%u lacr=%u mcr=%u " 969117632Sharti "crm=%u air=%u rdf=%u cdf=%u\n", scd->init_er, 970117632Sharti scd->lacr, mcr, crm, air, rdf, cdf); 971117632Sharti 972117632Sharti tct[0] = IDT_TCT_ABR | scd->sram; 973117632Sharti tct[1] = crm << IDT_TCT_CRM_SHIFT; 974117632Sharti tct[3] = IDT_TCT_HALT | IDT_TCT_IDLE | 975117632Sharti (4 << IDT_TCT_NAGE_SHIFT); 976117632Sharti tct[4] = mcr << IDT_TCT_LMCR_SHIFT; 977117632Sharti tct[5] = (cdf << IDT_TCT_CDF_SHIFT) | 978117632Sharti (rdf << IDT_TCT_RDF_SHIFT) | 979117632Sharti (air << IDT_TCT_AIR_SHIFT); 980117632Sharti 981117632Sharti sc->bwrem -= vcc->vcc.tparam.mcr; 982117632Sharti break; 983117632Sharti } 984117632Sharti } 985117632Sharti 986117632Sharti patm_sram_write4(sc, sram + 0, tct[0], tct[1], tct[2], tct[3]); 987117632Sharti patm_sram_write4(sc, sram + 4, tct[4], tct[5], tct[6], tct[7]); 988117632Sharti 989117632Sharti patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x %08x %08x %08x %08x", 990117632Sharti sram / 8, patm_sram_read(sc, sram + 0), 991117632Sharti patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2), 992117632Sharti patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4), 993117632Sharti patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6), 994117632Sharti patm_sram_read(sc, sram + 7)); 995117632Sharti} 996117632Sharti 997117632Sharti/* 998117632Sharti * Start a channel 999117632Sharti */ 1000117632Shartistatic void 1001117632Shartipatm_tct_start(struct patm_softc *sc, struct patm_vcc *vcc) 1002117632Sharti{ 1003117632Sharti 1004117632Sharti patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid, 1005117632Sharti vcc->scd->init_er)); 1006117632Sharti patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_SLACR(vcc->cid, 1007117632Sharti vcc->scd->lacr)); 1008117632Sharti} 1009117632Sharti 1010117632Shartistatic void 1011117632Shartipatm_tct_print(struct patm_softc *sc, u_int cid) 1012117632Sharti{ 1013117632Sharti#ifdef PATM_DEBUG 1014117632Sharti u_int sram = cid * 8; 1015117632Sharti#endif 1016117632Sharti 1017117632Sharti patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x %08x %08x %08x %08x", 1018117632Sharti sram / 8, patm_sram_read(sc, sram + 0), 1019117632Sharti patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2), 1020117632Sharti patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4), 1021117632Sharti patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6), 1022117632Sharti patm_sram_read(sc, sram + 7)); 1023117632Sharti} 1024117632Sharti 1025117632Sharti/* 1026117632Sharti * Setup the SCD 1027117632Sharti */ 1028117632Shartivoid 1029117632Shartipatm_scd_setup(struct patm_softc *sc, struct patm_scd *scd) 1030117632Sharti{ 1031117632Sharti patm_sram_write4(sc, scd->sram + 0, 1032117632Sharti scd->phy, 0, 0xffffffff, 0); 1033117632Sharti patm_sram_write4(sc, scd->sram + 4, 1034117632Sharti 0, 0, 0, 0); 1035117632Sharti 1036117632Sharti patm_debug(sc, VCC, "SCD(%x): %08x %08x %08x %08x %08x %08x %08x %08x", 1037117632Sharti scd->sram, 1038117632Sharti patm_sram_read(sc, scd->sram + 0), 1039117632Sharti patm_sram_read(sc, scd->sram + 1), 1040117632Sharti patm_sram_read(sc, scd->sram + 2), 1041117632Sharti patm_sram_read(sc, scd->sram + 3), 1042117632Sharti patm_sram_read(sc, scd->sram + 4), 1043117632Sharti patm_sram_read(sc, scd->sram + 5), 1044117632Sharti patm_sram_read(sc, scd->sram + 6), 1045117632Sharti patm_sram_read(sc, scd->sram + 7)); 1046117632Sharti} 1047117632Sharti 1048117632Sharti/* 1049117632Sharti * Grow the TX map table if possible 1050117632Sharti */ 1051117632Shartistatic void 1052117632Shartipatm_txmaps_grow(struct patm_softc *sc) 1053117632Sharti{ 1054117632Sharti u_int i; 1055117632Sharti struct patm_txmap *map; 1056117632Sharti int err; 1057117632Sharti 1058117632Sharti if (sc->tx_nmaps >= sc->tx_maxmaps) 1059117632Sharti return; 1060117632Sharti 1061117632Sharti for (i = sc->tx_nmaps; i < sc->tx_nmaps + PATM_CFG_TXMAPS_STEP; i++) { 1062117632Sharti map = uma_zalloc(sc->tx_mapzone, M_NOWAIT); 1063117632Sharti err = bus_dmamap_create(sc->tx_tag, 0, &map->map); 1064117632Sharti if (err) { 1065117632Sharti uma_zfree(sc->tx_mapzone, map); 1066117632Sharti break; 1067117632Sharti } 1068117632Sharti SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 1069117632Sharti } 1070117632Sharti 1071117632Sharti sc->tx_nmaps = i; 1072117632Sharti} 1073117632Sharti 1074117632Sharti/* 1075117632Sharti * Allocate a transmission map 1076117632Sharti */ 1077117632Shartistatic struct patm_txmap * 1078117632Shartipatm_txmap_get(struct patm_softc *sc) 1079117632Sharti{ 1080117632Sharti struct patm_txmap *map; 1081117632Sharti 1082117632Sharti if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL) { 1083117632Sharti patm_txmaps_grow(sc); 1084117632Sharti if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL) 1085117632Sharti return (NULL); 1086117632Sharti } 1087117632Sharti SLIST_REMOVE_HEAD(&sc->tx_maps_free, link); 1088117632Sharti return (map); 1089117632Sharti} 1090117632Sharti 1091117632Sharti/* 1092117632Sharti * Look whether we are in the process of updating the TST on the chip. 1093117632Sharti * If we are set the flag that we need another update. 1094117632Sharti * If we are not start the update. 1095117632Sharti */ 1096117632Shartistatic __inline void 1097117632Shartipatm_tst_start(struct patm_softc *sc) 1098117632Sharti{ 1099117632Sharti 1100117632Sharti if (!(sc->tst_state & TST_PENDING)) { 1101117632Sharti sc->tst_state |= TST_PENDING; 1102117632Sharti if (!(sc->tst_state & TST_WAIT)) { 1103117632Sharti /* timer not running */ 1104117632Sharti patm_tst_update(sc); 1105117632Sharti } 1106117632Sharti } 1107117632Sharti} 1108117632Sharti 1109117632Sharti/* 1110117632Sharti * Allocate TST entries to a CBR connection 1111117632Sharti */ 1112117632Shartistatic void 1113117632Shartipatm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc) 1114117632Sharti{ 1115117632Sharti u_int slots; 1116117632Sharti u_int qptr, pptr; 1117117632Sharti u_int qmax, pmax; 1118117632Sharti u_int pspc, last; 1119117632Sharti 1120117632Sharti mtx_lock(&sc->tst_lock); 1121117632Sharti 1122117632Sharti /* compute the number of slots we need, make sure to get at least 1123117632Sharti * the specified PCR */ 1124117632Sharti slots = cbr2slots(sc, vcc); 1125117632Sharti vcc->scd->slots = slots; 1126117632Sharti sc->bwrem -= slots2cr(sc, slots); 1127117632Sharti 1128117632Sharti patm_debug(sc, TST, "tst_alloc: cbr=%u link=%u tst=%u slots=%u", 1129147256Sbrooks vcc->vcc.tparam.pcr, IFP2IFATM(sc->ifp)->mib.pcr, sc->mmap->tst_size, slots); 1130117632Sharti 1131117632Sharti qmax = sc->mmap->tst_size - 1; 1132117632Sharti pmax = qmax << 8; 1133117632Sharti 1134117632Sharti pspc = pmax / slots; 1135117632Sharti 1136117632Sharti pptr = pspc >> 1; /* starting point */ 1137117632Sharti qptr = pptr >> 8; 1138117632Sharti 1139117632Sharti last = qptr; 1140117632Sharti 1141117632Sharti while (slots > 0) { 1142117632Sharti if (qptr >= qmax) 1143117632Sharti qptr -= qmax; 1144117632Sharti if (sc->tst_soft[qptr] != IDT_TST_VBR) { 1145117632Sharti /* used - try next */ 1146117632Sharti qptr++; 1147117632Sharti continue; 1148117632Sharti } 1149117632Sharti patm_debug(sc, TST, "slot[%u] = %u.%u diff=%d", qptr, 1150117632Sharti vcc->vcc.vpi, vcc->vcc.vci, (int)qptr - (int)last); 1151117632Sharti last = qptr; 1152117632Sharti 1153117632Sharti sc->tst_soft[qptr] = IDT_TST_CBR | vcc->cid | TST_BOTH; 1154117632Sharti sc->tst_free--; 1155117632Sharti 1156117632Sharti if ((pptr += pspc) >= pmax) 1157117632Sharti pptr -= pmax; 1158117632Sharti qptr = pptr >> 8; 1159117632Sharti 1160117632Sharti slots--; 1161117632Sharti } 1162117632Sharti patm_tst_start(sc); 1163117632Sharti mtx_unlock(&sc->tst_lock); 1164117632Sharti} 1165117632Sharti 1166117632Sharti/* 1167117632Sharti * Free a CBR connection's TST entries 1168117632Sharti */ 1169117632Shartistatic void 1170117632Shartipatm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc) 1171117632Sharti{ 1172117632Sharti u_int i; 1173117632Sharti 1174117632Sharti mtx_lock(&sc->tst_lock); 1175117632Sharti for (i = 0; i < sc->mmap->tst_size - 1; i++) { 1176117632Sharti if ((sc->tst_soft[i] & IDT_TST_MASK) == vcc->cid) { 1177117632Sharti sc->tst_soft[i] = IDT_TST_VBR | TST_BOTH; 1178117632Sharti sc->tst_free++; 1179117632Sharti } 1180117632Sharti } 1181117632Sharti sc->bwrem += slots2cr(sc, vcc->scd->slots); 1182117632Sharti patm_tst_start(sc); 1183117632Sharti mtx_unlock(&sc->tst_lock); 1184117632Sharti} 1185117632Sharti 1186117632Sharti/* 1187117632Sharti * Write the soft TST into the idle incore TST and start the wait timer. 1188117632Sharti * We assume that we hold the tst lock. 1189117632Sharti */ 1190117632Shartistatic void 1191117632Shartipatm_tst_update(struct patm_softc *sc) 1192117632Sharti{ 1193117632Sharti u_int flag; /* flag to clear from soft TST */ 1194117632Sharti u_int idle; /* the idle TST */ 1195117632Sharti u_int act; /* the active TST */ 1196117632Sharti u_int i; 1197117632Sharti 1198117632Sharti if (sc->tst_state & TST_ACT1) { 1199117632Sharti act = 1; 1200117632Sharti idle = 0; 1201117632Sharti flag = TST_CH0; 1202117632Sharti } else { 1203117632Sharti act = 0; 1204117632Sharti idle = 1; 1205117632Sharti flag = TST_CH1; 1206117632Sharti } 1207117632Sharti /* update the idle one */ 1208117632Sharti for (i = 0; i < sc->mmap->tst_size - 1; i++) 1209117632Sharti if (sc->tst_soft[i] & flag) { 1210117632Sharti patm_sram_write(sc, sc->tst_base[idle] + i, 1211117632Sharti sc->tst_soft[i] & ~TST_BOTH); 1212117632Sharti sc->tst_soft[i] &= ~flag; 1213117632Sharti } 1214117632Sharti /* the used one jump to the idle one */ 1215117632Sharti patm_sram_write(sc, sc->tst_jump[act], 1216117632Sharti IDT_TST_BR | (sc->tst_base[idle] << 2)); 1217117632Sharti 1218117632Sharti /* wait for the chip to jump */ 1219117632Sharti sc->tst_state &= ~TST_PENDING; 1220117632Sharti sc->tst_state |= TST_WAIT; 1221117632Sharti 1222117632Sharti callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc); 1223117632Sharti} 1224117632Sharti 1225117632Sharti/* 1226117632Sharti * Timer for TST updates 1227117632Sharti */ 1228117632Shartistatic void 1229117632Shartipatm_tst_timer(void *p) 1230117632Sharti{ 1231117632Sharti struct patm_softc *sc = p; 1232117632Sharti u_int act; /* active TST */ 1233117632Sharti u_int now; /* current place in TST */ 1234117632Sharti 1235117632Sharti mtx_lock(&sc->tst_lock); 1236117632Sharti 1237117632Sharti if (sc->tst_state & TST_WAIT) { 1238117632Sharti /* ignore the PENDING state while we are waiting for 1239117632Sharti * the chip to switch tables. Once the switch is done, 1240117632Sharti * we will again lock at PENDING */ 1241117632Sharti act = (sc->tst_state & TST_ACT1) ? 1 : 0; 1242117632Sharti now = patm_nor_read(sc, IDT_NOR_NOW) >> 2; 1243117632Sharti if (now >= sc->tst_base[act] && now <= sc->tst_jump[act]) { 1244117632Sharti /* not yet */ 1245117632Sharti callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc); 1246117632Sharti goto done; 1247117632Sharti } 1248117632Sharti sc->tst_state &= ~TST_WAIT; 1249117632Sharti /* change back jump */ 1250117632Sharti patm_sram_write(sc, sc->tst_jump[act], 1251117632Sharti IDT_TST_BR | (sc->tst_base[act] << 2)); 1252117632Sharti 1253117632Sharti /* switch */ 1254117632Sharti sc->tst_state ^= TST_ACT1; 1255117632Sharti } 1256117632Sharti 1257117632Sharti if (sc->tst_state & TST_PENDING) 1258117632Sharti /* we got another update request while the timer was running. */ 1259117632Sharti patm_tst_update(sc); 1260117632Sharti 1261117632Sharti done: 1262117632Sharti mtx_unlock(&sc->tst_lock); 1263117632Sharti} 1264117632Sharti 1265117632Shartistatic const char * 1266117632Shartidump_scd(struct patm_softc *sc, struct patm_scd *scd) 1267117632Sharti{ 1268117632Sharti u_int i; 1269117632Sharti 1270117632Sharti for (i = 0; i < IDT_TSQE_TAG_SPACE; i++) 1271117632Sharti printf("on_card[%u] = %p\n", i, scd->on_card[i]); 1272117632Sharti printf("space=%u tag=%u num_on_card=%u last_tag=%u\n", 1273117632Sharti scd->space, scd->tag, scd->num_on_card, scd->last_tag); 1274117632Sharti 1275117632Sharti return (""); 1276117632Sharti} 1277