2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * Author: Hartmut Brandt <harti@freebsd.org>
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
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>
46 #include <sys/errno.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>
55 #include <sys/sockio.h>
57 #include <sys/socket.h>
60 #include <net/if_var.h>
61 #include <net/if_media.h>
62 #include <net/if_atm.h>
63 #include <net/route.h>
67 #include <netinet/in.h>
68 #include <netinet/if_atm.h>
70 #include <machine/bus.h>
71 #include <machine/resource.h>
74 #include <dev/pci/pcireg.h>
75 #include <dev/pci/pcivar.h>
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>
84 * These macros are used to trace the flow of transmit mbufs and to
85 * detect transmit mbuf leaks in the driver.
88 #define hatm_free_txmbuf(SC) \
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")); \
95 #define hatm_get_txmbuf(SC) \
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")); \
103 #define hatm_free_txmbuf(SC) do { } while (0)
104 #define hatm_get_txmbuf(SC) do { } while (0)
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
113 hatm_alloc_tpd(struct hatm_softc *sc, u_int flags)
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)
122 if (sc->tpd_nfree == 0)
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);
136 bzero(&t->tpd, sizeof(t->tpd));
137 t->tpd.addr = t->no << HE_REGS_TPD_ADDR;
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.
149 hatm_free_tpd(struct hatm_softc *sc, struct tpd *tpd)
151 if (tpd->mbuf != NULL) {
152 bus_dmamap_unload(sc->tx_tag, tpd->map);
153 hatm_free_txmbuf(sc);
158 /* insert TPD into free list */
159 SLIST_INSERT_HEAD(&sc->tpd_free, tpd, link);
160 TPD_CLR_USED(sc, tpd->no);
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.
169 hatm_queue_tpds(struct hatm_softc *sc, u_int count, struct tpd **list,
175 if (count >= sc->tpdrq.size) {
176 sc->istats.tdprq_full++;
180 if (sc->tpdrq.tail < sc->tpdrq.head)
181 space = sc->tpdrq.head - sc->tpdrq.tail;
183 space = sc->tpdrq.head - sc->tpdrq.tail + sc->tpdrq.size;
185 if (space <= count) {
187 (READ4(sc, HE_REGO_TPDRQ_H) >> HE_REGS_TPDRQ_H_H) &
188 (sc->tpdrq.size - 1);
190 if (sc->tpdrq.tail < sc->tpdrq.head)
191 space = sc->tpdrq.head - sc->tpdrq.tail;
193 space = sc->tpdrq.head - sc->tpdrq.tail +
196 if (space <= count) {
197 if_printf(sc->ifp, "TPDRQ full\n");
198 sc->istats.tdprq_full++;
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);
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);
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;
217 if (++sc->tpdrq.tail == sc->tpdrq.size)
221 /* update tail pointer */
222 WRITE4(sc, HE_REGO_TPDRQ_T, (sc->tpdrq.tail << HE_REGS_TPDRQ_T_T));
228 * Helper struct for communication with the DMA load helper.
230 struct load_txbuf_arg {
231 struct hatm_softc *sc;
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.
248 hatm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg,
249 bus_size_t mapsize, int error)
251 struct load_txbuf_arg *arg = uarg;
252 u_int tpds_needed, i, n, tpd_cnt;
255 struct tpd *tpd_list[HE_CONFIG_MAX_TPD_PER_PACKET];
258 DBG(arg->sc, DMA, ("%s -- error=%d plen=%d\n",
259 __func__, error, arg->mbuf->m_pkthdr.len));
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);
274 * Check for the maximum number of TPDs on the connection.
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);
286 if (arg->vcc->ntpds + tpds_needed >
287 (9 * arg->sc->max_tpd) / 10)
293 tpd_list[tpd_cnt++] = tpd;
294 for (i = n = 0; i < nseg; i++, n++) {
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;
304 KASSERT(segs[i].ds_addr <= 0xffffffffLU,
305 ("phys addr too large %lx", (u_long)segs[i].ds_addr));
307 DBG(arg->sc, DMA, ("DMA loaded: %lx/%lu",
308 (u_long)segs[i].ds_addr, (u_long)segs[i].ds_len));
310 tpd->tpd.bufs[n].addr = segs[i].ds_addr;
311 tpd->tpd.bufs[n].len = segs[i].ds_len;
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));
317 tpd->tpd.bufs[n].len |= HE_REGM_TPD_LST;
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.
328 tmp = arg->first->map;
329 arg->first->map = tpd_list[tpd_cnt - 1]->map;
330 tpd_list[tpd_cnt - 1]->map = tmp;
332 tpd_list[tpd_cnt - 1]->mbuf = arg->mbuf;
335 tpd_list[tpd_cnt - 1]->tpd.addr |= HE_REGM_TPD_INTR;
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]);
345 arg->vcc->ntpds += tpd_cnt;
350 * Start output on the interface
353 hatm_start(struct ifnet *ifp)
355 struct hatm_softc *sc = ifp->if_softc;
357 struct atm_pseudohdr *aph;
360 struct load_txbuf_arg arg;
364 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
370 IF_DEQUEUE(&ifp->if_snd, m);
376 if (m->m_len < sizeof(*aph))
377 if ((m = m_pullup(m, sizeof(*aph))) == NULL) {
378 hatm_free_txmbuf(sc);
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));
387 if ((len = m->m_pkthdr.len) == 0) {
388 hatm_free_txmbuf(sc);
393 if ((arg.vpi & ~HE_VPI_MASK) || (arg.vci & ~HE_VCI_MASK) ||
395 hatm_free_txmbuf(sc);
399 cid = HE_CID(arg.vpi, arg.vci);
400 arg.vcc = sc->vccs[cid];
402 if (arg.vcc == NULL || !(arg.vcc->vflags & HE_VCC_OPEN)) {
403 hatm_free_txmbuf(sc);
407 if (arg.vcc->vflags & HE_VCC_FLOW_CTRL) {
408 hatm_free_txmbuf(sc);
410 sc->istats.flow_drop++;
415 if (arg.vcc->param.aal == ATMIO_AAL_RAW) {
418 hatm_free_txmbuf(sc);
424 * Get the header and ignore except
425 * payload type and CLP.
427 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) {
428 hatm_free_txmbuf(sc);
431 arg.pti = mtod(m, u_char *)[3] & 0xf;
432 arg.pti = ((arg.pti & 0xe) << 2) | ((arg.pti & 1) << 1);
437 m_adj(m, -((int)(len % 48)));
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))
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
452 if ((tpd = hatm_alloc_tpd(sc, M_NOWAIT)) == NULL) {
453 hatm_free_txmbuf(sc);
455 if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
459 tpd->tpd.addr |= arg.pti;
464 error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m,
465 hatm_load_txbuf, &arg, BUS_DMA_NOWAIT);
467 if (error == EFBIG) {
468 /* try to defragment the packet */
470 m = m_defrag(m, M_NOWAIT);
473 hatm_free_txmbuf(sc);
474 hatm_free_tpd(sc, tpd);
475 if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
479 error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m,
480 hatm_load_txbuf, &arg, BUS_DMA_NOWAIT);
484 if_printf(sc->ifp, "mbuf loaded error=%d\n",
486 hatm_free_tpd(sc, tpd);
487 if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
491 hatm_free_tpd(sc, tpd);
492 if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
496 arg.vcc->obytes += len;
497 if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
499 mtx_unlock(&sc->mtx);
503 hatm_tx_complete(struct hatm_softc *sc, struct tpd *tpd, uint32_t flags)
505 struct hevcc *vcc = sc->vccs[tpd->cid];
507 DBG(sc, TX, ("tx_complete cid=%#x flags=%#x", tpd->cid, flags));
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);
520 cv_signal(&sc->vcc_cv);
522 hatm_free_tpd(sc, tpd);
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);
538 * Convert CPS to Rate for a rate group
541 cps_to_rate(struct hatm_softc *sc, uint32_t cps)
543 u_int clk = sc->he622 ? HE_622_CLOCK : HE_155_CLOCK;
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)
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.
563 hatm_tx_vcc_can_open(struct hatm_softc *sc, u_int cid, struct hevcc *vcc)
565 uint32_t v, line_rate;
566 u_int rc, idx, free_idx;
567 struct atmio_tparam *t = &vcc->param.tparam;
569 /* verify that connection is closed */
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);
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",
584 /* check traffic parameters */
585 line_rate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M;
586 switch (vcc->param.traffic) {
588 case ATMIO_TRAFFIC_UBR:
589 if (t->pcr == 0 || 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 ||
597 case ATMIO_TRAFFIC_CBR:
599 * Compute rate group index
603 if (sc->cbr_bw + t->pcr > line_rate)
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 ||
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)
617 if (sc->rate_ctrl[idx].rate == rc)
621 if (idx == HE_REGN_CS_STPER) {
622 if ((idx = free_idx) == HE_REGN_CS_STPER)
624 sc->rate_ctrl[idx].rate = rc;
629 sc->rate_ctrl[idx].refcnt++;
630 sc->cbr_bw += t->pcr;
633 case ATMIO_TRAFFIC_ABR:
634 if (t->pcr > line_rate)
636 if (t->mcr > line_rate)
638 if (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)
652 #define NRM_CODE2VAL(CODE) (2 * (1 << (CODE)))
655 * Actually open the transmit VCC
658 hatm_tx_vcc_open(struct hatm_softc *sc, u_int cid)
660 struct hevcc *vcc = sc->vccs[cid];
661 uint32_t tsr0, tsr4, atmf, crm;
662 const struct atmio_tparam *t = &vcc->param.tparam;
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;
668 tsr0 = HE_REGM_TSR0_AAL_0 << HE_REGS_TSR0_AAL;
669 tsr4 = HE_REGM_TSR4_AAL_0 << HE_REGS_TSR4_AAL;
673 switch (vcc->param.traffic) {
675 case ATMIO_TRAFFIC_UBR:
676 atmf = hatm_cps2atmf(t->pcr);
678 tsr0 |= HE_REGM_TSR0_TRAFFIC_UBR << HE_REGS_TSR0_TRAFFIC;
679 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER;
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);
698 case ATMIO_TRAFFIC_CBR:
699 atmf = hatm_cps2atmf(t->pcr);
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);
705 tsr0 |= HE_REGM_TSR0_TRAFFIC_CBR << HE_REGS_TSR0_TRAFFIC;
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);
726 case ATMIO_TRAFFIC_ABR:
727 if ((crm = t->tbe / NRM_CODE2VAL(t->nrm)) > 0xffff)
730 tsr0 |= HE_REGM_TSR0_TRAFFIC_ABR << HE_REGS_TSR0_TRAFFIC;
731 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER;
733 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
734 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
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));
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);
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));
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));
772 vcc->vflags |= HE_VCC_TX_OPEN;
776 * Close the TX side of a VCC. Set the CLOSING flag.
779 hatm_tx_vcc_close(struct hatm_softc *sc, u_int cid)
781 struct hevcc *vcc = sc->vccs[cid];
782 struct tpd *tpd_list[1];
785 WRITE_TSR(sc, cid, 4, 0x8, HE_REGM_TSR4_FLUSH);
787 switch (vcc->param.traffic) {
789 case ATMIO_TRAFFIC_CBR:
790 WRITE_TSR(sc, cid, 14, 0x8, HE_REGM_TSR14_CBR_DELETE);
793 case ATMIO_TRAFFIC_ABR:
794 WRITE_TSR(sc, cid, 14, 0x4, HE_REGM_TSR14_ABR_CLOSE);
795 pcr = vcc->param.tparam.pcr;
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);
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;
809 vcc->vflags |= HE_VCC_TX_CLOSING;
810 vcc->vflags &= ~HE_VCC_TX_OPEN;
813 while (hatm_queue_tpds(sc, 1, tpd_list, cid) != 0) {
815 panic("TPDRQ permanently full");
821 hatm_tx_vcc_closed(struct hatm_softc *sc, u_int cid)
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--;