3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * Author: Hartmut Brandt <harti@freebsd.org>
29 * Driver for IDT77252 based cards like ProSum's.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/kernel.h>
46 #include <sys/errno.h>
48 #include <sys/module.h>
50 #include <sys/mutex.h>
51 #include <sys/sysctl.h>
52 #include <sys/queue.h>
53 #include <sys/condvar.h>
54 #include <sys/endian.h>
57 #include <sys/sockio.h>
59 #include <sys/socket.h>
62 #include <net/if_media.h>
63 #include <net/if_atm.h>
64 #include <net/route.h>
68 #include <netinet/in.h>
69 #include <netinet/if_atm.h>
71 #include <machine/bus.h>
72 #include <machine/resource.h>
75 #include <sys/mbpool.h>
77 #include <dev/utopia/utopia.h>
78 #include <dev/patm/idt77252reg.h>
79 #include <dev/patm/if_patmvar.h>
81 static void *patm_rcv_handle(struct patm_softc *sc, u_int handle);
82 static void patm_rcv_free(struct patm_softc *, void *, u_int handle);
83 static struct mbuf *patm_rcv_mbuf(struct patm_softc *, void *, u_int, int);
86 rct_write(struct patm_softc *sc, u_int cid, u_int w, u_int val)
88 patm_sram_write(sc, sc->mmap->rct + cid * IDT_RCT_ENTRY_SIZE + w, val);
91 rct_read(struct patm_softc *sc, u_int cid, u_int w)
93 return (patm_sram_read(sc, sc->mmap->rct +
94 cid * IDT_RCT_ENTRY_SIZE + w));
97 /* check if we can open this one */
99 patm_rx_vcc_can_open(struct patm_softc *sc, struct patm_vcc *vcc)
108 patm_rx_vcc_open(struct patm_softc *sc, struct patm_vcc *vcc)
110 uint32_t w1 = IDT_RCT_OPEN;
112 patm_debug(sc, VCC, "%u.%u RX opening", vcc->vcc.vpi, vcc->vcc.vci);
114 switch (vcc->vcc.aal) {
116 w1 |= IDT_RCT_AAL0 | IDT_RCT_FBP2 | IDT_RCT_RCI;
125 w1 |= IDT_RCT_AALRAW | IDT_RCT_RCI;
130 patm_sram_write4(sc, sc->mmap->rct + vcc->cid *
131 IDT_RCT_ENTRY_SIZE, w1, 0, 0, 0xffffffff);
133 /* switch the interface into promiscuous mode */
134 patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) |
135 IDT_CFG_ICAPT | IDT_CFG_VPECA);
138 vcc->vflags |= PATM_VCC_RX_OPEN;
141 /* close the given vcc for transmission */
143 patm_rx_vcc_close(struct patm_softc *sc, struct patm_vcc *vcc)
147 patm_debug(sc, VCC, "%u.%u RX closing", vcc->vcc.vpi, vcc->vcc.vci);
150 /* switch off promiscuous mode */
151 patm_nor_write(sc, IDT_NOR_CFG, patm_nor_read(sc, IDT_NOR_CFG) &
152 ~(IDT_CFG_ICAPT | IDT_CFG_VPECA));
153 vcc->vflags &= ~PATM_VCC_RX_OPEN;
157 /* close the connection but keep state */
158 w1 = rct_read(sc, vcc->cid, 0);
160 rct_write(sc, vcc->cid, 0, w1);
162 /* minimum idle count */
163 w1 = (w1 & ~IDT_RCT_IACT_CNT_MASK) | (1 << IDT_RCT_IACT_CNT_SHIFT);
164 rct_write(sc, vcc->cid, 0, w1);
166 /* initialize scan */
167 patm_nor_write(sc, IDT_NOR_IRCP, vcc->cid);
169 vcc->vflags &= ~PATM_VCC_RX_OPEN;
170 vcc->vflags |= PATM_VCC_RX_CLOSING;
174 * This is a hack. The problem is, that although an entry is written
175 * to the RSQ, no interrupt is generated. Also we must wait 1 cell
176 * time for the SAR to process the scan of our connection.
182 /* transmission side finally closed */
184 patm_rx_vcc_closed(struct patm_softc *sc, struct patm_vcc *vcc)
186 patm_debug(sc, VCC, "%u.%u RX finally closed",
187 vcc->vcc.vpi, vcc->vcc.vci);
191 * Handle the given receive status queue entry
194 patm_rx(struct patm_softc *sc, struct idt_rsqe *rsqe)
198 u_int stat, cid, w, cells, len, h;
199 struct patm_vcc *vcc;
200 struct atm_pseudohdr aph;
203 cid = le32toh(rsqe->cid);
204 stat = le32toh(rsqe->stat);
205 h = le32toh(rsqe->handle);
207 cid = PATM_CID(sc, IDT_RSQE_VPI(cid), IDT_RSQE_VCI(cid));
210 if (IDT_RSQE_TYPE(stat) == IDT_RSQE_IDLE) {
211 /* connection has gone idle */
212 if (stat & IDT_RSQE_BUF)
213 patm_rcv_free(sc, patm_rcv_handle(sc, h), h);
215 w = rct_read(sc, cid, 0);
216 if (w != 0 && !(w & IDT_RCT_OPEN))
217 rct_write(sc, cid, 0, 0);
218 if (vcc != NULL && (vcc->vflags & PATM_VCC_RX_CLOSING)) {
219 patm_debug(sc, VCC, "%u.%u RX closed", vcc->vcc.vpi,
221 vcc->vflags &= ~PATM_VCC_RX_CLOSING;
222 if (vcc->vcc.flags & ATMIO_FLAG_ASYNC) {
223 patm_rx_vcc_closed(sc, vcc);
224 if (!(vcc->vflags & PATM_VCC_OPEN))
225 patm_vcc_closed(sc, vcc);
227 cv_signal(&sc->vcc_cv);
232 buf = patm_rcv_handle(sc, h);
234 if (vcc == NULL || (vcc->vflags & PATM_VCC_RX_OPEN) == 0) {
235 patm_rcv_free(sc, buf, h);
239 cells = IDT_RSQE_CNT(stat);
240 KASSERT(cells > 0, ("zero cell count"));
242 if (vcc->vcc.aal == ATMIO_AAL_0) {
243 /* deliver this packet as it is */
244 if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
247 m->m_len = cells * 48;
248 m->m_pkthdr.len = m->m_len;
249 m->m_pkthdr.rcvif = &sc->ifatm.ifnet;
251 } else if (vcc->vcc.aal == ATMIO_AAL_34) {
253 patm_rcv_free(sc, buf, h);
256 } else if (vcc->vcc.aal == ATMIO_AAL_5) {
257 if (stat & IDT_RSQE_CRC) {
258 sc->ifatm.ifnet.if_ierrors++;
259 if (vcc->chain != NULL) {
261 vcc->chain = vcc->last = NULL;
266 /* append to current chain */
267 if (vcc->chain == NULL) {
268 if ((m = patm_rcv_mbuf(sc, buf, h, 1)) == NULL)
270 m->m_len = cells * 48;
271 m->m_pkthdr.len = m->m_len;
272 m->m_pkthdr.rcvif = &sc->ifatm.ifnet;
273 vcc->chain = vcc->last = m;
275 if ((m = patm_rcv_mbuf(sc, buf, h, 0)) == NULL)
277 m->m_len = cells * 48;
278 vcc->last->m_next = m;
280 vcc->chain->m_pkthdr.len += m->m_len;
283 if (!(stat & IDT_RSQE_EPDU))
286 trail = mtod(m, u_char *) + m->m_len - 6;
287 len = (trail[0] << 8) + trail[1];
289 if ((u_int)vcc->chain->m_pkthdr.len < len + 8) {
290 patm_printf(sc, "%s: bad aal5 lengths %u %u\n",
291 __func__, (u_int)m->m_pkthdr.len, len);
293 vcc->chain = vcc->last = NULL;
296 m->m_len -= vcc->chain->m_pkthdr.len - len;
297 KASSERT(m->m_len >= 0, ("bad last mbuf"));
300 vcc->chain = vcc->last = NULL;
301 m->m_pkthdr.len = len;
309 for (i = 0; i < m->m_len; i++) {
310 printf("%02x ", mtod(m, u_char *)[i]);
316 sc->ifatm.ifnet.if_ipackets++;
317 /* this is in if_atmsubr.c */
318 /* sc->ifatm.ifnet.if_ibytes += m->m_pkthdr.len; */
320 vcc->ibytes += m->m_pkthdr.len;
323 ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
324 ATM_PH_VPI(&aph) = IDT_RSQE_VPI(cid);
325 ATM_PH_SETVCI(&aph, IDT_RSQE_VCI(cid));
328 if (!(vcc->vcc.flags & ATMIO_FLAG_NG) &&
329 (vcc->vcc.aal == ATMIO_AAL_5) &&
330 (vcc->vcc.flags & ATM_PH_LLCSNAP))
331 BPF_MTAP(&sc->ifatm.ifnet, m);
334 atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand);
338 * Get the buffer for a receive handle. This is either an mbuf for
339 * a large handle or a pool buffer for the others.
342 patm_rcv_handle(struct patm_softc *sc, u_int handle)
347 if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE) {
350 c = handle & MBUF_HMASK;
356 bus_dmamap_sync(sc->lbuf_tag, b->map, BUS_DMASYNC_POSTREAD);
357 patm_lbuf_free(sc, b);
359 } else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE) {
360 mbp_sync(sc->vbuf_pool, handle,
361 0, VMBUF_SIZE, BUS_DMASYNC_POSTREAD);
362 buf = mbp_get(sc->vbuf_pool, handle);
365 mbp_sync(sc->sbuf_pool, handle,
366 0, SMBUF_SIZE, BUS_DMASYNC_POSTREAD);
367 buf = mbp_get(sc->sbuf_pool, handle);
377 patm_rcv_free(struct patm_softc *sc, void *p, u_int handle)
379 if ((handle & ~MBUF_HMASK) == LMBUF_HANDLE)
380 m_free((struct mbuf *)p);
382 else if ((handle & ~MBUF_HMASK) == MBUF_VHANDLE)
383 mbp_free(sc->vbuf_pool, p);
386 mbp_free(sc->sbuf_pool, p);
390 * Make an mbuf around the buffer
393 patm_rcv_mbuf(struct patm_softc *sc, void *buf, u_int h, int hdr)
397 if ((h & ~MBUF_HMASK) == MBUF_LHANDLE)
398 return ((struct mbuf *)buf);
401 MGETHDR(m, M_DONTWAIT, MT_DATA);
403 MGET(m, M_DONTWAIT, MT_DATA);
405 patm_rcv_free(sc, buf, h);
409 if ((h & ~MBUF_HMASK) == MBUF_VHANDLE) {
410 m_extadd(m, (caddr_t)buf, VMBUF_SIZE, mbp_ext_free,
411 sc->vbuf_pool, M_PKTHDR, EXT_NET_DRV);
412 m->m_data += VMBUF_OFFSET;
414 m_extadd(m, (caddr_t)buf, SMBUF_SIZE, mbp_ext_free,
415 sc->sbuf_pool, M_PKTHDR, EXT_NET_DRV);
416 m->m_data += SMBUF_OFFSET;
419 if (!(m->m_flags & M_EXT)) {
420 patm_rcv_free(sc, buf, h);
428 * Process the raw cell at the given address.
431 patm_rx_raw(struct patm_softc *sc, u_char *cell)
434 struct patm_vcc *vcc;
438 struct atm_pseudohdr aph;
441 sc->stats.raw_cells++;
444 * For some non-appearant reason the cell header
445 * is in the wrong endian.
447 *(uint32_t *)cell = bswap32(*(uint32_t *)cell);
449 vpi = ((cell[0] & 0xf) << 4) | ((cell[1] & 0xf0) >> 4);
450 vci = ((cell[1] & 0xf) << 12) | (cell[2] << 4) | ((cell[3] & 0xf0) >> 4);
451 cid = PATM_CID(sc, vpi, vci);
454 if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN) ||
455 vcc->vcc.aal != ATMIO_AAL_RAW) {
457 if (vcc == NULL || !(vcc->vflags & PATM_VCC_RX_OPEN)) {
458 sc->stats.raw_no_vcc++;
463 MGETHDR(m, M_DONTWAIT, MT_DATA);
465 sc->stats.raw_no_buf++;
468 m->m_pkthdr.rcvif = &sc->ifatm.ifnet;
470 switch (vcc->vflags & PATM_RAW_FORMAT) {
474 m->m_len = m->m_pkthdr.len = 53;
476 dst = mtod(m, u_char *);
481 *dst++ = 0; /* HEC */
482 bcopy(cell + 12, dst, 48);
486 m->m_len = m->m_pkthdr.len = 52;
488 dst = mtod(m, u_char *);
493 bcopy(cell + 12, dst, 48);
497 m->m_len = m->m_pkthdr.len = 64;
499 dst = mtod(m, u_char *);
504 *dst++ = 0; /* HEC */
505 *dst++ = 0; /* flags */
506 *dst++ = 0; /* reserved */
507 *dst++ = 0; /* reserved */
509 cts = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
511 bcopy(cell + 12, dst + 8, 48);
515 sc->ifatm.ifnet.if_ipackets++;
516 /* this is in if_atmsubr.c */
517 /* sc->ifatm.ifnet.if_ibytes += m->m_pkthdr.len; */
519 vcc->ibytes += m->m_pkthdr.len;
522 ATM_PH_FLAGS(&aph) = vcc->vcc.flags & 0xff;
523 ATM_PH_VPI(&aph) = vcc->vcc.vpi;
524 ATM_PH_SETVCI(&aph, vcc->vcc.vci);
526 atm_input(&sc->ifatm.ifnet, &aph, m, vcc->rxhand);