if_bm.c revision 1.41 1 /* $NetBSD: if_bm.c,v 1.41 2010/01/19 22:06:21 pooka Exp $ */
2
3 /*-
4 * Copyright (C) 1998, 1999, 2000 Tsubai Masanari. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: if_bm.c,v 1.41 2010/01/19 22:06:21 pooka Exp $");
31
32 #include "opt_inet.h"
33
34 #include <sys/param.h>
35 #include <sys/device.h>
36 #include <sys/ioctl.h>
37 #include <sys/kernel.h>
38 #include <sys/mbuf.h>
39 #include <sys/socket.h>
40 #include <sys/systm.h>
41 #include <sys/callout.h>
42
43 #include <uvm/uvm_extern.h>
44
45 #include <net/if.h>
46 #include <net/if_dl.h>
47 #include <net/if_ether.h>
48 #include <net/if_media.h>
49
50 #include <net/bpf.h>
51
52 #ifdef INET
53 #include <netinet/in.h>
54 #include <netinet/if_inarp.h>
55 #endif
56
57
58 #include <dev/ofw/openfirm.h>
59
60 #include <dev/mii/mii.h>
61 #include <dev/mii/miivar.h>
62 #include <dev/mii/mii_bitbang.h>
63
64 #include <powerpc/spr.h>
65
66 #include <machine/autoconf.h>
67 #include <machine/pio.h>
68
69 #include <macppc/dev/dbdma.h>
70 #include <macppc/dev/if_bmreg.h>
71 #include <macppc/dev/obiovar.h>
72
73 #define BMAC_TXBUFS 2
74 #define BMAC_RXBUFS 16
75 #define BMAC_BUFLEN 2048
76
77 struct bmac_softc {
78 struct device sc_dev;
79 struct ethercom sc_ethercom;
80 #define sc_if sc_ethercom.ec_if
81 struct callout sc_tick_ch;
82 bus_space_tag_t sc_iot;
83 bus_space_handle_t sc_ioh;
84 dbdma_regmap_t *sc_txdma;
85 dbdma_regmap_t *sc_rxdma;
86 dbdma_command_t *sc_txcmd;
87 dbdma_command_t *sc_rxcmd;
88 void *sc_txbuf;
89 void *sc_rxbuf;
90 int sc_rxlast;
91 int sc_flags;
92 struct mii_data sc_mii;
93 u_char sc_enaddr[6];
94 };
95
96 #define BMAC_BMACPLUS 0x01
97 #define BMAC_DEBUGFLAG 0x02
98
99 int bmac_match(struct device *, struct cfdata *, void *);
100 void bmac_attach(struct device *, struct device *, void *);
101 void bmac_reset_chip(struct bmac_softc *);
102 void bmac_init(struct bmac_softc *);
103 void bmac_init_dma(struct bmac_softc *);
104 int bmac_intr(void *);
105 int bmac_rint(void *);
106 void bmac_reset(struct bmac_softc *);
107 void bmac_stop(struct bmac_softc *);
108 void bmac_start(struct ifnet *);
109 void bmac_transmit_packet(struct bmac_softc *, void *, int);
110 int bmac_put(struct bmac_softc *, void *, struct mbuf *);
111 struct mbuf *bmac_get(struct bmac_softc *, void *, int);
112 void bmac_watchdog(struct ifnet *);
113 int bmac_ioctl(struct ifnet *, u_long, void *);
114 void bmac_setladrf(struct bmac_softc *);
115
116 int bmac_mii_readreg(struct device *, int, int);
117 void bmac_mii_writereg(struct device *, int, int, int);
118 void bmac_mii_statchg(struct device *);
119 void bmac_mii_tick(void *);
120 u_int32_t bmac_mbo_read(struct device *);
121 void bmac_mbo_write(struct device *, u_int32_t);
122
123 CFATTACH_DECL(bm, sizeof(struct bmac_softc),
124 bmac_match, bmac_attach, NULL, NULL);
125
126 const struct mii_bitbang_ops bmac_mbo = {
127 bmac_mbo_read, bmac_mbo_write,
128 { MIFDO, MIFDI, MIFDC, MIFDIR, 0 }
129 };
130
131 static inline uint16_t
132 bmac_read_reg(struct bmac_softc *sc, bus_size_t off)
133 {
134 return bus_space_read_2(sc->sc_iot, sc->sc_ioh, off);
135 }
136
137 static inline void
138 bmac_write_reg(struct bmac_softc *sc, bus_size_t off, uint16_t val)
139 {
140 bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, val);
141 }
142
143 static inline void
144 bmac_set_bits(struct bmac_softc *sc, bus_size_t off, uint16_t val)
145 {
146 val |= bmac_read_reg(sc, off);
147 bmac_write_reg(sc, off, val);
148 }
149
150 static inline void
151 bmac_reset_bits(struct bmac_softc *sc, bus_size_t off, uint16_t val)
152 {
153 bmac_write_reg(sc, off, bmac_read_reg(sc, off) & ~val);
154 }
155
156 int
157 bmac_match(struct device *parent, struct cfdata *cf, void *aux)
158 {
159 struct confargs *ca = aux;
160
161 if (ca->ca_nreg < 24 || ca->ca_nintr < 12)
162 return 0;
163
164 if (strcmp(ca->ca_name, "bmac") == 0) /* bmac */
165 return 1;
166 if (strcmp(ca->ca_name, "ethernet") == 0) /* bmac+ */
167 return 1;
168
169 return 0;
170 }
171
172 void
173 bmac_attach(struct device *parent, struct device *self, void *aux)
174 {
175 struct confargs *ca = aux;
176 struct bmac_softc *sc = (void *)self;
177 struct ifnet *ifp = &sc->sc_if;
178 struct mii_data *mii = &sc->sc_mii;
179 u_char laddr[6];
180
181 callout_init(&sc->sc_tick_ch, 0);
182
183 sc->sc_flags =0;
184 if (strcmp(ca->ca_name, "ethernet") == 0) {
185 char name[64];
186
187 memset(name, 0, 64);
188 OF_package_to_path(ca->ca_node, name, sizeof(name));
189 OF_open(name);
190 sc->sc_flags |= BMAC_BMACPLUS;
191 }
192
193 ca->ca_reg[0] += ca->ca_baseaddr;
194 ca->ca_reg[2] += ca->ca_baseaddr;
195 ca->ca_reg[4] += ca->ca_baseaddr;
196
197 sc->sc_iot = ca->ca_tag;
198 if (bus_space_map(sc->sc_iot, ca->ca_reg[0], ca->ca_reg[1], 0,
199 &sc->sc_ioh) != 0) {
200 aprint_error(": couldn't map %#x", ca->ca_reg[0]);
201 return;
202 }
203
204 bmac_write_reg(sc, INTDISABLE, NoEventsMask);
205
206 if (OF_getprop(ca->ca_node, "local-mac-address", laddr, 6) == -1 &&
207 OF_getprop(ca->ca_node, "mac-address", laddr, 6) == -1) {
208 printf(": cannot get mac-address\n");
209 return;
210 }
211 memcpy(sc->sc_enaddr, laddr, 6);
212
213 sc->sc_txdma = mapiodev(ca->ca_reg[2], PAGE_SIZE);
214 sc->sc_rxdma = mapiodev(ca->ca_reg[4], PAGE_SIZE);
215 sc->sc_txcmd = dbdma_alloc(BMAC_TXBUFS * sizeof(dbdma_command_t));
216 sc->sc_rxcmd = dbdma_alloc((BMAC_RXBUFS + 1) * sizeof(dbdma_command_t));
217 sc->sc_txbuf = malloc(BMAC_BUFLEN * BMAC_TXBUFS, M_DEVBUF, M_NOWAIT);
218 sc->sc_rxbuf = malloc(BMAC_BUFLEN * BMAC_RXBUFS, M_DEVBUF, M_NOWAIT);
219 if (sc->sc_txbuf == NULL || sc->sc_rxbuf == NULL ||
220 sc->sc_txcmd == NULL || sc->sc_rxcmd == NULL) {
221 printf("cannot allocate memory\n");
222 return;
223 }
224
225 printf(" irq %d,%d: address %s\n", ca->ca_intr[0], ca->ca_intr[2],
226 ether_sprintf(laddr));
227
228 intr_establish(ca->ca_intr[0], IST_EDGE, IPL_NET, bmac_intr, sc);
229 intr_establish(ca->ca_intr[2], IST_EDGE, IPL_NET, bmac_rint, sc);
230
231 memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
232 ifp->if_softc = sc;
233 ifp->if_ioctl = bmac_ioctl;
234 ifp->if_start = bmac_start;
235 ifp->if_flags =
236 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
237 ifp->if_watchdog = bmac_watchdog;
238 IFQ_SET_READY(&ifp->if_snd);
239
240 mii->mii_ifp = ifp;
241 mii->mii_readreg = bmac_mii_readreg;
242 mii->mii_writereg = bmac_mii_writereg;
243 mii->mii_statchg = bmac_mii_statchg;
244
245 sc->sc_ethercom.ec_mii = mii;
246 ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
247 mii_attach(&sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY,
248 MII_OFFSET_ANY, 0);
249
250 /* Choose a default media. */
251 if (LIST_FIRST(&mii->mii_phys) == NULL) {
252 ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_10_T, 0, NULL);
253 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_10_T);
254 } else
255 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO);
256
257 bmac_reset_chip(sc);
258
259 if_attach(ifp);
260 ether_ifattach(ifp, sc->sc_enaddr);
261 }
262
263 /*
264 * Reset and enable bmac by heathrow FCR.
265 */
266 void
267 bmac_reset_chip(struct bmac_softc *sc)
268 {
269 u_int v;
270
271 dbdma_reset(sc->sc_txdma);
272 dbdma_reset(sc->sc_rxdma);
273
274 v = obio_read_4(HEATHROW_FCR);
275
276 v |= EnetEnable;
277 obio_write_4(HEATHROW_FCR, v);
278 delay(50000);
279
280 v |= ResetEnetCell;
281 obio_write_4(HEATHROW_FCR, v);
282 delay(50000);
283
284 v &= ~ResetEnetCell;
285 obio_write_4(HEATHROW_FCR, v);
286 delay(50000);
287
288 obio_write_4(HEATHROW_FCR, v);
289 }
290
291 void
292 bmac_init(struct bmac_softc *sc)
293 {
294 struct ifnet *ifp = &sc->sc_if;
295 struct ether_header *eh;
296 void *data;
297 int i, tb, bmcr;
298 u_short *p;
299
300 bmac_reset_chip(sc);
301
302 /* XXX */
303 bmcr = bmac_mii_readreg((struct device *)sc, 0, MII_BMCR);
304 bmcr &= ~BMCR_ISO;
305 bmac_mii_writereg((struct device *)sc, 0, MII_BMCR, bmcr);
306
307 bmac_write_reg(sc, RXRST, RxResetValue);
308 bmac_write_reg(sc, TXRST, TxResetBit);
309
310 /* Wait for reset completion. */
311 for (i = 1000; i > 0; i -= 10) {
312 if ((bmac_read_reg(sc, TXRST) & TxResetBit) == 0)
313 break;
314 delay(10);
315 }
316 if (i <= 0)
317 printf("%s: reset timeout\n", ifp->if_xname);
318
319 if (! (sc->sc_flags & BMAC_BMACPLUS))
320 bmac_set_bits(sc, XCVRIF, ClkBit|SerialMode|COLActiveLow);
321
322 if ((mfpvr() >> 16) == MPC601)
323 tb = mfrtcl();
324 else
325 tb = mftbl();
326 bmac_write_reg(sc, RSEED, tb);
327 bmac_set_bits(sc, XIFC, TxOutputEnable);
328 bmac_read_reg(sc, PAREG);
329
330 /* Reset various counters. */
331 bmac_write_reg(sc, NCCNT, 0);
332 bmac_write_reg(sc, NTCNT, 0);
333 bmac_write_reg(sc, EXCNT, 0);
334 bmac_write_reg(sc, LTCNT, 0);
335 bmac_write_reg(sc, FRCNT, 0);
336 bmac_write_reg(sc, LECNT, 0);
337 bmac_write_reg(sc, AECNT, 0);
338 bmac_write_reg(sc, FECNT, 0);
339 bmac_write_reg(sc, RXCV, 0);
340
341 /* Set tx fifo information. */
342 bmac_write_reg(sc, TXTH, 4); /* 4 octets before tx starts */
343
344 bmac_write_reg(sc, TXFIFOCSR, 0);
345 bmac_write_reg(sc, TXFIFOCSR, TxFIFOEnable);
346
347 /* Set rx fifo information. */
348 bmac_write_reg(sc, RXFIFOCSR, 0);
349 bmac_write_reg(sc, RXFIFOCSR, RxFIFOEnable);
350
351 /* Clear status register. */
352 bmac_read_reg(sc, STATUS);
353
354 bmac_write_reg(sc, HASH3, 0);
355 bmac_write_reg(sc, HASH2, 0);
356 bmac_write_reg(sc, HASH1, 0);
357 bmac_write_reg(sc, HASH0, 0);
358
359 /* Set MAC address. */
360 p = (u_short *)sc->sc_enaddr;
361 bmac_write_reg(sc, MADD0, *p++);
362 bmac_write_reg(sc, MADD1, *p++);
363 bmac_write_reg(sc, MADD2, *p);
364
365 bmac_write_reg(sc, RXCFG,
366 RxCRCEnable | RxHashFilterEnable | RxRejectOwnPackets);
367
368 if (ifp->if_flags & IFF_PROMISC)
369 bmac_set_bits(sc, RXCFG, RxPromiscEnable);
370
371 bmac_init_dma(sc);
372
373 /* Enable TX/RX */
374 bmac_set_bits(sc, RXCFG, RxMACEnable);
375 bmac_set_bits(sc, TXCFG, TxMACEnable);
376
377 bmac_write_reg(sc, INTDISABLE, NormalIntEvents);
378
379 ifp->if_flags |= IFF_RUNNING;
380 ifp->if_flags &= ~IFF_OACTIVE;
381 ifp->if_timer = 0;
382
383 data = sc->sc_txbuf;
384 eh = (struct ether_header *)data;
385
386 memset(data, 0, sizeof(eh) + ETHERMIN);
387 memcpy(eh->ether_dhost, sc->sc_enaddr, ETHER_ADDR_LEN);
388 memcpy(eh->ether_shost, sc->sc_enaddr, ETHER_ADDR_LEN);
389 bmac_transmit_packet(sc, data, sizeof(eh) + ETHERMIN);
390
391 bmac_start(ifp);
392
393 callout_reset(&sc->sc_tick_ch, hz, bmac_mii_tick, sc);
394 }
395
396 void
397 bmac_init_dma(struct bmac_softc *sc)
398 {
399 dbdma_command_t *cmd = sc->sc_rxcmd;
400 int i;
401
402 dbdma_reset(sc->sc_txdma);
403 dbdma_reset(sc->sc_rxdma);
404
405 memset(sc->sc_txcmd, 0, BMAC_TXBUFS * sizeof(dbdma_command_t));
406 memset(sc->sc_rxcmd, 0, (BMAC_RXBUFS + 1) * sizeof(dbdma_command_t));
407
408 for (i = 0; i < BMAC_RXBUFS; i++) {
409 DBDMA_BUILD(cmd, DBDMA_CMD_IN_LAST, 0, BMAC_BUFLEN,
410 vtophys((vaddr_t)sc->sc_rxbuf + BMAC_BUFLEN * i),
411 DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
412 cmd++;
413 }
414 DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
415 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
416 out32rb(&cmd->d_cmddep, vtophys((vaddr_t)sc->sc_rxcmd));
417
418 sc->sc_rxlast = 0;
419
420 dbdma_start(sc->sc_rxdma, sc->sc_rxcmd);
421 }
422
423 int
424 bmac_intr(void *v)
425 {
426 struct bmac_softc *sc = v;
427 int stat;
428
429 stat = bmac_read_reg(sc, STATUS);
430 if (stat == 0)
431 return 0;
432
433 #ifdef BMAC_DEBUG
434 printf("bmac_intr status = 0x%x\n", stat);
435 #endif
436
437 if (stat & IntFrameSent) {
438 sc->sc_if.if_flags &= ~IFF_OACTIVE;
439 sc->sc_if.if_timer = 0;
440 sc->sc_if.if_opackets++;
441 bmac_start(&sc->sc_if);
442 }
443
444 /* XXX should do more! */
445
446 return 1;
447 }
448
449 int
450 bmac_rint(void *v)
451 {
452 struct bmac_softc *sc = v;
453 struct ifnet *ifp = &sc->sc_if;
454 struct mbuf *m;
455 dbdma_command_t *cmd;
456 int status, resid, count, datalen;
457 int i, n;
458 void *data;
459
460 i = sc->sc_rxlast;
461 for (n = 0; n < BMAC_RXBUFS; n++, i++) {
462 if (i == BMAC_RXBUFS)
463 i = 0;
464 cmd = &sc->sc_rxcmd[i];
465 status = in16rb(&cmd->d_status);
466 resid = in16rb(&cmd->d_resid);
467
468 #ifdef BMAC_DEBUG
469 if (status != 0 && status != 0x8440 && status != 0x9440)
470 printf("bmac_rint status = 0x%x\n", status);
471 #endif
472
473 if ((status & DBDMA_CNTRL_ACTIVE) == 0) /* 0x9440 | 0x8440 */
474 continue;
475 count = in16rb(&cmd->d_count);
476 datalen = count - resid - 2; /* 2 == framelen */
477 if (datalen < sizeof(struct ether_header)) {
478 printf("%s: short packet len = %d\n",
479 ifp->if_xname, datalen);
480 goto next;
481 }
482 DBDMA_BUILD_CMD(cmd, DBDMA_CMD_STOP, 0, 0, 0, 0);
483 data = (char *)sc->sc_rxbuf + BMAC_BUFLEN * i;
484
485 /* XXX Sometimes bmac reads one extra byte. */
486 if (datalen == ETHER_MAX_LEN + 1)
487 datalen--;
488
489 /* Trim the CRC. */
490 datalen -= ETHER_CRC_LEN;
491
492 m = bmac_get(sc, data, datalen);
493 if (m == NULL) {
494 ifp->if_ierrors++;
495 goto next;
496 }
497
498 /*
499 * Check if there's a BPF listener on this interface.
500 * If so, hand off the raw packet to BPF.
501 */
502 if (ifp->if_bpf)
503 bpf_ops->bpf_mtap(ifp->if_bpf, m);
504 (*ifp->if_input)(ifp, m);
505 ifp->if_ipackets++;
506
507 next:
508 DBDMA_BUILD_CMD(cmd, DBDMA_CMD_IN_LAST, 0, DBDMA_INT_ALWAYS,
509 DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
510
511 cmd->d_status = 0;
512 cmd->d_resid = 0;
513 sc->sc_rxlast = i + 1;
514 }
515 ether_mediachange(ifp);
516
517 dbdma_continue(sc->sc_rxdma);
518
519 return 1;
520 }
521
522 void
523 bmac_reset(struct bmac_softc *sc)
524 {
525 int s;
526
527 s = splnet();
528 bmac_init(sc);
529 splx(s);
530 }
531
532 void
533 bmac_stop(struct bmac_softc *sc)
534 {
535 struct ifnet *ifp = &sc->sc_if;
536 int s;
537
538 s = splnet();
539
540 callout_stop(&sc->sc_tick_ch);
541 mii_down(&sc->sc_mii);
542
543 /* Disable TX/RX. */
544 bmac_reset_bits(sc, TXCFG, TxMACEnable);
545 bmac_reset_bits(sc, RXCFG, RxMACEnable);
546
547 /* Disable all interrupts. */
548 bmac_write_reg(sc, INTDISABLE, NoEventsMask);
549
550 dbdma_stop(sc->sc_txdma);
551 dbdma_stop(sc->sc_rxdma);
552
553 ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
554 ifp->if_timer = 0;
555
556 splx(s);
557 }
558
559 void
560 bmac_start(struct ifnet *ifp)
561 {
562 struct bmac_softc *sc = ifp->if_softc;
563 struct mbuf *m;
564 int tlen;
565
566 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
567 return;
568
569 while (1) {
570 if (ifp->if_flags & IFF_OACTIVE)
571 return;
572
573 IFQ_DEQUEUE(&ifp->if_snd, m);
574 if (m == 0)
575 break;
576 /*
577 * If BPF is listening on this interface, let it see the
578 * packet before we commit it to the wire.
579 */
580 if (ifp->if_bpf)
581 bpf_ops->bpf_mtap(ifp->if_bpf, m);
582
583 ifp->if_flags |= IFF_OACTIVE;
584 tlen = bmac_put(sc, sc->sc_txbuf, m);
585
586 /* 5 seconds to watch for failing to transmit */
587 ifp->if_timer = 5;
588 ifp->if_opackets++; /* # of pkts */
589
590 bmac_transmit_packet(sc, sc->sc_txbuf, tlen);
591 }
592 }
593
594 void
595 bmac_transmit_packet(struct bmac_softc *sc, void *buff, int len)
596 {
597 dbdma_command_t *cmd = sc->sc_txcmd;
598 vaddr_t va = (vaddr_t)buff;
599
600 #ifdef BMAC_DEBUG
601 if (vtophys(va) + len - 1 != vtophys(va + len - 1))
602 panic("bmac_transmit_packet");
603 #endif
604
605 DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, len, vtophys(va),
606 DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
607 cmd++;
608 DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0,
609 DBDMA_INT_ALWAYS, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
610
611 dbdma_start(sc->sc_txdma, sc->sc_txcmd);
612 }
613
614 int
615 bmac_put(struct bmac_softc *sc, void *buff, struct mbuf *m)
616 {
617 struct mbuf *n;
618 int len, tlen = 0;
619
620 for (; m; m = n) {
621 len = m->m_len;
622 if (len == 0) {
623 MFREE(m, n);
624 continue;
625 }
626 memcpy(buff, mtod(m, void *), len);
627 buff = (char *)buff + len;
628 tlen += len;
629 MFREE(m, n);
630 }
631 if (tlen > PAGE_SIZE)
632 panic("%s: putpacket packet overflow", sc->sc_dev.dv_xname);
633
634 return tlen;
635 }
636
637 struct mbuf *
638 bmac_get(struct bmac_softc *sc, void *pkt, int totlen)
639 {
640 struct mbuf *m;
641 struct mbuf *top, **mp;
642 int len;
643
644 MGETHDR(m, M_DONTWAIT, MT_DATA);
645 if (m == 0)
646 return 0;
647 m->m_pkthdr.rcvif = &sc->sc_if;
648 m->m_pkthdr.len = totlen;
649 len = MHLEN;
650 top = 0;
651 mp = ⊤
652
653 while (totlen > 0) {
654 if (top) {
655 MGET(m, M_DONTWAIT, MT_DATA);
656 if (m == 0) {
657 m_freem(top);
658 return 0;
659 }
660 len = MLEN;
661 }
662 if (totlen >= MINCLSIZE) {
663 MCLGET(m, M_DONTWAIT);
664 if ((m->m_flags & M_EXT) == 0) {
665 m_free(m);
666 m_freem(top);
667 return 0;
668 }
669 len = MCLBYTES;
670 }
671 m->m_len = len = min(totlen, len);
672 memcpy(mtod(m, void *), pkt, len);
673 pkt = (char *)pkt + len;
674 totlen -= len;
675 *mp = m;
676 mp = &m->m_next;
677 }
678
679 return top;
680 }
681
682 void
683 bmac_watchdog(struct ifnet *ifp)
684 {
685 struct bmac_softc *sc = ifp->if_softc;
686
687 bmac_reset_bits(sc, RXCFG, RxMACEnable);
688 bmac_reset_bits(sc, TXCFG, TxMACEnable);
689
690 printf("%s: device timeout\n", ifp->if_xname);
691 ifp->if_oerrors++;
692
693 bmac_reset(sc);
694 }
695
696 int
697 bmac_ioctl(struct ifnet *ifp, unsigned long cmd, void *data)
698 {
699 struct bmac_softc *sc = ifp->if_softc;
700 struct ifaddr *ifa = (struct ifaddr *)data;
701 int s, error = 0;
702
703 s = splnet();
704
705 switch (cmd) {
706
707 case SIOCINITIFADDR:
708 ifp->if_flags |= IFF_UP;
709
710 bmac_init(sc);
711 switch (ifa->ifa_addr->sa_family) {
712 #ifdef INET
713 case AF_INET:
714 arp_ifinit(ifp, ifa);
715 break;
716 #endif
717 default:
718 break;
719 }
720 break;
721
722 case SIOCSIFFLAGS:
723 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
724 break;
725 /* XXX see the comment in ed_ioctl() about code re-use */
726 if ((ifp->if_flags & IFF_UP) == 0 &&
727 (ifp->if_flags & IFF_RUNNING) != 0) {
728 /*
729 * If interface is marked down and it is running, then
730 * stop it.
731 */
732 bmac_stop(sc);
733 ifp->if_flags &= ~IFF_RUNNING;
734 } else if ((ifp->if_flags & IFF_UP) != 0 &&
735 (ifp->if_flags & IFF_RUNNING) == 0) {
736 /*
737 * If interface is marked up and it is stopped, then
738 * start it.
739 */
740 bmac_init(sc);
741 } else {
742 /*
743 * Reset the interface to pick up changes in any other
744 * flags that affect hardware registers.
745 */
746 /*bmac_stop(sc);*/
747 bmac_init(sc);
748 }
749 #ifdef BMAC_DEBUG
750 if (ifp->if_flags & IFF_DEBUG)
751 sc->sc_flags |= BMAC_DEBUGFLAG;
752 #endif
753 break;
754
755 case SIOCADDMULTI:
756 case SIOCDELMULTI:
757 case SIOCGIFMEDIA:
758 case SIOCSIFMEDIA:
759 if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
760 /*
761 * Multicast list has changed; set the hardware filter
762 * accordingly.
763 */
764 if (ifp->if_flags & IFF_RUNNING) {
765 bmac_init(sc);
766 bmac_setladrf(sc);
767 }
768 error = 0;
769 }
770 break;
771 default:
772 error = ether_ioctl(ifp, cmd, data);
773 break;
774 }
775
776 splx(s);
777 return error;
778 }
779
780 /*
781 * Set up the logical address filter.
782 */
783 void
784 bmac_setladrf(struct bmac_softc *sc)
785 {
786 struct ifnet *ifp = &sc->sc_if;
787 struct ether_multi *enm;
788 struct ether_multistep step;
789 u_int32_t crc;
790 u_int16_t hash[4];
791 int x;
792
793 /*
794 * Set up multicast address filter by passing all multicast addresses
795 * through a crc generator, and then using the high order 6 bits as an
796 * index into the 64 bit logical address filter. The high order bit
797 * selects the word, while the rest of the bits select the bit within
798 * the word.
799 */
800
801 if (ifp->if_flags & IFF_PROMISC) {
802 bmac_set_bits(sc, RXCFG, RxPromiscEnable);
803 return;
804 }
805
806 if (ifp->if_flags & IFF_ALLMULTI) {
807 hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
808 goto chipit;
809 }
810
811 hash[3] = hash[2] = hash[1] = hash[0] = 0;
812
813 ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
814 while (enm != NULL) {
815 if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
816 /*
817 * We must listen to a range of multicast addresses.
818 * For now, just accept all multicasts, rather than
819 * trying to set only those filter bits needed to match
820 * the range. (At this time, the only use of address
821 * ranges is for IP multicast routing, for which the
822 * range is big enough to require all bits set.)
823 */
824 hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
825 ifp->if_flags |= IFF_ALLMULTI;
826 goto chipit;
827 }
828
829 crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
830
831 /* Just want the 6 most significant bits. */
832 crc >>= 26;
833
834 /* Set the corresponding bit in the filter. */
835 hash[crc >> 4] |= 1 << (crc & 0xf);
836
837 ETHER_NEXT_MULTI(step, enm);
838 }
839
840 ifp->if_flags &= ~IFF_ALLMULTI;
841
842 chipit:
843 bmac_write_reg(sc, HASH0, hash[0]);
844 bmac_write_reg(sc, HASH1, hash[1]);
845 bmac_write_reg(sc, HASH2, hash[2]);
846 bmac_write_reg(sc, HASH3, hash[3]);
847 x = bmac_read_reg(sc, RXCFG);
848 x &= ~RxPromiscEnable;
849 x |= RxHashFilterEnable;
850 bmac_write_reg(sc, RXCFG, x);
851 }
852
853 int
854 bmac_mii_readreg(struct device *dev, int phy, int reg)
855 {
856 return mii_bitbang_readreg(dev, &bmac_mbo, phy, reg);
857 }
858
859 void
860 bmac_mii_writereg(struct device *dev, int phy, int reg, int val)
861 {
862 mii_bitbang_writereg(dev, &bmac_mbo, phy, reg, val);
863 }
864
865 u_int32_t
866 bmac_mbo_read(struct device *dev)
867 {
868 struct bmac_softc *sc = (void *)dev;
869
870 return bmac_read_reg(sc, MIFCSR);
871 }
872
873 void
874 bmac_mbo_write(struct device *dev, u_int32_t val)
875 {
876 struct bmac_softc *sc = (void *)dev;
877
878 bmac_write_reg(sc, MIFCSR, val);
879 }
880
881 void
882 bmac_mii_statchg(struct device *dev)
883 {
884 struct bmac_softc *sc = (void *)dev;
885 int x;
886
887 /* Update duplex mode in TX configuration */
888 x = bmac_read_reg(sc, TXCFG);
889 if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0)
890 x |= TxFullDuplex;
891 else
892 x &= ~TxFullDuplex;
893 bmac_write_reg(sc, TXCFG, x);
894
895 #ifdef BMAC_DEBUG
896 printf("bmac_mii_statchg 0x%x\n",
897 IFM_OPTIONS(sc->sc_mii.mii_media_active));
898 #endif
899 }
900
901 void
902 bmac_mii_tick(void *v)
903 {
904 struct bmac_softc *sc = v;
905 int s;
906
907 s = splnet();
908 mii_tick(&sc->sc_mii);
909 splx(s);
910
911 callout_reset(&sc->sc_tick_ch, hz, bmac_mii_tick, sc);
912 }
913