if_sbni.c revision 257176
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 257176 2013-10-26 17:58:36Z 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> 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 253126966Smdodd if_printf(ifp, "speed %ld, rxl ", 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 61086752Sfjoe * error was occured... drop entire packet 61186752Sfjoe */ 61286752Sfjoe } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 61386752Sfjoe sc->wait_frameno = 0; 61486752Sfjoe sc->inppos = 0; 615147256Sbrooks sc->ifp->if_ierrors++; 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; 627147256Sbrooks sc->ifp->if_ierrors++; 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; 641147256Sbrooks sc->ifp->if_opackets++; 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); 692147256Sbrooks sc->ifp->if_ipackets++; 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; 74186752Sfjoe sc->tx_frameno = (len + sc->maxframe - 1) / 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; 758147256Sbrooks sc->ifp->if_oerrors++; 75986752Sfjoe } 76086752Sfjoe 76186752Sfjoe for (;;) { 762147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, m); 76386752Sfjoe if (m == NULL) 76486752Sfjoe break; 76586752Sfjoe m_freem(m); 766147256Sbrooks sc->ifp->if_oerrors++; 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 */ 881243857Sglebius MCLGET(m, M_NOWAIT); 88286752Sfjoe if ((m->m_flags & M_EXT) == 0) { 88386752Sfjoe m_freem(m); 88486752Sfjoe return (0); 88586752Sfjoe } 88686752Sfjoe } 88786752Sfjoe m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 88886752Sfjoe 88986752Sfjoe /* 89086752Sfjoe * The +2 is to longword align the start of the real packet. 89186752Sfjoe * (sizeof ether_header == 14) 89286752Sfjoe * This is important for NFS. 89386752Sfjoe */ 89486752Sfjoe m_adj(m, 2); 89586752Sfjoe sc->rx_buf_p = m; 89686752Sfjoe return (1); 89786752Sfjoe} 89886752Sfjoe 89986752Sfjoe 90086752Sfjoestatic void 90186752Sfjoeindicate_pkt(struct sbni_softc *sc) 90286752Sfjoe{ 903147256Sbrooks struct ifnet *ifp = sc->ifp; 90486752Sfjoe struct mbuf *m; 90586752Sfjoe 90686752Sfjoe m = sc->rx_buf_p; 907106937Ssam m->m_pkthdr.rcvif = ifp; 90886752Sfjoe m->m_pkthdr.len = m->m_len = sc->inppos; 909180263Sjhb sc->rx_buf_p = NULL; 91086752Sfjoe 911180263Sjhb SBNI_UNLOCK(sc); 912106937Ssam (*ifp->if_input)(ifp, m); 913180263Sjhb SBNI_LOCK(sc); 91486752Sfjoe} 91586752Sfjoe 91686752Sfjoe/* -------------------------------------------------------------------------- */ 91786752Sfjoe 91886752Sfjoe/* 91986752Sfjoe * Routine checks periodically wire activity and regenerates marker if 92086752Sfjoe * connect was inactive for a long time. 92186752Sfjoe */ 92286752Sfjoe 92386752Sfjoestatic void 92486752Sfjoesbni_timeout(void *xsc) 92586752Sfjoe{ 92686752Sfjoe struct sbni_softc *sc; 92786752Sfjoe u_char csr0; 92886752Sfjoe 92986752Sfjoe sc = (struct sbni_softc *)xsc; 930180263Sjhb SBNI_ASSERT_LOCKED(sc); 93186752Sfjoe 93286752Sfjoe csr0 = sbni_inb(sc, CSR0); 93386752Sfjoe if (csr0 & RC_CHK) { 93486752Sfjoe 93586752Sfjoe if (sc->timer_ticks) { 93686752Sfjoe if (csr0 & (RC_RDY | BU_EMP)) 93786752Sfjoe /* receiving not active */ 93886752Sfjoe sc->timer_ticks--; 93986752Sfjoe } else { 94086752Sfjoe sc->in_stats.timeout_number++; 94186752Sfjoe if (sc->delta_rxl) 94286752Sfjoe timeout_change_level(sc); 94386752Sfjoe 94486752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 94586752Sfjoe csr0 = sbni_inb(sc, CSR0); 94686752Sfjoe } 94786752Sfjoe } 94886752Sfjoe 949180263Sjhb sbni_outb(sc, CSR0, csr0 | RC_CHK); 950180263Sjhb callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); 95186752Sfjoe} 95286752Sfjoe 95386752Sfjoe/* -------------------------------------------------------------------------- */ 95486752Sfjoe 95586752Sfjoestatic void 95686752Sfjoecard_start(struct sbni_softc *sc) 95786752Sfjoe{ 95886752Sfjoe sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 95986752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 96086752Sfjoe sc->state |= FL_PREV_OK; 96186752Sfjoe 96286752Sfjoe sc->inppos = 0; 96386752Sfjoe sc->wait_frameno = 0; 96486752Sfjoe 96586752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 96686752Sfjoe sbni_outb(sc, CSR0, EN_INT); 96786752Sfjoe} 96886752Sfjoe 96986752Sfjoe/* -------------------------------------------------------------------------- */ 97086752Sfjoe 97186752Sfjoestatic u_char rxl_tab[] = { 97286752Sfjoe 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 97386752Sfjoe 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 97486752Sfjoe}; 97586752Sfjoe 97686752Sfjoe#define SIZE_OF_TIMEOUT_RXL_TAB 4 97786752Sfjoestatic u_char timeout_rxl_tab[] = { 97886752Sfjoe 0x03, 0x05, 0x08, 0x0b 97986752Sfjoe}; 98086752Sfjoe 98186752Sfjoestatic void 98286752Sfjoeset_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 98386752Sfjoe{ 98486752Sfjoe if (flags.fixed_rxl) { 98586752Sfjoe sc->delta_rxl = 0; /* disable receive level autodetection */ 98686752Sfjoe sc->cur_rxl_index = flags.rxl; 98786752Sfjoe } else { 98886752Sfjoe sc->delta_rxl = DEF_RXL_DELTA; 98986752Sfjoe sc->cur_rxl_index = DEF_RXL; 99086752Sfjoe } 99186752Sfjoe 99286752Sfjoe sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 99386752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 99486752Sfjoe sc->maxframe = DEFAULT_FRAME_LEN; 99586752Sfjoe 99686752Sfjoe /* 99786752Sfjoe * generate Ethernet address (0x00ff01xxxxxx) 99886752Sfjoe */ 999147256Sbrooks *(u_int16_t *) sc->enaddr = htons(0x00ff); 1000101400Sfjoe if (flags.mac_addr) { 1001147256Sbrooks *(u_int32_t *) (sc->enaddr + 2) = 1002101400Sfjoe htonl(flags.mac_addr | 0x01000000); 1003101400Sfjoe } else { 1004147256Sbrooks *(u_char *) (sc->enaddr + 2) = 0x01; 1005147256Sbrooks read_random(sc->enaddr + 3, 3); 100686752Sfjoe } 100786752Sfjoe} 100886752Sfjoe 100986752Sfjoe 101086752Sfjoe#ifdef SBNI_DUAL_COMPOUND 1011180263Sjhbvoid 1012180263Sjhbsbni_add(struct sbni_softc *sc) 1013180263Sjhb{ 101486752Sfjoe 1015180263Sjhb mtx_lock(&headlist_lock); 1016180263Sjhb sc->link = sbni_headlist; 1017180263Sjhb sbni_headlist = sc; 1018180263Sjhb mtx_unlock(&headlist_lock); 1019180263Sjhb} 1020180263Sjhb 102186752Sfjoestruct sbni_softc * 102286752Sfjoeconnect_to_master(struct sbni_softc *sc) 102386752Sfjoe{ 1024101400Sfjoe struct sbni_softc *p, *p_prev; 102586752Sfjoe 1026180263Sjhb mtx_lock(&headlist_lock); 1027101400Sfjoe for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { 1028101400Sfjoe if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || 1029101400Sfjoe rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { 1030101400Sfjoe p->slave_sc = sc; 1031101400Sfjoe if (p_prev) 1032101400Sfjoe p_prev->link = p->link; 1033101400Sfjoe else 1034101400Sfjoe sbni_headlist = p->link; 1035180263Sjhb mtx_unlock(&headlist_lock); 1036101400Sfjoe return p; 103786752Sfjoe } 103886752Sfjoe } 1039180263Sjhb mtx_unlock(&headlist_lock); 104086752Sfjoe 104186752Sfjoe return (NULL); 104286752Sfjoe} 104386752Sfjoe 104486752Sfjoe#endif /* SBNI_DUAL_COMPOUND */ 104586752Sfjoe 104686752Sfjoe 104786752Sfjoe/* Receive level auto-selection */ 104886752Sfjoe 104986752Sfjoestatic void 105086752Sfjoechange_level(struct sbni_softc *sc) 105186752Sfjoe{ 105286752Sfjoe if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 105386752Sfjoe return; 105486752Sfjoe 105586752Sfjoe if (sc->cur_rxl_index == 0) 105686752Sfjoe sc->delta_rxl = 1; 105786752Sfjoe else if (sc->cur_rxl_index == 15) 105886752Sfjoe sc->delta_rxl = -1; 105986752Sfjoe else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 106086752Sfjoe sc->delta_rxl = -sc->delta_rxl; 106186752Sfjoe 106286752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 106386752Sfjoe sbni_inb(sc, CSR0); /* it needed for PCI cards */ 106486752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 106586752Sfjoe 106686752Sfjoe sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 106786752Sfjoe sc->cur_rxl_rcvd = 0; 106886752Sfjoe} 106986752Sfjoe 107086752Sfjoe 107186752Sfjoestatic void 107286752Sfjoetimeout_change_level(struct sbni_softc *sc) 107386752Sfjoe{ 107486752Sfjoe sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 107586752Sfjoe if (++sc->timeout_rxl >= 4) 107686752Sfjoe sc->timeout_rxl = 0; 107786752Sfjoe 107886752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 107986752Sfjoe sbni_inb(sc, CSR0); 108086752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 108186752Sfjoe 108286752Sfjoe sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 108386752Sfjoe sc->cur_rxl_rcvd = 0; 108486752Sfjoe} 108586752Sfjoe 108686752Sfjoe/* -------------------------------------------------------------------------- */ 108786752Sfjoe 108886752Sfjoe/* 108986752Sfjoe * Process an ioctl request. This code needs some work - it looks 109086752Sfjoe * pretty ugly. 109186752Sfjoe */ 109286752Sfjoe 109386752Sfjoestatic int 109486752Sfjoesbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 109586752Sfjoe{ 109686752Sfjoe struct sbni_softc *sc; 109786752Sfjoe struct ifreq *ifr; 109893593Sjhb struct thread *td; 109986752Sfjoe struct sbni_in_stats *in_stats; 110086752Sfjoe struct sbni_flags flags; 1101180263Sjhb int error; 110286752Sfjoe 110386752Sfjoe sc = ifp->if_softc; 110486752Sfjoe ifr = (struct ifreq *)data; 110593593Sjhb td = curthread; 110686752Sfjoe error = 0; 110786752Sfjoe 110886752Sfjoe switch (command) { 110986752Sfjoe case SIOCSIFFLAGS: 111086752Sfjoe /* 111186752Sfjoe * If the interface is marked up and stopped, then start it. 111286752Sfjoe * If it is marked down and running, then stop it. 111386752Sfjoe */ 1114180263Sjhb SBNI_LOCK(sc); 111586752Sfjoe if (ifp->if_flags & IFF_UP) { 1116148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1117180263Sjhb sbni_init_locked(sc); 111886752Sfjoe } else { 1119148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 112086752Sfjoe sbni_stop(sc); 112186752Sfjoe } 112286752Sfjoe } 1123180263Sjhb SBNI_UNLOCK(sc); 112486752Sfjoe break; 112586752Sfjoe 112686752Sfjoe case SIOCADDMULTI: 112786752Sfjoe case SIOCDELMULTI: 112886752Sfjoe /* 112986752Sfjoe * Multicast list has changed; set the hardware filter 113086752Sfjoe * accordingly. 113186752Sfjoe */ 113286752Sfjoe error = 0; 113386752Sfjoe /* if (ifr == NULL) 113486752Sfjoe error = EAFNOSUPPORT; */ 113586752Sfjoe break; 113686752Sfjoe 113786752Sfjoe /* 113886752Sfjoe * SBNI specific ioctl 113986752Sfjoe */ 114086752Sfjoe case SIOCGHWFLAGS: /* get flags */ 1141180263Sjhb SBNI_LOCK(sc); 1142152315Sru bcopy((caddr_t)IF_LLADDR(sc->ifp)+3, (caddr_t) &flags, 3); 114386752Sfjoe flags.rxl = sc->cur_rxl_index; 114486752Sfjoe flags.rate = sc->csr1.rate; 114586752Sfjoe flags.fixed_rxl = (sc->delta_rxl == 0); 114686752Sfjoe flags.fixed_rate = 1; 1147180263Sjhb SBNI_UNLOCK(sc); 114886752Sfjoe ifr->ifr_data = *(caddr_t*) &flags; 114986752Sfjoe break; 115086752Sfjoe 115186752Sfjoe case SIOCGINSTATS: 1152180263Sjhb in_stats = malloc(sizeof(struct sbni_in_stats), M_DEVBUF, 1153180263Sjhb M_WAITOK); 1154180263Sjhb SBNI_LOCK(sc); 1155180263Sjhb bcopy(&sc->in_stats, in_stats, sizeof(struct sbni_in_stats)); 1156180263Sjhb SBNI_UNLOCK(sc); 1157180263Sjhb error = copyout(ifr->ifr_data, in_stats, 1158180263Sjhb sizeof(struct sbni_in_stats)); 1159180263Sjhb free(in_stats, M_DEVBUF); 116086752Sfjoe break; 116186752Sfjoe 116286752Sfjoe case SIOCSHWFLAGS: /* set flags */ 116386752Sfjoe /* root only */ 1164164033Srwatson error = priv_check(td, PRIV_DRIVER); 116586752Sfjoe if (error) 116686752Sfjoe break; 116786752Sfjoe flags = *(struct sbni_flags*)&ifr->ifr_data; 1168180263Sjhb SBNI_LOCK(sc); 116986752Sfjoe if (flags.fixed_rxl) { 117086752Sfjoe sc->delta_rxl = 0; 117186752Sfjoe sc->cur_rxl_index = flags.rxl; 117286752Sfjoe } else { 117386752Sfjoe sc->delta_rxl = DEF_RXL_DELTA; 117486752Sfjoe sc->cur_rxl_index = DEF_RXL; 117586752Sfjoe } 117686752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 117786752Sfjoe sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 117886752Sfjoe if (flags.mac_addr) 117986752Sfjoe bcopy((caddr_t) &flags, 1180152315Sru (caddr_t) IF_LLADDR(sc->ifp)+3, 3); 118186752Sfjoe 118286752Sfjoe /* Don't be afraid... */ 118386752Sfjoe sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 1184180263Sjhb SBNI_UNLOCK(sc); 118586752Sfjoe break; 118686752Sfjoe 118786752Sfjoe case SIOCRINSTATS: 1188180263Sjhb SBNI_LOCK(sc); 1189164033Srwatson if (!(error = priv_check(td, PRIV_DRIVER))) /* root only */ 119086752Sfjoe bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 1191180263Sjhb SBNI_UNLOCK(sc); 119286752Sfjoe break; 119386752Sfjoe 119486752Sfjoe default: 1195106937Ssam error = ether_ioctl(ifp, command, data); 1196106937Ssam break; 119786752Sfjoe } 119886752Sfjoe 119986752Sfjoe return (error); 120086752Sfjoe} 120186752Sfjoe 120286752Sfjoe/* -------------------------------------------------------------------------- */ 120386752Sfjoe 120486752Sfjoestatic u_int32_t 120586752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len) 120686752Sfjoe{ 120786752Sfjoe while (len--) 120886752Sfjoe crc = CRC32(*p++, crc); 120986752Sfjoe 121086752Sfjoe return (crc); 121186752Sfjoe} 121286752Sfjoe 1213103844Salfredstatic u_int32_t crc32tab[] __aligned(8) = { 121486752Sfjoe 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 121586752Sfjoe 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 121686752Sfjoe 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 121786752Sfjoe 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 121886752Sfjoe 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 121986752Sfjoe 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 122086752Sfjoe 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 122186752Sfjoe 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 122286752Sfjoe 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 122386752Sfjoe 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 122486752Sfjoe 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 122586752Sfjoe 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 122686752Sfjoe 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 122786752Sfjoe 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 122886752Sfjoe 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 122986752Sfjoe 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 123086752Sfjoe 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 123186752Sfjoe 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 123286752Sfjoe 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 123386752Sfjoe 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 123486752Sfjoe 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 123586752Sfjoe 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 123686752Sfjoe 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 123786752Sfjoe 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 123886752Sfjoe 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 123986752Sfjoe 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 124086752Sfjoe 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 124186752Sfjoe 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 124286752Sfjoe 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 124386752Sfjoe 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 124486752Sfjoe 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 124586752Sfjoe 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 124686752Sfjoe 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 124786752Sfjoe 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 124886752Sfjoe 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 124986752Sfjoe 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 125086752Sfjoe 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 125186752Sfjoe 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 125286752Sfjoe 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 125386752Sfjoe 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 125486752Sfjoe 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 125586752Sfjoe 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 125686752Sfjoe 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 125786752Sfjoe 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 125886752Sfjoe 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 125986752Sfjoe 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 126086752Sfjoe 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 126186752Sfjoe 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 126286752Sfjoe 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 126386752Sfjoe 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 126486752Sfjoe 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 126586752Sfjoe 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 126686752Sfjoe 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 126786752Sfjoe 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 126886752Sfjoe 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 126986752Sfjoe 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 127086752Sfjoe 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 127186752Sfjoe 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 127286752Sfjoe 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 127386752Sfjoe 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 127486752Sfjoe 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 127586752Sfjoe 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 127686752Sfjoe 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 127786752Sfjoe 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 127886752Sfjoe}; 1279