| 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
|
| |