| @@ -1,728 +1,728 @@ | | | @@ -1,728 +1,728 @@ |
1 | /* $NetBSD: if_mc.c,v 1.53 2020/01/29 05:25:41 thorpej Exp $ */ | | 1 | /* $NetBSD: if_mc.c,v 1.54 2020/01/30 06:28:46 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997 David Huang <khym@azeotrope.org> | | 4 | * Copyright (c) 1997 David Huang <khym@azeotrope.org> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Portions of this code are based on code by Denton Gentry <denny1@home.com>, | | 7 | * Portions of this code are based on code by Denton Gentry <denny1@home.com>, |
8 | * Charles M. Hannum, Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>, and | | 8 | * Charles M. Hannum, Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>, and |
9 | * Jason R. Thorpe. | | 9 | * Jason R. Thorpe. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. The name of the author may not be used to endorse or promote products | | 16 | * 2. The name of the author may not be used to endorse or promote products |
17 | * derived from this software without specific prior written permission | | 17 | * derived from this software without specific prior written permission |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | * | | 29 | * |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Driver for the AMD Am79C940 (MACE) ethernet chip, used for onboard | | 33 | * Driver for the AMD Am79C940 (MACE) ethernet chip, used for onboard |
34 | * ethernet on the Centris/Quadra 660av and Quadra 840av. | | 34 | * ethernet on the Centris/Quadra 660av and Quadra 840av. |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: if_mc.c,v 1.53 2020/01/29 05:25:41 thorpej Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: if_mc.c,v 1.54 2020/01/30 06:28:46 martin Exp $"); |
39 | | | 39 | |
40 | #include "opt_ddb.h" | | 40 | #include "opt_ddb.h" |
41 | #include "opt_inet.h" | | 41 | #include "opt_inet.h" |
42 | | | 42 | |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <sys/systm.h> | | 44 | #include <sys/systm.h> |
45 | #include <sys/mbuf.h> | | 45 | #include <sys/mbuf.h> |
46 | #include <sys/buf.h> | | 46 | #include <sys/buf.h> |
47 | #include <sys/protosw.h> | | 47 | #include <sys/protosw.h> |
48 | #include <sys/socket.h> | | 48 | #include <sys/socket.h> |
49 | #include <sys/syslog.h> | | 49 | #include <sys/syslog.h> |
50 | #include <sys/ioctl.h> | | 50 | #include <sys/ioctl.h> |
51 | #include <sys/errno.h> | | 51 | #include <sys/errno.h> |
52 | #include <sys/device.h> | | 52 | #include <sys/device.h> |
53 | | | 53 | |
54 | #include <uvm/uvm_extern.h> | | 54 | #include <uvm/uvm_extern.h> |
55 | | | 55 | |
56 | #include <net/if.h> | | 56 | #include <net/if.h> |
57 | #include <net/if_dl.h> | | 57 | #include <net/if_dl.h> |
58 | #include <net/if_ether.h> | | 58 | #include <net/if_ether.h> |
59 | #include <net/bpf.h> | | 59 | #include <net/bpf.h> |
60 | | | 60 | |
61 | #ifdef INET | | 61 | #ifdef INET |
62 | #include <netinet/in.h> | | 62 | #include <netinet/in.h> |
63 | #include <netinet/if_inarp.h> | | 63 | #include <netinet/if_inarp.h> |
64 | #include <netinet/in_systm.h> | | 64 | #include <netinet/in_systm.h> |
65 | #include <netinet/in_var.h> | | 65 | #include <netinet/in_var.h> |
66 | #include <netinet/ip.h> | | 66 | #include <netinet/ip.h> |
67 | #endif | | 67 | #endif |
68 | | | 68 | |
69 | #include <machine/bus.h> | | 69 | #include <machine/bus.h> |
70 | #include <mac68k/dev/if_mcreg.h> | | 70 | #include <mac68k/dev/if_mcreg.h> |
71 | #include <mac68k/dev/if_mcvar.h> | | 71 | #include <mac68k/dev/if_mcvar.h> |
72 | | | 72 | |
73 | hide void mcwatchdog(struct ifnet *); | | 73 | hide void mcwatchdog(struct ifnet *); |
74 | hide int mcinit(struct mc_softc *); | | 74 | hide int mcinit(struct mc_softc *); |
75 | hide int mcstop(struct mc_softc *); | | 75 | hide int mcstop(struct mc_softc *); |
76 | hide int mcioctl(struct ifnet *, u_long, void *); | | 76 | hide int mcioctl(struct ifnet *, u_long, void *); |
77 | hide void mcstart(struct ifnet *); | | 77 | hide void mcstart(struct ifnet *); |
78 | hide void mcreset(struct mc_softc *); | | 78 | hide void mcreset(struct mc_softc *); |
79 | | | 79 | |
80 | integrate u_int maceput(struct mc_softc *, struct mbuf *); | | 80 | integrate u_int maceput(struct mc_softc *, struct mbuf *); |
81 | integrate void mc_tint(struct mc_softc *); | | 81 | integrate void mc_tint(struct mc_softc *); |
82 | integrate void mace_read(struct mc_softc *, void *, int); | | 82 | integrate void mace_read(struct mc_softc *, void *, int); |
83 | integrate struct mbuf *mace_get(struct mc_softc *, void *, int); | | 83 | integrate struct mbuf *mace_get(struct mc_softc *, void *, int); |
84 | static void mace_calcladrf(struct ethercom *, uint8_t *); | | 84 | static void mace_calcladrf(struct ethercom *, uint8_t *); |
85 | static inline uint16_t ether_cmp(void *, void *); | | 85 | static inline uint16_t ether_cmp(void *, void *); |
86 | | | 86 | |
87 | | | 87 | |
88 | /* | | 88 | /* |
89 | * Compare two Ether/802 addresses for equality, inlined and | | 89 | * Compare two Ether/802 addresses for equality, inlined and |
90 | * unrolled for speed. Use this like memcmp(). | | 90 | * unrolled for speed. Use this like memcmp(). |
91 | * | | 91 | * |
92 | * XXX: Add <machine/inlines.h> for stuff like this? | | 92 | * XXX: Add <machine/inlines.h> for stuff like this? |
93 | * XXX: or maybe add it to libkern.h instead? | | 93 | * XXX: or maybe add it to libkern.h instead? |
94 | * | | 94 | * |
95 | * "I'd love to have an inline assembler version of this." | | 95 | * "I'd love to have an inline assembler version of this." |
96 | * XXX: Who wanted that? mycroft? I wrote one, but this | | 96 | * XXX: Who wanted that? mycroft? I wrote one, but this |
97 | * version in C is as good as hand-coded assembly. -gwr | | 97 | * version in C is as good as hand-coded assembly. -gwr |
98 | * | | 98 | * |
99 | * Please do NOT tweak this without looking at the actual | | 99 | * Please do NOT tweak this without looking at the actual |
100 | * assembly code generated before and after your tweaks! | | 100 | * assembly code generated before and after your tweaks! |
101 | */ | | 101 | */ |
102 | static inline uint16_t | | 102 | static inline uint16_t |
103 | ether_cmp(void *one, void *two) | | 103 | ether_cmp(void *one, void *two) |
104 | { | | 104 | { |
105 | uint16_t *a = (u_short *) one; | | 105 | uint16_t *a = (u_short *) one; |
106 | uint16_t *b = (u_short *) two; | | 106 | uint16_t *b = (u_short *) two; |
107 | uint16_t diff; | | 107 | uint16_t diff; |
108 | | | 108 | |
109 | #ifdef m68k | | 109 | #ifdef m68k |
110 | /* | | 110 | /* |
111 | * The post-increment-pointer form produces the best | | 111 | * The post-increment-pointer form produces the best |
112 | * machine code for m68k. This was carefully tuned | | 112 | * machine code for m68k. This was carefully tuned |
113 | * so it compiles to just 8 short (2-byte) op-codes! | | 113 | * so it compiles to just 8 short (2-byte) op-codes! |
114 | */ | | 114 | */ |
115 | diff = *a++ - *b++; | | 115 | diff = *a++ - *b++; |
116 | diff |= *a++ - *b++; | | 116 | diff |= *a++ - *b++; |
117 | diff |= *a++ - *b++; | | 117 | diff |= *a++ - *b++; |
118 | #else | | 118 | #else |
119 | /* | | 119 | /* |
120 | * Most modern CPUs do better with a single expression. | | 120 | * Most modern CPUs do better with a single expression. |
121 | * Note that short-cut evaluation is NOT helpful here, | | 121 | * Note that short-cut evaluation is NOT helpful here, |
122 | * because it just makes the code longer, not faster! | | 122 | * because it just makes the code longer, not faster! |
123 | */ | | 123 | */ |
124 | diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]); | | 124 | diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]); |
125 | #endif | | 125 | #endif |
126 | | | 126 | |
127 | return diff; | | 127 | return diff; |
128 | } | | 128 | } |
129 | | | 129 | |
130 | #define ETHER_CMP ether_cmp | | 130 | #define ETHER_CMP ether_cmp |
131 | | | 131 | |
132 | /* | | 132 | /* |
133 | * Interface exists: make available by filling in network interface | | 133 | * Interface exists: make available by filling in network interface |
134 | * record. System will initialize the interface when it is ready | | 134 | * record. System will initialize the interface when it is ready |
135 | * to accept packets. | | 135 | * to accept packets. |
136 | */ | | 136 | */ |
137 | int | | 137 | int |
138 | mcsetup(struct mc_softc *sc, uint8_t *lladdr) | | 138 | mcsetup(struct mc_softc *sc, uint8_t *lladdr) |
139 | { | | 139 | { |
140 | struct ifnet *ifp = &sc->sc_if; | | 140 | struct ifnet *ifp = &sc->sc_if; |
141 | | | 141 | |
142 | /* reset the chip and disable all interrupts */ | | 142 | /* reset the chip and disable all interrupts */ |
143 | NIC_PUT(sc, MACE_BIUCC, SWRST); | | 143 | NIC_PUT(sc, MACE_BIUCC, SWRST); |
144 | DELAY(100); | | 144 | DELAY(100); |
145 | NIC_PUT(sc, MACE_IMR, ~0); | | 145 | NIC_PUT(sc, MACE_IMR, ~0); |
146 | | | 146 | |
147 | memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN); | | 147 | memcpy(sc->sc_enaddr, lladdr, ETHER_ADDR_LEN); |
148 | printf(": address %s\n", ether_sprintf(lladdr)); | | 148 | printf(": address %s\n", ether_sprintf(lladdr)); |
149 | | | 149 | |
150 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | | 150 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); |
151 | ifp->if_softc = sc; | | 151 | ifp->if_softc = sc; |
152 | ifp->if_ioctl = mcioctl; | | 152 | ifp->if_ioctl = mcioctl; |
153 | ifp->if_start = mcstart; | | 153 | ifp->if_start = mcstart; |
154 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | | 154 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
155 | ifp->if_watchdog = mcwatchdog; | | 155 | ifp->if_watchdog = mcwatchdog; |
156 | | | 156 | |
157 | if_attach(ifp); | | 157 | if_attach(ifp); |
158 | if_deferred_start_init(ifp, NULL); | | 158 | if_deferred_start_init(ifp, NULL); |
159 | ether_ifattach(ifp, lladdr); | | 159 | ether_ifattach(ifp, lladdr); |
160 | | | 160 | |
161 | return 0; | | 161 | return 0; |
162 | } | | 162 | } |
163 | | | 163 | |
164 | hide int | | 164 | hide int |
165 | mcioctl(struct ifnet *ifp, u_long cmd, void *data) | | 165 | mcioctl(struct ifnet *ifp, u_long cmd, void *data) |
166 | { | | 166 | { |
167 | struct mc_softc *sc = ifp->if_softc; | | 167 | struct mc_softc *sc = ifp->if_softc; |
168 | struct ifaddr *ifa; | | 168 | struct ifaddr *ifa; |
169 | | | 169 | |
170 | int s = splnet(), err = 0; | | 170 | int s = splnet(), err = 0; |
171 | | | 171 | |
172 | switch (cmd) { | | 172 | switch (cmd) { |
173 | | | 173 | |
174 | case SIOCINITIFADDR: | | 174 | case SIOCINITIFADDR: |
175 | ifa = (struct ifaddr *)data; | | 175 | ifa = (struct ifaddr *)data; |
176 | ifp->if_flags |= IFF_UP; | | 176 | ifp->if_flags |= IFF_UP; |
177 | mcinit(sc); | | 177 | mcinit(sc); |
178 | switch (ifa->ifa_addr->sa_family) { | | 178 | switch (ifa->ifa_addr->sa_family) { |
179 | #ifdef INET | | 179 | #ifdef INET |
180 | case AF_INET: | | 180 | case AF_INET: |
181 | arp_ifinit(ifp, ifa); | | 181 | arp_ifinit(ifp, ifa); |
182 | break; | | 182 | break; |
183 | #endif | | 183 | #endif |
184 | default: | | 184 | default: |
185 | break; | | 185 | break; |
186 | } | | 186 | } |
187 | break; | | 187 | break; |
188 | | | 188 | |
189 | case SIOCSIFFLAGS: | | 189 | case SIOCSIFFLAGS: |
190 | if ((err = ifioctl_common(ifp, cmd, data)) != 0) | | 190 | if ((err = ifioctl_common(ifp, cmd, data)) != 0) |
191 | break; | | 191 | break; |
192 | /* XXX see the comment in ed_ioctl() about code re-use */ | | 192 | /* XXX see the comment in ed_ioctl() about code re-use */ |
193 | if ((ifp->if_flags & IFF_UP) == 0 && | | 193 | if ((ifp->if_flags & IFF_UP) == 0 && |
194 | (ifp->if_flags & IFF_RUNNING) != 0) { | | 194 | (ifp->if_flags & IFF_RUNNING) != 0) { |
195 | /* | | 195 | /* |
196 | * If interface is marked down and it is running, | | 196 | * If interface is marked down and it is running, |
197 | * then stop it. | | 197 | * then stop it. |
198 | */ | | 198 | */ |
199 | mcstop(sc); | | 199 | mcstop(sc); |
200 | ifp->if_flags &= ~IFF_RUNNING; | | 200 | ifp->if_flags &= ~IFF_RUNNING; |
201 | } else if ((ifp->if_flags & IFF_UP) != 0 && | | 201 | } else if ((ifp->if_flags & IFF_UP) != 0 && |
202 | (ifp->if_flags & IFF_RUNNING) == 0) { | | 202 | (ifp->if_flags & IFF_RUNNING) == 0) { |
203 | /* | | 203 | /* |
204 | * If interface is marked up and it is stopped, | | 204 | * If interface is marked up and it is stopped, |
205 | * then start it. | | 205 | * then start it. |
206 | */ | | 206 | */ |
207 | (void)mcinit(sc); | | 207 | (void)mcinit(sc); |
208 | } else { | | 208 | } else { |
209 | /* | | 209 | /* |
210 | * reset the interface to pick up any other changes | | 210 | * reset the interface to pick up any other changes |
211 | * in flags | | 211 | * in flags |
212 | */ | | 212 | */ |
213 | mcreset(sc); | | 213 | mcreset(sc); |
214 | mcstart(ifp); | | 214 | mcstart(ifp); |
215 | } | | 215 | } |
216 | break; | | 216 | break; |
217 | | | 217 | |
218 | case SIOCADDMULTI: | | 218 | case SIOCADDMULTI: |
219 | case SIOCDELMULTI: | | 219 | case SIOCDELMULTI: |
220 | if ((err = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | | 220 | if ((err = ether_ioctl(ifp, cmd, data)) == ENETRESET) { |
221 | /* | | 221 | /* |
222 | * Multicast list has changed; set the hardware | | 222 | * Multicast list has changed; set the hardware |
223 | * filter accordingly. But remember UP flag! | | 223 | * filter accordingly. But remember UP flag! |
224 | */ | | 224 | */ |
225 | if (ifp->if_flags & IFF_RUNNING) | | 225 | if (ifp->if_flags & IFF_RUNNING) |
226 | mcreset(sc); | | 226 | mcreset(sc); |
227 | err = 0; | | 227 | err = 0; |
228 | } | | 228 | } |
229 | break; | | 229 | break; |
230 | default: | | 230 | default: |
231 | err = ether_ioctl(ifp, cmd, data); | | 231 | err = ether_ioctl(ifp, cmd, data); |
232 | } | | 232 | } |
233 | splx(s); | | 233 | splx(s); |
234 | return err; | | 234 | return err; |
235 | } | | 235 | } |
236 | | | 236 | |
237 | /* | | 237 | /* |
238 | * Encapsulate a packet of type family for the local net. | | 238 | * Encapsulate a packet of type family for the local net. |
239 | */ | | 239 | */ |
240 | hide void | | 240 | hide void |
241 | mcstart(struct ifnet *ifp) | | 241 | mcstart(struct ifnet *ifp) |
242 | { | | 242 | { |
243 | struct mc_softc *sc = ifp->if_softc; | | 243 | struct mc_softc *sc = ifp->if_softc; |
244 | struct mbuf *m; | | 244 | struct mbuf *m; |
245 | | | 245 | |
246 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) | | 246 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) |
247 | return; | | 247 | return; |
248 | | | 248 | |
249 | while (1) { | | 249 | while (1) { |
250 | if (ifp->if_flags & IFF_OACTIVE) | | 250 | if (ifp->if_flags & IFF_OACTIVE) |
251 | return; | | 251 | return; |
252 | | | 252 | |
253 | IF_DEQUEUE(&ifp->if_snd, m); | | 253 | IF_DEQUEUE(&ifp->if_snd, m); |
254 | if (m == 0) | | 254 | if (m == 0) |
255 | return; | | 255 | return; |
256 | | | 256 | |
257 | /* | | 257 | /* |
258 | * If bpf is listening on this interface, let it | | 258 | * If bpf is listening on this interface, let it |
259 | * see the packet before we commit it to the wire. | | 259 | * see the packet before we commit it to the wire. |
260 | */ | | 260 | */ |
261 | bpf_mtap(ifp, m, BPF_D_OUT); | | 261 | bpf_mtap(ifp, m, BPF_D_OUT); |
262 | | | 262 | |
263 | /* | | 263 | /* |
264 | * Copy the mbuf chain into the transmit buffer. | | 264 | * Copy the mbuf chain into the transmit buffer. |
265 | */ | | 265 | */ |
266 | ifp->if_flags |= IFF_OACTIVE; | | 266 | ifp->if_flags |= IFF_OACTIVE; |
267 | maceput(sc, m); | | 267 | maceput(sc, m); |
268 | | | 268 | |
269 | if_statinc(ifp, if_opackets); /* # of pkts */ | | 269 | if_statinc(ifp, if_opackets); /* # of pkts */ |
270 | } | | 270 | } |
271 | } | | 271 | } |
272 | | | 272 | |
273 | /* | | 273 | /* |
274 | * reset and restart the MACE. Called in case of fatal | | 274 | * reset and restart the MACE. Called in case of fatal |
275 | * hardware/software errors. | | 275 | * hardware/software errors. |
276 | */ | | 276 | */ |
277 | hide void | | 277 | hide void |
278 | mcreset(struct mc_softc *sc) | | 278 | mcreset(struct mc_softc *sc) |
279 | { | | 279 | { |
280 | mcstop(sc); | | 280 | mcstop(sc); |
281 | mcinit(sc); | | 281 | mcinit(sc); |
282 | } | | 282 | } |
283 | | | 283 | |
284 | hide int | | 284 | hide int |
285 | mcinit(struct mc_softc *sc) | | 285 | mcinit(struct mc_softc *sc) |
286 | { | | 286 | { |
287 | int s; | | 287 | int s; |
288 | uint8_t maccc, ladrf[8]; | | 288 | uint8_t maccc, ladrf[8]; |
289 | | | 289 | |
290 | if (sc->sc_if.if_flags & IFF_RUNNING) | | 290 | if (sc->sc_if.if_flags & IFF_RUNNING) |
291 | /* already running */ | | 291 | /* already running */ |
292 | return 0; | | 292 | return 0; |
293 | | | 293 | |
294 | s = splnet(); | | 294 | s = splnet(); |
295 | | | 295 | |
296 | NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc); | | 296 | NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc); |
297 | NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc); | | 297 | NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc); |
298 | NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */ | | 298 | NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */ |
299 | NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc); | | 299 | NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc); |
300 | | | 300 | |
301 | NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */ | | 301 | NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */ |
302 | | | 302 | |
303 | /* set MAC address */ | | 303 | /* set MAC address */ |
304 | NIC_PUT(sc, MACE_IAC, ADDRCHG); | | 304 | NIC_PUT(sc, MACE_IAC, ADDRCHG); |
305 | while (NIC_GET(sc, MACE_IAC) & ADDRCHG) | | 305 | while (NIC_GET(sc, MACE_IAC) & ADDRCHG) |
306 | ; | | 306 | ; |
307 | NIC_PUT(sc, MACE_IAC, PHYADDR); | | 307 | NIC_PUT(sc, MACE_IAC, PHYADDR); |
308 | bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_PADR), | | 308 | bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_PADR), |
309 | sc->sc_enaddr, ETHER_ADDR_LEN); | | 309 | sc->sc_enaddr, ETHER_ADDR_LEN); |
310 | | | 310 | |
311 | /* set logical address filter */ | | 311 | /* set logical address filter */ |
312 | mace_calcladrf(&sc->sc_ethercom, ladrf); | | 312 | mace_calcladrf(&sc->sc_ethercom, ladrf); |
313 | | | 313 | |
314 | NIC_PUT(sc, MACE_IAC, ADDRCHG); | | 314 | NIC_PUT(sc, MACE_IAC, ADDRCHG); |
315 | while (NIC_GET(sc, MACE_IAC) & ADDRCHG) | | 315 | while (NIC_GET(sc, MACE_IAC) & ADDRCHG) |
316 | ; | | 316 | ; |
317 | NIC_PUT(sc, MACE_IAC, LOGADDR); | | 317 | NIC_PUT(sc, MACE_IAC, LOGADDR); |
318 | bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_LADRF), | | 318 | bus_space_write_multi_1(sc->sc_regt, sc->sc_regh, MACE_REG(MACE_LADRF), |
319 | ladrf, 8); | | 319 | ladrf, 8); |
320 | | | 320 | |
321 | NIC_PUT(sc, MACE_XMTFC, APADXMT); | | 321 | NIC_PUT(sc, MACE_XMTFC, APADXMT); |
322 | /* | | 322 | /* |
323 | * No need to autostrip padding on receive... Ethernet frames | | 323 | * No need to autostrip padding on receive... Ethernet frames |
324 | * don't have a length field, unlike 802.3 frames, so the MACE | | 324 | * don't have a length field, unlike 802.3 frames, so the MACE |
325 | * can't figure out the length of the packet anyways. | | 325 | * can't figure out the length of the packet anyways. |
326 | */ | | 326 | */ |
327 | NIC_PUT(sc, MACE_RCVFC, 0); | | 327 | NIC_PUT(sc, MACE_RCVFC, 0); |
328 | | | 328 | |
329 | maccc = ENXMT | ENRCV; | | 329 | maccc = ENXMT | ENRCV; |
330 | if (sc->sc_if.if_flags & IFF_PROMISC) | | 330 | if (sc->sc_if.if_flags & IFF_PROMISC) |
331 | maccc |= PROM; | | 331 | maccc |= PROM; |
332 | | | 332 | |
333 | NIC_PUT(sc, MACE_MACCC, maccc); | | 333 | NIC_PUT(sc, MACE_MACCC, maccc); |
334 | | | 334 | |
335 | if (sc->sc_bus_init) | | 335 | if (sc->sc_bus_init) |
336 | (*sc->sc_bus_init)(sc); | | 336 | (*sc->sc_bus_init)(sc); |
337 | | | 337 | |
338 | /* | | 338 | /* |
339 | * Enable all interrupts except receive, since we use the DMA | | 339 | * Enable all interrupts except receive, since we use the DMA |
340 | * completion interrupt for that. | | 340 | * completion interrupt for that. |
341 | */ | | 341 | */ |
342 | NIC_PUT(sc, MACE_IMR, RCVINTM); | | 342 | NIC_PUT(sc, MACE_IMR, RCVINTM); |
343 | | | 343 | |
344 | /* flag interface as "running" */ | | 344 | /* flag interface as "running" */ |
345 | sc->sc_if.if_flags |= IFF_RUNNING; | | 345 | sc->sc_if.if_flags |= IFF_RUNNING; |
346 | sc->sc_if.if_flags &= ~IFF_OACTIVE; | | 346 | sc->sc_if.if_flags &= ~IFF_OACTIVE; |
347 | | | 347 | |
348 | splx(s); | | 348 | splx(s); |
349 | return 0; | | 349 | return 0; |
350 | } | | 350 | } |
351 | | | 351 | |
352 | /* | | 352 | /* |
353 | * close down an interface and free its buffers | | 353 | * close down an interface and free its buffers |
354 | * Called on final close of device, or if mcinit() fails | | 354 | * Called on final close of device, or if mcinit() fails |
355 | * part way through. | | 355 | * part way through. |
356 | */ | | 356 | */ |
357 | hide int | | 357 | hide int |
358 | mcstop(struct mc_softc *sc) | | 358 | mcstop(struct mc_softc *sc) |
359 | { | | 359 | { |
360 | int s; | | 360 | int s; |
361 | | | 361 | |
362 | s = splnet(); | | 362 | s = splnet(); |
363 | | | 363 | |
364 | NIC_PUT(sc, MACE_BIUCC, SWRST); | | 364 | NIC_PUT(sc, MACE_BIUCC, SWRST); |
365 | DELAY(100); | | 365 | DELAY(100); |
366 | | | 366 | |
367 | sc->sc_if.if_timer = 0; | | 367 | sc->sc_if.if_timer = 0; |
368 | sc->sc_if.if_flags &= ~IFF_RUNNING; | | 368 | sc->sc_if.if_flags &= ~IFF_RUNNING; |
369 | | | 369 | |
370 | splx(s); | | 370 | splx(s); |
371 | return 0; | | 371 | return 0; |
372 | } | | 372 | } |
373 | | | 373 | |
374 | /* | | 374 | /* |
375 | * Called if any Tx packets remain unsent after 5 seconds, | | 375 | * Called if any Tx packets remain unsent after 5 seconds, |
376 | * In all cases we just reset the chip, and any retransmission | | 376 | * In all cases we just reset the chip, and any retransmission |
377 | * will be handled by higher level protocol timeouts. | | 377 | * will be handled by higher level protocol timeouts. |
378 | */ | | 378 | */ |
379 | hide void | | 379 | hide void |
380 | mcwatchdog(struct ifnet *ifp) | | 380 | mcwatchdog(struct ifnet *ifp) |
381 | { | | 381 | { |
382 | struct mc_softc *sc = ifp->if_softc; | | 382 | struct mc_softc *sc = ifp->if_softc; |
383 | | | 383 | |
384 | printf("mcwatchdog: resetting chip\n"); | | 384 | printf("mcwatchdog: resetting chip\n"); |
385 | mcreset(sc); | | 385 | mcreset(sc); |
386 | } | | 386 | } |
387 | | | 387 | |
388 | /* | | 388 | /* |
389 | * stuff packet into MACE (at splnet) | | 389 | * stuff packet into MACE (at splnet) |
390 | */ | | 390 | */ |
391 | integrate u_int | | 391 | integrate u_int |
392 | maceput(struct mc_softc *sc, struct mbuf *m) | | 392 | maceput(struct mc_softc *sc, struct mbuf *m) |
393 | { | | 393 | { |
394 | struct mbuf *n; | | 394 | struct mbuf *n; |
395 | u_int len, totlen = 0; | | 395 | u_int len, totlen = 0; |
396 | u_char *buff; | | 396 | u_char *buff; |
397 | | | 397 | |
398 | buff = (u_char*)sc->sc_txbuf + (sc->sc_txset == 0 ? 0 : 0x800); | | 398 | buff = (u_char*)sc->sc_txbuf + (sc->sc_txset == 0 ? 0 : 0x800); |
399 | | | 399 | |
400 | for (; m; m = n) { | | 400 | for (; m; m = n) { |
401 | u_char *data = mtod(m, u_char *); | | 401 | u_char *data = mtod(m, u_char *); |
402 | len = m->m_len; | | 402 | len = m->m_len; |
403 | totlen += len; | | 403 | totlen += len; |
404 | memcpy(buff, data, len); | | 404 | memcpy(buff, data, len); |
405 | buff += len; | | 405 | buff += len; |
406 | n = m_free(m); | | 406 | n = m_free(m); |
407 | } | | 407 | } |
408 | | | 408 | |
409 | if (totlen > PAGE_SIZE) | | 409 | if (totlen > PAGE_SIZE) |
410 | panic("%s: maceput: packet overflow", device_xname(sc->sc_dev)); | | 410 | panic("%s: maceput: packet overflow", device_xname(sc->sc_dev)); |
411 | | | 411 | |
412 | #if 0 | | 412 | #if 0 |
413 | if (totlen < ETHERMIN + sizeof(struct ether_header)) { | | 413 | if (totlen < ETHERMIN + sizeof(struct ether_header)) { |
414 | int pad = ETHERMIN + sizeof(struct ether_header) - totlen; | | 414 | int pad = ETHERMIN + sizeof(struct ether_header) - totlen; |
415 | memset(sc->sc_txbuf + totlen, 0, pad); | | 415 | memset(sc->sc_txbuf + totlen, 0, pad); |
416 | totlen = ETHERMIN + sizeof(struct ether_header); | | 416 | totlen = ETHERMIN + sizeof(struct ether_header); |
417 | } | | 417 | } |
418 | #endif | | 418 | #endif |
419 | | | 419 | |
420 | (*sc->sc_putpacket)(sc, totlen); | | 420 | (*sc->sc_putpacket)(sc, totlen); |
421 | | | 421 | |
422 | sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */ | | 422 | sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */ |
423 | return totlen; | | 423 | return totlen; |
424 | } | | 424 | } |
425 | | | 425 | |
426 | void | | 426 | void |
427 | mcintr(void *arg) | | 427 | mcintr(void *arg) |
428 | { | | 428 | { |
429 | struct mc_softc *sc = arg; | | 429 | struct mc_softc *sc = arg; |
430 | uint8_t ir; | | 430 | uint8_t ir; |
431 | | | 431 | |
432 | ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR); | | 432 | ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR); |
433 | if (ir & JAB) { | | 433 | if (ir & JAB) { |
434 | #ifdef MCDEBUG | | 434 | #ifdef MCDEBUG |
435 | printf("%s: jabber error\n", device_xname(sc->sc_dev)); | | 435 | printf("%s: jabber error\n", device_xname(sc->sc_dev)); |
436 | #endif | | 436 | #endif |
437 | if_statinc(&sc->sc_if, if_oerrors); | | 437 | if_statinc(&sc->sc_if, if_oerrors); |
438 | } | | 438 | } |
439 | | | 439 | |
440 | if (ir & BABL) { | | 440 | if (ir & BABL) { |
441 | #ifdef MCDEBUG | | 441 | #ifdef MCDEBUG |
442 | printf("%s: babble\n", device_xname(sc->sc_dev)); | | 442 | printf("%s: babble\n", device_xname(sc->sc_dev)); |
443 | #endif | | 443 | #endif |
444 | if_statinc(&sc->sc_if, if_oerrors); | | 444 | if_statinc(&sc->sc_if, if_oerrors); |
445 | } | | 445 | } |
446 | | | 446 | |
447 | if (ir & CERR) { | | 447 | if (ir & CERR) { |
448 | #ifdef MCDEBUG | | 448 | #ifdef MCDEBUG |
449 | printf("%s: collision error\n", device_xname(sc->sc_dev)); | | 449 | printf("%s: collision error\n", device_xname(sc->sc_dev)); |
450 | #endif | | 450 | #endif |
451 | if_statinc(&sc->sc_if, if_collisions); | | 451 | if_statinc(&sc->sc_if, if_collisions); |
452 | } | | 452 | } |
453 | | | 453 | |
454 | /* | | 454 | /* |
455 | * Pretend we have carrier; if we don't this will be cleared | | 455 | * Pretend we have carrier; if we don't this will be cleared |
456 | * shortly. | | 456 | * shortly. |
457 | */ | | 457 | */ |
458 | sc->sc_havecarrier = 1; | | 458 | sc->sc_havecarrier = 1; |
459 | | | 459 | |
460 | if (ir & XMTINT) | | 460 | if (ir & XMTINT) |
461 | mc_tint(sc); | | 461 | mc_tint(sc); |
462 | | | 462 | |
463 | if (ir & RCVINT) | | 463 | if (ir & RCVINT) |
464 | mc_rint(sc); | | 464 | mc_rint(sc); |
465 | } | | 465 | } |
466 | | | 466 | |
467 | integrate void | | 467 | integrate void |
468 | mc_tint(struct mc_softc *sc) | | 468 | mc_tint(struct mc_softc *sc) |
469 | { | | 469 | { |
470 | uint8_t /* xmtrc,*/ xmtfs; | | 470 | uint8_t /* xmtrc,*/ xmtfs; |
471 | | | 471 | |
472 | /* xmtrc = */ NIC_GET(sc, MACE_XMTRC); | | 472 | /* xmtrc = */ NIC_GET(sc, MACE_XMTRC); |
473 | xmtfs = NIC_GET(sc, MACE_XMTFS); | | 473 | xmtfs = NIC_GET(sc, MACE_XMTFS); |
474 | | | 474 | |
475 | if ((xmtfs & XMTSV) == 0) | | 475 | if ((xmtfs & XMTSV) == 0) |
476 | return; | | 476 | return; |
477 | | | 477 | |
478 | if (xmtfs & UFLO) { | | 478 | if (xmtfs & UFLO) { |
479 | printf("%s: underflow\n", device_xname(sc->sc_dev)); | | 479 | printf("%s: underflow\n", device_xname(sc->sc_dev)); |
480 | mcreset(sc); | | 480 | mcreset(sc); |
481 | return; | | 481 | return; |
482 | } | | 482 | } |
483 | | | 483 | |
484 | net_stat_ref_t nsr = IF_STAT_GETREF(&sc->sc_if); | | 484 | net_stat_ref_t nsr = IF_STAT_GETREF(&sc->sc_if); |
485 | | | 485 | |
486 | if (xmtfs & LCOL) { | | 486 | if (xmtfs & LCOL) { |
487 | printf("%s: late collision\n", device_xname(sc->sc_dev)); | | 487 | printf("%s: late collision\n", device_xname(sc->sc_dev)); |
488 | if_statinc_ref(nsr, if_oerrors); | | 488 | if_statinc_ref(nsr, if_oerrors); |
489 | if_statinc_ref(nsr, if_collisions); | | 489 | if_statinc_ref(nsr, if_collisions); |
490 | } | | 490 | } |
491 | | | 491 | |
492 | if (xmtfs & MORE) | | 492 | if (xmtfs & MORE) |
493 | /* Real number is unknown. */ | | 493 | /* Real number is unknown. */ |
494 | if_statadd_ref(nsr, if_collsions, 2); | | 494 | if_statadd_ref(nsr, if_collisons, 2); |
495 | else if (xmtfs & ONE) | | 495 | else if (xmtfs & ONE) |
496 | if_statinc_ref(nsr, if_collisions); | | 496 | if_statinc_ref(nsr, if_collisions); |
497 | else if (xmtfs & RTRY) { | | 497 | else if (xmtfs & RTRY) { |
498 | printf("%s: excessive collisions\n", device_xname(sc->sc_dev)); | | 498 | printf("%s: excessive collisions\n", device_xname(sc->sc_dev)); |
499 | if_statadd_ref(nsr, if_collsions, 16); | | 499 | if_statadd_ref(nsr, if_collsions, 16); |
500 | if_statinc_ref(nsr, if_oerrors); | | 500 | if_statinc_ref(nsr, if_oerrors); |
501 | } | | 501 | } |
502 | | | 502 | |
503 | if (xmtfs & LCAR) { | | 503 | if (xmtfs & LCAR) { |
504 | sc->sc_havecarrier = 0; | | 504 | sc->sc_havecarrier = 0; |
505 | printf("%s: lost carrier\n", device_xname(sc->sc_dev)); | | 505 | printf("%s: lost carrier\n", device_xname(sc->sc_dev)); |
506 | if_statinc_ref(nsr, if_oerrors); | | 506 | if_statinc_ref(nsr, if_oerrors); |
507 | } | | 507 | } |
508 | | | 508 | |
509 | IF_STAT_PUTREF(&sc->sc_if); | | 509 | IF_STAT_PUTREF(&sc->sc_if); |
510 | | | 510 | |
511 | sc->sc_if.if_flags &= ~IFF_OACTIVE; | | 511 | sc->sc_if.if_flags &= ~IFF_OACTIVE; |
512 | sc->sc_if.if_timer = 0; | | 512 | sc->sc_if.if_timer = 0; |
513 | if_schedule_deferred_start(&sc->sc_if); | | 513 | if_schedule_deferred_start(&sc->sc_if); |
514 | } | | 514 | } |
515 | | | 515 | |
516 | void | | 516 | void |
517 | mc_rint(struct mc_softc *sc) | | 517 | mc_rint(struct mc_softc *sc) |
518 | { | | 518 | { |
519 | #define rxf sc->sc_rxframe | | 519 | #define rxf sc->sc_rxframe |
520 | u_int len; | | 520 | u_int len; |
521 | | | 521 | |
522 | len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4; | | 522 | len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4; |
523 | | | 523 | |
524 | #ifdef MCDEBUG | | 524 | #ifdef MCDEBUG |
525 | if (rxf.rx_rcvsts & 0xf0) | | 525 | if (rxf.rx_rcvsts & 0xf0) |
526 | printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n", | | 526 | printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n", |
527 | device_xname(sc->sc_dev), rxf.rx_rcvcnt, rxf.rx_rcvsts, | | 527 | device_xname(sc->sc_dev), rxf.rx_rcvcnt, rxf.rx_rcvsts, |
528 | rxf.rx_rntpc, rxf.rx_rcvcc); | | 528 | rxf.rx_rntpc, rxf.rx_rcvcc); |
529 | #endif | | 529 | #endif |
530 | | | 530 | |
531 | if (rxf.rx_rcvsts & OFLO) { | | 531 | if (rxf.rx_rcvsts & OFLO) { |
532 | printf("%s: receive FIFO overflow\n", device_xname(sc->sc_dev)); | | 532 | printf("%s: receive FIFO overflow\n", device_xname(sc->sc_dev)); |
533 | if_statinc(&sc->sc_if, if_ierrors); | | 533 | if_statinc(&sc->sc_if, if_ierrors); |
534 | return; | | 534 | return; |
535 | } | | 535 | } |
536 | | | 536 | |
537 | if (rxf.rx_rcvsts & CLSN) | | 537 | if (rxf.rx_rcvsts & CLSN) |
538 | if_statinc(&sc->sc_if, if_collisions); | | 538 | if_statinc(&sc->sc_if, if_collisions); |
539 | | | 539 | |
540 | if (rxf.rx_rcvsts & FRAM) { | | 540 | if (rxf.rx_rcvsts & FRAM) { |
541 | #ifdef MCDEBUG | | 541 | #ifdef MCDEBUG |
542 | printf("%s: framing error\n", device_xname(sc->sc_dev)); | | 542 | printf("%s: framing error\n", device_xname(sc->sc_dev)); |
543 | #endif | | 543 | #endif |
544 | if_statinc(&sc->sc_if, if_ierrors); | | 544 | if_statinc(&sc->sc_if, if_ierrors); |
545 | return; | | 545 | return; |
546 | } | | 546 | } |
547 | | | 547 | |
548 | if (rxf.rx_rcvsts & FCS) { | | 548 | if (rxf.rx_rcvsts & FCS) { |
549 | #ifdef MCDEBUG | | 549 | #ifdef MCDEBUG |
550 | printf("%s: frame control checksum error\n", device_xname(sc->sc_dev)); | | 550 | printf("%s: frame control checksum error\n", device_xname(sc->sc_dev)); |
551 | #endif | | 551 | #endif |
552 | if_statinc(&sc->sc_if, if_ierrors); | | 552 | if_statinc(&sc->sc_if, if_ierrors); |
553 | return; | | 553 | return; |
554 | } | | 554 | } |
555 | | | 555 | |
556 | mace_read(sc, rxf.rx_frame, len); | | 556 | mace_read(sc, rxf.rx_frame, len); |
557 | #undef rxf | | 557 | #undef rxf |
558 | } | | 558 | } |
559 | | | 559 | |
560 | integrate void | | 560 | integrate void |
561 | mace_read(struct mc_softc *sc, void *pkt, int len) | | 561 | mace_read(struct mc_softc *sc, void *pkt, int len) |
562 | { | | 562 | { |
563 | struct ifnet *ifp = &sc->sc_if; | | 563 | struct ifnet *ifp = &sc->sc_if; |
564 | struct mbuf *m; | | 564 | struct mbuf *m; |
565 | | | 565 | |
566 | if (len <= sizeof(struct ether_header) || | | 566 | if (len <= sizeof(struct ether_header) || |
567 | len > ETHERMTU + sizeof(struct ether_header)) { | | 567 | len > ETHERMTU + sizeof(struct ether_header)) { |
568 | #ifdef MCDEBUG | | 568 | #ifdef MCDEBUG |
569 | printf("%s: invalid packet size %d; dropping\n", | | 569 | printf("%s: invalid packet size %d; dropping\n", |
570 | device_xname(sc->sc_dev), len); | | 570 | device_xname(sc->sc_dev), len); |
571 | #endif | | 571 | #endif |
572 | if_statinc(ifp, if_ierrors); | | 572 | if_statinc(ifp, if_ierrors); |
573 | return; | | 573 | return; |
574 | } | | 574 | } |
575 | | | 575 | |
576 | m = mace_get(sc, pkt, len); | | 576 | m = mace_get(sc, pkt, len); |
577 | if (m == NULL) { | | 577 | if (m == NULL) { |
578 | if_statinc(ifp, if_ierrors); | | 578 | if_statinc(ifp, if_ierrors); |
579 | return; | | 579 | return; |
580 | } | | 580 | } |
581 | | | 581 | |
582 | /* Pass the packet up. */ | | 582 | /* Pass the packet up. */ |
583 | if_percpuq_enqueue(ifp->if_percpuq, m); | | 583 | if_percpuq_enqueue(ifp->if_percpuq, m); |
584 | } | | 584 | } |
585 | | | 585 | |
586 | /* | | 586 | /* |
587 | * Pull data off an interface. | | 587 | * Pull data off an interface. |
588 | * Len is length of data, with local net header stripped. | | 588 | * Len is length of data, with local net header stripped. |
589 | * We copy the data into mbufs. When full cluster sized units are present | | 589 | * We copy the data into mbufs. When full cluster sized units are present |
590 | * we copy into clusters. | | 590 | * we copy into clusters. |
591 | */ | | 591 | */ |
592 | integrate struct mbuf * | | 592 | integrate struct mbuf * |
593 | mace_get(struct mc_softc *sc, void *pkt, int totlen) | | 593 | mace_get(struct mc_softc *sc, void *pkt, int totlen) |
594 | { | | 594 | { |
595 | struct mbuf *m; | | 595 | struct mbuf *m; |
596 | struct mbuf *top, **mp; | | 596 | struct mbuf *top, **mp; |
597 | int len; | | 597 | int len; |
598 | | | 598 | |
599 | MGETHDR(m, M_DONTWAIT, MT_DATA); | | 599 | MGETHDR(m, M_DONTWAIT, MT_DATA); |
600 | if (m == 0) | | 600 | if (m == 0) |
601 | return 0; | | 601 | return 0; |
602 | m_set_rcvif(m, &sc->sc_if); | | 602 | m_set_rcvif(m, &sc->sc_if); |
603 | m->m_pkthdr.len = totlen; | | 603 | m->m_pkthdr.len = totlen; |
604 | len = MHLEN; | | 604 | len = MHLEN; |
605 | top = 0; | | 605 | top = 0; |
606 | mp = ⊤ | | 606 | mp = ⊤ |
607 | | | 607 | |
608 | while (totlen > 0) { | | 608 | while (totlen > 0) { |
609 | if (top) { | | 609 | if (top) { |
610 | MGET(m, M_DONTWAIT, MT_DATA); | | 610 | MGET(m, M_DONTWAIT, MT_DATA); |
611 | if (m == 0) { | | 611 | if (m == 0) { |
612 | m_freem(top); | | 612 | m_freem(top); |
613 | return 0; | | 613 | return 0; |
614 | } | | 614 | } |
615 | len = MLEN; | | 615 | len = MLEN; |
616 | } | | 616 | } |
617 | if (totlen >= MINCLSIZE) { | | 617 | if (totlen >= MINCLSIZE) { |
618 | MCLGET(m, M_DONTWAIT); | | 618 | MCLGET(m, M_DONTWAIT); |
619 | if ((m->m_flags & M_EXT) == 0) { | | 619 | if ((m->m_flags & M_EXT) == 0) { |
620 | m_free(m); | | 620 | m_free(m); |
621 | m_freem(top); | | 621 | m_freem(top); |
622 | return 0; | | 622 | return 0; |
623 | } | | 623 | } |
624 | len = MCLBYTES; | | 624 | len = MCLBYTES; |
625 | } | | 625 | } |
626 | m->m_len = len = uimin(totlen, len); | | 626 | m->m_len = len = uimin(totlen, len); |
627 | memcpy(mtod(m, void *), pkt, len); | | 627 | memcpy(mtod(m, void *), pkt, len); |
628 | pkt = (char*)pkt + len; | | 628 | pkt = (char*)pkt + len; |
629 | totlen -= len; | | 629 | totlen -= len; |
630 | *mp = m; | | 630 | *mp = m; |
631 | mp = &m->m_next; | | 631 | mp = &m->m_next; |
632 | } | | 632 | } |
633 | | | 633 | |
634 | return top; | | 634 | return top; |
635 | } | | 635 | } |
636 | | | 636 | |
637 | /* | | 637 | /* |
638 | * Go through the list of multicast addresses and calculate the logical | | 638 | * Go through the list of multicast addresses and calculate the logical |
639 | * address filter. | | 639 | * address filter. |
640 | */ | | 640 | */ |
641 | void | | 641 | void |
642 | mace_calcladrf(struct ethercom *ec, uint8_t *af) | | 642 | mace_calcladrf(struct ethercom *ec, uint8_t *af) |
643 | { | | 643 | { |
644 | struct ifnet *ifp = &ec->ec_if; | | 644 | struct ifnet *ifp = &ec->ec_if; |
645 | struct ether_multi *enm; | | 645 | struct ether_multi *enm; |
646 | u_char *cp; | | 646 | u_char *cp; |
647 | uint32_t crc; | | 647 | uint32_t crc; |
648 | static const uint32_t crctab[] = { | | 648 | static const uint32_t crctab[] = { |
649 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, | | 649 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
650 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, | | 650 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
651 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, | | 651 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, |
652 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c | | 652 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c |
653 | }; | | 653 | }; |
654 | int len; | | 654 | int len; |
655 | struct ether_multistep step; | | 655 | struct ether_multistep step; |
656 | | | 656 | |
657 | /* | | 657 | /* |
658 | * Set up multicast address filter by passing all multicast addresses | | 658 | * Set up multicast address filter by passing all multicast addresses |
659 | * through a crc generator, and then using the high order 6 bits as an | | 659 | * through a crc generator, and then using the high order 6 bits as an |
660 | * index into the 64 bit logical address filter. The high order bit | | 660 | * index into the 64 bit logical address filter. The high order bit |
661 | * selects the word, while the rest of the bits select the bit within | | 661 | * selects the word, while the rest of the bits select the bit within |
662 | * the word. | | 662 | * the word. |
663 | */ | | 663 | */ |
664 | | | 664 | |
665 | *((uint32_t *)af) = *((uint32_t *)af + 1) = 0; | | 665 | *((uint32_t *)af) = *((uint32_t *)af + 1) = 0; |
666 | ETHER_LOCK(ec); | | 666 | ETHER_LOCK(ec); |
667 | ETHER_FIRST_MULTI(step, ec, enm); | | 667 | ETHER_FIRST_MULTI(step, ec, enm); |
668 | while (enm != NULL) { | | 668 | while (enm != NULL) { |
669 | if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) { | | 669 | if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) { |
670 | /* | | 670 | /* |
671 | * We must listen to a range of multicast addresses. | | 671 | * We must listen to a range of multicast addresses. |
672 | * For now, just accept all multicasts, rather than | | 672 | * For now, just accept all multicasts, rather than |
673 | * trying to set only those filter bits needed to match | | 673 | * trying to set only those filter bits needed to match |
674 | * the range. (At this time, the only use of address | | 674 | * the range. (At this time, the only use of address |
675 | * ranges is for IP multicast routing, for which the | | 675 | * ranges is for IP multicast routing, for which the |
676 | * range is big enough to require all bits set.) | | 676 | * range is big enough to require all bits set.) |
677 | */ | | 677 | */ |
678 | ETHER_UNLOCK(ec); | | 678 | ETHER_UNLOCK(ec); |
679 | goto allmulti; | | 679 | goto allmulti; |
680 | } | | 680 | } |
681 | | | 681 | |
682 | cp = enm->enm_addrlo; | | 682 | cp = enm->enm_addrlo; |
683 | crc = 0xffffffff; | | 683 | crc = 0xffffffff; |
684 | for (len = sizeof(enm->enm_addrlo); --len >= 0;) { | | 684 | for (len = sizeof(enm->enm_addrlo); --len >= 0;) { |
685 | crc ^= *cp++; | | 685 | crc ^= *cp++; |
686 | crc = (crc >> 4) ^ crctab[crc & 0xf]; | | 686 | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
687 | crc = (crc >> 4) ^ crctab[crc & 0xf]; | | 687 | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
688 | } | | 688 | } |
689 | /* Just want the 6 most significant bits. */ | | 689 | /* Just want the 6 most significant bits. */ |
690 | crc >>= 26; | | 690 | crc >>= 26; |
691 | | | 691 | |
692 | /* Set the corresponding bit in the filter. */ | | 692 | /* Set the corresponding bit in the filter. */ |
693 | af[crc >> 3] |= 1 << (crc & 7); | | 693 | af[crc >> 3] |= 1 << (crc & 7); |
694 | | | 694 | |
695 | ETHER_NEXT_MULTI(step, enm); | | 695 | ETHER_NEXT_MULTI(step, enm); |
696 | } | | 696 | } |
697 | ETHER_UNLOCK(ec); | | 697 | ETHER_UNLOCK(ec); |
698 | ifp->if_flags &= ~IFF_ALLMULTI; | | 698 | ifp->if_flags &= ~IFF_ALLMULTI; |
699 | return; | | 699 | return; |
700 | | | 700 | |
701 | allmulti: | | 701 | allmulti: |
702 | ifp->if_flags |= IFF_ALLMULTI; | | 702 | ifp->if_flags |= IFF_ALLMULTI; |
703 | *((uint32_t *)af) = *((uint32_t *)af + 1) = 0xffffffff; | | 703 | *((uint32_t *)af) = *((uint32_t *)af + 1) = 0xffffffff; |
704 | } | | 704 | } |
705 | | | 705 | |
706 | static u_char bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}; | | 706 | static u_char bbr4[] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}; |
707 | #define bbr(v) ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf]) | | 707 | #define bbr(v) ((bbr4[(v)&0xf] << 4) | bbr4[((v)>>4) & 0xf]) |
708 | | | 708 | |
709 | u_char | | 709 | u_char |
710 | mc_get_enaddr(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, | | 710 | mc_get_enaddr(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, |
711 | u_char *dst) | | 711 | u_char *dst) |
712 | { | | 712 | { |
713 | int i; | | 713 | int i; |
714 | u_char b, csum; | | 714 | u_char b, csum; |
715 | | | 715 | |
716 | /* | | 716 | /* |
717 | * The XOR of the 8 bytes of the ROM must be 0xff for it to be | | 717 | * The XOR of the 8 bytes of the ROM must be 0xff for it to be |
718 | * valid | | 718 | * valid |
719 | */ | | 719 | */ |
720 | for (i = 0, csum = 0; i < 8; i++) { | | 720 | for (i = 0, csum = 0; i < 8; i++) { |
721 | b = bus_space_read_1(t, h, o+16*i); | | 721 | b = bus_space_read_1(t, h, o+16*i); |
722 | if (i < ETHER_ADDR_LEN) | | 722 | if (i < ETHER_ADDR_LEN) |
723 | dst[i] = bbr(b); | | 723 | dst[i] = bbr(b); |
724 | csum ^= b; | | 724 | csum ^= b; |
725 | } | | 725 | } |
726 | | | 726 | |
727 | return csum; | | 727 | return csum; |
728 | } | | 728 | } |