Deleted Added
full compact
if_hatm_tx.c (121687) if_hatm_tx.c (122112)
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>
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: head/sys/dev/hatm/if_hatm_tx.c 121687 2003-10-29 15:15:19Z harti $");
35__FBSDID("$FreeBSD: head/sys/dev/hatm/if_hatm_tx.c 122112 2003-11-05 11:43:06Z harti $");
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
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
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/*
82 * Allocate a new TPD, zero the TPD part. Cannot return NULL if
83 * flag is 0. The TPD is removed from the free list and its used
84 * bit is set.
85 */
86static struct tpd *
87hatm_alloc_tpd(struct hatm_softc *sc, u_int flags)
88{
89 struct tpd *t;
90
91 /* if we allocate a transmit TPD check for the reserve */
92 if (flags & M_NOWAIT) {
93 if (sc->tpd_nfree <= HE_CONFIG_TPD_RESERVE)
94 return (NULL);
95 } else {
96 if (sc->tpd_nfree == 0)
97 return (NULL);
98 }
99
100 /* make it beeing used */
101 t = SLIST_FIRST(&sc->tpd_free);
102 KASSERT(t != NULL, ("tpd botch"));
103 SLIST_REMOVE_HEAD(&sc->tpd_free, link);
104 TPD_SET_USED(sc, t->no);
105 sc->tpd_nfree--;
106
107 /* initialize */
108 t->mbuf = NULL;
109 t->cid = 0;
110 bzero(&t->tpd, sizeof(t->tpd));
111 t->tpd.addr = t->no << HE_REGS_TPD_ADDR;
112
113 return (t);
114}
115
116/*
117 * Free a TPD. If the mbuf pointer in that TPD is not zero, it is assumed, that
118 * the DMA map of this TPD was used to load this mbuf. The map is unloaded
119 * and the mbuf is freed. The TPD is put back onto the free list and
120 * its used bit is cleared.
121 */
122static void
123hatm_free_tpd(struct hatm_softc *sc, struct tpd *tpd)
124{
125 if (tpd->mbuf != NULL) {
126 bus_dmamap_unload(sc->tx_tag, tpd->map);
107 * Allocate a new TPD, zero the TPD part. Cannot return NULL if
108 * flag is 0. The TPD is removed from the free list and its used
109 * bit is set.
110 */
111static struct tpd *
112hatm_alloc_tpd(struct hatm_softc *sc, u_int flags)
113{
114 struct tpd *t;
115
116 /* if we allocate a transmit TPD check for the reserve */
117 if (flags & M_NOWAIT) {
118 if (sc->tpd_nfree <= HE_CONFIG_TPD_RESERVE)
119 return (NULL);
120 } else {
121 if (sc->tpd_nfree == 0)
122 return (NULL);
123 }
124
125 /* make it beeing used */
126 t = SLIST_FIRST(&sc->tpd_free);
127 KASSERT(t != NULL, ("tpd botch"));
128 SLIST_REMOVE_HEAD(&sc->tpd_free, link);
129 TPD_SET_USED(sc, t->no);
130 sc->tpd_nfree--;
131
132 /* initialize */
133 t->mbuf = NULL;
134 t->cid = 0;
135 bzero(&t->tpd, sizeof(t->tpd));
136 t->tpd.addr = t->no << HE_REGS_TPD_ADDR;
137
138 return (t);
139}
140
141/*
142 * Free a TPD. If the mbuf pointer in that TPD is not zero, it is assumed, that
143 * the DMA map of this TPD was used to load this mbuf. The map is unloaded
144 * and the mbuf is freed. The TPD is put back onto the free list and
145 * its used bit is cleared.
146 */
147static void
148hatm_free_tpd(struct hatm_softc *sc, struct tpd *tpd)
149{
150 if (tpd->mbuf != NULL) {
151 bus_dmamap_unload(sc->tx_tag, tpd->map);
152 hatm_free_txmbuf(sc);
127 m_freem(tpd->mbuf);
128 tpd->mbuf = NULL;
129 }
130
131 /* insert TPD into free list */
132 SLIST_INSERT_HEAD(&sc->tpd_free, tpd, link);
133 TPD_CLR_USED(sc, tpd->no);
134 sc->tpd_nfree++;
135}
136
137/*
138 * Queue a number of TPD. If there is not enough space none of the TPDs
139 * is queued and an error code is returned.
140 */
141static int
142hatm_queue_tpds(struct hatm_softc *sc, u_int count, struct tpd **list,
143 u_int cid)
144{
145 u_int space;
146 u_int i;
147
148 if (count >= sc->tpdrq.size) {
149 sc->istats.tdprq_full++;
150 return (EBUSY);
151 }
152
153 if (sc->tpdrq.tail < sc->tpdrq.head)
154 space = sc->tpdrq.head - sc->tpdrq.tail;
155 else
156 space = sc->tpdrq.head - sc->tpdrq.tail + sc->tpdrq.size;
157
158 if (space <= count) {
159 sc->tpdrq.head =
160 (READ4(sc, HE_REGO_TPDRQ_H) >> HE_REGS_TPDRQ_H_H) &
161 (sc->tpdrq.size - 1);
162
163 if (sc->tpdrq.tail < sc->tpdrq.head)
164 space = sc->tpdrq.head - sc->tpdrq.tail;
165 else
166 space = sc->tpdrq.head - sc->tpdrq.tail +
167 sc->tpdrq.size;
168
169 if (space <= count) {
170 if_printf(&sc->ifatm.ifnet, "TPDRQ full\n");
171 sc->istats.tdprq_full++;
172 return (EBUSY);
173 }
174 }
175
176 /* we are going to write to the TPD queue space */
177 bus_dmamap_sync(sc->tpdrq.mem.tag, sc->tpdrq.mem.map,
178 BUS_DMASYNC_PREWRITE);
179
180 /* put the entries into the TPD space */
181 for (i = 0; i < count; i++) {
182 /* we are going to 'write' the TPD to the device */
183 bus_dmamap_sync(sc->tpds.tag, sc->tpds.map,
184 BUS_DMASYNC_PREWRITE);
185
186 sc->tpdrq.tpdrq[sc->tpdrq.tail].tpd =
187 sc->tpds.paddr + HE_TPD_SIZE * list[i]->no;
188 sc->tpdrq.tpdrq[sc->tpdrq.tail].cid = cid;
189
190 if (++sc->tpdrq.tail == sc->tpdrq.size)
191 sc->tpdrq.tail = 0;
192 }
193
194 /* update tail pointer */
195 WRITE4(sc, HE_REGO_TPDRQ_T, (sc->tpdrq.tail << HE_REGS_TPDRQ_T_T));
196
197 return (0);
198}
199
200/*
201 * Helper struct for communication with the DMA load helper.
202 */
203struct load_txbuf_arg {
204 struct hatm_softc *sc;
205 struct tpd *first;
206 struct mbuf *mbuf;
207 struct hevcc *vcc;
208 int error;
209 u_int pti;
210 u_int vpi, vci;
211};
212
213/*
214 * Loader callback for the mbuf. This function allocates the TPDs and
215 * fills them. It puts the dmamap and and the mbuf pointer into the last
216 * TPD and then tries to queue all the TPDs. If anything fails, all TPDs
217 * allocated by this function are freed and the error flag is set in the
218 * argument structure. The first TPD must then be freed by the caller.
219 */
220static void
221hatm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg,
222 bus_size_t mapsize, int error)
223{
224 struct load_txbuf_arg *arg = uarg;
225 u_int tpds_needed, i, n, tpd_cnt;
226 int need_intr;
227 struct tpd *tpd;
228 struct tpd *tpd_list[HE_CONFIG_MAX_TPD_PER_PACKET];
229
230 if (error != 0) {
231 DBG(arg->sc, DMA, ("%s -- error=%d plen=%d\n",
232 __func__, error, arg->mbuf->m_pkthdr.len));
233 return;
234 }
235
236 /* ensure, we have enough TPDs (remember, we already have one) */
237 tpds_needed = (nseg + 2) / 3;
238 if (HE_CONFIG_TPD_RESERVE + tpds_needed - 1 > arg->sc->tpd_nfree) {
239 if_printf(&arg->sc->ifatm.ifnet, "%s -- out of TPDs (need %d, "
240 "have %u)\n", __func__, tpds_needed - 1,
241 arg->sc->tpd_nfree + 1);
242 arg->error = 1;
243 return;
244 }
245
246 /*
247 * Check for the maximum number of TPDs on the connection.
248 */
249 need_intr = 0;
250 if (arg->sc->max_tpd > 0) {
251 if (arg->vcc->ntpds + tpds_needed > arg->sc->max_tpd) {
252 arg->sc->istats.flow_closed++;
253 arg->vcc->vflags |= HE_VCC_FLOW_CTRL;
254 ATMEV_SEND_FLOW_CONTROL(&arg->sc->ifatm,
255 arg->vpi, arg->vci, 1);
256 arg->error = 1;
257 return;
258 }
259 if (arg->vcc->ntpds + tpds_needed >
260 (9 * arg->sc->max_tpd) / 10)
261 need_intr = 1;
262 }
263
264 tpd = arg->first;
265 tpd_cnt = 0;
266 tpd_list[tpd_cnt++] = tpd;
267 for (i = n = 0; i < nseg; i++, n++) {
268 if (n == 3) {
269 if ((tpd = hatm_alloc_tpd(arg->sc, M_NOWAIT)) == NULL)
270 /* may not fail (see check above) */
271 panic("%s: out of TPDs", __func__);
272 tpd->cid = arg->first->cid;
273 tpd->tpd.addr |= arg->pti;
274 tpd_list[tpd_cnt++] = tpd;
275 n = 0;
276 }
277 KASSERT(segs[i].ds_addr <= 0xffffffffLU,
278 ("phys addr too large %lx", (u_long)segs[i].ds_addr));
279
280 DBG(arg->sc, DMA, ("DMA loaded: %lx/%lu",
281 (u_long)segs[i].ds_addr, (u_long)segs[i].ds_len));
282
283 tpd->tpd.bufs[n].addr = segs[i].ds_addr;
284 tpd->tpd.bufs[n].len = segs[i].ds_len;
285
286 DBG(arg->sc, TX, ("seg[%u]=tpd[%u,%u]=%x/%u", i,
287 tpd_cnt, n, tpd->tpd.bufs[n].addr, tpd->tpd.bufs[n].len));
288
289 if (i == nseg - 1)
290 tpd->tpd.bufs[n].len |= HE_REGM_TPD_LST;
291 }
292
293 /*
294 * Swap the MAP in the first and the last TPD and set the mbuf
295 * pointer into the last TPD. We use the map in the last TPD, because
296 * the map must stay valid until the last TPD is processed by the card.
297 */
298 if (tpd_cnt > 1) {
299 bus_dmamap_t tmp;
300
301 tmp = arg->first->map;
302 arg->first->map = tpd_list[tpd_cnt - 1]->map;
303 tpd_list[tpd_cnt - 1]->map = tmp;
304 }
305 tpd_list[tpd_cnt - 1]->mbuf = arg->mbuf;
306
307 if (need_intr)
308 tpd_list[tpd_cnt - 1]->tpd.addr |= HE_REGM_TPD_INTR;
309
310 /* queue the TPDs */
311 if (hatm_queue_tpds(arg->sc, tpd_cnt, tpd_list, arg->first->cid)) {
312 /* free all, except the first TPD */
313 for (i = 1; i < tpd_cnt; i++)
314 hatm_free_tpd(arg->sc, tpd_list[i]);
315 arg->error = 1;
316 return;
317 }
318 arg->vcc->ntpds += tpd_cnt;
319}
320
321
322/*
323 * Start output on the interface
324 */
325void
326hatm_start(struct ifnet *ifp)
327{
328 struct hatm_softc *sc = (struct hatm_softc *)ifp->if_softc;
329 struct mbuf *m;
330 struct atm_pseudohdr *aph;
331 u_int cid;
332 struct tpd *tpd;
333 struct load_txbuf_arg arg;
334 u_int len;
335 int error;
336
337 if (!(ifp->if_flags & IFF_RUNNING))
338 return;
339 mtx_lock(&sc->mtx);
340 arg.sc = sc;
341
342 while (1) {
343 IF_DEQUEUE(&ifp->if_snd, m);
344 if (m == NULL)
345 break;
346
153 m_freem(tpd->mbuf);
154 tpd->mbuf = NULL;
155 }
156
157 /* insert TPD into free list */
158 SLIST_INSERT_HEAD(&sc->tpd_free, tpd, link);
159 TPD_CLR_USED(sc, tpd->no);
160 sc->tpd_nfree++;
161}
162
163/*
164 * Queue a number of TPD. If there is not enough space none of the TPDs
165 * is queued and an error code is returned.
166 */
167static int
168hatm_queue_tpds(struct hatm_softc *sc, u_int count, struct tpd **list,
169 u_int cid)
170{
171 u_int space;
172 u_int i;
173
174 if (count >= sc->tpdrq.size) {
175 sc->istats.tdprq_full++;
176 return (EBUSY);
177 }
178
179 if (sc->tpdrq.tail < sc->tpdrq.head)
180 space = sc->tpdrq.head - sc->tpdrq.tail;
181 else
182 space = sc->tpdrq.head - sc->tpdrq.tail + sc->tpdrq.size;
183
184 if (space <= count) {
185 sc->tpdrq.head =
186 (READ4(sc, HE_REGO_TPDRQ_H) >> HE_REGS_TPDRQ_H_H) &
187 (sc->tpdrq.size - 1);
188
189 if (sc->tpdrq.tail < sc->tpdrq.head)
190 space = sc->tpdrq.head - sc->tpdrq.tail;
191 else
192 space = sc->tpdrq.head - sc->tpdrq.tail +
193 sc->tpdrq.size;
194
195 if (space <= count) {
196 if_printf(&sc->ifatm.ifnet, "TPDRQ full\n");
197 sc->istats.tdprq_full++;
198 return (EBUSY);
199 }
200 }
201
202 /* we are going to write to the TPD queue space */
203 bus_dmamap_sync(sc->tpdrq.mem.tag, sc->tpdrq.mem.map,
204 BUS_DMASYNC_PREWRITE);
205
206 /* put the entries into the TPD space */
207 for (i = 0; i < count; i++) {
208 /* we are going to 'write' the TPD to the device */
209 bus_dmamap_sync(sc->tpds.tag, sc->tpds.map,
210 BUS_DMASYNC_PREWRITE);
211
212 sc->tpdrq.tpdrq[sc->tpdrq.tail].tpd =
213 sc->tpds.paddr + HE_TPD_SIZE * list[i]->no;
214 sc->tpdrq.tpdrq[sc->tpdrq.tail].cid = cid;
215
216 if (++sc->tpdrq.tail == sc->tpdrq.size)
217 sc->tpdrq.tail = 0;
218 }
219
220 /* update tail pointer */
221 WRITE4(sc, HE_REGO_TPDRQ_T, (sc->tpdrq.tail << HE_REGS_TPDRQ_T_T));
222
223 return (0);
224}
225
226/*
227 * Helper struct for communication with the DMA load helper.
228 */
229struct load_txbuf_arg {
230 struct hatm_softc *sc;
231 struct tpd *first;
232 struct mbuf *mbuf;
233 struct hevcc *vcc;
234 int error;
235 u_int pti;
236 u_int vpi, vci;
237};
238
239/*
240 * Loader callback for the mbuf. This function allocates the TPDs and
241 * fills them. It puts the dmamap and and the mbuf pointer into the last
242 * TPD and then tries to queue all the TPDs. If anything fails, all TPDs
243 * allocated by this function are freed and the error flag is set in the
244 * argument structure. The first TPD must then be freed by the caller.
245 */
246static void
247hatm_load_txbuf(void *uarg, bus_dma_segment_t *segs, int nseg,
248 bus_size_t mapsize, int error)
249{
250 struct load_txbuf_arg *arg = uarg;
251 u_int tpds_needed, i, n, tpd_cnt;
252 int need_intr;
253 struct tpd *tpd;
254 struct tpd *tpd_list[HE_CONFIG_MAX_TPD_PER_PACKET];
255
256 if (error != 0) {
257 DBG(arg->sc, DMA, ("%s -- error=%d plen=%d\n",
258 __func__, error, arg->mbuf->m_pkthdr.len));
259 return;
260 }
261
262 /* ensure, we have enough TPDs (remember, we already have one) */
263 tpds_needed = (nseg + 2) / 3;
264 if (HE_CONFIG_TPD_RESERVE + tpds_needed - 1 > arg->sc->tpd_nfree) {
265 if_printf(&arg->sc->ifatm.ifnet, "%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(&arg->sc->ifatm,
281 arg->vpi, arg->vci, 1);
282 arg->error = 1;
283 return;
284 }
285 if (arg->vcc->ntpds + tpds_needed >
286 (9 * arg->sc->max_tpd) / 10)
287 need_intr = 1;
288 }
289
290 tpd = arg->first;
291 tpd_cnt = 0;
292 tpd_list[tpd_cnt++] = tpd;
293 for (i = n = 0; i < nseg; i++, n++) {
294 if (n == 3) {
295 if ((tpd = hatm_alloc_tpd(arg->sc, M_NOWAIT)) == NULL)
296 /* may not fail (see check above) */
297 panic("%s: out of TPDs", __func__);
298 tpd->cid = arg->first->cid;
299 tpd->tpd.addr |= arg->pti;
300 tpd_list[tpd_cnt++] = tpd;
301 n = 0;
302 }
303 KASSERT(segs[i].ds_addr <= 0xffffffffLU,
304 ("phys addr too large %lx", (u_long)segs[i].ds_addr));
305
306 DBG(arg->sc, DMA, ("DMA loaded: %lx/%lu",
307 (u_long)segs[i].ds_addr, (u_long)segs[i].ds_len));
308
309 tpd->tpd.bufs[n].addr = segs[i].ds_addr;
310 tpd->tpd.bufs[n].len = segs[i].ds_len;
311
312 DBG(arg->sc, TX, ("seg[%u]=tpd[%u,%u]=%x/%u", i,
313 tpd_cnt, n, tpd->tpd.bufs[n].addr, tpd->tpd.bufs[n].len));
314
315 if (i == nseg - 1)
316 tpd->tpd.bufs[n].len |= HE_REGM_TPD_LST;
317 }
318
319 /*
320 * Swap the MAP in the first and the last TPD and set the mbuf
321 * pointer into the last TPD. We use the map in the last TPD, because
322 * the map must stay valid until the last TPD is processed by the card.
323 */
324 if (tpd_cnt > 1) {
325 bus_dmamap_t tmp;
326
327 tmp = arg->first->map;
328 arg->first->map = tpd_list[tpd_cnt - 1]->map;
329 tpd_list[tpd_cnt - 1]->map = tmp;
330 }
331 tpd_list[tpd_cnt - 1]->mbuf = arg->mbuf;
332
333 if (need_intr)
334 tpd_list[tpd_cnt - 1]->tpd.addr |= HE_REGM_TPD_INTR;
335
336 /* queue the TPDs */
337 if (hatm_queue_tpds(arg->sc, tpd_cnt, tpd_list, arg->first->cid)) {
338 /* free all, except the first TPD */
339 for (i = 1; i < tpd_cnt; i++)
340 hatm_free_tpd(arg->sc, tpd_list[i]);
341 arg->error = 1;
342 return;
343 }
344 arg->vcc->ntpds += tpd_cnt;
345}
346
347
348/*
349 * Start output on the interface
350 */
351void
352hatm_start(struct ifnet *ifp)
353{
354 struct hatm_softc *sc = (struct hatm_softc *)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_flags & IFF_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
347 if (m->m_len < sizeof(*aph))
375 if (m->m_len < sizeof(*aph))
348 if ((m = m_pullup(m, sizeof(*aph))) == NULL)
376 if ((m = m_pullup(m, sizeof(*aph))) == NULL) {
377 hatm_free_txmbuf(sc);
349 continue;
378 continue;
379 }
350
351 aph = mtod(m, struct atm_pseudohdr *);
352 arg.vci = ATM_PH_VCI(aph);
353 arg.vpi = ATM_PH_VPI(aph);
354 m_adj(m, sizeof(*aph));
355
356 if ((len = m->m_pkthdr.len) == 0) {
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);
357 m_freem(m);
358 continue;
359 }
360
361 if ((arg.vpi & ~HE_VPI_MASK) || (arg.vci & ~HE_VCI_MASK) ||
362 (arg.vci == 0)) {
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);
363 m_freem(m);
364 continue;
365 }
366 cid = HE_CID(arg.vpi, arg.vci);
367 arg.vcc = sc->vccs[cid];
368
369 if (arg.vcc == NULL || !(arg.vcc->vflags & HE_VCC_OPEN)) {
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);
370 m_freem(m);
371 continue;
372 }
373 if (arg.vcc->vflags & HE_VCC_FLOW_CTRL) {
403 m_freem(m);
404 continue;
405 }
406 if (arg.vcc->vflags & HE_VCC_FLOW_CTRL) {
407 hatm_free_txmbuf(sc);
374 m_freem(m);
375 sc->istats.flow_drop++;
376 continue;
377 }
378
379 arg.pti = 0;
380 if (arg.vcc->param.aal == ATMIO_AAL_RAW) {
381 if (len < 52) {
382 /* too short */
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);
383 m_freem(m);
384 continue;
385 }
386
387 /*
388 * Get the header and ignore except
389 * payload type and CLP.
390 */
418 m_freem(m);
419 continue;
420 }
421
422 /*
423 * Get the header and ignore except
424 * payload type and CLP.
425 */
391 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL)
426 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) {
427 hatm_free_txmbuf(sc);
392 continue;
428 continue;
429 }
393 arg.pti = mtod(m, u_char *)[3] & 0xf;
394 arg.pti = ((arg.pti & 0xe) << 2) | ((arg.pti & 1) << 1);
395 m_adj(m, 4);
396 len -= 4;
397
398 if (len % 48 != 0) {
399 m_adj(m, -((int)(len % 48)));
400 len -= len % 48;
401 }
402 }
403
404#ifdef ENABLE_BPF
405 if (!(arg.vcc->param.flags & ATMIO_FLAG_NG) &&
406 (arg.vcc->param.aal == ATMIO_AAL_5) &&
407 (arg.vcc->param.flags & ATM_PH_LLCSNAP))
408 BPF_MTAP(ifp, m);
409#endif
410
411 /* Now load a DMA map with the packet. Allocate the first
412 * TPD to get a map. Additional TPDs may be allocated by the
413 * callback. */
414 if ((tpd = hatm_alloc_tpd(sc, M_NOWAIT)) == NULL) {
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);
415 m_freem(m);
416 sc->ifatm.ifnet.if_oerrors++;
417 continue;
418 }
419 tpd->cid = cid;
420 tpd->tpd.addr |= arg.pti;
421 arg.first = tpd;
422 arg.error = 0;
423 arg.mbuf = m;
424
425 error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m,
426 hatm_load_txbuf, &arg, BUS_DMA_NOWAIT);
427
428 if (error == EFBIG) {
429 /* try to defragment the packet */
430 sc->istats.defrag++;
431 m = m_defrag(m, M_DONTWAIT);
432 if (m == NULL) {
453 m_freem(m);
454 sc->ifatm.ifnet.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_DONTWAIT);
470 if (m == NULL) {
471 tpd->mbuf = NULL;
472 hatm_free_txmbuf(sc);
473 hatm_free_tpd(sc, tpd);
433 sc->ifatm.ifnet.if_oerrors++;
434 continue;
435 }
436 arg.mbuf = m;
437 error = bus_dmamap_load_mbuf(sc->tx_tag, tpd->map, m,
438 hatm_load_txbuf, &arg, BUS_DMA_NOWAIT);
439 }
440
441 if (error != 0) {
442 if_printf(&sc->ifatm.ifnet, "mbuf loaded error=%d\n",
443 error);
444 hatm_free_tpd(sc, tpd);
445 sc->ifatm.ifnet.if_oerrors++;
446 continue;
447 }
448 if (arg.error) {
449 hatm_free_tpd(sc, tpd);
450 sc->ifatm.ifnet.if_oerrors++;
451 continue;
452 }
453 arg.vcc->opackets++;
454 arg.vcc->obytes += len;
455 sc->ifatm.ifnet.if_opackets++;
456 }
457 mtx_unlock(&sc->mtx);
458}
459
460void
461hatm_tx_complete(struct hatm_softc *sc, struct tpd *tpd, uint32_t flags)
462{
463 struct hevcc *vcc = sc->vccs[tpd->cid];
464
465 DBG(sc, TX, ("tx_complete cid=%#x flags=%#x", tpd->cid, flags));
466
467 if (vcc == NULL)
468 return;
469 if ((flags & HE_REGM_TBRQ_EOS) && (vcc->vflags & HE_VCC_TX_CLOSING)) {
470 vcc->vflags &= ~HE_VCC_TX_CLOSING;
471 if (vcc->param.flags & ATMIO_FLAG_ASYNC) {
472 hatm_tx_vcc_closed(sc, tpd->cid);
473 if (!(vcc->vflags & HE_VCC_OPEN)) {
474 hatm_vcc_closed(sc, tpd->cid);
475 vcc = NULL;
476 }
477 } else
478 cv_signal(&sc->vcc_cv);
479 }
480 hatm_free_tpd(sc, tpd);
481
482 if (vcc == NULL)
483 return;
484
485 vcc->ntpds--;
486
487 if ((vcc->vflags & HE_VCC_FLOW_CTRL) &&
488 vcc->ntpds <= HE_CONFIG_TPD_FLOW_ENB) {
489 vcc->vflags &= ~HE_VCC_FLOW_CTRL;
490 ATMEV_SEND_FLOW_CONTROL(&sc->ifatm,
491 HE_VPI(tpd->cid), HE_VCI(tpd->cid), 0);
492 }
493}
494
495/*
496 * Convert CPS to Rate for a rate group
497 */
498static u_int
499cps_to_rate(struct hatm_softc *sc, uint32_t cps)
500{
501 u_int clk = sc->he622 ? HE_622_CLOCK : HE_155_CLOCK;
502 u_int period, rate;
503
504 /* how many double ticks between two cells */
505 period = (clk + 2 * cps - 1) / (2 * cps);
506 rate = hatm_cps2atmf(period);
507 if (hatm_atmf2cps(rate) < period)
508 rate++;
509
510 return (rate);
511}
512
513/*
514 * Check whether the VCC is really closed on the hardware and available for
515 * open. Check that we have enough resources. If this function returns ok,
516 * a later actual open must succeed. Assume, that we are locked between this
517 * function and the next one, so that nothing does change. For CBR this
518 * assigns the rate group and set the rate group's parameter.
519 */
520int
521hatm_tx_vcc_can_open(struct hatm_softc *sc, u_int cid, struct hevcc *vcc)
522{
523 uint32_t v, line_rate;
524 u_int rc, idx, free_idx;
525 struct atmio_tparam *t = &vcc->param.tparam;
526
527 /* verify that connection is closed */
528#if 0
529 v = READ_TSR(sc, cid, 4);
530 if(!(v & HE_REGM_TSR4_SESS_END)) {
531 if_printf(&sc->ifatm.ifnet, "cid=%#x not closed (TSR4)\n", cid);
532 return (EBUSY);
533 }
534#endif
535 v = READ_TSR(sc, cid, 0);
536 if((v & HE_REGM_TSR0_CONN_STATE) != 0) {
537 if_printf(&sc->ifatm.ifnet, "cid=%#x not closed (TSR0=%#x)\n",
538 cid, v);
539 return (EBUSY);
540 }
541
542 /* check traffic parameters */
543 line_rate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M;
544 switch (vcc->param.traffic) {
545
546 case ATMIO_TRAFFIC_UBR:
547 if (t->pcr == 0 || t->pcr > line_rate)
548 t->pcr = line_rate;
549 if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 ||
550 t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 ||
551 t->cdf != 0)
552 return (EINVAL);
553 break;
554
555 case ATMIO_TRAFFIC_CBR:
556 /*
557 * Compute rate group index
558 */
559 if (t->pcr < 10)
560 t->pcr = 10;
561 if (sc->cbr_bw + t->pcr > line_rate)
562 return (EINVAL);
563 if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 ||
564 t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 ||
565 t->cdf != 0)
566 return (EINVAL);
567
568 rc = cps_to_rate(sc, t->pcr);
569 free_idx = HE_REGN_CS_STPER;
570 for (idx = 0; idx < HE_REGN_CS_STPER; idx++) {
571 if (sc->rate_ctrl[idx].refcnt == 0) {
572 if (free_idx == HE_REGN_CS_STPER)
573 free_idx = idx;
574 } else {
575 if (sc->rate_ctrl[idx].rate == rc)
576 break;
577 }
578 }
579 if (idx == HE_REGN_CS_STPER) {
580 if ((idx = free_idx) == HE_REGN_CS_STPER)
581 return (EBUSY);
582 sc->rate_ctrl[idx].rate = rc;
583 }
584 vcc->rc = idx;
585
586 /* commit */
587 sc->rate_ctrl[idx].refcnt++;
588 sc->cbr_bw += t->pcr;
589 break;
590
591 case ATMIO_TRAFFIC_ABR:
592 if (t->pcr > line_rate)
593 t->pcr = line_rate;
594 if (t->mcr > line_rate)
595 t->mcr = line_rate;
596 if (t->icr > line_rate)
597 t->icr = line_rate;
598 if (t->tbe == 0 || t->tbe >= 1 << 24 || t->nrm > 7 ||
599 t->trm > 7 || t->adtf >= 1 << 10 || t->rif > 15 ||
600 t->rdf > 15 || t->cdf > 7)
601 return (EINVAL);
602 break;
603
604 default:
605 return (EINVAL);
606 }
607 return (0);
608}
609
610#define NRM_CODE2VAL(CODE) (2 * (1 << (CODE)))
611
612/*
613 * Actually open the transmit VCC
614 */
615void
616hatm_tx_vcc_open(struct hatm_softc *sc, u_int cid)
617{
618 struct hevcc *vcc = sc->vccs[cid];
619 uint32_t tsr0, tsr4, atmf, crm;
620 const struct atmio_tparam *t = &vcc->param.tparam;
621
622 if (vcc->param.aal == ATMIO_AAL_5) {
623 tsr0 = HE_REGM_TSR0_AAL_5 << HE_REGS_TSR0_AAL;
624 tsr4 = HE_REGM_TSR4_AAL_5 << HE_REGS_TSR4_AAL;
625 } else {
626 tsr0 = HE_REGM_TSR0_AAL_0 << HE_REGS_TSR0_AAL;
627 tsr4 = HE_REGM_TSR4_AAL_0 << HE_REGS_TSR4_AAL;
628 }
629 tsr4 |= 1;
630
631 switch (vcc->param.traffic) {
632
633 case ATMIO_TRAFFIC_UBR:
634 atmf = hatm_cps2atmf(t->pcr);
635
636 tsr0 |= HE_REGM_TSR0_TRAFFIC_UBR << HE_REGS_TSR0_TRAFFIC;
637 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER;
638
639 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
640 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
641 WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR));
642 WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR));
643 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
644 WRITE_TSR(sc, cid, 3, 0xf, 0);
645 WRITE_TSR(sc, cid, 5, 0xf, 0);
646 WRITE_TSR(sc, cid, 6, 0xf, 0);
647 WRITE_TSR(sc, cid, 7, 0xf, 0);
648 WRITE_TSR(sc, cid, 8, 0xf, 0);
649 WRITE_TSR(sc, cid, 10, 0xf, 0);
650 WRITE_TSR(sc, cid, 11, 0xf, 0);
651 WRITE_TSR(sc, cid, 12, 0xf, 0);
652 WRITE_TSR(sc, cid, 13, 0xf, 0);
653 WRITE_TSR(sc, cid, 14, 0xf, 0);
654 break;
655
656 case ATMIO_TRAFFIC_CBR:
657 atmf = hatm_cps2atmf(t->pcr);
658
659 if (sc->rate_ctrl[vcc->rc].refcnt == 1)
660 WRITE_MBOX4(sc, HE_REGO_CS_STPER(vcc->rc),
661 sc->rate_ctrl[vcc->rc].rate);
662
663 tsr0 |= HE_REGM_TSR0_TRAFFIC_CBR << HE_REGS_TSR0_TRAFFIC;
664 tsr0 |= vcc->rc;
665
666 WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR));
667 WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR));
668 WRITE_TSR(sc, cid, 3, 0xf, 0);
669 WRITE_TSR(sc, cid, 5, 0xf, 0);
670 WRITE_TSR(sc, cid, 6, 0xf, 0);
671 WRITE_TSR(sc, cid, 7, 0xf, 0);
672 WRITE_TSR(sc, cid, 8, 0xf, 0);
673 WRITE_TSR(sc, cid, 10, 0xf, 0);
674 WRITE_TSR(sc, cid, 11, 0xf, 0);
675 WRITE_TSR(sc, cid, 12, 0xf, 0);
676 WRITE_TSR(sc, cid, 13, 0xf, 0);
677 WRITE_TSR(sc, cid, 14, 0xf, 0);
678 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
679 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
680 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
681
682 break;
683
684 case ATMIO_TRAFFIC_ABR:
685 if ((crm = t->tbe / NRM_CODE2VAL(t->nrm)) > 0xffff)
686 crm = 0xffff;
687
688 tsr0 |= HE_REGM_TSR0_TRAFFIC_ABR << HE_REGS_TSR0_TRAFFIC;
689 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER;
690
691 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
692 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
693
694 WRITE_TSR(sc, cid, 1, 0xf,
695 ((hatm_cps2atmf(t->pcr) << HE_REGS_TSR1_PCR) |
696 (hatm_cps2atmf(t->mcr) << HE_REGS_TSR1_MCR)));
697 WRITE_TSR(sc, cid, 2, 0xf,
698 (hatm_cps2atmf(t->icr) << HE_REGS_TSR2_ACR));
699 WRITE_TSR(sc, cid, 3, 0xf,
700 ((NRM_CODE2VAL(t->nrm) - 1) << HE_REGS_TSR3_NRM) |
701 (crm << HE_REGS_TSR3_CRM));
702
703 WRITE_TSR(sc, cid, 5, 0xf, 0);
704 WRITE_TSR(sc, cid, 6, 0xf, 0);
705 WRITE_TSR(sc, cid, 7, 0xf, 0);
706 WRITE_TSR(sc, cid, 8, 0xf, 0);
707 WRITE_TSR(sc, cid, 10, 0xf, 0);
708 WRITE_TSR(sc, cid, 12, 0xf, 0);
709 WRITE_TSR(sc, cid, 14, 0xf, 0);
710 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
711
712 WRITE_TSR(sc, cid, 11, 0xf,
713 (hatm_cps2atmf(t->icr) << HE_REGS_TSR11_ICR) |
714 (t->trm << HE_REGS_TSR11_TRM) |
715 (t->nrm << HE_REGS_TSR11_NRM) |
716 (t->adtf << HE_REGS_TSR11_ADTF));
717
718 WRITE_TSR(sc, cid, 13, 0xf,
719 (t->rdf << HE_REGS_TSR13_RDF) |
720 (t->rif << HE_REGS_TSR13_RIF) |
721 (t->cdf << HE_REGS_TSR13_CDF) |
722 (crm << HE_REGS_TSR13_CRM));
723
724 break;
725
726 default:
727 return;
728 }
729
730 vcc->vflags |= HE_VCC_TX_OPEN;
731}
732
733/*
734 * Close the TX side of a VCC. Set the CLOSING flag.
735 */
736void
737hatm_tx_vcc_close(struct hatm_softc *sc, u_int cid)
738{
739 struct hevcc *vcc = sc->vccs[cid];
740 struct tpd *tpd_list[1];
741 u_int i, pcr = 0;
742
743 WRITE_TSR(sc, cid, 4, 0x8, HE_REGM_TSR4_FLUSH);
744
745 switch (vcc->param.traffic) {
746
747 case ATMIO_TRAFFIC_CBR:
748 WRITE_TSR(sc, cid, 14, 0x8, HE_REGM_TSR14_CBR_DELETE);
749 break;
750
751 case ATMIO_TRAFFIC_ABR:
752 WRITE_TSR(sc, cid, 14, 0x4, HE_REGM_TSR14_ABR_CLOSE);
753 pcr = vcc->param.tparam.pcr;
754 /* FALL THROUGH */
755
756 case ATMIO_TRAFFIC_UBR:
757 WRITE_TSR(sc, cid, 1, 0xf,
758 hatm_cps2atmf(HE_CONFIG_FLUSH_RATE) << HE_REGS_TSR1_MCR |
759 hatm_cps2atmf(pcr) << HE_REGS_TSR1_PCR);
760 break;
761 }
762
763 tpd_list[0] = hatm_alloc_tpd(sc, 0);
764 tpd_list[0]->tpd.addr |= HE_REGM_TPD_EOS | HE_REGM_TPD_INTR;
765 tpd_list[0]->cid = cid;
766
767 vcc->vflags |= HE_VCC_TX_CLOSING;
768 vcc->vflags &= ~HE_VCC_TX_OPEN;
769
770 i = 0;
771 while (hatm_queue_tpds(sc, 1, tpd_list, cid) != 0) {
772 if (++i == 1000)
773 panic("TPDRQ permanently full");
774 DELAY(1000);
775 }
776}
777
778void
779hatm_tx_vcc_closed(struct hatm_softc *sc, u_int cid)
780{
781 if (sc->vccs[cid]->param.traffic == ATMIO_TRAFFIC_CBR) {
782 sc->cbr_bw -= sc->vccs[cid]->param.tparam.pcr;
783 sc->rate_ctrl[sc->vccs[cid]->rc].refcnt--;
784 }
785}
474 sc->ifatm.ifnet.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->ifatm.ifnet, "mbuf loaded error=%d\n",
484 error);
485 hatm_free_tpd(sc, tpd);
486 sc->ifatm.ifnet.if_oerrors++;
487 continue;
488 }
489 if (arg.error) {
490 hatm_free_tpd(sc, tpd);
491 sc->ifatm.ifnet.if_oerrors++;
492 continue;
493 }
494 arg.vcc->opackets++;
495 arg.vcc->obytes += len;
496 sc->ifatm.ifnet.if_opackets++;
497 }
498 mtx_unlock(&sc->mtx);
499}
500
501void
502hatm_tx_complete(struct hatm_softc *sc, struct tpd *tpd, uint32_t flags)
503{
504 struct hevcc *vcc = sc->vccs[tpd->cid];
505
506 DBG(sc, TX, ("tx_complete cid=%#x flags=%#x", tpd->cid, flags));
507
508 if (vcc == NULL)
509 return;
510 if ((flags & HE_REGM_TBRQ_EOS) && (vcc->vflags & HE_VCC_TX_CLOSING)) {
511 vcc->vflags &= ~HE_VCC_TX_CLOSING;
512 if (vcc->param.flags & ATMIO_FLAG_ASYNC) {
513 hatm_tx_vcc_closed(sc, tpd->cid);
514 if (!(vcc->vflags & HE_VCC_OPEN)) {
515 hatm_vcc_closed(sc, tpd->cid);
516 vcc = NULL;
517 }
518 } else
519 cv_signal(&sc->vcc_cv);
520 }
521 hatm_free_tpd(sc, tpd);
522
523 if (vcc == NULL)
524 return;
525
526 vcc->ntpds--;
527
528 if ((vcc->vflags & HE_VCC_FLOW_CTRL) &&
529 vcc->ntpds <= HE_CONFIG_TPD_FLOW_ENB) {
530 vcc->vflags &= ~HE_VCC_FLOW_CTRL;
531 ATMEV_SEND_FLOW_CONTROL(&sc->ifatm,
532 HE_VPI(tpd->cid), HE_VCI(tpd->cid), 0);
533 }
534}
535
536/*
537 * Convert CPS to Rate for a rate group
538 */
539static u_int
540cps_to_rate(struct hatm_softc *sc, uint32_t cps)
541{
542 u_int clk = sc->he622 ? HE_622_CLOCK : HE_155_CLOCK;
543 u_int period, rate;
544
545 /* how many double ticks between two cells */
546 period = (clk + 2 * cps - 1) / (2 * cps);
547 rate = hatm_cps2atmf(period);
548 if (hatm_atmf2cps(rate) < period)
549 rate++;
550
551 return (rate);
552}
553
554/*
555 * Check whether the VCC is really closed on the hardware and available for
556 * open. Check that we have enough resources. If this function returns ok,
557 * a later actual open must succeed. Assume, that we are locked between this
558 * function and the next one, so that nothing does change. For CBR this
559 * assigns the rate group and set the rate group's parameter.
560 */
561int
562hatm_tx_vcc_can_open(struct hatm_softc *sc, u_int cid, struct hevcc *vcc)
563{
564 uint32_t v, line_rate;
565 u_int rc, idx, free_idx;
566 struct atmio_tparam *t = &vcc->param.tparam;
567
568 /* verify that connection is closed */
569#if 0
570 v = READ_TSR(sc, cid, 4);
571 if(!(v & HE_REGM_TSR4_SESS_END)) {
572 if_printf(&sc->ifatm.ifnet, "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->ifatm.ifnet, "cid=%#x not closed (TSR0=%#x)\n",
579 cid, v);
580 return (EBUSY);
581 }
582
583 /* check traffic parameters */
584 line_rate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M;
585 switch (vcc->param.traffic) {
586
587 case ATMIO_TRAFFIC_UBR:
588 if (t->pcr == 0 || t->pcr > line_rate)
589 t->pcr = line_rate;
590 if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 ||
591 t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 ||
592 t->cdf != 0)
593 return (EINVAL);
594 break;
595
596 case ATMIO_TRAFFIC_CBR:
597 /*
598 * Compute rate group index
599 */
600 if (t->pcr < 10)
601 t->pcr = 10;
602 if (sc->cbr_bw + t->pcr > line_rate)
603 return (EINVAL);
604 if (t->mcr != 0 || t->icr != 0 || t->tbe != 0 || t->nrm != 0 ||
605 t->trm != 0 || t->adtf != 0 || t->rif != 0 || t->rdf != 0 ||
606 t->cdf != 0)
607 return (EINVAL);
608
609 rc = cps_to_rate(sc, t->pcr);
610 free_idx = HE_REGN_CS_STPER;
611 for (idx = 0; idx < HE_REGN_CS_STPER; idx++) {
612 if (sc->rate_ctrl[idx].refcnt == 0) {
613 if (free_idx == HE_REGN_CS_STPER)
614 free_idx = idx;
615 } else {
616 if (sc->rate_ctrl[idx].rate == rc)
617 break;
618 }
619 }
620 if (idx == HE_REGN_CS_STPER) {
621 if ((idx = free_idx) == HE_REGN_CS_STPER)
622 return (EBUSY);
623 sc->rate_ctrl[idx].rate = rc;
624 }
625 vcc->rc = idx;
626
627 /* commit */
628 sc->rate_ctrl[idx].refcnt++;
629 sc->cbr_bw += t->pcr;
630 break;
631
632 case ATMIO_TRAFFIC_ABR:
633 if (t->pcr > line_rate)
634 t->pcr = line_rate;
635 if (t->mcr > line_rate)
636 t->mcr = line_rate;
637 if (t->icr > line_rate)
638 t->icr = line_rate;
639 if (t->tbe == 0 || t->tbe >= 1 << 24 || t->nrm > 7 ||
640 t->trm > 7 || t->adtf >= 1 << 10 || t->rif > 15 ||
641 t->rdf > 15 || t->cdf > 7)
642 return (EINVAL);
643 break;
644
645 default:
646 return (EINVAL);
647 }
648 return (0);
649}
650
651#define NRM_CODE2VAL(CODE) (2 * (1 << (CODE)))
652
653/*
654 * Actually open the transmit VCC
655 */
656void
657hatm_tx_vcc_open(struct hatm_softc *sc, u_int cid)
658{
659 struct hevcc *vcc = sc->vccs[cid];
660 uint32_t tsr0, tsr4, atmf, crm;
661 const struct atmio_tparam *t = &vcc->param.tparam;
662
663 if (vcc->param.aal == ATMIO_AAL_5) {
664 tsr0 = HE_REGM_TSR0_AAL_5 << HE_REGS_TSR0_AAL;
665 tsr4 = HE_REGM_TSR4_AAL_5 << HE_REGS_TSR4_AAL;
666 } else {
667 tsr0 = HE_REGM_TSR0_AAL_0 << HE_REGS_TSR0_AAL;
668 tsr4 = HE_REGM_TSR4_AAL_0 << HE_REGS_TSR4_AAL;
669 }
670 tsr4 |= 1;
671
672 switch (vcc->param.traffic) {
673
674 case ATMIO_TRAFFIC_UBR:
675 atmf = hatm_cps2atmf(t->pcr);
676
677 tsr0 |= HE_REGM_TSR0_TRAFFIC_UBR << HE_REGS_TSR0_TRAFFIC;
678 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER;
679
680 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
681 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
682 WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR));
683 WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR));
684 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
685 WRITE_TSR(sc, cid, 3, 0xf, 0);
686 WRITE_TSR(sc, cid, 5, 0xf, 0);
687 WRITE_TSR(sc, cid, 6, 0xf, 0);
688 WRITE_TSR(sc, cid, 7, 0xf, 0);
689 WRITE_TSR(sc, cid, 8, 0xf, 0);
690 WRITE_TSR(sc, cid, 10, 0xf, 0);
691 WRITE_TSR(sc, cid, 11, 0xf, 0);
692 WRITE_TSR(sc, cid, 12, 0xf, 0);
693 WRITE_TSR(sc, cid, 13, 0xf, 0);
694 WRITE_TSR(sc, cid, 14, 0xf, 0);
695 break;
696
697 case ATMIO_TRAFFIC_CBR:
698 atmf = hatm_cps2atmf(t->pcr);
699
700 if (sc->rate_ctrl[vcc->rc].refcnt == 1)
701 WRITE_MBOX4(sc, HE_REGO_CS_STPER(vcc->rc),
702 sc->rate_ctrl[vcc->rc].rate);
703
704 tsr0 |= HE_REGM_TSR0_TRAFFIC_CBR << HE_REGS_TSR0_TRAFFIC;
705 tsr0 |= vcc->rc;
706
707 WRITE_TSR(sc, cid, 1, 0xf, (atmf << HE_REGS_TSR1_PCR));
708 WRITE_TSR(sc, cid, 2, 0xf, (atmf << HE_REGS_TSR2_ACR));
709 WRITE_TSR(sc, cid, 3, 0xf, 0);
710 WRITE_TSR(sc, cid, 5, 0xf, 0);
711 WRITE_TSR(sc, cid, 6, 0xf, 0);
712 WRITE_TSR(sc, cid, 7, 0xf, 0);
713 WRITE_TSR(sc, cid, 8, 0xf, 0);
714 WRITE_TSR(sc, cid, 10, 0xf, 0);
715 WRITE_TSR(sc, cid, 11, 0xf, 0);
716 WRITE_TSR(sc, cid, 12, 0xf, 0);
717 WRITE_TSR(sc, cid, 13, 0xf, 0);
718 WRITE_TSR(sc, cid, 14, 0xf, 0);
719 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
720 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
721 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
722
723 break;
724
725 case ATMIO_TRAFFIC_ABR:
726 if ((crm = t->tbe / NRM_CODE2VAL(t->nrm)) > 0xffff)
727 crm = 0xffff;
728
729 tsr0 |= HE_REGM_TSR0_TRAFFIC_ABR << HE_REGS_TSR0_TRAFFIC;
730 tsr0 |= HE_REGM_TSR0_USE_WMIN | HE_REGM_TSR0_UPDATE_GER;
731
732 WRITE_TSR(sc, cid, 0, 0xf, tsr0);
733 WRITE_TSR(sc, cid, 4, 0xf, tsr4);
734
735 WRITE_TSR(sc, cid, 1, 0xf,
736 ((hatm_cps2atmf(t->pcr) << HE_REGS_TSR1_PCR) |
737 (hatm_cps2atmf(t->mcr) << HE_REGS_TSR1_MCR)));
738 WRITE_TSR(sc, cid, 2, 0xf,
739 (hatm_cps2atmf(t->icr) << HE_REGS_TSR2_ACR));
740 WRITE_TSR(sc, cid, 3, 0xf,
741 ((NRM_CODE2VAL(t->nrm) - 1) << HE_REGS_TSR3_NRM) |
742 (crm << HE_REGS_TSR3_CRM));
743
744 WRITE_TSR(sc, cid, 5, 0xf, 0);
745 WRITE_TSR(sc, cid, 6, 0xf, 0);
746 WRITE_TSR(sc, cid, 7, 0xf, 0);
747 WRITE_TSR(sc, cid, 8, 0xf, 0);
748 WRITE_TSR(sc, cid, 10, 0xf, 0);
749 WRITE_TSR(sc, cid, 12, 0xf, 0);
750 WRITE_TSR(sc, cid, 14, 0xf, 0);
751 WRITE_TSR(sc, cid, 9, 0xf, HE_REGM_TSR9_INIT);
752
753 WRITE_TSR(sc, cid, 11, 0xf,
754 (hatm_cps2atmf(t->icr) << HE_REGS_TSR11_ICR) |
755 (t->trm << HE_REGS_TSR11_TRM) |
756 (t->nrm << HE_REGS_TSR11_NRM) |
757 (t->adtf << HE_REGS_TSR11_ADTF));
758
759 WRITE_TSR(sc, cid, 13, 0xf,
760 (t->rdf << HE_REGS_TSR13_RDF) |
761 (t->rif << HE_REGS_TSR13_RIF) |
762 (t->cdf << HE_REGS_TSR13_CDF) |
763 (crm << HE_REGS_TSR13_CRM));
764
765 break;
766
767 default:
768 return;
769 }
770
771 vcc->vflags |= HE_VCC_TX_OPEN;
772}
773
774/*
775 * Close the TX side of a VCC. Set the CLOSING flag.
776 */
777void
778hatm_tx_vcc_close(struct hatm_softc *sc, u_int cid)
779{
780 struct hevcc *vcc = sc->vccs[cid];
781 struct tpd *tpd_list[1];
782 u_int i, pcr = 0;
783
784 WRITE_TSR(sc, cid, 4, 0x8, HE_REGM_TSR4_FLUSH);
785
786 switch (vcc->param.traffic) {
787
788 case ATMIO_TRAFFIC_CBR:
789 WRITE_TSR(sc, cid, 14, 0x8, HE_REGM_TSR14_CBR_DELETE);
790 break;
791
792 case ATMIO_TRAFFIC_ABR:
793 WRITE_TSR(sc, cid, 14, 0x4, HE_REGM_TSR14_ABR_CLOSE);
794 pcr = vcc->param.tparam.pcr;
795 /* FALL THROUGH */
796
797 case ATMIO_TRAFFIC_UBR:
798 WRITE_TSR(sc, cid, 1, 0xf,
799 hatm_cps2atmf(HE_CONFIG_FLUSH_RATE) << HE_REGS_TSR1_MCR |
800 hatm_cps2atmf(pcr) << HE_REGS_TSR1_PCR);
801 break;
802 }
803
804 tpd_list[0] = hatm_alloc_tpd(sc, 0);
805 tpd_list[0]->tpd.addr |= HE_REGM_TPD_EOS | HE_REGM_TPD_INTR;
806 tpd_list[0]->cid = cid;
807
808 vcc->vflags |= HE_VCC_TX_CLOSING;
809 vcc->vflags &= ~HE_VCC_TX_OPEN;
810
811 i = 0;
812 while (hatm_queue_tpds(sc, 1, tpd_list, cid) != 0) {
813 if (++i == 1000)
814 panic("TPDRQ permanently full");
815 DELAY(1000);
816 }
817}
818
819void
820hatm_tx_vcc_closed(struct hatm_softc *sc, u_int cid)
821{
822 if (sc->vccs[cid]->param.traffic == ATMIO_TRAFFIC_CBR) {
823 sc->cbr_bw -= sc->vccs[cid]->param.tparam.pcr;
824 sc->rate_ctrl[sc->vccs[cid]->rc].refcnt--;
825 }
826}