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