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