if_sbni.c revision 243857
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: head/sys/dev/sbni/if_sbni.c 243857 2012-12-04 09:32:43Z glebius $"); 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> 82152315Sru#include <net/if_dl.h> 8386752Sfjoe#include <net/ethernet.h> 8486752Sfjoe#include <net/bpf.h> 85147256Sbrooks#include <net/if_types.h> 8686752Sfjoe 8786752Sfjoe#include <dev/sbni/if_sbnireg.h> 8886752Sfjoe#include <dev/sbni/if_sbnivar.h> 8986752Sfjoe 9086752Sfjoestatic void sbni_init(void *); 91180263Sjhbstatic void sbni_init_locked(struct sbni_softc *); 9286752Sfjoestatic void sbni_start(struct ifnet *); 93180263Sjhbstatic void sbni_start_locked(struct ifnet *); 9486752Sfjoestatic int sbni_ioctl(struct ifnet *, u_long, caddr_t); 9586752Sfjoestatic void sbni_stop(struct sbni_softc *); 9686752Sfjoestatic void handle_channel(struct sbni_softc *); 9786752Sfjoe 9886752Sfjoestatic void card_start(struct sbni_softc *); 9986752Sfjoestatic int recv_frame(struct sbni_softc *); 10086752Sfjoestatic void send_frame(struct sbni_softc *); 10186752Sfjoestatic int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 10286752Sfjoestatic int skip_tail(struct sbni_softc *, u_int, u_int32_t); 10386752Sfjoestatic void interpret_ack(struct sbni_softc *, u_int); 10486752Sfjoestatic void download_data(struct sbni_softc *, u_int32_t *); 10586752Sfjoestatic void prepare_to_send(struct sbni_softc *); 10686752Sfjoestatic void drop_xmit_queue(struct sbni_softc *); 10786752Sfjoestatic int get_rx_buf(struct sbni_softc *); 10886752Sfjoestatic void indicate_pkt(struct sbni_softc *); 10986752Sfjoestatic void change_level(struct sbni_softc *); 11086752Sfjoestatic int check_fhdr(struct sbni_softc *, u_int *, u_int *, 11186752Sfjoe u_int *, u_int *, u_int32_t *); 11286752Sfjoestatic int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 11386752Sfjoestatic void timeout_change_level(struct sbni_softc *); 11486752Sfjoestatic void send_frame_header(struct sbni_softc *, u_int32_t *); 11586752Sfjoestatic void set_initial_values(struct sbni_softc *, struct sbni_flags); 11686752Sfjoe 11786752Sfjoestatic u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 11886752Sfjoestatic timeout_t sbni_timeout; 11986752Sfjoe 12086752Sfjoestatic __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 12186752Sfjoestatic __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 12286752Sfjoestatic __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 12386752Sfjoestatic __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 12486752Sfjoe 12586752Sfjoestatic u_int32_t crc32tab[]; 12686752Sfjoe 12786752Sfjoe#ifdef SBNI_DUAL_COMPOUND 128180263Sjhbstatic struct mtx headlist_lock; 129180263SjhbMTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF); 130180263Sjhbstatic struct sbni_softc *sbni_headlist; 13186752Sfjoe#endif 13286752Sfjoe 13386752Sfjoe/* -------------------------------------------------------------------------- */ 13486752Sfjoe 13586752Sfjoestatic __inline u_char 13686752Sfjoesbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 13786752Sfjoe{ 138101400Sfjoe return bus_space_read_1( 139101400Sfjoe rman_get_bustag(sc->io_res), 140101400Sfjoe rman_get_bushandle(sc->io_res), 141101400Sfjoe sc->io_off + reg); 14286752Sfjoe} 14386752Sfjoe 14486752Sfjoestatic __inline void 14586752Sfjoesbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 14686752Sfjoe{ 147101400Sfjoe bus_space_write_1( 148101400Sfjoe rman_get_bustag(sc->io_res), 149101400Sfjoe rman_get_bushandle(sc->io_res), 150101400Sfjoe sc->io_off + reg, value); 15186752Sfjoe} 15286752Sfjoe 15386752Sfjoestatic __inline void 15486752Sfjoesbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 15586752Sfjoe{ 156101400Sfjoe bus_space_read_multi_1( 157101400Sfjoe rman_get_bustag(sc->io_res), 158101400Sfjoe rman_get_bushandle(sc->io_res), 159101400Sfjoe sc->io_off + DAT, to, len); 16086752Sfjoe} 16186752Sfjoe 16286752Sfjoestatic __inline void 16386752Sfjoesbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 16486752Sfjoe{ 165101400Sfjoe bus_space_write_multi_1( 166101400Sfjoe rman_get_bustag(sc->io_res), 167101400Sfjoe rman_get_bushandle(sc->io_res), 168101400Sfjoe sc->io_off + DAT, from, len); 16986752Sfjoe} 17086752Sfjoe 17186752Sfjoe 17286752Sfjoe/* 17386752Sfjoe Valid combinations in CSR0 (for probing): 17486752Sfjoe 17586752Sfjoe VALID_DECODER 0000,0011,1011,1010 17686752Sfjoe 17786752Sfjoe ; 0 ; - 17886752Sfjoe TR_REQ ; 1 ; + 17986752Sfjoe TR_RDY ; 2 ; - 18086752Sfjoe TR_RDY TR_REQ ; 3 ; + 18186752Sfjoe BU_EMP ; 4 ; + 18286752Sfjoe BU_EMP TR_REQ ; 5 ; + 18386752Sfjoe BU_EMP TR_RDY ; 6 ; - 18486752Sfjoe BU_EMP TR_RDY TR_REQ ; 7 ; + 18586752Sfjoe RC_RDY ; 8 ; + 18686752Sfjoe RC_RDY TR_REQ ; 9 ; + 18786752Sfjoe RC_RDY TR_RDY ; 10 ; - 18886752Sfjoe RC_RDY TR_RDY TR_REQ ; 11 ; - 18986752Sfjoe RC_RDY BU_EMP ; 12 ; - 19086752Sfjoe RC_RDY BU_EMP TR_REQ ; 13 ; - 19186752Sfjoe RC_RDY BU_EMP TR_RDY ; 14 ; - 19286752Sfjoe RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 19386752Sfjoe*/ 19486752Sfjoe 19586752Sfjoe#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 19686752Sfjoe 19786752Sfjoe 19886752Sfjoeint 19986752Sfjoesbni_probe(struct sbni_softc *sc) 20086752Sfjoe{ 20186752Sfjoe u_char csr0; 20286752Sfjoe 20386752Sfjoe csr0 = sbni_inb(sc, CSR0); 20486752Sfjoe if (csr0 != 0xff && csr0 != 0x00) { 20586752Sfjoe csr0 &= ~EN_INT; 20686752Sfjoe if (csr0 & BU_EMP) 20786752Sfjoe csr0 |= EN_INT; 20886752Sfjoe 20986752Sfjoe if (VALID_DECODER & (1 << (csr0 >> 4))) 21086752Sfjoe return (0); 21186752Sfjoe } 21286752Sfjoe 21386752Sfjoe return (ENXIO); 21486752Sfjoe} 21586752Sfjoe 21686752Sfjoe 21786752Sfjoe/* 21886752Sfjoe * Install interface into kernel networking data structures 21986752Sfjoe */ 220180263Sjhbint 22186752Sfjoesbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 22286752Sfjoe{ 22386752Sfjoe struct ifnet *ifp; 22486752Sfjoe u_char csr0; 22586752Sfjoe 226147256Sbrooks ifp = sc->ifp = if_alloc(IFT_ETHER); 227147256Sbrooks if (ifp == NULL) 228180263Sjhb return (ENOMEM); 22986752Sfjoe sbni_outb(sc, CSR0, 0); 23086752Sfjoe set_initial_values(sc, flags); 23186752Sfjoe 232121752Sbrooks /* Initialize ifnet structure */ 233121752Sbrooks ifp->if_softc = sc; 234121816Sbrooks if_initname(ifp, "sbni", unit); 235121752Sbrooks ifp->if_init = sbni_init; 236121752Sbrooks ifp->if_start = sbni_start; 237121752Sbrooks ifp->if_ioctl = sbni_ioctl; 238207554Ssobomax IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 23986752Sfjoe 240121752Sbrooks /* report real baud rate */ 241121752Sbrooks csr0 = sbni_inb(sc, CSR0); 242121752Sbrooks ifp->if_baudrate = 243121752Sbrooks (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 24486752Sfjoe 245180263Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 246180263Sjhb 247180263Sjhb mtx_init(&sc->lock, ifp->if_xname, MTX_NETWORK_LOCK, MTX_DEF); 248180263Sjhb callout_init_mtx(&sc->wch, &sc->lock, 0); 249147256Sbrooks ether_ifattach(ifp, sc->enaddr); 25086752Sfjoe /* device attach does transition from UNCONFIGURED to IDLE state */ 25186752Sfjoe 252126966Smdodd if_printf(ifp, "speed %ld, rxl ", ifp->if_baudrate); 25386752Sfjoe if (sc->delta_rxl) 25486752Sfjoe printf("auto\n"); 25586752Sfjoe else 25686752Sfjoe printf("%d (fixed)\n", sc->cur_rxl_index); 257180263Sjhb return (0); 25886752Sfjoe} 25986752Sfjoe 260180263Sjhbvoid 261180263Sjhbsbni_detach(struct sbni_softc *sc) 262180263Sjhb{ 263180263Sjhb 264180263Sjhb SBNI_LOCK(sc); 265180263Sjhb sbni_stop(sc); 266180263Sjhb SBNI_UNLOCK(sc); 267180263Sjhb callout_drain(&sc->wch); 268180263Sjhb ether_ifdetach(sc->ifp); 269180263Sjhb if (sc->irq_handle) 270180263Sjhb bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle); 271180263Sjhb mtx_destroy(&sc->lock); 272180263Sjhb if_free(sc->ifp); 273180263Sjhb} 274180263Sjhb 275180263Sjhbvoid 276180263Sjhbsbni_release_resources(struct sbni_softc *sc) 277180263Sjhb{ 278180263Sjhb 279180263Sjhb if (sc->irq_res) 280180263Sjhb bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 281180263Sjhb sc->irq_res); 282180263Sjhb if (sc->io_res && sc->io_off == 0) 283180263Sjhb bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid, 284180263Sjhb sc->io_res); 285180263Sjhb} 286180263Sjhb 28786752Sfjoe/* -------------------------------------------------------------------------- */ 28886752Sfjoe 28986752Sfjoestatic void 29086752Sfjoesbni_init(void *xsc) 29186752Sfjoe{ 29286752Sfjoe struct sbni_softc *sc; 293180263Sjhb 294180263Sjhb sc = (struct sbni_softc *)xsc; 295180263Sjhb SBNI_LOCK(sc); 296180263Sjhb sbni_init_locked(sc); 297180263Sjhb SBNI_UNLOCK(sc); 298180263Sjhb} 299180263Sjhb 300180263Sjhbstatic void 301180263Sjhbsbni_init_locked(struct sbni_softc *sc) 302180263Sjhb{ 30386752Sfjoe struct ifnet *ifp; 30486752Sfjoe 305147256Sbrooks ifp = sc->ifp; 30686752Sfjoe 30786752Sfjoe /* 30886752Sfjoe * kludge to avoid multiple initialization when more than once 30986752Sfjoe * protocols configured 31086752Sfjoe */ 311148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 31286752Sfjoe return; 31386752Sfjoe 31486752Sfjoe card_start(sc); 315180263Sjhb callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); 31686752Sfjoe 317148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 318148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 31986752Sfjoe 32086752Sfjoe /* attempt to start output */ 321180263Sjhb sbni_start_locked(ifp); 32286752Sfjoe} 32386752Sfjoe 32486752Sfjoestatic void 32586752Sfjoesbni_start(struct ifnet *ifp) 32686752Sfjoe{ 32786752Sfjoe struct sbni_softc *sc = ifp->if_softc; 328180263Sjhb 329180263Sjhb SBNI_LOCK(sc); 330180263Sjhb sbni_start_locked(ifp); 331180263Sjhb SBNI_UNLOCK(sc); 332180263Sjhb} 333180263Sjhb 334180263Sjhbstatic void 335180263Sjhbsbni_start_locked(struct ifnet *ifp) 336180263Sjhb{ 337180263Sjhb struct sbni_softc *sc = ifp->if_softc; 338180263Sjhb 33986752Sfjoe if (sc->tx_frameno == 0) 34086752Sfjoe prepare_to_send(sc); 34186752Sfjoe} 34286752Sfjoe 34386752Sfjoe 34486752Sfjoestatic void 34586752Sfjoesbni_stop(struct sbni_softc *sc) 34686752Sfjoe{ 34786752Sfjoe sbni_outb(sc, CSR0, 0); 34886752Sfjoe drop_xmit_queue(sc); 34986752Sfjoe 35086752Sfjoe if (sc->rx_buf_p) { 35186752Sfjoe m_freem(sc->rx_buf_p); 35286752Sfjoe sc->rx_buf_p = NULL; 35386752Sfjoe } 35486752Sfjoe 355180263Sjhb callout_stop(&sc->wch); 356180263Sjhb sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 35786752Sfjoe} 35886752Sfjoe 35986752Sfjoe/* -------------------------------------------------------------------------- */ 36086752Sfjoe 36186752Sfjoe/* interrupt handler */ 36286752Sfjoe 36386752Sfjoe/* 36486752Sfjoe * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 36586752Sfjoe * be looked as two independent single-channel devices. Every channel seems 36686752Sfjoe * as Ethernet interface but interrupt handler must be common. Really, first 36786752Sfjoe * channel ("master") driver only registers the handler. In it's struct softc 36886752Sfjoe * it has got pointer to "slave" channel's struct softc and handles that's 36986752Sfjoe * interrupts too. 37086752Sfjoe * softc of successfully attached ISA SBNI boards is linked to list. 37186752Sfjoe * While next board driver is initialized, it scans this list. If one 37286752Sfjoe * has found softc with same irq and ioaddr different by 4 then it assumes 37386752Sfjoe * this board to be "master". 37486752Sfjoe */ 37586752Sfjoe 37686752Sfjoevoid 37786752Sfjoesbni_intr(void *arg) 37886752Sfjoe{ 37986752Sfjoe struct sbni_softc *sc; 38086752Sfjoe int repeat; 38186752Sfjoe 38286752Sfjoe sc = (struct sbni_softc *)arg; 38386752Sfjoe 38486752Sfjoe do { 38586752Sfjoe repeat = 0; 386180263Sjhb SBNI_LOCK(sc); 38786752Sfjoe if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 38886752Sfjoe handle_channel(sc); 38986752Sfjoe repeat = 1; 39086752Sfjoe } 391180263Sjhb SBNI_UNLOCK(sc); 392180263Sjhb if (sc->slave_sc) { 393180263Sjhb /* second channel present */ 394180263Sjhb SBNI_LOCK(sc->slave_sc); 395180263Sjhb if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) { 396180263Sjhb handle_channel(sc->slave_sc); 397180263Sjhb repeat = 1; 398180263Sjhb } 399180263Sjhb SBNI_UNLOCK(sc->slave_sc); 40086752Sfjoe } 40186752Sfjoe } while (repeat); 40286752Sfjoe} 40386752Sfjoe 40486752Sfjoe 40586752Sfjoestatic void 40686752Sfjoehandle_channel(struct sbni_softc *sc) 40786752Sfjoe{ 40886752Sfjoe int req_ans; 40986752Sfjoe u_char csr0; 41086752Sfjoe 41186752Sfjoe sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 41286752Sfjoe 41386752Sfjoe sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 41486752Sfjoe for (;;) { 41586752Sfjoe csr0 = sbni_inb(sc, CSR0); 41686752Sfjoe if ((csr0 & (RC_RDY | TR_RDY)) == 0) 41786752Sfjoe break; 41886752Sfjoe 41986752Sfjoe req_ans = !(sc->state & FL_PREV_OK); 42086752Sfjoe 42186752Sfjoe if (csr0 & RC_RDY) 42286752Sfjoe req_ans = recv_frame(sc); 42386752Sfjoe 42486752Sfjoe /* 42586752Sfjoe * TR_RDY always equals 1 here because we have owned the marker, 42686752Sfjoe * and we set TR_REQ when disabled interrupts 42786752Sfjoe */ 42886752Sfjoe csr0 = sbni_inb(sc, CSR0); 42986752Sfjoe if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 430180263Sjhb if_printf(sc->ifp, "internal error!\n"); 43186752Sfjoe 43286752Sfjoe /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 43386752Sfjoe if (req_ans || sc->tx_frameno != 0) 43486752Sfjoe send_frame(sc); 435101393Sfjoe else { 43686752Sfjoe /* send the marker without any data */ 43786752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 438101393Sfjoe } 43986752Sfjoe } 44086752Sfjoe 44186752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 44286752Sfjoe} 44386752Sfjoe 44486752Sfjoe 44586752Sfjoe/* 44686752Sfjoe * Routine returns 1 if it need to acknoweledge received frame. 44786752Sfjoe * Empty frame received without errors won't be acknoweledged. 44886752Sfjoe */ 44986752Sfjoe 45086752Sfjoestatic int 45186752Sfjoerecv_frame(struct sbni_softc *sc) 45286752Sfjoe{ 45386752Sfjoe u_int32_t crc; 45486752Sfjoe u_int framelen, frameno, ack; 45586752Sfjoe u_int is_first, frame_ok; 45686752Sfjoe 45786752Sfjoe crc = CRC32_INITIAL; 45886752Sfjoe if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 459101393Sfjoe frame_ok = framelen > 4 ? 460101393Sfjoe upload_data(sc, framelen, frameno, is_first, crc) : 461101393Sfjoe skip_tail(sc, framelen, crc); 46286752Sfjoe if (frame_ok) 46386752Sfjoe interpret_ack(sc, ack); 464171243Speter } else { 465171243Speter framelen = 0; 46686752Sfjoe frame_ok = 0; 467171243Speter } 46886752Sfjoe 46986752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 47086752Sfjoe if (frame_ok) { 47186752Sfjoe sc->state |= FL_PREV_OK; 47286752Sfjoe if (framelen > 4) 47386752Sfjoe sc->in_stats.all_rx_number++; 47486752Sfjoe } else { 47586752Sfjoe sc->state &= ~FL_PREV_OK; 47686752Sfjoe change_level(sc); 47786752Sfjoe sc->in_stats.all_rx_number++; 47886752Sfjoe sc->in_stats.bad_rx_number++; 47986752Sfjoe } 48086752Sfjoe 48186752Sfjoe return (!frame_ok || framelen > 4); 48286752Sfjoe} 48386752Sfjoe 48486752Sfjoe 48586752Sfjoestatic void 48686752Sfjoesend_frame(struct sbni_softc *sc) 48786752Sfjoe{ 48886752Sfjoe u_int32_t crc; 48986752Sfjoe u_char csr0; 49086752Sfjoe 49186752Sfjoe crc = CRC32_INITIAL; 49286752Sfjoe if (sc->state & FL_NEED_RESEND) { 49386752Sfjoe 49486752Sfjoe /* if frame was sended but not ACK'ed - resend it */ 49586752Sfjoe if (sc->trans_errors) { 49686752Sfjoe sc->trans_errors--; 49786752Sfjoe if (sc->framelen != 0) 49886752Sfjoe sc->in_stats.resend_tx_number++; 49986752Sfjoe } else { 50086752Sfjoe /* cannot xmit with many attempts */ 50186752Sfjoe drop_xmit_queue(sc); 50286752Sfjoe goto do_send; 50386752Sfjoe } 50486752Sfjoe } else 50586752Sfjoe sc->trans_errors = TR_ERROR_COUNT; 50686752Sfjoe 50786752Sfjoe send_frame_header(sc, &crc); 50886752Sfjoe sc->state |= FL_NEED_RESEND; 50986752Sfjoe /* 51086752Sfjoe * FL_NEED_RESEND will be cleared after ACK, but if empty 51186752Sfjoe * frame sended then in prepare_to_send next frame 51286752Sfjoe */ 51386752Sfjoe 51486752Sfjoe 51586752Sfjoe if (sc->framelen) { 51686752Sfjoe download_data(sc, &crc); 51786752Sfjoe sc->in_stats.all_tx_number++; 51886752Sfjoe sc->state |= FL_WAIT_ACK; 51986752Sfjoe } 52086752Sfjoe 52186752Sfjoe sbni_outsb(sc, (u_char *)&crc, sizeof crc); 52286752Sfjoe 52386752Sfjoedo_send: 52486752Sfjoe csr0 = sbni_inb(sc, CSR0); 52586752Sfjoe sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 52686752Sfjoe 52786752Sfjoe if (sc->tx_frameno) { 52886752Sfjoe /* next frame exists - request to send */ 52986752Sfjoe sbni_outb(sc, CSR0, csr0 | TR_REQ); 53086752Sfjoe } 53186752Sfjoe} 53286752Sfjoe 53386752Sfjoe 53486752Sfjoestatic void 53586752Sfjoedownload_data(struct sbni_softc *sc, u_int32_t *crc_p) 53686752Sfjoe{ 53786752Sfjoe struct mbuf *m; 53886752Sfjoe caddr_t data_p; 53986752Sfjoe u_int data_len, pos, slice; 54086752Sfjoe 54186752Sfjoe data_p = NULL; /* initialized to avoid warn */ 54286752Sfjoe pos = 0; 54386752Sfjoe 54486752Sfjoe for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 54586752Sfjoe if (pos + m->m_len > sc->outpos) { 54686752Sfjoe data_len = m->m_len - (sc->outpos - pos); 54786752Sfjoe data_p = mtod(m, caddr_t) + (sc->outpos - pos); 54886752Sfjoe 54986752Sfjoe goto do_copy; 55086752Sfjoe } else 55186752Sfjoe pos += m->m_len; 55286752Sfjoe } 55386752Sfjoe 55486752Sfjoe data_len = 0; 55586752Sfjoe 55686752Sfjoedo_copy: 55786752Sfjoe pos = 0; 55886752Sfjoe do { 55986752Sfjoe if (data_len) { 56086752Sfjoe slice = min(data_len, sc->framelen - pos); 56186752Sfjoe sbni_outsb(sc, data_p, slice); 56286752Sfjoe *crc_p = calc_crc32(*crc_p, data_p, slice); 56386752Sfjoe 56486752Sfjoe pos += slice; 56586752Sfjoe if (data_len -= slice) 56686752Sfjoe data_p += slice; 56786752Sfjoe else { 568101393Sfjoe do { 569101393Sfjoe m = m->m_next; 570101393Sfjoe } while (m != NULL && m->m_len == 0); 57186752Sfjoe 57286752Sfjoe if (m) { 57386752Sfjoe data_len = m->m_len; 57486752Sfjoe data_p = mtod(m, caddr_t); 57586752Sfjoe } 57686752Sfjoe } 57786752Sfjoe } else { 57886752Sfjoe /* frame too short - zero padding */ 57986752Sfjoe 58086752Sfjoe pos = sc->framelen - pos; 58186752Sfjoe while (pos--) { 58286752Sfjoe sbni_outb(sc, DAT, 0); 58386752Sfjoe *crc_p = CRC32(0, *crc_p); 58486752Sfjoe } 58586752Sfjoe return; 58686752Sfjoe } 58786752Sfjoe } while (pos < sc->framelen); 58886752Sfjoe} 58986752Sfjoe 59086752Sfjoe 59186752Sfjoestatic int 59286752Sfjoeupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 59386752Sfjoe u_int is_first, u_int32_t crc) 59486752Sfjoe{ 59586752Sfjoe int frame_ok; 59686752Sfjoe 59786752Sfjoe if (is_first) { 59886752Sfjoe sc->wait_frameno = frameno; 59986752Sfjoe sc->inppos = 0; 60086752Sfjoe } 60186752Sfjoe 60286752Sfjoe if (sc->wait_frameno == frameno) { 60386752Sfjoe 60486752Sfjoe if (sc->inppos + framelen <= ETHER_MAX_LEN) { 60586752Sfjoe frame_ok = append_frame_to_pkt(sc, framelen, crc); 60686752Sfjoe 60786752Sfjoe /* 60886752Sfjoe * if CRC is right but framelen incorrect then transmitter 60986752Sfjoe * error was occured... drop entire packet 61086752Sfjoe */ 61186752Sfjoe } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 61286752Sfjoe sc->wait_frameno = 0; 61386752Sfjoe sc->inppos = 0; 614147256Sbrooks sc->ifp->if_ierrors++; 61586752Sfjoe /* now skip all frames until is_first != 0 */ 61686752Sfjoe } 61786752Sfjoe } else 61886752Sfjoe frame_ok = skip_tail(sc, framelen, crc); 61986752Sfjoe 62086752Sfjoe if (is_first && !frame_ok) { 62186752Sfjoe /* 62286752Sfjoe * Frame has been violated, but we have stored 62386752Sfjoe * is_first already... Drop entire packet. 62486752Sfjoe */ 62586752Sfjoe sc->wait_frameno = 0; 626147256Sbrooks sc->ifp->if_ierrors++; 62786752Sfjoe } 62886752Sfjoe 62986752Sfjoe return (frame_ok); 63086752Sfjoe} 63186752Sfjoe 63286752Sfjoe 63386752Sfjoestatic __inline void send_complete(struct sbni_softc *); 63486752Sfjoe 63586752Sfjoestatic __inline void 63686752Sfjoesend_complete(struct sbni_softc *sc) 63786752Sfjoe{ 63886752Sfjoe m_freem(sc->tx_buf_p); 63986752Sfjoe sc->tx_buf_p = NULL; 640147256Sbrooks sc->ifp->if_opackets++; 64186752Sfjoe} 64286752Sfjoe 64386752Sfjoe 64486752Sfjoestatic void 64586752Sfjoeinterpret_ack(struct sbni_softc *sc, u_int ack) 64686752Sfjoe{ 64786752Sfjoe if (ack == FRAME_SENT_OK) { 64886752Sfjoe sc->state &= ~FL_NEED_RESEND; 64986752Sfjoe 65086752Sfjoe if (sc->state & FL_WAIT_ACK) { 65186752Sfjoe sc->outpos += sc->framelen; 65286752Sfjoe 653101393Sfjoe if (--sc->tx_frameno) { 654101393Sfjoe sc->framelen = min( 655101393Sfjoe sc->maxframe, sc->pktlen - sc->outpos); 656101393Sfjoe } else { 65786752Sfjoe send_complete(sc); 65886752Sfjoe prepare_to_send(sc); 65986752Sfjoe } 66086752Sfjoe } 66186752Sfjoe } 66286752Sfjoe 66386752Sfjoe sc->state &= ~FL_WAIT_ACK; 66486752Sfjoe} 66586752Sfjoe 66686752Sfjoe 66786752Sfjoe/* 66886752Sfjoe * Glue received frame with previous fragments of packet. 66986752Sfjoe * Indicate packet when last frame would be accepted. 67086752Sfjoe */ 67186752Sfjoe 67286752Sfjoestatic int 67386752Sfjoeappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 67486752Sfjoe{ 67586752Sfjoe caddr_t p; 67686752Sfjoe 67786752Sfjoe if (sc->inppos + framelen > ETHER_MAX_LEN) 67886752Sfjoe return (0); 67986752Sfjoe 68086752Sfjoe if (!sc->rx_buf_p && !get_rx_buf(sc)) 68186752Sfjoe return (0); 68286752Sfjoe 68386752Sfjoe p = sc->rx_buf_p->m_data + sc->inppos; 68486752Sfjoe sbni_insb(sc, p, framelen); 68586752Sfjoe if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 68686752Sfjoe return (0); 68786752Sfjoe 68886752Sfjoe sc->inppos += framelen - 4; 68986752Sfjoe if (--sc->wait_frameno == 0) { /* last frame received */ 69086752Sfjoe indicate_pkt(sc); 691147256Sbrooks sc->ifp->if_ipackets++; 69286752Sfjoe } 69386752Sfjoe 69486752Sfjoe return (1); 69586752Sfjoe} 69686752Sfjoe 69786752Sfjoe 69886752Sfjoe/* 69986752Sfjoe * Prepare to start output on adapter. Current priority must be set to splimp 70086752Sfjoe * before this routine is called. 70186752Sfjoe * Transmitter will be actually activated when marker has been accepted. 70286752Sfjoe */ 70386752Sfjoe 70486752Sfjoestatic void 70586752Sfjoeprepare_to_send(struct sbni_softc *sc) 70686752Sfjoe{ 70786752Sfjoe struct mbuf *m; 70886752Sfjoe u_int len; 70986752Sfjoe 71086752Sfjoe /* sc->tx_buf_p == NULL here! */ 71186752Sfjoe if (sc->tx_buf_p) 71286752Sfjoe printf("sbni: memory leak!\n"); 71386752Sfjoe 71486752Sfjoe sc->outpos = 0; 71586752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 71686752Sfjoe 71786752Sfjoe for (;;) { 718147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p); 71986752Sfjoe if (!sc->tx_buf_p) { 72086752Sfjoe /* nothing to transmit... */ 72186752Sfjoe sc->pktlen = 0; 72286752Sfjoe sc->tx_frameno = 0; 72386752Sfjoe sc->framelen = 0; 724148887Srwatson sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 72586752Sfjoe return; 72686752Sfjoe } 72786752Sfjoe 72886752Sfjoe for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 72986752Sfjoe len += m->m_len; 73086752Sfjoe 73186752Sfjoe if (len != 0) 73286752Sfjoe break; 73386752Sfjoe m_freem(sc->tx_buf_p); 73486752Sfjoe } 73586752Sfjoe 73686752Sfjoe if (len < SBNI_MIN_LEN) 73786752Sfjoe len = SBNI_MIN_LEN; 73886752Sfjoe 73986752Sfjoe sc->pktlen = len; 74086752Sfjoe sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe; 74186752Sfjoe sc->framelen = min(len, sc->maxframe); 74286752Sfjoe 74386752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 744148887Srwatson sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 745147256Sbrooks BPF_MTAP(sc->ifp, sc->tx_buf_p); 74686752Sfjoe} 74786752Sfjoe 74886752Sfjoe 74986752Sfjoestatic void 75086752Sfjoedrop_xmit_queue(struct sbni_softc *sc) 75186752Sfjoe{ 75286752Sfjoe struct mbuf *m; 75386752Sfjoe 75486752Sfjoe if (sc->tx_buf_p) { 75586752Sfjoe m_freem(sc->tx_buf_p); 75686752Sfjoe sc->tx_buf_p = NULL; 757147256Sbrooks sc->ifp->if_oerrors++; 75886752Sfjoe } 75986752Sfjoe 76086752Sfjoe for (;;) { 761147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, m); 76286752Sfjoe if (m == NULL) 76386752Sfjoe break; 76486752Sfjoe m_freem(m); 765147256Sbrooks sc->ifp->if_oerrors++; 76686752Sfjoe } 76786752Sfjoe 76886752Sfjoe sc->tx_frameno = 0; 76986752Sfjoe sc->framelen = 0; 77086752Sfjoe sc->outpos = 0; 77186752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 772148887Srwatson sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 77386752Sfjoe} 77486752Sfjoe 77586752Sfjoe 77686752Sfjoestatic void 77786752Sfjoesend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 77886752Sfjoe{ 77986752Sfjoe u_int32_t crc; 78086752Sfjoe u_int len_field; 78186752Sfjoe u_char value; 78286752Sfjoe 78386752Sfjoe crc = *crc_p; 78486752Sfjoe len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 78586752Sfjoe 78686752Sfjoe if (sc->state & FL_NEED_RESEND) 78786752Sfjoe len_field |= FRAME_RETRY; /* non-first attempt... */ 78886752Sfjoe 78986752Sfjoe if (sc->outpos == 0) 79086752Sfjoe len_field |= FRAME_FIRST; 79186752Sfjoe 79286752Sfjoe len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 79386752Sfjoe sbni_outb(sc, DAT, SBNI_SIG); 79486752Sfjoe 79586752Sfjoe value = (u_char)len_field; 79686752Sfjoe sbni_outb(sc, DAT, value); 79786752Sfjoe crc = CRC32(value, crc); 79886752Sfjoe value = (u_char)(len_field >> 8); 79986752Sfjoe sbni_outb(sc, DAT, value); 80086752Sfjoe crc = CRC32(value, crc); 80186752Sfjoe 80286752Sfjoe sbni_outb(sc, DAT, sc->tx_frameno); 80386752Sfjoe crc = CRC32(sc->tx_frameno, crc); 80486752Sfjoe sbni_outb(sc, DAT, 0); 80586752Sfjoe crc = CRC32(0, crc); 80686752Sfjoe *crc_p = crc; 80786752Sfjoe} 80886752Sfjoe 80986752Sfjoe 81086752Sfjoe/* 81186752Sfjoe * if frame tail not needed (incorrect number or received twice), 81286752Sfjoe * it won't store, but CRC will be calculated 81386752Sfjoe */ 81486752Sfjoe 81586752Sfjoestatic int 81686752Sfjoeskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 81786752Sfjoe{ 81886752Sfjoe while (tail_len--) 81986752Sfjoe crc = CRC32(sbni_inb(sc, DAT), crc); 82086752Sfjoe 82186752Sfjoe return (crc == CRC32_REMAINDER); 82286752Sfjoe} 82386752Sfjoe 82486752Sfjoe 82586752Sfjoestatic int 82686752Sfjoecheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 82786752Sfjoe u_int *ack, u_int *is_first, u_int32_t *crc_p) 82886752Sfjoe{ 82986752Sfjoe u_int32_t crc; 83086752Sfjoe u_char value; 83186752Sfjoe 83286752Sfjoe crc = *crc_p; 83386752Sfjoe if (sbni_inb(sc, DAT) != SBNI_SIG) 83486752Sfjoe return (0); 83586752Sfjoe 83686752Sfjoe value = sbni_inb(sc, DAT); 83786752Sfjoe *framelen = (u_int)value; 83886752Sfjoe crc = CRC32(value, crc); 83986752Sfjoe value = sbni_inb(sc, DAT); 84086752Sfjoe *framelen |= ((u_int)value) << 8; 84186752Sfjoe crc = CRC32(value, crc); 84286752Sfjoe 84386752Sfjoe *ack = *framelen & FRAME_ACK_MASK; 84486752Sfjoe *is_first = (*framelen & FRAME_FIRST) != 0; 84586752Sfjoe 84686752Sfjoe if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 84786752Sfjoe return (0); 84886752Sfjoe 84986752Sfjoe value = sbni_inb(sc, DAT); 85086752Sfjoe *frameno = (u_int)value; 85186752Sfjoe crc = CRC32(value, crc); 85286752Sfjoe 85386752Sfjoe crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 85486752Sfjoe *framelen -= 2; 85586752Sfjoe 85686752Sfjoe *crc_p = crc; 85786752Sfjoe return (1); 85886752Sfjoe} 85986752Sfjoe 86086752Sfjoe 86186752Sfjoestatic int 86286752Sfjoeget_rx_buf(struct sbni_softc *sc) 86386752Sfjoe{ 86486752Sfjoe struct mbuf *m; 86586752Sfjoe 866243857Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 86786752Sfjoe if (m == NULL) { 868147256Sbrooks if_printf(sc->ifp, "cannot allocate header mbuf\n"); 86986752Sfjoe return (0); 87086752Sfjoe } 87186752Sfjoe 87286752Sfjoe /* 87386752Sfjoe * We always put the received packet in a single buffer - 87486752Sfjoe * either with just an mbuf header or in a cluster attached 87586752Sfjoe * to the header. The +2 is to compensate for the alignment 87686752Sfjoe * fixup below. 87786752Sfjoe */ 87886752Sfjoe if (ETHER_MAX_LEN + 2 > MHLEN) { 87986752Sfjoe /* Attach an mbuf cluster */ 880243857Sglebius MCLGET(m, M_NOWAIT); 88186752Sfjoe if ((m->m_flags & M_EXT) == 0) { 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); 114786752Sfjoe ifr->ifr_data = *(caddr_t*) &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); 1156180263Sjhb error = copyout(ifr->ifr_data, in_stats, 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; 116686752Sfjoe flags = *(struct sbni_flags*)&ifr->ifr_data; 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