xref: /NextBSD/sys/dev/hatm/if_hatm_tx.c (revision b137080f19736ee33fede2e88bb54438604cf86b)
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  */
112 static struct tpd *
hatm_alloc_tpd(struct hatm_softc * sc,u_int flags)113 hatm_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 beeing 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  */
148 static void
hatm_free_tpd(struct hatm_softc * sc,struct tpd * tpd)149 hatm_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  */
168 static int
hatm_queue_tpds(struct hatm_softc * sc,u_int count,struct tpd ** list,u_int cid)169 hatm_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  */
230 struct 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  */
247 static void
hatm_load_txbuf(void * uarg,bus_dma_segment_t * segs,int nseg,bus_size_t mapsize,int error)248 hatm_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  */
352 void
hatm_start(struct ifnet * ifp)353 hatm_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 
502 void
hatm_tx_complete(struct hatm_softc * sc,struct tpd * tpd,uint32_t flags)503 hatm_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  */
540 static u_int
cps_to_rate(struct hatm_softc * sc,uint32_t cps)541 cps_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  */
562 int
hatm_tx_vcc_can_open(struct hatm_softc * sc,u_int cid,struct hevcc * vcc)563 hatm_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  */
657 void
hatm_tx_vcc_open(struct hatm_softc * sc,u_int cid)658 hatm_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  */
778 void
hatm_tx_vcc_close(struct hatm_softc * sc,u_int cid)779 hatm_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 
820 void
hatm_tx_vcc_closed(struct hatm_softc * sc,u_int cid)821 hatm_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