mb86950.c revision 1.14 1 /* $NetBSD: mb86950.c,v 1.14 2009/03/14 15:36:17 dsl Exp $ */
2
3 /*
4 * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
5 *
6 * This software may be used, modified, copied, distributed, and sold, in
7 * both source and binary form provided that the above copyright, these
8 * terms and the following disclaimer are retained. The name of the author
9 * and/or the contributor may not be used to endorse or promote products
10 * derived from this software without specific prior written permission.
11 *
12 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND
13 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE
16 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION.
19 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22 * SUCH DAMAGE.
23 */
24
25 /*
26 * Portions copyright (C) 1993, David Greenman. This software may be used,
27 * modified, copied, distributed, and sold, in both source and binary form
28 * provided that the above copyright and these terms are retained. Under no
29 * circumstances is the author responsible for the proper functioning of this
30 * software, nor does the author assume any responsibility for damages
31 * incurred with its use.
32 */
33
34 /*
35 * Portions copyright (c) 1995 Mika Kortelainen
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by Mika Kortelainen
49 * 4. The name of the author may not be used to endorse or promote products
50 * derived from this software without specific prior written permission
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62 */
63
64 /*
65 * Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards.
66 * Contributed by M.S. <seki (at) sysrap.cs.fujitsu.co.jp>
67 */
68
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: mb86950.c,v 1.14 2009/03/14 15:36:17 dsl Exp $");
71
72 /*
73 * Device driver for Fujitsu mb86950 based Ethernet cards.
74 * Adapted by Dave J. Barnes from various Internet sources including
75 * mb86960.c (NetBSD), if_qn.c (NetBSD/Amiga), DOS Packet Driver (Brian Fisher,
76 * Queens University), EtherBoot Driver (Ken Yap).
77 */
78
79 /* XXX There are still rough edges......
80 *
81 * (1) There is no watchdog timer for the transmitter. It's doubtful that
82 * transmit from the chip could be restarted without a hardware reset
83 * though. (Fixed - not fully tested)
84 *
85 * (2) The media interface callback goo is broke. No big deal since to change
86 * from aui to bnc on the old Tiara LANCard requires moving 8 board jumpers.
87 * Other cards (SMC ?) using the EtherStar chip may support media change
88 * via software. (Fixed - tested)
89 *
90 * (3) The maximum outstanding transmit packets is set to 4. What
91 * is a good limit of outstanding transmit packets for the EtherStar?
92 * Is there a way to tell how many bytes are remaining to be
93 * transmitted? [no]
94 ---
95 When the EtherStar was designed, CPU power was a fraction
96 of what it is now. The single EtherStar transmit buffer
97 was fine. It was unlikely that the CPU could outrun the
98 EtherStar. However, things in 2004 are quite different.
99 sc->txb_size is used to keep the CPU from overrunning the
100 EtherStar. At most allow one packet transmitting and one
101 going into the fifo.
102
103 ---
104 No, that isn't right either :(
105
106 * (4) Multicast isn't supported. Feel free to add multicast code
107 * if you know how to make the EtherStar do multicast. Otherwise
108 * you'd have to use promiscuous mode and do multicast in software. OUCH!
109 *
110 * (5) There are no bus_space_barrier calls used. Are they needed? Maybe not.
111 *
112 * (6) Access to the fifo assumes word (16 bit) mode. Cards configured for
113 * byte wide fifo access will require driver code changes.
114 *
115 * Only the minimum code necessary to make the Tiara LANCard work
116 * has been tested. Other cards may require more work, especially
117 * byte mode fifo and if DMA is used.
118 *
119 * djb / 2004
120 */
121
122 #include "opt_inet.h"
123 #include "bpfilter.h"
124 #include "rnd.h"
125
126 #include <sys/param.h>
127 #include <sys/systm.h>
128 #include <sys/errno.h>
129 #include <sys/ioctl.h>
130 #include <sys/mbuf.h>
131 #include <sys/socket.h>
132 #include <sys/syslog.h>
133 #include <sys/device.h>
134 #if NRND > 0
135 #include <sys/rnd.h>
136 #endif
137
138 #include <net/if.h>
139 #include <net/if_dl.h>
140 #include <net/if_types.h>
141 #include <net/if_media.h>
142 #include <net/if_ether.h>
143
144 #ifdef INET
145 #include <netinet/in.h>
146 #include <netinet/in_systm.h>
147 #include <netinet/in_var.h>
148 #include <netinet/ip.h>
149 #include <netinet/if_inarp.h>
150 #endif
151
152
153 #if NBPFILTER > 0
154 #include <net/bpf.h>
155 #include <net/bpfdesc.h>
156 #endif
157
158 #include <sys/bus.h>
159
160 #include <dev/ic/mb86950reg.h>
161 #include <dev/ic/mb86950var.h>
162
163 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
164 #define bus_space_write_stream_2 bus_space_write_2
165 #define bus_space_write_multi_stream_2 bus_space_write_multi_2
166 #define bus_space_read_multi_stream_2 bus_space_read_multi_2
167 #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
168
169 /* Standard driver entry points. These can be static. */
170 int mb86950_ioctl(struct ifnet *, u_long, void *);
171 void mb86950_init(struct mb86950_softc *);
172 void mb86950_start(struct ifnet *);
173 void mb86950_watchdog(struct ifnet *);
174 void mb86950_reset(struct mb86950_softc *);
175
176 /* Local functions. */
177 void mb86950_stop(struct mb86950_softc *);
178 void mb86950_tint(struct mb86950_softc *, u_int8_t);
179 void mb86950_rint(struct mb86950_softc *, u_int8_t);
180 int mb86950_get_fifo(struct mb86950_softc *, u_int);
181 ushort mb86950_put_fifo(struct mb86950_softc *, struct mbuf *);
182 void mb86950_drain_fifo(struct mb86950_softc *);
183
184 int mb86950_mediachange(struct ifnet *);
185 void mb86950_mediastatus(struct ifnet *, struct ifmediareq *);
186
187
188 #if ESTAR_DEBUG >= 1
189 void mb86950_dump(int, struct mb86950_softc *);
190 #endif
191
192 /********************************************************************/
193
194 void
195 mb86950_attach(struct mb86950_softc *sc, u_int8_t *myea)
196 {
197
198 #ifdef DIAGNOSTIC
199 if (myea == NULL) {
200 printf("%s: ethernet address shouldn't be NULL\n",
201 device_xname(&sc->sc_dev));
202 panic("NULL ethernet address");
203 }
204 #endif
205
206 /* Initialize 86950. */
207 mb86950_stop(sc);
208
209 memcpy(sc->sc_enaddr, myea, sizeof(sc->sc_enaddr));
210
211 sc->sc_stat |= ESTAR_STAT_ENABLED;
212 }
213
214 /*
215 * Stop everything on the interface.
216 *
217 * All buffered packets, both transmitting and receiving,
218 * if any, will be lost by stopping the interface.
219 */
220 void
221 mb86950_stop(struct mb86950_softc *sc)
222 {
223 bus_space_tag_t bst = sc->sc_bst;
224 bus_space_handle_t bsh = sc->sc_bsh;
225
226 /* Stop interface hardware. */
227 bus_space_write_1(bst, bsh, DLCR_CONFIG, DISABLE_DLC);
228 delay(200);
229
230 /* Disable interrupts. */
231 bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0);
232 bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0);
233
234 /* Ack / Clear all interrupt status. */
235 bus_space_write_1(bst, bsh, DLCR_TX_STAT, 0xff);
236 bus_space_write_1(bst, bsh, DLCR_RX_STAT, 0xff);
237
238 /* Clear DMA Bit */
239 bus_space_write_2(bst, bsh, BMPR_DMA, 0);
240
241 /* accept no packets */
242 bus_space_write_1(bst, bsh, DLCR_TX_MODE, 0);
243 bus_space_write_1(bst, bsh, DLCR_RX_MODE, 0);
244
245 mb86950_drain_fifo(sc);
246
247 }
248
249 void
250 mb86950_drain_fifo(struct mb86950_softc *sc)
251 {
252 bus_space_tag_t bst = sc->sc_bst;
253 bus_space_handle_t bsh = sc->sc_bsh;
254
255 /* Read data until bus read error (i.e. buffer empty). */
256 /* XXX There ought to be a better way, eats CPU and bothers the chip */
257 while (!(bus_space_read_1(bst, bsh, DLCR_RX_STAT) & RX_BUS_RD_ERR))
258 bus_space_read_2(bst, bsh, BMPR_FIFO);
259 /* XXX */
260
261 /* Clear Bus Rd Error */
262 bus_space_write_1(bst, bsh, DLCR_RX_STAT, RX_BUS_RD_ERR);
263 }
264
265 /*
266 * Install interface into kernel networking data structures
267 */
268 void
269 mb86950_config(struct mb86950_softc *sc, int *media,
270 int nmedia, int defmedia)
271 {
272 struct ifnet *ifp = &sc->sc_ec.ec_if;
273 bus_space_tag_t bst = sc->sc_bst;
274 bus_space_handle_t bsh = sc->sc_bsh;
275
276 /* Initialize ifnet structure. */
277 strlcpy(ifp->if_xname, device_xname(&sc->sc_dev), IFNAMSIZ);
278 ifp->if_softc = sc;
279 ifp->if_start = mb86950_start;
280 ifp->if_ioctl = mb86950_ioctl;
281 ifp->if_watchdog = mb86950_watchdog;
282 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
283
284 IFQ_SET_READY(&ifp->if_snd);
285
286 /* Initialize media goo. */
287 /* XXX The Tiara LANCard uses board jumpers to change media.
288 * This code may have to be changed for other cards.
289 */
290 ifmedia_init(&sc->sc_media, 0, mb86950_mediachange, mb86950_mediastatus);
291 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
292 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
293
294 /* Attach the interface. */
295 if_attach(ifp);
296
297 /* Feed the chip the station address. */
298 bus_space_write_region_1(bst, bsh, DLCR_NODE_ID, sc->sc_enaddr, ETHER_ADDR_LEN);
299
300 ether_ifattach(ifp, sc->sc_enaddr);
301
302 #if NRND > 0
303 rnd_attach_source(&sc->rnd_source, device_xname(&sc->sc_dev),
304 RND_TYPE_NET, 0);
305 #endif
306
307 /* XXX No! This doesn't work - DLCR6 of the mb86950 is different
308
309 bus_space_write_1(bst, bsh, DLCR_CONFIG, 0x0f);
310 buf_config = bus_space_read_1(bst, bsh, DLCR_CONFIG);
311
312 sc->txb_count = ((buf_config & 0x0c) ? 2 : 1);
313 sc->txb_size = 1024 * (2 << ((buf_config & 0x0c) ? (((buf_config & 0x0c) >> 2) - 1) : 0));
314 sc->txb_free = (sc->txb_size * sc->txb_count) / 1500;
315
316 sc->rxb_size = ((8 << (buf_config & 3)) * 1024) - (sc->txb_size * sc->txb_count);
317 sc->rxb_max = sc->rxb_size / 64;
318
319 printf("mb86950: Buffer Size %dKB with %d transmit buffer(s) %dKB each.\n",
320 (8 << (buf_config & 3)), sc->txb_count, (sc->txb_size / 1024));
321 printf(" Transmit Buffer Space for %d maximum sized packet(s).\n",sc->txb_free);
322 printf(" System Bus Width %d bits, Buffer Memory %d bits.\n",
323 ((buf_config & 0x20) ? 8 : 16),
324 ((buf_config & 0x10) ? 8 : 16));
325
326 */
327
328 /* Set reasonable values for number of packet flow control if not
329 * set elsewhere */
330 if (sc->txb_num_pkt == 0) sc->txb_num_pkt = 1;
331 if (sc->rxb_num_pkt == 0) sc->rxb_num_pkt = 100;
332
333 /* Print additional info when attached. */
334 printf("%s: Ethernet address %s\n", device_xname(&sc->sc_dev),
335 ether_sprintf(sc->sc_enaddr));
336
337 /* The attach is successful. */
338 sc->sc_stat |= ESTAR_STAT_ATTACHED;
339 }
340
341 /*
342 * Media change callback.
343 */
344 int
345 mb86950_mediachange(struct ifnet *ifp)
346 {
347
348 struct mb86950_softc *sc = ifp->if_softc;
349
350 if (sc->sc_mediachange)
351 return ((*sc->sc_mediachange)(sc));
352
353 return (0);
354 }
355
356 /*
357 * Media status callback.
358 */
359 void
360 mb86950_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
361 {
362 struct mb86950_softc *sc = ifp->if_softc;
363
364 if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0) {
365 ifmr->ifm_active = IFM_ETHER | IFM_NONE;
366 ifmr->ifm_status = 0;
367 return;
368 }
369
370 if (sc->sc_mediastatus)
371 (*sc->sc_mediastatus)(sc, ifmr);
372
373 }
374
375 /*
376 * Reset interface.
377 */
378 void
379 mb86950_reset(struct mb86950_softc *sc)
380 {
381 int s;
382
383 s = splnet();
384 log(LOG_ERR, "%s: device reset\n", device_xname(&sc->sc_dev));
385 mb86950_stop(sc);
386 mb86950_init(sc);
387 splx(s);
388 }
389
390 /*
391 * Device timeout/watchdog routine. Entered if the device neglects to
392 * generate an interrupt after a transmit has been started on it.
393 */
394 void
395 mb86950_watchdog(struct ifnet *ifp)
396 {
397 struct mb86950_softc *sc = ifp->if_softc;
398 bus_space_tag_t bst = sc->sc_bst;
399 bus_space_handle_t bsh = sc->sc_bsh;
400 u_int8_t tstat;
401
402 /* verbose watchdog messages for debugging timeouts */
403 if ((tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT)) != 0) {
404 if (tstat & TX_CR_LOST) {
405 if ((tstat & (TX_COL | TX_16COL)) == 0) {
406 log(LOG_ERR, "%s: carrier lost\n",
407 device_xname(&sc->sc_dev));
408 } else {
409 log(LOG_ERR, "%s: excessive collisions\n",
410 device_xname(&sc->sc_dev));
411 }
412 }
413 else if ((tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) != 0) {
414 log(LOG_ERR, "%s: tx fifo underflow/overflow\n",
415 device_xname(&sc->sc_dev));
416 } else {
417 log(LOG_ERR, "%s: transmit error\n",
418 device_xname(&sc->sc_dev));
419 }
420 } else {
421 log(LOG_ERR, "%s: device timeout\n", device_xname(&sc->sc_dev));
422 }
423
424 /* Don't know how many packets are lost by this accident.
425 * ... So just errors = errors + 1
426 */
427 ifp->if_oerrors++;
428
429 mb86950_reset(sc);
430
431 }
432
433 /*
434 ******************** IOCTL
435 * Process an ioctl request.
436 */
437 int
438 mb86950_ioctl(struct ifnet *ifp, unsigned long cmd, void *data)
439 {
440 struct mb86950_softc *sc = ifp->if_softc;
441 struct ifaddr *ifa = (struct ifaddr *)data;
442 struct ifreq *ifr = (struct ifreq *)data;
443
444 int s, error = 0;
445
446 s = splnet();
447
448 switch (cmd) {
449 case SIOCINITIFADDR:
450 /* XXX deprecated ? What should I use instead? */
451 if ((error = mb86950_enable(sc)) != 0)
452 break;
453
454 ifp->if_flags |= IFF_UP;
455
456 mb86950_init(sc);
457 switch (ifa->ifa_addr->sa_family) {
458
459 #ifdef INET
460 case AF_INET:
461 arp_ifinit(ifp, ifa);
462 break;
463 #endif
464
465
466 default:
467 break;
468 }
469 break;
470
471 case SIOCSIFFLAGS:
472 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
473 break;
474 /* XXX re-use ether_ioctl() */
475 switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
476 case IFF_RUNNING:
477 /*
478 * If interface is marked down and it is running, then
479 * stop it.
480 */
481 mb86950_stop(sc);
482 ifp->if_flags &= ~IFF_RUNNING;
483 mb86950_disable(sc);
484 break;
485 case IFF_UP:
486 /*
487 * If interface is marked up and it is stopped, then
488 * start it.
489 */
490 if ((error = mb86950_enable(sc)) != 0)
491 break;
492 mb86950_init(sc);
493 break;
494 case IFF_UP|IFF_RUNNING:
495 /*
496 * Reset the interface to pick up changes in any other
497 * flags that affect hardware registers.
498 */
499 #if 0
500 /* Setmode not supported */
501 mb86950_setmode(sc);
502 #endif
503 break;
504 case 0:
505 break;
506 }
507
508 #if ESTAR_DEBUG >= 1
509 /* "ifconfig fe0 debug" to print register dump. */
510 if (ifp->if_flags & IFF_DEBUG) {
511 log(LOG_INFO, "%s: SIOCSIFFLAGS(DEBUG)\n",
512 device_xname(&sc->sc_dev));
513 mb86950_dump(LOG_DEBUG, sc);
514 }
515 #endif
516 break;
517
518 case SIOCGIFMEDIA:
519 case SIOCSIFMEDIA:
520 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
521 break;
522
523 default:
524 error = ether_ioctl(ifp, cmd, data);
525 break;
526 }
527
528 splx(s);
529 return (error);
530 }
531
532 /*
533 * Initialize device.
534 */
535 void
536 mb86950_init(struct mb86950_softc *sc)
537 {
538 bus_space_tag_t bst = sc->sc_bst;
539 bus_space_handle_t bsh = sc->sc_bsh;
540 struct ifnet *ifp = &sc->sc_ec.ec_if;
541
542 /* Reset transmitter flags. */
543 ifp->if_flags &= ~IFF_OACTIVE;
544 ifp->if_timer = 0;
545 sc->txb_sched = 0;
546
547 bus_space_write_1(bst, bsh, DLCR_TX_MODE, LBC);
548 bus_space_write_1(bst, bsh, DLCR_RX_MODE, NORMAL_MODE);
549
550 /* Enable interrupts. */
551 bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
552 bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK);
553
554 /* Enable transmitter and receiver. */
555 bus_space_write_1(bst, bsh, DLCR_CONFIG, ENABLE_DLC);
556 delay(200);
557
558 /* Set 'running' flag. */
559 ifp->if_flags |= IFF_RUNNING;
560
561 /* ...and attempt to start output. */
562 mb86950_start(ifp);
563
564 }
565
566 void
567 mb86950_start(struct ifnet *ifp)
568 {
569 struct mb86950_softc *sc = ifp->if_softc;
570 bus_space_tag_t bst = sc->sc_bst;
571 bus_space_handle_t bsh = sc->sc_bsh;
572 struct mbuf *m;
573 int len;
574
575 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
576 return;
577
578 IF_DEQUEUE(&ifp->if_snd, m);
579 if (m == 0)
580 return;
581
582 #if NBPFILTER > 0
583 /* Tap off here if there is a BPF listener. */
584 if (ifp->if_bpf)
585 bpf_mtap(ifp->if_bpf, m);
586 #endif
587
588 /* Send the packet to the mb86950 */
589 len = mb86950_put_fifo(sc,m);
590 m_freem(m);
591
592 /* XXX bus_space_barrier here ? */
593 if (bus_space_read_1(bst, bsh, DLCR_TX_STAT) & (TX_UNDERFLO | TX_BUS_WR_ERR)) {
594 log(LOG_ERR, "%s: tx fifo underflow/overflow\n", device_xname(&sc->sc_dev));
595 }
596
597 bus_space_write_2(bst, bsh, BMPR_TX_LENGTH, len | TRANSMIT_START);
598
599 bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
600 /* XXX */
601 sc->txb_sched++;
602
603 /* We have space for 'n' transmit packets of size 'mtu. */
604 if (sc->txb_sched > sc->txb_num_pkt) {
605 ifp->if_flags |= IFF_OACTIVE;
606 ifp->if_timer = 2;
607 }
608 }
609
610 /*
611 * Send packet - copy packet from mbuf to the fifo
612 */
613 u_short
614 mb86950_put_fifo(struct mb86950_softc *sc, struct mbuf *m)
615 {
616 bus_space_tag_t bst = sc->sc_bst;
617 bus_space_handle_t bsh = sc->sc_bsh;
618 u_short *data;
619 u_char savebyte[2];
620 int len, len1, wantbyte;
621 u_short totlen;
622
623 memset(savebyte, 0, sizeof(savebyte)); /* XXX gcc */
624
625 totlen = wantbyte = 0;
626
627 for (; m != NULL; m = m->m_next) {
628 data = mtod(m, u_short *);
629 len = m->m_len;
630 if (len > 0) {
631 totlen += len;
632
633 /* Finish the last word. */
634 if (wantbyte) {
635 savebyte[1] = *((u_char *)data);
636 bus_space_write_2(bst, bsh, BMPR_FIFO, *savebyte);
637 data = (u_short *)((u_char *)data + 1);
638 len--;
639 wantbyte = 0;
640 }
641 /* Output contiguous words. */
642 if (len > 1) {
643 len1 = len/2;
644 bus_space_write_multi_stream_2(bst, bsh, BMPR_FIFO, data, len1);
645 data += len1;
646 len &= 1;
647 }
648 /* Save last byte, if necessary. */
649 if (len == 1) {
650 savebyte[0] = *((u_char *)data);
651 wantbyte = 1;
652 }
653 }
654 }
655
656 if (wantbyte) {
657 savebyte[1] = 0;
658 bus_space_write_2(bst, bsh, BMPR_FIFO, *savebyte);
659 }
660
661 if (totlen < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
662
663 /* Fill the rest of the packet with zeros. */
664 /* XXX Replace this mess with something else, eats CPU */
665 /* The zero fill and last byte ought to be combined somehow */
666 for(len = totlen + 1; len < (ETHER_MIN_LEN - ETHER_CRC_LEN); len += 2)
667 bus_space_write_2(bst, bsh, BMPR_FIFO, 0);
668 /* XXX */
669
670 totlen = (ETHER_MIN_LEN - ETHER_CRC_LEN);
671 }
672
673 return (totlen);
674 }
675
676 /*
677 * Handle interrupts.
678 * Ethernet interface interrupt processor
679 */
680 int
681 mb86950_intr(void *arg)
682 {
683 struct mb86950_softc *sc = arg;
684 bus_space_tag_t bst = sc->sc_bst;
685 bus_space_handle_t bsh = sc->sc_bsh;
686 struct ifnet *ifp = &sc->sc_ec.ec_if;
687 u_int8_t tstat, rstat;
688
689 /* Get interrupt status. */
690 tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT);
691 rstat = bus_space_read_1(bst, bsh, DLCR_RX_STAT);
692
693 if (tstat == 0 && rstat == 0) return (0);
694
695 /* Disable etherstar interrupts so that we won't miss anything. */
696 bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0);
697 bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0);
698
699 /*
700 * Handle transmitter interrupts. Handle these first because
701 * the receiver will reset the board under some conditions.
702 */
703 if (tstat != 0) {
704
705 mb86950_tint(sc, tstat);
706
707 /* acknowledge transmit interrupt status. */
708 bus_space_write_1(bst, bsh, DLCR_TX_STAT, tstat);
709
710 }
711
712 /* Handle receiver interrupts. */
713 if (rstat != 0) {
714
715 mb86950_rint(sc, rstat);
716
717 /* acknowledge receive interrupt status. */
718 bus_space_write_1(bst, bsh, DLCR_RX_STAT, rstat);
719
720 }
721
722 /* If tx still pending reset tx interrupt mask */
723 if (sc->txb_sched > 0)
724 bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
725
726 /*
727 * If it looks like the transmitter can take more data,
728 * attempt to start output on the interface. This is done
729 * after handling the receiver interrupt to give the
730 * receive operation priority.
731 */
732
733 if ((ifp->if_flags & IFF_OACTIVE) == 0)
734 mb86950_start(ifp);
735
736 /* Set receive interrupts back */
737 bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK);
738
739 return(1);
740 }
741
742 /* Transmission interrupt handler */
743 void
744 mb86950_tint(struct mb86950_softc *sc, u_int8_t tstat)
745 {
746 bus_space_tag_t bst = sc->sc_bst;
747 bus_space_handle_t bsh = sc->sc_bsh;
748 struct ifnet *ifp = &sc->sc_ec.ec_if;
749 int col;
750
751 if (tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) {
752 /* XXX What do we need to do here? reset ? */
753 ifp->if_oerrors++;
754 }
755
756 /* excessive collision */
757 if (tstat & TX_16COL) {
758 ifp->if_collisions += 16;
759 /* 16 collisions means that the packet has been thrown away. */
760 if (sc->txb_sched > 0)
761 sc->txb_sched--;
762 }
763
764 /* transmission complete. */
765 if (tstat & TX_DONE) {
766 /* successfully transmitted packets ++. */
767 ifp->if_opackets++;
768 if (sc->txb_sched > 0)
769 sc->txb_sched--;
770
771 /* Collision count valid only when TX_DONE is set */
772 if (tstat & TX_COL) {
773 col = (bus_space_read_1(bst, bsh, DLCR_TX_MODE) & COL_MASK) >> 4;
774 ifp->if_collisions = ifp->if_collisions + col;
775 }
776 }
777
778 if (sc->txb_sched == 0) {
779 /* Reset output active flag and stop timer. */
780 ifp->if_flags &= ~IFF_OACTIVE;
781 ifp->if_timer = 0;
782 }
783 }
784
785 /* receiver interrupt. */
786 void
787 mb86950_rint(struct mb86950_softc *sc, u_int8_t rstat)
788 {
789 bus_space_tag_t bst = sc->sc_bst;
790 bus_space_handle_t bsh = sc->sc_bsh;
791 struct ifnet *ifp = &sc->sc_ec.ec_if;
792 u_int status, len;
793 int i;
794
795 /* Update statistics if this interrupt is caused by an error. */
796 if (rstat & RX_ERR_MASK) {
797
798 /* tried to read past end of fifo, should be harmless
799 * count everything else
800 */
801 if ((rstat & RX_BUS_RD_ERR) == 0) {
802 ifp->if_ierrors++;
803 }
804 }
805
806 /*
807 * mb86950 has a flag indicating "receive buffer empty."
808 * We just loop checking the flag to pull out all received
809 * packets.
810 *
811 * We limit the number of iterrations to avoid infinite loop.
812 * It can be caused by a very slow CPU (some broken
813 * peripheral may insert incredible number of wait cycles)
814 * or, worse, by a broken mb86950 chip.
815 */
816 for (i = 0; i < sc->rxb_num_pkt; i++) {
817 /* Stop the iterration if 86950 indicates no packets. */
818 if (bus_space_read_1(bst, bsh, DLCR_RX_MODE) & RX_BUF_EMTY)
819 break;
820
821 /* receive packet status */
822 status = bus_space_read_2(bst, bsh, BMPR_FIFO);
823
824 /* bad packet? */
825 if ((status & GOOD_PKT) == 0) {
826 ifp->if_ierrors++;
827 mb86950_drain_fifo(sc);
828 continue;
829 }
830
831 /* Length valid ? */
832 len = bus_space_read_2(bst, bsh, BMPR_FIFO);
833
834 if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN) || len < ETHER_HDR_LEN) {
835 ifp->if_ierrors++;
836 mb86950_drain_fifo(sc);
837 continue;
838 }
839
840 if (mb86950_get_fifo(sc, len) != 0) {
841 /* No mbufs? Drop packet. */
842 ifp->if_ierrors++;
843 mb86950_drain_fifo(sc);
844 return;
845 }
846
847 /* Successfully received a packet. Update stat. */
848 ifp->if_ipackets++;
849 }
850 }
851
852 /*
853 * Receive packet.
854 * Retrieve packet from receive buffer and send to the next level up via
855 * ether_input(). If there is a BPF listener, give a copy to BPF, too.
856 * Returns 0 if success, -1 if error (i.e., mbuf allocation failure).
857 */
858 int
859 mb86950_get_fifo(struct mb86950_softc *sc, u_int len)
860 {
861 bus_space_tag_t bst = sc->sc_bst;
862 bus_space_handle_t bsh = sc->sc_bsh;
863 struct ifnet *ifp = &sc->sc_ec.ec_if;
864 struct mbuf *m;
865
866 /* Allocate a header mbuf. */
867 MGETHDR(m, M_DONTWAIT, MT_DATA);
868 if (m == 0)
869 return (-1);
870
871 /*
872 * Round len to even value.
873 */
874 if (len & 1)
875 len++;
876
877 m->m_pkthdr.rcvif = ifp;
878 m->m_pkthdr.len = len;
879
880 /* The following silliness is to make NFS happy. */
881 #define EROUND ((sizeof(struct ether_header) + 3) & ~3)
882 #define EOFF (EROUND - sizeof(struct ether_header))
883
884 /*
885 * Our strategy has one more problem. There is a policy on
886 * mbuf cluster allocation. It says that we must have at
887 * least MINCLSIZE (208 bytes) to allocate a cluster. For a
888 * packet of a size between (MHLEN - 2) to (MINCLSIZE - 2),
889 * our code violates the rule...
890 * On the other hand, the current code is short, simple,
891 * and fast, however. It does no harmful thing, just wastes
892 * some memory. Any comments? FIXME.
893 */
894
895 /* Attach a cluster if this packet doesn't fit in a normal mbuf. */
896 if (len > MHLEN - EOFF) {
897 MCLGET(m, M_DONTWAIT);
898 if ((m->m_flags & M_EXT) == 0) {
899 m_freem(m);
900 return (-1);
901 }
902 }
903
904 /*
905 * The following assumes there is room for the ether header in the
906 * header mbuf.
907 */
908 m->m_data += EOFF;
909
910 /* Set the length of this packet. */
911 m->m_len = len;
912
913 /* Get a packet. */
914 bus_space_read_multi_stream_2(bst, bsh, BMPR_FIFO, mtod(m, u_int16_t *), (len + 1) >> 1);
915
916 #if NBPFILTER > 0
917 /*
918 * Check if there's a BPF listener on this interface. If so, hand off
919 * the raw packet to bpf.
920 */
921 if (ifp->if_bpf)
922 bpf_mtap(ifp->if_bpf, m);
923 #endif
924
925 (*ifp->if_input)(ifp, m);
926 return (0);
927 }
928
929 /*
930 * Enable power on the interface.
931 */
932 int
933 mb86950_enable(struct mb86950_softc *sc)
934 {
935
936 if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0 && sc->sc_enable != NULL) {
937 if ((*sc->sc_enable)(sc) != 0) {
938 aprint_error_dev(&sc->sc_dev, "device enable failed\n");
939 return (EIO);
940 }
941 }
942
943 sc->sc_stat |= ESTAR_STAT_ENABLED;
944 return (0);
945 }
946
947 /*
948 * Disable power on the interface.
949 */
950 void
951 mb86950_disable(struct mb86950_softc *sc)
952 {
953
954 if ((sc->sc_stat & ESTAR_STAT_ENABLED) != 0 && sc->sc_disable != NULL) {
955 (*sc->sc_disable)(sc);
956 sc->sc_stat &= ~ESTAR_STAT_ENABLED;
957 }
958 }
959
960 /*
961 * mbe_activate:
962 *
963 * Handle device activation/deactivation requests.
964 */
965 int
966 mb86950_activate(struct device *self, enum devact act)
967 {
968 struct mb86950_softc *sc = (struct mb86950_softc *)self;
969 int rv, s;
970
971 rv = 0;
972 s = splnet();
973 switch (act) {
974 case DVACT_ACTIVATE:
975 rv = EOPNOTSUPP;
976 break;
977
978 case DVACT_DEACTIVATE:
979 if_deactivate(&sc->sc_ec.ec_if);
980 break;
981 }
982 splx(s);
983 return (rv);
984 }
985
986 /*
987 * mb86950_detach:
988 *
989 * Detach a mb86950 interface.
990 */
991 int
992 mb86950_detach(struct mb86950_softc *sc)
993 {
994 struct ifnet *ifp = &sc->sc_ec.ec_if;
995
996 /* Succeed now if there's no work to do. */
997 if ((sc->sc_stat & ESTAR_STAT_ATTACHED) == 0)
998 return (0);
999
1000 /* Delete all media. */
1001 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
1002
1003 #if NRND > 0
1004 /* Unhook the entropy source. */
1005 rnd_detach_source(&sc->rnd_source);
1006 #endif
1007 ether_ifdetach(ifp);
1008 if_detach(ifp);
1009
1010 return (0);
1011 }
1012
1013 #if ESTAR_DEBUG >= 1
1014 void
1015 mb86950_dump(int level, struct mb86950_softc *sc)
1016 {
1017 bus_space_tag_t bst = sc->sc_bst;
1018 bus_space_handle_t bsh = sc->sc_bsh;
1019
1020 log(level, "\tDLCR = %02x %02x %02x %02x %02x %02x %02x\n",
1021 bus_space_read_1(bst, bsh, DLCR_TX_STAT),
1022 bus_space_read_1(bst, bsh, DLCR_TX_INT_EN),
1023 bus_space_read_1(bst, bsh, DLCR_RX_STAT),
1024 bus_space_read_1(bst, bsh, DLCR_RX_INT_EN),
1025 bus_space_read_1(bst, bsh, DLCR_TX_MODE),
1026 bus_space_read_1(bst, bsh, DLCR_RX_MODE),
1027 bus_space_read_1(bst, bsh, DLCR_CONFIG));
1028
1029 /* XXX BMPR2, 4 write only ?
1030 log(level, "\tBMPR = xxxx %04x %04x\n",
1031 bus_space_read_2(bst, bsh, BMPR_TX_LENGTH),
1032 bus_space_read_2(bst, bsh, BMPR_DMA));
1033 */
1034 }
1035 #endif
1036