FreeBSD/Linux Kernel Cross Reference
sys/dev/sbni/if_sbni.c
1 /*-
2 * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved.
3 * Author: Denis I.Timofeev <timofeev@granch.ru>
4 *
5 * Redistributon and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions, and the following
10 * 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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 /*
33 * Device driver for Granch SBNI12 leased line adapters
34 *
35 * Revision 2.0.0 1997/08/06
36 * Initial revision by Alexey Zverev
37 *
38 * Revision 2.0.1 1997/08/11
39 * Additional internal statistics support (tx statistics)
40 *
41 * Revision 2.0.2 1997/11/05
42 * if_bpf bug has been fixed
43 *
44 * Revision 2.0.3 1998/12/20
45 * Memory leakage has been eliminated in
46 * the sbni_st and sbni_timeout routines.
47 *
48 * Revision 3.0 2000/08/10 by Yaroslav Polyakov
49 * Support for PCI cards. 4.1 modification.
50 *
51 * Revision 3.1 2000/09/12
52 * Removed extra #defines around bpf functions
53 *
54 * Revision 4.0 2000/11/23 by Denis Timofeev
55 * Completely redesigned the buffer management
56 *
57 * Revision 4.1 2001/01/21
58 * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards
59 *
60 * Written with reference to NE2000 driver developed by David Greenman.
61 */
62
63
64 #include <sys/param.h>
65 #include <sys/bus.h>
66 #include <sys/systm.h>
67 #include <sys/socket.h>
68 #include <sys/sockio.h>
69 #include <sys/mbuf.h>
70 #include <sys/kernel.h>
71 #include <sys/priv.h>
72 #include <sys/proc.h>
73 #include <sys/callout.h>
74 #include <sys/syslog.h>
75 #include <sys/random.h>
76
77 #include <machine/bus.h>
78 #include <sys/rman.h>
79 #include <machine/resource.h>
80
81 #include <net/if.h>
82 #include <net/if_dl.h>
83 #include <net/ethernet.h>
84 #include <net/bpf.h>
85 #include <net/if_types.h>
86
87 #include <dev/sbni/if_sbnireg.h>
88 #include <dev/sbni/if_sbnivar.h>
89
90 static void sbni_init(void *);
91 static void sbni_init_locked(struct sbni_softc *);
92 static void sbni_start(struct ifnet *);
93 static void sbni_start_locked(struct ifnet *);
94 static int sbni_ioctl(struct ifnet *, u_long, caddr_t);
95 static void sbni_stop(struct sbni_softc *);
96 static void handle_channel(struct sbni_softc *);
97
98 static void card_start(struct sbni_softc *);
99 static int recv_frame(struct sbni_softc *);
100 static void send_frame(struct sbni_softc *);
101 static int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t);
102 static int skip_tail(struct sbni_softc *, u_int, u_int32_t);
103 static void interpret_ack(struct sbni_softc *, u_int);
104 static void download_data(struct sbni_softc *, u_int32_t *);
105 static void prepare_to_send(struct sbni_softc *);
106 static void drop_xmit_queue(struct sbni_softc *);
107 static int get_rx_buf(struct sbni_softc *);
108 static void indicate_pkt(struct sbni_softc *);
109 static void change_level(struct sbni_softc *);
110 static int check_fhdr(struct sbni_softc *, u_int *, u_int *,
111 u_int *, u_int *, u_int32_t *);
112 static int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t);
113 static void timeout_change_level(struct sbni_softc *);
114 static void send_frame_header(struct sbni_softc *, u_int32_t *);
115 static void set_initial_values(struct sbni_softc *, struct sbni_flags);
116
117 static u_int32_t calc_crc32(u_int32_t, caddr_t, u_int);
118 static timeout_t sbni_timeout;
119
120 static __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg);
121 static __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char);
122 static __inline void sbni_insb(struct sbni_softc *, u_char *, u_int);
123 static __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int);
124
125 static u_int32_t crc32tab[];
126
127 #ifdef SBNI_DUAL_COMPOUND
128 static struct mtx headlist_lock;
129 MTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF);
130 static struct sbni_softc *sbni_headlist;
131 #endif
132
133 /* -------------------------------------------------------------------------- */
134
135 static __inline u_char
136 sbni_inb(struct sbni_softc *sc, enum sbni_reg reg)
137 {
138 return bus_space_read_1(
139 rman_get_bustag(sc->io_res),
140 rman_get_bushandle(sc->io_res),
141 sc->io_off + reg);
142 }
143
144 static __inline void
145 sbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value)
146 {
147 bus_space_write_1(
148 rman_get_bustag(sc->io_res),
149 rman_get_bushandle(sc->io_res),
150 sc->io_off + reg, value);
151 }
152
153 static __inline void
154 sbni_insb(struct sbni_softc *sc, u_char *to, u_int len)
155 {
156 bus_space_read_multi_1(
157 rman_get_bustag(sc->io_res),
158 rman_get_bushandle(sc->io_res),
159 sc->io_off + DAT, to, len);
160 }
161
162 static __inline void
163 sbni_outsb(struct sbni_softc *sc, u_char *from, u_int len)
164 {
165 bus_space_write_multi_1(
166 rman_get_bustag(sc->io_res),
167 rman_get_bushandle(sc->io_res),
168 sc->io_off + DAT, from, len);
169 }
170
171
172 /*
173 Valid combinations in CSR0 (for probing):
174
175 VALID_DECODER 0000,0011,1011,1010
176
177 ; 0 ; -
178 TR_REQ ; 1 ; +
179 TR_RDY ; 2 ; -
180 TR_RDY TR_REQ ; 3 ; +
181 BU_EMP ; 4 ; +
182 BU_EMP TR_REQ ; 5 ; +
183 BU_EMP TR_RDY ; 6 ; -
184 BU_EMP TR_RDY TR_REQ ; 7 ; +
185 RC_RDY ; 8 ; +
186 RC_RDY TR_REQ ; 9 ; +
187 RC_RDY TR_RDY ; 10 ; -
188 RC_RDY TR_RDY TR_REQ ; 11 ; -
189 RC_RDY BU_EMP ; 12 ; -
190 RC_RDY BU_EMP TR_REQ ; 13 ; -
191 RC_RDY BU_EMP TR_RDY ; 14 ; -
192 RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; -
193 */
194
195 #define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
196
197
198 int
199 sbni_probe(struct sbni_softc *sc)
200 {
201 u_char csr0;
202
203 csr0 = sbni_inb(sc, CSR0);
204 if (csr0 != 0xff && csr0 != 0x00) {
205 csr0 &= ~EN_INT;
206 if (csr0 & BU_EMP)
207 csr0 |= EN_INT;
208
209 if (VALID_DECODER & (1 << (csr0 >> 4)))
210 return (0);
211 }
212
213 return (ENXIO);
214 }
215
216
217 /*
218 * Install interface into kernel networking data structures
219 */
220 int
221 sbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags)
222 {
223 struct ifnet *ifp;
224 u_char csr0;
225
226 ifp = sc->ifp = if_alloc(IFT_ETHER);
227 if (ifp == NULL)
228 return (ENOMEM);
229 sbni_outb(sc, CSR0, 0);
230 set_initial_values(sc, flags);
231
232 /* Initialize ifnet structure */
233 ifp->if_softc = sc;
234 if_initname(ifp, "sbni", unit);
235 ifp->if_init = sbni_init;
236 ifp->if_start = sbni_start;
237 ifp->if_ioctl = sbni_ioctl;
238 IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
239
240 /* report real baud rate */
241 csr0 = sbni_inb(sc, CSR0);
242 ifp->if_baudrate =
243 (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate);
244
245 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
246
247 mtx_init(&sc->lock, ifp->if_xname, MTX_NETWORK_LOCK, MTX_DEF);
248 callout_init_mtx(&sc->wch, &sc->lock, 0);
249 ether_ifattach(ifp, sc->enaddr);
250 /* device attach does transition from UNCONFIGURED to IDLE state */
251
252 if_printf(ifp, "speed %ld, rxl ", ifp->if_baudrate);
253 if (sc->delta_rxl)
254 printf("auto\n");
255 else
256 printf("%d (fixed)\n", sc->cur_rxl_index);
257 return (0);
258 }
259
260 void
261 sbni_detach(struct sbni_softc *sc)
262 {
263
264 SBNI_LOCK(sc);
265 sbni_stop(sc);
266 SBNI_UNLOCK(sc);
267 callout_drain(&sc->wch);
268 ether_ifdetach(sc->ifp);
269 if (sc->irq_handle)
270 bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle);
271 mtx_destroy(&sc->lock);
272 if_free(sc->ifp);
273 }
274
275 void
276 sbni_release_resources(struct sbni_softc *sc)
277 {
278
279 if (sc->irq_res)
280 bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
281 sc->irq_res);
282 if (sc->io_res && sc->io_off == 0)
283 bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid,
284 sc->io_res);
285 }
286
287 /* -------------------------------------------------------------------------- */
288
289 static void
290 sbni_init(void *xsc)
291 {
292 struct sbni_softc *sc;
293
294 sc = (struct sbni_softc *)xsc;
295 SBNI_LOCK(sc);
296 sbni_init_locked(sc);
297 SBNI_UNLOCK(sc);
298 }
299
300 static void
301 sbni_init_locked(struct sbni_softc *sc)
302 {
303 struct ifnet *ifp;
304
305 ifp = sc->ifp;
306
307 /*
308 * kludge to avoid multiple initialization when more than once
309 * protocols configured
310 */
311 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
312 return;
313
314 card_start(sc);
315 callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc);
316
317 ifp->if_drv_flags |= IFF_DRV_RUNNING;
318 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
319
320 /* attempt to start output */
321 sbni_start_locked(ifp);
322 }
323
324 static void
325 sbni_start(struct ifnet *ifp)
326 {
327 struct sbni_softc *sc = ifp->if_softc;
328
329 SBNI_LOCK(sc);
330 sbni_start_locked(ifp);
331 SBNI_UNLOCK(sc);
332 }
333
334 static void
335 sbni_start_locked(struct ifnet *ifp)
336 {
337 struct sbni_softc *sc = ifp->if_softc;
338
339 if (sc->tx_frameno == 0)
340 prepare_to_send(sc);
341 }
342
343
344 static void
345 sbni_stop(struct sbni_softc *sc)
346 {
347 sbni_outb(sc, CSR0, 0);
348 drop_xmit_queue(sc);
349
350 if (sc->rx_buf_p) {
351 m_freem(sc->rx_buf_p);
352 sc->rx_buf_p = NULL;
353 }
354
355 callout_stop(&sc->wch);
356 sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
357 }
358
359 /* -------------------------------------------------------------------------- */
360
361 /* interrupt handler */
362
363 /*
364 * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
365 * be looked as two independent single-channel devices. Every channel seems
366 * as Ethernet interface but interrupt handler must be common. Really, first
367 * channel ("master") driver only registers the handler. In it's struct softc
368 * it has got pointer to "slave" channel's struct softc and handles that's
369 * interrupts too.
370 * softc of successfully attached ISA SBNI boards is linked to list.
371 * While next board driver is initialized, it scans this list. If one
372 * has found softc with same irq and ioaddr different by 4 then it assumes
373 * this board to be "master".
374 */
375
376 void
377 sbni_intr(void *arg)
378 {
379 struct sbni_softc *sc;
380 int repeat;
381
382 sc = (struct sbni_softc *)arg;
383
384 do {
385 repeat = 0;
386 SBNI_LOCK(sc);
387 if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) {
388 handle_channel(sc);
389 repeat = 1;
390 }
391 SBNI_UNLOCK(sc);
392 if (sc->slave_sc) {
393 /* second channel present */
394 SBNI_LOCK(sc->slave_sc);
395 if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) {
396 handle_channel(sc->slave_sc);
397 repeat = 1;
398 }
399 SBNI_UNLOCK(sc->slave_sc);
400 }
401 } while (repeat);
402 }
403
404
405 static void
406 handle_channel(struct sbni_softc *sc)
407 {
408 int req_ans;
409 u_char csr0;
410
411 sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ);
412
413 sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
414 for (;;) {
415 csr0 = sbni_inb(sc, CSR0);
416 if ((csr0 & (RC_RDY | TR_RDY)) == 0)
417 break;
418
419 req_ans = !(sc->state & FL_PREV_OK);
420
421 if (csr0 & RC_RDY)
422 req_ans = recv_frame(sc);
423
424 /*
425 * TR_RDY always equals 1 here because we have owned the marker,
426 * and we set TR_REQ when disabled interrupts
427 */
428 csr0 = sbni_inb(sc, CSR0);
429 if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0)
430 if_printf(sc->ifp, "internal error!\n");
431
432 /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
433 if (req_ans || sc->tx_frameno != 0)
434 send_frame(sc);
435 else {
436 /* send the marker without any data */
437 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ);
438 }
439 }
440
441 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT);
442 }
443
444
445 /*
446 * Routine returns 1 if it need to acknoweledge received frame.
447 * Empty frame received without errors won't be acknoweledged.
448 */
449
450 static int
451 recv_frame(struct sbni_softc *sc)
452 {
453 u_int32_t crc;
454 u_int framelen, frameno, ack;
455 u_int is_first, frame_ok;
456
457 crc = CRC32_INITIAL;
458 if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) {
459 frame_ok = framelen > 4 ?
460 upload_data(sc, framelen, frameno, is_first, crc) :
461 skip_tail(sc, framelen, crc);
462 if (frame_ok)
463 interpret_ack(sc, ack);
464 } else {
465 framelen = 0;
466 frame_ok = 0;
467 }
468
469 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER);
470 if (frame_ok) {
471 sc->state |= FL_PREV_OK;
472 if (framelen > 4)
473 sc->in_stats.all_rx_number++;
474 } else {
475 sc->state &= ~FL_PREV_OK;
476 change_level(sc);
477 sc->in_stats.all_rx_number++;
478 sc->in_stats.bad_rx_number++;
479 }
480
481 return (!frame_ok || framelen > 4);
482 }
483
484
485 static void
486 send_frame(struct sbni_softc *sc)
487 {
488 u_int32_t crc;
489 u_char csr0;
490
491 crc = CRC32_INITIAL;
492 if (sc->state & FL_NEED_RESEND) {
493
494 /* if frame was sended but not ACK'ed - resend it */
495 if (sc->trans_errors) {
496 sc->trans_errors--;
497 if (sc->framelen != 0)
498 sc->in_stats.resend_tx_number++;
499 } else {
500 /* cannot xmit with many attempts */
501 drop_xmit_queue(sc);
502 goto do_send;
503 }
504 } else
505 sc->trans_errors = TR_ERROR_COUNT;
506
507 send_frame_header(sc, &crc);
508 sc->state |= FL_NEED_RESEND;
509 /*
510 * FL_NEED_RESEND will be cleared after ACK, but if empty
511 * frame sended then in prepare_to_send next frame
512 */
513
514
515 if (sc->framelen) {
516 download_data(sc, &crc);
517 sc->in_stats.all_tx_number++;
518 sc->state |= FL_WAIT_ACK;
519 }
520
521 sbni_outsb(sc, (u_char *)&crc, sizeof crc);
522
523 do_send:
524 csr0 = sbni_inb(sc, CSR0);
525 sbni_outb(sc, CSR0, csr0 & ~TR_REQ);
526
527 if (sc->tx_frameno) {
528 /* next frame exists - request to send */
529 sbni_outb(sc, CSR0, csr0 | TR_REQ);
530 }
531 }
532
533
534 static void
535 download_data(struct sbni_softc *sc, u_int32_t *crc_p)
536 {
537 struct mbuf *m;
538 caddr_t data_p;
539 u_int data_len, pos, slice;
540
541 data_p = NULL; /* initialized to avoid warn */
542 pos = 0;
543
544 for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) {
545 if (pos + m->m_len > sc->outpos) {
546 data_len = m->m_len - (sc->outpos - pos);
547 data_p = mtod(m, caddr_t) + (sc->outpos - pos);
548
549 goto do_copy;
550 } else
551 pos += m->m_len;
552 }
553
554 data_len = 0;
555
556 do_copy:
557 pos = 0;
558 do {
559 if (data_len) {
560 slice = min(data_len, sc->framelen - pos);
561 sbni_outsb(sc, data_p, slice);
562 *crc_p = calc_crc32(*crc_p, data_p, slice);
563
564 pos += slice;
565 if (data_len -= slice)
566 data_p += slice;
567 else {
568 do {
569 m = m->m_next;
570 } while (m != NULL && m->m_len == 0);
571
572 if (m) {
573 data_len = m->m_len;
574 data_p = mtod(m, caddr_t);
575 }
576 }
577 } else {
578 /* frame too short - zero padding */
579
580 pos = sc->framelen - pos;
581 while (pos--) {
582 sbni_outb(sc, DAT, 0);
583 *crc_p = CRC32(0, *crc_p);
584 }
585 return;
586 }
587 } while (pos < sc->framelen);
588 }
589
590
591 static int
592 upload_data(struct sbni_softc *sc, u_int framelen, u_int frameno,
593 u_int is_first, u_int32_t crc)
594 {
595 int frame_ok;
596
597 if (is_first) {
598 sc->wait_frameno = frameno;
599 sc->inppos = 0;
600 }
601
602 if (sc->wait_frameno == frameno) {
603
604 if (sc->inppos + framelen <= ETHER_MAX_LEN) {
605 frame_ok = append_frame_to_pkt(sc, framelen, crc);
606
607 /*
608 * if CRC is right but framelen incorrect then transmitter
609 * error was occured... drop entire packet
610 */
611 } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) {
612 sc->wait_frameno = 0;
613 sc->inppos = 0;
614 sc->ifp->if_ierrors++;
615 /* now skip all frames until is_first != 0 */
616 }
617 } else
618 frame_ok = skip_tail(sc, framelen, crc);
619
620 if (is_first && !frame_ok) {
621 /*
622 * Frame has been violated, but we have stored
623 * is_first already... Drop entire packet.
624 */
625 sc->wait_frameno = 0;
626 sc->ifp->if_ierrors++;
627 }
628
629 return (frame_ok);
630 }
631
632
633 static __inline void send_complete(struct sbni_softc *);
634
635 static __inline void
636 send_complete(struct sbni_softc *sc)
637 {
638 m_freem(sc->tx_buf_p);
639 sc->tx_buf_p = NULL;
640 sc->ifp->if_opackets++;
641 }
642
643
644 static void
645 interpret_ack(struct sbni_softc *sc, u_int ack)
646 {
647 if (ack == FRAME_SENT_OK) {
648 sc->state &= ~FL_NEED_RESEND;
649
650 if (sc->state & FL_WAIT_ACK) {
651 sc->outpos += sc->framelen;
652
653 if (--sc->tx_frameno) {
654 sc->framelen = min(
655 sc->maxframe, sc->pktlen - sc->outpos);
656 } else {
657 send_complete(sc);
658 prepare_to_send(sc);
659 }
660 }
661 }
662
663 sc->state &= ~FL_WAIT_ACK;
664 }
665
666
667 /*
668 * Glue received frame with previous fragments of packet.
669 * Indicate packet when last frame would be accepted.
670 */
671
672 static int
673 append_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc)
674 {
675 caddr_t p;
676
677 if (sc->inppos + framelen > ETHER_MAX_LEN)
678 return (0);
679
680 if (!sc->rx_buf_p && !get_rx_buf(sc))
681 return (0);
682
683 p = sc->rx_buf_p->m_data + sc->inppos;
684 sbni_insb(sc, p, framelen);
685 if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER)
686 return (0);
687
688 sc->inppos += framelen - 4;
689 if (--sc->wait_frameno == 0) { /* last frame received */
690 indicate_pkt(sc);
691 sc->ifp->if_ipackets++;
692 }
693
694 return (1);
695 }
696
697
698 /*
699 * Prepare to start output on adapter. Current priority must be set to splimp
700 * before this routine is called.
701 * Transmitter will be actually activated when marker has been accepted.
702 */
703
704 static void
705 prepare_to_send(struct sbni_softc *sc)
706 {
707 struct mbuf *m;
708 u_int len;
709
710 /* sc->tx_buf_p == NULL here! */
711 if (sc->tx_buf_p)
712 printf("sbni: memory leak!\n");
713
714 sc->outpos = 0;
715 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
716
717 for (;;) {
718 IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p);
719 if (!sc->tx_buf_p) {
720 /* nothing to transmit... */
721 sc->pktlen = 0;
722 sc->tx_frameno = 0;
723 sc->framelen = 0;
724 sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
725 return;
726 }
727
728 for (len = 0, m = sc->tx_buf_p; m; m = m->m_next)
729 len += m->m_len;
730
731 if (len != 0)
732 break;
733 m_freem(sc->tx_buf_p);
734 }
735
736 if (len < SBNI_MIN_LEN)
737 len = SBNI_MIN_LEN;
738
739 sc->pktlen = len;
740 sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe;
741 sc->framelen = min(len, sc->maxframe);
742
743 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ);
744 sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
745 BPF_MTAP(sc->ifp, sc->tx_buf_p);
746 }
747
748
749 static void
750 drop_xmit_queue(struct sbni_softc *sc)
751 {
752 struct mbuf *m;
753
754 if (sc->tx_buf_p) {
755 m_freem(sc->tx_buf_p);
756 sc->tx_buf_p = NULL;
757 sc->ifp->if_oerrors++;
758 }
759
760 for (;;) {
761 IF_DEQUEUE(&sc->ifp->if_snd, m);
762 if (m == NULL)
763 break;
764 m_freem(m);
765 sc->ifp->if_oerrors++;
766 }
767
768 sc->tx_frameno = 0;
769 sc->framelen = 0;
770 sc->outpos = 0;
771 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
772 sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
773 }
774
775
776 static void
777 send_frame_header(struct sbni_softc *sc, u_int32_t *crc_p)
778 {
779 u_int32_t crc;
780 u_int len_field;
781 u_char value;
782
783 crc = *crc_p;
784 len_field = sc->framelen + 6; /* CRC + frameno + reserved */
785
786 if (sc->state & FL_NEED_RESEND)
787 len_field |= FRAME_RETRY; /* non-first attempt... */
788
789 if (sc->outpos == 0)
790 len_field |= FRAME_FIRST;
791
792 len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
793 sbni_outb(sc, DAT, SBNI_SIG);
794
795 value = (u_char)len_field;
796 sbni_outb(sc, DAT, value);
797 crc = CRC32(value, crc);
798 value = (u_char)(len_field >> 8);
799 sbni_outb(sc, DAT, value);
800 crc = CRC32(value, crc);
801
802 sbni_outb(sc, DAT, sc->tx_frameno);
803 crc = CRC32(sc->tx_frameno, crc);
804 sbni_outb(sc, DAT, 0);
805 crc = CRC32(0, crc);
806 *crc_p = crc;
807 }
808
809
810 /*
811 * if frame tail not needed (incorrect number or received twice),
812 * it won't store, but CRC will be calculated
813 */
814
815 static int
816 skip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc)
817 {
818 while (tail_len--)
819 crc = CRC32(sbni_inb(sc, DAT), crc);
820
821 return (crc == CRC32_REMAINDER);
822 }
823
824
825 static int
826 check_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno,
827 u_int *ack, u_int *is_first, u_int32_t *crc_p)
828 {
829 u_int32_t crc;
830 u_char value;
831
832 crc = *crc_p;
833 if (sbni_inb(sc, DAT) != SBNI_SIG)
834 return (0);
835
836 value = sbni_inb(sc, DAT);
837 *framelen = (u_int)value;
838 crc = CRC32(value, crc);
839 value = sbni_inb(sc, DAT);
840 *framelen |= ((u_int)value) << 8;
841 crc = CRC32(value, crc);
842
843 *ack = *framelen & FRAME_ACK_MASK;
844 *is_first = (*framelen & FRAME_FIRST) != 0;
845
846 if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3)
847 return (0);
848
849 value = sbni_inb(sc, DAT);
850 *frameno = (u_int)value;
851 crc = CRC32(value, crc);
852
853 crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */
854 *framelen -= 2;
855
856 *crc_p = crc;
857 return (1);
858 }
859
860
861 static int
862 get_rx_buf(struct sbni_softc *sc)
863 {
864 struct mbuf *m;
865
866 MGETHDR(m, M_NOWAIT, MT_DATA);
867 if (m == NULL) {
868 if_printf(sc->ifp, "cannot allocate header mbuf\n");
869 return (0);
870 }
871
872 /*
873 * We always put the received packet in a single buffer -
874 * either with just an mbuf header or in a cluster attached
875 * to the header. The +2 is to compensate for the alignment
876 * fixup below.
877 */
878 if (ETHER_MAX_LEN + 2 > MHLEN) {
879 /* Attach an mbuf cluster */
880 MCLGET(m, M_NOWAIT);
881 if ((m->m_flags & M_EXT) == 0) {
882 m_freem(m);
883 return (0);
884 }
885 }
886 m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2;
887
888 /*
889 * The +2 is to longword align the start of the real packet.
890 * (sizeof ether_header == 14)
891 * This is important for NFS.
892 */
893 m_adj(m, 2);
894 sc->rx_buf_p = m;
895 return (1);
896 }
897
898
899 static void
900 indicate_pkt(struct sbni_softc *sc)
901 {
902 struct ifnet *ifp = sc->ifp;
903 struct mbuf *m;
904
905 m = sc->rx_buf_p;
906 m->m_pkthdr.rcvif = ifp;
907 m->m_pkthdr.len = m->m_len = sc->inppos;
908 sc->rx_buf_p = NULL;
909
910 SBNI_UNLOCK(sc);
911 (*ifp->if_input)(ifp, m);
912 SBNI_LOCK(sc);
913 }
914
915 /* -------------------------------------------------------------------------- */
916
917 /*
918 * Routine checks periodically wire activity and regenerates marker if
919 * connect was inactive for a long time.
920 */
921
922 static void
923 sbni_timeout(void *xsc)
924 {
925 struct sbni_softc *sc;
926 u_char csr0;
927
928 sc = (struct sbni_softc *)xsc;
929 SBNI_ASSERT_LOCKED(sc);
930
931 csr0 = sbni_inb(sc, CSR0);
932 if (csr0 & RC_CHK) {
933
934 if (sc->timer_ticks) {
935 if (csr0 & (RC_RDY | BU_EMP))
936 /* receiving not active */
937 sc->timer_ticks--;
938 } else {
939 sc->in_stats.timeout_number++;
940 if (sc->delta_rxl)
941 timeout_change_level(sc);
942
943 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
944 csr0 = sbni_inb(sc, CSR0);
945 }
946 }
947
948 sbni_outb(sc, CSR0, csr0 | RC_CHK);
949 callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc);
950 }
951
952 /* -------------------------------------------------------------------------- */
953
954 static void
955 card_start(struct sbni_softc *sc)
956 {
957 sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
958 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
959 sc->state |= FL_PREV_OK;
960
961 sc->inppos = 0;
962 sc->wait_frameno = 0;
963
964 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
965 sbni_outb(sc, CSR0, EN_INT);
966 }
967
968 /* -------------------------------------------------------------------------- */
969
970 static u_char rxl_tab[] = {
971 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
972 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
973 };
974
975 #define SIZE_OF_TIMEOUT_RXL_TAB 4
976 static u_char timeout_rxl_tab[] = {
977 0x03, 0x05, 0x08, 0x0b
978 };
979
980 static void
981 set_initial_values(struct sbni_softc *sc, struct sbni_flags flags)
982 {
983 if (flags.fixed_rxl) {
984 sc->delta_rxl = 0; /* disable receive level autodetection */
985 sc->cur_rxl_index = flags.rxl;
986 } else {
987 sc->delta_rxl = DEF_RXL_DELTA;
988 sc->cur_rxl_index = DEF_RXL;
989 }
990
991 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
992 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
993 sc->maxframe = DEFAULT_FRAME_LEN;
994
995 /*
996 * generate Ethernet address (0x00ff01xxxxxx)
997 */
998 *(u_int16_t *) sc->enaddr = htons(0x00ff);
999 if (flags.mac_addr) {
1000 *(u_int32_t *) (sc->enaddr + 2) =
1001 htonl(flags.mac_addr | 0x01000000);
1002 } else {
1003 *(u_char *) (sc->enaddr + 2) = 0x01;
1004 read_random(sc->enaddr + 3, 3);
1005 }
1006 }
1007
1008
1009 #ifdef SBNI_DUAL_COMPOUND
1010 void
1011 sbni_add(struct sbni_softc *sc)
1012 {
1013
1014 mtx_lock(&headlist_lock);
1015 sc->link = sbni_headlist;
1016 sbni_headlist = sc;
1017 mtx_unlock(&headlist_lock);
1018 }
1019
1020 struct sbni_softc *
1021 connect_to_master(struct sbni_softc *sc)
1022 {
1023 struct sbni_softc *p, *p_prev;
1024
1025 mtx_lock(&headlist_lock);
1026 for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) {
1027 if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 ||
1028 rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) {
1029 p->slave_sc = sc;
1030 if (p_prev)
1031 p_prev->link = p->link;
1032 else
1033 sbni_headlist = p->link;
1034 mtx_unlock(&headlist_lock);
1035 return p;
1036 }
1037 }
1038 mtx_unlock(&headlist_lock);
1039
1040 return (NULL);
1041 }
1042
1043 #endif /* SBNI_DUAL_COMPOUND */
1044
1045
1046 /* Receive level auto-selection */
1047
1048 static void
1049 change_level(struct sbni_softc *sc)
1050 {
1051 if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */
1052 return;
1053
1054 if (sc->cur_rxl_index == 0)
1055 sc->delta_rxl = 1;
1056 else if (sc->cur_rxl_index == 15)
1057 sc->delta_rxl = -1;
1058 else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd)
1059 sc->delta_rxl = -sc->delta_rxl;
1060
1061 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl];
1062 sbni_inb(sc, CSR0); /* it needed for PCI cards */
1063 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
1064
1065 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
1066 sc->cur_rxl_rcvd = 0;
1067 }
1068
1069
1070 static void
1071 timeout_change_level(struct sbni_softc *sc)
1072 {
1073 sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl];
1074 if (++sc->timeout_rxl >= 4)
1075 sc->timeout_rxl = 0;
1076
1077 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
1078 sbni_inb(sc, CSR0);
1079 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
1080
1081 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
1082 sc->cur_rxl_rcvd = 0;
1083 }
1084
1085 /* -------------------------------------------------------------------------- */
1086
1087 /*
1088 * Process an ioctl request. This code needs some work - it looks
1089 * pretty ugly.
1090 */
1091
1092 static int
1093 sbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1094 {
1095 struct sbni_softc *sc;
1096 struct ifreq *ifr;
1097 struct thread *td;
1098 struct sbni_in_stats *in_stats;
1099 struct sbni_flags flags;
1100 int error;
1101
1102 sc = ifp->if_softc;
1103 ifr = (struct ifreq *)data;
1104 td = curthread;
1105 error = 0;
1106
1107 switch (command) {
1108 case SIOCSIFFLAGS:
1109 /*
1110 * If the interface is marked up and stopped, then start it.
1111 * If it is marked down and running, then stop it.
1112 */
1113 SBNI_LOCK(sc);
1114 if (ifp->if_flags & IFF_UP) {
1115 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1116 sbni_init_locked(sc);
1117 } else {
1118 if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1119 sbni_stop(sc);
1120 }
1121 }
1122 SBNI_UNLOCK(sc);
1123 break;
1124
1125 case SIOCADDMULTI:
1126 case SIOCDELMULTI:
1127 /*
1128 * Multicast list has changed; set the hardware filter
1129 * accordingly.
1130 */
1131 error = 0;
1132 /* if (ifr == NULL)
1133 error = EAFNOSUPPORT; */
1134 break;
1135
1136 /*
1137 * SBNI specific ioctl
1138 */
1139 case SIOCGHWFLAGS: /* get flags */
1140 SBNI_LOCK(sc);
1141 bcopy((caddr_t)IF_LLADDR(sc->ifp)+3, (caddr_t) &flags, 3);
1142 flags.rxl = sc->cur_rxl_index;
1143 flags.rate = sc->csr1.rate;
1144 flags.fixed_rxl = (sc->delta_rxl == 0);
1145 flags.fixed_rate = 1;
1146 SBNI_UNLOCK(sc);
1147 ifr->ifr_data = *(caddr_t*) &flags;
1148 break;
1149
1150 case SIOCGINSTATS:
1151 in_stats = malloc(sizeof(struct sbni_in_stats), M_DEVBUF,
1152 M_WAITOK);
1153 SBNI_LOCK(sc);
1154 bcopy(&sc->in_stats, in_stats, sizeof(struct sbni_in_stats));
1155 SBNI_UNLOCK(sc);
1156 error = copyout(ifr->ifr_data, in_stats,
1157 sizeof(struct sbni_in_stats));
1158 free(in_stats, M_DEVBUF);
1159 break;
1160
1161 case SIOCSHWFLAGS: /* set flags */
1162 /* root only */
1163 error = priv_check(td, PRIV_DRIVER);
1164 if (error)
1165 break;
1166 flags = *(struct sbni_flags*)&ifr->ifr_data;
1167 SBNI_LOCK(sc);
1168 if (flags.fixed_rxl) {
1169 sc->delta_rxl = 0;
1170 sc->cur_rxl_index = flags.rxl;
1171 } else {
1172 sc->delta_rxl = DEF_RXL_DELTA;
1173 sc->cur_rxl_index = DEF_RXL;
1174 }
1175 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
1176 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
1177 if (flags.mac_addr)
1178 bcopy((caddr_t) &flags,
1179 (caddr_t) IF_LLADDR(sc->ifp)+3, 3);
1180
1181 /* Don't be afraid... */
1182 sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES);
1183 SBNI_UNLOCK(sc);
1184 break;
1185
1186 case SIOCRINSTATS:
1187 SBNI_LOCK(sc);
1188 if (!(error = priv_check(td, PRIV_DRIVER))) /* root only */
1189 bzero(&sc->in_stats, sizeof(struct sbni_in_stats));
1190 SBNI_UNLOCK(sc);
1191 break;
1192
1193 default:
1194 error = ether_ioctl(ifp, command, data);
1195 break;
1196 }
1197
1198 return (error);
1199 }
1200
1201 /* -------------------------------------------------------------------------- */
1202
1203 static u_int32_t
1204 calc_crc32(u_int32_t crc, caddr_t p, u_int len)
1205 {
1206 while (len--)
1207 crc = CRC32(*p++, crc);
1208
1209 return (crc);
1210 }
1211
1212 static u_int32_t crc32tab[] __aligned(8) = {
1213 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37,
1214 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E,
1215 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605,
1216 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C,
1217 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53,
1218 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A,
1219 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661,
1220 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278,
1221 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF,
1222 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6,
1223 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD,
1224 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4,
1225 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B,
1226 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82,
1227 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9,
1228 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0,
1229 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7,
1230 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE,
1231 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795,
1232 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C,
1233 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3,
1234 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA,
1235 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1,
1236 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8,
1237 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F,
1238 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76,
1239 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D,
1240 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344,
1241 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B,
1242 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12,
1243 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739,
1244 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320,
1245 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17,
1246 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E,
1247 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525,
1248 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C,
1249 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73,
1250 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A,
1251 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541,
1252 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158,
1253 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF,
1254 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6,
1255 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED,
1256 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4,
1257 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB,
1258 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2,
1259 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589,
1260 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190,
1261 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87,
1262 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E,
1263 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5,
1264 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC,
1265 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3,
1266 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA,
1267 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1,
1268 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8,
1269 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F,
1270 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856,
1271 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D,
1272 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064,
1273 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B,
1274 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832,
1275 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419,
1276 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000
1277 };
Cache object: b4dab293d2040318c86527b277ac47da
|