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