if_sbni.c revision 106937
186752Sfjoe/* 286752Sfjoe * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved. 386752Sfjoe * Author: Denis I.Timofeev <timofeev@granch.ru> 486752Sfjoe * 586752Sfjoe * Redistributon and use in source and binary forms, with or without 686752Sfjoe * modification, are permitted provided that the following conditions 786752Sfjoe * are met: 886752Sfjoe * 1. Redistributions of source code must retain the above copyright 986752Sfjoe * notice unmodified, this list of conditions, and the following 1086752Sfjoe * disclaimer. 1186752Sfjoe * 2. Redistributions in binary form must reproduce the above copyright 1286752Sfjoe * notice, this list of conditions and the following disclaimer in the 1386752Sfjoe * documentation and/or other materials provided with the distribution. 1486752Sfjoe * 1586752Sfjoe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1686752Sfjoe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1786752Sfjoe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1886752Sfjoe * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1986752Sfjoe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2086752Sfjoe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2186752Sfjoe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2286752Sfjoe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2386752Sfjoe * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY 2486752Sfjoe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2586752Sfjoe * SUCH DAMAGE. 2686752Sfjoe * 2786752Sfjoe * $FreeBSD: head/sys/dev/sbni/if_sbni.c 106937 2002-11-14 23:54:55Z sam $ 2886752Sfjoe */ 2986752Sfjoe 3086752Sfjoe/* 3186752Sfjoe * Device driver for Granch SBNI12 leased line adapters 3286752Sfjoe * 3386752Sfjoe * Revision 2.0.0 1997/08/06 3486752Sfjoe * Initial revision by Alexey Zverev 3586752Sfjoe * 3686752Sfjoe * Revision 2.0.1 1997/08/11 3786752Sfjoe * Additional internal statistics support (tx statistics) 3886752Sfjoe * 3986752Sfjoe * Revision 2.0.2 1997/11/05 4086752Sfjoe * if_bpf bug has been fixed 4186752Sfjoe * 4286752Sfjoe * Revision 2.0.3 1998/12/20 4386752Sfjoe * Memory leakage has been eliminated in 4486752Sfjoe * the sbni_st and sbni_timeout routines. 4586752Sfjoe * 4686752Sfjoe * Revision 3.0 2000/08/10 by Yaroslav Polyakov 4786752Sfjoe * Support for PCI cards. 4.1 modification. 4886752Sfjoe * 4986752Sfjoe * Revision 3.1 2000/09/12 5086752Sfjoe * Removed extra #defines around bpf functions 5186752Sfjoe * 5286752Sfjoe * Revision 4.0 2000/11/23 by Denis Timofeev 5386752Sfjoe * Completely redesigned the buffer management 5486752Sfjoe * 5586752Sfjoe * Revision 4.1 2001/01/21 5686752Sfjoe * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards 5786752Sfjoe * 5886752Sfjoe * Written with reference to NE2000 driver developed by David Greenman. 5986752Sfjoe */ 6086752Sfjoe 6186752Sfjoe 6286752Sfjoe#include <sys/param.h> 6386752Sfjoe#include <sys/systm.h> 6486752Sfjoe#include <sys/socket.h> 6586752Sfjoe#include <sys/sockio.h> 6686752Sfjoe#include <sys/mbuf.h> 6786752Sfjoe#include <sys/kernel.h> 6886752Sfjoe#include <sys/proc.h> 6986752Sfjoe#include <sys/callout.h> 7086752Sfjoe#include <sys/syslog.h> 71101400Sfjoe#include <sys/random.h> 7286752Sfjoe 73101400Sfjoe#include <machine/bus.h> 74101400Sfjoe#include <sys/rman.h> 75101400Sfjoe#include <machine/resource.h> 76101400Sfjoe 7786752Sfjoe#include <net/if.h> 7886752Sfjoe#include <net/ethernet.h> 7986752Sfjoe#include <net/if_arp.h> 8086752Sfjoe#include <net/bpf.h> 8186752Sfjoe 8286752Sfjoe#include <dev/sbni/if_sbnireg.h> 8386752Sfjoe#include <dev/sbni/if_sbnivar.h> 8486752Sfjoe 8586752Sfjoe#define ASM_CRC 1 8686752Sfjoe 8786752Sfjoestatic void sbni_init(void *); 8886752Sfjoestatic void sbni_start(struct ifnet *); 8986752Sfjoestatic int sbni_ioctl(struct ifnet *, u_long, caddr_t); 9086752Sfjoestatic void sbni_watchdog(struct ifnet *); 9186752Sfjoestatic void sbni_stop(struct sbni_softc *); 9286752Sfjoestatic void handle_channel(struct sbni_softc *); 9386752Sfjoe 9486752Sfjoestatic void card_start(struct sbni_softc *); 9586752Sfjoestatic int recv_frame(struct sbni_softc *); 9686752Sfjoestatic void send_frame(struct sbni_softc *); 9786752Sfjoestatic int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 9886752Sfjoestatic int skip_tail(struct sbni_softc *, u_int, u_int32_t); 9986752Sfjoestatic void interpret_ack(struct sbni_softc *, u_int); 10086752Sfjoestatic void download_data(struct sbni_softc *, u_int32_t *); 10186752Sfjoestatic void prepare_to_send(struct sbni_softc *); 10286752Sfjoestatic void drop_xmit_queue(struct sbni_softc *); 10386752Sfjoestatic int get_rx_buf(struct sbni_softc *); 10486752Sfjoestatic void indicate_pkt(struct sbni_softc *); 10586752Sfjoestatic void change_level(struct sbni_softc *); 10686752Sfjoestatic int check_fhdr(struct sbni_softc *, u_int *, u_int *, 10786752Sfjoe u_int *, u_int *, u_int32_t *); 10886752Sfjoestatic int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 10986752Sfjoestatic void timeout_change_level(struct sbni_softc *); 11086752Sfjoestatic void send_frame_header(struct sbni_softc *, u_int32_t *); 11186752Sfjoestatic void set_initial_values(struct sbni_softc *, struct sbni_flags); 11286752Sfjoe 11386752Sfjoestatic u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 11486752Sfjoestatic timeout_t sbni_timeout; 11586752Sfjoe 11686752Sfjoestatic __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 11786752Sfjoestatic __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 11886752Sfjoestatic __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 11986752Sfjoestatic __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 12086752Sfjoe 12186752Sfjoestatic u_int32_t crc32tab[]; 12286752Sfjoe 12386752Sfjoe#ifdef SBNI_DUAL_COMPOUND 12489092Smsmithstruct sbni_softc *sbni_headlist; 12586752Sfjoe#endif 12686752Sfjoe 12786752Sfjoeu_int32_t next_sbni_unit; 12886752Sfjoe 12986752Sfjoe/* -------------------------------------------------------------------------- */ 13086752Sfjoe 13186752Sfjoestatic __inline u_char 13286752Sfjoesbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 13386752Sfjoe{ 134101400Sfjoe return bus_space_read_1( 135101400Sfjoe rman_get_bustag(sc->io_res), 136101400Sfjoe rman_get_bushandle(sc->io_res), 137101400Sfjoe sc->io_off + reg); 13886752Sfjoe} 13986752Sfjoe 14086752Sfjoestatic __inline void 14186752Sfjoesbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 14286752Sfjoe{ 143101400Sfjoe bus_space_write_1( 144101400Sfjoe rman_get_bustag(sc->io_res), 145101400Sfjoe rman_get_bushandle(sc->io_res), 146101400Sfjoe sc->io_off + reg, value); 14786752Sfjoe} 14886752Sfjoe 14986752Sfjoestatic __inline void 15086752Sfjoesbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 15186752Sfjoe{ 152101400Sfjoe bus_space_read_multi_1( 153101400Sfjoe rman_get_bustag(sc->io_res), 154101400Sfjoe rman_get_bushandle(sc->io_res), 155101400Sfjoe sc->io_off + DAT, to, len); 15686752Sfjoe} 15786752Sfjoe 15886752Sfjoestatic __inline void 15986752Sfjoesbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 16086752Sfjoe{ 161101400Sfjoe bus_space_write_multi_1( 162101400Sfjoe rman_get_bustag(sc->io_res), 163101400Sfjoe rman_get_bushandle(sc->io_res), 164101400Sfjoe sc->io_off + DAT, from, len); 16586752Sfjoe} 16686752Sfjoe 16786752Sfjoe 16886752Sfjoe/* 16986752Sfjoe Valid combinations in CSR0 (for probing): 17086752Sfjoe 17186752Sfjoe VALID_DECODER 0000,0011,1011,1010 17286752Sfjoe 17386752Sfjoe ; 0 ; - 17486752Sfjoe TR_REQ ; 1 ; + 17586752Sfjoe TR_RDY ; 2 ; - 17686752Sfjoe TR_RDY TR_REQ ; 3 ; + 17786752Sfjoe BU_EMP ; 4 ; + 17886752Sfjoe BU_EMP TR_REQ ; 5 ; + 17986752Sfjoe BU_EMP TR_RDY ; 6 ; - 18086752Sfjoe BU_EMP TR_RDY TR_REQ ; 7 ; + 18186752Sfjoe RC_RDY ; 8 ; + 18286752Sfjoe RC_RDY TR_REQ ; 9 ; + 18386752Sfjoe RC_RDY TR_RDY ; 10 ; - 18486752Sfjoe RC_RDY TR_RDY TR_REQ ; 11 ; - 18586752Sfjoe RC_RDY BU_EMP ; 12 ; - 18686752Sfjoe RC_RDY BU_EMP TR_REQ ; 13 ; - 18786752Sfjoe RC_RDY BU_EMP TR_RDY ; 14 ; - 18886752Sfjoe RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 18986752Sfjoe*/ 19086752Sfjoe 19186752Sfjoe#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 19286752Sfjoe 19386752Sfjoe 19486752Sfjoeint 19586752Sfjoesbni_probe(struct sbni_softc *sc) 19686752Sfjoe{ 19786752Sfjoe u_char csr0; 19886752Sfjoe 19986752Sfjoe csr0 = sbni_inb(sc, CSR0); 20086752Sfjoe if (csr0 != 0xff && csr0 != 0x00) { 20186752Sfjoe csr0 &= ~EN_INT; 20286752Sfjoe if (csr0 & BU_EMP) 20386752Sfjoe csr0 |= EN_INT; 20486752Sfjoe 20586752Sfjoe if (VALID_DECODER & (1 << (csr0 >> 4))) 20686752Sfjoe return (0); 20786752Sfjoe } 20886752Sfjoe 20986752Sfjoe return (ENXIO); 21086752Sfjoe} 21186752Sfjoe 21286752Sfjoe 21386752Sfjoe/* 21486752Sfjoe * Install interface into kernel networking data structures 21586752Sfjoe */ 21686752Sfjoevoid 21786752Sfjoesbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 21886752Sfjoe{ 21986752Sfjoe struct ifnet *ifp; 22086752Sfjoe u_char csr0; 22186752Sfjoe 22286752Sfjoe ifp = &sc->arpcom.ac_if; 22386752Sfjoe sbni_outb(sc, CSR0, 0); 22486752Sfjoe set_initial_values(sc, flags); 22586752Sfjoe 22686752Sfjoe callout_handle_init(&sc->wch); 22786752Sfjoe if (!ifp->if_name) { 22886752Sfjoe /* Initialize ifnet structure */ 22986752Sfjoe ifp->if_softc = sc; 23086752Sfjoe ifp->if_unit = unit; 23186752Sfjoe ifp->if_name = "sbni"; 23286752Sfjoe ifp->if_init = sbni_init; 23386752Sfjoe ifp->if_start = sbni_start; 23486752Sfjoe ifp->if_output = ether_output; 23586752Sfjoe ifp->if_ioctl = sbni_ioctl; 23686752Sfjoe ifp->if_watchdog = sbni_watchdog; 23786752Sfjoe ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 23886752Sfjoe 23986752Sfjoe /* report real baud rate */ 24086752Sfjoe csr0 = sbni_inb(sc, CSR0); 24186752Sfjoe ifp->if_baudrate = 24286752Sfjoe (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 24386752Sfjoe 24486752Sfjoe ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 245106937Ssam ether_ifattach(ifp, sc->arpcom.ac_enaddr); 24686752Sfjoe } 24786752Sfjoe /* device attach does transition from UNCONFIGURED to IDLE state */ 24886752Sfjoe 249104256Sbrooks if_printf(ifp, "speed %ld, address %6D, rxl ", 250104256Sbrooks ifp->if_baudrate, sc->arpcom.ac_enaddr, ":"); 25186752Sfjoe if (sc->delta_rxl) 25286752Sfjoe printf("auto\n"); 25386752Sfjoe else 25486752Sfjoe printf("%d (fixed)\n", sc->cur_rxl_index); 25586752Sfjoe} 25686752Sfjoe 25786752Sfjoe/* -------------------------------------------------------------------------- */ 25886752Sfjoe 25986752Sfjoestatic void 26086752Sfjoesbni_init(void *xsc) 26186752Sfjoe{ 26286752Sfjoe struct sbni_softc *sc; 26386752Sfjoe struct ifnet *ifp; 26486752Sfjoe int s; 26586752Sfjoe 26686752Sfjoe sc = (struct sbni_softc *)xsc; 26786752Sfjoe ifp = &sc->arpcom.ac_if; 26886752Sfjoe 26986752Sfjoe /* address not known */ 27086752Sfjoe if (TAILQ_EMPTY(&ifp->if_addrhead)) 27186752Sfjoe return; 27286752Sfjoe 27386752Sfjoe /* 27486752Sfjoe * kludge to avoid multiple initialization when more than once 27586752Sfjoe * protocols configured 27686752Sfjoe */ 27786752Sfjoe if (ifp->if_flags & IFF_RUNNING) 27886752Sfjoe return; 27986752Sfjoe 28086752Sfjoe s = splimp(); 28186752Sfjoe ifp->if_timer = 0; 28286752Sfjoe card_start(sc); 28386752Sfjoe sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 28486752Sfjoe 28586752Sfjoe ifp->if_flags |= IFF_RUNNING; 28686752Sfjoe ifp->if_flags &= ~IFF_OACTIVE; 28786752Sfjoe 28886752Sfjoe /* attempt to start output */ 28986752Sfjoe sbni_start(ifp); 29086752Sfjoe splx(s); 29186752Sfjoe} 29286752Sfjoe 29386752Sfjoe 29486752Sfjoestatic void 29586752Sfjoesbni_start(struct ifnet *ifp) 29686752Sfjoe{ 29786752Sfjoe struct sbni_softc *sc = ifp->if_softc; 29886752Sfjoe if (sc->tx_frameno == 0) 29986752Sfjoe prepare_to_send(sc); 30086752Sfjoe} 30186752Sfjoe 30286752Sfjoe 30386752Sfjoestatic void 30486752Sfjoesbni_stop(struct sbni_softc *sc) 30586752Sfjoe{ 30686752Sfjoe sbni_outb(sc, CSR0, 0); 30786752Sfjoe drop_xmit_queue(sc); 30886752Sfjoe 30986752Sfjoe if (sc->rx_buf_p) { 31086752Sfjoe m_freem(sc->rx_buf_p); 31186752Sfjoe sc->rx_buf_p = NULL; 31286752Sfjoe } 31386752Sfjoe 31486752Sfjoe untimeout(sbni_timeout, sc, sc->wch); 31586752Sfjoe sc->wch.callout = NULL; 31686752Sfjoe} 31786752Sfjoe 31886752Sfjoe/* -------------------------------------------------------------------------- */ 31986752Sfjoe 32086752Sfjoe/* interrupt handler */ 32186752Sfjoe 32286752Sfjoe/* 32386752Sfjoe * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 32486752Sfjoe * be looked as two independent single-channel devices. Every channel seems 32586752Sfjoe * as Ethernet interface but interrupt handler must be common. Really, first 32686752Sfjoe * channel ("master") driver only registers the handler. In it's struct softc 32786752Sfjoe * it has got pointer to "slave" channel's struct softc and handles that's 32886752Sfjoe * interrupts too. 32986752Sfjoe * softc of successfully attached ISA SBNI boards is linked to list. 33086752Sfjoe * While next board driver is initialized, it scans this list. If one 33186752Sfjoe * has found softc with same irq and ioaddr different by 4 then it assumes 33286752Sfjoe * this board to be "master". 33386752Sfjoe */ 33486752Sfjoe 33586752Sfjoevoid 33686752Sfjoesbni_intr(void *arg) 33786752Sfjoe{ 33886752Sfjoe struct sbni_softc *sc; 33986752Sfjoe int repeat; 34086752Sfjoe 34186752Sfjoe sc = (struct sbni_softc *)arg; 34286752Sfjoe 34386752Sfjoe do { 34486752Sfjoe repeat = 0; 34586752Sfjoe if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 34686752Sfjoe handle_channel(sc); 34786752Sfjoe repeat = 1; 34886752Sfjoe } 349101393Sfjoe if (sc->slave_sc && /* second channel present */ 350101393Sfjoe (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) { 35186752Sfjoe handle_channel(sc->slave_sc); 35286752Sfjoe repeat = 1; 35386752Sfjoe } 35486752Sfjoe } while (repeat); 35586752Sfjoe} 35686752Sfjoe 35786752Sfjoe 35886752Sfjoestatic void 35986752Sfjoehandle_channel(struct sbni_softc *sc) 36086752Sfjoe{ 36186752Sfjoe int req_ans; 36286752Sfjoe u_char csr0; 36386752Sfjoe 36486752Sfjoe sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 36586752Sfjoe 36686752Sfjoe sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 36786752Sfjoe for (;;) { 36886752Sfjoe csr0 = sbni_inb(sc, CSR0); 36986752Sfjoe if ((csr0 & (RC_RDY | TR_RDY)) == 0) 37086752Sfjoe break; 37186752Sfjoe 37286752Sfjoe req_ans = !(sc->state & FL_PREV_OK); 37386752Sfjoe 37486752Sfjoe if (csr0 & RC_RDY) 37586752Sfjoe req_ans = recv_frame(sc); 37686752Sfjoe 37786752Sfjoe /* 37886752Sfjoe * TR_RDY always equals 1 here because we have owned the marker, 37986752Sfjoe * and we set TR_REQ when disabled interrupts 38086752Sfjoe */ 38186752Sfjoe csr0 = sbni_inb(sc, CSR0); 38286752Sfjoe if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 38386752Sfjoe printf("sbni: internal error!\n"); 38486752Sfjoe 38586752Sfjoe /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 38686752Sfjoe if (req_ans || sc->tx_frameno != 0) 38786752Sfjoe send_frame(sc); 388101393Sfjoe else { 38986752Sfjoe /* send the marker without any data */ 39086752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 391101393Sfjoe } 39286752Sfjoe } 39386752Sfjoe 39486752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 39586752Sfjoe} 39686752Sfjoe 39786752Sfjoe 39886752Sfjoe/* 39986752Sfjoe * Routine returns 1 if it need to acknoweledge received frame. 40086752Sfjoe * Empty frame received without errors won't be acknoweledged. 40186752Sfjoe */ 40286752Sfjoe 40386752Sfjoestatic int 40486752Sfjoerecv_frame(struct sbni_softc *sc) 40586752Sfjoe{ 40686752Sfjoe u_int32_t crc; 40786752Sfjoe u_int framelen, frameno, ack; 40886752Sfjoe u_int is_first, frame_ok; 40986752Sfjoe 41086752Sfjoe crc = CRC32_INITIAL; 41186752Sfjoe if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 412101393Sfjoe frame_ok = framelen > 4 ? 413101393Sfjoe upload_data(sc, framelen, frameno, is_first, crc) : 414101393Sfjoe skip_tail(sc, framelen, crc); 41586752Sfjoe if (frame_ok) 41686752Sfjoe interpret_ack(sc, ack); 41786752Sfjoe } else 41886752Sfjoe frame_ok = 0; 41986752Sfjoe 42086752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 42186752Sfjoe if (frame_ok) { 42286752Sfjoe sc->state |= FL_PREV_OK; 42386752Sfjoe if (framelen > 4) 42486752Sfjoe sc->in_stats.all_rx_number++; 42586752Sfjoe } else { 42686752Sfjoe sc->state &= ~FL_PREV_OK; 42786752Sfjoe change_level(sc); 42886752Sfjoe sc->in_stats.all_rx_number++; 42986752Sfjoe sc->in_stats.bad_rx_number++; 43086752Sfjoe } 43186752Sfjoe 43286752Sfjoe return (!frame_ok || framelen > 4); 43386752Sfjoe} 43486752Sfjoe 43586752Sfjoe 43686752Sfjoestatic void 43786752Sfjoesend_frame(struct sbni_softc *sc) 43886752Sfjoe{ 43986752Sfjoe u_int32_t crc; 44086752Sfjoe u_char csr0; 44186752Sfjoe 44286752Sfjoe crc = CRC32_INITIAL; 44386752Sfjoe if (sc->state & FL_NEED_RESEND) { 44486752Sfjoe 44586752Sfjoe /* if frame was sended but not ACK'ed - resend it */ 44686752Sfjoe if (sc->trans_errors) { 44786752Sfjoe sc->trans_errors--; 44886752Sfjoe if (sc->framelen != 0) 44986752Sfjoe sc->in_stats.resend_tx_number++; 45086752Sfjoe } else { 45186752Sfjoe /* cannot xmit with many attempts */ 45286752Sfjoe drop_xmit_queue(sc); 45386752Sfjoe goto do_send; 45486752Sfjoe } 45586752Sfjoe } else 45686752Sfjoe sc->trans_errors = TR_ERROR_COUNT; 45786752Sfjoe 45886752Sfjoe send_frame_header(sc, &crc); 45986752Sfjoe sc->state |= FL_NEED_RESEND; 46086752Sfjoe /* 46186752Sfjoe * FL_NEED_RESEND will be cleared after ACK, but if empty 46286752Sfjoe * frame sended then in prepare_to_send next frame 46386752Sfjoe */ 46486752Sfjoe 46586752Sfjoe 46686752Sfjoe if (sc->framelen) { 46786752Sfjoe download_data(sc, &crc); 46886752Sfjoe sc->in_stats.all_tx_number++; 46986752Sfjoe sc->state |= FL_WAIT_ACK; 47086752Sfjoe } 47186752Sfjoe 47286752Sfjoe sbni_outsb(sc, (u_char *)&crc, sizeof crc); 47386752Sfjoe 47486752Sfjoedo_send: 47586752Sfjoe csr0 = sbni_inb(sc, CSR0); 47686752Sfjoe sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 47786752Sfjoe 47886752Sfjoe if (sc->tx_frameno) { 47986752Sfjoe /* next frame exists - request to send */ 48086752Sfjoe sbni_outb(sc, CSR0, csr0 | TR_REQ); 48186752Sfjoe } 48286752Sfjoe} 48386752Sfjoe 48486752Sfjoe 48586752Sfjoestatic void 48686752Sfjoedownload_data(struct sbni_softc *sc, u_int32_t *crc_p) 48786752Sfjoe{ 48886752Sfjoe struct mbuf *m; 48986752Sfjoe caddr_t data_p; 49086752Sfjoe u_int data_len, pos, slice; 49186752Sfjoe 49286752Sfjoe data_p = NULL; /* initialized to avoid warn */ 49386752Sfjoe pos = 0; 49486752Sfjoe 49586752Sfjoe for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 49686752Sfjoe if (pos + m->m_len > sc->outpos) { 49786752Sfjoe data_len = m->m_len - (sc->outpos - pos); 49886752Sfjoe data_p = mtod(m, caddr_t) + (sc->outpos - pos); 49986752Sfjoe 50086752Sfjoe goto do_copy; 50186752Sfjoe } else 50286752Sfjoe pos += m->m_len; 50386752Sfjoe } 50486752Sfjoe 50586752Sfjoe data_len = 0; 50686752Sfjoe 50786752Sfjoedo_copy: 50886752Sfjoe pos = 0; 50986752Sfjoe do { 51086752Sfjoe if (data_len) { 51186752Sfjoe slice = min(data_len, sc->framelen - pos); 51286752Sfjoe sbni_outsb(sc, data_p, slice); 51386752Sfjoe *crc_p = calc_crc32(*crc_p, data_p, slice); 51486752Sfjoe 51586752Sfjoe pos += slice; 51686752Sfjoe if (data_len -= slice) 51786752Sfjoe data_p += slice; 51886752Sfjoe else { 519101393Sfjoe do { 520101393Sfjoe m = m->m_next; 521101393Sfjoe } while (m != NULL && m->m_len == 0); 52286752Sfjoe 52386752Sfjoe if (m) { 52486752Sfjoe data_len = m->m_len; 52586752Sfjoe data_p = mtod(m, caddr_t); 52686752Sfjoe } 52786752Sfjoe } 52886752Sfjoe } else { 52986752Sfjoe /* frame too short - zero padding */ 53086752Sfjoe 53186752Sfjoe pos = sc->framelen - pos; 53286752Sfjoe while (pos--) { 53386752Sfjoe sbni_outb(sc, DAT, 0); 53486752Sfjoe *crc_p = CRC32(0, *crc_p); 53586752Sfjoe } 53686752Sfjoe return; 53786752Sfjoe } 53886752Sfjoe } while (pos < sc->framelen); 53986752Sfjoe} 54086752Sfjoe 54186752Sfjoe 54286752Sfjoestatic int 54386752Sfjoeupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 54486752Sfjoe u_int is_first, u_int32_t crc) 54586752Sfjoe{ 54686752Sfjoe int frame_ok; 54786752Sfjoe 54886752Sfjoe if (is_first) { 54986752Sfjoe sc->wait_frameno = frameno; 55086752Sfjoe sc->inppos = 0; 55186752Sfjoe } 55286752Sfjoe 55386752Sfjoe if (sc->wait_frameno == frameno) { 55486752Sfjoe 55586752Sfjoe if (sc->inppos + framelen <= ETHER_MAX_LEN) { 55686752Sfjoe frame_ok = append_frame_to_pkt(sc, framelen, crc); 55786752Sfjoe 55886752Sfjoe /* 55986752Sfjoe * if CRC is right but framelen incorrect then transmitter 56086752Sfjoe * error was occured... drop entire packet 56186752Sfjoe */ 56286752Sfjoe } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 56386752Sfjoe sc->wait_frameno = 0; 56486752Sfjoe sc->inppos = 0; 56586752Sfjoe sc->arpcom.ac_if.if_ierrors++; 56686752Sfjoe /* now skip all frames until is_first != 0 */ 56786752Sfjoe } 56886752Sfjoe } else 56986752Sfjoe frame_ok = skip_tail(sc, framelen, crc); 57086752Sfjoe 57186752Sfjoe if (is_first && !frame_ok) { 57286752Sfjoe /* 57386752Sfjoe * Frame has been violated, but we have stored 57486752Sfjoe * is_first already... Drop entire packet. 57586752Sfjoe */ 57686752Sfjoe sc->wait_frameno = 0; 57786752Sfjoe sc->arpcom.ac_if.if_ierrors++; 57886752Sfjoe } 57986752Sfjoe 58086752Sfjoe return (frame_ok); 58186752Sfjoe} 58286752Sfjoe 58386752Sfjoe 58486752Sfjoestatic __inline void send_complete(struct sbni_softc *); 58586752Sfjoe 58686752Sfjoestatic __inline void 58786752Sfjoesend_complete(struct sbni_softc *sc) 58886752Sfjoe{ 58986752Sfjoe m_freem(sc->tx_buf_p); 59086752Sfjoe sc->tx_buf_p = NULL; 59186752Sfjoe sc->arpcom.ac_if.if_opackets++; 59286752Sfjoe} 59386752Sfjoe 59486752Sfjoe 59586752Sfjoestatic void 59686752Sfjoeinterpret_ack(struct sbni_softc *sc, u_int ack) 59786752Sfjoe{ 59886752Sfjoe if (ack == FRAME_SENT_OK) { 59986752Sfjoe sc->state &= ~FL_NEED_RESEND; 60086752Sfjoe 60186752Sfjoe if (sc->state & FL_WAIT_ACK) { 60286752Sfjoe sc->outpos += sc->framelen; 60386752Sfjoe 604101393Sfjoe if (--sc->tx_frameno) { 605101393Sfjoe sc->framelen = min( 606101393Sfjoe sc->maxframe, sc->pktlen - sc->outpos); 607101393Sfjoe } else { 60886752Sfjoe send_complete(sc); 60986752Sfjoe prepare_to_send(sc); 61086752Sfjoe } 61186752Sfjoe } 61286752Sfjoe } 61386752Sfjoe 61486752Sfjoe sc->state &= ~FL_WAIT_ACK; 61586752Sfjoe} 61686752Sfjoe 61786752Sfjoe 61886752Sfjoe/* 61986752Sfjoe * Glue received frame with previous fragments of packet. 62086752Sfjoe * Indicate packet when last frame would be accepted. 62186752Sfjoe */ 62286752Sfjoe 62386752Sfjoestatic int 62486752Sfjoeappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 62586752Sfjoe{ 62686752Sfjoe caddr_t p; 62786752Sfjoe 62886752Sfjoe if (sc->inppos + framelen > ETHER_MAX_LEN) 62986752Sfjoe return (0); 63086752Sfjoe 63186752Sfjoe if (!sc->rx_buf_p && !get_rx_buf(sc)) 63286752Sfjoe return (0); 63386752Sfjoe 63486752Sfjoe p = sc->rx_buf_p->m_data + sc->inppos; 63586752Sfjoe sbni_insb(sc, p, framelen); 63686752Sfjoe if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 63786752Sfjoe return (0); 63886752Sfjoe 63986752Sfjoe sc->inppos += framelen - 4; 64086752Sfjoe if (--sc->wait_frameno == 0) { /* last frame received */ 64186752Sfjoe indicate_pkt(sc); 64286752Sfjoe sc->arpcom.ac_if.if_ipackets++; 64386752Sfjoe } 64486752Sfjoe 64586752Sfjoe return (1); 64686752Sfjoe} 64786752Sfjoe 64886752Sfjoe 64986752Sfjoe/* 65086752Sfjoe * Prepare to start output on adapter. Current priority must be set to splimp 65186752Sfjoe * before this routine is called. 65286752Sfjoe * Transmitter will be actually activated when marker has been accepted. 65386752Sfjoe */ 65486752Sfjoe 65586752Sfjoestatic void 65686752Sfjoeprepare_to_send(struct sbni_softc *sc) 65786752Sfjoe{ 65886752Sfjoe struct mbuf *m; 65986752Sfjoe u_int len; 66086752Sfjoe 66186752Sfjoe /* sc->tx_buf_p == NULL here! */ 66286752Sfjoe if (sc->tx_buf_p) 66386752Sfjoe printf("sbni: memory leak!\n"); 66486752Sfjoe 66586752Sfjoe sc->outpos = 0; 66686752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 66786752Sfjoe 66886752Sfjoe for (;;) { 66986752Sfjoe IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, sc->tx_buf_p); 67086752Sfjoe if (!sc->tx_buf_p) { 67186752Sfjoe /* nothing to transmit... */ 67286752Sfjoe sc->pktlen = 0; 67386752Sfjoe sc->tx_frameno = 0; 67486752Sfjoe sc->framelen = 0; 67586752Sfjoe sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 67686752Sfjoe return; 67786752Sfjoe } 67886752Sfjoe 67986752Sfjoe for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 68086752Sfjoe len += m->m_len; 68186752Sfjoe 68286752Sfjoe if (len != 0) 68386752Sfjoe break; 68486752Sfjoe m_freem(sc->tx_buf_p); 68586752Sfjoe } 68686752Sfjoe 68786752Sfjoe if (len < SBNI_MIN_LEN) 68886752Sfjoe len = SBNI_MIN_LEN; 68986752Sfjoe 69086752Sfjoe sc->pktlen = len; 69186752Sfjoe sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe; 69286752Sfjoe sc->framelen = min(len, sc->maxframe); 69386752Sfjoe 69486752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 69586752Sfjoe sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; 696106937Ssam BPF_MTAP(&sc->arpcom.ac_if, sc->tx_buf_p); 69786752Sfjoe} 69886752Sfjoe 69986752Sfjoe 70086752Sfjoestatic void 70186752Sfjoedrop_xmit_queue(struct sbni_softc *sc) 70286752Sfjoe{ 70386752Sfjoe struct mbuf *m; 70486752Sfjoe 70586752Sfjoe if (sc->tx_buf_p) { 70686752Sfjoe m_freem(sc->tx_buf_p); 70786752Sfjoe sc->tx_buf_p = NULL; 70886752Sfjoe sc->arpcom.ac_if.if_oerrors++; 70986752Sfjoe } 71086752Sfjoe 71186752Sfjoe for (;;) { 71286752Sfjoe IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 71386752Sfjoe if (m == NULL) 71486752Sfjoe break; 71586752Sfjoe m_freem(m); 71686752Sfjoe sc->arpcom.ac_if.if_oerrors++; 71786752Sfjoe } 71886752Sfjoe 71986752Sfjoe sc->tx_frameno = 0; 72086752Sfjoe sc->framelen = 0; 72186752Sfjoe sc->outpos = 0; 72286752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 72386752Sfjoe sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 72486752Sfjoe} 72586752Sfjoe 72686752Sfjoe 72786752Sfjoestatic void 72886752Sfjoesend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 72986752Sfjoe{ 73086752Sfjoe u_int32_t crc; 73186752Sfjoe u_int len_field; 73286752Sfjoe u_char value; 73386752Sfjoe 73486752Sfjoe crc = *crc_p; 73586752Sfjoe len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 73686752Sfjoe 73786752Sfjoe if (sc->state & FL_NEED_RESEND) 73886752Sfjoe len_field |= FRAME_RETRY; /* non-first attempt... */ 73986752Sfjoe 74086752Sfjoe if (sc->outpos == 0) 74186752Sfjoe len_field |= FRAME_FIRST; 74286752Sfjoe 74386752Sfjoe len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 74486752Sfjoe sbni_outb(sc, DAT, SBNI_SIG); 74586752Sfjoe 74686752Sfjoe value = (u_char)len_field; 74786752Sfjoe sbni_outb(sc, DAT, value); 74886752Sfjoe crc = CRC32(value, crc); 74986752Sfjoe value = (u_char)(len_field >> 8); 75086752Sfjoe sbni_outb(sc, DAT, value); 75186752Sfjoe crc = CRC32(value, crc); 75286752Sfjoe 75386752Sfjoe sbni_outb(sc, DAT, sc->tx_frameno); 75486752Sfjoe crc = CRC32(sc->tx_frameno, crc); 75586752Sfjoe sbni_outb(sc, DAT, 0); 75686752Sfjoe crc = CRC32(0, crc); 75786752Sfjoe *crc_p = crc; 75886752Sfjoe} 75986752Sfjoe 76086752Sfjoe 76186752Sfjoe/* 76286752Sfjoe * if frame tail not needed (incorrect number or received twice), 76386752Sfjoe * it won't store, but CRC will be calculated 76486752Sfjoe */ 76586752Sfjoe 76686752Sfjoestatic int 76786752Sfjoeskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 76886752Sfjoe{ 76986752Sfjoe while (tail_len--) 77086752Sfjoe crc = CRC32(sbni_inb(sc, DAT), crc); 77186752Sfjoe 77286752Sfjoe return (crc == CRC32_REMAINDER); 77386752Sfjoe} 77486752Sfjoe 77586752Sfjoe 77686752Sfjoestatic int 77786752Sfjoecheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 77886752Sfjoe u_int *ack, u_int *is_first, u_int32_t *crc_p) 77986752Sfjoe{ 78086752Sfjoe u_int32_t crc; 78186752Sfjoe u_char value; 78286752Sfjoe 78386752Sfjoe crc = *crc_p; 78486752Sfjoe if (sbni_inb(sc, DAT) != SBNI_SIG) 78586752Sfjoe return (0); 78686752Sfjoe 78786752Sfjoe value = sbni_inb(sc, DAT); 78886752Sfjoe *framelen = (u_int)value; 78986752Sfjoe crc = CRC32(value, crc); 79086752Sfjoe value = sbni_inb(sc, DAT); 79186752Sfjoe *framelen |= ((u_int)value) << 8; 79286752Sfjoe crc = CRC32(value, crc); 79386752Sfjoe 79486752Sfjoe *ack = *framelen & FRAME_ACK_MASK; 79586752Sfjoe *is_first = (*framelen & FRAME_FIRST) != 0; 79686752Sfjoe 79786752Sfjoe if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 79886752Sfjoe return (0); 79986752Sfjoe 80086752Sfjoe value = sbni_inb(sc, DAT); 80186752Sfjoe *frameno = (u_int)value; 80286752Sfjoe crc = CRC32(value, crc); 80386752Sfjoe 80486752Sfjoe crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 80586752Sfjoe *framelen -= 2; 80686752Sfjoe 80786752Sfjoe *crc_p = crc; 80886752Sfjoe return (1); 80986752Sfjoe} 81086752Sfjoe 81186752Sfjoe 81286752Sfjoestatic int 81386752Sfjoeget_rx_buf(struct sbni_softc *sc) 81486752Sfjoe{ 81586752Sfjoe struct mbuf *m; 81686752Sfjoe 81786752Sfjoe MGETHDR(m, M_DONTWAIT, MT_DATA); 81886752Sfjoe if (m == NULL) { 819104256Sbrooks if_printf(&sc->arpcom.ac_if, "cannot allocate header mbuf\n"); 82086752Sfjoe return (0); 82186752Sfjoe } 82286752Sfjoe 82386752Sfjoe /* 82486752Sfjoe * We always put the received packet in a single buffer - 82586752Sfjoe * either with just an mbuf header or in a cluster attached 82686752Sfjoe * to the header. The +2 is to compensate for the alignment 82786752Sfjoe * fixup below. 82886752Sfjoe */ 82986752Sfjoe if (ETHER_MAX_LEN + 2 > MHLEN) { 83086752Sfjoe /* Attach an mbuf cluster */ 83186752Sfjoe MCLGET(m, M_DONTWAIT); 83286752Sfjoe if ((m->m_flags & M_EXT) == 0) { 83386752Sfjoe m_freem(m); 83486752Sfjoe return (0); 83586752Sfjoe } 83686752Sfjoe } 83786752Sfjoe m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 83886752Sfjoe 83986752Sfjoe /* 84086752Sfjoe * The +2 is to longword align the start of the real packet. 84186752Sfjoe * (sizeof ether_header == 14) 84286752Sfjoe * This is important for NFS. 84386752Sfjoe */ 84486752Sfjoe m_adj(m, 2); 84586752Sfjoe sc->rx_buf_p = m; 84686752Sfjoe return (1); 84786752Sfjoe} 84886752Sfjoe 84986752Sfjoe 85086752Sfjoestatic void 85186752Sfjoeindicate_pkt(struct sbni_softc *sc) 85286752Sfjoe{ 853106937Ssam struct ifnet *ifp = &sc->arpcom.ac_if; 85486752Sfjoe struct mbuf *m; 85586752Sfjoe 85686752Sfjoe m = sc->rx_buf_p; 857106937Ssam m->m_pkthdr.rcvif = ifp; 85886752Sfjoe m->m_pkthdr.len = m->m_len = sc->inppos; 85986752Sfjoe 860106937Ssam (*ifp->if_input)(ifp, m); 86186752Sfjoe sc->rx_buf_p = NULL; 86286752Sfjoe} 86386752Sfjoe 86486752Sfjoe/* -------------------------------------------------------------------------- */ 86586752Sfjoe 86686752Sfjoe/* 86786752Sfjoe * Routine checks periodically wire activity and regenerates marker if 86886752Sfjoe * connect was inactive for a long time. 86986752Sfjoe */ 87086752Sfjoe 87186752Sfjoestatic void 87286752Sfjoesbni_timeout(void *xsc) 87386752Sfjoe{ 87486752Sfjoe struct sbni_softc *sc; 87586752Sfjoe int s; 87686752Sfjoe u_char csr0; 87786752Sfjoe 87886752Sfjoe sc = (struct sbni_softc *)xsc; 87986752Sfjoe s = splimp(); 88086752Sfjoe 88186752Sfjoe csr0 = sbni_inb(sc, CSR0); 88286752Sfjoe if (csr0 & RC_CHK) { 88386752Sfjoe 88486752Sfjoe if (sc->timer_ticks) { 88586752Sfjoe if (csr0 & (RC_RDY | BU_EMP)) 88686752Sfjoe /* receiving not active */ 88786752Sfjoe sc->timer_ticks--; 88886752Sfjoe } else { 88986752Sfjoe sc->in_stats.timeout_number++; 89086752Sfjoe if (sc->delta_rxl) 89186752Sfjoe timeout_change_level(sc); 89286752Sfjoe 89386752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 89486752Sfjoe csr0 = sbni_inb(sc, CSR0); 89586752Sfjoe } 89686752Sfjoe } 89786752Sfjoe 89886752Sfjoe sbni_outb(sc, CSR0, csr0 | RC_CHK); 89986752Sfjoe sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 90086752Sfjoe splx(s); 90186752Sfjoe} 90286752Sfjoe 90386752Sfjoe/* -------------------------------------------------------------------------- */ 90486752Sfjoe 90586752Sfjoestatic void 90686752Sfjoecard_start(struct sbni_softc *sc) 90786752Sfjoe{ 90886752Sfjoe sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 90986752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 91086752Sfjoe sc->state |= FL_PREV_OK; 91186752Sfjoe 91286752Sfjoe sc->inppos = 0; 91386752Sfjoe sc->wait_frameno = 0; 91486752Sfjoe 91586752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 91686752Sfjoe sbni_outb(sc, CSR0, EN_INT); 91786752Sfjoe} 91886752Sfjoe 91986752Sfjoe/* -------------------------------------------------------------------------- */ 92086752Sfjoe 92186752Sfjoe/* 92286752Sfjoe * Device timeout/watchdog routine. Entered if the device neglects to 92386752Sfjoe * generate an interrupt after a transmit has been started on it. 92486752Sfjoe */ 92586752Sfjoe 92686752Sfjoestatic void 92786752Sfjoesbni_watchdog(struct ifnet *ifp) 92886752Sfjoe{ 92986752Sfjoe log(LOG_ERR, "sbni%d: device timeout\n", ifp->if_unit); 93086752Sfjoe ifp->if_oerrors++; 93186752Sfjoe} 93286752Sfjoe 93386752Sfjoe 93486752Sfjoestatic u_char rxl_tab[] = { 93586752Sfjoe 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 93686752Sfjoe 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 93786752Sfjoe}; 93886752Sfjoe 93986752Sfjoe#define SIZE_OF_TIMEOUT_RXL_TAB 4 94086752Sfjoestatic u_char timeout_rxl_tab[] = { 94186752Sfjoe 0x03, 0x05, 0x08, 0x0b 94286752Sfjoe}; 94386752Sfjoe 94486752Sfjoestatic void 94586752Sfjoeset_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 94686752Sfjoe{ 94786752Sfjoe if (flags.fixed_rxl) { 94886752Sfjoe sc->delta_rxl = 0; /* disable receive level autodetection */ 94986752Sfjoe sc->cur_rxl_index = flags.rxl; 95086752Sfjoe } else { 95186752Sfjoe sc->delta_rxl = DEF_RXL_DELTA; 95286752Sfjoe sc->cur_rxl_index = DEF_RXL; 95386752Sfjoe } 95486752Sfjoe 95586752Sfjoe sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 95686752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 95786752Sfjoe sc->maxframe = DEFAULT_FRAME_LEN; 95886752Sfjoe 95986752Sfjoe /* 96086752Sfjoe * generate Ethernet address (0x00ff01xxxxxx) 96186752Sfjoe */ 962101400Sfjoe *(u_int16_t *) sc->arpcom.ac_enaddr = htons(0x00ff); 963101400Sfjoe if (flags.mac_addr) { 964101400Sfjoe *(u_int32_t *) (sc->arpcom.ac_enaddr + 2) = 965101400Sfjoe htonl(flags.mac_addr | 0x01000000); 966101400Sfjoe } else { 967101400Sfjoe *(u_char *) (sc->arpcom.ac_enaddr + 2) = 0x01; 968101400Sfjoe read_random(sc->arpcom.ac_enaddr + 3, 3); 96986752Sfjoe } 97086752Sfjoe} 97186752Sfjoe 97286752Sfjoe 97386752Sfjoe#ifdef SBNI_DUAL_COMPOUND 97486752Sfjoe 97586752Sfjoestruct sbni_softc * 97686752Sfjoeconnect_to_master(struct sbni_softc *sc) 97786752Sfjoe{ 978101400Sfjoe struct sbni_softc *p, *p_prev; 97986752Sfjoe 980101400Sfjoe for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { 981101400Sfjoe if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || 982101400Sfjoe rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { 983101400Sfjoe p->slave_sc = sc; 984101400Sfjoe if (p_prev) 985101400Sfjoe p_prev->link = p->link; 986101400Sfjoe else 987101400Sfjoe sbni_headlist = p->link; 988101400Sfjoe return p; 98986752Sfjoe } 99086752Sfjoe } 99186752Sfjoe 99286752Sfjoe return (NULL); 99386752Sfjoe} 99486752Sfjoe 99586752Sfjoe#endif /* SBNI_DUAL_COMPOUND */ 99686752Sfjoe 99786752Sfjoe 99886752Sfjoe/* Receive level auto-selection */ 99986752Sfjoe 100086752Sfjoestatic void 100186752Sfjoechange_level(struct sbni_softc *sc) 100286752Sfjoe{ 100386752Sfjoe if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 100486752Sfjoe return; 100586752Sfjoe 100686752Sfjoe if (sc->cur_rxl_index == 0) 100786752Sfjoe sc->delta_rxl = 1; 100886752Sfjoe else if (sc->cur_rxl_index == 15) 100986752Sfjoe sc->delta_rxl = -1; 101086752Sfjoe else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 101186752Sfjoe sc->delta_rxl = -sc->delta_rxl; 101286752Sfjoe 101386752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 101486752Sfjoe sbni_inb(sc, CSR0); /* it needed for PCI cards */ 101586752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 101686752Sfjoe 101786752Sfjoe sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 101886752Sfjoe sc->cur_rxl_rcvd = 0; 101986752Sfjoe} 102086752Sfjoe 102186752Sfjoe 102286752Sfjoestatic void 102386752Sfjoetimeout_change_level(struct sbni_softc *sc) 102486752Sfjoe{ 102586752Sfjoe sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 102686752Sfjoe if (++sc->timeout_rxl >= 4) 102786752Sfjoe sc->timeout_rxl = 0; 102886752Sfjoe 102986752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 103086752Sfjoe sbni_inb(sc, CSR0); 103186752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 103286752Sfjoe 103386752Sfjoe sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 103486752Sfjoe sc->cur_rxl_rcvd = 0; 103586752Sfjoe} 103686752Sfjoe 103786752Sfjoe/* -------------------------------------------------------------------------- */ 103886752Sfjoe 103986752Sfjoe/* 104086752Sfjoe * Process an ioctl request. This code needs some work - it looks 104186752Sfjoe * pretty ugly. 104286752Sfjoe */ 104386752Sfjoe 104486752Sfjoestatic int 104586752Sfjoesbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 104686752Sfjoe{ 104786752Sfjoe struct sbni_softc *sc; 104886752Sfjoe struct ifreq *ifr; 104993593Sjhb struct thread *td; 105086752Sfjoe struct sbni_in_stats *in_stats; 105186752Sfjoe struct sbni_flags flags; 105286752Sfjoe int error, s; 105386752Sfjoe 105486752Sfjoe sc = ifp->if_softc; 105586752Sfjoe ifr = (struct ifreq *)data; 105693593Sjhb td = curthread; 105786752Sfjoe error = 0; 105886752Sfjoe 105986752Sfjoe s = splimp(); 106086752Sfjoe 106186752Sfjoe switch (command) { 106286752Sfjoe case SIOCSIFFLAGS: 106386752Sfjoe /* 106486752Sfjoe * If the interface is marked up and stopped, then start it. 106586752Sfjoe * If it is marked down and running, then stop it. 106686752Sfjoe */ 106786752Sfjoe if (ifp->if_flags & IFF_UP) { 106886752Sfjoe if (!(ifp->if_flags & IFF_RUNNING)) 106986752Sfjoe sbni_init(sc); 107086752Sfjoe } else { 107186752Sfjoe if (ifp->if_flags & IFF_RUNNING) { 107286752Sfjoe sbni_stop(sc); 107386752Sfjoe ifp->if_flags &= ~IFF_RUNNING; 107486752Sfjoe } 107586752Sfjoe } 107686752Sfjoe break; 107786752Sfjoe 107886752Sfjoe case SIOCADDMULTI: 107986752Sfjoe case SIOCDELMULTI: 108086752Sfjoe /* 108186752Sfjoe * Multicast list has changed; set the hardware filter 108286752Sfjoe * accordingly. 108386752Sfjoe */ 108486752Sfjoe error = 0; 108586752Sfjoe /* if (ifr == NULL) 108686752Sfjoe error = EAFNOSUPPORT; */ 108786752Sfjoe break; 108886752Sfjoe 108986752Sfjoe case SIOCSIFMTU: 109086752Sfjoe if (ifr->ifr_mtu > ETHERMTU) 109186752Sfjoe error = EINVAL; 109286752Sfjoe else 109386752Sfjoe ifp->if_mtu = ifr->ifr_mtu; 109486752Sfjoe break; 109586752Sfjoe 109686752Sfjoe /* 109786752Sfjoe * SBNI specific ioctl 109886752Sfjoe */ 109986752Sfjoe case SIOCGHWFLAGS: /* get flags */ 110086752Sfjoe bcopy((caddr_t) sc->arpcom.ac_enaddr+3, (caddr_t) &flags, 3); 110186752Sfjoe flags.rxl = sc->cur_rxl_index; 110286752Sfjoe flags.rate = sc->csr1.rate; 110386752Sfjoe flags.fixed_rxl = (sc->delta_rxl == 0); 110486752Sfjoe flags.fixed_rate = 1; 110586752Sfjoe ifr->ifr_data = *(caddr_t*) &flags; 110686752Sfjoe break; 110786752Sfjoe 110886752Sfjoe case SIOCGINSTATS: 110986752Sfjoe in_stats = (struct sbni_in_stats *)ifr->ifr_data; 111086752Sfjoe bcopy((void *)(&(sc->in_stats)), (void *)in_stats, 111186752Sfjoe sizeof(struct sbni_in_stats)); 111286752Sfjoe break; 111386752Sfjoe 111486752Sfjoe case SIOCSHWFLAGS: /* set flags */ 111586752Sfjoe /* root only */ 111693593Sjhb error = suser(td); 111786752Sfjoe if (error) 111886752Sfjoe break; 111986752Sfjoe flags = *(struct sbni_flags*)&ifr->ifr_data; 112086752Sfjoe if (flags.fixed_rxl) { 112186752Sfjoe sc->delta_rxl = 0; 112286752Sfjoe sc->cur_rxl_index = flags.rxl; 112386752Sfjoe } else { 112486752Sfjoe sc->delta_rxl = DEF_RXL_DELTA; 112586752Sfjoe sc->cur_rxl_index = DEF_RXL; 112686752Sfjoe } 112786752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 112886752Sfjoe sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 112986752Sfjoe if (flags.mac_addr) 113086752Sfjoe bcopy((caddr_t) &flags, 113186752Sfjoe (caddr_t) sc->arpcom.ac_enaddr+3, 3); 113286752Sfjoe 113386752Sfjoe /* Don't be afraid... */ 113486752Sfjoe sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 113586752Sfjoe break; 113686752Sfjoe 113786752Sfjoe case SIOCRINSTATS: 113893593Sjhb if (!(error = suser(td))) /* root only */ 113986752Sfjoe bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 114086752Sfjoe break; 114186752Sfjoe 114286752Sfjoe default: 1143106937Ssam error = ether_ioctl(ifp, command, data); 1144106937Ssam break; 114586752Sfjoe } 114686752Sfjoe 114786752Sfjoe splx(s); 114886752Sfjoe return (error); 114986752Sfjoe} 115086752Sfjoe 115186752Sfjoe/* -------------------------------------------------------------------------- */ 115286752Sfjoe 115386752Sfjoe#ifdef ASM_CRC 115486752Sfjoe 115586752Sfjoestatic u_int32_t 115686752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len) 115786752Sfjoe{ 115886752Sfjoe register u_int32_t _crc __asm ("ax"); 115986752Sfjoe _crc = crc; 116086752Sfjoe 116186752Sfjoe __asm __volatile ( 116286752Sfjoe "xorl %%ebx, %%ebx\n" 116386752Sfjoe "movl %1, %%esi\n" 116486752Sfjoe "movl %2, %%ecx\n" 116586752Sfjoe "movl $crc32tab, %%edi\n" 116686752Sfjoe "shrl $2, %%ecx\n" 116786752Sfjoe "jz 1f\n" 116886752Sfjoe 116986752Sfjoe ".align 4\n" 117086752Sfjoe "0:\n" 117186752Sfjoe "movb %%al, %%bl\n" 117286752Sfjoe "movl (%%esi), %%edx\n" 117386752Sfjoe "shrl $8, %%eax\n" 117486752Sfjoe "xorb %%dl, %%bl\n" 117586752Sfjoe "shrl $8, %%edx\n" 117686752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 117786752Sfjoe 117886752Sfjoe "movb %%al, %%bl\n" 117986752Sfjoe "shrl $8, %%eax\n" 118086752Sfjoe "xorb %%dl, %%bl\n" 118186752Sfjoe "shrl $8, %%edx\n" 118286752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 118386752Sfjoe 118486752Sfjoe "movb %%al, %%bl\n" 118586752Sfjoe "shrl $8, %%eax\n" 118686752Sfjoe "xorb %%dl, %%bl\n" 118786752Sfjoe "movb %%dh, %%dl\n" 118886752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 118986752Sfjoe 119086752Sfjoe "movb %%al, %%bl\n" 119186752Sfjoe "shrl $8, %%eax\n" 119286752Sfjoe "xorb %%dl, %%bl\n" 119386752Sfjoe "addl $4, %%esi\n" 119486752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 119586752Sfjoe 119686752Sfjoe "decl %%ecx\n" 119786752Sfjoe "jnz 0b\n" 119886752Sfjoe 119986752Sfjoe "1:\n" 120086752Sfjoe "movl %2, %%ecx\n" 120186752Sfjoe "andl $3, %%ecx\n" 120286752Sfjoe "jz 2f\n" 120386752Sfjoe 120486752Sfjoe "movb %%al, %%bl\n" 120586752Sfjoe "shrl $8, %%eax\n" 120686752Sfjoe "xorb (%%esi), %%bl\n" 120786752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 120886752Sfjoe 120986752Sfjoe "decl %%ecx\n" 121086752Sfjoe "jz 2f\n" 121186752Sfjoe 121286752Sfjoe "movb %%al, %%bl\n" 121386752Sfjoe "shrl $8, %%eax\n" 121486752Sfjoe "xorb 1(%%esi), %%bl\n" 121586752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 121686752Sfjoe 121786752Sfjoe "decl %%ecx\n" 121886752Sfjoe "jz 2f\n" 121986752Sfjoe 122086752Sfjoe "movb %%al, %%bl\n" 122186752Sfjoe "shrl $8, %%eax\n" 122286752Sfjoe "xorb 2(%%esi), %%bl\n" 122386752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 122486752Sfjoe "2:\n" 122586752Sfjoe : 122686752Sfjoe : "a" (_crc), "g" (p), "g" (len) 122786752Sfjoe : "ax", "bx", "cx", "dx", "si", "di" 122886752Sfjoe ); 122986752Sfjoe 123086752Sfjoe return (_crc); 123186752Sfjoe} 123286752Sfjoe 123386752Sfjoe#else /* ASM_CRC */ 123486752Sfjoe 123586752Sfjoestatic u_int32_t 123686752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len) 123786752Sfjoe{ 123886752Sfjoe while (len--) 123986752Sfjoe crc = CRC32(*p++, crc); 124086752Sfjoe 124186752Sfjoe return (crc); 124286752Sfjoe} 124386752Sfjoe 124486752Sfjoe#endif /* ASM_CRC */ 124586752Sfjoe 124686752Sfjoe 1247103844Salfredstatic u_int32_t crc32tab[] __aligned(8) = { 124886752Sfjoe 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 124986752Sfjoe 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 125086752Sfjoe 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 125186752Sfjoe 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 125286752Sfjoe 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 125386752Sfjoe 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 125486752Sfjoe 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 125586752Sfjoe 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 125686752Sfjoe 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 125786752Sfjoe 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 125886752Sfjoe 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 125986752Sfjoe 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 126086752Sfjoe 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 126186752Sfjoe 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 126286752Sfjoe 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 126386752Sfjoe 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 126486752Sfjoe 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 126586752Sfjoe 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 126686752Sfjoe 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 126786752Sfjoe 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 126886752Sfjoe 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 126986752Sfjoe 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 127086752Sfjoe 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 127186752Sfjoe 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 127286752Sfjoe 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 127386752Sfjoe 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 127486752Sfjoe 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 127586752Sfjoe 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 127686752Sfjoe 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 127786752Sfjoe 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 127886752Sfjoe 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 127986752Sfjoe 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 128086752Sfjoe 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 128186752Sfjoe 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 128286752Sfjoe 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 128386752Sfjoe 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 128486752Sfjoe 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 128586752Sfjoe 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 128686752Sfjoe 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 128786752Sfjoe 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 128886752Sfjoe 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 128986752Sfjoe 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 129086752Sfjoe 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 129186752Sfjoe 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 129286752Sfjoe 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 129386752Sfjoe 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 129486752Sfjoe 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 129586752Sfjoe 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 129686752Sfjoe 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 129786752Sfjoe 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 129886752Sfjoe 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 129986752Sfjoe 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 130086752Sfjoe 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 130186752Sfjoe 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 130286752Sfjoe 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 130386752Sfjoe 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 130486752Sfjoe 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 130586752Sfjoe 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 130686752Sfjoe 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 130786752Sfjoe 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 130886752Sfjoe 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 130986752Sfjoe 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 131086752Sfjoe 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 131186752Sfjoe 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 131286752Sfjoe}; 1313