if_hatm_tx.c revision 243857
1312003Scem/*-
2312003Scem * Copyright (c) 2001-2003
3312003Scem *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4312003Scem * 	All rights reserved.
5312003Scem *
6312003Scem * Redistribution and use in source and binary forms, with or without
7312003Scem * modification, are permitted provided that the following conditions
8312003Scem * are met:
9312003Scem * 1. Redistributions of source code must retain the above copyright
10312003Scem *    notice, this list of conditions and the following disclaimer.
11312003Scem * 2. Redistributions in binary form must reproduce the above copyright
12312003Scem *    notice, this list of conditions and the following disclaimer in the
13312003Scem *    documentation and/or other materials provided with the distribution.
14312003Scem *
15312003Scem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16312003Scem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17312003Scem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18312003Scem * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19312003Scem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20312003Scem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21312003Scem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22312003Scem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23312003Scem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24312003Scem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25312003Scem * SUCH DAMAGE.
26312003Scem *
27312003Scem * Author: Hartmut Brandt <harti@freebsd.org>
28312003Scem *
29312003Scem * ForeHE driver.
30312003Scem *
31312003Scem * Transmission.
32312003Scem */
33312003Scem
34312003Scem#include <sys/cdefs.h>
35312003Scem__FBSDID("$FreeBSD: head/sys/dev/hatm/if_hatm_tx.c 243857 2012-12-04 09:32:43Z glebius $");
36312003Scem
37312003Scem#include "opt_inet.h"
38312003Scem#include "opt_natm.h"
39312003Scem
40312003Scem#include <sys/types.h>
41312003Scem#include <sys/param.h>
42312003Scem#include <sys/systm.h>
43312003Scem#include <sys/kernel.h>
44312003Scem#include <sys/malloc.h>
45312003Scem#include <sys/bus.h>
46312003Scem#include <sys/errno.h>
47312003Scem#include <sys/conf.h>
48312003Scem#include <sys/module.h>
49312003Scem#include <sys/queue.h>
50312003Scem#include <sys/syslog.h>
51312003Scem#include <sys/condvar.h>
52312003Scem#include <sys/sysctl.h>
53312003Scem#include <vm/uma.h>
54312003Scem
55312003Scem#include <sys/sockio.h>
56312003Scem#include <sys/mbuf.h>
57312003Scem#include <sys/socket.h>
58312003Scem
59312003Scem#include <net/if.h>
60312003Scem#include <net/if_media.h>
61312003Scem#include <net/if_atm.h>
62312003Scem#include <net/route.h>
63312003Scem#ifdef ENABLE_BPF
64312003Scem#include <net/bpf.h>
65312003Scem#endif
66312003Scem#include <netinet/in.h>
67312003Scem#include <netinet/if_atm.h>
68312003Scem
69312003Scem#include <machine/bus.h>
70312003Scem#include <machine/resource.h>
71312003Scem#include <sys/bus.h>
72312003Scem#include <sys/rman.h>
73312003Scem#include <dev/pci/pcireg.h>
74312003Scem#include <dev/pci/pcivar.h>
75312003Scem
76312003Scem#include <dev/utopia/utopia.h>
77312003Scem#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_NOWAIT);
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