if_patm_tx.c revision 119418
1/*
2 * Copyright (c) 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 * The TST allocation algorithm is from the IDT driver which is:
28 *
29 *	Copyright (c) 2000, 2001 Richard Hodges and Matriplex, inc.
30 *	All rights reserved.
31 *
32 *	Copyright (c) 1996, 1997, 1998, 1999 Mark Tinguely
33 *	All rights reserved.
34 *
35 * Author: Hartmut Brandt <harti@freebsd.org>
36 *
37 * Driver for IDT77252 based cards like ProSum's.
38 */
39
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD: head/sys/dev/patm/if_patm_tx.c 119418 2003-08-24 17:55:58Z obrien $");
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/sys/dev/patm/if_patm_tx.c 119418 2003-08-24 17:55:58Z obrien $");
44
45#include "opt_inet.h"
46#include "opt_natm.h"
47
48#include <sys/types.h>
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/malloc.h>
52#include <sys/kernel.h>
53#include <sys/bus.h>
54#include <sys/errno.h>
55#include <sys/conf.h>
56#include <sys/module.h>
57#include <sys/lock.h>
58#include <sys/mutex.h>
59#include <sys/sysctl.h>
60#include <sys/queue.h>
61#include <sys/condvar.h>
62#include <sys/endian.h>
63#include <vm/uma.h>
64
65#include <sys/sockio.h>
66#include <sys/mbuf.h>
67#include <sys/socket.h>
68
69#include <net/if.h>
70#include <net/if_media.h>
71#include <net/if_atm.h>
72#include <net/route.h>
73#ifdef ENABLE_BPF
74#include <net/bpf.h>
75#endif
76#include <netinet/in.h>
77#include <netinet/if_atm.h>
78
79#include <machine/bus.h>
80#include <machine/resource.h>
81#include <sys/bus.h>
82#include <sys/rman.h>
83#include <sys/mbpool.h>
84
85#include <dev/utopia/utopia.h>
86#include <dev/patm/idt77252reg.h>
87#include <dev/patm/if_patmvar.h>
88
89static struct mbuf *patm_tx_pad(struct patm_softc *sc, struct mbuf *m0);
90static void patm_launch(struct patm_softc *sc, struct patm_scd *scd);
91
92static struct patm_txmap *patm_txmap_get(struct patm_softc *);
93static void patm_load_txbuf(void *, bus_dma_segment_t *, int,
94    bus_size_t, int);
95
96static void patm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc);
97static void patm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc);
98static void patm_tst_timer(void *p);
99static void patm_tst_update(struct patm_softc *);
100
101static void patm_tct_start(struct patm_softc *sc, struct patm_vcc *);
102
103static const char *dump_scd(struct patm_softc *sc, struct patm_scd *scd)
104    __unused;
105static void patm_tct_print(struct patm_softc *sc, u_int cid) __unused;
106
107/*
108 * Structure for communication with the loader function for transmission
109 */
110struct txarg {
111	struct patm_softc *sc;
112	struct patm_scd	*scd;		/* scheduling channel */
113	struct patm_vcc	*vcc;		/* the VCC of this PDU */
114	struct mbuf	*mbuf;
115	u_int		hdr;		/* cell header */
116};
117
118static __inline u_int
119cbr2slots(struct patm_softc *sc, struct patm_vcc *vcc)
120{
121	/* compute the number of slots we need, make sure to get at least
122	 * the specified PCR */
123	return ((u_int)(((uint64_t)(sc->mmap->tst_size - 1) *
124	    vcc->vcc.tparam.pcr + sc->ifatm.mib.pcr - 1) / sc->ifatm.mib.pcr));
125}
126
127static __inline u_int
128slots2cr(struct patm_softc *sc, u_int slots)
129{
130	return ((slots * sc->ifatm.mib.pcr + sc->mmap->tst_size - 2) /
131	    (sc->mmap->tst_size - 1));
132}
133
134/* check if we can open this one */
135int
136patm_tx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc)
137{
138
139	/* check resources */
140	switch (vcc->vcc.traffic) {
141
142	  case ATMIO_TRAFFIC_CBR:
143	    {
144		u_int slots = cbr2slots(sc, vcc);
145
146		if (slots > sc->tst_free + sc->tst_reserve)
147			return (EINVAL);
148		break;
149	    }
150
151	  case ATMIO_TRAFFIC_VBR:
152		if (vcc->vcc.tparam.scr > sc->bwrem)
153			return (EINVAL);
154		if (vcc->vcc.tparam.pcr > sc->ifatm.mib.pcr)
155			return (EINVAL);
156		if (vcc->vcc.tparam.scr > vcc->vcc.tparam.pcr ||
157		    vcc->vcc.tparam.mbs == 0)
158			return (EINVAL);
159		break;
160
161	  case ATMIO_TRAFFIC_ABR:
162		if (vcc->vcc.tparam.tbe == 0 ||
163		    vcc->vcc.tparam.nrm == 0)
164			/* needed to compute CRM */
165			return (EINVAL);
166		if (vcc->vcc.tparam.pcr > sc->ifatm.mib.pcr ||
167		    vcc->vcc.tparam.icr > vcc->vcc.tparam.pcr ||
168		    vcc->vcc.tparam.mcr > vcc->vcc.tparam.icr)
169			return (EINVAL);
170		if (vcc->vcc.tparam.mcr > sc->bwrem ||
171		    vcc->vcc.tparam.icr > sc->bwrem)
172			return (EINVAL);
173		break;
174	}
175
176	return (0);
177}
178
179#define	NEXT_TAG(T) do {				\
180	(T) = ((T) + 1) % IDT_TSQE_TAG_SPACE;		\
181    } while (0)
182
183/*
184 * open it
185 */
186void
187patm_tx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc)
188{
189	struct patm_scd *scd;
190
191	if (vcc->vcc.traffic == ATMIO_TRAFFIC_UBR) {
192		/* we use UBR0 */
193		vcc->scd = sc->scd0;
194		vcc->vflags |= PATM_VCC_TX_OPEN;
195		return;
196	}
197
198	/* get an SCD */
199	scd = patm_scd_alloc(sc);
200	if (scd == NULL) {
201		/* should not happen */
202		patm_printf(sc, "out of SCDs\n");
203		return;
204	}
205	vcc->scd = scd;
206	patm_scd_setup(sc, scd);
207	patm_tct_setup(sc, scd, vcc);
208
209	if (vcc->vcc.traffic != ATMIO_TRAFFIC_CBR)
210		patm_tct_start(sc, vcc);
211
212	vcc->vflags |= PATM_VCC_TX_OPEN;
213}
214
215/*
216 * close the given vcc for transmission
217 */
218void
219patm_tx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc)
220{
221	struct patm_scd *scd;
222	struct mbuf *m;
223
224	vcc->vflags |= PATM_VCC_TX_CLOSING;
225
226	if (vcc->vcc.traffic == ATMIO_TRAFFIC_UBR) {
227		/* let the queue PDUs go out */
228		vcc->scd = NULL;
229		vcc->vflags &= ~(PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING);
230		return;
231	}
232	scd = vcc->scd;
233
234	/* empty the waitq */
235	for (;;) {
236		_IF_DEQUEUE(&scd->q, m);
237		if (m == NULL)
238			break;
239		m_freem(m);
240	}
241
242	if (scd->num_on_card == 0) {
243		/* we are idle */
244		vcc->vflags &= ~PATM_VCC_TX_OPEN;
245
246		if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR)
247			patm_tst_free(sc, vcc);
248
249		patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0);
250		patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0);
251		patm_scd_free(sc, scd);
252
253		vcc->scd = NULL;
254		vcc->vflags &= ~PATM_VCC_TX_CLOSING;
255
256		return;
257	}
258
259	/* speed up transmission */
260	patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid, 0xff));
261	patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_ULACR(vcc->cid, 0xff));
262
263	/* wait for the interrupt to drop the number to 0 */
264	patm_debug(sc, VCC, "%u buffers still on card", scd->num_on_card);
265}
266
267/* transmission side finally closed */
268void
269patm_tx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
270{
271
272	patm_debug(sc, VCC, "%u.%u TX closed", vcc->vcc.vpi, vcc->vcc.vci);
273
274	if (vcc->vcc.traffic == ATMIO_TRAFFIC_VBR)
275		sc->bwrem += vcc->vcc.tparam.scr;
276}
277
278/*
279 * Pull off packets from the interface queue and try to transmit them.
280 * If the transmission fails because of a full transmit channel, we drop
281 * packets for CBR and queue them for other channels up to limit.
282 * This limit should depend on the CDVT for VBR and ABR, but it doesn't.
283 */
284void
285patm_start(struct ifnet *ifp)
286{
287	struct patm_softc *sc = (struct patm_softc *)ifp->if_softc;
288	struct mbuf *m;
289	struct atm_pseudohdr *aph;
290	u_int vpi, vci, cid;
291	struct patm_vcc *vcc;
292
293	mtx_lock(&sc->mtx);
294	if (!(ifp->if_flags & IFF_RUNNING)) {
295		mtx_unlock(&sc->mtx);
296		return;
297	}
298
299	while (1) {
300		/* get a new mbuf */
301		IF_DEQUEUE(&ifp->if_snd, m);
302		if (m == NULL)
303			break;
304
305		/* split of pseudo header */
306		if (m->m_len < sizeof(*aph) &&
307		    (m = m_pullup(m, sizeof(*aph))) == NULL) {
308			sc->ifatm.ifnet.if_oerrors++;
309			continue;
310		}
311
312		aph = mtod(m, struct atm_pseudohdr *);
313		vci = ATM_PH_VCI(aph);
314		vpi = ATM_PH_VPI(aph);
315		m_adj(m, sizeof(*aph));
316
317		/* reject empty packets */
318		if (m->m_pkthdr.len == 0) {
319			m_freem(m);
320			sc->ifatm.ifnet.if_oerrors++;
321			continue;
322		}
323
324		/* check whether this is a legal vcc */
325		if (!LEGAL_VPI(sc, vpi) || !LEGAL_VCI(sc, vci) || vci == 0) {
326			m_freem(m);
327			sc->ifatm.ifnet.if_oerrors++;
328			continue;
329		}
330		cid = PATM_CID(sc, vpi, vci);
331		vcc = sc->vccs[cid];
332		if (vcc == NULL) {
333			m_freem(m);
334			sc->ifatm.ifnet.if_oerrors++;
335			continue;
336		}
337
338		/* must be multiple of 48 if not AAL5 */
339		if (vcc->vcc.aal == ATMIO_AAL_0 ||
340		    vcc->vcc.aal == ATMIO_AAL_34) {
341			/* XXX AAL3/4 format? */
342			if (m->m_pkthdr.len % 48 != 0 &&
343			    (m = patm_tx_pad(sc, m)) == NULL) {
344				sc->ifatm.ifnet.if_oerrors++;
345				continue;
346			}
347		} else if (vcc->vcc.aal == ATMIO_AAL_RAW) {
348			switch (vcc->vflags & PATM_RAW_FORMAT) {
349
350			  default:
351			  case PATM_RAW_CELL:
352				if (m->m_pkthdr.len != 53) {
353					sc->ifatm.ifnet.if_oerrors++;
354					m_freem(m);
355					continue;
356				}
357				break;
358
359			  case PATM_RAW_NOHEC:
360				if (m->m_pkthdr.len != 52) {
361					sc->ifatm.ifnet.if_oerrors++;
362					m_freem(m);
363					continue;
364				}
365				break;
366
367			  case PATM_RAW_CS:
368				if (m->m_pkthdr.len != 64) {
369					sc->ifatm.ifnet.if_oerrors++;
370					m_freem(m);
371					continue;
372				}
373				break;
374			}
375		}
376
377		/* save data */
378		m->m_pkthdr.header = vcc;
379
380		/* try to put it on the channels queue */
381		if (_IF_QFULL(&vcc->scd->q)) {
382			sc->ifatm.ifnet.if_oerrors++;
383			sc->stats.tx_qfull++;
384			m_freem(m);
385			continue;
386		}
387		_IF_ENQUEUE(&vcc->scd->q, m);
388
389#ifdef ENABLE_BPF
390		if (!(vcc->vcc.flags & ATMIO_FLAG_NG) &&
391		    (vcc->vcc.aal == ATMIO_AAL_5) &&
392		    (vcc->vcc.flags & ATM_PH_LLCSNAP))
393		 	BPF_MTAP(ifp, m);
394#endif
395
396		/* kick the channel to life */
397		patm_launch(sc, vcc->scd);
398
399	}
400	mtx_unlock(&sc->mtx);
401}
402
403/*
404 * Pad non-AAL5 packet to a multiple of 48-byte.
405 * We assume AAL0 only. We have still to decide on the format of AAL3/4.
406 */
407static struct mbuf *
408patm_tx_pad(struct patm_softc *sc, struct mbuf *m0)
409{
410	struct mbuf *last, *m;
411	u_int plen, pad, space;
412
413	plen = m_length(m0, &last);
414	if (plen != m0->m_pkthdr.len) {
415		patm_printf(sc, "%s: mbuf length mismatch %d %u\n", __func__,
416		    m0->m_pkthdr.len, plen);
417		m0->m_pkthdr.len = plen;
418		if (plen == 0) {
419			m_freem(m0);
420			sc->ifatm.ifnet.if_oerrors++;
421			return (NULL);
422		}
423		if (plen % 48 == 0)
424			return (m0);
425	}
426	pad = 48 - plen % 48;
427	m0->m_pkthdr.len += pad;
428	if (M_WRITABLE(last)) {
429		if (M_TRAILINGSPACE(last) >= pad) {
430			bzero(last->m_data + last->m_len, pad);
431			last->m_len += pad;
432			return (m0);
433		}
434		space = M_LEADINGSPACE(last);
435		if (space + M_TRAILINGSPACE(last) >= pad) {
436			bcopy(last->m_data, last->m_data + space, last->m_len);
437			last->m_data -= space;
438			bzero(last->m_data + last->m_len, pad);
439			last->m_len += pad;
440			return (m0);
441		}
442	}
443	MGET(m, M_DONTWAIT, MT_DATA);
444	if (m == 0) {
445		m_freem(m0);
446		sc->ifatm.ifnet.if_oerrors++;
447		return (NULL);
448	}
449	bzero(mtod(m, u_char *), pad);
450	m->m_len = pad;
451	last->m_next = m;
452
453	return (m0);
454}
455
456/*
457 * Try to put as many packets from the channels queue onto the channel
458 */
459static void
460patm_launch(struct patm_softc *sc, struct patm_scd *scd)
461{
462	struct txarg a;
463	struct mbuf *m, *tmp;
464	u_int segs;
465	struct patm_txmap *map;
466	int error;
467
468	a.sc = sc;
469	a.scd = scd;
470
471	/* limit the number of outstanding packets to the tag space */
472	while (scd->num_on_card < IDT_TSQE_TAG_SPACE) {
473		/* get the next packet */
474		_IF_DEQUEUE(&scd->q, m);
475		if (m == NULL)
476			break;
477
478		a.vcc = m->m_pkthdr.header;
479
480		/* we must know the number of segments beforehand - count
481		 * this may actually give a wrong number of segments for
482		 * AAL_RAW where we still need to remove the cell header */
483		segs = 0;
484		for (tmp = m; tmp != NULL; tmp = tmp->m_next)
485			if (tmp->m_len != 0)
486				segs++;
487
488		/* check whether there is space in the queue */
489		if (segs >= scd->space) {
490			/* put back */
491			_IF_PREPEND(&scd->q, m);
492			sc->stats.tx_out_of_tbds++;
493			break;
494		}
495
496		/* get a DMA map */
497		if ((map = patm_txmap_get(sc)) == NULL) {
498			_IF_PREPEND(&scd->q, m);
499			sc->stats.tx_out_of_maps++;
500			break;
501		}
502
503		/* load the map */
504		m->m_pkthdr.header = map;
505		a.mbuf = m;
506
507		/* handle AAL_RAW */
508		if (a.vcc->vcc.aal == ATMIO_AAL_RAW) {
509			u_char hdr[4];
510
511			m_copydata(m, 0, 4, hdr);
512			a.hdr = (hdr[0] << 24) | (hdr[1] << 16) |
513			    (hdr[2] << 8) | hdr[3];
514
515			switch (a.vcc->vflags & PATM_RAW_FORMAT) {
516
517			  default:
518			  case PATM_RAW_CELL:
519				m_adj(m, 5);
520				break;
521
522			  case PATM_RAW_NOHEC:
523				m_adj(m, 4);
524				break;
525
526			  case PATM_RAW_CS:
527				m_adj(m, 16);
528				break;
529			}
530		} else
531			a.hdr = IDT_TBD_HDR(a.vcc->vcc.vpi, a.vcc->vcc.vci,
532			    0, 0);
533
534		error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m,
535		    patm_load_txbuf, &a, BUS_DMA_NOWAIT);
536		if (error == EFBIG) {
537			if ((m = m_defrag(m, M_DONTWAIT)) == NULL) {
538				sc->ifatm.ifnet.if_oerrors++;
539				continue;
540			}
541			error = bus_dmamap_load_mbuf(sc->tx_tag, map->map, m,
542			    patm_load_txbuf, &a, BUS_DMA_NOWAIT);
543		}
544		if (error != 0) {
545			sc->stats.tx_load_err++;
546			sc->ifatm.ifnet.if_oerrors++;
547			SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link);
548			m_freem(m);
549			continue;
550		}
551
552		sc->ifatm.ifnet.if_opackets++;
553	}
554}
555
556/*
557 * Load the DMA segments into the scheduling channel
558 */
559static void
560patm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg,
561    bus_size_t mapsize, int error)
562{
563	struct txarg *a= uarg;
564	struct patm_scd *scd = a->scd;
565	u_int w1, w3, cnt;
566	struct idt_tbd *tbd = NULL;
567	u_int rest = mapsize;
568
569	if (error != 0)
570		return;
571
572	cnt = 0;
573	while (nseg > 0) {
574		if (segs->ds_len == 0) {
575			/* transmit buffer length must be > 0 */
576			nseg--;
577			segs++;
578			continue;
579		}
580		/* rest after this buffer */
581		rest -= segs->ds_len;
582
583		/* put together status word */
584		w1 = 0;
585		if (rest < 48 /* && a->vcc->vcc.aal != ATMIO_AAL_5 */)
586			/* last cell is in this buffer */
587			w1 |= IDT_TBD_EPDU;
588
589		if (a->vcc->vcc.aal == ATMIO_AAL_5)
590			w1 |= IDT_TBD_AAL5;
591		else if (a->vcc->vcc.aal == ATMIO_AAL_34)
592			w1 |= IDT_TBD_AAL34;
593		else
594			w1 |= IDT_TBD_AAL0;
595
596		w1 |= segs->ds_len;
597
598		/* AAL5 PDU length (unpadded) */
599		if (a->vcc->vcc.aal == ATMIO_AAL_5)
600			w3 = mapsize;
601		else
602			w3 = 0;
603
604		if (rest == 0)
605			w1 |= IDT_TBD_TSIF | IDT_TBD_GTSI |
606			    (scd->tag << IDT_TBD_TAG_SHIFT);
607
608		tbd = &scd->scq[scd->tail];
609
610		tbd->flags = htole32(w1);
611		tbd->addr = htole32(segs->ds_addr);
612		tbd->aal5 = htole32(w3);
613		tbd->hdr = htole32(a->hdr);
614
615		patm_debug(a->sc, TX, "TBD(%u): %08x %08x %08x %08x",
616		    scd->tail, w1, segs->ds_addr, w3, a->hdr);
617
618		/* got to next entry */
619		if (++scd->tail == IDT_SCQ_SIZE)
620			scd->tail = 0;
621		cnt++;
622		nseg--;
623		segs++;
624	}
625	scd->space -= cnt;
626	scd->num_on_card++;
627
628	KASSERT(rest == 0, ("bad mbuf"));
629	KASSERT(cnt > 0, ("no segs"));
630	KASSERT(scd->space > 0, ("scq full"));
631
632	KASSERT(scd->on_card[scd->tag] == NULL,
633	    ("scd on_card wedged %u%s", scd->tag, dump_scd(a->sc, scd)));
634	scd->on_card[scd->tag] = a->mbuf;
635	a->mbuf->m_pkthdr.csum_data = cnt;
636
637	NEXT_TAG(scd->tag);
638
639	patm_debug(a->sc, TX, "SCD tail %u (%lx:%lx)", scd->tail,
640	    (u_long)scd->phy, (u_long)scd->phy + (scd->tail << IDT_TBD_SHIFT));
641	patm_sram_write(a->sc, scd->sram,
642	    scd->phy + (scd->tail << IDT_TBD_SHIFT));
643
644	if (patm_sram_read(a->sc, a->vcc->cid * 8 + 3) & IDT_TCT_IDLE) {
645		/*
646		 * if the connection is idle start it. We cannot rely
647		 * on a flag set by patm_tx_idle() here, because sometimes
648		 * the card seems to place an idle TSI into the TSQ but
649		 * forgets to raise an interrupt.
650		 */
651		patm_nor_write(a->sc, IDT_NOR_TCMDQ,
652		    IDT_TCMDQ_START(a->vcc->cid));
653	}
654}
655
656/*
657 * packet transmitted
658 */
659void
660patm_tx(struct patm_softc *sc, u_int stamp, u_int status)
661{
662	u_int cid, tag, last;
663	struct mbuf *m;
664	struct patm_vcc *vcc;
665	struct patm_scd *scd;
666	struct patm_txmap *map;
667
668	/* get the connection */
669	cid = PATM_CID(sc, IDT_TBD_VPI(status), IDT_TBD_VCI(status));
670	if ((vcc = sc->vccs[cid]) == NULL) {
671		/* closed UBR connection */
672		return;
673	}
674	scd = vcc->scd;
675
676	tag = IDT_TSQE_TAG(stamp);
677
678	last = scd->last_tag;
679	if (tag == last) {
680		patm_printf(sc, "same tag %u\n", tag);
681		return;
682	}
683
684	/* Errata 12 requests us to free all entries up to the one
685	 * with the given tag. */
686	do {
687		/* next tag to try */
688		NEXT_TAG(last);
689
690		m = scd->on_card[last];
691		KASSERT(m != NULL, ("%stag=%u", dump_scd(sc, scd), tag));
692		scd->on_card[last] = NULL;
693		patm_debug(sc, TX, "ok tag=%x", last);
694
695		map = m->m_pkthdr.header;
696		scd->space += m->m_pkthdr.csum_data;
697
698		bus_dmamap_sync(sc->tx_tag, map->map,
699		    BUS_DMASYNC_POSTWRITE);
700		bus_dmamap_unload(sc->tx_tag, map->map);
701		m_freem(m);
702		SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link);
703		scd->num_on_card--;
704
705		if (vcc->vflags & PATM_VCC_TX_CLOSING) {
706			if (scd->num_on_card == 0) {
707				/* done with this VCC */
708				if (vcc->vcc.traffic == ATMIO_TRAFFIC_CBR)
709					patm_tst_free(sc, vcc);
710
711				patm_sram_write4(sc, scd->sram + 0, 0, 0, 0, 0);
712				patm_sram_write4(sc, scd->sram + 4, 0, 0, 0, 0);
713				patm_scd_free(sc, scd);
714
715				vcc->scd = NULL;
716				vcc->vflags &= ~PATM_VCC_TX_CLOSING;
717
718				if (vcc->vcc.flags & ATMIO_FLAG_ASYNC) {
719					patm_tx_vcc_closed(sc, vcc);
720					if (!(vcc->vflags & PATM_VCC_OPEN))
721						patm_vcc_closed(sc, vcc);
722				} else
723					cv_signal(&sc->vcc_cv);
724				return;
725			}
726			patm_debug(sc, VCC, "%u buffers still on card",
727			    scd->num_on_card);
728
729			if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) {
730				/* insist on speeding up transmission for ABR */
731				patm_nor_write(sc, IDT_NOR_TCMDQ,
732				    IDT_TCMDQ_UIER(vcc->cid, 0xff));
733				patm_nor_write(sc, IDT_NOR_TCMDQ,
734				    IDT_TCMDQ_ULACR(vcc->cid, 0xff));
735			}
736		}
737
738	} while (last != tag);
739	scd->last_tag = tag;
740
741	if (vcc->vcc.traffic == ATMIO_TRAFFIC_ABR) {
742		u_int acri, cps;
743
744		acri = (patm_sram_read(sc, 8 * cid + 2) >> IDT_TCT_ACRI_SHIFT)
745		    & 0x3fff;
746		cps = sc->ifatm.mib.pcr * 32 /
747		    ((1 << (acri >> 10)) * (acri & 0x3ff));
748
749		if (cps != vcc->cps) {
750			patm_debug(sc, VCC, "ACRI=%04x CPS=%u", acri, cps);
751			ATMEV_SEND_ACR_CHANGED(&sc->ifatm, vcc->vcc.vpi,
752			    vcc->vcc.vci, cps);
753			vcc->cps = cps;
754		}
755	}
756
757	patm_launch(sc, scd);
758}
759
760/*
761 * VBR/ABR connection went idle
762 * Either restart it or set the idle flag.
763 */
764void
765patm_tx_idle(struct patm_softc *sc, u_int cid)
766{
767	struct patm_vcc *vcc;
768
769	patm_debug(sc, VCC, "idle %u", cid);
770
771	if ((vcc = sc->vccs[cid]) != NULL &&
772	    (vcc->vflags & (PATM_VCC_TX_OPEN | PATM_VCC_TX_CLOSING)) != 0 &&
773	    vcc->scd != NULL && (vcc->scd->num_on_card != 0 ||
774	    _IF_QLEN(&vcc->scd->q) != 0)) {
775		/*
776		 * If there is any packet outstanding in the SCD re-activate
777		 * the channel and kick it.
778		 */
779		patm_nor_write(sc, IDT_NOR_TCMDQ,
780		    IDT_TCMDQ_START(vcc->cid));
781
782		patm_launch(sc, vcc->scd);
783	}
784}
785
786/*
787 * Convert a (24bit) rate to the atm-forum form
788 * Our rate is never larger than 19 bit.
789 */
790static u_int
791cps2atmf(u_int cps)
792{
793	u_int e;
794
795	if (cps == 0)
796		return (0);
797	cps <<= 9;
798	e = 0;
799	while (cps > (1024 - 1)) {
800		e++;
801		cps >>= 1;
802	}
803	return ((1 << 14) | (e << 9) | (cps & 0x1ff));
804}
805
806/*
807 * Do a binary search on the log2rate table to convert the rate
808 * to its log form. This assumes that the ATM-Forum form is monotonically
809 * increasing with the plain cell rate.
810 */
811static u_int
812rate2log(struct patm_softc *sc, u_int rate)
813{
814	const uint32_t *tbl;
815	u_int lower, upper, mid, done, val, afr;
816
817	afr = cps2atmf(rate);
818
819	if (sc->flags & PATM_25M)
820		tbl = patm_rtables25;
821	else
822		tbl = patm_rtables155;
823
824	lower = 0;
825	upper = 255;
826	done = 0;
827	while (!done) {
828		mid = (lower + upper) / 2;
829		val = tbl[mid] >> 17;
830		if (val == afr || upper == lower)
831			break;
832		if (afr > val)
833			lower = mid + 1;
834		else
835			upper = mid - 1;
836	}
837	if (val > afr && mid > 0)
838		mid--;
839	return (mid);
840}
841
842/*
843 * Return the table index for an increase table. The increase table
844 * must be selected not by the RIF itself, but by PCR/2^RIF. Each table
845 * represents an additive increase of a cell rate that can be computed
846 * from the first table entry (the value in this entry will not be clamped
847 * by the link rate).
848 */
849static u_int
850get_air_table(struct patm_softc *sc, u_int rif, u_int pcr)
851{
852	const uint32_t *tbl;
853	u_int increase, base, lair0, ret, t, cps;
854
855#define	GET_ENTRY(TAB, IDX) (0xffff & ((IDX & 1) ?			\
856	(tbl[512 + (IDX / 2) + 128 * (TAB)] >> 16) :			\
857	(tbl[512 + (IDX / 2) + 128 * (TAB)])))
858
859#define	MANT_BITS	10
860#define	FRAC_BITS	16
861
862#define	DIFF_TO_FP(D)	(((D) & ((1 << MANT_BITS) - 1)) << ((D) >> MANT_BITS))
863#define	AFR_TO_INT(A)	((1 << (((A) >> 9) & 0x1f)) * \
864			    (512 + ((A) & 0x1ff)) / 512 * ((A) >> 14))
865
866	if (sc->flags & PATM_25M)
867		tbl = patm_rtables25;
868	else
869		tbl = patm_rtables155;
870	if (rif >= patm_rtables_ntab)
871		rif = patm_rtables_ntab - 1;
872	increase = pcr >> rif;
873
874	ret = 0;
875	for (t = 0; t < patm_rtables_ntab; t++) {
876		/* get base rate of this table */
877		base = GET_ENTRY(t, 0);
878		/* convert this to fixed point */
879		lair0 = DIFF_TO_FP(base) >> FRAC_BITS;
880
881		/* get the CPS from the log2rate table */
882		cps = AFR_TO_INT(tbl[lair0] >> 17) - 10;
883
884		if (increase >= cps)
885			break;
886
887		ret = t;
888	}
889	return (ret + 4);
890}
891
892/*
893 * Setup the TCT
894 */
895void
896patm_tct_setup(struct patm_softc *sc, struct patm_scd *scd,
897    struct patm_vcc *vcc)
898{
899	uint32_t tct[8];
900	u_int sram;
901	u_int mbs, token;
902	u_int tmp, crm, rdf, cdf, air, mcr;
903
904	bzero(tct, sizeof(tct));
905	if (vcc == NULL) {
906		/* special case for UBR0 */
907		sram = 0;
908		tct[0] = IDT_TCT_UBR | scd->sram;
909		tct[7] = IDT_TCT_UBR_FLG;
910
911	} else {
912		sram = vcc->cid * 8;
913		switch (vcc->vcc.traffic) {
914
915		  case ATMIO_TRAFFIC_CBR:
916			patm_tst_alloc(sc, vcc);
917			tct[0] = IDT_TCT_CBR | scd->sram;
918			/* must account for what was really allocated */
919			break;
920
921		  case ATMIO_TRAFFIC_VBR:
922			/* compute parameters for the TCT */
923			scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr);
924			scd->lacr = rate2log(sc, vcc->vcc.tparam.scr);
925
926			/* get the 16-bit fraction of SCR/PCR
927			 * both a 24 bit. Do it the simple way. */
928			token = (uint64_t)(vcc->vcc.tparam.scr << 16) /
929			    vcc->vcc.tparam.pcr;
930
931			patm_debug(sc, VCC, "VBR: init_er=%u lacr=%u "
932			    "token=0x%04x\n", scd->init_er, scd->lacr, token);
933
934			tct[0] = IDT_TCT_VBR | scd->sram;
935			tct[2] = IDT_TCT_TSIF;
936			tct[3] = IDT_TCT_IDLE | IDT_TCT_HALT;
937			tct[4] = IDT_TCT_MAXIDLE;
938			tct[5] = 0x01000000;
939			if ((mbs = vcc->vcc.tparam.mbs) > 0xff)
940				mbs = 0xff;
941			tct[6] = (mbs << 16) | token;
942			sc->bwrem -= vcc->vcc.tparam.scr;
943			break;
944
945		  case ATMIO_TRAFFIC_ABR:
946			scd->init_er = rate2log(sc, vcc->vcc.tparam.pcr);
947			scd->lacr = rate2log(sc, vcc->vcc.tparam.icr);
948			mcr = rate2log(sc, vcc->vcc.tparam.mcr);
949
950			/* compute CRM */
951			tmp = vcc->vcc.tparam.tbe / vcc->vcc.tparam.nrm;
952			if (tmp * vcc->vcc.tparam.nrm < vcc->vcc.tparam.tbe)
953				tmp++;
954			for (crm = 1; tmp > (1 << crm); crm++)
955				;
956			if (crm > 0x7)
957				crm = 7;
958
959			air = get_air_table(sc, vcc->vcc.tparam.rif,
960			    vcc->vcc.tparam.pcr);
961
962			if ((rdf = vcc->vcc.tparam.rdf) >= patm_rtables_ntab)
963				rdf = patm_rtables_ntab - 1;
964			rdf += patm_rtables_ntab + 4;
965
966			if ((cdf = vcc->vcc.tparam.cdf) >= patm_rtables_ntab)
967				cdf = patm_rtables_ntab - 1;
968			cdf += patm_rtables_ntab + 4;
969
970			patm_debug(sc, VCC, "ABR: init_er=%u lacr=%u mcr=%u "
971			    "crm=%u air=%u rdf=%u cdf=%u\n", scd->init_er,
972			    scd->lacr, mcr, crm, air, rdf, cdf);
973
974			tct[0] = IDT_TCT_ABR | scd->sram;
975			tct[1] = crm << IDT_TCT_CRM_SHIFT;
976			tct[3] = IDT_TCT_HALT | IDT_TCT_IDLE |
977			    (4 << IDT_TCT_NAGE_SHIFT);
978			tct[4] = mcr << IDT_TCT_LMCR_SHIFT;
979			tct[5] = (cdf << IDT_TCT_CDF_SHIFT) |
980			    (rdf << IDT_TCT_RDF_SHIFT) |
981			    (air << IDT_TCT_AIR_SHIFT);
982
983			sc->bwrem -= vcc->vcc.tparam.mcr;
984			break;
985		}
986	}
987
988	patm_sram_write4(sc, sram + 0, tct[0], tct[1], tct[2], tct[3]);
989	patm_sram_write4(sc, sram + 4, tct[4], tct[5], tct[6], tct[7]);
990
991	patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x  %08x %08x %08x %08x",
992	    sram / 8, patm_sram_read(sc, sram + 0),
993	    patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2),
994	    patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4),
995	    patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6),
996	    patm_sram_read(sc, sram + 7));
997}
998
999/*
1000 * Start a channel
1001 */
1002static void
1003patm_tct_start(struct patm_softc *sc, struct patm_vcc *vcc)
1004{
1005
1006	patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_UIER(vcc->cid,
1007	    vcc->scd->init_er));
1008	patm_nor_write(sc, IDT_NOR_TCMDQ, IDT_TCMDQ_SLACR(vcc->cid,
1009	    vcc->scd->lacr));
1010}
1011
1012static void
1013patm_tct_print(struct patm_softc *sc, u_int cid)
1014{
1015#ifdef PATM_DEBUG
1016	u_int sram = cid * 8;
1017#endif
1018
1019	patm_debug(sc, VCC, "TCT[%u]: %08x %08x %08x %08x  %08x %08x %08x %08x",
1020	    sram / 8, patm_sram_read(sc, sram + 0),
1021	    patm_sram_read(sc, sram + 1), patm_sram_read(sc, sram + 2),
1022	    patm_sram_read(sc, sram + 3), patm_sram_read(sc, sram + 4),
1023	    patm_sram_read(sc, sram + 5), patm_sram_read(sc, sram + 6),
1024	    patm_sram_read(sc, sram + 7));
1025}
1026
1027/*
1028 * Setup the SCD
1029 */
1030void
1031patm_scd_setup(struct patm_softc *sc, struct patm_scd *scd)
1032{
1033	patm_sram_write4(sc, scd->sram + 0,
1034	    scd->phy, 0, 0xffffffff, 0);
1035	patm_sram_write4(sc, scd->sram + 4,
1036	    0, 0, 0, 0);
1037
1038	patm_debug(sc, VCC, "SCD(%x): %08x %08x %08x %08x %08x %08x %08x %08x",
1039	    scd->sram,
1040	    patm_sram_read(sc, scd->sram + 0),
1041	    patm_sram_read(sc, scd->sram + 1),
1042	    patm_sram_read(sc, scd->sram + 2),
1043	    patm_sram_read(sc, scd->sram + 3),
1044	    patm_sram_read(sc, scd->sram + 4),
1045	    patm_sram_read(sc, scd->sram + 5),
1046	    patm_sram_read(sc, scd->sram + 6),
1047	    patm_sram_read(sc, scd->sram + 7));
1048}
1049
1050/*
1051 * Grow the TX map table if possible
1052 */
1053static void
1054patm_txmaps_grow(struct patm_softc *sc)
1055{
1056	u_int i;
1057	struct patm_txmap *map;
1058	int err;
1059
1060	if (sc->tx_nmaps >= sc->tx_maxmaps)
1061		return;
1062
1063	for (i = sc->tx_nmaps; i < sc->tx_nmaps + PATM_CFG_TXMAPS_STEP; i++) {
1064		map = uma_zalloc(sc->tx_mapzone, M_NOWAIT);
1065		err = bus_dmamap_create(sc->tx_tag, 0, &map->map);
1066		if (err) {
1067			uma_zfree(sc->tx_mapzone, map);
1068			break;
1069		}
1070		SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link);
1071	}
1072
1073	sc->tx_nmaps = i;
1074}
1075
1076/*
1077 * Allocate a transmission map
1078 */
1079static struct patm_txmap *
1080patm_txmap_get(struct patm_softc *sc)
1081{
1082	struct patm_txmap *map;
1083
1084	if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL) {
1085		patm_txmaps_grow(sc);
1086		if ((map = SLIST_FIRST(&sc->tx_maps_free)) == NULL)
1087			return (NULL);
1088	}
1089	SLIST_REMOVE_HEAD(&sc->tx_maps_free, link);
1090	return (map);
1091}
1092
1093/*
1094 * Look whether we are in the process of updating the TST on the chip.
1095 * If we are set the flag that we need another update.
1096 * If we are not start the update.
1097 */
1098static __inline void
1099patm_tst_start(struct patm_softc *sc)
1100{
1101
1102	if (!(sc->tst_state & TST_PENDING)) {
1103		sc->tst_state |= TST_PENDING;
1104		if (!(sc->tst_state & TST_WAIT)) {
1105			/* timer not running */
1106			patm_tst_update(sc);
1107		}
1108	}
1109}
1110
1111/*
1112 * Allocate TST entries to a CBR connection
1113 */
1114static void
1115patm_tst_alloc(struct patm_softc *sc, struct patm_vcc *vcc)
1116{
1117	u_int slots;
1118	u_int qptr, pptr;
1119	u_int qmax, pmax;
1120	u_int pspc, last;
1121
1122	mtx_lock(&sc->tst_lock);
1123
1124	/* compute the number of slots we need, make sure to get at least
1125	 * the specified PCR */
1126	slots = cbr2slots(sc, vcc);
1127	vcc->scd->slots = slots;
1128	sc->bwrem -= slots2cr(sc, slots);
1129
1130	patm_debug(sc, TST, "tst_alloc: cbr=%u link=%u tst=%u slots=%u",
1131	    vcc->vcc.tparam.pcr, sc->ifatm.mib.pcr, sc->mmap->tst_size, slots);
1132
1133	qmax = sc->mmap->tst_size - 1;
1134	pmax = qmax << 8;
1135
1136	pspc = pmax / slots;
1137
1138	pptr = pspc >> 1;	/* starting point */
1139	qptr = pptr >> 8;
1140
1141	last = qptr;
1142
1143	while (slots > 0) {
1144		if (qptr >= qmax)
1145			qptr -= qmax;
1146		if (sc->tst_soft[qptr] != IDT_TST_VBR) {
1147			/* used - try next */
1148			qptr++;
1149			continue;
1150		}
1151		patm_debug(sc, TST, "slot[%u] = %u.%u diff=%d", qptr,
1152		    vcc->vcc.vpi, vcc->vcc.vci, (int)qptr - (int)last);
1153		last = qptr;
1154
1155		sc->tst_soft[qptr] = IDT_TST_CBR | vcc->cid | TST_BOTH;
1156		sc->tst_free--;
1157
1158		if ((pptr += pspc) >= pmax)
1159			pptr -= pmax;
1160		qptr = pptr >> 8;
1161
1162		slots--;
1163	}
1164	patm_tst_start(sc);
1165	mtx_unlock(&sc->tst_lock);
1166}
1167
1168/*
1169 * Free a CBR connection's TST entries
1170 */
1171static void
1172patm_tst_free(struct patm_softc *sc, struct patm_vcc *vcc)
1173{
1174	u_int i;
1175
1176	mtx_lock(&sc->tst_lock);
1177	for (i = 0; i < sc->mmap->tst_size - 1; i++) {
1178		if ((sc->tst_soft[i] & IDT_TST_MASK) == vcc->cid) {
1179			sc->tst_soft[i] = IDT_TST_VBR | TST_BOTH;
1180			sc->tst_free++;
1181		}
1182	}
1183	sc->bwrem += slots2cr(sc, vcc->scd->slots);
1184	patm_tst_start(sc);
1185	mtx_unlock(&sc->tst_lock);
1186}
1187
1188/*
1189 * Write the soft TST into the idle incore TST and start the wait timer.
1190 * We assume that we hold the tst lock.
1191 */
1192static void
1193patm_tst_update(struct patm_softc *sc)
1194{
1195	u_int flag;		/* flag to clear from soft TST */
1196	u_int idle;		/* the idle TST */
1197	u_int act;		/* the active TST */
1198	u_int i;
1199
1200	if (sc->tst_state & TST_ACT1) {
1201		act = 1;
1202		idle = 0;
1203		flag = TST_CH0;
1204	} else {
1205		act = 0;
1206		idle = 1;
1207		flag = TST_CH1;
1208	}
1209	/* update the idle one */
1210	for (i = 0; i < sc->mmap->tst_size - 1; i++)
1211		if (sc->tst_soft[i] & flag) {
1212			patm_sram_write(sc, sc->tst_base[idle] + i,
1213			    sc->tst_soft[i] & ~TST_BOTH);
1214			sc->tst_soft[i] &= ~flag;
1215		}
1216	/* the used one jump to the idle one */
1217	patm_sram_write(sc, sc->tst_jump[act],
1218	    IDT_TST_BR | (sc->tst_base[idle] << 2));
1219
1220	/* wait for the chip to jump */
1221	sc->tst_state &= ~TST_PENDING;
1222	sc->tst_state |= TST_WAIT;
1223
1224	callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc);
1225}
1226
1227/*
1228 * Timer for TST updates
1229 */
1230static void
1231patm_tst_timer(void *p)
1232{
1233	struct patm_softc *sc = p;
1234	u_int act;	/* active TST */
1235	u_int now;	/* current place in TST */
1236
1237	mtx_lock(&sc->tst_lock);
1238
1239	if (sc->tst_state & TST_WAIT) {
1240		/* ignore the PENDING state while we are waiting for
1241		 * the chip to switch tables. Once the switch is done,
1242		 * we will again lock at PENDING */
1243		act = (sc->tst_state & TST_ACT1) ? 1 : 0;
1244		now = patm_nor_read(sc, IDT_NOR_NOW) >> 2;
1245		if (now >= sc->tst_base[act] && now <= sc->tst_jump[act]) {
1246			/* not yet */
1247			callout_reset(&sc->tst_callout, 1, patm_tst_timer, sc);
1248			goto done;
1249		}
1250		sc->tst_state &= ~TST_WAIT;
1251		/* change back jump */
1252		patm_sram_write(sc, sc->tst_jump[act],
1253		    IDT_TST_BR | (sc->tst_base[act] << 2));
1254
1255		/* switch */
1256		sc->tst_state ^= TST_ACT1;
1257	}
1258
1259	if (sc->tst_state & TST_PENDING)
1260		/* we got another update request while the timer was running. */
1261		patm_tst_update(sc);
1262
1263  done:
1264	mtx_unlock(&sc->tst_lock);
1265}
1266
1267static const char *
1268dump_scd(struct patm_softc *sc, struct patm_scd *scd)
1269{
1270	u_int i;
1271
1272	for (i = 0; i < IDT_TSQE_TAG_SPACE; i++)
1273		printf("on_card[%u] = %p\n", i, scd->on_card[i]);
1274	printf("space=%u tag=%u num_on_card=%u last_tag=%u\n",
1275	    scd->space, scd->tag, scd->num_on_card, scd->last_tag);
1276
1277	return ("");
1278}
1279