if_sbni.c revision 121816
12088Ssos/* 25536Ssos * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved. 32088Ssos * Author: Denis I.Timofeev <timofeev@granch.ru> 42088Ssos * 52088Ssos * Redistributon and use in source and binary forms, with or without 62088Ssos * modification, are permitted provided that the following conditions 72088Ssos * are met: 82088Ssos * 1. Redistributions of source code must retain the above copyright 95994Ssos * notice unmodified, this list of conditions, and the following 105994Ssos * disclaimer. 112088Ssos * 2. Redistributions in binary form must reproduce the above copyright 122088Ssos * notice, this list of conditions and the following disclaimer in the 132088Ssos * documentation and/or other materials provided with the distribution. 142088Ssos * 152088Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 162088Ssos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 172088Ssos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 182088Ssos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 192088Ssos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 202088Ssos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 212088Ssos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 222088Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 232088Ssos * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY 242088Ssos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 252088Ssos * SUCH DAMAGE. 262088Ssos * 272088Ssos */ 282088Ssos 2929603Scharnier#include <sys/cdefs.h> 3029603Scharnier__FBSDID("$FreeBSD: head/sys/dev/sbni/if_sbni.c 121816 2003-10-31 18:32:15Z brooks $"); 3138139Syokota 3229603Scharnier/* 3329603Scharnier * Device driver for Granch SBNI12 leased line adapters 342088Ssos * 3529603Scharnier * Revision 2.0.0 1997/08/06 362088Ssos * Initial revision by Alexey Zverev 3729603Scharnier * 383864Sswallace * Revision 2.0.1 1997/08/11 3929603Scharnier * Additional internal statistics support (tx statistics) 402088Ssos * 412088Ssos * Revision 2.0.2 1997/11/05 422088Ssos * if_bpf bug has been fixed 432088Ssos * 442088Ssos * Revision 2.0.3 1998/12/20 458857Srgrimes * Memory leakage has been eliminated in 462088Ssos * the sbni_st and sbni_timeout routines. 472088Ssos * 4838139Syokota * Revision 3.0 2000/08/10 by Yaroslav Polyakov 492088Ssos * Support for PCI cards. 4.1 modification. 502088Ssos * 5132316Syokota * Revision 3.1 2000/09/12 5232316Syokota * Removed extra #defines around bpf functions 5332316Syokota * 5432316Syokota * Revision 4.0 2000/11/23 by Denis Timofeev 5532316Syokota * Completely redesigned the buffer management 5632316Syokota * 5732316Syokota * Revision 4.1 2001/01/21 5832316Syokota * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards 5932316Syokota * 6032316Syokota * Written with reference to NE2000 driver developed by David Greenman. 6132316Syokota */ 6232316Syokota 635994Ssos 645994Ssos#include <sys/param.h> 655994Ssos#include <sys/systm.h> 665994Ssos#include <sys/socket.h> 675994Ssos#include <sys/sockio.h> 685994Ssos#include <sys/mbuf.h> 695994Ssos#include <sys/kernel.h> 705994Ssos#include <sys/proc.h> 715994Ssos#include <sys/callout.h> 725994Ssos#include <sys/syslog.h> 735994Ssos#include <sys/random.h> 745994Ssos 759202Srgrimes#include <machine/bus.h> 765994Ssos#include <sys/rman.h> 775994Ssos#include <machine/resource.h> 785994Ssos 799202Srgrimes#include <net/if.h> 805994Ssos#include <net/ethernet.h> 815994Ssos#include <net/if_arp.h> 825994Ssos#include <net/bpf.h> 835994Ssos 845994Ssos#include <dev/sbni/if_sbnireg.h> 855994Ssos#include <dev/sbni/if_sbnivar.h> 865994Ssos 875994Ssos#define ASM_CRC 1 882088Ssos 892088Ssosstatic void sbni_init(void *); 902088Ssosstatic void sbni_start(struct ifnet *); 912088Ssosstatic int sbni_ioctl(struct ifnet *, u_long, caddr_t); 922088Ssosstatic void sbni_watchdog(struct ifnet *); 932088Ssosstatic void sbni_stop(struct sbni_softc *); 942088Ssosstatic void handle_channel(struct sbni_softc *); 952088Ssos 962088Ssosstatic void card_start(struct sbni_softc *); 972088Ssosstatic int recv_frame(struct sbni_softc *); 986046Ssosstatic void send_frame(struct sbni_softc *); 992088Ssosstatic int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 10032316Syokotastatic int skip_tail(struct sbni_softc *, u_int, u_int32_t); 1012088Ssosstatic void interpret_ack(struct sbni_softc *, u_int); 10229603Scharnierstatic void download_data(struct sbni_softc *, u_int32_t *); 1032088Ssosstatic void prepare_to_send(struct sbni_softc *); 1042088Ssosstatic void drop_xmit_queue(struct sbni_softc *); 1052088Ssosstatic int get_rx_buf(struct sbni_softc *); 1062088Ssosstatic void indicate_pkt(struct sbni_softc *); 1072088Ssosstatic void change_level(struct sbni_softc *); 1082088Ssosstatic int check_fhdr(struct sbni_softc *, u_int *, u_int *, 10929603Scharnier u_int *, u_int *, u_int32_t *); 1102088Ssosstatic int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 1112088Ssosstatic void timeout_change_level(struct sbni_softc *); 1122088Ssosstatic void send_frame_header(struct sbni_softc *, u_int32_t *); 1132088Ssosstatic void set_initial_values(struct sbni_softc *, struct sbni_flags); 1142088Ssos 1152088Ssosstatic u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 1162088Ssosstatic timeout_t sbni_timeout; 1172088Ssos 1185536Ssosstatic __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 1195536Ssosstatic __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 1205536Ssosstatic __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 1212088Ssosstatic __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 1222088Ssos 1232088Ssosstatic u_int32_t crc32tab[]; 1242088Ssos 1252088Ssos#ifdef SBNI_DUAL_COMPOUND 1262088Ssosstruct sbni_softc *sbni_headlist; 1272088Ssos#endif 1282088Ssos 1292088Ssosu_int32_t next_sbni_unit; 1302088Ssos 1312088Ssos/* -------------------------------------------------------------------------- */ 1322088Ssos 1332088Ssosstatic __inline u_char 1342088Ssossbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 1352088Ssos{ 1362088Ssos return bus_space_read_1( 1372088Ssos rman_get_bustag(sc->io_res), 1382088Ssos rman_get_bushandle(sc->io_res), 1392088Ssos sc->io_off + reg); 1402088Ssos} 1412088Ssos 1422088Ssosstatic __inline void 1432088Ssossbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 14432316Syokota{ 1452088Ssos bus_space_write_1( 1462088Ssos rman_get_bustag(sc->io_res), 1472088Ssos rman_get_bushandle(sc->io_res), 1482088Ssos sc->io_off + reg, value); 1492088Ssos} 1502088Ssos 1512088Ssosstatic __inline void 1522088Ssossbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 1532088Ssos{ 1542088Ssos bus_space_read_multi_1( 1552088Ssos rman_get_bustag(sc->io_res), 1562088Ssos rman_get_bushandle(sc->io_res), 1572088Ssos sc->io_off + DAT, to, len); 1582088Ssos} 1592088Ssos 1602088Ssosstatic __inline void 1612088Ssossbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 1622088Ssos{ 1632088Ssos bus_space_write_multi_1( 1642088Ssos rman_get_bustag(sc->io_res), 1652088Ssos rman_get_bushandle(sc->io_res), 1662088Ssos sc->io_off + DAT, from, len); 1672088Ssos} 1682088Ssos 1692088Ssos 1702088Ssos/* 1712088Ssos Valid combinations in CSR0 (for probing): 1722088Ssos 1732088Ssos VALID_DECODER 0000,0011,1011,1010 1742088Ssos 1752088Ssos ; 0 ; - 1762088Ssos TR_REQ ; 1 ; + 1772088Ssos TR_RDY ; 2 ; - 1782088Ssos TR_RDY TR_REQ ; 3 ; + 1795994Ssos BU_EMP ; 4 ; + 1805994Ssos BU_EMP TR_REQ ; 5 ; + 18138053Syokota BU_EMP TR_RDY ; 6 ; - 18238053Syokota BU_EMP TR_RDY TR_REQ ; 7 ; + 18332316Syokota RC_RDY ; 8 ; + 18432316Syokota RC_RDY TR_REQ ; 9 ; + 18532316Syokota RC_RDY TR_RDY ; 10 ; - 18632316Syokota RC_RDY TR_RDY TR_REQ ; 11 ; - 1872088Ssos RC_RDY BU_EMP ; 12 ; - 1882088Ssos RC_RDY BU_EMP TR_REQ ; 13 ; - 1892088Ssos RC_RDY BU_EMP TR_RDY ; 14 ; - 1902088Ssos RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 1912088Ssos*/ 1922088Ssos 1932088Ssos#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 1942088Ssos 1952088Ssos 1962088Ssosint 1972088Ssossbni_probe(struct sbni_softc *sc) 1982088Ssos{ 1992088Ssos u_char csr0; 2002088Ssos 2012088Ssos csr0 = sbni_inb(sc, CSR0); 2022088Ssos if (csr0 != 0xff && csr0 != 0x00) { 2032088Ssos csr0 &= ~EN_INT; 2042088Ssos if (csr0 & BU_EMP) 2052088Ssos csr0 |= EN_INT; 2062088Ssos 20732316Syokota if (VALID_DECODER & (1 << (csr0 >> 4))) 2082088Ssos return (0); 20932316Syokota } 2102088Ssos 2112088Ssos return (ENXIO); 2122088Ssos} 21332316Syokota 21432316Syokota 21532316Syokota/* 21632316Syokota * Install interface into kernel networking data structures 21732316Syokota */ 21832316Syokotavoid 21932316Syokotasbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 22032316Syokota{ 22132316Syokota struct ifnet *ifp; 22232316Syokota u_char csr0; 22332316Syokota 22432316Syokota ifp = &sc->arpcom.ac_if; 22532316Syokota sbni_outb(sc, CSR0, 0); 22632316Syokota set_initial_values(sc, flags); 22732316Syokota 22832316Syokota callout_handle_init(&sc->wch); 22932316Syokota /* Initialize ifnet structure */ 23032316Syokota ifp->if_softc = sc; 23132316Syokota if_initname(ifp, "sbni", unit); 2322088Ssos ifp->if_init = sbni_init; 23332316Syokota ifp->if_start = sbni_start; 23432316Syokota ifp->if_output = ether_output; 23532316Syokota ifp->if_ioctl = sbni_ioctl; 23632316Syokota ifp->if_watchdog = sbni_watchdog; 23732316Syokota ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 23832316Syokota 23932316Syokota /* report real baud rate */ 24032316Syokota csr0 = sbni_inb(sc, CSR0); 24132316Syokota ifp->if_baudrate = 24232316Syokota (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 24332316Syokota 24432316Syokota ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2452088Ssos ether_ifattach(ifp, sc->arpcom.ac_enaddr); 2462088Ssos /* device attach does transition from UNCONFIGURED to IDLE state */ 2472088Ssos 2482088Ssos if_printf(ifp, "speed %ld, address %6D, rxl ", 2492088Ssos ifp->if_baudrate, sc->arpcom.ac_enaddr, ":"); 2502088Ssos if (sc->delta_rxl) 2512088Ssos printf("auto\n"); 2522088Ssos else 2532088Ssos printf("%d (fixed)\n", sc->cur_rxl_index); 2542088Ssos} 2552088Ssos 2562088Ssos/* -------------------------------------------------------------------------- */ 2572088Ssos 2582088Ssosstatic void 25932316Syokotasbni_init(void *xsc) 2602088Ssos{ 2612088Ssos struct sbni_softc *sc; 26232316Syokota struct ifnet *ifp; 26332316Syokota int s; 2642088Ssos 2652088Ssos sc = (struct sbni_softc *)xsc; 26632316Syokota ifp = &sc->arpcom.ac_if; 26732316Syokota 26832316Syokota /* address not known */ 26932316Syokota if (TAILQ_EMPTY(&ifp->if_addrhead)) 27032316Syokota return; 27132316Syokota 2722088Ssos /* 27332316Syokota * kludge to avoid multiple initialization when more than once 27432316Syokota * protocols configured 27532316Syokota */ 27632316Syokota if (ifp->if_flags & IFF_RUNNING) 27732316Syokota return; 27832316Syokota 27932316Syokota s = splimp(); 28032316Syokota ifp->if_timer = 0; 28132316Syokota card_start(sc); 28232316Syokota sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 28332316Syokota 28432316Syokota ifp->if_flags |= IFF_RUNNING; 28532316Syokota ifp->if_flags &= ~IFF_OACTIVE; 28632316Syokota 28732316Syokota /* attempt to start output */ 28832316Syokota sbni_start(ifp); 28932316Syokota splx(s); 29032316Syokota} 29132316Syokota 29232316Syokota 29332316Syokotastatic void 29432316Syokotasbni_start(struct ifnet *ifp) 29532316Syokota{ 29632316Syokota struct sbni_softc *sc = ifp->if_softc; 29732316Syokota if (sc->tx_frameno == 0) 29832316Syokota prepare_to_send(sc); 29932316Syokota} 30032316Syokota 30132316Syokota 30232316Syokotastatic void 30332316Syokotasbni_stop(struct sbni_softc *sc) 30432316Syokota{ 30532316Syokota sbni_outb(sc, CSR0, 0); 30632316Syokota drop_xmit_queue(sc); 30732316Syokota 30832316Syokota if (sc->rx_buf_p) { 30932316Syokota m_freem(sc->rx_buf_p); 31032316Syokota sc->rx_buf_p = NULL; 31132316Syokota } 31232316Syokota 31332316Syokota untimeout(sbni_timeout, sc, sc->wch); 31432316Syokota sc->wch.callout = NULL; 31532316Syokota} 31632316Syokota 31732316Syokota/* -------------------------------------------------------------------------- */ 31832316Syokota 31932316Syokota/* interrupt handler */ 32032316Syokota 32132316Syokota/* 32232316Syokota * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 32332316Syokota * be looked as two independent single-channel devices. Every channel seems 32432316Syokota * as Ethernet interface but interrupt handler must be common. Really, first 32532316Syokota * channel ("master") driver only registers the handler. In it's struct softc 32632316Syokota * it has got pointer to "slave" channel's struct softc and handles that's 32729603Scharnier * interrupts too. 3282088Ssos * softc of successfully attached ISA SBNI boards is linked to list. 3292088Ssos * While next board driver is initialized, it scans this list. If one 3302088Ssos * has found softc with same irq and ioaddr different by 4 then it assumes 3312088Ssos * this board to be "master". 3322088Ssos */ 3332088Ssos 3348857Srgrimesvoid 3352088Ssossbni_intr(void *arg) 3362088Ssos{ 3372088Ssos struct sbni_softc *sc; 3382088Ssos int repeat; 3392088Ssos 3402088Ssos sc = (struct sbni_softc *)arg; 3412088Ssos 3422088Ssos do { 3432088Ssos repeat = 0; 3442088Ssos if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 3452088Ssos handle_channel(sc); 3462088Ssos repeat = 1; 3472088Ssos } 3482088Ssos if (sc->slave_sc && /* second channel present */ 3492088Ssos (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) { 3502088Ssos handle_channel(sc->slave_sc); 3512088Ssos repeat = 1; 3522088Ssos } 3532088Ssos } while (repeat); 3542088Ssos} 3552088Ssos 3562088Ssos 3572088Ssosstatic void 3582088Ssoshandle_channel(struct sbni_softc *sc) 3592088Ssos{ 3602088Ssos int req_ans; 3612088Ssos u_char csr0; 3622088Ssos 3632088Ssos sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 3642088Ssos 3652088Ssos sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 3662088Ssos for (;;) { 3672088Ssos csr0 = sbni_inb(sc, CSR0); 3682088Ssos if ((csr0 & (RC_RDY | TR_RDY)) == 0) 3692088Ssos break; 3702088Ssos 3712088Ssos req_ans = !(sc->state & FL_PREV_OK); 3722088Ssos 3732088Ssos if (csr0 & RC_RDY) 3742088Ssos req_ans = recv_frame(sc); 3752088Ssos 3762088Ssos /* 3772088Ssos * TR_RDY always equals 1 here because we have owned the marker, 3782088Ssos * and we set TR_REQ when disabled interrupts 3792088Ssos */ 3802088Ssos csr0 = sbni_inb(sc, CSR0); 3812088Ssos if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 3822088Ssos printf("sbni: internal error!\n"); 3832088Ssos 38432316Syokota /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 38532316Syokota if (req_ans || sc->tx_frameno != 0) 38632316Syokota send_frame(sc); 38738053Syokota else { 38838053Syokota /* send the marker without any data */ 38938053Syokota sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 3902088Ssos } 3912088Ssos } 3928857Srgrimes 3932088Ssos sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 3948857Srgrimes} 3952088Ssos 39632316Syokota 39732316Syokota/* 3982088Ssos * Routine returns 1 if it need to acknoweledge received frame. 3998857Srgrimes * Empty frame received without errors won't be acknoweledged. 4002088Ssos */ 40132316Syokota 4022088Ssosstatic int 4032088Ssosrecv_frame(struct sbni_softc *sc) 4042088Ssos{ 4058857Srgrimes u_int32_t crc; 4062088Ssos u_int framelen, frameno, ack; 4078857Srgrimes u_int is_first, frame_ok; 4089202Srgrimes 4098857Srgrimes crc = CRC32_INITIAL; 4102088Ssos if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 4118857Srgrimes frame_ok = framelen > 4 ? 4122088Ssos upload_data(sc, framelen, frameno, is_first, crc) : 4138857Srgrimes skip_tail(sc, framelen, crc); 4142088Ssos if (frame_ok) 4152088Ssos interpret_ack(sc, ack); 4162088Ssos } else 4172088Ssos frame_ok = 0; 4182088Ssos 4192088Ssos sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 4202088Ssos if (frame_ok) { 4212088Ssos sc->state |= FL_PREV_OK; 42229603Scharnier if (framelen > 4) 4232088Ssos sc->in_stats.all_rx_number++; 4242088Ssos } else { 4252088Ssos sc->state &= ~FL_PREV_OK; 4262088Ssos change_level(sc); 4272088Ssos sc->in_stats.all_rx_number++; 4282088Ssos sc->in_stats.bad_rx_number++; 4292088Ssos } 4302088Ssos 4312088Ssos return (!frame_ok || framelen > 4); 4322088Ssos} 4332088Ssos 4342088Ssos 4358857Srgrimesstatic void 4362088Ssossend_frame(struct sbni_softc *sc) 4372088Ssos{ 4382088Ssos u_int32_t crc; 4392088Ssos u_char csr0; 4402088Ssos 4412088Ssos crc = CRC32_INITIAL; 4422088Ssos if (sc->state & FL_NEED_RESEND) { 4432088Ssos 4442088Ssos /* if frame was sended but not ACK'ed - resend it */ 4452088Ssos if (sc->trans_errors) { 4462088Ssos sc->trans_errors--; 4472088Ssos if (sc->framelen != 0) 4482088Ssos sc->in_stats.resend_tx_number++; 4496046Ssos } else { 4506046Ssos /* cannot xmit with many attempts */ 4516046Ssos drop_xmit_queue(sc); 4528857Srgrimes goto do_send; 4532088Ssos } 4542088Ssos } else 45532316Syokota sc->trans_errors = TR_ERROR_COUNT; 45632316Syokota 45732316Syokota send_frame_header(sc, &crc); 45832316Syokota sc->state |= FL_NEED_RESEND; 45932316Syokota /* 4602088Ssos * FL_NEED_RESEND will be cleared after ACK, but if empty 46132316Syokota * frame sended then in prepare_to_send next frame 46232316Syokota */ 46332316Syokota 46432316Syokota 46532316Syokota if (sc->framelen) { 46632316Syokota download_data(sc, &crc); 46732316Syokota sc->in_stats.all_tx_number++; 46832316Syokota sc->state |= FL_WAIT_ACK; 46932316Syokota } 47032316Syokota 47132316Syokota sbni_outsb(sc, (u_char *)&crc, sizeof crc); 47232316Syokota 47332316Syokotado_send: 47432316Syokota csr0 = sbni_inb(sc, CSR0); 47532316Syokota sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 47632316Syokota 47732316Syokota if (sc->tx_frameno) { 47832316Syokota /* next frame exists - request to send */ 47932316Syokota sbni_outb(sc, CSR0, csr0 | TR_REQ); 48032316Syokota } 48132316Syokota} 48232316Syokota 48332316Syokota 48432316Syokotastatic void 48532316Syokotadownload_data(struct sbni_softc *sc, u_int32_t *crc_p) 48632316Syokota{ 48732316Syokota struct mbuf *m; 48832316Syokota caddr_t data_p; 48932316Syokota u_int data_len, pos, slice; 49032316Syokota 49132316Syokota data_p = NULL; /* initialized to avoid warn */ 49232316Syokota pos = 0; 49332316Syokota 49432316Syokota for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 49532316Syokota if (pos + m->m_len > sc->outpos) { 4962088Ssos data_len = m->m_len - (sc->outpos - pos); 49732316Syokota data_p = mtod(m, caddr_t) + (sc->outpos - pos); 49832316Syokota 49932316Syokota goto do_copy; 50032316Syokota } else 50132316Syokota pos += m->m_len; 50232316Syokota } 50332316Syokota 50432316Syokota data_len = 0; 50532316Syokota 50632316Syokotado_copy: 50732316Syokota pos = 0; 50832316Syokota do { 50932316Syokota if (data_len) { 51032316Syokota slice = min(data_len, sc->framelen - pos); 51132316Syokota sbni_outsb(sc, data_p, slice); 51232316Syokota *crc_p = calc_crc32(*crc_p, data_p, slice); 51332316Syokota 51432316Syokota pos += slice; 51532316Syokota if (data_len -= slice) 51632316Syokota data_p += slice; 51732316Syokota else { 51832316Syokota do { 51932316Syokota m = m->m_next; 52032316Syokota } while (m != NULL && m->m_len == 0); 52132316Syokota 52232316Syokota if (m) { 52332316Syokota data_len = m->m_len; 52432316Syokota data_p = mtod(m, caddr_t); 52532316Syokota } 52632316Syokota } 52732316Syokota } else { 52832316Syokota /* frame too short - zero padding */ 52932316Syokota 53032316Syokota pos = sc->framelen - pos; 53132316Syokota while (pos--) { 53232316Syokota sbni_outb(sc, DAT, 0); 53332316Syokota *crc_p = CRC32(0, *crc_p); 53432316Syokota } 53532316Syokota return; 53632316Syokota } 53732316Syokota } while (pos < sc->framelen); 53832316Syokota} 53932316Syokota 54032316Syokota 54132316Syokotastatic int 54232316Syokotaupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 54332316Syokota u_int is_first, u_int32_t crc) 54432316Syokota{ 54532316Syokota int frame_ok; 54632316Syokota 54732316Syokota if (is_first) { 54832316Syokota sc->wait_frameno = frameno; 54932316Syokota sc->inppos = 0; 55032316Syokota } 55132316Syokota 55232316Syokota if (sc->wait_frameno == frameno) { 55332316Syokota 55432316Syokota if (sc->inppos + framelen <= ETHER_MAX_LEN) { 55532316Syokota frame_ok = append_frame_to_pkt(sc, framelen, crc); 55638053Syokota 55738053Syokota /* 55838053Syokota * if CRC is right but framelen incorrect then transmitter 55932316Syokota * error was occured... drop entire packet 56032316Syokota */ 56132316Syokota } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 56232316Syokota sc->wait_frameno = 0; 56332486Syokota sc->inppos = 0; 56432316Syokota sc->arpcom.ac_if.if_ierrors++; 56532316Syokota /* now skip all frames until is_first != 0 */ 56632316Syokota } 56732316Syokota } else 56832316Syokota frame_ok = skip_tail(sc, framelen, crc); 56932316Syokota 57032316Syokota if (is_first && !frame_ok) { 57132316Syokota /* 57232316Syokota * Frame has been violated, but we have stored 57332316Syokota * is_first already... Drop entire packet. 57432316Syokota */ 57532316Syokota sc->wait_frameno = 0; 57632316Syokota sc->arpcom.ac_if.if_ierrors++; 57732316Syokota } 57832316Syokota 57932316Syokota return (frame_ok); 58032316Syokota} 58132316Syokota 58232316Syokota 58332316Syokotastatic __inline void send_complete(struct sbni_softc *); 58432316Syokota 58532316Syokotastatic __inline void 58632486Syokotasend_complete(struct sbni_softc *sc) 58732316Syokota{ 58832316Syokota m_freem(sc->tx_buf_p); 58932486Syokota sc->tx_buf_p = NULL; 59032486Syokota sc->arpcom.ac_if.if_opackets++; 59132486Syokota} 59232316Syokota 59332316Syokota 59432316Syokotastatic void 59532486Syokotainterpret_ack(struct sbni_softc *sc, u_int ack) 59632316Syokota{ 59732316Syokota if (ack == FRAME_SENT_OK) { 59832316Syokota sc->state &= ~FL_NEED_RESEND; 59932316Syokota 60032316Syokota if (sc->state & FL_WAIT_ACK) { 60132316Syokota sc->outpos += sc->framelen; 60232486Syokota 60332316Syokota if (--sc->tx_frameno) { 60432316Syokota sc->framelen = min( 60532316Syokota sc->maxframe, sc->pktlen - sc->outpos); 60632486Syokota } else { 60732316Syokota send_complete(sc); 60832316Syokota prepare_to_send(sc); 60932316Syokota } 61032316Syokota } 61132316Syokota } 61232316Syokota 61332316Syokota sc->state &= ~FL_WAIT_ACK; 61432316Syokota} 61532486Syokota 61632316Syokota 61732486Syokota/* 61832486Syokota * Glue received frame with previous fragments of packet. 61932486Syokota * Indicate packet when last frame would be accepted. 62032486Syokota */ 62132486Syokota 62232316Syokotastatic int 62332316Syokotaappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 62432316Syokota{ 62532316Syokota caddr_t p; 62632316Syokota 62732316Syokota if (sc->inppos + framelen > ETHER_MAX_LEN) 62832316Syokota return (0); 62932316Syokota 63032316Syokota if (!sc->rx_buf_p && !get_rx_buf(sc)) 63132316Syokota return (0); 63232316Syokota 63332316Syokota p = sc->rx_buf_p->m_data + sc->inppos; 63432316Syokota sbni_insb(sc, p, framelen); 63532316Syokota if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 63632316Syokota return (0); 63732316Syokota 63832316Syokota sc->inppos += framelen - 4; 63932316Syokota if (--sc->wait_frameno == 0) { /* last frame received */ 64032316Syokota indicate_pkt(sc); 64132316Syokota sc->arpcom.ac_if.if_ipackets++; 64232316Syokota } 64332316Syokota 64432316Syokota return (1); 64532316Syokota} 64632316Syokota 64732316Syokota 64832316Syokota/* 64932316Syokota * Prepare to start output on adapter. Current priority must be set to splimp 65032486Syokota * before this routine is called. 65132316Syokota * Transmitter will be actually activated when marker has been accepted. 65232316Syokota */ 65332316Syokota 65419569Sjoergstatic void 6552088Ssosprepare_to_send(struct sbni_softc *sc) 65632316Syokota{ 65732316Syokota struct mbuf *m; 6582088Ssos u_int len; 65932316Syokota 66019569Sjoerg /* sc->tx_buf_p == NULL here! */ 66135750Sdes if (sc->tx_buf_p) 66235750Sdes printf("sbni: memory leak!\n"); 6632088Ssos 6642088Ssos sc->outpos = 0; 6652088Ssos sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 66629603Scharnier 6672088Ssos for (;;) { 6682088Ssos IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, sc->tx_buf_p); 6692088Ssos if (!sc->tx_buf_p) { 67029603Scharnier /* nothing to transmit... */ 6712088Ssos sc->pktlen = 0; 6722088Ssos sc->tx_frameno = 0; 67332316Syokota sc->framelen = 0; 67432316Syokota sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 67532316Syokota return; 6762088Ssos } 67732316Syokota 6782088Ssos for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 6792088Ssos len += m->m_len; 68019569Sjoerg 68119569Sjoerg if (len != 0) 68219569Sjoerg break; 68319569Sjoerg m_freem(sc->tx_buf_p); 68432316Syokota } 68532316Syokota 68632316Syokota if (len < SBNI_MIN_LEN) 68732316Syokota len = SBNI_MIN_LEN; 68832316Syokota 68932316Syokota sc->pktlen = len; 69019569Sjoerg sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe; 69119569Sjoerg sc->framelen = min(len, sc->maxframe); 69232316Syokota 69329603Scharnier sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 6942088Ssos sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; 6952088Ssos BPF_MTAP(&sc->arpcom.ac_if, sc->tx_buf_p); 6962088Ssos} 69732316Syokota 69832316Syokota 69932316Syokotastatic void 70032316Syokotadrop_xmit_queue(struct sbni_softc *sc) 70132316Syokota{ 70232316Syokota struct mbuf *m; 7032088Ssos 7042088Ssos if (sc->tx_buf_p) { 7052088Ssos m_freem(sc->tx_buf_p); 7062088Ssos sc->tx_buf_p = NULL; 7072088Ssos sc->arpcom.ac_if.if_oerrors++; 70832316Syokota } 70932316Syokota 7102088Ssos for (;;) { 7112088Ssos IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 71232316Syokota if (m == NULL) 71329603Scharnier break; 71432316Syokota m_freem(m); 71532316Syokota sc->arpcom.ac_if.if_oerrors++; 7162088Ssos } 7172088Ssos 7182088Ssos sc->tx_frameno = 0; 7192088Ssos sc->framelen = 0; 7202088Ssos sc->outpos = 0; 7212088Ssos sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 72232316Syokota sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 72332316Syokota} 72432316Syokota 72532316Syokota 72632316Syokotastatic void 72732316Syokotasend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 72832316Syokota{ 7292088Ssos u_int32_t crc; 7302088Ssos u_int len_field; 7312088Ssos u_char value; 7322088Ssos 7332088Ssos crc = *crc_p; 7342088Ssos len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 7352088Ssos 7362088Ssos if (sc->state & FL_NEED_RESEND) 7372088Ssos len_field |= FRAME_RETRY; /* non-first attempt... */ 7382088Ssos 7392088Ssos if (sc->outpos == 0) 7402088Ssos len_field |= FRAME_FIRST; 7412088Ssos 7422088Ssos len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 74329603Scharnier sbni_outb(sc, DAT, SBNI_SIG); 7442088Ssos 7452088Ssos value = (u_char)len_field; 7462088Ssos sbni_outb(sc, DAT, value); 7472088Ssos crc = CRC32(value, crc); 7482088Ssos value = (u_char)(len_field >> 8); 7492088Ssos sbni_outb(sc, DAT, value); 7502088Ssos crc = CRC32(value, crc); 7512088Ssos 7522088Ssos sbni_outb(sc, DAT, sc->tx_frameno); 7532088Ssos crc = CRC32(sc->tx_frameno, crc); 7542088Ssos sbni_outb(sc, DAT, 0); 7552088Ssos crc = CRC32(0, crc); 7562088Ssos *crc_p = crc; 7572088Ssos} 75829603Scharnier 7592088Ssos 7602088Ssos/* 7612088Ssos * if frame tail not needed (incorrect number or received twice), 7622088Ssos * it won't store, but CRC will be calculated 76329603Scharnier */ 7642088Ssos 7652088Ssosstatic int 7662088Ssosskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 7672088Ssos{ 7682088Ssos while (tail_len--) 7692088Ssos crc = CRC32(sbni_inb(sc, DAT), crc); 77029603Scharnier 7712088Ssos return (crc == CRC32_REMAINDER); 7722088Ssos} 7732088Ssos 7742088Ssos 7752088Ssosstatic int 7762088Ssoscheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 7775536Ssos u_int *ack, u_int *is_first, u_int32_t *crc_p) 7782088Ssos{ 77938044Syokota u_int32_t crc; 78038044Syokota u_char value; 78138044Syokota 78238044Syokota crc = *crc_p; 78338044Syokota if (sbni_inb(sc, DAT) != SBNI_SIG) 7848857Srgrimes return (0); 78538044Syokota 7865536Ssos value = sbni_inb(sc, DAT); 78738044Syokota *framelen = (u_int)value; 7882088Ssos crc = CRC32(value, crc); 7892088Ssos value = sbni_inb(sc, DAT); 7908857Srgrimes *framelen |= ((u_int)value) << 8; 7915536Ssos crc = CRC32(value, crc); 7922088Ssos 7932088Ssos *ack = *framelen & FRAME_ACK_MASK; 7942088Ssos *is_first = (*framelen & FRAME_FIRST) != 0; 7952088Ssos 7962088Ssos if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 7972088Ssos return (0); 7982088Ssos 79929603Scharnier value = sbni_inb(sc, DAT); 8002088Ssos *frameno = (u_int)value; 8012088Ssos crc = CRC32(value, crc); 80238044Syokota 80338044Syokota crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 80438044Syokota *framelen -= 2; 8052088Ssos 8062088Ssos *crc_p = crc; 8075536Ssos return (1); 80838044Syokota} 8095536Ssos 8102088Ssos 8112088Ssosstatic int 8122088Ssosget_rx_buf(struct sbni_softc *sc) 8132088Ssos{ 8142088Ssos struct mbuf *m; 8152088Ssos 8162088Ssos MGETHDR(m, M_DONTWAIT, MT_DATA); 8172088Ssos if (m == NULL) { 8182088Ssos if_printf(&sc->arpcom.ac_if, "cannot allocate header mbuf\n"); 8192088Ssos return (0); 8202088Ssos } 8212088Ssos 8222088Ssos /* 8232088Ssos * We always put the received packet in a single buffer - 8242088Ssos * either with just an mbuf header or in a cluster attached 8252088Ssos * to the header. The +2 is to compensate for the alignment 8262088Ssos * fixup below. 8272088Ssos */ 8282088Ssos if (ETHER_MAX_LEN + 2 > MHLEN) { 8292088Ssos /* Attach an mbuf cluster */ 8302088Ssos MCLGET(m, M_DONTWAIT); 8312088Ssos if ((m->m_flags & M_EXT) == 0) { 8322088Ssos m_freem(m); 8332088Ssos return (0); 8342088Ssos } 8352088Ssos } 8362088Ssos m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 8372088Ssos 8382088Ssos /* 8392088Ssos * The +2 is to longword align the start of the real packet. 84029603Scharnier * (sizeof ether_header == 14) 8412088Ssos * This is important for NFS. 8422088Ssos */ 8432088Ssos m_adj(m, 2); 8442088Ssos sc->rx_buf_p = m; 8452088Ssos return (1); 8462088Ssos} 8472088Ssos 8482088Ssos 8492088Ssosstatic void 8502088Ssosindicate_pkt(struct sbni_softc *sc) 8512088Ssos{ 8522088Ssos struct ifnet *ifp = &sc->arpcom.ac_if; 8532088Ssos struct mbuf *m; 85429603Scharnier 8552088Ssos m = sc->rx_buf_p; 8562088Ssos m->m_pkthdr.rcvif = ifp; 8572088Ssos m->m_pkthdr.len = m->m_len = sc->inppos; 8586046Ssos 8596046Ssos (*ifp->if_input)(ifp, m); 8606046Ssos sc->rx_buf_p = NULL; 8616046Ssos} 8626046Ssos 8636046Ssos/* -------------------------------------------------------------------------- */ 8646046Ssos 86529603Scharnier/* 8666046Ssos * Routine checks periodically wire activity and regenerates marker if 8676046Ssos * connect was inactive for a long time. 8686046Ssos */ 86929603Scharnier 8706046Ssosstatic void 8716046Ssossbni_timeout(void *xsc) 8726046Ssos{ 87329603Scharnier struct sbni_softc *sc; 8742088Ssos int s; 8752088Ssos u_char csr0; 87629603Scharnier 87738044Syokota sc = (struct sbni_softc *)xsc; 87829603Scharnier s = splimp(); 87929603Scharnier 88029603Scharnier csr0 = sbni_inb(sc, CSR0); 8812088Ssos if (csr0 & RC_CHK) { 8822088Ssos 8832088Ssos if (sc->timer_ticks) { 8842088Ssos if (csr0 & (RC_RDY | BU_EMP)) 8852088Ssos /* receiving not active */ 8862088Ssos sc->timer_ticks--; 8872088Ssos } else { 8882088Ssos sc->in_stats.timeout_number++; 88919569Sjoerg if (sc->delta_rxl) 8902088Ssos timeout_change_level(sc); 8912088Ssos 8922088Ssos sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 8932088Ssos csr0 = sbni_inb(sc, CSR0); 8942088Ssos } 8952088Ssos } 8962088Ssos 8972088Ssos sbni_outb(sc, CSR0, csr0 | RC_CHK); 89819569Sjoerg sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 8992088Ssos splx(s); 90019569Sjoerg} 90119569Sjoerg 90219569Sjoerg/* -------------------------------------------------------------------------- */ 9032088Ssos 9048857Srgrimesstatic void 9052088Ssoscard_start(struct sbni_softc *sc) 9062088Ssos{ 9072088Ssos sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 9082088Ssos sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 9092088Ssos sc->state |= FL_PREV_OK; 9106046Ssos 9116046Ssos sc->inppos = 0; 9126046Ssos sc->wait_frameno = 0; 9132088Ssos 9142088Ssos sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 9152088Ssos sbni_outb(sc, CSR0, EN_INT); 9162088Ssos} 9172088Ssos 9182088Ssos/* -------------------------------------------------------------------------- */ 9192088Ssos 9202088Ssos/* 9212088Ssos * Device timeout/watchdog routine. Entered if the device neglects to 92229603Scharnier * generate an interrupt after a transmit has been started on it. 9232088Ssos */ 9242088Ssos 9252088Ssosstatic void 9262088Ssossbni_watchdog(struct ifnet *ifp) 9272088Ssos{ 928 log(LOG_ERR, "%s: device timeout\n", ifp->if_xname); 929 ifp->if_oerrors++; 930} 931 932 933static u_char rxl_tab[] = { 934 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 935 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 936}; 937 938#define SIZE_OF_TIMEOUT_RXL_TAB 4 939static u_char timeout_rxl_tab[] = { 940 0x03, 0x05, 0x08, 0x0b 941}; 942 943static void 944set_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 945{ 946 if (flags.fixed_rxl) { 947 sc->delta_rxl = 0; /* disable receive level autodetection */ 948 sc->cur_rxl_index = flags.rxl; 949 } else { 950 sc->delta_rxl = DEF_RXL_DELTA; 951 sc->cur_rxl_index = DEF_RXL; 952 } 953 954 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 955 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 956 sc->maxframe = DEFAULT_FRAME_LEN; 957 958 /* 959 * generate Ethernet address (0x00ff01xxxxxx) 960 */ 961 *(u_int16_t *) sc->arpcom.ac_enaddr = htons(0x00ff); 962 if (flags.mac_addr) { 963 *(u_int32_t *) (sc->arpcom.ac_enaddr + 2) = 964 htonl(flags.mac_addr | 0x01000000); 965 } else { 966 *(u_char *) (sc->arpcom.ac_enaddr + 2) = 0x01; 967 read_random(sc->arpcom.ac_enaddr + 3, 3); 968 } 969} 970 971 972#ifdef SBNI_DUAL_COMPOUND 973 974struct sbni_softc * 975connect_to_master(struct sbni_softc *sc) 976{ 977 struct sbni_softc *p, *p_prev; 978 979 for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { 980 if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || 981 rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { 982 p->slave_sc = sc; 983 if (p_prev) 984 p_prev->link = p->link; 985 else 986 sbni_headlist = p->link; 987 return p; 988 } 989 } 990 991 return (NULL); 992} 993 994#endif /* SBNI_DUAL_COMPOUND */ 995 996 997/* Receive level auto-selection */ 998 999static void 1000change_level(struct sbni_softc *sc) 1001{ 1002 if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 1003 return; 1004 1005 if (sc->cur_rxl_index == 0) 1006 sc->delta_rxl = 1; 1007 else if (sc->cur_rxl_index == 15) 1008 sc->delta_rxl = -1; 1009 else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 1010 sc->delta_rxl = -sc->delta_rxl; 1011 1012 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 1013 sbni_inb(sc, CSR0); /* it needed for PCI cards */ 1014 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1015 1016 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1017 sc->cur_rxl_rcvd = 0; 1018} 1019 1020 1021static void 1022timeout_change_level(struct sbni_softc *sc) 1023{ 1024 sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 1025 if (++sc->timeout_rxl >= 4) 1026 sc->timeout_rxl = 0; 1027 1028 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1029 sbni_inb(sc, CSR0); 1030 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1031 1032 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1033 sc->cur_rxl_rcvd = 0; 1034} 1035 1036/* -------------------------------------------------------------------------- */ 1037 1038/* 1039 * Process an ioctl request. This code needs some work - it looks 1040 * pretty ugly. 1041 */ 1042 1043static int 1044sbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1045{ 1046 struct sbni_softc *sc; 1047 struct ifreq *ifr; 1048 struct thread *td; 1049 struct sbni_in_stats *in_stats; 1050 struct sbni_flags flags; 1051 int error, s; 1052 1053 sc = ifp->if_softc; 1054 ifr = (struct ifreq *)data; 1055 td = curthread; 1056 error = 0; 1057 1058 s = splimp(); 1059 1060 switch (command) { 1061 case SIOCSIFFLAGS: 1062 /* 1063 * If the interface is marked up and stopped, then start it. 1064 * If it is marked down and running, then stop it. 1065 */ 1066 if (ifp->if_flags & IFF_UP) { 1067 if (!(ifp->if_flags & IFF_RUNNING)) 1068 sbni_init(sc); 1069 } else { 1070 if (ifp->if_flags & IFF_RUNNING) { 1071 sbni_stop(sc); 1072 ifp->if_flags &= ~IFF_RUNNING; 1073 } 1074 } 1075 break; 1076 1077 case SIOCADDMULTI: 1078 case SIOCDELMULTI: 1079 /* 1080 * Multicast list has changed; set the hardware filter 1081 * accordingly. 1082 */ 1083 error = 0; 1084 /* if (ifr == NULL) 1085 error = EAFNOSUPPORT; */ 1086 break; 1087 1088 case SIOCSIFMTU: 1089 if (ifr->ifr_mtu > ETHERMTU) 1090 error = EINVAL; 1091 else 1092 ifp->if_mtu = ifr->ifr_mtu; 1093 break; 1094 1095 /* 1096 * SBNI specific ioctl 1097 */ 1098 case SIOCGHWFLAGS: /* get flags */ 1099 bcopy((caddr_t) sc->arpcom.ac_enaddr+3, (caddr_t) &flags, 3); 1100 flags.rxl = sc->cur_rxl_index; 1101 flags.rate = sc->csr1.rate; 1102 flags.fixed_rxl = (sc->delta_rxl == 0); 1103 flags.fixed_rate = 1; 1104 ifr->ifr_data = *(caddr_t*) &flags; 1105 break; 1106 1107 case SIOCGINSTATS: 1108 in_stats = (struct sbni_in_stats *)ifr->ifr_data; 1109 bcopy((void *)(&(sc->in_stats)), (void *)in_stats, 1110 sizeof(struct sbni_in_stats)); 1111 break; 1112 1113 case SIOCSHWFLAGS: /* set flags */ 1114 /* root only */ 1115 error = suser(td); 1116 if (error) 1117 break; 1118 flags = *(struct sbni_flags*)&ifr->ifr_data; 1119 if (flags.fixed_rxl) { 1120 sc->delta_rxl = 0; 1121 sc->cur_rxl_index = flags.rxl; 1122 } else { 1123 sc->delta_rxl = DEF_RXL_DELTA; 1124 sc->cur_rxl_index = DEF_RXL; 1125 } 1126 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1127 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 1128 if (flags.mac_addr) 1129 bcopy((caddr_t) &flags, 1130 (caddr_t) sc->arpcom.ac_enaddr+3, 3); 1131 1132 /* Don't be afraid... */ 1133 sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 1134 break; 1135 1136 case SIOCRINSTATS: 1137 if (!(error = suser(td))) /* root only */ 1138 bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 1139 break; 1140 1141 default: 1142 error = ether_ioctl(ifp, command, data); 1143 break; 1144 } 1145 1146 splx(s); 1147 return (error); 1148} 1149 1150/* -------------------------------------------------------------------------- */ 1151 1152#ifdef ASM_CRC 1153 1154static u_int32_t 1155calc_crc32(u_int32_t crc, caddr_t p, u_int len) 1156{ 1157 register u_int32_t _crc __asm ("ax"); 1158 _crc = crc; 1159 1160 __asm __volatile ( 1161 "xorl %%ebx, %%ebx\n" 1162 "movl %1, %%esi\n" 1163 "movl %2, %%ecx\n" 1164 "movl $crc32tab, %%edi\n" 1165 "shrl $2, %%ecx\n" 1166 "jz 1f\n" 1167 1168 ".align 4\n" 1169 "0:\n" 1170 "movb %%al, %%bl\n" 1171 "movl (%%esi), %%edx\n" 1172 "shrl $8, %%eax\n" 1173 "xorb %%dl, %%bl\n" 1174 "shrl $8, %%edx\n" 1175 "xorl (%%edi,%%ebx,4), %%eax\n" 1176 1177 "movb %%al, %%bl\n" 1178 "shrl $8, %%eax\n" 1179 "xorb %%dl, %%bl\n" 1180 "shrl $8, %%edx\n" 1181 "xorl (%%edi,%%ebx,4), %%eax\n" 1182 1183 "movb %%al, %%bl\n" 1184 "shrl $8, %%eax\n" 1185 "xorb %%dl, %%bl\n" 1186 "movb %%dh, %%dl\n" 1187 "xorl (%%edi,%%ebx,4), %%eax\n" 1188 1189 "movb %%al, %%bl\n" 1190 "shrl $8, %%eax\n" 1191 "xorb %%dl, %%bl\n" 1192 "addl $4, %%esi\n" 1193 "xorl (%%edi,%%ebx,4), %%eax\n" 1194 1195 "decl %%ecx\n" 1196 "jnz 0b\n" 1197 1198 "1:\n" 1199 "movl %2, %%ecx\n" 1200 "andl $3, %%ecx\n" 1201 "jz 2f\n" 1202 1203 "movb %%al, %%bl\n" 1204 "shrl $8, %%eax\n" 1205 "xorb (%%esi), %%bl\n" 1206 "xorl (%%edi,%%ebx,4), %%eax\n" 1207 1208 "decl %%ecx\n" 1209 "jz 2f\n" 1210 1211 "movb %%al, %%bl\n" 1212 "shrl $8, %%eax\n" 1213 "xorb 1(%%esi), %%bl\n" 1214 "xorl (%%edi,%%ebx,4), %%eax\n" 1215 1216 "decl %%ecx\n" 1217 "jz 2f\n" 1218 1219 "movb %%al, %%bl\n" 1220 "shrl $8, %%eax\n" 1221 "xorb 2(%%esi), %%bl\n" 1222 "xorl (%%edi,%%ebx,4), %%eax\n" 1223 "2:\n" 1224 : "=a" (_crc) 1225 : "g" (p), "g" (len) 1226 : "bx", "cx", "dx", "si", "di" 1227 ); 1228 1229 return (_crc); 1230} 1231 1232#else /* ASM_CRC */ 1233 1234static u_int32_t 1235calc_crc32(u_int32_t crc, caddr_t p, u_int len) 1236{ 1237 while (len--) 1238 crc = CRC32(*p++, crc); 1239 1240 return (crc); 1241} 1242 1243#endif /* ASM_CRC */ 1244 1245 1246static u_int32_t crc32tab[] __aligned(8) = { 1247 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 1248 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 1249 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 1250 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 1251 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 1252 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 1253 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 1254 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 1255 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 1256 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 1257 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 1258 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 1259 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 1260 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 1261 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 1262 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 1263 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 1264 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 1265 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 1266 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 1267 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 1268 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 1269 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 1270 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 1271 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 1272 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 1273 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 1274 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 1275 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 1276 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 1277 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 1278 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 1279 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 1280 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 1281 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 1282 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 1283 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 1284 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 1285 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 1286 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 1287 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 1288 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 1289 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 1290 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 1291 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 1292 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 1293 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 1294 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 1295 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 1296 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 1297 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 1298 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 1299 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 1300 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 1301 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 1302 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 1303 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 1304 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 1305 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 1306 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 1307 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 1308 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 1309 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 1310 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 1311}; 1312