if_patm_tx.c revision 117632
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 117632 2003-07-15 11:57:24Z 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 if (M_WRITABLE(last)) { 425 if (M_TRAILINGSPACE(last) >= pad) { 426 bzero(last->m_data + last->m_len, pad); 427 last->m_len += pad; 428 return (m0); 429 } 430 space = M_LEADINGSPACE(last); 431 if (space + M_TRAILINGSPACE(last) >= pad) { 432 bcopy(last->m_data, last->m_data + space, last->m_len); 433 last->m_data -= space; 434 bzero(last->m_data + last->m_len, pad); 435 last->m_len += pad; 436 return (m0); 437 } 438 } 439 MGET(m, M_DONTWAIT, MT_DATA); 440 if (m == 0) { 441 m_freem(m0); 442 sc->ifatm.ifnet.if_oerrors++; 443 return (NULL); 444 } 445 bzero(mtod(m, u_char *), pad); 446 m->m_len = pad; 447 last->m_next = m; 448 449 return (m0); 450} 451 452/* 453 * Try to put as many packets from the channels queue onto the channel 454 */ 455static void 456patm_launch(struct patm_softc *sc, struct patm_scd *scd) 457{ 458 struct txarg a; 459 struct mbuf *m, *tmp; 460 u_int segs; 461 struct patm_txmap *map; 462 int error; 463 464 a.sc = sc; 465 a.scd = scd; 466 467 /* limit the number of outstanding packets to the tag space */ 468 while (scd->num_on_card < IDT_TSQE_TAG_SPACE) { 469 /* get the next packet */ 470 _IF_DEQUEUE(&scd->q, m); 471 if (m == NULL) 472 break; 473 474 a.vcc = m->m_pkthdr.header; 475 476 /* we must know the number of segments beforehand - count 477 * this may actually give a wrong number of segments for 478 * AAL_RAW where we still need to remove the cell header */ 479 segs = 0; 480 for (tmp = m; tmp != NULL; tmp = tmp->m_next) 481 if (tmp->m_len != 0) 482 segs++; 483 484 /* check whether there is space in the queue */ 485 if (segs >= scd->space) { 486 /* put back */ 487 _IF_PREPEND(&scd->q, m); 488 sc->stats.tx_out_of_tbds++; 489 break; 490 } 491 492 /* get a DMA map */ 493 if ((map = patm_txmap_get(sc)) == NULL) { 494 _IF_PREPEND(&scd->q, m); 495 sc->stats.tx_out_of_maps++; 496 break; 497 } 498 499 /* load the map */ 500 m->m_pkthdr.header = map; 501 a.mbuf = m; 502 503 /* handle AAL_RAW */ 504 if (a.vcc->vcc.aal == ATMIO_AAL_RAW) { 505 u_char hdr[4]; 506 507 m_copydata(m, 0, 4, hdr); 508 a.hdr = (hdr[0] << 24) | (hdr[1] << 16) | 509 (hdr[2] << 8) | hdr[3]; 510 511 switch (a.vcc->vflags & PATM_RAW_FORMAT) { 512 513 default: 514 case PATM_RAW_CELL: 515 m_adj(m, 5); 516 break; 517 518 case PATM_RAW_NOHEC: 519 m_adj(m, 4); 520 break; 521 522 case PATM_RAW_CS: 523 m_adj(m, 16); 524 break; 525 } 526 } else 527 a.hdr = IDT_TBD_HDR(a.vcc->vcc.vpi, a.vcc->vcc.vci, 528 0, 0); 529 530 error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m, 531 patm_load_txbuf, &a, BUS_DMA_NOWAIT); 532 if (error == EFBIG) { 533 if ((m = m_defrag(m, M_DONTWAIT)) == NULL) { 534 sc->ifatm.ifnet.if_oerrors++; 535 continue; 536 } 537 error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m, 538 patm_load_txbuf, &a, BUS_DMA_NOWAIT); 539 } 540 if (error != 0) { 541 sc->stats.tx_load_err++; 542 sc->ifatm.ifnet.if_oerrors++; 543 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 544 m_freem(m); 545 continue; 546 } 547 548 sc->ifatm.ifnet.if_opackets++; 549 } 550} 551 552/* 553 * Load the DMA segments into the scheduling channel 554 */ 555static void 556patm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg, 557 bus_size_t mapsize, int error) 558{ 559 struct txarg *a= uarg; 560 struct patm_scd *scd = a->scd; 561 u_int w1, w3, cnt; 562 struct idt_tbd *tbd = NULL; 563 u_int rest = mapsize; 564 565 if (error != 0) 566 return; 567 568 cnt = 0; 569 while (nseg > 0) { 570 if (segs->ds_len == 0) { 571 /* transmit buffer length must be > 0 */ 572 nseg--; 573 segs++; 574 continue; 575 } 576 /* rest after this buffer */ 577 rest -= segs->ds_len; 578 579 /* put together status word */ 580 w1 = 0; 581 if (rest < 48 /* && a->vcc->vcc.aal != ATMIO_AAL_5 */) 582 /* last cell is in this buffer */ 583 w1 |= IDT_TBD_EPDU; 584 585 if (a->vcc->vcc.aal == ATMIO_AAL_5) 586 w1 |= IDT_TBD_AAL5; 587 else if (a->vcc->vcc.aal == ATMIO_AAL_34) 588 w1 |= IDT_TBD_AAL34; 589 else 590 w1 |= IDT_TBD_AAL0; 591 592 w1 |= segs->ds_len; 593 594 /* AAL5 PDU length (unpadded) */ 595 if (a->vcc->vcc.aal == ATMIO_AAL_5) 596 w3 = mapsize; 597 else 598 w3 = 0; 599 600 if (rest == 0) 601 w1 |= IDT_TBD_TSIF | IDT_TBD_GTSI | 602 (scd->tag << IDT_TBD_TAG_SHIFT); 603 604 tbd = &scd->scq[scd->tail]; 605 606 tbd->flags = htole32(w1); 607 tbd->addr = htole32(segs->ds_addr); 608 tbd->aal5 = htole32(w3); 609 tbd->hdr = htole32(a->hdr); 610 611 patm_debug(a->sc, TX, "TBD(%u): %08x %08x %08x %08x", 612 scd->tail, w1, segs->ds_addr, w3, a->hdr); 613 614 /* got to next entry */ 615 if (++scd->tail == IDT_SCQ_SIZE) 616 scd->tail = 0; 617 cnt++; 618 nseg--; 619 segs++; 620 } 621 scd->space -= cnt; 622 scd->num_on_card++; 623 624 KASSERT(rest == 0, ("bad mbuf")); 625 KASSERT(cnt > 0, ("no segs")); 626 KASSERT(scd->space > 0, ("scq full")); 627 628 KASSERT(scd->on_card[scd->tag] == NULL, 629 ("scd on_card wedged %u%s", scd->tag, dump_scd(a->sc, scd))); 630 scd->on_card[scd->tag] = a->mbuf; 631 a->mbuf->m_pkthdr.csum_data = cnt; 632 633 NEXT_TAG(scd->tag); 634 635 patm_debug(a->sc, TX, "SCD tail %u (%lx:%lx)", scd->tail, 636 (u_long)scd->phy, (u_long)scd->phy + (scd->tail << IDT_TBD_SHIFT)); 637 patm_sram_write(a->sc, scd->sram, 638 scd->phy + (scd->tail << IDT_TBD_SHIFT)); 639 640 if (patm_sram_read(a->sc, a->vcc->cid * 8 + 3) & IDT_TCT_IDLE) { 641 /* 642 * if the connection is idle start it. We cannot rely 643 * on a flag set by patm_tx_idle() here, because sometimes 644 * the card seems to place an idle TSI into the TSQ but 645 * forgets to raise an interrupt. 646 */ 647 patm_nor_write(a->sc, IDT_NOR_TCMDQ, 648 IDT_TCMDQ_START(a->vcc->cid)); 649 } 650} 651 652/* 653 * packet transmitted 654 */ 655void 656patm_tx(struct patm_softc *sc, u_int stamp, u_int status) 657{ 658 u_int cid, tag, last; 659 struct mbuf *m; 660 struct patm_vcc *vcc; 661 struct patm_scd *scd; 662 struct patm_txmap *map; 663 664 /* get the connection */ 665 cid = PATM_CID(sc, IDT_TBD_VPI(status), IDT_TBD_VCI(status)); 666 if ((vcc = sc->vccs[cid]) == NULL) { 667 /* closed UBR connection */ 668 return; 669 } 670 scd = vcc->scd; 671 672 tag = IDT_TSQE_TAG(stamp); 673 674 last = scd->last_tag; 675 if (tag == last) { 676 patm_printf(sc, "same tag %u\n", tag); 677 return; 678 } 679 680 /* Errata 12 requests us to free all entries up to the one 681 * with the given tag. */ 682 do { 683 /* next tag to try */ 684 NEXT_TAG(last); 685 686 m = scd->on_card[last]; 687 KASSERT(m != NULL, ("%stag=%u", dump_scd(sc, scd), tag)); 688 scd->on_card[last] = NULL; 689 patm_debug(sc, TX, "ok tag=%x", last); 690 691 map = m->m_pkthdr.header; 692 scd->space += m->m_pkthdr.csum_data; 693 694 bus_dmamap_sync(sc->tx_tag, map->map, 695 BUS_DMASYNC_POSTWRITE); 696 bus_dmamap_unload(sc->tx_tag, map->map); 697 m_freem(m); 698 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 699 scd->num_on_card--; 700 701 if (vcc->vflags & PATM_VCC_TX_CLOSING) { 702 if (scd->num_on_card == 0) { 703 /* done with this VCC */ 704 if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR) 705 patm_tst_free(sc, vcc); 706 707 patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0); 708 patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0); 709 patm_scd_free(sc, scd); 710 711 vcc->scd = NULL; 712 vcc->vflags &= ~PATM_VCC_TX_CLOSING; 713 714 if (vcc->vflags & PATM_VCC_ASYNC) { 715 patm_tx_vcc_closed(sc, vcc); 716 if (!(vcc->vflags & PATM_VCC_OPEN)) 717 patm_vcc_closed(sc, vcc); 718 } else 719 cv_signal(&sc->vcc_cv); 720 return; 721 } 722 patm_debug(sc, VCC, "%u buffers still on card", 723 scd->num_on_card); 724 725 if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) { 726 /* insist on speeding up transmission for ABR */ 727 patm_nor_write(sc, IDT_NOR_TCMDQ, 728 IDT_TCMDQ_UIER(vcc->cid, 0xff)); 729 patm_nor_write(sc, IDT_NOR_TCMDQ, 730 IDT_TCMDQ_ULACR(vcc->cid, 0xff)); 731 } 732 } 733 734 } while (last != tag); 735 scd->last_tag = tag; 736 737 if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) { 738 u_int acri, cps; 739 740 acri = (patm_sram_read(sc, 8 * cid + 2) >> IDT_TCT_ACRI_SHIFT) 741 & 0x3fff; 742 cps = sc->ifatm.mib.pcr * 32 / 743 ((1 << (acri >> 10)) * (acri & 0x3ff)); 744 745 if (cps != vcc->cps) { 746 /* send message */ 747 patm_debug(sc, VCC, "ACRI=%04x CPS=%u", acri, cps); 748 vcc->cps = cps; 749 } 750 } 751 752 patm_launch(sc, scd); 753} 754 755/* 756 * VBR/ABR connection went idle 757 * Either restart it or set the idle flag. 758 */ 759void 760patm_tx_idle(struct patm_softc *sc, u_int cid) 761{ 762 struct patm_vcc *vcc; 763 764 patm_debug(sc, VCC, "idle %u", cid); 765 766 if ((vcc = sc->vccs[cid]) != NULL && 767 (vcc->vflags & (PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING)) != 0 && 768 vcc->scd != NULL && (vcc->scd->num_on_card != 0 || 769 _IF_QLEN(&vcc->scd->q) != 0)) { 770 /* 771 * If there is any packet outstanding in the SCD re-activate 772 * the channel and kick it. 773 */ 774 patm_nor_write(sc, IDT_NOR_TCMDQ, 775 IDT_TCMDQ_START(vcc->cid)); 776 777 patm_launch(sc, vcc->scd); 778 } 779} 780 781/* 782 * Convert a (24bit) rate to the atm-forum form 783 * Our rate is never larger than 19 bit. 784 */ 785static u_int 786cps2atmf(u_int cps) 787{ 788 u_int e; 789 790 if (cps == 0) 791 return (0); 792 cps <<= 9; 793 e = 0; 794 while (cps > (1024 - 1)) { 795 e++; 796 cps >>= 1; 797 } 798 return ((1 << 14) | (e << 9) | (cps & 0x1ff)); 799} 800 801/* 802 * Do a binary search on the log2rate table to convert the rate 803 * to its log form. This assumes that the ATM-Forum form is monotonically 804 * increasing with the plain cell rate. 805 */ 806static u_int 807rate2log(struct patm_softc *sc, u_int rate) 808{ 809 const uint32_t *tbl; 810 u_int lower, upper, mid, done, val, afr; 811 812 afr = cps2atmf(rate); 813 814 if (sc->flags & PATM_25M) 815 tbl = patm_rtables25; 816 else 817 tbl = patm_rtables155; 818 819 lower = 0; 820 upper = 255; 821 done = 0; 822 while (!done) { 823 mid = (lower + upper) / 2; 824 val = tbl[mid] >> 17; 825 if (val == afr || upper == lower) 826 break; 827 if (afr > val) 828 lower = mid + 1; 829 else 830 upper = mid - 1; 831 } 832 if (val > afr && mid > 0) 833 mid--; 834 return (mid); 835} 836 837/* 838 * Return the table index for an increase table. The increase table 839 * must be selected not by the RIF itself, but by PCR/2^RIF. Each table 840 * represents an additive increase of a cell rate that can be computed 841 * from the first table entry (the value in this entry will not be clamped 842 * by the link rate). 843 */ 844static u_int 845get_air_table(struct patm_softc *sc, u_int rif, u_int pcr) 846{ 847 const uint32_t *tbl; 848 u_int increase, base, lair0, ret, t, cps; 849 850#define GET_ENTRY(TAB, IDX) (0xffff & ((IDX & 1) ? \ 851 (tbl[512 + (IDX / 2) + 128 * (TAB)] >> 16) : \ 852 (tbl[512 + (IDX / 2) + 128 * (TAB)]))) 853 854#define MANT_BITS 10 855#define FRAC_BITS 16 856 857#define DIFF_TO_FP(D) (((D) & ((1 << MANT_BITS) - 1)) << ((D) >> MANT_BITS)) 858#define AFR_TO_INT(A) ((1 << (((A) >> 9) & 0x1f)) * \ 859 (512 + ((A) & 0x1ff)) / 512 * ((A) >> 14)) 860 861 if (sc->flags & PATM_25M) 862 tbl = patm_rtables25; 863 else 864 tbl = patm_rtables155; 865 if (rif >= patm_rtables_ntab) 866 rif = patm_rtables_ntab - 1; 867 increase = pcr >> rif; 868 869 ret = 0; 870 for (t = 0; t < patm_rtables_ntab; t++) { 871 /* get base rate of this table */ 872 base = GET_ENTRY(t, 0); 873 /* convert this to fixed point */ 874 lair0 = DIFF_TO_FP(base) >> FRAC_BITS; 875 876 /* get the CPS from the log2rate table */ 877 cps = AFR_TO_INT(tbl[lair0] >> 17) - 10; 878 879 if (increase >= cps) 880 break; 881 882 ret = t; 883 } 884 return (ret + 4); 885} 886 887/* 888 * Setup the TCT 889 */ 890void 891patm_tct_setup(struct patm_softc *sc, struct patm_scd *scd, 892 struct patm_vcc *vcc) 893{ 894 uint32_t tct[8]; 895 u_int sram; 896 u_int mbs, token; 897 u_int tmp, crm, rdf, cdf, air, mcr; 898 899 bzero(tct, sizeof(tct)); 900 if (vcc == NULL) { 901 /* special case for UBR0 */ 902 sram = 0; 903 tct[0] = IDT_TCT_UBR | scd->sram; 904 tct[7] = IDT_TCT_UBR_FLG; 905 906 } else { 907 sram = vcc->cid * 8; 908 switch (vcc->vcc.traffic) { 909 910 case ATMIO_TRAFFIC_CBR: 911 patm_tst_alloc(sc, vcc); 912 tct[0] = IDT_TCT_CBR | scd->sram; 913 /* must account for what was really allocated */ 914 break; 915 916 case ATMIO_TRAFFIC_VBR: 917 /* compute parameters for the TCT */ 918 scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr); 919 scd->lacr = rate2log(sc, vcc->vcc.tparam.scr); 920 921 /* get the 16-bit fraction of SCR/PCR 922 * both a 24 bit. Do it the simple way. */ 923 token = (uint64_t)(vcc->vcc.tparam.scr << 16) / 924 vcc->vcc.tparam.pcr; 925 926 patm_debug(sc, VCC, "VBR: init_er=%u lacr=%u " 927 "token=0x%04x\n", scd->init_er, scd->lacr, token); 928 929 tct[0] = IDT_TCT_VBR | scd->sram; 930 tct[2] = IDT_TCT_TSIF; 931 tct[3] = IDT_TCT_IDLE | IDT_TCT_HALT; 932 tct[4] = IDT_TCT_MAXIDLE; 933 tct[5] = 0x01000000; 934 if ((mbs = vcc->vcc.tparam.mbs) > 0xff) 935 mbs = 0xff; 936 tct[6] = (mbs << 16) | token; 937 sc->bwrem -= vcc->vcc.tparam.scr; 938 break; 939 940 case ATMIO_TRAFFIC_ABR: 941 scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr); 942 scd->lacr = rate2log(sc, vcc->vcc.tparam.icr); 943 mcr = rate2log(sc, vcc->vcc.tparam.mcr); 944 945 /* compute CRM */ 946 tmp = vcc->vcc.tparam.tbe / vcc->vcc.tparam.nrm; 947 if (tmp * vcc->vcc.tparam.nrm < vcc->vcc.tparam.tbe) 948 tmp++; 949 for (crm = 1; tmp > (1 << crm); crm++) 950 ; 951 if (crm > 0x7) 952 crm = 7; 953 954 air = get_air_table(sc, vcc->vcc.tparam.rif, 955 vcc->vcc.tparam.pcr); 956 957 if ((rdf = vcc->vcc.tparam.rdf) >= patm_rtables_ntab) 958 rdf = patm_rtables_ntab - 1; 959 rdf += patm_rtables_ntab + 4; 960 961 if ((cdf = vcc->vcc.tparam.cdf) >= patm_rtables_ntab) 962 cdf = patm_rtables_ntab - 1; 963 cdf += patm_rtables_ntab + 4; 964 965 patm_debug(sc, VCC, "ABR: init_er=%u lacr=%u mcr=%u " 966 "crm=%u air=%u rdf=%u cdf=%u\n", scd->init_er, 967 scd->lacr, mcr, crm, air, rdf, cdf); 968 969 tct[0] = IDT_TCT_ABR | scd->sram; 970 tct[1] = crm << IDT_TCT_CRM_SHIFT; 971 tct[3] = IDT_TCT_HALT | IDT_TCT_IDLE | 972 (4 << IDT_TCT_NAGE_SHIFT); 973 tct[4] = mcr << IDT_TCT_LMCR_SHIFT; 974 tct[5] = (cdf << IDT_TCT_CDF_SHIFT) | 975 (rdf << IDT_TCT_RDF_SHIFT) | 976 (air << IDT_TCT_AIR_SHIFT); 977 978 sc->bwrem -= vcc->vcc.tparam.mcr; 979 break; 980 } 981 } 982 983 patm_sram_write4(sc, sram + 0, tct[0], tct[1], tct[2], tct[3]); 984 patm_sram_write4(sc, sram + 4, tct[4], tct[5], tct[6], tct[7]); 985 986 patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x %08x %08x %08x %08x", 987 sram / 8, patm_sram_read(sc, sram + 0), 988 patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2), 989 patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4), 990 patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6), 991 patm_sram_read(sc, sram + 7)); 992} 993 994/* 995 * Start a channel 996 */ 997static void 998patm_tct_start(struct patm_softc *sc, struct patm_vcc *vcc) 999{ 1000 1001 patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid, 1002 vcc->scd->init_er)); 1003 patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_SLACR(vcc->cid, 1004 vcc->scd->lacr)); 1005} 1006 1007static void 1008patm_tct_print(struct patm_softc *sc, u_int cid) 1009{ 1010#ifdef PATM_DEBUG 1011 u_int sram = cid * 8; 1012#endif 1013 1014 patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x %08x %08x %08x %08x", 1015 sram / 8, patm_sram_read(sc, sram + 0), 1016 patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2), 1017 patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4), 1018 patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6), 1019 patm_sram_read(sc, sram + 7)); 1020} 1021 1022/* 1023 * Setup the SCD 1024 */ 1025void 1026patm_scd_setup(struct patm_softc *sc, struct patm_scd *scd) 1027{ 1028 patm_sram_write4(sc, scd->sram + 0, 1029 scd->phy, 0, 0xffffffff, 0); 1030 patm_sram_write4(sc, scd->sram + 4, 1031 0, 0, 0, 0); 1032 1033 patm_debug(sc, VCC, "SCD(%x): %08x %08x %08x %08x %08x %08x %08x %08x", 1034 scd->sram, 1035 patm_sram_read(sc, scd->sram + 0), 1036 patm_sram_read(sc, scd->sram + 1), 1037 patm_sram_read(sc, scd->sram + 2), 1038 patm_sram_read(sc, scd->sram + 3), 1039 patm_sram_read(sc, scd->sram + 4), 1040 patm_sram_read(sc, scd->sram + 5), 1041 patm_sram_read(sc, scd->sram + 6), 1042 patm_sram_read(sc, scd->sram + 7)); 1043} 1044 1045/* 1046 * Grow the TX map table if possible 1047 */ 1048static void 1049patm_txmaps_grow(struct patm_softc *sc) 1050{ 1051 u_int i; 1052 struct patm_txmap *map; 1053 int err; 1054 1055 if (sc->tx_nmaps >= sc->tx_maxmaps) 1056 return; 1057 1058 for (i = sc->tx_nmaps; i < sc->tx_nmaps + PATM_CFG_TXMAPS_STEP; i++) { 1059 map = uma_zalloc(sc->tx_mapzone, M_NOWAIT); 1060 err = bus_dmamap_create(sc->tx_tag, 0, &map->map); 1061 if (err) { 1062 uma_zfree(sc->tx_mapzone, map); 1063 break; 1064 } 1065 SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link); 1066 } 1067 1068 sc->tx_nmaps = i; 1069} 1070 1071/* 1072 * Allocate a transmission map 1073 */ 1074static struct patm_txmap * 1075patm_txmap_get(struct patm_softc *sc) 1076{ 1077 struct patm_txmap *map; 1078 1079 if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL) { 1080 patm_txmaps_grow(sc); 1081 if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL) 1082 return (NULL); 1083 } 1084 SLIST_REMOVE_HEAD(&sc->tx_maps_free, link); 1085 return (map); 1086} 1087 1088/* 1089 * Look whether we are in the process of updating the TST on the chip. 1090 * If we are set the flag that we need another update. 1091 * If we are not start the update. 1092 */ 1093static __inline void 1094patm_tst_start(struct patm_softc *sc) 1095{ 1096 1097 if (!(sc->tst_state & TST_PENDING)) { 1098 sc->tst_state |= TST_PENDING; 1099 if (!(sc->tst_state & TST_WAIT)) { 1100 /* timer not running */ 1101 patm_tst_update(sc); 1102 } 1103 } 1104} 1105 1106/* 1107 * Allocate TST entries to a CBR connection 1108 */ 1109static void 1110patm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc) 1111{ 1112 u_int slots; 1113 u_int qptr, pptr; 1114 u_int qmax, pmax; 1115 u_int pspc, last; 1116 1117 mtx_lock(&sc->tst_lock); 1118 1119 /* compute the number of slots we need, make sure to get at least 1120 * the specified PCR */ 1121 slots = cbr2slots(sc, vcc); 1122 vcc->scd->slots = slots; 1123 sc->bwrem -= slots2cr(sc, slots); 1124 1125 patm_debug(sc, TST, "tst_alloc: cbr=%u link=%u tst=%u slots=%u", 1126 vcc->vcc.tparam.pcr, sc->ifatm.mib.pcr, sc->mmap->tst_size, slots); 1127 1128 qmax = sc->mmap->tst_size - 1; 1129 pmax = qmax << 8; 1130 1131 pspc = pmax / slots; 1132 1133 pptr = pspc >> 1; /* starting point */ 1134 qptr = pptr >> 8; 1135 1136 last = qptr; 1137 1138 while (slots > 0) { 1139 if (qptr >= qmax) 1140 qptr -= qmax; 1141 if (sc->tst_soft[qptr] != IDT_TST_VBR) { 1142 /* used - try next */ 1143 qptr++; 1144 continue; 1145 } 1146 patm_debug(sc, TST, "slot[%u] = %u.%u diff=%d", qptr, 1147 vcc->vcc.vpi, vcc->vcc.vci, (int)qptr - (int)last); 1148 last = qptr; 1149 1150 sc->tst_soft[qptr] = IDT_TST_CBR | vcc->cid | TST_BOTH; 1151 sc->tst_free--; 1152 1153 if ((pptr += pspc) >= pmax) 1154 pptr -= pmax; 1155 qptr = pptr >> 8; 1156 1157 slots--; 1158 } 1159 patm_tst_start(sc); 1160 mtx_unlock(&sc->tst_lock); 1161} 1162 1163/* 1164 * Free a CBR connection's TST entries 1165 */ 1166static void 1167patm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc) 1168{ 1169 u_int i; 1170 1171 mtx_lock(&sc->tst_lock); 1172 for (i = 0; i < sc->mmap->tst_size - 1; i++) { 1173 if ((sc->tst_soft[i] & IDT_TST_MASK) == vcc->cid) { 1174 sc->tst_soft[i] = IDT_TST_VBR | TST_BOTH; 1175 sc->tst_free++; 1176 } 1177 } 1178 sc->bwrem += slots2cr(sc, vcc->scd->slots); 1179 patm_tst_start(sc); 1180 mtx_unlock(&sc->tst_lock); 1181} 1182 1183/* 1184 * Write the soft TST into the idle incore TST and start the wait timer. 1185 * We assume that we hold the tst lock. 1186 */ 1187static void 1188patm_tst_update(struct patm_softc *sc) 1189{ 1190 u_int flag; /* flag to clear from soft TST */ 1191 u_int idle; /* the idle TST */ 1192 u_int act; /* the active TST */ 1193 u_int i; 1194 1195 if (sc->tst_state & TST_ACT1) { 1196 act = 1; 1197 idle = 0; 1198 flag = TST_CH0; 1199 } else { 1200 act = 0; 1201 idle = 1; 1202 flag = TST_CH1; 1203 } 1204 /* update the idle one */ 1205 for (i = 0; i < sc->mmap->tst_size - 1; i++) 1206 if (sc->tst_soft[i] & flag) { 1207 patm_sram_write(sc, sc->tst_base[idle] + i, 1208 sc->tst_soft[i] & ~TST_BOTH); 1209 sc->tst_soft[i] &= ~flag; 1210 } 1211 /* the used one jump to the idle one */ 1212 patm_sram_write(sc, sc->tst_jump[act], 1213 IDT_TST_BR | (sc->tst_base[idle] << 2)); 1214 1215 /* wait for the chip to jump */ 1216 sc->tst_state &= ~TST_PENDING; 1217 sc->tst_state |= TST_WAIT; 1218 1219 callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc); 1220} 1221 1222/* 1223 * Timer for TST updates 1224 */ 1225static void 1226patm_tst_timer(void *p) 1227{ 1228 struct patm_softc *sc = p; 1229 u_int act; /* active TST */ 1230 u_int now; /* current place in TST */ 1231 1232 mtx_lock(&sc->tst_lock); 1233 1234 if (sc->tst_state & TST_WAIT) { 1235 /* ignore the PENDING state while we are waiting for 1236 * the chip to switch tables. Once the switch is done, 1237 * we will again lock at PENDING */ 1238 act = (sc->tst_state & TST_ACT1) ? 1 : 0; 1239 now = patm_nor_read(sc, IDT_NOR_NOW) >> 2; 1240 if (now >= sc->tst_base[act] && now <= sc->tst_jump[act]) { 1241 /* not yet */ 1242 callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc); 1243 goto done; 1244 } 1245 sc->tst_state &= ~TST_WAIT; 1246 /* change back jump */ 1247 patm_sram_write(sc, sc->tst_jump[act], 1248 IDT_TST_BR | (sc->tst_base[act] << 2)); 1249 1250 /* switch */ 1251 sc->tst_state ^= TST_ACT1; 1252 } 1253 1254 if (sc->tst_state & TST_PENDING) 1255 /* we got another update request while the timer was running. */ 1256 patm_tst_update(sc); 1257 1258 done: 1259 mtx_unlock(&sc->tst_lock); 1260} 1261 1262static const char * 1263dump_scd(struct patm_softc *sc, struct patm_scd *scd) 1264{ 1265 u_int i; 1266 1267 for (i = 0; i < IDT_TSQE_TAG_SPACE; i++) 1268 printf("on_card[%u] = %p\n", i, scd->on_card[i]); 1269 printf("space=%u tag=%u num_on_card=%u last_tag=%u\n", 1270 scd->space, scd->tag, scd->num_on_card, scd->last_tag); 1271 1272 return (""); 1273} 1274