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