Deleted Added
full compact
pdq_ifsubr.c (91439) pdq_ifsubr.c (93383)
1/* $NetBSD: pdq_ifsubr.c,v 1.38 2001/12/21 23:21:47 matt Exp $ */
2
1/*-
2 * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. The name of the author may not be used to endorse or promote products
3/*-
4 * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the author may not be used to endorse or promote products
11 * derived from this software withough specific prior written permission
13 * derived from this software without specific prior written permission
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
24 * $FreeBSD: head/sys/dev/pdq/pdq_ifsubr.c 91439 2002-02-27 23:28:57Z peter $
25 *
26 * $NetBSD: pdq_ifsubr.c,v 1.12 1997/06/05 01:56:35 thomas Exp$
27 * $FreeBSD: head/sys/dev/pdq/pdq_ifsubr.c 93383 2002-03-29 11:22:22Z mdodd $
26 */
27
28/*
29 * DEC PDQ FDDI Controller; code for BSD derived operating systems
30 *
31 * This module provide bus independent BSD specific O/S functions.
32 * (ie. it provides an ifnet interface to the rest of the system)
33 */
34
28 */
29
30/*
31 * DEC PDQ FDDI Controller; code for BSD derived operating systems
32 *
33 * This module provide bus independent BSD specific O/S functions.
34 * (ie. it provides an ifnet interface to the rest of the system)
35 */
36
37#ifdef __NetBSD__
38#include <sys/cdefs.h>
39__KERNEL_RCSID(0, "$NetBSD: pdq_ifsubr.c,v 1.38 2001/12/21 23:21:47 matt Exp $");
40#endif
35
41
36#include "opt_inet.h"
42#define PDQ_OSSUPPORT
37
38#include <sys/param.h>
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/kernel.h>
47#include <sys/lock.h>
48#include <sys/mutex.h>
49#include <sys/malloc.h>
39#include <sys/socket.h>
40#include <sys/sockio.h>
50#include <sys/socket.h>
51#include <sys/sockio.h>
41#if defined(__bsdi__) || defined(__NetBSD__)
42#include <sys/device.h>
43#endif
44
52
53#include <sys/module.h>
54#include <sys/bus.h>
55
56#include <machine/bus_memio.h>
57#include <machine/bus_pio.h>
58#include <machine/bus.h>
59#include <machine/resource.h>
60#include <sys/rman.h>
61
45#include <net/if.h>
62#include <net/if.h>
63#include <net/if_arp.h>
46#include <net/if_dl.h>
64#include <net/if_dl.h>
65#include <net/if_media.h>
66#include <net/fddi.h>
47
48#include <net/bpf.h>
49
67
68#include <net/bpf.h>
69
50#if defined(__FreeBSD__)
51#ifdef INET
52#include <netinet/in.h>
53#include <netinet/if_ether.h>
54#endif
55#include <netinet/if_fddi.h>
56#else
57#include <net/if_fddi.h>
58#endif
59
60#if defined(__bsdi__)
61#include <i386/isa/isavar.h>
62#endif
63
64#ifdef NS
65#include <netns/ns.h>
66#include <netns/ns_if.h>
67#endif
68
69#if defined(__FreeBSD__)
70#include <dev/pdq/pdqvar.h>
70#include <dev/pdq/pdq_freebsd.h>
71#include <dev/pdq/pdqreg.h>
71#include <dev/pdq/pdqreg.h>
72#else
73#include "pdqvar.h"
74#include "pdqreg.h"
75#endif
76
72
77#if defined(__bsdi__) && _BSDI_VERSION < 199506 /* XXX */
78static void
79arp_ifinit(
80 struct arpcom *ac,
81 struct ifaddr *ifa)
82{
83 sc->sc_ac.ac_ipaddr = IA_SIN(ifa)->sin_addr;
84 arpwhohas(&sc->sc_ac, &IA_SIN(ifa)->sin_addr);
85#if _BSDI_VERSION >= 199401
86 ifa->ifa_rtrequest = arp_rtrequest;
87 ifa->ifa_flags |= RTF_CLONING;
88#endif
89}
90#endif
73devclass_t pdq_devclass;
91
74
92
93void
75static void
94pdq_ifinit(
95 pdq_softc_t *sc)
96{
97 if (sc->sc_if.if_flags & IFF_UP) {
98 sc->sc_if.if_flags |= IFF_RUNNING;
99 if (sc->sc_if.if_flags & IFF_PROMISC) {
100 sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
101 } else {
102 sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
103 }
76pdq_ifinit(
77 pdq_softc_t *sc)
78{
79 if (sc->sc_if.if_flags & IFF_UP) {
80 sc->sc_if.if_flags |= IFF_RUNNING;
81 if (sc->sc_if.if_flags & IFF_PROMISC) {
82 sc->sc_pdq->pdq_flags |= PDQ_PROMISC;
83 } else {
84 sc->sc_pdq->pdq_flags &= ~PDQ_PROMISC;
85 }
104 if (sc->sc_if.if_flags & IFF_ALLMULTI) {
105 sc->sc_pdq->pdq_flags |= PDQ_ALLMULTI;
106 } else {
107 sc->sc_pdq->pdq_flags &= ~PDQ_ALLMULTI;
108 }
109 if (sc->sc_if.if_flags & IFF_LINK1) {
110 sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
111 } else {
112 sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
113 }
114 sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
115 pdq_run(sc->sc_pdq);
116 } else {
117 sc->sc_if.if_flags &= ~IFF_RUNNING;
118 sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
119 pdq_stop(sc->sc_pdq);
120 }
121}
122
86 if (sc->sc_if.if_flags & IFF_LINK1) {
87 sc->sc_pdq->pdq_flags |= PDQ_PASS_SMT;
88 } else {
89 sc->sc_pdq->pdq_flags &= ~PDQ_PASS_SMT;
90 }
91 sc->sc_pdq->pdq_flags |= PDQ_RUNNING;
92 pdq_run(sc->sc_pdq);
93 } else {
94 sc->sc_if.if_flags &= ~IFF_RUNNING;
95 sc->sc_pdq->pdq_flags &= ~PDQ_RUNNING;
96 pdq_stop(sc->sc_pdq);
97 }
98}
99
123void
100static void
124pdq_ifwatchdog(
125 struct ifnet *ifp)
126{
127 /*
128 * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
129 * seconds. Remove all queued packets.
130 */
131
132 ifp->if_flags &= ~IFF_OACTIVE;
133 ifp->if_timer = 0;
101pdq_ifwatchdog(
102 struct ifnet *ifp)
103{
104 /*
105 * No progress was made on the transmit queue for PDQ_OS_TX_TRANSMIT
106 * seconds. Remove all queued packets.
107 */
108
109 ifp->if_flags &= ~IFF_OACTIVE;
110 ifp->if_timer = 0;
134 IF_DRAIN(&ifp->if_snd);
111 for (;;) {
112 struct mbuf *m;
113 IFQ_DEQUEUE(&ifp->if_snd, m);
114 if (m == NULL)
115 return;
116 PDQ_OS_DATABUF_FREE(PDQ_OS_IFP_TO_SOFTC(ifp)->sc_pdq, m);
117 }
135}
136
118}
119
137ifnet_ret_t
120static void
138pdq_ifstart(
139 struct ifnet *ifp)
140{
121pdq_ifstart(
122 struct ifnet *ifp)
123{
141 pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_ac.ac_if));
142 struct ifqueue *ifq = &ifp->if_snd;
124 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
143 struct mbuf *m;
144 int tx = 0;
145
146 if ((ifp->if_flags & IFF_RUNNING) == 0)
147 return;
148
149 if (sc->sc_if.if_timer == 0)
150 sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
151
152 if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
153 sc->sc_if.if_flags |= IFF_OACTIVE;
154 return;
155 }
125 struct mbuf *m;
126 int tx = 0;
127
128 if ((ifp->if_flags & IFF_RUNNING) == 0)
129 return;
130
131 if (sc->sc_if.if_timer == 0)
132 sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
133
134 if ((sc->sc_pdq->pdq_flags & PDQ_TXOK) == 0) {
135 sc->sc_if.if_flags |= IFF_OACTIVE;
136 return;
137 }
138 sc->sc_flags |= PDQIF_DOWNCALL;
156 for (;; tx = 1) {
139 for (;; tx = 1) {
157 IF_DEQUEUE(ifq, m);
140 IF_DEQUEUE(&ifp->if_snd, m);
158 if (m == NULL)
159 break;
141 if (m == NULL)
142 break;
143#if defined(PDQ_BUS_DMA) && !defined(PDQ_BUS_DMA_NOTX)
144 if ((m->m_flags & M_HASTXDMAMAP) == 0) {
145 bus_dmamap_t map;
146 if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
147 m->m_data[0] = PDQ_FDDI_PH0;
148 m->m_data[1] = PDQ_FDDI_PH1;
149 m->m_data[2] = PDQ_FDDI_PH2;
150 }
151 if (!bus_dmamap_create(sc->sc_dmatag, m->m_pkthdr.len, 255,
152 m->m_pkthdr.len, 0, BUS_DMA_NOWAIT, &map)) {
153 if (!bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
154 BUS_DMA_WRITE|BUS_DMA_NOWAIT)) {
155 bus_dmamap_sync(sc->sc_dmatag, map, 0, m->m_pkthdr.len,
156 BUS_DMASYNC_PREWRITE);
157 M_SETCTX(m, map);
158 m->m_flags |= M_HASTXDMAMAP;
159 }
160 }
161 if ((m->m_flags & M_HASTXDMAMAP) == 0)
162 break;
163 }
164#else
165 if (PDQ_OS_HDR_OFFSET != PDQ_RX_FC_OFFSET) {
166 m->m_data[0] = PDQ_FDDI_PH0;
167 m->m_data[1] = PDQ_FDDI_PH1;
168 m->m_data[2] = PDQ_FDDI_PH2;
169 }
170#endif
160
171
161 if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE) {
162 ifp->if_flags |= IFF_OACTIVE;
163 IF_PREPEND(ifq, m);
172 if (pdq_queue_transmit_data(sc->sc_pdq, m) == PDQ_FALSE)
164 break;
173 break;
165 }
166 }
174 }
175 if (m != NULL) {
176 ifp->if_flags |= IFF_OACTIVE;
177 IF_PREPEND(&ifp->if_snd, m);
178 }
167 if (tx)
168 PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
179 if (tx)
180 PDQ_DO_TYPE2_PRODUCER(sc->sc_pdq);
181 sc->sc_flags &= ~PDQIF_DOWNCALL;
169}
170
171void
172pdq_os_receive_pdu(
173 pdq_t *pdq,
174 struct mbuf *m,
182}
183
184void
185pdq_os_receive_pdu(
186 pdq_t *pdq,
187 struct mbuf *m,
175 size_t pktlen)
188 size_t pktlen,
189 int drop)
176{
190{
177 pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
178 struct fddi_header *fh = mtod(m, struct fddi_header *);
191 pdq_softc_t *sc = pdq->pdq_os_ctx;
192 struct fddi_header *fh;
179
180 sc->sc_if.if_ipackets++;
193
194 sc->sc_if.if_ipackets++;
195#if defined(PDQ_BUS_DMA)
196 {
197 /*
198 * Even though the first mbuf start at the first fddi header octet,
199 * the dmamap starts PDQ_OS_HDR_OFFSET octets earlier. Any additional
200 * mbufs will start normally.
201 */
202 int offset = PDQ_OS_HDR_OFFSET;
203 struct mbuf *m0;
204 for (m0 = m; m0 != NULL; m0 = m0->m_next, offset = 0) {
205 pdq_os_databuf_sync(sc, m0, offset, m0->m_len, BUS_DMASYNC_POSTREAD);
206 bus_dmamap_unload(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
207 bus_dmamap_destroy(sc->sc_dmatag, M_GETCTX(m0, bus_dmamap_t));
208 m0->m_flags &= ~M_HASRXDMAMAP;
209 M_SETCTX(m0, NULL);
210 }
211 }
212#endif
213 m->m_pkthdr.len = pktlen;
214#if NBPFILTER > 0
181 if (sc->sc_bpf != NULL)
182 PDQ_BPF_MTAP(sc, m);
215 if (sc->sc_bpf != NULL)
216 PDQ_BPF_MTAP(sc, m);
183 if ((fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
184 m_freem(m);
217#endif
218 fh = mtod(m, struct fddi_header *);
219 if (drop || (fh->fddi_fc & (FDDIFC_L|FDDIFC_F)) != FDDIFC_LLC_ASYNC) {
220 sc->sc_if.if_iqdrops++;
221 sc->sc_if.if_ierrors++;
222 PDQ_OS_DATABUF_FREE(pdq, m);
185 return;
186 }
187
223 return;
224 }
225
188 m->m_data += sizeof(struct fddi_header);
189 m->m_len -= sizeof(struct fddi_header);
190 m->m_pkthdr.len = pktlen - sizeof(struct fddi_header);
226 m_adj(m, FDDI_HDR_LEN);
191 m->m_pkthdr.rcvif = &sc->sc_if;
192 fddi_input(&sc->sc_if, fh, m);
193}
194
195void
196pdq_os_restart_transmitter(
197 pdq_t *pdq)
198{
227 m->m_pkthdr.rcvif = &sc->sc_if;
228 fddi_input(&sc->sc_if, fh, m);
229}
230
231void
232pdq_os_restart_transmitter(
233 pdq_t *pdq)
234{
199 pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
235 pdq_softc_t *sc = pdq->pdq_os_ctx;
200 sc->sc_if.if_flags &= ~IFF_OACTIVE;
236 sc->sc_if.if_flags &= ~IFF_OACTIVE;
201 if (sc->sc_if.if_snd.ifq_head != NULL) {
237 if (IFQ_IS_EMPTY(&sc->sc_if.if_snd) == 0) {
202 sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
238 sc->sc_if.if_timer = PDQ_OS_TX_TIMEOUT;
203 pdq_ifstart(&sc->sc_if);
239 if ((sc->sc_flags & PDQIF_DOWNCALL) == 0)
240 pdq_ifstart(&sc->sc_if);
204 } else {
205 sc->sc_if.if_timer = 0;
206 }
207}
208
209void
210pdq_os_transmit_done(
211 pdq_t *pdq,
212 struct mbuf *m)
213{
241 } else {
242 sc->sc_if.if_timer = 0;
243 }
244}
245
246void
247pdq_os_transmit_done(
248 pdq_t *pdq,
249 struct mbuf *m)
250{
214 pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
251 pdq_softc_t *sc = pdq->pdq_os_ctx;
252#if NBPFILTER > 0
215 if (sc->sc_bpf != NULL)
216 PDQ_BPF_MTAP(sc, m);
253 if (sc->sc_bpf != NULL)
254 PDQ_BPF_MTAP(sc, m);
217 m_freem(m);
255#endif
256 PDQ_OS_DATABUF_FREE(pdq, m);
218 sc->sc_if.if_opackets++;
219}
220
221void
222pdq_os_addr_fill(
223 pdq_t *pdq,
224 pdq_lanaddr_t *addr,
225 size_t num_addrs)
226{
257 sc->sc_if.if_opackets++;
258}
259
260void
261pdq_os_addr_fill(
262 pdq_t *pdq,
263 pdq_lanaddr_t *addr,
264 size_t num_addrs)
265{
227 pdq_softc_t *sc = (pdq_softc_t *) pdq->pdq_os_ctx;
266 pdq_softc_t *sc = pdq->pdq_os_ctx;
267 struct ifnet *ifp;
228 struct ifmultiaddr *ifma;
229
268 struct ifmultiaddr *ifma;
269
270 ifp = &sc->arpcom.ac_if;
271
272 /*
273 * ADDR_FILTER_SET is always issued before FILTER_SET so
274 * we can play with PDQ_ALLMULTI and not worry about
275 * queueing a FILTER_SET ourselves.
276 */
277
278 pdq->pdq_flags &= ~PDQ_ALLMULTI;
279#if defined(IFF_ALLMULTI)
280 sc->sc_if.if_flags &= ~IFF_ALLMULTI;
281#endif
282
230 for (ifma = TAILQ_FIRST(&sc->sc_if.if_multiaddrs); ifma && num_addrs > 0;
231 ifma = TAILQ_NEXT(ifma, ifma_link)) {
232 char *mcaddr;
233 if (ifma->ifma_addr->sa_family != AF_LINK)
234 continue;
235 mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
236 ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) mcaddr)[0];
237 ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) mcaddr)[1];
238 ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) mcaddr)[2];
239 addr++;
240 num_addrs--;
241 }
283 for (ifma = TAILQ_FIRST(&sc->sc_if.if_multiaddrs); ifma && num_addrs > 0;
284 ifma = TAILQ_NEXT(ifma, ifma_link)) {
285 char *mcaddr;
286 if (ifma->ifma_addr->sa_family != AF_LINK)
287 continue;
288 mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
289 ((u_short *) addr->lanaddr_bytes)[0] = ((u_short *) mcaddr)[0];
290 ((u_short *) addr->lanaddr_bytes)[1] = ((u_short *) mcaddr)[1];
291 ((u_short *) addr->lanaddr_bytes)[2] = ((u_short *) mcaddr)[2];
292 addr++;
293 num_addrs--;
294 }
295 /*
296 * If not all the address fit into the CAM, turn on all-multicast mode.
297 */
298 if (ifma != NULL) {
299 pdq->pdq_flags |= PDQ_ALLMULTI;
300#if defined(IFF_ALLMULTI)
301 sc->sc_if.if_flags |= IFF_ALLMULTI;
302#endif
303 }
242}
243
304}
305
244int
245pdq_ifioctl(
306#if defined(IFM_FDDI)
307static int
308pdq_ifmedia_change(
309 struct ifnet *ifp)
310{
311 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
312
313 if (sc->sc_ifmedia.ifm_media & IFM_FDX) {
314 if ((sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) == 0) {
315 sc->sc_pdq->pdq_flags |= PDQ_WANT_FDX;
316 if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
317 pdq_run(sc->sc_pdq);
318 }
319 } else if (sc->sc_pdq->pdq_flags & PDQ_WANT_FDX) {
320 sc->sc_pdq->pdq_flags &= ~PDQ_WANT_FDX;
321 if (sc->sc_pdq->pdq_flags & PDQ_RUNNING)
322 pdq_run(sc->sc_pdq);
323 }
324
325 return 0;
326}
327
328static void
329pdq_ifmedia_status(
246 struct ifnet *ifp,
330 struct ifnet *ifp,
247 ioctl_cmd_t cmd,
248 caddr_t data)
331 struct ifmediareq *ifmr)
249{
332{
250 pdq_softc_t *sc = (pdq_softc_t *) ((caddr_t) ifp - offsetof(pdq_softc_t, sc_ac.ac_if));
251 int s, error = 0;
333 pdq_softc_t * const sc = PDQ_OS_IFP_TO_SOFTC(ifp);
252
334
253 s = splimp();
335 ifmr->ifm_status = IFM_AVALID;
336 if (sc->sc_pdq->pdq_flags & PDQ_IS_ONRING)
337 ifmr->ifm_status |= IFM_ACTIVE;
254
338
255 switch (cmd) {
256 case SIOCSIFADDR: {
257 struct ifaddr *ifa = (struct ifaddr *)data;
339 ifmr->ifm_active = (ifmr->ifm_current & ~IFM_FDX);
340 if (sc->sc_pdq->pdq_flags & PDQ_IS_FDX)
341 ifmr->ifm_active |= IFM_FDX;
342}
258
343
259 ifp->if_flags |= IFF_UP;
260 switch(ifa->ifa_addr->sa_family) {
261#if defined(INET)
262 case AF_INET: {
263 pdq_ifinit(sc);
264 arp_ifinit(&sc->sc_ac.ac_if, ifa);
265 break;
266 }
267#endif /* INET */
344void
345pdq_os_update_status(
346 pdq_t *pdq,
347 const void *arg)
348{
349 pdq_softc_t * const sc = pdq->pdq_os_ctx;
350 const pdq_response_status_chars_get_t *rsp = arg;
351 int media = 0;
268
352
269#if defined(NS)
270 /* This magic copied from if_is.c; I don't use XNS,
271 * so I have no way of telling if this actually
272 * works or not.
273 */
274 case AF_NS: {
275 struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
276 if (ns_nullhost(*ina)) {
277 ina->x_host = *(union ns_host *)(sc->sc_ac.ac_enaddr);
278 } else {
279 ifp->if_flags &= ~IFF_RUNNING;
280 bcopy((caddr_t)ina->x_host.c_host,
281 (caddr_t)sc->sc_ac.ac_enaddr,
282 sizeof sc->sc_ac.ac_enaddr);
283 }
353 switch (rsp->status_chars_get.pmd_type[0]) {
354 case PDQ_PMD_TYPE_ANSI_MUTLI_MODE: media = IFM_FDDI_MMF; break;
355 case PDQ_PMD_TYPE_ANSI_SINGLE_MODE_TYPE_1: media = IFM_FDDI_SMF; break;
356 case PDQ_PMD_TYPE_ANSI_SIGNLE_MODE_TYPE_2: media = IFM_FDDI_SMF; break;
357 case PDQ_PMD_TYPE_UNSHIELDED_TWISTED_PAIR: media = IFM_FDDI_UTP; break;
358 default: media |= IFM_MANUAL;
359 }
284
360
285 pdq_ifinit(sc);
286 break;
287 }
288#endif /* NS */
361 if (rsp->status_chars_get.station_type == PDQ_STATION_TYPE_DAS)
362 media |= IFM_FDDI_DA;
289
363
290 default: {
291 pdq_ifinit(sc);
292 break;
293 }
294 }
364 sc->sc_ifmedia.ifm_media = media | IFM_FDDI;
365}
366#endif /* defined(IFM_FDDI) */
367
368static int
369pdq_ifioctl(
370 struct ifnet *ifp,
371 u_long cmd,
372 caddr_t data)
373{
374 pdq_softc_t *sc = PDQ_OS_IFP_TO_SOFTC(ifp);
375 int error = 0;
376
377 PDQ_LOCK(sc);
378
379 switch (cmd) {
380 case SIOCSIFMTU:
381 case SIOCGIFADDR:
382 case SIOCSIFADDR: {
383 error = fddi_ioctl(ifp, cmd, data);
295 break;
296 }
384 break;
385 }
297 case SIOCGIFADDR: {
298 struct ifreq *ifr = (struct ifreq *)data;
299 bcopy((caddr_t) sc->sc_ac.ac_enaddr,
300 (caddr_t) ((struct sockaddr *)&ifr->ifr_data)->sa_data,
301 6);
302 break;
303 }
304
305 case SIOCSIFFLAGS: {
306 pdq_ifinit(sc);
307 break;
308 }
309
310 case SIOCADDMULTI:
386
387 case SIOCSIFFLAGS: {
388 pdq_ifinit(sc);
389 break;
390 }
391
392 case SIOCADDMULTI:
311 case SIOCDELMULTI:
312 /*
313 * Update multicast listeners
314 */
315 if (sc->sc_if.if_flags & IFF_RUNNING)
316 pdq_run(sc->sc_pdq);
393 case SIOCDELMULTI: {
394 if (sc->sc_if.if_flags & IFF_RUNNING) {
395 pdq_run(sc->sc_pdq);
317 error = 0;
396 error = 0;
318 break;
397 }
398 break;
399 }
319
400
320#if defined(SIOCSIFMTU)
321#if !defined(ifr_mtu)
322#define ifr_mtu ifr_metric
323#endif
324 case SIOCSIFMTU: {
401#if defined(IFM_FDDI) && defined(SIOCSIFMEDIA)
402 case SIOCSIFMEDIA:
403 case SIOCGIFMEDIA: {
325 struct ifreq *ifr = (struct ifreq *)data;
404 struct ifreq *ifr = (struct ifreq *)data;
326 /*
327 * Set the interface MTU.
328 */
329 if (ifr->ifr_mtu > FDDIMTU) {
330 error = EINVAL;
331 break;
332 }
333 ifp->if_mtu = ifr->ifr_mtu;
405 error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
334 break;
335 }
406 break;
407 }
336#endif /* SIOCSIFMTU */
408#endif
337
338 default: {
339 error = EINVAL;
340 break;
341 }
342 }
343
409
410 default: {
411 error = EINVAL;
412 break;
413 }
414 }
415
344 splx(s);
416 PDQ_UNLOCK(sc);
345 return error;
346}
347
348#ifndef IFF_NOTRAILERS
349#define IFF_NOTRAILERS 0
350#endif
351
352void
417 return error;
418}
419
420#ifndef IFF_NOTRAILERS
421#define IFF_NOTRAILERS 0
422#endif
423
424void
353pdq_ifattach(
354 pdq_softc_t *sc,
355 ifnet_ret_t (*ifwatchdog)(int unit))
425pdq_ifattach(pdq_softc_t *sc)
356{
357 struct ifnet *ifp = &sc->sc_if;
358
426{
427 struct ifnet *ifp = &sc->sc_if;
428
429 mtx_init(&sc->mtx, device_get_nameunit(sc->dev), MTX_DEF | MTX_RECURSE);
430
431 ifp->if_softc = sc;
432 ifp->if_init = (if_init_f_t *)pdq_ifinit;
433 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
359 ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
360
361#if (defined(__FreeBSD__) && BSD >= 199506) || defined(__NetBSD__)
362 ifp->if_watchdog = pdq_ifwatchdog;
363#else
364 ifp->if_watchdog = ifwatchdog;
365#endif
366
367 ifp->if_ioctl = pdq_ifioctl;
434 ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_NOTRAILERS|IFF_MULTICAST;
435
436#if (defined(__FreeBSD__) && BSD >= 199506) || defined(__NetBSD__)
437 ifp->if_watchdog = pdq_ifwatchdog;
438#else
439 ifp->if_watchdog = ifwatchdog;
440#endif
441
442 ifp->if_ioctl = pdq_ifioctl;
443#if !defined(__NetBSD__) && !defined(__FreeBSD__)
368 ifp->if_output = fddi_output;
444 ifp->if_output = fddi_output;
445#endif
369 ifp->if_start = pdq_ifstart;
446 ifp->if_start = pdq_ifstart;
370 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
371#warning "Implement fddi_resolvemulti!"
372/* ifp->if_resolvemulti = ether_resolvemulti; XXX */
447
448#if defined(IFM_FDDI)
449 {
450 const int media = sc->sc_ifmedia.ifm_media;
451 ifmedia_init(&sc->sc_ifmedia, IFM_FDX,
452 pdq_ifmedia_change, pdq_ifmedia_status);
453 ifmedia_add(&sc->sc_ifmedia, media, 0, 0);
454 ifmedia_set(&sc->sc_ifmedia, media);
455 }
456#endif
373
374 if_attach(ifp);
457
458 if_attach(ifp);
375 fddi_ifattach(ifp);
376 PDQ_BPFATTACH(sc, DLT_FDDI, sizeof(struct fddi_header));
459#if defined(__NetBSD__)
460 fddi_ifattach(ifp, (caddr_t)&sc->sc_pdq->pdq_hwaddr);
461#else
462 fddi_ifattach(ifp, FDDI_BPF_SUPPORTED);
463#endif
377}
464}
465
466void
467pdq_ifdetach (pdq_softc_t *sc)
468{
469 struct ifnet *ifp;
470
471 ifp = &sc->arpcom.ac_if;
472
473 fddi_ifdetach(ifp, FDDI_BPF_SUPPORTED);
474 pdq_stop(sc->sc_pdq);
475 pdq_free(sc->dev);
476
477 return;
478}
479
480void
481pdq_free (device_t dev)
482{
483 pdq_softc_t *sc;
484
485 sc = device_get_softc(dev);
486
487 if (sc->io)
488 bus_release_resource(dev, sc->io_type, sc->io_rid, sc->io);
489 if (sc->mem)
490 bus_release_resource(dev, sc->mem_type, sc->mem_rid, sc->mem);
491 if (sc->irq_ih)
492 bus_teardown_intr(dev, sc->irq, sc->irq_ih);
493 if (sc->irq)
494 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
495
496 /*
497 * Destroy the mutex.
498 */
499 if (mtx_initialized(&sc->mtx) != 0) {
500 mtx_destroy(&sc->mtx);
501 }
502
503 return;
504}
505
506#if defined(PDQ_BUS_DMA)
507int
508pdq_os_memalloc_contig(
509 pdq_t *pdq)
510{
511 pdq_softc_t * const sc = pdq->pdq_os_ctx;
512 bus_dma_segment_t db_segs[1], ui_segs[1], cb_segs[1];
513 int db_nsegs = 0, ui_nsegs = 0;
514 int steps = 0;
515 int not_ok;
516
517 not_ok = bus_dmamem_alloc(sc->sc_dmatag,
518 sizeof(*pdq->pdq_dbp), sizeof(*pdq->pdq_dbp),
519 sizeof(*pdq->pdq_dbp), db_segs, 1, &db_nsegs,
520 BUS_DMA_NOWAIT);
521 if (!not_ok) {
522 steps = 1;
523 not_ok = bus_dmamem_map(sc->sc_dmatag, db_segs, db_nsegs,
524 sizeof(*pdq->pdq_dbp), (caddr_t *) &pdq->pdq_dbp,
525 BUS_DMA_NOWAIT);
526 }
527 if (!not_ok) {
528 steps = 2;
529 not_ok = bus_dmamap_create(sc->sc_dmatag, db_segs[0].ds_len, 1,
530 0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_dbmap);
531 }
532 if (!not_ok) {
533 steps = 3;
534 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_dbmap,
535 pdq->pdq_dbp, sizeof(*pdq->pdq_dbp),
536 NULL, BUS_DMA_NOWAIT);
537 }
538 if (!not_ok) {
539 steps = 4;
540 pdq->pdq_pa_descriptor_block = sc->sc_dbmap->dm_segs[0].ds_addr;
541 not_ok = bus_dmamem_alloc(sc->sc_dmatag,
542 PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE, PDQ_OS_PAGESIZE,
543 ui_segs, 1, &ui_nsegs, BUS_DMA_NOWAIT);
544 }
545 if (!not_ok) {
546 steps = 5;
547 not_ok = bus_dmamem_map(sc->sc_dmatag, ui_segs, ui_nsegs,
548 PDQ_OS_PAGESIZE,
549 (caddr_t *) &pdq->pdq_unsolicited_info.ui_events,
550 BUS_DMA_NOWAIT);
551 }
552 if (!not_ok) {
553 steps = 6;
554 not_ok = bus_dmamap_create(sc->sc_dmatag, ui_segs[0].ds_len, 1,
555 PDQ_OS_PAGESIZE, 0, BUS_DMA_NOWAIT,
556 &sc->sc_uimap);
557 }
558 if (!not_ok) {
559 steps = 7;
560 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_uimap,
561 pdq->pdq_unsolicited_info.ui_events,
562 PDQ_OS_PAGESIZE, NULL, BUS_DMA_NOWAIT);
563 }
564 if (!not_ok) {
565 steps = 8;
566 pdq->pdq_unsolicited_info.ui_pa_bufstart = sc->sc_uimap->dm_segs[0].ds_addr;
567 cb_segs[0] = db_segs[0];
568 cb_segs[0].ds_addr += offsetof(pdq_descriptor_block_t, pdqdb_consumer);
569 cb_segs[0].ds_len = sizeof(pdq_consumer_block_t);
570 not_ok = bus_dmamem_map(sc->sc_dmatag, cb_segs, 1,
571 sizeof(*pdq->pdq_cbp), (caddr_t *) &pdq->pdq_cbp,
572 BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
573 }
574 if (!not_ok) {
575 steps = 9;
576 not_ok = bus_dmamap_create(sc->sc_dmatag, cb_segs[0].ds_len, 1,
577 0x2000, 0, BUS_DMA_NOWAIT, &sc->sc_cbmap);
578 }
579 if (!not_ok) {
580 steps = 10;
581 not_ok = bus_dmamap_load(sc->sc_dmatag, sc->sc_cbmap,
582 (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp),
583 NULL, BUS_DMA_NOWAIT);
584 }
585 if (!not_ok) {
586 pdq->pdq_pa_consumer_block = sc->sc_cbmap->dm_segs[0].ds_addr;
587 return not_ok;
588 }
589
590 switch (steps) {
591 case 11: {
592 bus_dmamap_unload(sc->sc_dmatag, sc->sc_cbmap);
593 /* FALL THROUGH */
594 }
595 case 10: {
596 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_cbmap);
597 /* FALL THROUGH */
598 }
599 case 9: {
600 bus_dmamem_unmap(sc->sc_dmatag,
601 (caddr_t) pdq->pdq_cbp, sizeof(*pdq->pdq_cbp));
602 /* FALL THROUGH */
603 }
604 case 8: {
605 bus_dmamap_unload(sc->sc_dmatag, sc->sc_uimap);
606 /* FALL THROUGH */
607 }
608 case 7: {
609 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_uimap);
610 /* FALL THROUGH */
611 }
612 case 6: {
613 bus_dmamem_unmap(sc->sc_dmatag,
614 (caddr_t) pdq->pdq_unsolicited_info.ui_events,
615 PDQ_OS_PAGESIZE);
616 /* FALL THROUGH */
617 }
618 case 5: {
619 bus_dmamem_free(sc->sc_dmatag, ui_segs, ui_nsegs);
620 /* FALL THROUGH */
621 }
622 case 4: {
623 bus_dmamap_unload(sc->sc_dmatag, sc->sc_dbmap);
624 /* FALL THROUGH */
625 }
626 case 3: {
627 bus_dmamap_destroy(sc->sc_dmatag, sc->sc_dbmap);
628 /* FALL THROUGH */
629 }
630 case 2: {
631 bus_dmamem_unmap(sc->sc_dmatag,
632 (caddr_t) pdq->pdq_dbp,
633 sizeof(*pdq->pdq_dbp));
634 /* FALL THROUGH */
635 }
636 case 1: {
637 bus_dmamem_free(sc->sc_dmatag, db_segs, db_nsegs);
638 /* FALL THROUGH */
639 }
640 }
641
642 return not_ok;
643}
644
645extern void
646pdq_os_descriptor_block_sync(
647 pdq_os_ctx_t *sc,
648 size_t offset,
649 size_t length,
650 int ops)
651{
652 bus_dmamap_sync(sc->sc_dmatag, sc->sc_dbmap, offset, length, ops);
653}
654
655extern void
656pdq_os_consumer_block_sync(
657 pdq_os_ctx_t *sc,
658 int ops)
659{
660 bus_dmamap_sync(sc->sc_dmatag, sc->sc_cbmap, 0, sizeof(pdq_consumer_block_t), ops);
661}
662
663extern void
664pdq_os_unsolicited_event_sync(
665 pdq_os_ctx_t *sc,
666 size_t offset,
667 size_t length,
668 int ops)
669{
670 bus_dmamap_sync(sc->sc_dmatag, sc->sc_uimap, offset, length, ops);
671}
672
673extern void
674pdq_os_databuf_sync(
675 pdq_os_ctx_t *sc,
676 struct mbuf *m,
677 size_t offset,
678 size_t length,
679 int ops)
680{
681 bus_dmamap_sync(sc->sc_dmatag, M_GETCTX(m, bus_dmamap_t), offset, length, ops);
682}
683
684extern void
685pdq_os_databuf_free(
686 pdq_os_ctx_t *sc,
687 struct mbuf *m)
688{
689 if (m->m_flags & (M_HASRXDMAMAP|M_HASTXDMAMAP)) {
690 bus_dmamap_t map = M_GETCTX(m, bus_dmamap_t);
691 bus_dmamap_unload(sc->sc_dmatag, map);
692 bus_dmamap_destroy(sc->sc_dmatag, map);
693 m->m_flags &= ~(M_HASRXDMAMAP|M_HASTXDMAMAP);
694 }
695 m_freem(m);
696}
697
698extern struct mbuf *
699pdq_os_databuf_alloc(
700 pdq_os_ctx_t *sc)
701{
702 struct mbuf *m;
703 bus_dmamap_t map;
704
705 MGETHDR(m, M_DONTWAIT, MT_DATA);
706 if (m == NULL) {
707 printf("%s: can't alloc small buf\n", sc->sc_dev.dv_xname);
708 return NULL;
709 }
710 MCLGET(m, M_DONTWAIT);
711 if ((m->m_flags & M_EXT) == 0) {
712 printf("%s: can't alloc cluster\n", sc->sc_dev.dv_xname);
713 m_free(m);
714 return NULL;
715 }
716 m->m_pkthdr.len = m->m_len = PDQ_OS_DATABUF_SIZE;
717
718 if (bus_dmamap_create(sc->sc_dmatag, PDQ_OS_DATABUF_SIZE,
719 1, PDQ_OS_DATABUF_SIZE, 0, BUS_DMA_NOWAIT, &map)) {
720 printf("%s: can't create dmamap\n", sc->sc_dev.dv_xname);
721 m_free(m);
722 return NULL;
723 }
724 if (bus_dmamap_load_mbuf(sc->sc_dmatag, map, m,
725 BUS_DMA_READ|BUS_DMA_NOWAIT)) {
726 printf("%s: can't load dmamap\n", sc->sc_dev.dv_xname);
727 bus_dmamap_destroy(sc->sc_dmatag, map);
728 m_free(m);
729 return NULL;
730 }
731 m->m_flags |= M_HASRXDMAMAP;
732 M_SETCTX(m, map);
733 return m;
734}
735#endif