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