if_patm_tx.c revision 117872
1/* 2 * Copyright (c) 2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * The TST allocation algorithm is from the IDT driver which is: 28 * 29 * Copyright (c) 2000, 2001 Richard Hodges and Matriplex, inc. 30 * All rights reserved. 31 * 32 * Copyright (c) 1996, 1997, 1998, 1999 Mark Tinguely 33 * All rights reserved. 34 * 35 * Author: Hartmut Brandt <harti@freebsd.org> 36 * 37 * Driver for IDT77252 based cards like ProSum's. 38 */ 39#include <sys/cdefs.h> 40__FBSDID("$FreeBSD: head/sys/dev/patm/if_patm_tx.c 117872 2003-07-22 08:20:09Z harti $"); 41 42#include "opt_inet.h" 43#include "opt_natm.h" 44 45#include <sys/types.h> 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/malloc.h> 49#include <sys/kernel.h> 50#include <sys/bus.h> 51#include <sys/errno.h> 52#include <sys/conf.h> 53#include <sys/module.h> 54#include <sys/lock.h> 55#include <sys/mutex.h> 56#include <sys/sysctl.h> 57#include <sys/queue.h> 58#include <sys/condvar.h> 59#include <sys/endian.h> 60#include <vm/uma.h> 61 62#include <sys/sockio.h> 63#include <sys/mbuf.h> 64#include <sys/socket.h> 65 66#include <net/if.h> 67#include <net/if_media.h> 68#include <net/if_atm.h> 69#include <net/route.h> 70#ifdef ENABLE_BPF 71#include <net/bpf.h> 72#endif 73#include <netinet/in.h> 74#include <netinet/if_atm.h> 75 76#include <machine/bus.h> 77#include <machine/resource.h> 78#include <sys/bus.h> 79#include <sys/rman.h> 80#include <sys/mbpool.h> 81 82#include <dev/utopia/utopia.h> 83#include <dev/patm/idt77252reg.h> 84#include <dev/patm/if_patmvar.h> 85 86static struct mbuf *patm_tx_pad(struct patm_softc *sc, struct mbuf *m0); 87static void patm_launch(struct patm_softc *sc, struct patm_scd *scd); 88 89static struct patm_txmap *patm_txmap_get(struct patm_softc *); 90static void patm_load_txbuf(void *, bus_dma_segment_t *, int, 91 bus_size_t, int); 92 93static void patm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc); 94static void patm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc); 95static void patm_tst_timer(void *p); 96static void patm_tst_update(struct patm_softc *); 97 98static void patm_tct_start(struct patm_softc *sc, struct patm_vcc *); 99 100static const char *dump_scd(struct patm_softc *sc, struct patm_scd *scd) 101 __unused; 102static void patm_tct_print(struct patm_softc *sc, u_int cid) __unused; 103 104/* 105 * Structure for communication with the loader function for transmission 106 */ 107struct txarg { 108 struct patm_softc *sc; 109 struct patm_scd *scd; /* scheduling channel */ 110 struct patm_vcc *vcc; /* the VCC of this PDU */ 111 struct mbuf *mbuf; 112 u_int hdr; /* cell header */ 113}; 114 115static __inline u_int 116cbr2slots(struct patm_softc *sc, struct patm_vcc *vcc) 117{ 118 /* compute the number of slots we need, make sure to get at least 119 * the specified PCR */ 120 return ((u_int)(((uint64_t)(sc->mmap->tst_size - 1) * 121 vcc->vcc.tparam.pcr + sc->ifatm.mib.pcr - 1) / sc->ifatm.mib.pcr)); 122} 123 124static __inline u_int 125slots2cr(struct patm_softc *sc, u_int slots) 126{ 127 return ((slots * sc->ifatm.mib.pcr + sc->mmap->tst_size - 2) / 128 (sc->mmap->tst_size - 1)); 129} 130 131/* check if we can open this one */ 132int 133patm_tx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc) 134{ 135 136 /* check resources */ 137 switch (vcc->vcc.traffic) { 138 139 case ATMIO_TRAFFIC_CBR: 140 { 141 u_int slots = cbr2slots(sc, vcc); 142 143 if (slots > sc->tst_free + sc->tst_reserve) 144 return (EINVAL); 145 break; 146 } 147 148 case ATMIO_TRAFFIC_VBR: 149 if (vcc->vcc.tparam.scr > sc->bwrem) 150 return (EINVAL); 151 if (vcc->vcc.tparam.pcr > sc->ifatm.mib.pcr) 152 return (EINVAL); 153 if (vcc->vcc.tparam.scr > vcc->vcc.tparam.pcr || 154 vcc->vcc.tparam.mbs == 0) 155 return (EINVAL); 156 break; 157 158 case ATMIO_TRAFFIC_ABR: 159 if (vcc->vcc.tparam.tbe == 0 || 160 vcc->vcc.tparam.nrm == 0) 161 /* needed to compute CRM */ 162 return (EINVAL); 163 if (vcc->vcc.tparam.pcr > sc->ifatm.mib.pcr || 164 vcc->vcc.tparam.icr > vcc->vcc.tparam.pcr || 165 vcc->vcc.tparam.mcr > vcc->vcc.tparam.icr) 166 return (EINVAL); 167 if (vcc->vcc.tparam.mcr > sc->bwrem || 168 vcc->vcc.tparam.icr > sc->bwrem) 169 return (EINVAL); 170 break; 171 } 172 173 return (0); 174} 175 176#define NEXT_TAG(T) do { \ 177 (T) = ((T) + 1) % IDT_TSQE_TAG_SPACE; \ 178 } while (0) 179 180/* 181 * open it 182 */ 183void 184patm_tx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc) 185{ 186 struct patm_scd *scd; 187 188 if (vcc->vcc.traffic == ATMIO_TRAFFIC_UBR) { 189 /* we use UBR0 */ 190 vcc->scd = sc->scd0; 191 vcc->vflags |= PATM_VCC_TX_OPEN; 192 return; 193 } 194 195 /* get an SCD */ 196 scd = patm_scd_alloc(sc); 197 if (scd == NULL) { 198 /* should not happen */ 199 patm_printf(sc, "out of SCDs\n"); 200 return; 201 } 202 vcc->scd = scd; 203 patm_scd_setup(sc, scd); 204 patm_tct_setup(sc, scd, vcc); 205 206 if (vcc->vcc.traffic != ATMIO_TRAFFIC_CBR) 207 patm_tct_start(sc, vcc); 208 209 vcc->vflags |= PATM_VCC_TX_OPEN; 210} 211 212/* 213 * close the given vcc for transmission 214 */ 215void 216patm_tx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc) 217{ 218 struct patm_scd *scd; 219 struct mbuf *m; 220 221 vcc->vflags |= PATM_VCC_TX_CLOSING; 222 223 if (vcc->vcc.traffic == ATMIO_TRAFFIC_UBR) { 224 /* let the queue PDUs go out */ 225 vcc->scd = NULL; 226 vcc->vflags &= ~(PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING); 227 return; 228 } 229 scd = vcc->scd; 230 231 /* empty the waitq */ 232 for (;;) { 233 _IF_DEQUEUE(&scd->q, m); 234 if (m == NULL) 235 break; 236 m_freem(m); 237 } 238 239 if (scd->num_on_card == 0) { 240 /* we are idle */ 241 vcc->vflags &= ~PATM_VCC_TX_OPEN; 242 243 if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR) 244 patm_tst_free(sc, vcc); 245 246 patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0); 247 patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0); 248 patm_scd_free(sc, scd); 249 250 vcc->scd = NULL; 251 vcc->vflags &= ~PATM_VCC_TX_CLOSING; 252 253 return; 254 } 255 256 /* speed up transmission */ 257 patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid, 0xff)); 258 patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_ULACR(vcc->cid, 0xff)); 259 260 /* wait for the interrupt to drop the number to 0 */ 261 patm_debug(sc, VCC, "%u buffers still on card", scd->num_on_card); 262} 263 264/* transmission side finally closed */ 265void 266patm_tx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc) 267{ 268 269 patm_debug(sc, VCC, "%u.%u TX closed", vcc->vcc.vpi, vcc->vcc.vci); 270 271 if (vcc->vcc.traffic == ATMIO_TRAFFIC_VBR) 272 sc->bwrem += vcc->vcc.tparam.scr; 273} 274 275/* 276 * Pull off packets from the interface queue and try to transmit them. 277 * If the transmission fails because of a full transmit channel, we drop 278 * packets for CBR and queue them for other channels up to limit. 279 * This limit should depend on the CDVT for VBR and ABR, but it doesn't. 280 */ 281void 282patm_start(struct ifnet *ifp) 283{ 284 struct patm_softc *sc = (struct patm_softc *)ifp->if_softc; 285 struct mbuf *m; 286 struct atm_pseudohdr *aph; 287 u_int vpi, vci, cid; 288 struct patm_vcc *vcc; 289 290 mtx_lock(&sc->mtx); 291 if (!(ifp->if_flags & IFF_RUNNING)) { 292 mtx_unlock(&sc->mtx); 293 return; 294 } 295 296 while (1) { 297 /* get a new mbuf */ 298 IF_DEQUEUE(&ifp->if_snd, m); 299 if (m == NULL) 300 break; 301 302 /* split of pseudo header */ 303 if (m->m_len < sizeof(*aph) && 304 (m = m_pullup(m, sizeof(*aph))) == NULL) { 305 sc->ifatm.ifnet.if_oerrors++; 306 continue; 307 } 308 309 aph = mtod(m, struct atm_pseudohdr *); 310 vci = ATM_PH_VCI(aph); 311 vpi = ATM_PH_VPI(aph); 312 m_adj(m, sizeof(*aph)); 313 314 /* reject empty packets */ 315 if (m->m_pkthdr.len == 0) { 316 m_freem(m); 317 sc->ifatm.ifnet.if_oerrors++; 318 continue; 319 } 320 321 /* check whether this is a legal vcc */ 322 if (!LEGAL_VPI(sc, vpi) || !LEGAL_VCI(sc, vci) || vci == 0) { 323 m_freem(m); 324 sc->ifatm.ifnet.if_oerrors++; 325 continue; 326 } 327 cid = PATM_CID(sc, vpi, vci); 328 vcc = sc->vccs[cid]; 329 if (vcc == NULL) { 330 m_freem(m); 331 sc->ifatm.ifnet.if_oerrors++; 332 continue; 333 } 334 335 /* must be multiple of 48 if not AAL5 */ 336 if (vcc->vcc.aal == ATMIO_AAL_0 || 337 vcc->vcc.aal == ATMIO_AAL_34) { 338 /* XXX AAL3/4 format? */ 339 if (m->m_pkthdr.len % 48 != 0 && 340 (m = patm_tx_pad(sc, m)) == NULL) { 341 sc->ifatm.ifnet.if_oerrors++; 342 continue; 343 } 344 } else if (vcc->vcc.aal == ATMIO_AAL_RAW) { 345 switch (vcc->vflags & PATM_RAW_FORMAT) { 346 347 default: 348 case PATM_RAW_CELL: 349 if (m->m_pkthdr.len != 53) { 350 sc->ifatm.ifnet.if_oerrors++; 351 m_freem(m); 352 continue; 353 } 354 break; 355 356 case PATM_RAW_NOHEC: 357 if (m->m_pkthdr.len != 52) { 358 sc->ifatm.ifnet.if_oerrors++; 359 m_freem(m); 360 continue; 361 } 362 break; 363 364 case PATM_RAW_CS: 365 if (m->m_pkthdr.len != 64) { 366 sc->ifatm.ifnet.if_oerrors++; 367 m_freem(m); 368 continue; 369 } 370 break; 371 } 372 } 373 374 /* save data */ 375 m->m_pkthdr.header = vcc; 376 377 /* try to put it on the channels queue */ 378 if (_IF_QFULL(&vcc->scd->q)) { 379 sc->ifatm.ifnet.if_oerrors++; 380 sc->stats.tx_qfull++; 381 m_freem(m); 382 continue; 383 } 384 _IF_ENQUEUE(&vcc->scd->q, m); 385 386#ifdef ENABLE_BPF 387 if (!(vcc->vcc.flags & ATMIO_FLAG_NG) && 388 (vcc->vcc.flags & ATM_PH_AAL5) && 389 (vcc->vcc.flags & ATM_PH_LLCSNAP)) 390 BPF_MTAP(ifp, m); 391#endif 392 393 /* kick the channel to life */ 394 patm_launch(sc, vcc->scd); 395 396 } 397 mtx_unlock(&sc->mtx); 398} 399 400/* 401 * Pad non-AAL5 packet to a multiple of 48-byte. 402 * We assume AAL0 only. We have still to decide on the format of AAL3/4. 403 */ 404static struct mbuf * 405patm_tx_pad(struct patm_softc *sc, struct mbuf *m0) 406{ 407 struct mbuf *last, *m; 408 u_int plen, pad, space; 409 410 plen = m_length(m0, &last); 411 if (plen != m0->m_pkthdr.len) { 412 patm_printf(sc, "%s: mbuf length mismatch %d %u\n", __func__, 413 m0->m_pkthdr.len, plen); 414 m0->m_pkthdr.len = plen; 415 if (plen == 0) { 416 m_freem(m0); 417 sc->ifatm.ifnet.if_oerrors++; 418 return (NULL); 419 } 420 if (plen % 48 == 0) 421 return (m0); 422 } 423 pad = 48 - plen % 48; 424 m0->m_pkthdr.len += pad; 425 if (M_WRITABLE(last)) { 426 if (M_TRAILINGSPACE(last) >= pad) { 427 bzero(last->m_data + last->m_len, pad); 428 last->m_len += pad; 429 return (m0); 430 } 431 space = M_LEADINGSPACE(last); 432 if (space + M_TRAILINGSPACE(last) >= pad) { 433 bcopy(last->m_data, last->m_data + space, last->m_len); 434 last->m_data -= space; 435 bzero(last->m_data + last->m_len, pad); 436 last->m_len += pad; 437 return (m0); 438 } 439 } 440 MGET(m, M_DONTWAIT, MT_DATA); 441 if (m == 0) { 442 m_freem(m0); 443 sc->ifatm.ifnet.if_oerrors++; 444 return (NULL); 445 } 446 bzero(mtod(m, u_char *), pad); 447 m->m_len = pad; 448 last->m_next = m; 449 450 return (m0); 451} 452 453/* 454 * Try to put as many packets from the channels queue onto the channel 455 */ 456static void 457patm_launch(struct patm_softc *sc, struct patm_scd *scd) 458{ 459 struct txarg a; 460 struct mbuf *m, *tmp; 461 u_int segs; 462 struct patm_txmap *map; 463 int error; 464 465 a.sc = sc; 466 a.scd = scd; 467 468 /* limit the number of outstanding packets to the tag space */ 469 while (scd->num_on_card < IDT_TSQE_TAG_SPACE) { 470 /* get the next packet */ 471 _IF_DEQUEUE(&scd->q, m); 472 if (m == NULL) 473 break; 474 475 a.vcc = m->m_pkthdr.header; 476 477 /* we must know the number of segments beforehand - count 478 * this may actually give a wrong number of segments for 479 * AAL_RAW where we still need to remove the cell header */ 480 segs = 0; 481 for (tmp = m; tmp != NULL; tmp = tmp->m_next) 482 if (tmp->m_len != 0) 483 segs++; 484 485 /* check whether there is space in the queue */ 486 if (segs >= scd->space) { 487 /* put back */ 488 _IF_PREPEND(&scd->q, m); 489 sc->stats.tx_out_of_tbds++; 490 break; 491 } 492 493 /* get a DMA map */ 494 if ((map = patm_txmap_get(sc)) == NULL) { 495 _IF_PREPEND(&scd->q, m); 496 sc->stats.tx_out_of_maps++; 497 break; 498 } 499 500 /* load the map */ 501 m->m_pkthdr.header = map; 502 a.mbuf = m; 503 504 /* handle AAL_RAW */ 505 if (a.vcc->vcc.aal == ATMIO_AAL_RAW) { 506 u_char hdr[4]; 507 508 m_copydata(m, 0, 4, hdr); 509 a.hdr = (hdr[0] << 24) | (hdr[1] << 16) | 510 (hdr[2] << 8) | hdr[3]; 511 512 switch (a.vcc->vflags & PATM_RAW_FORMAT) { 513 514 default: 515 case PATM_RAW_CELL: 516 m_adj(m, 5); 517 break; 518 519 case PATM_RAW_NOHEC: 520 m_adj(m, 4); 521 break; 522 523 case PATM_RAW_CS: 524 m_adj(m, 16); 525 break; 526 } 527 } else 528 a.hdr = IDT_TBD_HDR(a.vcc->vcc.vpi, a.vcc->vcc.vci, 529 0, 0); 530 531 error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m, 532 patm_load_txbuf, &a, BUS_DMA_NOWAIT); 533 if (error == EFBIG) { 534 if ((m = m_defrag(m, M_DONTWAIT)) == NULL) { 535 sc->ifatm.ifnet.if_oerrors++; 536 continue; 537 } 538 error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m, 539 patm_load_txbuf, &a, BUS_DMA_NOWAIT); 540 } 541 if (error != 0) { 542 sc->stats.tx_load_err++; 543 sc->ifatm.ifnet.if_oerrors++; 544 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 545 m_freem(m); 546 continue; 547 } 548 549 sc->ifatm.ifnet.if_opackets++; 550 } 551} 552 553/* 554 * Load the DMA segments into the scheduling channel 555 */ 556static void 557patm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg, 558 bus_size_t mapsize, int error) 559{ 560 struct txarg *a= uarg; 561 struct patm_scd *scd = a->scd; 562 u_int w1, w3, cnt; 563 struct idt_tbd *tbd = NULL; 564 u_int rest = mapsize; 565 566 if (error != 0) 567 return; 568 569 cnt = 0; 570 while (nseg > 0) { 571 if (segs->ds_len == 0) { 572 /* transmit buffer length must be > 0 */ 573 nseg--; 574 segs++; 575 continue; 576 } 577 /* rest after this buffer */ 578 rest -= segs->ds_len; 579 580 /* put together status word */ 581 w1 = 0; 582 if (rest < 48 /* && a->vcc->vcc.aal != ATMIO_AAL_5 */) 583 /* last cell is in this buffer */ 584 w1 |= IDT_TBD_EPDU; 585 586 if (a->vcc->vcc.aal == ATMIO_AAL_5) 587 w1 |= IDT_TBD_AAL5; 588 else if (a->vcc->vcc.aal == ATMIO_AAL_34) 589 w1 |= IDT_TBD_AAL34; 590 else 591 w1 |= IDT_TBD_AAL0; 592 593 w1 |= segs->ds_len; 594 595 /* AAL5 PDU length (unpadded) */ 596 if (a->vcc->vcc.aal == ATMIO_AAL_5) 597 w3 = mapsize; 598 else 599 w3 = 0; 600 601 if (rest == 0) 602 w1 |= IDT_TBD_TSIF | IDT_TBD_GTSI | 603 (scd->tag << IDT_TBD_TAG_SHIFT); 604 605 tbd = &scd->scq[scd->tail]; 606 607 tbd->flags = htole32(w1); 608 tbd->addr = htole32(segs->ds_addr); 609 tbd->aal5 = htole32(w3); 610 tbd->hdr = htole32(a->hdr); 611 612 patm_debug(a->sc, TX, "TBD(%u): %08x %08x %08x %08x", 613 scd->tail, w1, segs->ds_addr, w3, a->hdr); 614 615 /* got to next entry */ 616 if (++scd->tail == IDT_SCQ_SIZE) 617 scd->tail = 0; 618 cnt++; 619 nseg--; 620 segs++; 621 } 622 scd->space -= cnt; 623 scd->num_on_card++; 624 625 KASSERT(rest == 0, ("bad mbuf")); 626 KASSERT(cnt > 0, ("no segs")); 627 KASSERT(scd->space > 0, ("scq full")); 628 629 KASSERT(scd->on_card[scd->tag] == NULL, 630 ("scd on_card wedged %u%s", scd->tag, dump_scd(a->sc, scd))); 631 scd->on_card[scd->tag] = a->mbuf; 632 a->mbuf->m_pkthdr.csum_data = cnt; 633 634 NEXT_TAG(scd->tag); 635 636 patm_debug(a->sc, TX, "SCD tail %u (%lx:%lx)", scd->tail, 637 (u_long)scd->phy, (u_long)scd->phy + (scd->tail << IDT_TBD_SHIFT)); 638 patm_sram_write(a->sc, scd->sram, 639 scd->phy + (scd->tail << IDT_TBD_SHIFT)); 640 641 if (patm_sram_read(a->sc, a->vcc->cid * 8 + 3) & IDT_TCT_IDLE) { 642 /* 643 * if the connection is idle start it. We cannot rely 644 * on a flag set by patm_tx_idle() here, because sometimes 645 * the card seems to place an idle TSI into the TSQ but 646 * forgets to raise an interrupt. 647 */ 648 patm_nor_write(a->sc, IDT_NOR_TCMDQ, 649 IDT_TCMDQ_START(a->vcc->cid)); 650 } 651} 652 653/* 654 * packet transmitted 655 */ 656void 657patm_tx(struct patm_softc *sc, u_int stamp, u_int status) 658{ 659 u_int cid, tag, last; 660 struct mbuf *m; 661 struct patm_vcc *vcc; 662 struct patm_scd *scd; 663 struct patm_txmap *map; 664 665 /* get the connection */ 666 cid = PATM_CID(sc, IDT_TBD_VPI(status), IDT_TBD_VCI(status)); 667 if ((vcc = sc->vccs[cid]) == NULL) { 668 /* closed UBR connection */ 669 return; 670 } 671 scd = vcc->scd; 672 673 tag = IDT_TSQE_TAG(stamp); 674 675 last = scd->last_tag; 676 if (tag == last) { 677 patm_printf(sc, "same tag %u\n", tag); 678 return; 679 } 680 681 /* Errata 12 requests us to free all entries up to the one 682 * with the given tag. */ 683 do { 684 /* next tag to try */ 685 NEXT_TAG(last); 686 687 m = scd->on_card[last]; 688 KASSERT(m != NULL, ("%stag=%u", dump_scd(sc, scd), tag)); 689 scd->on_card[last] = NULL; 690 patm_debug(sc, TX, "ok tag=%x", last); 691 692 map = m->m_pkthdr.header; 693 scd->space += m->m_pkthdr.csum_data; 694 695 bus_dmamap_sync(sc->tx_tag, map->map, 696 BUS_DMASYNC_POSTWRITE); 697 bus_dmamap_unload(sc->tx_tag, map->map); 698 m_freem(m); 699 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 700 scd->num_on_card--; 701 702 if (vcc->vflags & PATM_VCC_TX_CLOSING) { 703 if (scd->num_on_card == 0) { 704 /* done with this VCC */ 705 if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR) 706 patm_tst_free(sc, vcc); 707 708 patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0); 709 patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0); 710 patm_scd_free(sc, scd); 711 712 vcc->scd = NULL; 713 vcc->vflags &= ~PATM_VCC_TX_CLOSING; 714 715 if (vcc->vflags & PATM_VCC_ASYNC) { 716 patm_tx_vcc_closed(sc, vcc); 717 if (!(vcc->vflags & PATM_VCC_OPEN)) 718 patm_vcc_closed(sc, vcc); 719 } else 720 cv_signal(&sc->vcc_cv); 721 return; 722 } 723 patm_debug(sc, VCC, "%u buffers still on card", 724 scd->num_on_card); 725 726 if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) { 727 /* insist on speeding up transmission for ABR */ 728 patm_nor_write(sc, IDT_NOR_TCMDQ, 729 IDT_TCMDQ_UIER(vcc->cid, 0xff)); 730 patm_nor_write(sc, IDT_NOR_TCMDQ, 731 IDT_TCMDQ_ULACR(vcc->cid, 0xff)); 732 } 733 } 734 735 } while (last != tag); 736 scd->last_tag = tag; 737 738 if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) { 739 u_int acri, cps; 740 741 acri = (patm_sram_read(sc, 8 * cid + 2) >> IDT_TCT_ACRI_SHIFT) 742 & 0x3fff; 743 cps = sc->ifatm.mib.pcr * 32 / 744 ((1 << (acri >> 10)) * (acri & 0x3ff)); 745 746 if (cps != vcc->cps) { 747 /* send message */ 748 patm_debug(sc, VCC, "ACRI=%04x CPS=%u", acri, cps); 749 vcc->cps = cps; 750 } 751 } 752 753 patm_launch(sc, scd); 754} 755 756/* 757 * VBR/ABR connection went idle 758 * Either restart it or set the idle flag. 759 */ 760void 761patm_tx_idle(struct patm_softc *sc, u_int cid) 762{ 763 struct patm_vcc *vcc; 764 765 patm_debug(sc, VCC, "idle %u", cid); 766 767 if ((vcc = sc->vccs[cid]) != NULL && 768 (vcc->vflags & (PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING)) != 0 && 769 vcc->scd != NULL && (vcc->scd->num_on_card != 0 || 770 _IF_QLEN(&vcc->scd->q) != 0)) { 771 /* 772 * If there is any packet outstanding in the SCD re-activate 773 * the channel and kick it. 774 */ 775 patm_nor_write(sc, IDT_NOR_TCMDQ, 776 IDT_TCMDQ_START(vcc->cid)); 777 778 patm_launch(sc, vcc->scd); 779 } 780} 781 782/* 783 * Convert a (24bit) rate to the atm-forum form 784 * Our rate is never larger than 19 bit. 785 */ 786static u_int 787cps2atmf(u_int cps) 788{ 789 u_int e; 790 791 if (cps == 0) 792 return (0); 793 cps <<= 9; 794 e = 0; 795 while (cps > (1024 - 1)) { 796 e++; 797 cps >>= 1; 798 } 799 return ((1 << 14) | (e << 9) | (cps & 0x1ff)); 800} 801 802/* 803 * Do a binary search on the log2rate table to convert the rate 804 * to its log form. This assumes that the ATM-Forum form is monotonically 805 * increasing with the plain cell rate. 806 */ 807static u_int 808rate2log(struct patm_softc *sc, u_int rate) 809{ 810 const uint32_t *tbl; 811 u_int lower, upper, mid, done, val, afr; 812 813 afr = cps2atmf(rate); 814 815 if (sc->flags & PATM_25M) 816 tbl = patm_rtables25; 817 else 818 tbl = patm_rtables155; 819 820 lower = 0; 821 upper = 255; 822 done = 0; 823 while (!done) { 824 mid = (lower + upper) / 2; 825 val = tbl[mid] >> 17; 826 if (val == afr || upper == lower) 827 break; 828 if (afr > val) 829 lower = mid + 1; 830 else 831 upper = mid - 1; 832 } 833 if (val > afr && mid > 0) 834 mid--; 835 return (mid); 836} 837 838/* 839 * Return the table index for an increase table. The increase table 840 * must be selected not by the RIF itself, but by PCR/2^RIF. Each table 841 * represents an additive increase of a cell rate that can be computed 842 * from the first table entry (the value in this entry will not be clamped 843 * by the link rate). 844 */ 845static u_int 846get_air_table(struct patm_softc *sc, u_int rif, u_int pcr) 847{ 848 const uint32_t *tbl; 849 u_int increase, base, lair0, ret, t, cps; 850 851#define GET_ENTRY(TAB, IDX) (0xffff & ((IDX & 1) ? \ 852 (tbl[512 + (IDX / 2) + 128 * (TAB)] >> 16) : \ 853 (tbl[512 + (IDX / 2) + 128 * (TAB)]))) 854 855#define MANT_BITS 10 856#define FRAC_BITS 16 857 858#define DIFF_TO_FP(D) (((D) & ((1 << MANT_BITS) - 1)) << ((D) >> MANT_BITS)) 859#define AFR_TO_INT(A) ((1 << (((A) >> 9) & 0x1f)) * \ 860 (512 + ((A) & 0x1ff)) / 512 * ((A) >> 14)) 861 862 if (sc->flags & PATM_25M) 863 tbl = patm_rtables25; 864 else 865 tbl = patm_rtables155; 866 if (rif >= patm_rtables_ntab) 867 rif = patm_rtables_ntab - 1; 868 increase = pcr >> rif; 869 870 ret = 0; 871 for (t = 0; t < patm_rtables_ntab; t++) { 872 /* get base rate of this table */ 873 base = GET_ENTRY(t, 0); 874 /* convert this to fixed point */ 875 lair0 = DIFF_TO_FP(base) >> FRAC_BITS; 876 877 /* get the CPS from the log2rate table */ 878 cps = AFR_TO_INT(tbl[lair0] >> 17) - 10; 879 880 if (increase >= cps) 881 break; 882 883 ret = t; 884 } 885 return (ret + 4); 886} 887 888/* 889 * Setup the TCT 890 */ 891void 892patm_tct_setup(struct patm_softc *sc, struct patm_scd *scd, 893 struct patm_vcc *vcc) 894{ 895 uint32_t tct[8]; 896 u_int sram; 897 u_int mbs, token; 898 u_int tmp, crm, rdf, cdf, air, mcr; 899 900 bzero(tct, sizeof(tct)); 901 if (vcc == NULL) { 902 /* special case for UBR0 */ 903 sram = 0; 904 tct[0] = IDT_TCT_UBR | scd->sram; 905 tct[7] = IDT_TCT_UBR_FLG; 906 907 } else { 908 sram = vcc->cid * 8; 909 switch (vcc->vcc.traffic) { 910 911 case ATMIO_TRAFFIC_CBR: 912 patm_tst_alloc(sc, vcc); 913 tct[0] = IDT_TCT_CBR | scd->sram; 914 /* must account for what was really allocated */ 915 break; 916 917 case ATMIO_TRAFFIC_VBR: 918 /* compute parameters for the TCT */ 919 scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr); 920 scd->lacr = rate2log(sc, vcc->vcc.tparam.scr); 921 922 /* get the 16-bit fraction of SCR/PCR 923 * both a 24 bit. Do it the simple way. */ 924 token = (uint64_t)(vcc->vcc.tparam.scr << 16) / 925 vcc->vcc.tparam.pcr; 926 927 patm_debug(sc, VCC, "VBR: init_er=%u lacr=%u " 928 "token=0x%04x\n", scd->init_er, scd->lacr, token); 929 930 tct[0] = IDT_TCT_VBR | scd->sram; 931 tct[2] = IDT_TCT_TSIF; 932 tct[3] = IDT_TCT_IDLE | IDT_TCT_HALT; 933 tct[4] = IDT_TCT_MAXIDLE; 934 tct[5] = 0x01000000; 935 if ((mbs = vcc->vcc.tparam.mbs) > 0xff) 936 mbs = 0xff; 937 tct[6] = (mbs << 16) | token; 938 sc->bwrem -= vcc->vcc.tparam.scr; 939 break; 940 941 case ATMIO_TRAFFIC_ABR: 942 scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr); 943 scd->lacr = rate2log(sc, vcc->vcc.tparam.icr); 944 mcr = rate2log(sc, vcc->vcc.tparam.mcr); 945 946 /* compute CRM */ 947 tmp = vcc->vcc.tparam.tbe / vcc->vcc.tparam.nrm; 948 if (tmp * vcc->vcc.tparam.nrm < vcc->vcc.tparam.tbe) 949 tmp++; 950 for (crm = 1; tmp > (1 << crm); crm++) 951 ; 952 if (crm > 0x7) 953 crm = 7; 954 955 air = get_air_table(sc, vcc->vcc.tparam.rif, 956 vcc->vcc.tparam.pcr); 957 958 if ((rdf = vcc->vcc.tparam.rdf) >= patm_rtables_ntab) 959 rdf = patm_rtables_ntab - 1; 960 rdf += patm_rtables_ntab + 4; 961 962 if ((cdf = vcc->vcc.tparam.cdf) >= patm_rtables_ntab) 963 cdf = patm_rtables_ntab - 1; 964 cdf += patm_rtables_ntab + 4; 965 966 patm_debug(sc, VCC, "ABR: init_er=%u lacr=%u mcr=%u " 967 "crm=%u air=%u rdf=%u cdf=%u\n", scd->init_er, 968 scd->lacr, mcr, crm, air, rdf, cdf); 969 970 tct[0] = IDT_TCT_ABR | scd->sram; 971 tct[1] = crm << IDT_TCT_CRM_SHIFT; 972 tct[3] = IDT_TCT_HALT | IDT_TCT_IDLE | 973 (4 << IDT_TCT_NAGE_SHIFT); 974 tct[4] = mcr << IDT_TCT_LMCR_SHIFT; 975 tct[5] = (cdf << IDT_TCT_CDF_SHIFT) | 976 (rdf << IDT_TCT_RDF_SHIFT) | 977 (air << IDT_TCT_AIR_SHIFT); 978 979 sc->bwrem -= vcc->vcc.tparam.mcr; 980 break; 981 } 982 } 983 984 patm_sram_write4(sc, sram + 0, tct[0], tct[1], tct[2], tct[3]); 985 patm_sram_write4(sc, sram + 4, tct[4], tct[5], tct[6], tct[7]); 986 987 patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x %08x %08x %08x %08x", 988 sram / 8, patm_sram_read(sc, sram + 0), 989 patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2), 990 patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4), 991 patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6), 992 patm_sram_read(sc, sram + 7)); 993} 994 995/* 996 * Start a channel 997 */ 998static void 999patm_tct_start(struct patm_softc *sc, struct patm_vcc *vcc) 1000{ 1001 1002 patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid, 1003 vcc->scd->init_er)); 1004 patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_SLACR(vcc->cid, 1005 vcc->scd->lacr)); 1006} 1007 1008static void 1009patm_tct_print(struct patm_softc *sc, u_int cid) 1010{ 1011#ifdef PATM_DEBUG 1012 u_int sram = cid * 8; 1013#endif 1014 1015 patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x %08x %08x %08x %08x", 1016 sram / 8, patm_sram_read(sc, sram + 0), 1017 patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2), 1018 patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4), 1019 patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6), 1020 patm_sram_read(sc, sram + 7)); 1021} 1022 1023/* 1024 * Setup the SCD 1025 */ 1026void 1027patm_scd_setup(struct patm_softc *sc, struct patm_scd *scd) 1028{ 1029 patm_sram_write4(sc, scd->sram + 0, 1030 scd->phy, 0, 0xffffffff, 0); 1031 patm_sram_write4(sc, scd->sram + 4, 1032 0, 0, 0, 0); 1033 1034 patm_debug(sc, VCC, "SCD(%x): %08x %08x %08x %08x %08x %08x %08x %08x", 1035 scd->sram, 1036 patm_sram_read(sc, scd->sram + 0), 1037 patm_sram_read(sc, scd->sram + 1), 1038 patm_sram_read(sc, scd->sram + 2), 1039 patm_sram_read(sc, scd->sram + 3), 1040 patm_sram_read(sc, scd->sram + 4), 1041 patm_sram_read(sc, scd->sram + 5), 1042 patm_sram_read(sc, scd->sram + 6), 1043 patm_sram_read(sc, scd->sram + 7)); 1044} 1045 1046/* 1047 * Grow the TX map table if possible 1048 */ 1049static void 1050patm_txmaps_grow(struct patm_softc *sc) 1051{ 1052 u_int i; 1053 struct patm_txmap *map; 1054 int err; 1055 1056 if (sc->tx_nmaps >= sc->tx_maxmaps) 1057 return; 1058 1059 for (i = sc->tx_nmaps; i < sc->tx_nmaps + PATM_CFG_TXMAPS_STEP; i++) { 1060 map = uma_zalloc(sc->tx_mapzone, M_NOWAIT); 1061 err = bus_dmamap_create(sc->tx_tag, 0, &map->map); 1062 if (err) { 1063 uma_zfree(sc->tx_mapzone, map); 1064 break; 1065 } 1066 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 1067 } 1068 1069 sc->tx_nmaps = i; 1070} 1071 1072/* 1073 * Allocate a transmission map 1074 */ 1075static struct patm_txmap * 1076patm_txmap_get(struct patm_softc *sc) 1077{ 1078 struct patm_txmap *map; 1079 1080 if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL) { 1081 patm_txmaps_grow(sc); 1082 if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL) 1083 return (NULL); 1084 } 1085 SLIST_REMOVE_HEAD(&sc->tx_maps_free, link); 1086 return (map); 1087} 1088 1089/* 1090 * Look whether we are in the process of updating the TST on the chip. 1091 * If we are set the flag that we need another update. 1092 * If we are not start the update. 1093 */ 1094static __inline void 1095patm_tst_start(struct patm_softc *sc) 1096{ 1097 1098 if (!(sc->tst_state & TST_PENDING)) { 1099 sc->tst_state |= TST_PENDING; 1100 if (!(sc->tst_state & TST_WAIT)) { 1101 /* timer not running */ 1102 patm_tst_update(sc); 1103 } 1104 } 1105} 1106 1107/* 1108 * Allocate TST entries to a CBR connection 1109 */ 1110static void 1111patm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc) 1112{ 1113 u_int slots; 1114 u_int qptr, pptr; 1115 u_int qmax, pmax; 1116 u_int pspc, last; 1117 1118 mtx_lock(&sc->tst_lock); 1119 1120 /* compute the number of slots we need, make sure to get at least 1121 * the specified PCR */ 1122 slots = cbr2slots(sc, vcc); 1123 vcc->scd->slots = slots; 1124 sc->bwrem -= slots2cr(sc, slots); 1125 1126 patm_debug(sc, TST, "tst_alloc: cbr=%u link=%u tst=%u slots=%u", 1127 vcc->vcc.tparam.pcr, sc->ifatm.mib.pcr, sc->mmap->tst_size, slots); 1128 1129 qmax = sc->mmap->tst_size - 1; 1130 pmax = qmax << 8; 1131 1132 pspc = pmax / slots; 1133 1134 pptr = pspc >> 1; /* starting point */ 1135 qptr = pptr >> 8; 1136 1137 last = qptr; 1138 1139 while (slots > 0) { 1140 if (qptr >= qmax) 1141 qptr -= qmax; 1142 if (sc->tst_soft[qptr] != IDT_TST_VBR) { 1143 /* used - try next */ 1144 qptr++; 1145 continue; 1146 } 1147 patm_debug(sc, TST, "slot[%u] = %u.%u diff=%d", qptr, 1148 vcc->vcc.vpi, vcc->vcc.vci, (int)qptr - (int)last); 1149 last = qptr; 1150 1151 sc->tst_soft[qptr] = IDT_TST_CBR | vcc->cid | TST_BOTH; 1152 sc->tst_free--; 1153 1154 if ((pptr += pspc) >= pmax) 1155 pptr -= pmax; 1156 qptr = pptr >> 8; 1157 1158 slots--; 1159 } 1160 patm_tst_start(sc); 1161 mtx_unlock(&sc->tst_lock); 1162} 1163 1164/* 1165 * Free a CBR connection's TST entries 1166 */ 1167static void 1168patm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc) 1169{ 1170 u_int i; 1171 1172 mtx_lock(&sc->tst_lock); 1173 for (i = 0; i < sc->mmap->tst_size - 1; i++) { 1174 if ((sc->tst_soft[i] & IDT_TST_MASK) == vcc->cid) { 1175 sc->tst_soft[i] = IDT_TST_VBR | TST_BOTH; 1176 sc->tst_free++; 1177 } 1178 } 1179 sc->bwrem += slots2cr(sc, vcc->scd->slots); 1180 patm_tst_start(sc); 1181 mtx_unlock(&sc->tst_lock); 1182} 1183 1184/* 1185 * Write the soft TST into the idle incore TST and start the wait timer. 1186 * We assume that we hold the tst lock. 1187 */ 1188static void 1189patm_tst_update(struct patm_softc *sc) 1190{ 1191 u_int flag; /* flag to clear from soft TST */ 1192 u_int idle; /* the idle TST */ 1193 u_int act; /* the active TST */ 1194 u_int i; 1195 1196 if (sc->tst_state & TST_ACT1) { 1197 act = 1; 1198 idle = 0; 1199 flag = TST_CH0; 1200 } else { 1201 act = 0; 1202 idle = 1; 1203 flag = TST_CH1; 1204 } 1205 /* update the idle one */ 1206 for (i = 0; i < sc->mmap->tst_size - 1; i++) 1207 if (sc->tst_soft[i] & flag) { 1208 patm_sram_write(sc, sc->tst_base[idle] + i, 1209 sc->tst_soft[i] & ~TST_BOTH); 1210 sc->tst_soft[i] &= ~flag; 1211 } 1212 /* the used one jump to the idle one */ 1213 patm_sram_write(sc, sc->tst_jump[act], 1214 IDT_TST_BR | (sc->tst_base[idle] << 2)); 1215 1216 /* wait for the chip to jump */ 1217 sc->tst_state &= ~TST_PENDING; 1218 sc->tst_state |= TST_WAIT; 1219 1220 callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc); 1221} 1222 1223/* 1224 * Timer for TST updates 1225 */ 1226static void 1227patm_tst_timer(void *p) 1228{ 1229 struct patm_softc *sc = p; 1230 u_int act; /* active TST */ 1231 u_int now; /* current place in TST */ 1232 1233 mtx_lock(&sc->tst_lock); 1234 1235 if (sc->tst_state & TST_WAIT) { 1236 /* ignore the PENDING state while we are waiting for 1237 * the chip to switch tables. Once the switch is done, 1238 * we will again lock at PENDING */ 1239 act = (sc->tst_state & TST_ACT1) ? 1 : 0; 1240 now = patm_nor_read(sc, IDT_NOR_NOW) >> 2; 1241 if (now >= sc->tst_base[act] && now <= sc->tst_jump[act]) { 1242 /* not yet */ 1243 callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc); 1244 goto done; 1245 } 1246 sc->tst_state &= ~TST_WAIT; 1247 /* change back jump */ 1248 patm_sram_write(sc, sc->tst_jump[act], 1249 IDT_TST_BR | (sc->tst_base[act] << 2)); 1250 1251 /* switch */ 1252 sc->tst_state ^= TST_ACT1; 1253 } 1254 1255 if (sc->tst_state & TST_PENDING) 1256 /* we got another update request while the timer was running. */ 1257 patm_tst_update(sc); 1258 1259 done: 1260 mtx_unlock(&sc->tst_lock); 1261} 1262 1263static const char * 1264dump_scd(struct patm_softc *sc, struct patm_scd *scd) 1265{ 1266 u_int i; 1267 1268 for (i = 0; i < IDT_TSQE_TAG_SPACE; i++) 1269 printf("on_card[%u] = %p\n", i, scd->on_card[i]); 1270 printf("space=%u tag=%u num_on_card=%u last_tag=%u\n", 1271 scd->space, scd->tag, scd->num_on_card, scd->last_tag); 1272 1273 return (""); 1274} 1275