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