1139749Simp/*- 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: stable/11/sys/dev/sbni/if_sbni.c 337909 2018-08-16 15:27:19Z brooks $"); 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> 65180263Sjhb#include <sys/bus.h> 6686752Sfjoe#include <sys/systm.h> 6786752Sfjoe#include <sys/socket.h> 6886752Sfjoe#include <sys/sockio.h> 6986752Sfjoe#include <sys/mbuf.h> 7086752Sfjoe#include <sys/kernel.h> 71164033Srwatson#include <sys/priv.h> 7286752Sfjoe#include <sys/proc.h> 7386752Sfjoe#include <sys/callout.h> 7486752Sfjoe#include <sys/syslog.h> 75101400Sfjoe#include <sys/random.h> 7686752Sfjoe 77101400Sfjoe#include <machine/bus.h> 78101400Sfjoe#include <sys/rman.h> 79101400Sfjoe#include <machine/resource.h> 80101400Sfjoe 8186752Sfjoe#include <net/if.h> 82257176Sglebius#include <net/if_var.h> 83152315Sru#include <net/if_dl.h> 8486752Sfjoe#include <net/ethernet.h> 8586752Sfjoe#include <net/bpf.h> 86147256Sbrooks#include <net/if_types.h> 8786752Sfjoe 8886752Sfjoe#include <dev/sbni/if_sbnireg.h> 8986752Sfjoe#include <dev/sbni/if_sbnivar.h> 9086752Sfjoe 9186752Sfjoestatic void sbni_init(void *); 92180263Sjhbstatic void sbni_init_locked(struct sbni_softc *); 9386752Sfjoestatic void sbni_start(struct ifnet *); 94180263Sjhbstatic void sbni_start_locked(struct ifnet *); 9586752Sfjoestatic int sbni_ioctl(struct ifnet *, u_long, caddr_t); 9686752Sfjoestatic void sbni_stop(struct sbni_softc *); 9786752Sfjoestatic void handle_channel(struct sbni_softc *); 9886752Sfjoe 9986752Sfjoestatic void card_start(struct sbni_softc *); 10086752Sfjoestatic int recv_frame(struct sbni_softc *); 10186752Sfjoestatic void send_frame(struct sbni_softc *); 10286752Sfjoestatic int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 10386752Sfjoestatic int skip_tail(struct sbni_softc *, u_int, u_int32_t); 10486752Sfjoestatic void interpret_ack(struct sbni_softc *, u_int); 10586752Sfjoestatic void download_data(struct sbni_softc *, u_int32_t *); 10686752Sfjoestatic void prepare_to_send(struct sbni_softc *); 10786752Sfjoestatic void drop_xmit_queue(struct sbni_softc *); 10886752Sfjoestatic int get_rx_buf(struct sbni_softc *); 10986752Sfjoestatic void indicate_pkt(struct sbni_softc *); 11086752Sfjoestatic void change_level(struct sbni_softc *); 11186752Sfjoestatic int check_fhdr(struct sbni_softc *, u_int *, u_int *, 11286752Sfjoe u_int *, u_int *, u_int32_t *); 11386752Sfjoestatic int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 11486752Sfjoestatic void timeout_change_level(struct sbni_softc *); 11586752Sfjoestatic void send_frame_header(struct sbni_softc *, u_int32_t *); 11686752Sfjoestatic void set_initial_values(struct sbni_softc *, struct sbni_flags); 11786752Sfjoe 11886752Sfjoestatic u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 11986752Sfjoestatic timeout_t sbni_timeout; 12086752Sfjoe 12186752Sfjoestatic __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 12286752Sfjoestatic __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 12386752Sfjoestatic __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 12486752Sfjoestatic __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 12586752Sfjoe 12686752Sfjoestatic u_int32_t crc32tab[]; 12786752Sfjoe 12886752Sfjoe#ifdef SBNI_DUAL_COMPOUND 129180263Sjhbstatic struct mtx headlist_lock; 130180263SjhbMTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF); 131180263Sjhbstatic struct sbni_softc *sbni_headlist; 13286752Sfjoe#endif 13386752Sfjoe 13486752Sfjoe/* -------------------------------------------------------------------------- */ 13586752Sfjoe 13686752Sfjoestatic __inline u_char 13786752Sfjoesbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 13886752Sfjoe{ 139101400Sfjoe return bus_space_read_1( 140101400Sfjoe rman_get_bustag(sc->io_res), 141101400Sfjoe rman_get_bushandle(sc->io_res), 142101400Sfjoe sc->io_off + reg); 14386752Sfjoe} 14486752Sfjoe 14586752Sfjoestatic __inline void 14686752Sfjoesbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 14786752Sfjoe{ 148101400Sfjoe bus_space_write_1( 149101400Sfjoe rman_get_bustag(sc->io_res), 150101400Sfjoe rman_get_bushandle(sc->io_res), 151101400Sfjoe sc->io_off + reg, value); 15286752Sfjoe} 15386752Sfjoe 15486752Sfjoestatic __inline void 15586752Sfjoesbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 15686752Sfjoe{ 157101400Sfjoe bus_space_read_multi_1( 158101400Sfjoe rman_get_bustag(sc->io_res), 159101400Sfjoe rman_get_bushandle(sc->io_res), 160101400Sfjoe sc->io_off + DAT, to, len); 16186752Sfjoe} 16286752Sfjoe 16386752Sfjoestatic __inline void 16486752Sfjoesbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 16586752Sfjoe{ 166101400Sfjoe bus_space_write_multi_1( 167101400Sfjoe rman_get_bustag(sc->io_res), 168101400Sfjoe rman_get_bushandle(sc->io_res), 169101400Sfjoe sc->io_off + DAT, from, len); 17086752Sfjoe} 17186752Sfjoe 17286752Sfjoe 17386752Sfjoe/* 17486752Sfjoe Valid combinations in CSR0 (for probing): 17586752Sfjoe 17686752Sfjoe VALID_DECODER 0000,0011,1011,1010 17786752Sfjoe 17886752Sfjoe ; 0 ; - 17986752Sfjoe TR_REQ ; 1 ; + 18086752Sfjoe TR_RDY ; 2 ; - 18186752Sfjoe TR_RDY TR_REQ ; 3 ; + 18286752Sfjoe BU_EMP ; 4 ; + 18386752Sfjoe BU_EMP TR_REQ ; 5 ; + 18486752Sfjoe BU_EMP TR_RDY ; 6 ; - 18586752Sfjoe BU_EMP TR_RDY TR_REQ ; 7 ; + 18686752Sfjoe RC_RDY ; 8 ; + 18786752Sfjoe RC_RDY TR_REQ ; 9 ; + 18886752Sfjoe RC_RDY TR_RDY ; 10 ; - 18986752Sfjoe RC_RDY TR_RDY TR_REQ ; 11 ; - 19086752Sfjoe RC_RDY BU_EMP ; 12 ; - 19186752Sfjoe RC_RDY BU_EMP TR_REQ ; 13 ; - 19286752Sfjoe RC_RDY BU_EMP TR_RDY ; 14 ; - 19386752Sfjoe RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 19486752Sfjoe*/ 19586752Sfjoe 19686752Sfjoe#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 19786752Sfjoe 19886752Sfjoe 19986752Sfjoeint 20086752Sfjoesbni_probe(struct sbni_softc *sc) 20186752Sfjoe{ 20286752Sfjoe u_char csr0; 20386752Sfjoe 20486752Sfjoe csr0 = sbni_inb(sc, CSR0); 20586752Sfjoe if (csr0 != 0xff && csr0 != 0x00) { 20686752Sfjoe csr0 &= ~EN_INT; 20786752Sfjoe if (csr0 & BU_EMP) 20886752Sfjoe csr0 |= EN_INT; 20986752Sfjoe 21086752Sfjoe if (VALID_DECODER & (1 << (csr0 >> 4))) 21186752Sfjoe return (0); 21286752Sfjoe } 21386752Sfjoe 21486752Sfjoe return (ENXIO); 21586752Sfjoe} 21686752Sfjoe 21786752Sfjoe 21886752Sfjoe/* 21986752Sfjoe * Install interface into kernel networking data structures 22086752Sfjoe */ 221180263Sjhbint 22286752Sfjoesbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 22386752Sfjoe{ 22486752Sfjoe struct ifnet *ifp; 22586752Sfjoe u_char csr0; 22686752Sfjoe 227147256Sbrooks ifp = sc->ifp = if_alloc(IFT_ETHER); 228147256Sbrooks if (ifp == NULL) 229180263Sjhb return (ENOMEM); 23086752Sfjoe sbni_outb(sc, CSR0, 0); 23186752Sfjoe set_initial_values(sc, flags); 23286752Sfjoe 233121752Sbrooks /* Initialize ifnet structure */ 234121752Sbrooks ifp->if_softc = sc; 235121816Sbrooks if_initname(ifp, "sbni", unit); 236121752Sbrooks ifp->if_init = sbni_init; 237121752Sbrooks ifp->if_start = sbni_start; 238121752Sbrooks ifp->if_ioctl = sbni_ioctl; 239207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 24086752Sfjoe 241121752Sbrooks /* report real baud rate */ 242121752Sbrooks csr0 = sbni_inb(sc, CSR0); 243121752Sbrooks ifp->if_baudrate = 244121752Sbrooks (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 24586752Sfjoe 246180263Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 247180263Sjhb 248180263Sjhb mtx_init(&sc->lock, ifp->if_xname, MTX_NETWORK_LOCK, MTX_DEF); 249180263Sjhb callout_init_mtx(&sc->wch, &sc->lock, 0); 250147256Sbrooks ether_ifattach(ifp, sc->enaddr); 25186752Sfjoe /* device attach does transition from UNCONFIGURED to IDLE state */ 25286752Sfjoe 253263102Sglebius if_printf(ifp, "speed %ju, rxl ", (uintmax_t)ifp->if_baudrate); 25486752Sfjoe if (sc->delta_rxl) 25586752Sfjoe printf("auto\n"); 25686752Sfjoe else 25786752Sfjoe printf("%d (fixed)\n", sc->cur_rxl_index); 258180263Sjhb return (0); 25986752Sfjoe} 26086752Sfjoe 261180263Sjhbvoid 262180263Sjhbsbni_detach(struct sbni_softc *sc) 263180263Sjhb{ 264180263Sjhb 265180263Sjhb SBNI_LOCK(sc); 266180263Sjhb sbni_stop(sc); 267180263Sjhb SBNI_UNLOCK(sc); 268180263Sjhb callout_drain(&sc->wch); 269180263Sjhb ether_ifdetach(sc->ifp); 270180263Sjhb if (sc->irq_handle) 271180263Sjhb bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle); 272180263Sjhb mtx_destroy(&sc->lock); 273180263Sjhb if_free(sc->ifp); 274180263Sjhb} 275180263Sjhb 276180263Sjhbvoid 277180263Sjhbsbni_release_resources(struct sbni_softc *sc) 278180263Sjhb{ 279180263Sjhb 280180263Sjhb if (sc->irq_res) 281180263Sjhb bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 282180263Sjhb sc->irq_res); 283180263Sjhb if (sc->io_res && sc->io_off == 0) 284180263Sjhb bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid, 285180263Sjhb sc->io_res); 286180263Sjhb} 287180263Sjhb 28886752Sfjoe/* -------------------------------------------------------------------------- */ 28986752Sfjoe 29086752Sfjoestatic void 29186752Sfjoesbni_init(void *xsc) 29286752Sfjoe{ 29386752Sfjoe struct sbni_softc *sc; 294180263Sjhb 295180263Sjhb sc = (struct sbni_softc *)xsc; 296180263Sjhb SBNI_LOCK(sc); 297180263Sjhb sbni_init_locked(sc); 298180263Sjhb SBNI_UNLOCK(sc); 299180263Sjhb} 300180263Sjhb 301180263Sjhbstatic void 302180263Sjhbsbni_init_locked(struct sbni_softc *sc) 303180263Sjhb{ 30486752Sfjoe struct ifnet *ifp; 30586752Sfjoe 306147256Sbrooks ifp = sc->ifp; 30786752Sfjoe 30886752Sfjoe /* 30986752Sfjoe * kludge to avoid multiple initialization when more than once 31086752Sfjoe * protocols configured 31186752Sfjoe */ 312148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 31386752Sfjoe return; 31486752Sfjoe 31586752Sfjoe card_start(sc); 316180263Sjhb callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); 31786752Sfjoe 318148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 319148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 32086752Sfjoe 32186752Sfjoe /* attempt to start output */ 322180263Sjhb sbni_start_locked(ifp); 32386752Sfjoe} 32486752Sfjoe 32586752Sfjoestatic void 32686752Sfjoesbni_start(struct ifnet *ifp) 32786752Sfjoe{ 32886752Sfjoe struct sbni_softc *sc = ifp->if_softc; 329180263Sjhb 330180263Sjhb SBNI_LOCK(sc); 331180263Sjhb sbni_start_locked(ifp); 332180263Sjhb SBNI_UNLOCK(sc); 333180263Sjhb} 334180263Sjhb 335180263Sjhbstatic void 336180263Sjhbsbni_start_locked(struct ifnet *ifp) 337180263Sjhb{ 338180263Sjhb struct sbni_softc *sc = ifp->if_softc; 339180263Sjhb 34086752Sfjoe if (sc->tx_frameno == 0) 34186752Sfjoe prepare_to_send(sc); 34286752Sfjoe} 34386752Sfjoe 34486752Sfjoe 34586752Sfjoestatic void 34686752Sfjoesbni_stop(struct sbni_softc *sc) 34786752Sfjoe{ 34886752Sfjoe sbni_outb(sc, CSR0, 0); 34986752Sfjoe drop_xmit_queue(sc); 35086752Sfjoe 35186752Sfjoe if (sc->rx_buf_p) { 35286752Sfjoe m_freem(sc->rx_buf_p); 35386752Sfjoe sc->rx_buf_p = NULL; 35486752Sfjoe } 35586752Sfjoe 356180263Sjhb callout_stop(&sc->wch); 357180263Sjhb sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 35886752Sfjoe} 35986752Sfjoe 36086752Sfjoe/* -------------------------------------------------------------------------- */ 36186752Sfjoe 36286752Sfjoe/* interrupt handler */ 36386752Sfjoe 36486752Sfjoe/* 36586752Sfjoe * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 36686752Sfjoe * be looked as two independent single-channel devices. Every channel seems 36786752Sfjoe * as Ethernet interface but interrupt handler must be common. Really, first 36886752Sfjoe * channel ("master") driver only registers the handler. In it's struct softc 36986752Sfjoe * it has got pointer to "slave" channel's struct softc and handles that's 37086752Sfjoe * interrupts too. 37186752Sfjoe * softc of successfully attached ISA SBNI boards is linked to list. 37286752Sfjoe * While next board driver is initialized, it scans this list. If one 37386752Sfjoe * has found softc with same irq and ioaddr different by 4 then it assumes 37486752Sfjoe * this board to be "master". 37586752Sfjoe */ 37686752Sfjoe 37786752Sfjoevoid 37886752Sfjoesbni_intr(void *arg) 37986752Sfjoe{ 38086752Sfjoe struct sbni_softc *sc; 38186752Sfjoe int repeat; 38286752Sfjoe 38386752Sfjoe sc = (struct sbni_softc *)arg; 38486752Sfjoe 38586752Sfjoe do { 38686752Sfjoe repeat = 0; 387180263Sjhb SBNI_LOCK(sc); 38886752Sfjoe if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 38986752Sfjoe handle_channel(sc); 39086752Sfjoe repeat = 1; 39186752Sfjoe } 392180263Sjhb SBNI_UNLOCK(sc); 393180263Sjhb if (sc->slave_sc) { 394180263Sjhb /* second channel present */ 395180263Sjhb SBNI_LOCK(sc->slave_sc); 396180263Sjhb if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) { 397180263Sjhb handle_channel(sc->slave_sc); 398180263Sjhb repeat = 1; 399180263Sjhb } 400180263Sjhb SBNI_UNLOCK(sc->slave_sc); 40186752Sfjoe } 40286752Sfjoe } while (repeat); 40386752Sfjoe} 40486752Sfjoe 40586752Sfjoe 40686752Sfjoestatic void 40786752Sfjoehandle_channel(struct sbni_softc *sc) 40886752Sfjoe{ 40986752Sfjoe int req_ans; 41086752Sfjoe u_char csr0; 41186752Sfjoe 41286752Sfjoe sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 41386752Sfjoe 41486752Sfjoe sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 41586752Sfjoe for (;;) { 41686752Sfjoe csr0 = sbni_inb(sc, CSR0); 41786752Sfjoe if ((csr0 & (RC_RDY | TR_RDY)) == 0) 41886752Sfjoe break; 41986752Sfjoe 42086752Sfjoe req_ans = !(sc->state & FL_PREV_OK); 42186752Sfjoe 42286752Sfjoe if (csr0 & RC_RDY) 42386752Sfjoe req_ans = recv_frame(sc); 42486752Sfjoe 42586752Sfjoe /* 42686752Sfjoe * TR_RDY always equals 1 here because we have owned the marker, 42786752Sfjoe * and we set TR_REQ when disabled interrupts 42886752Sfjoe */ 42986752Sfjoe csr0 = sbni_inb(sc, CSR0); 43086752Sfjoe if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 431180263Sjhb if_printf(sc->ifp, "internal error!\n"); 43286752Sfjoe 43386752Sfjoe /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 43486752Sfjoe if (req_ans || sc->tx_frameno != 0) 43586752Sfjoe send_frame(sc); 436101393Sfjoe else { 43786752Sfjoe /* send the marker without any data */ 43886752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 439101393Sfjoe } 44086752Sfjoe } 44186752Sfjoe 44286752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 44386752Sfjoe} 44486752Sfjoe 44586752Sfjoe 44686752Sfjoe/* 44786752Sfjoe * Routine returns 1 if it need to acknoweledge received frame. 44886752Sfjoe * Empty frame received without errors won't be acknoweledged. 44986752Sfjoe */ 45086752Sfjoe 45186752Sfjoestatic int 45286752Sfjoerecv_frame(struct sbni_softc *sc) 45386752Sfjoe{ 45486752Sfjoe u_int32_t crc; 45586752Sfjoe u_int framelen, frameno, ack; 45686752Sfjoe u_int is_first, frame_ok; 45786752Sfjoe 45886752Sfjoe crc = CRC32_INITIAL; 45986752Sfjoe if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 460101393Sfjoe frame_ok = framelen > 4 ? 461101393Sfjoe upload_data(sc, framelen, frameno, is_first, crc) : 462101393Sfjoe skip_tail(sc, framelen, crc); 46386752Sfjoe if (frame_ok) 46486752Sfjoe interpret_ack(sc, ack); 465171243Speter } else { 466171243Speter framelen = 0; 46786752Sfjoe frame_ok = 0; 468171243Speter } 46986752Sfjoe 47086752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 47186752Sfjoe if (frame_ok) { 47286752Sfjoe sc->state |= FL_PREV_OK; 47386752Sfjoe if (framelen > 4) 47486752Sfjoe sc->in_stats.all_rx_number++; 47586752Sfjoe } else { 47686752Sfjoe sc->state &= ~FL_PREV_OK; 47786752Sfjoe change_level(sc); 47886752Sfjoe sc->in_stats.all_rx_number++; 47986752Sfjoe sc->in_stats.bad_rx_number++; 48086752Sfjoe } 48186752Sfjoe 48286752Sfjoe return (!frame_ok || framelen > 4); 48386752Sfjoe} 48486752Sfjoe 48586752Sfjoe 48686752Sfjoestatic void 48786752Sfjoesend_frame(struct sbni_softc *sc) 48886752Sfjoe{ 48986752Sfjoe u_int32_t crc; 49086752Sfjoe u_char csr0; 49186752Sfjoe 49286752Sfjoe crc = CRC32_INITIAL; 49386752Sfjoe if (sc->state & FL_NEED_RESEND) { 49486752Sfjoe 49586752Sfjoe /* if frame was sended but not ACK'ed - resend it */ 49686752Sfjoe if (sc->trans_errors) { 49786752Sfjoe sc->trans_errors--; 49886752Sfjoe if (sc->framelen != 0) 49986752Sfjoe sc->in_stats.resend_tx_number++; 50086752Sfjoe } else { 50186752Sfjoe /* cannot xmit with many attempts */ 50286752Sfjoe drop_xmit_queue(sc); 50386752Sfjoe goto do_send; 50486752Sfjoe } 50586752Sfjoe } else 50686752Sfjoe sc->trans_errors = TR_ERROR_COUNT; 50786752Sfjoe 50886752Sfjoe send_frame_header(sc, &crc); 50986752Sfjoe sc->state |= FL_NEED_RESEND; 51086752Sfjoe /* 51186752Sfjoe * FL_NEED_RESEND will be cleared after ACK, but if empty 51286752Sfjoe * frame sended then in prepare_to_send next frame 51386752Sfjoe */ 51486752Sfjoe 51586752Sfjoe 51686752Sfjoe if (sc->framelen) { 51786752Sfjoe download_data(sc, &crc); 51886752Sfjoe sc->in_stats.all_tx_number++; 51986752Sfjoe sc->state |= FL_WAIT_ACK; 52086752Sfjoe } 52186752Sfjoe 52286752Sfjoe sbni_outsb(sc, (u_char *)&crc, sizeof crc); 52386752Sfjoe 52486752Sfjoedo_send: 52586752Sfjoe csr0 = sbni_inb(sc, CSR0); 52686752Sfjoe sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 52786752Sfjoe 52886752Sfjoe if (sc->tx_frameno) { 52986752Sfjoe /* next frame exists - request to send */ 53086752Sfjoe sbni_outb(sc, CSR0, csr0 | TR_REQ); 53186752Sfjoe } 53286752Sfjoe} 53386752Sfjoe 53486752Sfjoe 53586752Sfjoestatic void 53686752Sfjoedownload_data(struct sbni_softc *sc, u_int32_t *crc_p) 53786752Sfjoe{ 53886752Sfjoe struct mbuf *m; 53986752Sfjoe caddr_t data_p; 54086752Sfjoe u_int data_len, pos, slice; 54186752Sfjoe 54286752Sfjoe data_p = NULL; /* initialized to avoid warn */ 54386752Sfjoe pos = 0; 54486752Sfjoe 54586752Sfjoe for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 54686752Sfjoe if (pos + m->m_len > sc->outpos) { 54786752Sfjoe data_len = m->m_len - (sc->outpos - pos); 54886752Sfjoe data_p = mtod(m, caddr_t) + (sc->outpos - pos); 54986752Sfjoe 55086752Sfjoe goto do_copy; 55186752Sfjoe } else 55286752Sfjoe pos += m->m_len; 55386752Sfjoe } 55486752Sfjoe 55586752Sfjoe data_len = 0; 55686752Sfjoe 55786752Sfjoedo_copy: 55886752Sfjoe pos = 0; 55986752Sfjoe do { 56086752Sfjoe if (data_len) { 56186752Sfjoe slice = min(data_len, sc->framelen - pos); 56286752Sfjoe sbni_outsb(sc, data_p, slice); 56386752Sfjoe *crc_p = calc_crc32(*crc_p, data_p, slice); 56486752Sfjoe 56586752Sfjoe pos += slice; 56686752Sfjoe if (data_len -= slice) 56786752Sfjoe data_p += slice; 56886752Sfjoe else { 569101393Sfjoe do { 570101393Sfjoe m = m->m_next; 571101393Sfjoe } while (m != NULL && m->m_len == 0); 57286752Sfjoe 57386752Sfjoe if (m) { 57486752Sfjoe data_len = m->m_len; 57586752Sfjoe data_p = mtod(m, caddr_t); 57686752Sfjoe } 57786752Sfjoe } 57886752Sfjoe } else { 57986752Sfjoe /* frame too short - zero padding */ 58086752Sfjoe 58186752Sfjoe pos = sc->framelen - pos; 58286752Sfjoe while (pos--) { 58386752Sfjoe sbni_outb(sc, DAT, 0); 58486752Sfjoe *crc_p = CRC32(0, *crc_p); 58586752Sfjoe } 58686752Sfjoe return; 58786752Sfjoe } 58886752Sfjoe } while (pos < sc->framelen); 58986752Sfjoe} 59086752Sfjoe 59186752Sfjoe 59286752Sfjoestatic int 59386752Sfjoeupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 59486752Sfjoe u_int is_first, u_int32_t crc) 59586752Sfjoe{ 59686752Sfjoe int frame_ok; 59786752Sfjoe 59886752Sfjoe if (is_first) { 59986752Sfjoe sc->wait_frameno = frameno; 60086752Sfjoe sc->inppos = 0; 60186752Sfjoe } 60286752Sfjoe 60386752Sfjoe if (sc->wait_frameno == frameno) { 60486752Sfjoe 60586752Sfjoe if (sc->inppos + framelen <= ETHER_MAX_LEN) { 60686752Sfjoe frame_ok = append_frame_to_pkt(sc, framelen, crc); 60786752Sfjoe 60886752Sfjoe /* 60986752Sfjoe * if CRC is right but framelen incorrect then transmitter 610298955Spfg * error was occurred... drop entire packet 61186752Sfjoe */ 61286752Sfjoe } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 61386752Sfjoe sc->wait_frameno = 0; 61486752Sfjoe sc->inppos = 0; 615271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 61686752Sfjoe /* now skip all frames until is_first != 0 */ 61786752Sfjoe } 61886752Sfjoe } else 61986752Sfjoe frame_ok = skip_tail(sc, framelen, crc); 62086752Sfjoe 62186752Sfjoe if (is_first && !frame_ok) { 62286752Sfjoe /* 62386752Sfjoe * Frame has been violated, but we have stored 62486752Sfjoe * is_first already... Drop entire packet. 62586752Sfjoe */ 62686752Sfjoe sc->wait_frameno = 0; 627271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 62886752Sfjoe } 62986752Sfjoe 63086752Sfjoe return (frame_ok); 63186752Sfjoe} 63286752Sfjoe 63386752Sfjoe 63486752Sfjoestatic __inline void send_complete(struct sbni_softc *); 63586752Sfjoe 63686752Sfjoestatic __inline void 63786752Sfjoesend_complete(struct sbni_softc *sc) 63886752Sfjoe{ 63986752Sfjoe m_freem(sc->tx_buf_p); 64086752Sfjoe sc->tx_buf_p = NULL; 641271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1); 64286752Sfjoe} 64386752Sfjoe 64486752Sfjoe 64586752Sfjoestatic void 64686752Sfjoeinterpret_ack(struct sbni_softc *sc, u_int ack) 64786752Sfjoe{ 64886752Sfjoe if (ack == FRAME_SENT_OK) { 64986752Sfjoe sc->state &= ~FL_NEED_RESEND; 65086752Sfjoe 65186752Sfjoe if (sc->state & FL_WAIT_ACK) { 65286752Sfjoe sc->outpos += sc->framelen; 65386752Sfjoe 654101393Sfjoe if (--sc->tx_frameno) { 655101393Sfjoe sc->framelen = min( 656101393Sfjoe sc->maxframe, sc->pktlen - sc->outpos); 657101393Sfjoe } else { 65886752Sfjoe send_complete(sc); 65986752Sfjoe prepare_to_send(sc); 66086752Sfjoe } 66186752Sfjoe } 66286752Sfjoe } 66386752Sfjoe 66486752Sfjoe sc->state &= ~FL_WAIT_ACK; 66586752Sfjoe} 66686752Sfjoe 66786752Sfjoe 66886752Sfjoe/* 66986752Sfjoe * Glue received frame with previous fragments of packet. 67086752Sfjoe * Indicate packet when last frame would be accepted. 67186752Sfjoe */ 67286752Sfjoe 67386752Sfjoestatic int 67486752Sfjoeappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 67586752Sfjoe{ 67686752Sfjoe caddr_t p; 67786752Sfjoe 67886752Sfjoe if (sc->inppos + framelen > ETHER_MAX_LEN) 67986752Sfjoe return (0); 68086752Sfjoe 68186752Sfjoe if (!sc->rx_buf_p && !get_rx_buf(sc)) 68286752Sfjoe return (0); 68386752Sfjoe 68486752Sfjoe p = sc->rx_buf_p->m_data + sc->inppos; 68586752Sfjoe sbni_insb(sc, p, framelen); 68686752Sfjoe if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 68786752Sfjoe return (0); 68886752Sfjoe 68986752Sfjoe sc->inppos += framelen - 4; 69086752Sfjoe if (--sc->wait_frameno == 0) { /* last frame received */ 69186752Sfjoe indicate_pkt(sc); 692271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 69386752Sfjoe } 69486752Sfjoe 69586752Sfjoe return (1); 69686752Sfjoe} 69786752Sfjoe 69886752Sfjoe 69986752Sfjoe/* 70086752Sfjoe * Prepare to start output on adapter. Current priority must be set to splimp 70186752Sfjoe * before this routine is called. 70286752Sfjoe * Transmitter will be actually activated when marker has been accepted. 70386752Sfjoe */ 70486752Sfjoe 70586752Sfjoestatic void 70686752Sfjoeprepare_to_send(struct sbni_softc *sc) 70786752Sfjoe{ 70886752Sfjoe struct mbuf *m; 70986752Sfjoe u_int len; 71086752Sfjoe 71186752Sfjoe /* sc->tx_buf_p == NULL here! */ 71286752Sfjoe if (sc->tx_buf_p) 71386752Sfjoe printf("sbni: memory leak!\n"); 71486752Sfjoe 71586752Sfjoe sc->outpos = 0; 71686752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 71786752Sfjoe 71886752Sfjoe for (;;) { 719147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p); 72086752Sfjoe if (!sc->tx_buf_p) { 72186752Sfjoe /* nothing to transmit... */ 72286752Sfjoe sc->pktlen = 0; 72386752Sfjoe sc->tx_frameno = 0; 72486752Sfjoe sc->framelen = 0; 725148887Srwatson sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 72686752Sfjoe return; 72786752Sfjoe } 72886752Sfjoe 72986752Sfjoe for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 73086752Sfjoe len += m->m_len; 73186752Sfjoe 73286752Sfjoe if (len != 0) 73386752Sfjoe break; 73486752Sfjoe m_freem(sc->tx_buf_p); 73586752Sfjoe } 73686752Sfjoe 73786752Sfjoe if (len < SBNI_MIN_LEN) 73886752Sfjoe len = SBNI_MIN_LEN; 73986752Sfjoe 74086752Sfjoe sc->pktlen = len; 741298646Spfg sc->tx_frameno = howmany(len, sc->maxframe); 74286752Sfjoe sc->framelen = min(len, sc->maxframe); 74386752Sfjoe 74486752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 745148887Srwatson sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 746147256Sbrooks BPF_MTAP(sc->ifp, sc->tx_buf_p); 74786752Sfjoe} 74886752Sfjoe 74986752Sfjoe 75086752Sfjoestatic void 75186752Sfjoedrop_xmit_queue(struct sbni_softc *sc) 75286752Sfjoe{ 75386752Sfjoe struct mbuf *m; 75486752Sfjoe 75586752Sfjoe if (sc->tx_buf_p) { 75686752Sfjoe m_freem(sc->tx_buf_p); 75786752Sfjoe sc->tx_buf_p = NULL; 758271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 75986752Sfjoe } 76086752Sfjoe 76186752Sfjoe for (;;) { 762147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, m); 76386752Sfjoe if (m == NULL) 76486752Sfjoe break; 76586752Sfjoe m_freem(m); 766271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 76786752Sfjoe } 76886752Sfjoe 76986752Sfjoe sc->tx_frameno = 0; 77086752Sfjoe sc->framelen = 0; 77186752Sfjoe sc->outpos = 0; 77286752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 773148887Srwatson sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 77486752Sfjoe} 77586752Sfjoe 77686752Sfjoe 77786752Sfjoestatic void 77886752Sfjoesend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 77986752Sfjoe{ 78086752Sfjoe u_int32_t crc; 78186752Sfjoe u_int len_field; 78286752Sfjoe u_char value; 78386752Sfjoe 78486752Sfjoe crc = *crc_p; 78586752Sfjoe len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 78686752Sfjoe 78786752Sfjoe if (sc->state & FL_NEED_RESEND) 78886752Sfjoe len_field |= FRAME_RETRY; /* non-first attempt... */ 78986752Sfjoe 79086752Sfjoe if (sc->outpos == 0) 79186752Sfjoe len_field |= FRAME_FIRST; 79286752Sfjoe 79386752Sfjoe len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 79486752Sfjoe sbni_outb(sc, DAT, SBNI_SIG); 79586752Sfjoe 79686752Sfjoe value = (u_char)len_field; 79786752Sfjoe sbni_outb(sc, DAT, value); 79886752Sfjoe crc = CRC32(value, crc); 79986752Sfjoe value = (u_char)(len_field >> 8); 80086752Sfjoe sbni_outb(sc, DAT, value); 80186752Sfjoe crc = CRC32(value, crc); 80286752Sfjoe 80386752Sfjoe sbni_outb(sc, DAT, sc->tx_frameno); 80486752Sfjoe crc = CRC32(sc->tx_frameno, crc); 80586752Sfjoe sbni_outb(sc, DAT, 0); 80686752Sfjoe crc = CRC32(0, crc); 80786752Sfjoe *crc_p = crc; 80886752Sfjoe} 80986752Sfjoe 81086752Sfjoe 81186752Sfjoe/* 81286752Sfjoe * if frame tail not needed (incorrect number or received twice), 81386752Sfjoe * it won't store, but CRC will be calculated 81486752Sfjoe */ 81586752Sfjoe 81686752Sfjoestatic int 81786752Sfjoeskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 81886752Sfjoe{ 81986752Sfjoe while (tail_len--) 82086752Sfjoe crc = CRC32(sbni_inb(sc, DAT), crc); 82186752Sfjoe 82286752Sfjoe return (crc == CRC32_REMAINDER); 82386752Sfjoe} 82486752Sfjoe 82586752Sfjoe 82686752Sfjoestatic int 82786752Sfjoecheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 82886752Sfjoe u_int *ack, u_int *is_first, u_int32_t *crc_p) 82986752Sfjoe{ 83086752Sfjoe u_int32_t crc; 83186752Sfjoe u_char value; 83286752Sfjoe 83386752Sfjoe crc = *crc_p; 83486752Sfjoe if (sbni_inb(sc, DAT) != SBNI_SIG) 83586752Sfjoe return (0); 83686752Sfjoe 83786752Sfjoe value = sbni_inb(sc, DAT); 83886752Sfjoe *framelen = (u_int)value; 83986752Sfjoe crc = CRC32(value, crc); 84086752Sfjoe value = sbni_inb(sc, DAT); 84186752Sfjoe *framelen |= ((u_int)value) << 8; 84286752Sfjoe crc = CRC32(value, crc); 84386752Sfjoe 84486752Sfjoe *ack = *framelen & FRAME_ACK_MASK; 84586752Sfjoe *is_first = (*framelen & FRAME_FIRST) != 0; 84686752Sfjoe 84786752Sfjoe if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 84886752Sfjoe return (0); 84986752Sfjoe 85086752Sfjoe value = sbni_inb(sc, DAT); 85186752Sfjoe *frameno = (u_int)value; 85286752Sfjoe crc = CRC32(value, crc); 85386752Sfjoe 85486752Sfjoe crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 85586752Sfjoe *framelen -= 2; 85686752Sfjoe 85786752Sfjoe *crc_p = crc; 85886752Sfjoe return (1); 85986752Sfjoe} 86086752Sfjoe 86186752Sfjoe 86286752Sfjoestatic int 86386752Sfjoeget_rx_buf(struct sbni_softc *sc) 86486752Sfjoe{ 86586752Sfjoe struct mbuf *m; 86686752Sfjoe 867243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 86886752Sfjoe if (m == NULL) { 869147256Sbrooks if_printf(sc->ifp, "cannot allocate header mbuf\n"); 87086752Sfjoe return (0); 87186752Sfjoe } 87286752Sfjoe 87386752Sfjoe /* 87486752Sfjoe * We always put the received packet in a single buffer - 87586752Sfjoe * either with just an mbuf header or in a cluster attached 87686752Sfjoe * to the header. The +2 is to compensate for the alignment 87786752Sfjoe * fixup below. 87886752Sfjoe */ 87986752Sfjoe if (ETHER_MAX_LEN + 2 > MHLEN) { 88086752Sfjoe /* Attach an mbuf cluster */ 881276750Srwatson if (!(MCLGET(m, M_NOWAIT))) { 88286752Sfjoe m_freem(m); 88386752Sfjoe return (0); 88486752Sfjoe } 88586752Sfjoe } 88686752Sfjoe m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 88786752Sfjoe 88886752Sfjoe /* 88986752Sfjoe * The +2 is to longword align the start of the real packet. 89086752Sfjoe * (sizeof ether_header == 14) 89186752Sfjoe * This is important for NFS. 89286752Sfjoe */ 89386752Sfjoe m_adj(m, 2); 89486752Sfjoe sc->rx_buf_p = m; 89586752Sfjoe return (1); 89686752Sfjoe} 89786752Sfjoe 89886752Sfjoe 89986752Sfjoestatic void 90086752Sfjoeindicate_pkt(struct sbni_softc *sc) 90186752Sfjoe{ 902147256Sbrooks struct ifnet *ifp = sc->ifp; 90386752Sfjoe struct mbuf *m; 90486752Sfjoe 90586752Sfjoe m = sc->rx_buf_p; 906106937Ssam m->m_pkthdr.rcvif = ifp; 90786752Sfjoe m->m_pkthdr.len = m->m_len = sc->inppos; 908180263Sjhb sc->rx_buf_p = NULL; 90986752Sfjoe 910180263Sjhb SBNI_UNLOCK(sc); 911106937Ssam (*ifp->if_input)(ifp, m); 912180263Sjhb SBNI_LOCK(sc); 91386752Sfjoe} 91486752Sfjoe 91586752Sfjoe/* -------------------------------------------------------------------------- */ 91686752Sfjoe 91786752Sfjoe/* 91886752Sfjoe * Routine checks periodically wire activity and regenerates marker if 91986752Sfjoe * connect was inactive for a long time. 92086752Sfjoe */ 92186752Sfjoe 92286752Sfjoestatic void 92386752Sfjoesbni_timeout(void *xsc) 92486752Sfjoe{ 92586752Sfjoe struct sbni_softc *sc; 92686752Sfjoe u_char csr0; 92786752Sfjoe 92886752Sfjoe sc = (struct sbni_softc *)xsc; 929180263Sjhb SBNI_ASSERT_LOCKED(sc); 93086752Sfjoe 93186752Sfjoe csr0 = sbni_inb(sc, CSR0); 93286752Sfjoe if (csr0 & RC_CHK) { 93386752Sfjoe 93486752Sfjoe if (sc->timer_ticks) { 93586752Sfjoe if (csr0 & (RC_RDY | BU_EMP)) 93686752Sfjoe /* receiving not active */ 93786752Sfjoe sc->timer_ticks--; 93886752Sfjoe } else { 93986752Sfjoe sc->in_stats.timeout_number++; 94086752Sfjoe if (sc->delta_rxl) 94186752Sfjoe timeout_change_level(sc); 94286752Sfjoe 94386752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 94486752Sfjoe csr0 = sbni_inb(sc, CSR0); 94586752Sfjoe } 94686752Sfjoe } 94786752Sfjoe 948180263Sjhb sbni_outb(sc, CSR0, csr0 | RC_CHK); 949180263Sjhb callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); 95086752Sfjoe} 95186752Sfjoe 95286752Sfjoe/* -------------------------------------------------------------------------- */ 95386752Sfjoe 95486752Sfjoestatic void 95586752Sfjoecard_start(struct sbni_softc *sc) 95686752Sfjoe{ 95786752Sfjoe sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 95886752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 95986752Sfjoe sc->state |= FL_PREV_OK; 96086752Sfjoe 96186752Sfjoe sc->inppos = 0; 96286752Sfjoe sc->wait_frameno = 0; 96386752Sfjoe 96486752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 96586752Sfjoe sbni_outb(sc, CSR0, EN_INT); 96686752Sfjoe} 96786752Sfjoe 96886752Sfjoe/* -------------------------------------------------------------------------- */ 96986752Sfjoe 97086752Sfjoestatic u_char rxl_tab[] = { 97186752Sfjoe 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 97286752Sfjoe 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 97386752Sfjoe}; 97486752Sfjoe 97586752Sfjoe#define SIZE_OF_TIMEOUT_RXL_TAB 4 97686752Sfjoestatic u_char timeout_rxl_tab[] = { 97786752Sfjoe 0x03, 0x05, 0x08, 0x0b 97886752Sfjoe}; 97986752Sfjoe 98086752Sfjoestatic void 98186752Sfjoeset_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 98286752Sfjoe{ 98386752Sfjoe if (flags.fixed_rxl) { 98486752Sfjoe sc->delta_rxl = 0; /* disable receive level autodetection */ 98586752Sfjoe sc->cur_rxl_index = flags.rxl; 98686752Sfjoe } else { 98786752Sfjoe sc->delta_rxl = DEF_RXL_DELTA; 98886752Sfjoe sc->cur_rxl_index = DEF_RXL; 98986752Sfjoe } 99086752Sfjoe 99186752Sfjoe sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 99286752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 99386752Sfjoe sc->maxframe = DEFAULT_FRAME_LEN; 99486752Sfjoe 99586752Sfjoe /* 99686752Sfjoe * generate Ethernet address (0x00ff01xxxxxx) 99786752Sfjoe */ 998147256Sbrooks *(u_int16_t *) sc->enaddr = htons(0x00ff); 999101400Sfjoe if (flags.mac_addr) { 1000147256Sbrooks *(u_int32_t *) (sc->enaddr + 2) = 1001101400Sfjoe htonl(flags.mac_addr | 0x01000000); 1002101400Sfjoe } else { 1003147256Sbrooks *(u_char *) (sc->enaddr + 2) = 0x01; 1004147256Sbrooks read_random(sc->enaddr + 3, 3); 100586752Sfjoe } 100686752Sfjoe} 100786752Sfjoe 100886752Sfjoe 100986752Sfjoe#ifdef SBNI_DUAL_COMPOUND 1010180263Sjhbvoid 1011180263Sjhbsbni_add(struct sbni_softc *sc) 1012180263Sjhb{ 101386752Sfjoe 1014180263Sjhb mtx_lock(&headlist_lock); 1015180263Sjhb sc->link = sbni_headlist; 1016180263Sjhb sbni_headlist = sc; 1017180263Sjhb mtx_unlock(&headlist_lock); 1018180263Sjhb} 1019180263Sjhb 102086752Sfjoestruct sbni_softc * 102186752Sfjoeconnect_to_master(struct sbni_softc *sc) 102286752Sfjoe{ 1023101400Sfjoe struct sbni_softc *p, *p_prev; 102486752Sfjoe 1025180263Sjhb mtx_lock(&headlist_lock); 1026101400Sfjoe for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { 1027101400Sfjoe if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || 1028101400Sfjoe rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { 1029101400Sfjoe p->slave_sc = sc; 1030101400Sfjoe if (p_prev) 1031101400Sfjoe p_prev->link = p->link; 1032101400Sfjoe else 1033101400Sfjoe sbni_headlist = p->link; 1034180263Sjhb mtx_unlock(&headlist_lock); 1035101400Sfjoe return p; 103686752Sfjoe } 103786752Sfjoe } 1038180263Sjhb mtx_unlock(&headlist_lock); 103986752Sfjoe 104086752Sfjoe return (NULL); 104186752Sfjoe} 104286752Sfjoe 104386752Sfjoe#endif /* SBNI_DUAL_COMPOUND */ 104486752Sfjoe 104586752Sfjoe 104686752Sfjoe/* Receive level auto-selection */ 104786752Sfjoe 104886752Sfjoestatic void 104986752Sfjoechange_level(struct sbni_softc *sc) 105086752Sfjoe{ 105186752Sfjoe if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 105286752Sfjoe return; 105386752Sfjoe 105486752Sfjoe if (sc->cur_rxl_index == 0) 105586752Sfjoe sc->delta_rxl = 1; 105686752Sfjoe else if (sc->cur_rxl_index == 15) 105786752Sfjoe sc->delta_rxl = -1; 105886752Sfjoe else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 105986752Sfjoe sc->delta_rxl = -sc->delta_rxl; 106086752Sfjoe 106186752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 106286752Sfjoe sbni_inb(sc, CSR0); /* it needed for PCI cards */ 106386752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 106486752Sfjoe 106586752Sfjoe sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 106686752Sfjoe sc->cur_rxl_rcvd = 0; 106786752Sfjoe} 106886752Sfjoe 106986752Sfjoe 107086752Sfjoestatic void 107186752Sfjoetimeout_change_level(struct sbni_softc *sc) 107286752Sfjoe{ 107386752Sfjoe sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 107486752Sfjoe if (++sc->timeout_rxl >= 4) 107586752Sfjoe sc->timeout_rxl = 0; 107686752Sfjoe 107786752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 107886752Sfjoe sbni_inb(sc, CSR0); 107986752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 108086752Sfjoe 108186752Sfjoe sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 108286752Sfjoe sc->cur_rxl_rcvd = 0; 108386752Sfjoe} 108486752Sfjoe 108586752Sfjoe/* -------------------------------------------------------------------------- */ 108686752Sfjoe 108786752Sfjoe/* 108886752Sfjoe * Process an ioctl request. This code needs some work - it looks 108986752Sfjoe * pretty ugly. 109086752Sfjoe */ 109186752Sfjoe 109286752Sfjoestatic int 109386752Sfjoesbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 109486752Sfjoe{ 109586752Sfjoe struct sbni_softc *sc; 109686752Sfjoe struct ifreq *ifr; 109793593Sjhb struct thread *td; 109886752Sfjoe struct sbni_in_stats *in_stats; 109986752Sfjoe struct sbni_flags flags; 1100180263Sjhb int error; 110186752Sfjoe 110286752Sfjoe sc = ifp->if_softc; 110386752Sfjoe ifr = (struct ifreq *)data; 110493593Sjhb td = curthread; 110586752Sfjoe error = 0; 110686752Sfjoe 110786752Sfjoe switch (command) { 110886752Sfjoe case SIOCSIFFLAGS: 110986752Sfjoe /* 111086752Sfjoe * If the interface is marked up and stopped, then start it. 111186752Sfjoe * If it is marked down and running, then stop it. 111286752Sfjoe */ 1113180263Sjhb SBNI_LOCK(sc); 111486752Sfjoe if (ifp->if_flags & IFF_UP) { 1115148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1116180263Sjhb sbni_init_locked(sc); 111786752Sfjoe } else { 1118148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 111986752Sfjoe sbni_stop(sc); 112086752Sfjoe } 112186752Sfjoe } 1122180263Sjhb SBNI_UNLOCK(sc); 112386752Sfjoe break; 112486752Sfjoe 112586752Sfjoe case SIOCADDMULTI: 112686752Sfjoe case SIOCDELMULTI: 112786752Sfjoe /* 112886752Sfjoe * Multicast list has changed; set the hardware filter 112986752Sfjoe * accordingly. 113086752Sfjoe */ 113186752Sfjoe error = 0; 113286752Sfjoe /* if (ifr == NULL) 113386752Sfjoe error = EAFNOSUPPORT; */ 113486752Sfjoe break; 113586752Sfjoe 113686752Sfjoe /* 113786752Sfjoe * SBNI specific ioctl 113886752Sfjoe */ 113986752Sfjoe case SIOCGHWFLAGS: /* get flags */ 1140180263Sjhb SBNI_LOCK(sc); 1141152315Sru bcopy((caddr_t)IF_LLADDR(sc->ifp)+3, (caddr_t) &flags, 3); 114286752Sfjoe flags.rxl = sc->cur_rxl_index; 114386752Sfjoe flags.rate = sc->csr1.rate; 114486752Sfjoe flags.fixed_rxl = (sc->delta_rxl == 0); 114586752Sfjoe flags.fixed_rate = 1; 1146180263Sjhb SBNI_UNLOCK(sc); 1147332161Sbrooks bcopy(&flags, &ifr->ifr_ifru, sizeof(flags)); 114886752Sfjoe break; 114986752Sfjoe 115086752Sfjoe case SIOCGINSTATS: 1151180263Sjhb in_stats = malloc(sizeof(struct sbni_in_stats), M_DEVBUF, 1152180263Sjhb M_WAITOK); 1153180263Sjhb SBNI_LOCK(sc); 1154180263Sjhb bcopy(&sc->in_stats, in_stats, sizeof(struct sbni_in_stats)); 1155180263Sjhb SBNI_UNLOCK(sc); 1156337909Sbrooks error = copyout(in_stats, ifr_data_get_ptr(ifr), 1157180263Sjhb sizeof(struct sbni_in_stats)); 1158180263Sjhb free(in_stats, M_DEVBUF); 115986752Sfjoe break; 116086752Sfjoe 116186752Sfjoe case SIOCSHWFLAGS: /* set flags */ 116286752Sfjoe /* root only */ 1163164033Srwatson error = priv_check(td, PRIV_DRIVER); 116486752Sfjoe if (error) 116586752Sfjoe break; 1166332161Sbrooks bcopy(&ifr->ifr_ifru, &flags, sizeof(flags)); 1167180263Sjhb SBNI_LOCK(sc); 116886752Sfjoe if (flags.fixed_rxl) { 116986752Sfjoe sc->delta_rxl = 0; 117086752Sfjoe sc->cur_rxl_index = flags.rxl; 117186752Sfjoe } else { 117286752Sfjoe sc->delta_rxl = DEF_RXL_DELTA; 117386752Sfjoe sc->cur_rxl_index = DEF_RXL; 117486752Sfjoe } 117586752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 117686752Sfjoe sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 117786752Sfjoe if (flags.mac_addr) 117886752Sfjoe bcopy((caddr_t) &flags, 1179152315Sru (caddr_t) IF_LLADDR(sc->ifp)+3, 3); 118086752Sfjoe 118186752Sfjoe /* Don't be afraid... */ 118286752Sfjoe sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 1183180263Sjhb SBNI_UNLOCK(sc); 118486752Sfjoe break; 118586752Sfjoe 118686752Sfjoe case SIOCRINSTATS: 1187180263Sjhb SBNI_LOCK(sc); 1188164033Srwatson if (!(error = priv_check(td, PRIV_DRIVER))) /* root only */ 118986752Sfjoe bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 1190180263Sjhb SBNI_UNLOCK(sc); 119186752Sfjoe break; 119286752Sfjoe 119386752Sfjoe default: 1194106937Ssam error = ether_ioctl(ifp, command, data); 1195106937Ssam break; 119686752Sfjoe } 119786752Sfjoe 119886752Sfjoe return (error); 119986752Sfjoe} 120086752Sfjoe 120186752Sfjoe/* -------------------------------------------------------------------------- */ 120286752Sfjoe 120386752Sfjoestatic u_int32_t 120486752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len) 120586752Sfjoe{ 120686752Sfjoe while (len--) 120786752Sfjoe crc = CRC32(*p++, crc); 120886752Sfjoe 120986752Sfjoe return (crc); 121086752Sfjoe} 121186752Sfjoe 1212103844Salfredstatic u_int32_t crc32tab[] __aligned(8) = { 121386752Sfjoe 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 121486752Sfjoe 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 121586752Sfjoe 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 121686752Sfjoe 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 121786752Sfjoe 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 121886752Sfjoe 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 121986752Sfjoe 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 122086752Sfjoe 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 122186752Sfjoe 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 122286752Sfjoe 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 122386752Sfjoe 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 122486752Sfjoe 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 122586752Sfjoe 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 122686752Sfjoe 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 122786752Sfjoe 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 122886752Sfjoe 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 122986752Sfjoe 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 123086752Sfjoe 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 123186752Sfjoe 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 123286752Sfjoe 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 123386752Sfjoe 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 123486752Sfjoe 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 123586752Sfjoe 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 123686752Sfjoe 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 123786752Sfjoe 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 123886752Sfjoe 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 123986752Sfjoe 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 124086752Sfjoe 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 124186752Sfjoe 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 124286752Sfjoe 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 124386752Sfjoe 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 124486752Sfjoe 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 124586752Sfjoe 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 124686752Sfjoe 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 124786752Sfjoe 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 124886752Sfjoe 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 124986752Sfjoe 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 125086752Sfjoe 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 125186752Sfjoe 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 125286752Sfjoe 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 125386752Sfjoe 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 125486752Sfjoe 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 125586752Sfjoe 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 125686752Sfjoe 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 125786752Sfjoe 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 125886752Sfjoe 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 125986752Sfjoe 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 126086752Sfjoe 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 126186752Sfjoe 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 126286752Sfjoe 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 126386752Sfjoe 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 126486752Sfjoe 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 126586752Sfjoe 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 126686752Sfjoe 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 126786752Sfjoe 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 126886752Sfjoe 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 126986752Sfjoe 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 127086752Sfjoe 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 127186752Sfjoe 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 127286752Sfjoe 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 127386752Sfjoe 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 127486752Sfjoe 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 127586752Sfjoe 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 127686752Sfjoe 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 127786752Sfjoe}; 1278