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