if_hatm_tx.c revision 116491
1/* 2 * Copyright (c) 2001-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 * Author: Hartmut Brandt <harti@freebsd.org> 28 * 29 * $FreeBSD: head/sys/dev/hatm/if_hatm_tx.c 116491 2003-06-17 16:12:50Z harti $ 30 * 31 * ForeHE driver. 32 * 33 * Transmission. 34 */ 35 36#include "opt_inet.h" 37#include "opt_natm.h" 38 39#include <sys/types.h> 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/malloc.h> 44#include <sys/bus.h> 45#include <sys/errno.h> 46#include <sys/conf.h> 47#include <sys/module.h> 48#include <sys/queue.h> 49#include <sys/syslog.h> 50#include <sys/condvar.h> 51#include <sys/sysctl.h> 52#include <vm/uma.h> 53 54#include <sys/sockio.h> 55#include <sys/mbuf.h> 56#include <sys/socket.h> 57 58#include <net/if.h> 59#include <net/if_media.h> 60#include <net/if_atm.h> 61#include <net/route.h> 62#ifdef ENABLE_BPF 63#include <net/bpf.h> 64#endif 65#include <netinet/in.h> 66#include <netinet/if_atm.h> 67 68#include <machine/bus.h> 69#include <machine/resource.h> 70#include <sys/bus.h> 71#include <sys/rman.h> 72#include <pci/pcireg.h> 73#include <pci/pcivar.h> 74 75#include <dev/utopia/utopia.h> 76#include <dev/hatm/if_hatmconf.h> 77#include <dev/hatm/if_hatmreg.h> 78#include <dev/hatm/if_hatmvar.h> 79 80/* 81 * Allocate a new TPD, zero the TPD part. Cannot return NULL if 82 * flag is 0. The TPD is removed from the free list and its used 83 * bit is set. 84 */ 85static struct tpd * 86hatm_alloc_tpd(struct hatm_softc *sc, u_int flags) 87{ 88 struct tpd *t; 89 90 /* if we allocate a transmit TPD check for the reserve */ 91 if (flags & M_NOWAIT) { 92 if (sc->tpd_nfree <= HE_CONFIG_TPD_RESERVE) 93 return (NULL); 94 } else { 95 if (sc->tpd_nfree == 0) 96 return (NULL); 97 } 98 99 /* make it beeing used */ 100 t = SLIST_FIRST(&sc->tpd_free); 101 KASSERT(t != NULL, ("tpd botch")); 102 SLIST_REMOVE_HEAD(&sc->tpd_free, link); 103 TPD_SET_USED(sc, t->no); 104 sc->tpd_nfree--; 105 106 /* initialize */ 107 t->mbuf = NULL; 108 t->cid = 0; 109 bzero(&t->tpd, sizeof(t->tpd)); 110 t->tpd.addr = t->no << HE_REGS_TPD_ADDR; 111 112 return (t); 113} 114 115/* 116 * Free a TPD. If the mbuf pointer in that TPD is not zero, it is assumed, that 117 * the DMA map of this TPD was used to load this mbuf. The map is unloaded 118 * and the mbuf is freed. The TPD is put back onto the free list and 119 * its used bit is cleared. 120 */ 121static void 122hatm_free_tpd(struct hatm_softc *sc, struct tpd *tpd) 123{ 124 if (tpd->mbuf != NULL) { 125 bus_dmamap_unload(sc->tx_tag, tpd->map); 126 m_freem(tpd->mbuf); 127 tpd->mbuf = NULL; 128 } 129 130 /* insert TPD into free list */ 131 SLIST_INSERT_HEAD(&sc->tpd_free, tpd, link); 132 TPD_CLR_USED(sc, tpd->no); 133 sc->tpd_nfree++; 134} 135 136/* 137 * Queue a number of TPD. If there is not enough space none of the TPDs 138 * is queued and an error code is returned. 139 */ 140static int 141hatm_queue_tpds(struct hatm_softc *sc, u_int count, struct tpd **list, 142 u_int cid) 143{ 144 u_int space; 145 u_int i; 146 147 if (count >= sc->tpdrq.size) { 148 sc->istats.tdprq_full++; 149 return (EBUSY); 150 } 151 152 if (sc->tpdrq.tail < sc->tpdrq.head) 153 space = sc->tpdrq.head - sc->tpdrq.tail; 154 else 155 space = sc->tpdrq.head - sc->tpdrq.tail + sc->tpdrq.size; 156 157 if (space <= count) { 158 sc->tpdrq.head = 159 (READ4(sc, HE_REGO_TPDRQ_H) >> HE_REGS_TPDRQ_H_H) & 160 (sc->tpdrq.size - 1); 161 162 if (sc->tpdrq.tail < sc->tpdrq.head) 163 space = sc->tpdrq.head - sc->tpdrq.tail; 164 else 165 space = sc->tpdrq.head - sc->tpdrq.tail + 166 sc->tpdrq.size; 167 168 if (space <= count) { 169 if_printf(&sc->ifatm.ifnet, "TPDRQ full\n"); 170 sc->istats.tdprq_full++; 171 return (EBUSY); 172 } 173 } 174 175 /* we are going to write to the TPD queue space */ 176 bus_dmamap_sync(sc->tpdrq.mem.tag, sc->tpdrq.mem.map, 177 BUS_DMASYNC_PREWRITE); 178 179 /* put the entries into the TPD space */ 180 for (i = 0; i < count; i++) { 181 /* we are going to 'write' the TPD to the device */ 182 bus_dmamap_sync(sc->tpds.tag, sc->tpds.map, 183 BUS_DMASYNC_PREWRITE); 184 185 sc->tpdrq.tpdrq[sc->tpdrq.tail].tpd = 186 sc->tpds.paddr + HE_TPD_SIZE * list[i]->no; 187 sc->tpdrq.tpdrq[sc->tpdrq.tail].cid = cid; 188 189 if (++sc->tpdrq.tail == sc->tpdrq.size) 190 sc->tpdrq.tail = 0; 191 } 192 193 /* update tail pointer */ 194 WRITE4(sc, HE_REGO_TPDRQ_T, (sc->tpdrq.tail << HE_REGS_TPDRQ_T_T)); 195 196 return (0); 197} 198 199/* 200 * Helper struct for communication with the DMA load helper. 201 */ 202struct load_txbuf_arg { 203 struct hatm_softc *sc; 204 struct tpd *first; 205 struct mbuf *mbuf; 206 struct hevcc *vcc; 207 int error; 208 u_int pti; 209 u_int vpi, vci; 210}; 211 212/* 213 * Loader callback for the mbuf. This function allocates the TPDs and 214 * fills them. It puts the dmamap and and the mbuf pointer into the last 215 * TPD and then tries to queue all the TPDs. If anything fails, all TPDs 216 * allocated by this function are freed and the error flag is set in the 217 * argument structure. The first TPD must then be freed by the caller. 218 */ 219static void 220hatm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg, 221 bus_size_t mapsize, int error) 222{ 223 struct load_txbuf_arg *arg = uarg; 224 u_int tpds_needed, i, n, tpd_cnt; 225 int need_intr; 226 struct tpd *tpd; 227 struct tpd *tpd_list[HE_CONFIG_MAX_TPD_PER_PACKET]; 228 229 if (error != 0) { 230 DBG(arg->sc, DMA, ("%s -- error=%d plen=%d\n", 231 __func__, error, arg->mbuf->m_pkthdr.len)); 232 return; 233 } 234 235 /* ensure, we have enough TPDs (remember, we already have one) */ 236 tpds_needed = (nseg + 2) / 3; 237 if (HE_CONFIG_TPD_RESERVE + tpds_needed - 1 > arg->sc->tpd_nfree) { 238 if_printf(&arg->sc->ifatm.ifnet, "%s -- out of TPDs (need %d, " 239 "have %u)\n", __func__, tpds_needed - 1, 240 arg->sc->tpd_nfree + 1); 241 arg->error = 1; 242 return; 243 } 244 245 /* 246 * Check for the maximum number of TPDs on the connection. 247 */ 248 need_intr = 0; 249 if (arg->sc->max_tpd > 0) { 250 if (arg->vcc->ntpds + tpds_needed > arg->sc->max_tpd) { 251 arg->sc->istats.flow_closed++; 252 arg->vcc->vflags |= HE_VCC_FLOW_CTRL; 253#ifdef notyet 254 atm_message(&arg->sc->ifatm.ifnet, ATM_MSG_FLOW_CONTROL, 255 (1 << 24) | (arg->vpi << 16) | arg->vci); 256#endif 257 arg->error = 1; 258 return; 259 } 260 if (arg->vcc->ntpds + tpds_needed > 261 (9 * arg->sc->max_tpd) / 10) 262 need_intr = 1; 263 } 264 265 tpd = arg->first; 266 tpd_cnt = 0; 267 tpd_list[tpd_cnt++] = tpd; 268 for (i = n = 0; i < nseg; i++, n++) { 269 if (n == 3) { 270 if ((tpd = hatm_alloc_tpd(arg->sc, M_NOWAIT)) == NULL) 271 /* may not fail (see check above) */ 272 panic("%s: out of TPDs", __func__); 273 tpd->cid = arg->first->cid; 274 tpd->tpd.addr |= arg->pti; 275 tpd_list[tpd_cnt++] = tpd; 276 n = 0; 277 } 278 KASSERT(segs[i].ds_addr <= 0xffffffffLU, 279 ("phys addr too large %lx", (u_long)segs[i].ds_addr)); 280 281 DBG(arg->sc, DMA, ("DMA loaded: %lx/%lu", 282 (u_long)segs[i].ds_addr, (u_long)segs[i].ds_len)); 283 284 tpd->tpd.bufs[n].addr = segs[i].ds_addr; 285 tpd->tpd.bufs[n].len = segs[i].ds_len; 286 287 DBG(arg->sc, TX, ("seg[%u]=tpd[%u,%u]=%x/%u", i, 288 tpd_cnt, n, tpd->tpd.bufs[n].addr, tpd->tpd.bufs[n].len)); 289 290 if (i == nseg - 1) 291 tpd->tpd.bufs[n].len |= HE_REGM_TPD_LST; 292 } 293 294 /* 295 * Swap the MAP in the first and the last TPD and set the mbuf 296 * pointer into the last TPD. We use the map in the last TPD, because 297 * the map must stay valid until the last TPD is processed by the card. 298 */ 299 if (tpd_cnt > 1) { 300 bus_dmamap_t tmp; 301 302 tmp = arg->first->map; 303 arg->first->map = tpd_list[tpd_cnt - 1]->map; 304 tpd_list[tpd_cnt - 1]->map = tmp; 305 } 306 tpd_list[tpd_cnt - 1]->mbuf = arg->mbuf; 307 308 if (need_intr) 309 tpd_list[tpd_cnt - 1]->tpd.addr |= HE_REGM_TPD_INTR; 310 311 /* queue the TPDs */ 312 if (hatm_queue_tpds(arg->sc, tpd_cnt, tpd_list, arg->first->cid)) { 313 /* free all, except the first TPD */ 314 for (i = 1; i < tpd_cnt; i++) 315 hatm_free_tpd(arg->sc, tpd_list[i]); 316 arg->error = 1; 317 return; 318 } 319 arg->vcc->ntpds += tpd_cnt; 320} 321 322 323/* 324 * Start output on the interface 325 * 326 * For raw aal we process only the first cell in the mbuf chain! XXX 327 */ 328void 329hatm_start(struct ifnet *ifp) 330{ 331 struct hatm_softc *sc = (struct hatm_softc *)ifp->if_softc; 332 struct mbuf *m; 333 struct atm_pseudohdr *aph; 334 u_int cid; 335 struct tpd *tpd; 336 struct load_txbuf_arg arg; 337 u_int len; 338 int error; 339 340 if (!(ifp->if_flags & IFF_RUNNING)) 341 return; 342 mtx_lock(&sc->mtx); 343 arg.sc = sc; 344 345 while (1) { 346 IF_DEQUEUE(&ifp->if_snd, m); 347 if (m == NULL) 348 break; 349 350 if (m->m_len < sizeof(*aph)) 351 if ((m = m_pullup(m, sizeof(*aph))) == NULL) 352 continue; 353 354 aph = mtod(m, struct atm_pseudohdr *); 355 arg.vci = ATM_PH_VCI(aph); 356 arg.vpi = ATM_PH_VPI(aph); 357 m_adj(m, sizeof(*aph)); 358 359 if ((len = m->m_pkthdr.len) == 0) { 360 m_freem(m); 361 continue; 362 } 363 364 if ((arg.vpi & ~HE_VPI_MASK) || (arg.vci & ~HE_VCI_MASK) || 365 (arg.vci == 0)) { 366 m_freem(m); 367 continue; 368 } 369 cid = HE_CID(arg.vpi, arg.vci); 370 arg.vcc = sc->vccs[cid]; 371 372 if (arg.vcc == NULL || !(arg.vcc->vflags & HE_VCC_OPEN)) { 373 m_freem(m); 374 continue; 375 } 376 if (arg.vcc->vflags & HE_VCC_FLOW_CTRL) { 377 m_freem(m); 378 sc->istats.flow_drop++; 379 continue; 380 } 381 382 arg.pti = 0; 383 if (arg.vcc->param.aal == ATMIO_AAL_RAW) { 384 if (len < 52) { 385 m_freem(m); 386 continue; 387 } 388 if (len > 52) { 389 m_adj(m, -((int)(len - 52))); 390 len = 52; 391 } 392 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) 393 continue; 394 395 /* ignore header except payload type and CLP */ 396 arg.pti = mtod(m, u_char *)[3] & 0xf; 397 arg.pti = ((arg.pti & 0xe) << 2) | ((arg.pti & 1) << 1); 398 m_adj(m, 4); 399 len -= 4; 400 } 401 402#ifdef ENABLE_BPF 403 if (!(arg.vcc->param.flags & ATMIO_FLAG_NG) && 404 (arg.vcc->param.flags & ATM_PH_AAL5) && 405 (arg.vcc->param.flags & ATM_PH_LLCSNAP)) 406 BPF_MTAP(ifp, m); 407#endif 408 409 /* Now load a DMA map with the packet. Allocate the first 410 * TPD to get a map. Additional TPDs may be allocated by the 411 * callback. */ 412 if ((tpd = hatm_alloc_tpd(sc, M_NOWAIT)) == NULL) { 413 m_freem(m); 414 sc->ifatm.ifnet.if_oerrors++; 415 continue; 416 } 417 tpd->cid = cid; 418 tpd->tpd.addr |= arg.pti; 419 arg.first = tpd; 420 arg.error = 0; 421 arg.mbuf = m; 422 423 error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m, 424 hatm_load_txbuf, &arg, 0); 425 426 if (error == EFBIG) { 427 /* try to defragment the packet */ 428 sc->istats.defrag++; 429 m = m_defrag(m, M_DONTWAIT); 430 if (m == NULL) { 431 sc->ifatm.ifnet.if_oerrors++; 432 continue; 433 } 434 arg.mbuf = m; 435 error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m, 436 hatm_load_txbuf, &arg, 0); 437 } 438 439 if (error != 0) { 440 if_printf(&sc->ifatm.ifnet, "mbuf loaded error=%d\n", 441 error); 442 hatm_free_tpd(sc, tpd); 443 sc->ifatm.ifnet.if_oerrors++; 444 continue; 445 } 446 if (arg.error) { 447 hatm_free_tpd(sc, tpd); 448 sc->ifatm.ifnet.if_oerrors++; 449 continue; 450 } 451 arg.vcc->opackets++; 452 arg.vcc->obytes += len; 453 sc->ifatm.ifnet.if_opackets++; 454 } 455 mtx_unlock(&sc->mtx); 456} 457 458void 459hatm_tx_complete(struct hatm_softc *sc, struct tpd *tpd, uint32_t flags) 460{ 461 struct hevcc *vcc = sc->vccs[tpd->cid]; 462 463 DBG(sc, TX, ("tx_complete cid=%#x flags=%#x", tpd->cid, flags)); 464 465 if (vcc == NULL) 466 return; 467 if ((flags & HE_REGM_TBRQ_EOS) && (vcc->vflags & HE_VCC_TX_CLOSING)) { 468 vcc->vflags &= ~HE_VCC_TX_CLOSING; 469 if (vcc->vflags & HE_VCC_ASYNC) { 470 hatm_tx_vcc_closed(sc, tpd->cid); 471 if (!(vcc->vflags & HE_VCC_OPEN)) { 472 hatm_vcc_closed(sc, tpd->cid); 473 vcc = NULL; 474 } 475 } else 476 cv_signal(&sc->vcc_cv); 477 } 478 hatm_free_tpd(sc, tpd); 479 480 if (vcc == NULL) 481 return; 482 483 vcc->ntpds--; 484 485 if ((vcc->vflags & HE_VCC_FLOW_CTRL) && 486 vcc->ntpds <= HE_CONFIG_TPD_FLOW_ENB) { 487 vcc->vflags &= ~HE_VCC_FLOW_CTRL; 488#ifdef notyet 489 atm_message(&sc->ifatm.ifnet, ATM_MSG_FLOW_CONTROL, 490 (0 << 24) | (HE_VPI(tpd->cid) << 16) | HE_VCI(tpd->cid)); 491#endif 492 } 493} 494 495/* 496 * Convert CPS to Rate for a rate group 497 */ 498static u_int 499cps_to_rate(struct hatm_softc *sc, uint32_t cps) 500{ 501 u_int clk = sc->he622 ? HE_622_CLOCK : HE_155_CLOCK; 502 u_int period, rate; 503 504 /* how many double ticks between two cells */ 505 period = (clk + 2 * cps - 1) / (2 * cps); 506 rate = hatm_cps2atmf(period); 507 if (hatm_atmf2cps(rate) < period) 508 rate++; 509 510 return (rate); 511} 512 513/* 514 * Check whether the VCC is really closed on the hardware and available for 515 * open. Check that we have enough resources. If this function returns ok, 516 * a later actual open must succeed. Assume, that we are locked between this 517 * function and the next one, so that nothing does change. For CBR this 518 * assigns the rate group and set the rate group's parameter. 519 */ 520int 521hatm_tx_vcc_can_open(struct hatm_softc *sc, u_int cid, struct hevcc *vcc) 522{ 523 uint32_t v, line_rate; 524 u_int rc, idx, free_idx; 525 struct atmio_tparam *t = &vcc->param.tparam; 526 527 /* verify that connection is closed */ 528#if 0 529 v = READ_TSR(sc, cid, 4); 530 if(!(v & HE_REGM_TSR4_SESS_END)) { 531 if_printf(&sc->ifatm.ifnet, "cid=%#x not closed (TSR4)\n", cid); 532 return (EBUSY); 533 } 534#endif 535 v = READ_TSR(sc, cid, 0); 536 if((v & HE_REGM_TSR0_CONN_STATE) != 0) { 537 if_printf(&sc->ifatm.ifnet, "cid=%#x not closed (TSR0=%#x)\n", 538 cid, v); 539 return (EBUSY); 540 } 541 542 /* check traffic parameters */ 543 line_rate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M; 544 switch (vcc->param.traffic) { 545 546 case ATMIO_TRAFFIC_UBR: 547 if (t->pcr == 0 || t->pcr > line_rate) 548 t->pcr = line_rate; 549 if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 || 550 t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 || 551 t->cdf != 0) 552 return (EINVAL); 553 break; 554 555 case ATMIO_TRAFFIC_CBR: 556 /* 557 * Compute rate group index 558 */ 559 if (t->pcr < 10) 560 t->pcr = 10; 561 if (sc->cbr_bw + t->pcr > line_rate) 562 return (EINVAL); 563 if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 || 564 t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 || 565 t->cdf != 0) 566 return (EINVAL); 567 568 rc = cps_to_rate(sc, t->pcr); 569 free_idx = HE_REGN_CS_STPER; 570 for (idx = 0; idx < HE_REGN_CS_STPER; idx++) { 571 if (sc->rate_ctrl[idx].refcnt == 0) { 572 if (free_idx == HE_REGN_CS_STPER) 573 free_idx = idx; 574 } else { 575 if (sc->rate_ctrl[idx].rate == rc) 576 break; 577 } 578 } 579 if (idx == HE_REGN_CS_STPER) { 580 if ((idx = free_idx) == HE_REGN_CS_STPER) 581 return (EBUSY); 582 sc->rate_ctrl[idx].rate = rc; 583 WRITE_MBOX4(sc, HE_REGO_CS_STPER(idx), rc); 584 } 585 vcc->rc = idx; 586 break; 587 588 case ATMIO_TRAFFIC_ABR: 589 if (t->pcr > line_rate) 590 t->pcr = line_rate; 591 if (t->mcr > line_rate) 592 t->mcr = line_rate; 593 if (t->icr > line_rate) 594 t->icr = line_rate; 595 if (t->tbe == 0 || t->tbe >= 1 << 24 || t->nrm > 7 || 596 t->trm > 7 || t->adtf >= 1 << 10 || t->rif > 15 || 597 t->rdf > 15 || t->cdf > 7) 598 return (EINVAL); 599 break; 600 601 default: 602 return (EINVAL); 603 } 604 return (0); 605} 606 607#define NRM_CODE2VAL(CODE) (2 * (1 << (CODE))) 608 609/* 610 * Actually open the transmit VCC 611 */ 612void 613hatm_tx_vcc_open(struct hatm_softc *sc, u_int cid) 614{ 615 struct hevcc *vcc = sc->vccs[cid]; 616 uint32_t tsr0, tsr4, atmf, crm; 617 const struct atmio_tparam *t = &vcc->param.tparam; 618 619 if (vcc->param.aal == ATMIO_AAL_5) { 620 tsr0 = HE_REGM_TSR0_AAL_5 << HE_REGS_TSR0_AAL; 621 tsr4 = HE_REGM_TSR4_AAL_5 << HE_REGS_TSR4_AAL; 622 } else { 623 tsr0 = HE_REGM_TSR0_AAL_0 << HE_REGS_TSR0_AAL; 624 tsr4 = HE_REGM_TSR4_AAL_0 << HE_REGS_TSR4_AAL; 625 } 626 tsr4 |= 1; 627 628 switch (vcc->param.traffic) { 629 630 case ATMIO_TRAFFIC_UBR: 631 atmf = hatm_cps2atmf(t->pcr); 632 633 tsr0 |= HE_REGM_TSR0_TRAFFIC_UBR << HE_REGS_TSR0_TRAFFIC; 634 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER; 635 636 WRITE_TSR(sc, cid, 0, 0xf, tsr0); 637 WRITE_TSR(sc, cid, 4, 0xf, tsr4); 638 WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR)); 639 WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR)); 640 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT); 641 WRITE_TSR(sc, cid, 3, 0xf, 0); 642 WRITE_TSR(sc, cid, 5, 0xf, 0); 643 WRITE_TSR(sc, cid, 6, 0xf, 0); 644 WRITE_TSR(sc, cid, 7, 0xf, 0); 645 WRITE_TSR(sc, cid, 8, 0xf, 0); 646 WRITE_TSR(sc, cid, 10, 0xf, 0); 647 WRITE_TSR(sc, cid, 11, 0xf, 0); 648 WRITE_TSR(sc, cid, 12, 0xf, 0); 649 WRITE_TSR(sc, cid, 13, 0xf, 0); 650 WRITE_TSR(sc, cid, 14, 0xf, 0); 651 break; 652 653 case ATMIO_TRAFFIC_CBR: 654 atmf = hatm_cps2atmf(t->pcr); 655 sc->rate_ctrl[vcc->rc].refcnt++; 656 657 tsr0 |= HE_REGM_TSR0_TRAFFIC_CBR << HE_REGS_TSR0_TRAFFIC; 658 tsr0 |= vcc->rc; 659 660 WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR)); 661 WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR)); 662 WRITE_TSR(sc, cid, 3, 0xf, 0); 663 WRITE_TSR(sc, cid, 5, 0xf, 0); 664 WRITE_TSR(sc, cid, 6, 0xf, 0); 665 WRITE_TSR(sc, cid, 7, 0xf, 0); 666 WRITE_TSR(sc, cid, 8, 0xf, 0); 667 WRITE_TSR(sc, cid, 10, 0xf, 0); 668 WRITE_TSR(sc, cid, 11, 0xf, 0); 669 WRITE_TSR(sc, cid, 12, 0xf, 0); 670 WRITE_TSR(sc, cid, 13, 0xf, 0); 671 WRITE_TSR(sc, cid, 14, 0xf, 0); 672 WRITE_TSR(sc, cid, 4, 0xf, tsr4); 673 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT); 674 WRITE_TSR(sc, cid, 0, 0xf, tsr0); 675 676 sc->cbr_bw += t->pcr; 677 break; 678 679 case ATMIO_TRAFFIC_ABR: 680 if ((crm = t->tbe / NRM_CODE2VAL(t->nrm)) > 0xffff) 681 crm = 0xffff; 682 683 tsr0 |= HE_REGM_TSR0_TRAFFIC_ABR << HE_REGS_TSR0_TRAFFIC; 684 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER; 685 686 WRITE_TSR(sc, cid, 0, 0xf, tsr0); 687 WRITE_TSR(sc, cid, 4, 0xf, tsr4); 688 689 WRITE_TSR(sc, cid, 1, 0xf, 690 ((hatm_cps2atmf(t->pcr) << HE_REGS_TSR1_PCR) | 691 (hatm_cps2atmf(t->mcr) << HE_REGS_TSR1_MCR))); 692 WRITE_TSR(sc, cid, 2, 0xf, 693 (hatm_cps2atmf(t->icr) << HE_REGS_TSR2_ACR)); 694 WRITE_TSR(sc, cid, 3, 0xf, 695 ((NRM_CODE2VAL(t->nrm) - 1) << HE_REGS_TSR3_NRM) | 696 (crm << HE_REGS_TSR3_CRM)); 697 698 WRITE_TSR(sc, cid, 5, 0xf, 0); 699 WRITE_TSR(sc, cid, 6, 0xf, 0); 700 WRITE_TSR(sc, cid, 7, 0xf, 0); 701 WRITE_TSR(sc, cid, 8, 0xf, 0); 702 WRITE_TSR(sc, cid, 10, 0xf, 0); 703 WRITE_TSR(sc, cid, 12, 0xf, 0); 704 WRITE_TSR(sc, cid, 14, 0xf, 0); 705 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT); 706 707 WRITE_TSR(sc, cid, 11, 0xf, 708 (hatm_cps2atmf(t->icr) << HE_REGS_TSR11_ICR) | 709 (t->trm << HE_REGS_TSR11_TRM) | 710 (t->nrm << HE_REGS_TSR11_NRM) | 711 (t->adtf << HE_REGS_TSR11_ADTF)); 712 713 WRITE_TSR(sc, cid, 13, 0xf, 714 (t->rdf << HE_REGS_TSR13_RDF) | 715 (t->rif << HE_REGS_TSR13_RIF) | 716 (t->cdf << HE_REGS_TSR13_CDF) | 717 (crm << HE_REGS_TSR13_CRM)); 718 719 break; 720 721 default: 722 return; 723 } 724 725 vcc->vflags |= HE_VCC_TX_OPEN; 726} 727 728/* 729 * Close the TX side of a VCC. Set the CLOSING flag. 730 */ 731void 732hatm_tx_vcc_close(struct hatm_softc *sc, u_int cid) 733{ 734 struct hevcc *vcc = sc->vccs[cid]; 735 struct tpd *tpd_list[1]; 736 u_int i, pcr = 0; 737 738 WRITE_TSR(sc, cid, 4, 0x8, HE_REGM_TSR4_FLUSH); 739 740 switch (vcc->param.traffic) { 741 742 case ATMIO_TRAFFIC_CBR: 743 WRITE_TSR(sc, cid, 14, 0x8, HE_REGM_TSR14_CBR_DELETE); 744 break; 745 746 case ATMIO_TRAFFIC_ABR: 747 WRITE_TSR(sc, cid, 14, 0x4, HE_REGM_TSR14_ABR_CLOSE); 748 pcr = vcc->param.tparam.pcr; 749 /* FALL THROUGH */ 750 751 case ATMIO_TRAFFIC_UBR: 752 WRITE_TSR(sc, cid, 1, 0xf, 753 hatm_cps2atmf(HE_CONFIG_FLUSH_RATE) << HE_REGS_TSR1_MCR | 754 hatm_cps2atmf(pcr) << HE_REGS_TSR1_PCR); 755 break; 756 } 757 758 tpd_list[0] = hatm_alloc_tpd(sc, 0); 759 tpd_list[0]->tpd.addr |= HE_REGM_TPD_EOS | HE_REGM_TPD_INTR; 760 tpd_list[0]->cid = cid; 761 762 vcc->vflags |= HE_VCC_TX_CLOSING; 763 vcc->vflags &= ~HE_VCC_TX_OPEN; 764 765 i = 0; 766 while (hatm_queue_tpds(sc, 1, tpd_list, cid) != 0) { 767 if (++i == 1000) 768 panic("TPDRQ permanently full"); 769 DELAY(1000); 770 } 771} 772 773void 774hatm_tx_vcc_closed(struct hatm_softc *sc, u_int cid) 775{ 776 if (sc->vccs[cid]->param.traffic == ATMIO_TRAFFIC_CBR) { 777 sc->cbr_bw -= sc->vccs[cid]->param.tparam.pcr; 778 sc->rate_ctrl[sc->vccs[cid]->rc].refcnt--; 779 } 780} 781