if_sbni.c revision 337909
157429Smarkm/*- 257429Smarkm * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved. 357429Smarkm * Author: Denis I.Timofeev <timofeev@granch.ru> 457429Smarkm * 565668Skris * Redistributon and use in source and binary forms, with or without 660573Skris * modification, are permitted provided that the following conditions 765668Skris * are met: 865668Skris * 1. Redistributions of source code must retain the above copyright 965668Skris * notice unmodified, this list of conditions, and the following 1065668Skris * disclaimer. 1165668Skris * 2. Redistributions in binary form must reproduce the above copyright 1260573Skris * notice, this list of conditions and the following disclaimer in the 1360573Skris * documentation and/or other materials provided with the distribution. 1465668Skris * 1560573Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1665668Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1765668Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1865668Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1965668Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2065668Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2165668Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2265668Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2365668Skris * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY 2465668Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2565668Skris * SUCH DAMAGE. 2665668Skris * 2765668Skris */ 2865668Skris 2965668Skris#include <sys/cdefs.h> 3065668Skris__FBSDID("$FreeBSD: stable/11/sys/dev/sbni/if_sbni.c 337909 2018-08-16 15:27:19Z brooks $"); 3165668Skris 3265668Skris/* 3365668Skris * Device driver for Granch SBNI12 leased line adapters 3465668Skris * 3565668Skris * Revision 2.0.0 1997/08/06 3665668Skris * Initial revision by Alexey Zverev 3760573Skris * 3892555Sdes * Revision 2.0.1 1997/08/11 3965668Skris * Additional internal statistics support (tx statistics) 4065668Skris * 4165668Skris * Revision 2.0.2 1997/11/05 4265668Skris * if_bpf bug has been fixed 4365668Skris * 4465668Skris * Revision 2.0.3 1998/12/20 4565668Skris * Memory leakage has been eliminated in 4665668Skris * the sbni_st and sbni_timeout routines. 4765668Skris * 4865668Skris * Revision 3.0 2000/08/10 by Yaroslav Polyakov 4965668Skris * Support for PCI cards. 4.1 modification. 5065668Skris * 5165668Skris * Revision 3.1 2000/09/12 5265668Skris * Removed extra #defines around bpf functions 5365668Skris * 5465668Skris * Revision 4.0 2000/11/23 by Denis Timofeev 5565668Skris * Completely redesigned the buffer management 5665668Skris * 5765668Skris * Revision 4.1 2001/01/21 5865668Skris * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards 5957429Smarkm * 6057429Smarkm * Written with reference to NE2000 driver developed by David Greenman. 6157429Smarkm */ 62113908Sdes 6357429Smarkm 6476259Sgreen#include <sys/param.h> 6576259Sgreen#include <sys/bus.h> 6676259Sgreen#include <sys/systm.h> 6757429Smarkm#include <sys/socket.h> 6857429Smarkm#include <sys/sockio.h> 6957429Smarkm#include <sys/mbuf.h> 7060573Skris#include <sys/kernel.h> 7160573Skris#include <sys/priv.h> 7260573Skris#include <sys/proc.h> 7365668Skris#include <sys/callout.h> 7465668Skris#include <sys/syslog.h> 7576259Sgreen#include <sys/random.h> 7676259Sgreen 7776259Sgreen#include <machine/bus.h> 7876259Sgreen#include <sys/rman.h> 7976259Sgreen#include <machine/resource.h> 8076259Sgreen 8176259Sgreen#include <net/if.h> 8276259Sgreen#include <net/if_var.h> 8376259Sgreen#include <net/if_dl.h> 8498675Sdes#include <net/ethernet.h> 8560573Skris#include <net/bpf.h> 8669587Sgreen#include <net/if_types.h> 8768700Sgreen 8868700Sgreen#include <dev/sbni/if_sbnireg.h> 8957429Smarkm#include <dev/sbni/if_sbnivar.h> 9057429Smarkm 9157429Smarkmstatic void sbni_init(void *); 9257429Smarkmstatic void sbni_init_locked(struct sbni_softc *); 9357429Smarkmstatic void sbni_start(struct ifnet *); 9457429Smarkmstatic void sbni_start_locked(struct ifnet *); 9557429Smarkmstatic int sbni_ioctl(struct ifnet *, u_long, caddr_t); 9657429Smarkmstatic void sbni_stop(struct sbni_softc *); 9757429Smarkmstatic void handle_channel(struct sbni_softc *); 9857429Smarkm 9957429Smarkmstatic void card_start(struct sbni_softc *); 10057429Smarkmstatic int recv_frame(struct sbni_softc *); 10157429Smarkmstatic void send_frame(struct sbni_softc *); 10257429Smarkmstatic int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 10357429Smarkmstatic int skip_tail(struct sbni_softc *, u_int, u_int32_t); 10457429Smarkmstatic void interpret_ack(struct sbni_softc *, u_int); 10592555Sdesstatic void download_data(struct sbni_softc *, u_int32_t *); 10692555Sdesstatic void prepare_to_send(struct sbni_softc *); 10757429Smarkmstatic void drop_xmit_queue(struct sbni_softc *); 10857429Smarkmstatic int get_rx_buf(struct sbni_softc *); 10957429Smarkmstatic void indicate_pkt(struct sbni_softc *); 11057429Smarkmstatic void change_level(struct sbni_softc *); 11157429Smarkmstatic int check_fhdr(struct sbni_softc *, u_int *, u_int *, 11265668Skris u_int *, u_int *, u_int32_t *); 11365668Skrisstatic int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 11457429Smarkmstatic void timeout_change_level(struct sbni_softc *); 11557429Smarkmstatic void send_frame_header(struct sbni_softc *, u_int32_t *); 11657429Smarkmstatic void set_initial_values(struct sbni_softc *, struct sbni_flags); 11757429Smarkm 11857429Smarkmstatic u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 11957429Smarkmstatic timeout_t sbni_timeout; 12057429Smarkm 12176259Sgreenstatic __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 12276259Sgreenstatic __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 12357429Smarkmstatic __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 12457429Smarkmstatic __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 12576259Sgreen 12676259Sgreenstatic u_int32_t crc32tab[]; 12757429Smarkm 12892555Sdes#ifdef SBNI_DUAL_COMPOUND 12960573Skrisstatic struct mtx headlist_lock; 13060573SkrisMTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF); 13176259Sgreenstatic struct sbni_softc *sbni_headlist; 13276259Sgreen#endif 13357429Smarkm 13457429Smarkm/* -------------------------------------------------------------------------- */ 13557429Smarkm 13692555Sdesstatic __inline u_char 13776259Sgreensbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 13857429Smarkm{ 13957429Smarkm return bus_space_read_1( 14057429Smarkm rman_get_bustag(sc->io_res), 14157429Smarkm rman_get_bushandle(sc->io_res), 14257429Smarkm sc->io_off + reg); 14357429Smarkm} 14457429Smarkm 14557429Smarkmstatic __inline void 14657429Smarkmsbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 14757429Smarkm{ 14892555Sdes bus_space_write_1( 14976259Sgreen rman_get_bustag(sc->io_res), 15057429Smarkm rman_get_bushandle(sc->io_res), 15157429Smarkm sc->io_off + reg, value); 15257429Smarkm} 15357429Smarkm 15457429Smarkmstatic __inline void 15557429Smarkmsbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 15657429Smarkm{ 15757429Smarkm bus_space_read_multi_1( 15857429Smarkm rman_get_bustag(sc->io_res), 15957429Smarkm rman_get_bushandle(sc->io_res), 16057429Smarkm sc->io_off + DAT, to, len); 16192555Sdes} 16257429Smarkm 16357429Smarkmstatic __inline void 16457429Smarkmsbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 16557429Smarkm{ 16657429Smarkm bus_space_write_multi_1( 16757429Smarkm rman_get_bustag(sc->io_res), 16857429Smarkm rman_get_bushandle(sc->io_res), 16957429Smarkm sc->io_off + DAT, from, len); 17057429Smarkm} 17157429Smarkm 17257429Smarkm 17392555Sdes/* 17457429Smarkm Valid combinations in CSR0 (for probing): 17557429Smarkm 17692555Sdes VALID_DECODER 0000,0011,1011,1010 17792555Sdes 17857429Smarkm ; 0 ; - 17957429Smarkm TR_REQ ; 1 ; + 18057429Smarkm TR_RDY ; 2 ; - 18157429Smarkm TR_RDY TR_REQ ; 3 ; + 18257429Smarkm BU_EMP ; 4 ; + 18357429Smarkm BU_EMP TR_REQ ; 5 ; + 18457429Smarkm BU_EMP TR_RDY ; 6 ; - 18592555Sdes BU_EMP TR_RDY TR_REQ ; 7 ; + 18676259Sgreen RC_RDY ; 8 ; + 18757429Smarkm RC_RDY TR_REQ ; 9 ; + 18857429Smarkm RC_RDY TR_RDY ; 10 ; - 18957429Smarkm RC_RDY TR_RDY TR_REQ ; 11 ; - 19057429Smarkm RC_RDY BU_EMP ; 12 ; - 19157429Smarkm RC_RDY BU_EMP TR_REQ ; 13 ; - 19257429Smarkm RC_RDY BU_EMP TR_RDY ; 14 ; - 19357429Smarkm RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 19457429Smarkm*/ 19557429Smarkm 19657429Smarkm#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 19757429Smarkm 19857429Smarkm 19992555Sdesint 20076259Sgreensbni_probe(struct sbni_softc *sc) 20157429Smarkm{ 20257429Smarkm u_char csr0; 20357429Smarkm 20457429Smarkm csr0 = sbni_inb(sc, CSR0); 20557429Smarkm if (csr0 != 0xff && csr0 != 0x00) { 20657429Smarkm csr0 &= ~EN_INT; 20757429Smarkm if (csr0 & BU_EMP) 20857429Smarkm csr0 |= EN_INT; 20957429Smarkm 21057429Smarkm if (VALID_DECODER & (1 << (csr0 >> 4))) 21157429Smarkm return (0); 21257429Smarkm } 21357429Smarkm 21457429Smarkm return (ENXIO); 21557429Smarkm} 21657429Smarkm 21757429Smarkm 21857429Smarkm/* 21957429Smarkm * Install interface into kernel networking data structures 22057429Smarkm */ 22157429Smarkmint 22257429Smarkmsbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 22357429Smarkm{ 22457429Smarkm struct ifnet *ifp; 22557429Smarkm u_char csr0; 22657429Smarkm 22757429Smarkm ifp = sc->ifp = if_alloc(IFT_ETHER); 22857429Smarkm if (ifp == NULL) 22957429Smarkm return (ENOMEM); 23057429Smarkm sbni_outb(sc, CSR0, 0); 23157429Smarkm set_initial_values(sc, flags); 23257429Smarkm 23357429Smarkm /* Initialize ifnet structure */ 23457429Smarkm ifp->if_softc = sc; 23557429Smarkm if_initname(ifp, "sbni", unit); 23676259Sgreen ifp->if_init = sbni_init; 23757429Smarkm ifp->if_start = sbni_start; 23876259Sgreen ifp->if_ioctl = sbni_ioctl; 23957429Smarkm IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); 24057429Smarkm 24157429Smarkm /* report real baud rate */ 24257429Smarkm csr0 = sbni_inb(sc, CSR0); 24357429Smarkm ifp->if_baudrate = 24457429Smarkm (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 24557429Smarkm 24657429Smarkm ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 24757429Smarkm 24857429Smarkm mtx_init(&sc->lock, ifp->if_xname, MTX_NETWORK_LOCK, MTX_DEF); 24957429Smarkm callout_init_mtx(&sc->wch, &sc->lock, 0); 25057429Smarkm ether_ifattach(ifp, sc->enaddr); 25192555Sdes /* device attach does transition from UNCONFIGURED to IDLE state */ 25276259Sgreen 25357429Smarkm if_printf(ifp, "speed %ju, rxl ", (uintmax_t)ifp->if_baudrate); 25476259Sgreen if (sc->delta_rxl) 25557429Smarkm printf("auto\n"); 25657429Smarkm else 25757429Smarkm printf("%d (fixed)\n", sc->cur_rxl_index); 25892555Sdes return (0); 25957429Smarkm} 26057429Smarkm 26157429Smarkmvoid 26257429Smarkmsbni_detach(struct sbni_softc *sc) 26357429Smarkm{ 26457429Smarkm 26557429Smarkm SBNI_LOCK(sc); 26657429Smarkm sbni_stop(sc); 26776259Sgreen SBNI_UNLOCK(sc); 26857429Smarkm callout_drain(&sc->wch); 26957429Smarkm ether_ifdetach(sc->ifp); 27057429Smarkm if (sc->irq_handle) 27157429Smarkm bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle); 27257429Smarkm mtx_destroy(&sc->lock); 27357429Smarkm if_free(sc->ifp); 27457429Smarkm} 27557429Smarkm 27657429Smarkmvoid 27757429Smarkmsbni_release_resources(struct sbni_softc *sc) 27857429Smarkm{ 27957429Smarkm 28057429Smarkm if (sc->irq_res) 28157429Smarkm bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 28257429Smarkm sc->irq_res); 28392555Sdes if (sc->io_res && sc->io_off == 0) 28476259Sgreen bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid, 28557429Smarkm sc->io_res); 28660573Skris} 28757429Smarkm 28860573Skris/* -------------------------------------------------------------------------- */ 28960573Skris 29060573Skrisstatic void 29160573Skrissbni_init(void *xsc) 29257429Smarkm{ 29360573Skris struct sbni_softc *sc; 29460573Skris 29560573Skris sc = (struct sbni_softc *)xsc; 29669587Sgreen SBNI_LOCK(sc); 29760573Skris sbni_init_locked(sc); 29860573Skris SBNI_UNLOCK(sc); 29960573Skris} 30060573Skris 30160573Skrisstatic void 30260573Skrissbni_init_locked(struct sbni_softc *sc) 30360573Skris{ 30460573Skris struct ifnet *ifp; 30560573Skris 30660573Skris ifp = sc->ifp; 30760573Skris 30860573Skris /* 30960573Skris * kludge to avoid multiple initialization when more than once 31060573Skris * protocols configured 31160573Skris */ 31257429Smarkm if (ifp->if_drv_flags & IFF_DRV_RUNNING) 31357429Smarkm return; 31457429Smarkm 31557429Smarkm card_start(sc); 31657429Smarkm callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); 31757429Smarkm 31857429Smarkm ifp->if_drv_flags |= IFF_DRV_RUNNING; 31957429Smarkm ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 32092555Sdes 32176259Sgreen /* attempt to start output */ 32292555Sdes sbni_start_locked(ifp); 32357429Smarkm} 32476259Sgreen 32592555Sdesstatic void 32657429Smarkmsbni_start(struct ifnet *ifp) 32760573Skris{ 32860573Skris struct sbni_softc *sc = ifp->if_softc; 32960573Skris 33060573Skris SBNI_LOCK(sc); 33160573Skris sbni_start_locked(ifp); 33276259Sgreen SBNI_UNLOCK(sc); 33360573Skris} 33460573Skris 33560573Skrisstatic void 33660573Skrissbni_start_locked(struct ifnet *ifp) 33760573Skris{ 33876259Sgreen struct sbni_softc *sc = ifp->if_softc; 33960573Skris 34060573Skris if (sc->tx_frameno == 0) 34160573Skris prepare_to_send(sc); 34276259Sgreen} 34360573Skris 34476259Sgreen 34560573Skrisstatic void 34692555Sdessbni_stop(struct sbni_softc *sc) 34792555Sdes{ 34892555Sdes sbni_outb(sc, CSR0, 0); 34992555Sdes drop_xmit_queue(sc); 35092555Sdes 35192555Sdes if (sc->rx_buf_p) { 35292555Sdes m_freem(sc->rx_buf_p); 35392555Sdes sc->rx_buf_p = NULL; 35492555Sdes } 35592555Sdes 35660573Skris callout_stop(&sc->wch); 35757429Smarkm sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 35857429Smarkm} 35957429Smarkm 36076259Sgreen/* -------------------------------------------------------------------------- */ 36157429Smarkm 36257429Smarkm/* interrupt handler */ 36357429Smarkm 36457429Smarkm/* 36557429Smarkm * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 36657429Smarkm * be looked as two independent single-channel devices. Every channel seems 36757429Smarkm * as Ethernet interface but interrupt handler must be common. Really, first 36857429Smarkm * channel ("master") driver only registers the handler. In it's struct softc 36957429Smarkm * it has got pointer to "slave" channel's struct softc and handles that's 37057429Smarkm * interrupts too. 37176259Sgreen * softc of successfully attached ISA SBNI boards is linked to list. 37257429Smarkm * While next board driver is initialized, it scans this list. If one 37376259Sgreen * has found softc with same irq and ioaddr different by 4 then it assumes 37476259Sgreen * this board to be "master". 37576259Sgreen */ 37676259Sgreen 37776259Sgreenvoid 37876259Sgreensbni_intr(void *arg) 37992555Sdes{ 38092555Sdes struct sbni_softc *sc; 38176259Sgreen int repeat; 38257429Smarkm 38357429Smarkm sc = (struct sbni_softc *)arg; 38457429Smarkm 38557429Smarkm do { 38657429Smarkm repeat = 0; 38757429Smarkm SBNI_LOCK(sc); 38857429Smarkm if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 38957429Smarkm handle_channel(sc); 39057429Smarkm repeat = 1; 39192555Sdes } 39265668Skris SBNI_UNLOCK(sc); 39357429Smarkm if (sc->slave_sc) { 39457429Smarkm /* second channel present */ 39557429Smarkm SBNI_LOCK(sc->slave_sc); 39657429Smarkm if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) { 39765668Skris handle_channel(sc->slave_sc); 39865668Skris repeat = 1; 39965668Skris } 40065668Skris SBNI_UNLOCK(sc->slave_sc); 40157429Smarkm } 40257429Smarkm } while (repeat); 40357429Smarkm} 40457429Smarkm 40557429Smarkm 40657429Smarkmstatic void 40757429Smarkmhandle_channel(struct sbni_softc *sc) 40865668Skris{ 40965668Skris int req_ans; 41065668Skris u_char csr0; 41157429Smarkm 41257429Smarkm sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 41357429Smarkm 41457429Smarkm sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 41557429Smarkm for (;;) { 41657429Smarkm csr0 = sbni_inb(sc, CSR0); 41757429Smarkm if ((csr0 & (RC_RDY | TR_RDY)) == 0) 41857429Smarkm break; 41957429Smarkm 42057429Smarkm req_ans = !(sc->state & FL_PREV_OK); 42192555Sdes 42292555Sdes if (csr0 & RC_RDY) 42392555Sdes req_ans = recv_frame(sc); 42457429Smarkm 42557429Smarkm /* 42657429Smarkm * TR_RDY always equals 1 here because we have owned the marker, 42765668Skris * and we set TR_REQ when disabled interrupts 42865668Skris */ 42965668Skris csr0 = sbni_inb(sc, CSR0); 43057429Smarkm if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 43157429Smarkm if_printf(sc->ifp, "internal error!\n"); 43257429Smarkm 43357429Smarkm /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 43492555Sdes if (req_ans || sc->tx_frameno != 0) 43560573Skris send_frame(sc); 43657429Smarkm else { 43760573Skris /* send the marker without any data */ 43860573Skris sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 43957429Smarkm } 44057429Smarkm } 44157429Smarkm 44257429Smarkm sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 44357429Smarkm} 44457429Smarkm 44557429Smarkm 44657429Smarkm/* 44757429Smarkm * Routine returns 1 if it need to acknoweledge received frame. 44857429Smarkm * Empty frame received without errors won't be acknoweledged. 44957429Smarkm */ 45057429Smarkm 45157429Smarkmstatic int 45257429Smarkmrecv_frame(struct sbni_softc *sc) 45357429Smarkm{ 45457429Smarkm u_int32_t crc; 45557429Smarkm u_int framelen, frameno, ack; 45657429Smarkm u_int is_first, frame_ok; 45757429Smarkm 45857429Smarkm crc = CRC32_INITIAL; 45976259Sgreen if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 46057429Smarkm frame_ok = framelen > 4 ? 46157429Smarkm upload_data(sc, framelen, frameno, is_first, crc) : 46257429Smarkm skip_tail(sc, framelen, crc); 46357429Smarkm if (frame_ok) 46457429Smarkm interpret_ack(sc, ack); 46557429Smarkm } else { 46657429Smarkm framelen = 0; 46757429Smarkm frame_ok = 0; 46857429Smarkm } 46957429Smarkm 47057429Smarkm sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 47157429Smarkm if (frame_ok) { 47260573Skris sc->state |= FL_PREV_OK; 47360573Skris if (framelen > 4) 47498675Sdes sc->in_stats.all_rx_number++; 47598675Sdes } else { 47698675Sdes sc->state &= ~FL_PREV_OK; 47798675Sdes change_level(sc); 47898675Sdes sc->in_stats.all_rx_number++; 47998675Sdes sc->in_stats.bad_rx_number++; 48098675Sdes } 48198675Sdes 48298675Sdes return (!frame_ok || framelen > 4); 48398675Sdes} 48498675Sdes 48598675Sdes 48698675Sdesstatic void 48798675Sdessend_frame(struct sbni_softc *sc) 48898675Sdes{ 48998675Sdes u_int32_t crc; 49098675Sdes u_char csr0; 49198675Sdes 49298675Sdes crc = CRC32_INITIAL; 49398675Sdes if (sc->state & FL_NEED_RESEND) { 49498675Sdes 49598675Sdes /* if frame was sended but not ACK'ed - resend it */ 49698675Sdes if (sc->trans_errors) { 49798675Sdes sc->trans_errors--; 49898675Sdes if (sc->framelen != 0) 49998675Sdes sc->in_stats.resend_tx_number++; 50098675Sdes } else { 50198675Sdes /* cannot xmit with many attempts */ 50298675Sdes drop_xmit_queue(sc); 50398675Sdes goto do_send; 50498675Sdes } 50598675Sdes } else 50698675Sdes sc->trans_errors = TR_ERROR_COUNT; 50798675Sdes 50898675Sdes send_frame_header(sc, &crc); 50998675Sdes sc->state |= FL_NEED_RESEND; 51098675Sdes /* 51198675Sdes * FL_NEED_RESEND will be cleared after ACK, but if empty 51298675Sdes * frame sended then in prepare_to_send next frame 51398675Sdes */ 51498675Sdes 51598675Sdes 51698675Sdes if (sc->framelen) { 51798675Sdes download_data(sc, &crc); 51898675Sdes sc->in_stats.all_tx_number++; 51998675Sdes sc->state |= FL_WAIT_ACK; 52098675Sdes } 52198675Sdes 52298675Sdes sbni_outsb(sc, (u_char *)&crc, sizeof crc); 52398675Sdes 52498675Sdesdo_send: 52598675Sdes csr0 = sbni_inb(sc, CSR0); 52698675Sdes sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 52798675Sdes 52898675Sdes if (sc->tx_frameno) { 52998675Sdes /* next frame exists - request to send */ 53098675Sdes sbni_outb(sc, CSR0, csr0 | TR_REQ); 53198675Sdes } 53298675Sdes} 53398675Sdes 53498675Sdes 53565668Skrisstatic void 53692555Sdesdownload_data(struct sbni_softc *sc, u_int32_t *crc_p) 53765668Skris{ 53865668Skris struct mbuf *m; 53965668Skris caddr_t data_p; 54065668Skris u_int data_len, pos, slice; 54165668Skris 54276259Sgreen data_p = NULL; /* initialized to avoid warn */ 54376259Sgreen pos = 0; 54465668Skris 54565668Skris for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 54665668Skris if (pos + m->m_len > sc->outpos) { 54765668Skris data_len = m->m_len - (sc->outpos - pos); 54865668Skris data_p = mtod(m, caddr_t) + (sc->outpos - pos); 54965668Skris 55065668Skris goto do_copy; 55165668Skris } else 55265668Skris pos += m->m_len; 55365668Skris } 55465668Skris 55565668Skris data_len = 0; 55665668Skris 55765668Skrisdo_copy: 55865668Skris pos = 0; 55965668Skris do { 56065668Skris if (data_len) { 56165668Skris slice = min(data_len, sc->framelen - pos); 56265668Skris sbni_outsb(sc, data_p, slice); 56365668Skris *crc_p = calc_crc32(*crc_p, data_p, slice); 56465668Skris 56565668Skris pos += slice; 56665668Skris if (data_len -= slice) 56765668Skris data_p += slice; 56865668Skris else { 56965668Skris do { 57065668Skris m = m->m_next; 57165668Skris } while (m != NULL && m->m_len == 0); 57265668Skris 57365668Skris if (m) { 57465668Skris data_len = m->m_len; 57565668Skris data_p = mtod(m, caddr_t); 57665668Skris } 57776259Sgreen } 57876259Sgreen } else { 57976259Sgreen /* frame too short - zero padding */ 58076259Sgreen 58176259Sgreen pos = sc->framelen - pos; 58276259Sgreen while (pos--) { 58376259Sgreen sbni_outb(sc, DAT, 0); 58476259Sgreen *crc_p = CRC32(0, *crc_p); 58576259Sgreen } 58665668Skris return; 58765668Skris } 58865668Skris } while (pos < sc->framelen); 58965668Skris} 59065668Skris 59165668Skris 59265668Skrisstatic int 59365668Skrisupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 59465668Skris u_int is_first, u_int32_t crc) 59565668Skris{ 59665668Skris int frame_ok; 59792555Sdes 59892555Sdes if (is_first) { 59992555Sdes sc->wait_frameno = frameno; 60065668Skris sc->inppos = 0; 60165668Skris } 60265668Skris 60365668Skris if (sc->wait_frameno == frameno) { 60465668Skris 60565668Skris if (sc->inppos + framelen <= ETHER_MAX_LEN) { 60665668Skris frame_ok = append_frame_to_pkt(sc, framelen, crc); 60765668Skris 60865668Skris /* 60965668Skris * if CRC is right but framelen incorrect then transmitter 61065668Skris * error was occurred... drop entire packet 61165668Skris */ 61292555Sdes } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 61392555Sdes sc->wait_frameno = 0; 61492555Sdes sc->inppos = 0; 61592555Sdes if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 61692555Sdes /* now skip all frames until is_first != 0 */ 61792555Sdes } 61892555Sdes } else 61992555Sdes frame_ok = skip_tail(sc, framelen, crc); 62092555Sdes 62192555Sdes if (is_first && !frame_ok) { 62292555Sdes /* 62392555Sdes * Frame has been violated, but we have stored 62492555Sdes * is_first already... Drop entire packet. 62592555Sdes */ 62692555Sdes sc->wait_frameno = 0; 62792555Sdes if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 62892555Sdes } 62992555Sdes 63092555Sdes return (frame_ok); 63192555Sdes} 63292555Sdes 63365668Skris 63465668Skrisstatic __inline void send_complete(struct sbni_softc *); 63565668Skris 63665668Skrisstatic __inline void 63765668Skrissend_complete(struct sbni_softc *sc) 638106121Sdes{ 639106121Sdes m_freem(sc->tx_buf_p); 640106121Sdes sc->tx_buf_p = NULL; 641106121Sdes if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1); 642106121Sdes} 643106121Sdes 644106121Sdes 645106121Sdesstatic void 64665668Skrisinterpret_ack(struct sbni_softc *sc, u_int ack) 647106121Sdes{ 648106121Sdes if (ack == FRAME_SENT_OK) { 649106121Sdes sc->state &= ~FL_NEED_RESEND; 65065668Skris 65165668Skris if (sc->state & FL_WAIT_ACK) { 65265668Skris sc->outpos += sc->framelen; 65365668Skris 65465668Skris if (--sc->tx_frameno) { 65565668Skris sc->framelen = min( 65665668Skris sc->maxframe, sc->pktlen - sc->outpos); 65765668Skris } else { 65865668Skris send_complete(sc); 65965668Skris prepare_to_send(sc); 66065668Skris } 66198675Sdes } 66298675Sdes } 66398675Sdes 66498675Sdes sc->state &= ~FL_WAIT_ACK; 66565668Skris} 66665668Skris 66765668Skris 66865668Skris/* 66965668Skris * Glue received frame with previous fragments of packet. 67065668Skris * Indicate packet when last frame would be accepted. 67165668Skris */ 67265668Skris 67365668Skrisstatic int 67465668Skrisappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 67565668Skris{ 67665668Skris caddr_t p; 67765668Skris 67865668Skris if (sc->inppos + framelen > ETHER_MAX_LEN) 67965668Skris return (0); 68065668Skris 68165668Skris if (!sc->rx_buf_p && !get_rx_buf(sc)) 68265668Skris return (0); 68365668Skris 68465668Skris p = sc->rx_buf_p->m_data + sc->inppos; 68565668Skris sbni_insb(sc, p, framelen); 68665668Skris if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 68765668Skris return (0); 68865668Skris 68965668Skris sc->inppos += framelen - 4; 69065668Skris if (--sc->wait_frameno == 0) { /* last frame received */ 69165668Skris indicate_pkt(sc); 69265668Skris if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 69365668Skris } 69465668Skris 69565668Skris return (1); 69692555Sdes} 69760573Skris 69860573Skris 69960573Skris/* 70065668Skris * Prepare to start output on adapter. Current priority must be set to splimp 70160573Skris * before this routine is called. 70257429Smarkm * Transmitter will be actually activated when marker has been accepted. 70357429Smarkm */ 70457429Smarkm 70557429Smarkmstatic void 70676259Sgreenprepare_to_send(struct sbni_softc *sc) 70776259Sgreen{ 70857429Smarkm struct mbuf *m; 70957429Smarkm u_int len; 71057429Smarkm 71157429Smarkm /* sc->tx_buf_p == NULL here! */ 71257429Smarkm if (sc->tx_buf_p) 71357429Smarkm printf("sbni: memory leak!\n"); 71457429Smarkm 71557429Smarkm sc->outpos = 0; 71657429Smarkm sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 71757429Smarkm 71857429Smarkm for (;;) { 71957429Smarkm IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p); 72057429Smarkm if (!sc->tx_buf_p) { 72157429Smarkm /* nothing to transmit... */ 72257429Smarkm sc->pktlen = 0; 72357429Smarkm sc->tx_frameno = 0; 72457429Smarkm sc->framelen = 0; 72557429Smarkm sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 72657429Smarkm return; 72757429Smarkm } 72857429Smarkm 72957429Smarkm for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 73057429Smarkm len += m->m_len; 73192555Sdes 73257429Smarkm if (len != 0) 73357429Smarkm break; 73457429Smarkm m_freem(sc->tx_buf_p); 73557429Smarkm } 73657429Smarkm 73757429Smarkm if (len < SBNI_MIN_LEN) 73857429Smarkm len = SBNI_MIN_LEN; 73957429Smarkm 74057429Smarkm sc->pktlen = len; 74157429Smarkm sc->tx_frameno = howmany(len, sc->maxframe); 74276259Sgreen sc->framelen = min(len, sc->maxframe); 74376259Sgreen 74465668Skris sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 74557429Smarkm sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 74657429Smarkm BPF_MTAP(sc->ifp, sc->tx_buf_p); 74757429Smarkm} 74857429Smarkm 74992555Sdes 75057429Smarkmstatic void 75157429Smarkmdrop_xmit_queue(struct sbni_softc *sc) 75257429Smarkm{ 75357429Smarkm struct mbuf *m; 75457429Smarkm 75557429Smarkm if (sc->tx_buf_p) { 75657429Smarkm m_freem(sc->tx_buf_p); 75757429Smarkm sc->tx_buf_p = NULL; 75857429Smarkm if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 75957429Smarkm } 76057429Smarkm 76176259Sgreen for (;;) { 76257429Smarkm IF_DEQUEUE(&sc->ifp->if_snd, m); 76357429Smarkm if (m == NULL) 76457429Smarkm break; 76557429Smarkm m_freem(m); 76657429Smarkm if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1); 76757429Smarkm } 76857429Smarkm 76957429Smarkm sc->tx_frameno = 0; 77057429Smarkm sc->framelen = 0; 77157429Smarkm sc->outpos = 0; 77257429Smarkm sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 77357429Smarkm sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 77457429Smarkm} 77557429Smarkm 77676259Sgreen 77757429Smarkmstatic void 77857429Smarkmsend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 77957429Smarkm{ 78057429Smarkm u_int32_t crc; 78157429Smarkm u_int len_field; 78257429Smarkm u_char value; 78357429Smarkm 78476259Sgreen crc = *crc_p; 78557429Smarkm len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 78657429Smarkm 78757429Smarkm if (sc->state & FL_NEED_RESEND) 78857429Smarkm len_field |= FRAME_RETRY; /* non-first attempt... */ 78957429Smarkm 79057429Smarkm if (sc->outpos == 0) 79157429Smarkm len_field |= FRAME_FIRST; 79257429Smarkm 79357429Smarkm len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 79476259Sgreen sbni_outb(sc, DAT, SBNI_SIG); 79557429Smarkm 79657429Smarkm value = (u_char)len_field; 79757429Smarkm sbni_outb(sc, DAT, value); 79857429Smarkm crc = CRC32(value, crc); 79960573Skris value = (u_char)(len_field >> 8); 80060573Skris sbni_outb(sc, DAT, value); 80160573Skris crc = CRC32(value, crc); 80260573Skris 80360573Skris sbni_outb(sc, DAT, sc->tx_frameno); 80460573Skris crc = CRC32(sc->tx_frameno, crc); 80560573Skris sbni_outb(sc, DAT, 0); 80660573Skris crc = CRC32(0, crc); 80760573Skris *crc_p = crc; 80860573Skris} 80960573Skris 81092555Sdes 81176259Sgreen/* 81260573Skris * if frame tail not needed (incorrect number or received twice), 81376259Sgreen * it won't store, but CRC will be calculated 81460573Skris */ 81560573Skris 81665668Skrisstatic int 81765668Skrisskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 81892555Sdes{ 81965668Skris while (tail_len--) 82065668Skris crc = CRC32(sbni_inb(sc, DAT), crc); 82165668Skris 82265668Skris return (crc == CRC32_REMAINDER); 82365668Skris} 82465668Skris 82592555Sdes 82676259Sgreenstatic int 82776259Sgreencheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 82876259Sgreen u_int *ack, u_int *is_first, u_int32_t *crc_p) 82976259Sgreen{ 83076259Sgreen u_int32_t crc; 83192555Sdes u_char value; 83276259Sgreen 83376259Sgreen crc = *crc_p; 83476259Sgreen if (sbni_inb(sc, DAT) != SBNI_SIG) 83576259Sgreen return (0); 83676259Sgreen 83760573Skris value = sbni_inb(sc, DAT); 83857429Smarkm *framelen = (u_int)value; 83957429Smarkm crc = CRC32(value, crc); 84092555Sdes value = sbni_inb(sc, DAT); 84192555Sdes *framelen |= ((u_int)value) << 8; 84257429Smarkm crc = CRC32(value, crc); 84357429Smarkm 84460573Skris *ack = *framelen & FRAME_ACK_MASK; 84565668Skris *is_first = (*framelen & FRAME_FIRST) != 0; 84657429Smarkm 84776259Sgreen if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 84857429Smarkm return (0); 84992555Sdes 85057429Smarkm value = sbni_inb(sc, DAT); 85157429Smarkm *frameno = (u_int)value; 85257429Smarkm crc = CRC32(value, crc); 85357429Smarkm 85457429Smarkm crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 85557429Smarkm *framelen -= 2; 85657429Smarkm 85757429Smarkm *crc_p = crc; 85857429Smarkm return (1); 85957429Smarkm} 86057429Smarkm 86157429Smarkm 86257429Smarkmstatic int 86357429Smarkmget_rx_buf(struct sbni_softc *sc) 86476259Sgreen{ 86576259Sgreen struct mbuf *m; 86676259Sgreen 86776259Sgreen MGETHDR(m, M_NOWAIT, MT_DATA); 86876259Sgreen if (m == NULL) { 86976259Sgreen if_printf(sc->ifp, "cannot allocate header mbuf\n"); 87076259Sgreen return (0); 87176259Sgreen } 87276259Sgreen 87376259Sgreen /* 87476259Sgreen * We always put the received packet in a single buffer - 87576259Sgreen * either with just an mbuf header or in a cluster attached 87676259Sgreen * to the header. The +2 is to compensate for the alignment 87776259Sgreen * fixup below. 87857429Smarkm */ 87957429Smarkm if (ETHER_MAX_LEN + 2 > MHLEN) { 88057429Smarkm /* Attach an mbuf cluster */ 88157429Smarkm if (!(MCLGET(m, M_NOWAIT))) { 88257429Smarkm m_freem(m); 88357429Smarkm return (0); 88457429Smarkm } 88557429Smarkm } 88657429Smarkm m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 88757429Smarkm 88857429Smarkm /* 88960573Skris * The +2 is to longword align the start of the real packet. 89060573Skris * (sizeof ether_header == 14) 891113908Sdes * This is important for NFS. 892113908Sdes */ 893113908Sdes m_adj(m, 2); 894113908Sdes sc->rx_buf_p = m; 895113908Sdes return (1); 896113908Sdes} 897113908Sdes 898113908Sdes 899113908Sdesstatic void 900113908Sdesindicate_pkt(struct sbni_softc *sc) 90157429Smarkm{ 90257429Smarkm struct ifnet *ifp = sc->ifp; 90357429Smarkm struct mbuf *m; 90457429Smarkm 90557429Smarkm m = sc->rx_buf_p; 90657429Smarkm m->m_pkthdr.rcvif = ifp; 90776259Sgreen m->m_pkthdr.len = m->m_len = sc->inppos; 90876259Sgreen sc->rx_buf_p = NULL; 90992555Sdes 91076259Sgreen SBNI_UNLOCK(sc); 91176259Sgreen (*ifp->if_input)(ifp, m); 91276259Sgreen SBNI_LOCK(sc); 91376259Sgreen} 91476259Sgreen 91576259Sgreen/* -------------------------------------------------------------------------- */ 91676259Sgreen 91760573Skris/* 91876259Sgreen * Routine checks periodically wire activity and regenerates marker if 91957429Smarkm * connect was inactive for a long time. 92057429Smarkm */ 92157429Smarkm 92257429Smarkmstatic void 92357429Smarkmsbni_timeout(void *xsc) 92457429Smarkm{ 92557429Smarkm struct sbni_softc *sc; 92676259Sgreen u_char csr0; 92760573Skris 92860573Skris sc = (struct sbni_softc *)xsc; 92976259Sgreen SBNI_ASSERT_LOCKED(sc); 93057429Smarkm 93176259Sgreen csr0 = sbni_inb(sc, CSR0); 93276259Sgreen if (csr0 & RC_CHK) { 93376259Sgreen 93476259Sgreen if (sc->timer_ticks) { 93576259Sgreen if (csr0 & (RC_RDY | BU_EMP)) 93676259Sgreen /* receiving not active */ 93776259Sgreen sc->timer_ticks--; 93876259Sgreen } else { 93976259Sgreen sc->in_stats.timeout_number++; 94057429Smarkm if (sc->delta_rxl) 94176259Sgreen timeout_change_level(sc); 94276259Sgreen 94376259Sgreen sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 94476259Sgreen csr0 = sbni_inb(sc, CSR0); 94576259Sgreen } 94676259Sgreen } 94757429Smarkm 94876259Sgreen sbni_outb(sc, CSR0, csr0 | RC_CHK); 94976259Sgreen callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); 95076259Sgreen} 95176259Sgreen 95276259Sgreen/* -------------------------------------------------------------------------- */ 95357429Smarkm 95476259Sgreenstatic void 95576259Sgreencard_start(struct sbni_softc *sc) 95676259Sgreen{ 95757429Smarkm sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 95857429Smarkm sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 95957429Smarkm sc->state |= FL_PREV_OK; 96057429Smarkm 96192555Sdes sc->inppos = 0; 96276259Sgreen sc->wait_frameno = 0; 96392555Sdes 96457429Smarkm sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 96557429Smarkm sbni_outb(sc, CSR0, EN_INT); 96657429Smarkm} 96757429Smarkm 96876259Sgreen/* -------------------------------------------------------------------------- */ 96976259Sgreen 97076259Sgreenstatic u_char rxl_tab[] = { 97157429Smarkm 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 97276259Sgreen 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 97376259Sgreen}; 97476259Sgreen 97576259Sgreen#define SIZE_OF_TIMEOUT_RXL_TAB 4 97676259Sgreenstatic u_char timeout_rxl_tab[] = { 97776259Sgreen 0x03, 0x05, 0x08, 0x0b 97876259Sgreen}; 97976259Sgreen 98060573Skrisstatic void 98176259Sgreenset_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 98257429Smarkm{ 98360573Skris if (flags.fixed_rxl) { 98460573Skris sc->delta_rxl = 0; /* disable receive level autodetection */ 98557429Smarkm sc->cur_rxl_index = flags.rxl; 98660573Skris } else { 98760573Skris sc->delta_rxl = DEF_RXL_DELTA; 98876259Sgreen sc->cur_rxl_index = DEF_RXL; 98960573Skris } 99060573Skris 99160573Skris sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 99260573Skris sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 99376259Sgreen sc->maxframe = DEFAULT_FRAME_LEN; 99460573Skris 99560573Skris /* 99657429Smarkm * generate Ethernet address (0x00ff01xxxxxx) 99776259Sgreen */ 99857429Smarkm *(u_int16_t *) sc->enaddr = htons(0x00ff); 99957429Smarkm if (flags.mac_addr) { 100076259Sgreen *(u_int32_t *) (sc->enaddr + 2) = 100176259Sgreen htonl(flags.mac_addr | 0x01000000); 100276259Sgreen } else { 100376259Sgreen *(u_char *) (sc->enaddr + 2) = 0x01; 100457429Smarkm read_random(sc->enaddr + 3, 3); 100557429Smarkm } 100657429Smarkm} 100757429Smarkm 100857429Smarkm 100957429Smarkm#ifdef SBNI_DUAL_COMPOUND 101057429Smarkmvoid 101192555Sdessbni_add(struct sbni_softc *sc) 101257429Smarkm{ 101392555Sdes 101492555Sdes mtx_lock(&headlist_lock); 101592555Sdes sc->link = sbni_headlist; 101692555Sdes sbni_headlist = sc; 101792555Sdes mtx_unlock(&headlist_lock); 101892555Sdes} 101992555Sdes 102092555Sdesstruct sbni_softc * 102192555Sdesconnect_to_master(struct sbni_softc *sc) 102292555Sdes{ 102392555Sdes struct sbni_softc *p, *p_prev; 102492555Sdes 102592555Sdes mtx_lock(&headlist_lock); 102692555Sdes for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { 102792555Sdes if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || 102892555Sdes rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { 102992555Sdes p->slave_sc = sc; 103057429Smarkm if (p_prev) 103157429Smarkm p_prev->link = p->link; 103257429Smarkm else 103357429Smarkm sbni_headlist = p->link; 103457429Smarkm mtx_unlock(&headlist_lock); 103557429Smarkm return p; 103657429Smarkm } 103757429Smarkm } 103892555Sdes mtx_unlock(&headlist_lock); 103957429Smarkm 104057429Smarkm return (NULL); 104157429Smarkm} 104257429Smarkm 104357429Smarkm#endif /* SBNI_DUAL_COMPOUND */ 104457429Smarkm 104557429Smarkm 104657429Smarkm/* Receive level auto-selection */ 104757429Smarkm 104876259Sgreenstatic void 104957429Smarkmchange_level(struct sbni_softc *sc) 105057429Smarkm{ 105157429Smarkm if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 105257429Smarkm return; 105357429Smarkm 105457429Smarkm if (sc->cur_rxl_index == 0) 105557429Smarkm sc->delta_rxl = 1; 105657429Smarkm else if (sc->cur_rxl_index == 15) 105757429Smarkm sc->delta_rxl = -1; 105857429Smarkm else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 105957429Smarkm sc->delta_rxl = -sc->delta_rxl; 106076259Sgreen 106157429Smarkm sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 106257429Smarkm sbni_inb(sc, CSR0); /* it needed for PCI cards */ 106357429Smarkm sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 106457429Smarkm 106557429Smarkm sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 106657429Smarkm sc->cur_rxl_rcvd = 0; 106757429Smarkm} 106857429Smarkm 106957429Smarkm 107057429Smarkmstatic void 107157429Smarkmtimeout_change_level(struct sbni_softc *sc) 107292555Sdes{ 107357429Smarkm sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 107457429Smarkm if (++sc->timeout_rxl >= 4) 107592555Sdes sc->timeout_rxl = 0; 107692555Sdes 107757429Smarkm sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 107857429Smarkm sbni_inb(sc, CSR0); 107957429Smarkm sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 108057429Smarkm 108157429Smarkm sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 108260573Skris sc->cur_rxl_rcvd = 0; 108360573Skris} 108460573Skris 108592555Sdes/* -------------------------------------------------------------------------- */ 108692555Sdes 108760573Skris/* 108876259Sgreen * Process an ioctl request. This code needs some work - it looks 108960573Skris * pretty ugly. 109092555Sdes */ 109160573Skris 109260573Skrisstatic int 109360573Skrissbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 109460573Skris{ 109592555Sdes struct sbni_softc *sc; 109692555Sdes struct ifreq *ifr; 109760573Skris struct thread *td; 109876259Sgreen struct sbni_in_stats *in_stats; 109960573Skris struct sbni_flags flags; 110092555Sdes int error; 110160573Skris 110260573Skris sc = ifp->if_softc; 110360573Skris ifr = (struct ifreq *)data; 110460573Skris td = curthread; 110592555Sdes error = 0; 110692555Sdes 110760573Skris switch (command) { 110860573Skris case SIOCSIFFLAGS: 110992555Sdes /* 111060573Skris * If the interface is marked up and stopped, then start it. 111160573Skris * If it is marked down and running, then stop it. 111260573Skris */ 111360573Skris SBNI_LOCK(sc); 111460573Skris if (ifp->if_flags & IFF_UP) { 111560573Skris if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 111660573Skris sbni_init_locked(sc); 111760573Skris } else { 111860573Skris if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 111960573Skris sbni_stop(sc); 112060573Skris } 112160573Skris } 112292555Sdes SBNI_UNLOCK(sc); 112376259Sgreen break; 112476259Sgreen 1125106121Sdes case SIOCADDMULTI: 112676259Sgreen case SIOCDELMULTI: 112776259Sgreen /* 112892555Sdes * Multicast list has changed; set the hardware filter 112976259Sgreen * accordingly. 113076259Sgreen */ 113176259Sgreen error = 0; 113276259Sgreen /* if (ifr == NULL) 113376259Sgreen error = EAFNOSUPPORT; */ 113476259Sgreen break; 113592555Sdes 113676259Sgreen /* 113776259Sgreen * SBNI specific ioctl 113876259Sgreen */ 113976259Sgreen case SIOCGHWFLAGS: /* get flags */ 114092555Sdes SBNI_LOCK(sc); 114192555Sdes bcopy((caddr_t)IF_LLADDR(sc->ifp)+3, (caddr_t) &flags, 3); 114292555Sdes flags.rxl = sc->cur_rxl_index; 114392555Sdes flags.rate = sc->csr1.rate; 114492555Sdes flags.fixed_rxl = (sc->delta_rxl == 0); 114576259Sgreen flags.fixed_rate = 1; 114692555Sdes SBNI_UNLOCK(sc); 114792555Sdes bcopy(&flags, &ifr->ifr_ifru, sizeof(flags)); 114892555Sdes break; 114992555Sdes 115076259Sgreen case SIOCGINSTATS: 115176259Sgreen in_stats = malloc(sizeof(struct sbni_in_stats), M_DEVBUF, 115276259Sgreen M_WAITOK); 115376259Sgreen SBNI_LOCK(sc); 115476259Sgreen bcopy(&sc->in_stats, in_stats, sizeof(struct sbni_in_stats)); 1155106121Sdes SBNI_UNLOCK(sc); 115676259Sgreen error = copyout(in_stats, ifr_data_get_ptr(ifr), 115776259Sgreen sizeof(struct sbni_in_stats)); 115876259Sgreen free(in_stats, M_DEVBUF); 115976259Sgreen break; 116076259Sgreen 116192555Sdes case SIOCSHWFLAGS: /* set flags */ 116276259Sgreen /* root only */ 116376259Sgreen error = priv_check(td, PRIV_DRIVER); 116476259Sgreen if (error) 116576259Sgreen break; 116676259Sgreen bcopy(&ifr->ifr_ifru, &flags, sizeof(flags)); 116776259Sgreen SBNI_LOCK(sc); 116876259Sgreen if (flags.fixed_rxl) { 116976259Sgreen sc->delta_rxl = 0; 117076259Sgreen sc->cur_rxl_index = flags.rxl; 117176259Sgreen } else { 117276259Sgreen sc->delta_rxl = DEF_RXL_DELTA; 117376259Sgreen sc->cur_rxl_index = DEF_RXL; 117476259Sgreen } 117592555Sdes sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 117676259Sgreen sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 117776259Sgreen if (flags.mac_addr) 117876259Sgreen bcopy((caddr_t) &flags, 117992555Sdes (caddr_t) IF_LLADDR(sc->ifp)+3, 3); 118076259Sgreen 118192555Sdes /* Don't be afraid... */ 118292555Sdes sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 118392555Sdes SBNI_UNLOCK(sc); 118492555Sdes break; 118592555Sdes 118692555Sdes case SIOCRINSTATS: 118792555Sdes SBNI_LOCK(sc); 118876259Sgreen if (!(error = priv_check(td, PRIV_DRIVER))) /* root only */ 118976259Sgreen bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 119076259Sgreen SBNI_UNLOCK(sc); 1191106121Sdes break; 119276259Sgreen 119376259Sgreen default: 119476259Sgreen error = ether_ioctl(ifp, command, data); 119592555Sdes break; 119676259Sgreen } 119776259Sgreen 119876259Sgreen return (error); 119976259Sgreen} 120076259Sgreen 120176259Sgreen/* -------------------------------------------------------------------------- */ 120276259Sgreen 120392555Sdesstatic u_int32_t 120492555Sdescalc_crc32(u_int32_t crc, caddr_t p, u_int len) 120592555Sdes{ 120692555Sdes while (len--) 120792555Sdes crc = CRC32(*p++, crc); 120892555Sdes 120992555Sdes return (crc); 121076259Sgreen} 121176259Sgreen 121276259Sgreenstatic u_int32_t crc32tab[] __aligned(8) = { 121360573Skris 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 121492555Sdes 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 121592555Sdes 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 121660573Skris 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 121760573Skris 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 121860573Skris 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 121960573Skris 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 122099060Sdes 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 122160573Skris 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 122260573Skris 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 122360573Skris 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 122460573Skris 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 122560573Skris 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 122660573Skris 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 122760573Skris 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 122860573Skris 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 122960573Skris 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 123076259Sgreen 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 123176259Sgreen 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 123276259Sgreen 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 123376259Sgreen 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 123476259Sgreen 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 123576259Sgreen 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 123660573Skris 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 123760573Skris 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 123860573Skris 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 123960573Skris 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 124060573Skris 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 124160573Skris 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 124260573Skris 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 124392555Sdes 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 124492555Sdes 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 124592555Sdes 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 124692555Sdes 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 124792555Sdes 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 124892555Sdes 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 124992555Sdes 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 125092555Sdes 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 125160573Skris 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 125260573Skris 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 125360573Skris 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 125460573Skris 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 125560573Skris 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 125692555Sdes 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 125792555Sdes 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 125892555Sdes 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 125992555Sdes 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 126060573Skris 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 126160573Skris 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 126260573Skris 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 126360573Skris 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 126492555Sdes 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 126592555Sdes 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 126676259Sgreen 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 126776259Sgreen 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 126876259Sgreen 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 126976259Sgreen 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 127060573Skris 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 127176259Sgreen 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 127276259Sgreen 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 127376259Sgreen 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 127476259Sgreen 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 127576259Sgreen 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 127676259Sgreen 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 127776259Sgreen}; 127876259Sgreen