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