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