suser_* to priv_* conversion
[dragonfly.git] / sys / dev / netif / sbni / if_sbni.c
blob21f4f5c56a86167e009681b99c132a036c72ecab
1 /*
2 * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved.
3 * Author: Denis I.Timofeev <timofeev@granch.ru>
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.
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.
27 * $FreeBSD: src/sys/dev/sbni/if_sbni.c,v 1.1.2.4 2002/08/11 09:32:00 fjoe Exp $
28 * $DragonFly: src/sys/dev/netif/sbni/if_sbni.c,v 1.28 2008/05/14 11:59:21 sephe Exp $
32 * Device driver for Granch SBNI12 leased line adapters
34 * Revision 2.0.0 1997/08/06
35 * Initial revision by Alexey Zverev
37 * Revision 2.0.1 1997/08/11
38 * Additional internal statistics support (tx statistics)
40 * Revision 2.0.2 1997/11/05
41 * if_bpf bug has been fixed
43 * Revision 2.0.3 1998/12/20
44 * Memory leakage has been eliminated in
45 * the sbni_st and sbni_timeout routines.
47 * Revision 3.0 2000/08/10 by Yaroslav Polyakov
48 * Support for PCI cards. 4.1 modification.
50 * Revision 3.1 2000/09/12
51 * Removed extra #defines around bpf functions
53 * Revision 4.0 2000/11/23 by Denis Timofeev
54 * Completely redesigned the buffer management
56 * Revision 4.1 2001/01/21
57 * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards
59 * Written with reference to NE2000 driver developed by David Greenman.
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/socket.h>
66 #include <sys/sockio.h>
67 #include <sys/mbuf.h>
68 #include <sys/kernel.h>
69 #include <sys/proc.h>
70 #include <sys/priv.h>
71 #include <sys/callout.h>
72 #include <sys/syslog.h>
73 #include <sys/random.h>
74 #include <sys/bus.h>
75 #include <sys/rman.h>
76 #include <sys/thread2.h>
78 #include <net/if.h>
79 #include <net/ifq_var.h>
80 #include <net/ethernet.h>
81 #include <net/if_arp.h>
82 #include <net/bpf.h>
84 #include "if_sbnireg.h"
85 #include "if_sbnivar.h"
87 #ifdef __i386__
88 #define ASM_CRC 1
89 #endif
91 static void sbni_init(void *);
92 static void sbni_start(struct ifnet *);
93 static int sbni_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
94 static void sbni_watchdog(struct ifnet *);
95 static void sbni_stop(struct sbni_softc *);
96 static void handle_channel(struct sbni_softc *);
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);
117 static u_int32_t calc_crc32(u_int32_t, caddr_t, u_int);
118 static timeout_t sbni_timeout;
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);
125 DECLARE_DUMMY_MODULE(if_sbni);
127 static u_int32_t crc32tab[];
129 #ifdef SBNI_DUAL_COMPOUND
130 struct sbni_softc *sbni_headlist;
131 #endif
133 u_int32_t next_sbni_unit;
135 /* -------------------------------------------------------------------------- */
137 static __inline u_char
138 sbni_inb(struct sbni_softc *sc, enum sbni_reg reg)
140 return bus_space_read_1(
141 rman_get_bustag(sc->io_res),
142 rman_get_bushandle(sc->io_res),
143 sc->io_off + reg);
146 static __inline void
147 sbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value)
149 bus_space_write_1(
150 rman_get_bustag(sc->io_res),
151 rman_get_bushandle(sc->io_res),
152 sc->io_off + reg, value);
155 static __inline void
156 sbni_insb(struct sbni_softc *sc, u_char *to, u_int len)
158 bus_space_read_multi_1(
159 rman_get_bustag(sc->io_res),
160 rman_get_bushandle(sc->io_res),
161 sc->io_off + DAT, to, len);
164 static __inline void
165 sbni_outsb(struct sbni_softc *sc, u_char *from, u_int len)
167 bus_space_write_multi_1(
168 rman_get_bustag(sc->io_res),
169 rman_get_bushandle(sc->io_res),
170 sc->io_off + DAT, from, len);
175 Valid combinations in CSR0 (for probing):
177 VALID_DECODER 0000,0011,1011,1010
179 ; 0 ; -
180 TR_REQ ; 1 ; +
181 TR_RDY ; 2 ; -
182 TR_RDY TR_REQ ; 3 ; +
183 BU_EMP ; 4 ; +
184 BU_EMP TR_REQ ; 5 ; +
185 BU_EMP TR_RDY ; 6 ; -
186 BU_EMP TR_RDY TR_REQ ; 7 ; +
187 RC_RDY ; 8 ; +
188 RC_RDY TR_REQ ; 9 ; +
189 RC_RDY TR_RDY ; 10 ; -
190 RC_RDY TR_RDY TR_REQ ; 11 ; -
191 RC_RDY BU_EMP ; 12 ; -
192 RC_RDY BU_EMP TR_REQ ; 13 ; -
193 RC_RDY BU_EMP TR_RDY ; 14 ; -
194 RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; -
197 #define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
201 sbni_probe(struct sbni_softc *sc)
203 u_char csr0;
205 csr0 = sbni_inb(sc, CSR0);
206 if (csr0 != 0xff && csr0 != 0x00) {
207 csr0 &= ~EN_INT;
208 if (csr0 & BU_EMP)
209 csr0 |= EN_INT;
211 if (VALID_DECODER & (1 << (csr0 >> 4)))
212 return (0);
215 return (ENXIO);
220 * Install interface into kernel networking data structures
222 void
223 sbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags)
225 struct ifnet *ifp;
226 u_char csr0;
228 ifp = &sc->arpcom.ac_if;
229 sbni_outb(sc, CSR0, 0);
230 set_initial_values(sc, flags);
232 callout_init(&sc->sbni_stat_timer);
233 /* Initialize ifnet structure */
234 ifp->if_softc = sc;
235 if_initname(ifp, "sbni", unit);
236 ifp->if_init = sbni_init;
237 ifp->if_start = sbni_start;
238 ifp->if_ioctl = sbni_ioctl;
239 ifp->if_watchdog = sbni_watchdog;
240 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
241 ifq_set_ready(&ifp->if_snd);
243 /* report real baud rate */
244 csr0 = sbni_inb(sc, CSR0);
245 ifp->if_baudrate =
246 (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate);
248 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
249 ether_ifattach(ifp, sc->arpcom.ac_enaddr, NULL);
251 /* device attach does transition from UNCONFIGURED to IDLE state */
253 if_printf(ifp, "speed %ld, rxl ", ifp->if_baudrate);
254 if (sc->delta_rxl)
255 kprintf("auto\n");
256 else
257 kprintf("%d (fixed)\n", sc->cur_rxl_index);
260 /* -------------------------------------------------------------------------- */
262 static void
263 sbni_init(void *xsc)
265 struct sbni_softc *sc =xsc;
266 struct ifnet *ifp = &sc->arpcom.ac_if;
269 * kludge to avoid multiple initialization when more than once
270 * protocols configured
272 if (ifp->if_flags & IFF_RUNNING)
273 return;
274 ifp->if_timer = 0;
275 card_start(sc);
276 callout_reset(&sc->sbni_stat_timer,hz / SBNI_HZ, sbni_timeout, sc);
278 ifp->if_flags |= IFF_RUNNING;
279 ifp->if_flags &= ~IFF_OACTIVE;
281 /* attempt to start output */
282 if_devstart(ifp);
286 static void
287 sbni_start(struct ifnet *ifp)
289 struct sbni_softc *sc = ifp->if_softc;
290 if (sc->tx_frameno == 0)
291 prepare_to_send(sc);
295 static void
296 sbni_stop(struct sbni_softc *sc)
298 sbni_outb(sc, CSR0, 0);
299 drop_xmit_queue(sc);
301 if (sc->rx_buf_p) {
302 m_freem(sc->rx_buf_p);
303 sc->rx_buf_p = NULL;
306 callout_stop(&sc->sbni_stat_timer);
309 /* -------------------------------------------------------------------------- */
311 /* interrupt handler */
314 * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
315 * be looked as two independent single-channel devices. Every channel seems
316 * as Ethernet interface but interrupt handler must be common. Really, first
317 * channel ("master") driver only registers the handler. In it's struct softc
318 * it has got pointer to "slave" channel's struct softc and handles that's
319 * interrupts too.
320 * softc of successfully attached ISA SBNI boards is linked to list.
321 * While next board driver is initialized, it scans this list. If one
322 * has found softc with same irq and ioaddr different by 4 then it assumes
323 * this board to be "master".
326 void
327 sbni_intr(void *arg)
329 struct sbni_softc *sc;
330 int repeat;
332 sc = (struct sbni_softc *)arg;
334 do {
335 repeat = 0;
336 if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) {
337 handle_channel(sc);
338 repeat = 1;
340 if (sc->slave_sc && /* second channel present */
341 (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) {
342 handle_channel(sc->slave_sc);
343 repeat = 1;
345 } while (repeat);
349 static void
350 handle_channel(struct sbni_softc *sc)
352 int req_ans;
353 u_char csr0;
355 sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ);
357 sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
358 for (;;) {
359 csr0 = sbni_inb(sc, CSR0);
360 if ((csr0 & (RC_RDY | TR_RDY)) == 0)
361 break;
363 req_ans = !(sc->state & FL_PREV_OK);
365 if (csr0 & RC_RDY)
366 req_ans = recv_frame(sc);
369 * TR_RDY always equals 1 here because we have owned the marker,
370 * and we set TR_REQ when disabled interrupts
372 csr0 = sbni_inb(sc, CSR0);
373 if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0)
374 kprintf("sbni: internal error!\n");
376 /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
377 if (req_ans || sc->tx_frameno != 0)
378 send_frame(sc);
379 else {
380 /* send the marker without any data */
381 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ);
385 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT);
390 * Routine returns 1 if it need to acknoweledge received frame.
391 * Empty frame received without errors won't be acknoweledged.
394 static int
395 recv_frame(struct sbni_softc *sc)
397 u_int32_t crc;
398 u_int framelen, frameno, ack;
399 u_int is_first, frame_ok;
401 crc = CRC32_INITIAL;
402 framelen = 0;
403 if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) {
404 frame_ok = framelen > 4 ?
405 upload_data(sc, framelen, frameno, is_first, crc) :
406 skip_tail(sc, framelen, crc);
407 if (frame_ok)
408 interpret_ack(sc, ack);
409 } else
410 frame_ok = 0;
412 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER);
413 if (frame_ok) {
414 sc->state |= FL_PREV_OK;
415 if (framelen > 4)
416 sc->in_stats.all_rx_number++;
417 } else {
418 sc->state &= ~FL_PREV_OK;
419 change_level(sc);
420 sc->in_stats.all_rx_number++;
421 sc->in_stats.bad_rx_number++;
424 return (!frame_ok || framelen > 4);
428 static void
429 send_frame(struct sbni_softc *sc)
431 u_int32_t crc;
432 u_char csr0;
434 crc = CRC32_INITIAL;
435 if (sc->state & FL_NEED_RESEND) {
437 /* if frame was sended but not ACK'ed - resend it */
438 if (sc->trans_errors) {
439 sc->trans_errors--;
440 if (sc->framelen != 0)
441 sc->in_stats.resend_tx_number++;
442 } else {
443 /* cannot xmit with many attempts */
444 drop_xmit_queue(sc);
445 goto do_send;
447 } else
448 sc->trans_errors = TR_ERROR_COUNT;
450 send_frame_header(sc, &crc);
451 sc->state |= FL_NEED_RESEND;
453 * FL_NEED_RESEND will be cleared after ACK, but if empty
454 * frame sended then in prepare_to_send next frame
458 if (sc->framelen) {
459 download_data(sc, &crc);
460 sc->in_stats.all_tx_number++;
461 sc->state |= FL_WAIT_ACK;
464 sbni_outsb(sc, (u_char *)&crc, sizeof crc);
466 do_send:
467 csr0 = sbni_inb(sc, CSR0);
468 sbni_outb(sc, CSR0, csr0 & ~TR_REQ);
470 if (sc->tx_frameno) {
471 /* next frame exists - request to send */
472 sbni_outb(sc, CSR0, csr0 | TR_REQ);
477 static void
478 download_data(struct sbni_softc *sc, u_int32_t *crc_p)
480 struct mbuf *m;
481 caddr_t data_p;
482 u_int data_len, pos, slice;
484 data_p = NULL; /* initialized to avoid warn */
485 pos = 0;
487 for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) {
488 if (pos + m->m_len > sc->outpos) {
489 data_len = m->m_len - (sc->outpos - pos);
490 data_p = mtod(m, caddr_t) + (sc->outpos - pos);
492 goto do_copy;
493 } else
494 pos += m->m_len;
497 data_len = 0;
499 do_copy:
500 pos = 0;
501 do {
502 if (data_len) {
503 slice = min(data_len, sc->framelen - pos);
504 sbni_outsb(sc, data_p, slice);
505 *crc_p = calc_crc32(*crc_p, data_p, slice);
507 pos += slice;
508 if (data_len -= slice)
509 data_p += slice;
510 else {
511 do {
512 m = m->m_next;
513 } while (m != NULL && m->m_len == 0);
515 if (m) {
516 data_len = m->m_len;
517 data_p = mtod(m, caddr_t);
520 } else {
521 /* frame too short - zero padding */
523 pos = sc->framelen - pos;
524 while (pos--) {
525 sbni_outb(sc, DAT, 0);
526 *crc_p = CRC32(0, *crc_p);
528 return;
530 } while (pos < sc->framelen);
534 static int
535 upload_data(struct sbni_softc *sc, u_int framelen, u_int frameno,
536 u_int is_first, u_int32_t crc)
538 int frame_ok;
540 if (is_first) {
541 sc->wait_frameno = frameno;
542 sc->inppos = 0;
545 if (sc->wait_frameno == frameno) {
547 if (sc->inppos + framelen <= ETHER_MAX_LEN) {
548 frame_ok = append_frame_to_pkt(sc, framelen, crc);
551 * if CRC is right but framelen incorrect then transmitter
552 * error was occured... drop entire packet
554 } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) {
555 sc->wait_frameno = 0;
556 sc->inppos = 0;
557 sc->arpcom.ac_if.if_ierrors++;
558 /* now skip all frames until is_first != 0 */
560 } else
561 frame_ok = skip_tail(sc, framelen, crc);
563 if (is_first && !frame_ok) {
565 * Frame has been violated, but we have stored
566 * is_first already... Drop entire packet.
568 sc->wait_frameno = 0;
569 sc->arpcom.ac_if.if_ierrors++;
572 return (frame_ok);
576 static __inline void send_complete(struct sbni_softc *);
578 static __inline void
579 send_complete(struct sbni_softc *sc)
581 m_freem(sc->tx_buf_p);
582 sc->tx_buf_p = NULL;
583 sc->arpcom.ac_if.if_opackets++;
587 static void
588 interpret_ack(struct sbni_softc *sc, u_int ack)
590 if (ack == FRAME_SENT_OK) {
591 sc->state &= ~FL_NEED_RESEND;
593 if (sc->state & FL_WAIT_ACK) {
594 sc->outpos += sc->framelen;
596 if (--sc->tx_frameno) {
597 sc->framelen = min(
598 sc->maxframe, sc->pktlen - sc->outpos);
599 } else {
600 send_complete(sc);
601 prepare_to_send(sc);
606 sc->state &= ~FL_WAIT_ACK;
611 * Glue received frame with previous fragments of packet.
612 * Indicate packet when last frame would be accepted.
615 static int
616 append_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc)
618 caddr_t p;
620 if (sc->inppos + framelen > ETHER_MAX_LEN)
621 return (0);
623 if (!sc->rx_buf_p && !get_rx_buf(sc))
624 return (0);
626 p = sc->rx_buf_p->m_data + sc->inppos;
627 sbni_insb(sc, p, framelen);
628 if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER)
629 return (0);
631 sc->inppos += framelen - 4;
632 if (--sc->wait_frameno == 0) { /* last frame received */
633 indicate_pkt(sc);
634 sc->arpcom.ac_if.if_ipackets++;
637 return (1);
642 * Prepare to start output on adapter.
643 * Transmitter will be actually activated when marker has been accepted.
646 static void
647 prepare_to_send(struct sbni_softc *sc)
649 struct mbuf *m;
650 u_int len;
652 /* sc->tx_buf_p == NULL here! */
653 if (sc->tx_buf_p)
654 kprintf("sbni: memory leak!\n");
656 sc->outpos = 0;
657 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
659 for (;;) {
660 sc->tx_buf_p = ifq_dequeue(&sc->arpcom.ac_if.if_snd, NULL);
661 if (sc->tx_buf_p == NULL) {
662 /* nothing to transmit... */
663 sc->pktlen = 0;
664 sc->tx_frameno = 0;
665 sc->framelen = 0;
666 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
667 return;
670 for (len = 0, m = sc->tx_buf_p; m; m = m->m_next)
671 len += m->m_len;
673 if (len != 0)
674 break;
675 m_freem(sc->tx_buf_p);
678 if (len < SBNI_MIN_LEN)
679 len = SBNI_MIN_LEN;
681 sc->pktlen = len;
682 sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe;
683 sc->framelen = min(len, sc->maxframe);
685 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ);
686 sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
687 BPF_MTAP(&sc->arpcom.ac_if, sc->tx_buf_p);
691 static void
692 drop_xmit_queue(struct sbni_softc *sc)
694 if (sc->tx_buf_p) {
695 m_freem(sc->tx_buf_p);
696 sc->tx_buf_p = NULL;
697 sc->arpcom.ac_if.if_oerrors++;
700 ifq_purge(&sc->arpcom.ac_if.if_snd);
702 sc->tx_frameno = 0;
703 sc->framelen = 0;
704 sc->outpos = 0;
705 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
706 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
710 static void
711 send_frame_header(struct sbni_softc *sc, u_int32_t *crc_p)
713 u_int32_t crc;
714 u_int len_field;
715 u_char value;
717 crc = *crc_p;
718 len_field = sc->framelen + 6; /* CRC + frameno + reserved */
720 if (sc->state & FL_NEED_RESEND)
721 len_field |= FRAME_RETRY; /* non-first attempt... */
723 if (sc->outpos == 0)
724 len_field |= FRAME_FIRST;
726 len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
727 sbni_outb(sc, DAT, SBNI_SIG);
729 value = (u_char)len_field;
730 sbni_outb(sc, DAT, value);
731 crc = CRC32(value, crc);
732 value = (u_char)(len_field >> 8);
733 sbni_outb(sc, DAT, value);
734 crc = CRC32(value, crc);
736 sbni_outb(sc, DAT, sc->tx_frameno);
737 crc = CRC32(sc->tx_frameno, crc);
738 sbni_outb(sc, DAT, 0);
739 crc = CRC32(0, crc);
740 *crc_p = crc;
745 * if frame tail not needed (incorrect number or received twice),
746 * it won't store, but CRC will be calculated
749 static int
750 skip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc)
752 while (tail_len--)
753 crc = CRC32(sbni_inb(sc, DAT), crc);
755 return (crc == CRC32_REMAINDER);
759 static int
760 check_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno,
761 u_int *ack, u_int *is_first, u_int32_t *crc_p)
763 u_int32_t crc;
764 u_char value;
766 crc = *crc_p;
767 if (sbni_inb(sc, DAT) != SBNI_SIG)
768 return (0);
770 value = sbni_inb(sc, DAT);
771 *framelen = (u_int)value;
772 crc = CRC32(value, crc);
773 value = sbni_inb(sc, DAT);
774 *framelen |= ((u_int)value) << 8;
775 crc = CRC32(value, crc);
777 *ack = *framelen & FRAME_ACK_MASK;
778 *is_first = (*framelen & FRAME_FIRST) != 0;
780 if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3)
781 return (0);
783 value = sbni_inb(sc, DAT);
784 *frameno = (u_int)value;
785 crc = CRC32(value, crc);
787 crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */
788 *framelen -= 2;
790 *crc_p = crc;
791 return (1);
795 static int
796 get_rx_buf(struct sbni_softc *sc)
798 struct mbuf *m;
800 MGETHDR(m, MB_DONTWAIT, MT_DATA);
801 if (m == NULL) {
802 kprintf("%s: cannot allocate header mbuf\n",
803 sc->arpcom.ac_if.if_xname);
804 return (0);
808 * We always put the received packet in a single buffer -
809 * either with just an mbuf header or in a cluster attached
810 * to the header. The +2 is to compensate for the alignment
811 * fixup below.
813 if (ETHER_MAX_LEN + 2 > MHLEN) {
814 /* Attach an mbuf cluster */
815 MCLGET(m, MB_DONTWAIT);
816 if ((m->m_flags & M_EXT) == 0) {
817 m_freem(m);
818 return (0);
821 m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2;
824 * The +2 is to longword align the start of the real packet.
825 * (sizeof ether_header == 14)
826 * This is important for NFS.
828 m_adj(m, 2);
829 sc->rx_buf_p = m;
830 return (1);
834 static void
835 indicate_pkt(struct sbni_softc *sc)
837 struct ifnet *ifp = &sc->arpcom.ac_if;
838 struct mbuf *m;
840 m = sc->rx_buf_p;
841 m->m_pkthdr.rcvif = ifp;
842 m->m_pkthdr.len = m->m_len = sc->inppos;
844 ifp->if_input(ifp, m);
845 sc->rx_buf_p = NULL;
848 /* -------------------------------------------------------------------------- */
851 * Routine checks periodically wire activity and regenerates marker if
852 * connect was inactive for a long time.
855 static void
856 sbni_timeout(void *xsc)
858 struct sbni_softc *sc = xsc;
859 u_char csr0;
861 lwkt_serialize_enter(sc->arpcom.ac_if.if_serializer);
863 csr0 = sbni_inb(sc, CSR0);
864 if (csr0 & RC_CHK) {
866 if (sc->timer_ticks) {
867 if (csr0 & (RC_RDY | BU_EMP))
868 /* receiving not active */
869 sc->timer_ticks--;
870 } else {
871 sc->in_stats.timeout_number++;
872 if (sc->delta_rxl)
873 timeout_change_level(sc);
875 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
876 csr0 = sbni_inb(sc, CSR0);
880 sbni_outb(sc, CSR0, csr0 | RC_CHK);
881 callout_reset(&sc->sbni_stat_timer, hz / SBNI_HZ, sbni_timeout, sc);
883 lwkt_serialize_exit(sc->arpcom.ac_if.if_serializer);
886 /* -------------------------------------------------------------------------- */
888 static void
889 card_start(struct sbni_softc *sc)
891 sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
892 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
893 sc->state |= FL_PREV_OK;
895 sc->inppos = 0;
896 sc->wait_frameno = 0;
898 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
899 sbni_outb(sc, CSR0, EN_INT);
902 /* -------------------------------------------------------------------------- */
905 * Device timeout/watchdog routine. Entered if the device neglects to
906 * generate an interrupt after a transmit has been started on it.
909 static void
910 sbni_watchdog(struct ifnet *ifp)
912 log(LOG_ERR, "%s: device timeout\n", ifp->if_xname);
913 ifp->if_oerrors++;
917 static u_char rxl_tab[] = {
918 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
919 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
922 #define SIZE_OF_TIMEOUT_RXL_TAB 4
923 static u_char timeout_rxl_tab[] = {
924 0x03, 0x05, 0x08, 0x0b
927 static void
928 set_initial_values(struct sbni_softc *sc, struct sbni_flags flags)
930 if (flags.fixed_rxl) {
931 sc->delta_rxl = 0; /* disable receive level autodetection */
932 sc->cur_rxl_index = flags.rxl;
933 } else {
934 sc->delta_rxl = DEF_RXL_DELTA;
935 sc->cur_rxl_index = DEF_RXL;
938 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
939 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
940 sc->maxframe = DEFAULT_FRAME_LEN;
943 * generate Ethernet address (0x00ff01xxxxxx)
945 *(u_int16_t *) sc->arpcom.ac_enaddr = htons(0x00ff);
946 if (flags.mac_addr) {
947 *(u_int32_t *) (sc->arpcom.ac_enaddr + 2) =
948 htonl(flags.mac_addr | 0x01000000);
949 } else {
950 *(u_char *) (sc->arpcom.ac_enaddr + 2) = 0x01;
951 read_random_unlimited(sc->arpcom.ac_enaddr + 3, 3);
956 #ifdef SBNI_DUAL_COMPOUND
958 struct sbni_softc *
959 connect_to_master(struct sbni_softc *sc)
961 struct sbni_softc *p, *p_prev;
963 for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) {
964 if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 ||
965 rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) {
966 p->slave_sc = sc;
967 if (p_prev)
968 p_prev->link = p->link;
969 else
970 sbni_headlist = p->link;
971 return p;
975 return (NULL);
978 #endif /* SBNI_DUAL_COMPOUND */
981 /* Receive level auto-selection */
983 static void
984 change_level(struct sbni_softc *sc)
986 if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */
987 return;
989 if (sc->cur_rxl_index == 0)
990 sc->delta_rxl = 1;
991 else if (sc->cur_rxl_index == 15)
992 sc->delta_rxl = -1;
993 else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd)
994 sc->delta_rxl = -sc->delta_rxl;
996 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl];
997 sbni_inb(sc, CSR0); /* it needed for PCI cards */
998 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
1000 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
1001 sc->cur_rxl_rcvd = 0;
1005 static void
1006 timeout_change_level(struct sbni_softc *sc)
1008 sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl];
1009 if (++sc->timeout_rxl >= 4)
1010 sc->timeout_rxl = 0;
1012 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
1013 sbni_inb(sc, CSR0);
1014 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
1016 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
1017 sc->cur_rxl_rcvd = 0;
1020 /* -------------------------------------------------------------------------- */
1023 * Process an ioctl request. This code needs some work - it looks
1024 * pretty ugly.
1027 static int
1028 sbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
1030 struct sbni_softc *sc;
1031 struct ifreq *ifr;
1032 struct sbni_in_stats *in_stats;
1033 struct sbni_flags flags;
1034 int error;
1036 sc = ifp->if_softc;
1037 ifr = (struct ifreq *)data;
1038 error = 0;
1040 switch (command) {
1041 case SIOCSIFFLAGS:
1043 * If the interface is marked up and stopped, then start it.
1044 * If it is marked down and running, then stop it.
1046 if (ifp->if_flags & IFF_UP) {
1047 if (!(ifp->if_flags & IFF_RUNNING))
1048 sbni_init(sc);
1049 } else {
1050 if (ifp->if_flags & IFF_RUNNING) {
1051 sbni_stop(sc);
1052 ifp->if_flags &= ~IFF_RUNNING;
1055 break;
1057 case SIOCADDMULTI:
1058 case SIOCDELMULTI:
1060 * Multicast list has changed; set the hardware filter
1061 * accordingly.
1063 error = 0;
1064 /* if (ifr == NULL)
1065 error = EAFNOSUPPORT; */
1066 break;
1068 case SIOCSIFMTU:
1069 if (ifr->ifr_mtu > ETHERMTU)
1070 error = EINVAL;
1071 else
1072 ifp->if_mtu = ifr->ifr_mtu;
1073 break;
1076 * SBNI specific ioctl
1078 case SIOCGHWFLAGS: /* get flags */
1079 bcopy((caddr_t) sc->arpcom.ac_enaddr+3, (caddr_t) &flags, 3);
1080 flags.rxl = sc->cur_rxl_index;
1081 flags.rate = sc->csr1.rate;
1082 flags.fixed_rxl = (sc->delta_rxl == 0);
1083 flags.fixed_rate = 1;
1084 ifr->ifr_data = *(caddr_t*) &flags;
1085 break;
1087 case SIOCGINSTATS:
1088 in_stats = (struct sbni_in_stats *)ifr->ifr_data;
1089 bcopy((void *)(&(sc->in_stats)), (void *)in_stats,
1090 sizeof(struct sbni_in_stats));
1091 break;
1093 case SIOCSHWFLAGS: /* set flags */
1094 /* root only */
1095 error = priv_check_cred(cr, PRIV_ROOT, NULL_CRED_OKAY);
1096 /* NOTE: returns EPERM if no proc */
1097 if (error)
1098 break;
1099 flags = *(struct sbni_flags*)&ifr->ifr_data;
1100 if (flags.fixed_rxl) {
1101 sc->delta_rxl = 0;
1102 sc->cur_rxl_index = flags.rxl;
1103 } else {
1104 sc->delta_rxl = DEF_RXL_DELTA;
1105 sc->cur_rxl_index = DEF_RXL;
1107 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
1108 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
1109 if (flags.mac_addr)
1110 bcopy((caddr_t) &flags,
1111 (caddr_t) sc->arpcom.ac_enaddr+3, 3);
1113 /* Don't be afraid... */
1114 sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES);
1115 break;
1117 case SIOCRINSTATS:
1118 if (!(error = priv_check_cred(cr, PRIV_ROOT, NULL_CRED_OKAY))) /* root only */
1119 bzero(&sc->in_stats, sizeof(struct sbni_in_stats));
1120 break;
1122 default:
1123 error = ether_ioctl(ifp, command, data);
1124 break;
1126 return (error);
1129 /* -------------------------------------------------------------------------- */
1131 #ifdef ASM_CRC
1133 static u_int32_t
1134 calc_crc32(u_int32_t crc, caddr_t p, u_int len)
1136 u_int32_t _crc;
1137 _crc = crc;
1139 __asm __volatile (
1140 "xorl %%ebx, %%ebx\n"
1141 "movl %1, %%esi\n"
1142 "movl %2, %%ecx\n"
1143 "movl $crc32tab, %%edi\n"
1144 "shrl $2, %%ecx\n"
1145 "jz 1f\n"
1147 ".align 4\n"
1148 "0:\n"
1149 "movb %%al, %%bl\n"
1150 "movl (%%esi), %%edx\n"
1151 "shrl $8, %%eax\n"
1152 "xorb %%dl, %%bl\n"
1153 "shrl $8, %%edx\n"
1154 "xorl (%%edi,%%ebx,4), %%eax\n"
1156 "movb %%al, %%bl\n"
1157 "shrl $8, %%eax\n"
1158 "xorb %%dl, %%bl\n"
1159 "shrl $8, %%edx\n"
1160 "xorl (%%edi,%%ebx,4), %%eax\n"
1162 "movb %%al, %%bl\n"
1163 "shrl $8, %%eax\n"
1164 "xorb %%dl, %%bl\n"
1165 "movb %%dh, %%dl\n"
1166 "xorl (%%edi,%%ebx,4), %%eax\n"
1168 "movb %%al, %%bl\n"
1169 "shrl $8, %%eax\n"
1170 "xorb %%dl, %%bl\n"
1171 "addl $4, %%esi\n"
1172 "xorl (%%edi,%%ebx,4), %%eax\n"
1174 "decl %%ecx\n"
1175 "jnz 0b\n"
1177 "1:\n"
1178 "movl %2, %%ecx\n"
1179 "andl $3, %%ecx\n"
1180 "jz 2f\n"
1182 "movb %%al, %%bl\n"
1183 "shrl $8, %%eax\n"
1184 "xorb (%%esi), %%bl\n"
1185 "xorl (%%edi,%%ebx,4), %%eax\n"
1187 "decl %%ecx\n"
1188 "jz 2f\n"
1190 "movb %%al, %%bl\n"
1191 "shrl $8, %%eax\n"
1192 "xorb 1(%%esi), %%bl\n"
1193 "xorl (%%edi,%%ebx,4), %%eax\n"
1195 "decl %%ecx\n"
1196 "jz 2f\n"
1198 "movb %%al, %%bl\n"
1199 "shrl $8, %%eax\n"
1200 "xorb 2(%%esi), %%bl\n"
1201 "xorl (%%edi,%%ebx,4), %%eax\n"
1202 "2:\n"
1204 : "a" (_crc), "g" (p), "g" (len)
1205 : "bx", "cx", "dx", "si", "di"
1208 return (_crc);
1211 #else /* ASM_CRC */
1213 static u_int32_t
1214 calc_crc32(u_int32_t crc, caddr_t p, u_int len)
1216 while (len--)
1217 crc = CRC32(*p++, crc);
1219 return (crc);
1222 #endif /* ASM_CRC */
1225 static u_int32_t crc32tab[] __attribute__ ((aligned(8))) = {
1226 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37,
1227 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E,
1228 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605,
1229 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C,
1230 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53,
1231 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A,
1232 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661,
1233 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278,
1234 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF,
1235 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6,
1236 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD,
1237 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4,
1238 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B,
1239 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82,
1240 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9,
1241 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0,
1242 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7,
1243 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE,
1244 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795,
1245 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C,
1246 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3,
1247 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA,
1248 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1,
1249 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8,
1250 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F,
1251 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76,
1252 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D,
1253 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344,
1254 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B,
1255 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12,
1256 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739,
1257 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320,
1258 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17,
1259 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E,
1260 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525,
1261 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C,
1262 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73,
1263 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A,
1264 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541,
1265 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158,
1266 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF,
1267 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6,
1268 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED,
1269 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4,
1270 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB,
1271 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2,
1272 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589,
1273 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190,
1274 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87,
1275 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E,
1276 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5,
1277 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC,
1278 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3,
1279 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA,
1280 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1,
1281 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8,
1282 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F,
1283 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856,
1284 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D,
1285 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064,
1286 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B,
1287 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832,
1288 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419,
1289 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000