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