]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/hatm/if_hatm_tx.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / hatm / if_hatm_tx.c
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_media.h>
61 #include <net/if_atm.h>
62 #include <net/route.h>
63 #ifdef ENABLE_BPF
64 #include <net/bpf.h>
65 #endif
66 #include <netinet/in.h>
67 #include <netinet/if_atm.h>
68
69 #include <machine/bus.h>
70 #include <machine/resource.h>
71 #include <sys/bus.h>
72 #include <sys/rman.h>
73 #include <dev/pci/pcireg.h>
74 #include <dev/pci/pcivar.h>
75
76 #include <dev/utopia/utopia.h>
77 #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  */
111 static struct tpd *
112 hatm_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  */
147 static void
148 hatm_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  */
167 static int
168 hatm_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  */
229 struct 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  */
246 static void
247 hatm_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  */
351 void
352 hatm_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
501 void
502 hatm_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  */
539 static u_int
540 cps_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  */
561 int
562 hatm_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  */
656 void
657 hatm_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  */
777 void
778 hatm_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
819 void
820 hatm_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 }