if_sbni.c revision 147256
1262395Sbapt/*- 2262395Sbapt * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved. 3262395Sbapt * Author: Denis I.Timofeev <timofeev@granch.ru> 4262395Sbapt * 5262395Sbapt * Redistributon and use in source and binary forms, with or without 6262395Sbapt * modification, are permitted provided that the following conditions 7262395Sbapt * are met: 8262395Sbapt * 1. Redistributions of source code must retain the above copyright 9262395Sbapt * notice unmodified, this list of conditions, and the following 10262395Sbapt * disclaimer. 11262395Sbapt * 2. Redistributions in binary form must reproduce the above copyright 12262395Sbapt * notice, this list of conditions and the following disclaimer in the 13262395Sbapt * documentation and/or other materials provided with the distribution. 14262395Sbapt * 15262395Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16262395Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17262395Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18262395Sbapt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19262395Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20262395Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21262395Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22262395Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23262395Sbapt * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY 24262395Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25262395Sbapt * SUCH DAMAGE. 26262395Sbapt * 27262395Sbapt */ 28262395Sbapt 29262395Sbapt#include <sys/cdefs.h> 30262395Sbapt__FBSDID("$FreeBSD: head/sys/dev/sbni/if_sbni.c 147256 2005-06-10 16:49:24Z brooks $"); 31262395Sbapt 32262395Sbapt/* 33262395Sbapt * Device driver for Granch SBNI12 leased line adapters 34262395Sbapt * 35262395Sbapt * Revision 2.0.0 1997/08/06 36262395Sbapt * Initial revision by Alexey Zverev 37262395Sbapt * 38262395Sbapt * Revision 2.0.1 1997/08/11 39262395Sbapt * Additional internal statistics support (tx statistics) 40262395Sbapt * 41262395Sbapt * Revision 2.0.2 1997/11/05 42262395Sbapt * if_bpf bug has been fixed 43262395Sbapt * 44262395Sbapt * Revision 2.0.3 1998/12/20 45262395Sbapt * Memory leakage has been eliminated in 46262395Sbapt * the sbni_st and sbni_timeout routines. 47262395Sbapt * 48262395Sbapt * Revision 3.0 2000/08/10 by Yaroslav Polyakov 49262395Sbapt * Support for PCI cards. 4.1 modification. 50262395Sbapt * 51262395Sbapt * Revision 3.1 2000/09/12 52262395Sbapt * Removed extra #defines around bpf functions 53262395Sbapt * 54262395Sbapt * Revision 4.0 2000/11/23 by Denis Timofeev 55262395Sbapt * Completely redesigned the buffer management 56262395Sbapt * 57262395Sbapt * Revision 4.1 2001/01/21 58262395Sbapt * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards 59262395Sbapt * 60262395Sbapt * Written with reference to NE2000 driver developed by David Greenman. 61262395Sbapt */ 62262395Sbapt 63262395Sbapt 64262395Sbapt#include <sys/param.h> 65262395Sbapt#include <sys/systm.h> 66262395Sbapt#include <sys/socket.h> 67262395Sbapt#include <sys/sockio.h> 68262395Sbapt#include <sys/mbuf.h> 69262395Sbapt#include <sys/kernel.h> 70262395Sbapt#include <sys/proc.h> 71262395Sbapt#include <sys/callout.h> 72262395Sbapt#include <sys/syslog.h> 73262395Sbapt#include <sys/random.h> 74262395Sbapt 75262395Sbapt#include <machine/bus.h> 76262395Sbapt#include <sys/rman.h> 77262395Sbapt#include <machine/resource.h> 78262395Sbapt 79262395Sbapt#include <net/if.h> 80262395Sbapt#include <net/ethernet.h> 81262395Sbapt#include <net/if_arp.h> 82262395Sbapt#include <net/bpf.h> 83262395Sbapt#include <net/if_types.h> 84262395Sbapt 85262395Sbapt#include <dev/sbni/if_sbnireg.h> 86262395Sbapt#include <dev/sbni/if_sbnivar.h> 87262395Sbapt 88262395Sbapt#define ASM_CRC 1 89262395Sbapt 90262395Sbaptstatic void sbni_init(void *); 91262395Sbaptstatic void sbni_start(struct ifnet *); 92262395Sbaptstatic int sbni_ioctl(struct ifnet *, u_long, caddr_t); 93262395Sbaptstatic void sbni_watchdog(struct ifnet *); 94262395Sbaptstatic void sbni_stop(struct sbni_softc *); 95262395Sbaptstatic void handle_channel(struct sbni_softc *); 96262395Sbapt 97262395Sbaptstatic void card_start(struct sbni_softc *); 98262395Sbaptstatic int recv_frame(struct sbni_softc *); 99262395Sbaptstatic void send_frame(struct sbni_softc *); 100262395Sbaptstatic int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 101262395Sbaptstatic int skip_tail(struct sbni_softc *, u_int, u_int32_t); 102262395Sbaptstatic void interpret_ack(struct sbni_softc *, u_int); 103262395Sbaptstatic void download_data(struct sbni_softc *, u_int32_t *); 104262395Sbaptstatic void prepare_to_send(struct sbni_softc *); 105262395Sbaptstatic void drop_xmit_queue(struct sbni_softc *); 106262395Sbaptstatic int get_rx_buf(struct sbni_softc *); 107262395Sbaptstatic void indicate_pkt(struct sbni_softc *); 108262395Sbaptstatic void change_level(struct sbni_softc *); 109262395Sbaptstatic int check_fhdr(struct sbni_softc *, u_int *, u_int *, 110262395Sbapt u_int *, u_int *, u_int32_t *); 111262395Sbaptstatic int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 112262395Sbaptstatic void timeout_change_level(struct sbni_softc *); 113262395Sbaptstatic void send_frame_header(struct sbni_softc *, u_int32_t *); 114262395Sbaptstatic void set_initial_values(struct sbni_softc *, struct sbni_flags); 115262395Sbapt 116262395Sbaptstatic u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 117262395Sbaptstatic timeout_t sbni_timeout; 118262395Sbapt 119262395Sbaptstatic __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 120262395Sbaptstatic __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 121262395Sbaptstatic __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 122262395Sbaptstatic __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 123262395Sbapt 124262395Sbaptstatic u_int32_t crc32tab[]; 125262395Sbapt 126262395Sbapt#ifdef SBNI_DUAL_COMPOUND 127262395Sbaptstruct sbni_softc *sbni_headlist; 128262395Sbapt#endif 129262395Sbapt 130262395Sbaptu_int32_t next_sbni_unit; 131262395Sbapt 132262395Sbapt/* -------------------------------------------------------------------------- */ 133262395Sbapt 134262395Sbaptstatic __inline u_char 135262395Sbaptsbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 136262395Sbapt{ 137262395Sbapt return bus_space_read_1( 138262395Sbapt rman_get_bustag(sc->io_res), 139262395Sbapt rman_get_bushandle(sc->io_res), 140262395Sbapt sc->io_off + reg); 141262395Sbapt} 142262395Sbapt 143262395Sbaptstatic __inline void 144262395Sbaptsbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 145262395Sbapt{ 146262395Sbapt bus_space_write_1( 147262395Sbapt rman_get_bustag(sc->io_res), 148262395Sbapt rman_get_bushandle(sc->io_res), 149262395Sbapt sc->io_off + reg, value); 150262395Sbapt} 151262395Sbapt 152262395Sbaptstatic __inline void 153262395Sbaptsbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 154262395Sbapt{ 155262395Sbapt bus_space_read_multi_1( 156262395Sbapt rman_get_bustag(sc->io_res), 157262395Sbapt rman_get_bushandle(sc->io_res), 158262395Sbapt sc->io_off + DAT, to, len); 159262395Sbapt} 160262395Sbapt 161262395Sbaptstatic __inline void 162262395Sbaptsbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 163262395Sbapt{ 164262395Sbapt bus_space_write_multi_1( 165262395Sbapt rman_get_bustag(sc->io_res), 166262395Sbapt rman_get_bushandle(sc->io_res), 167262395Sbapt sc->io_off + DAT, from, len); 168262395Sbapt} 169262395Sbapt 170262395Sbapt 171262395Sbapt/* 172262395Sbapt Valid combinations in CSR0 (for probing): 173262395Sbapt 174262395Sbapt VALID_DECODER 0000,0011,1011,1010 175262395Sbapt 176262395Sbapt ; 0 ; - 177262395Sbapt TR_REQ ; 1 ; + 178262395Sbapt TR_RDY ; 2 ; - 179262395Sbapt TR_RDY TR_REQ ; 3 ; + 180262395Sbapt BU_EMP ; 4 ; + 181262395Sbapt BU_EMP TR_REQ ; 5 ; + 182262395Sbapt BU_EMP TR_RDY ; 6 ; - 183262395Sbapt BU_EMP TR_RDY TR_REQ ; 7 ; + 184262395Sbapt RC_RDY ; 8 ; + 185262395Sbapt RC_RDY TR_REQ ; 9 ; + 186262395Sbapt RC_RDY TR_RDY ; 10 ; - 187262395Sbapt RC_RDY TR_RDY TR_REQ ; 11 ; - 188262395Sbapt RC_RDY BU_EMP ; 12 ; - 189262395Sbapt RC_RDY BU_EMP TR_REQ ; 13 ; - 190262395Sbapt RC_RDY BU_EMP TR_RDY ; 14 ; - 191262395Sbapt RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 192262395Sbapt*/ 193262395Sbapt 194262395Sbapt#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 195262395Sbapt 196262395Sbapt 197262395Sbaptint 198262395Sbaptsbni_probe(struct sbni_softc *sc) 199262395Sbapt{ 200262395Sbapt u_char csr0; 201262395Sbapt 202262395Sbapt csr0 = sbni_inb(sc, CSR0); 203262395Sbapt if (csr0 != 0xff && csr0 != 0x00) { 204262395Sbapt csr0 &= ~EN_INT; 205262395Sbapt if (csr0 & BU_EMP) 206262395Sbapt csr0 |= EN_INT; 207262395Sbapt 208262395Sbapt if (VALID_DECODER & (1 << (csr0 >> 4))) 209262395Sbapt return (0); 210262395Sbapt } 211262395Sbapt 212262395Sbapt return (ENXIO); 213262395Sbapt} 214262395Sbapt 215262395Sbapt 216262395Sbapt/* 217262395Sbapt * Install interface into kernel networking data structures 218262395Sbapt */ 219262395Sbaptvoid 220262395Sbaptsbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 221262395Sbapt{ 222262395Sbapt struct ifnet *ifp; 223262395Sbapt u_char csr0; 224262395Sbapt 225262395Sbapt ifp = sc->ifp = if_alloc(IFT_ETHER); 226262395Sbapt if (ifp == NULL) 227262395Sbapt panic("sbni%d: can not if_alloc()", unit); 228262395Sbapt sbni_outb(sc, CSR0, 0); 229262395Sbapt set_initial_values(sc, flags); 230262395Sbapt 231262395Sbapt callout_handle_init(&sc->wch); 232262395Sbapt /* Initialize ifnet structure */ 233262395Sbapt ifp->if_softc = sc; 234262395Sbapt if_initname(ifp, "sbni", unit); 235262395Sbapt ifp->if_init = sbni_init; 236262395Sbapt ifp->if_start = sbni_start; 237262395Sbapt ifp->if_ioctl = sbni_ioctl; 238262395Sbapt ifp->if_watchdog = sbni_watchdog; 239266636Sbapt ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 240266636Sbapt 241266636Sbapt /* report real baud rate */ 242262395Sbapt csr0 = sbni_inb(sc, CSR0); 243262395Sbapt ifp->if_baudrate = 244262395Sbapt (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 245262395Sbapt 246262395Sbapt ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | 247262395Sbapt IFF_NEEDSGIANT; 248262395Sbapt ether_ifattach(ifp, sc->enaddr); 249262395Sbapt /* device attach does transition from UNCONFIGURED to IDLE state */ 250262395Sbapt 251262395Sbapt if_printf(ifp, "speed %ld, rxl ", ifp->if_baudrate); 252262395Sbapt if (sc->delta_rxl) 253262395Sbapt printf("auto\n"); 254262395Sbapt else 255262395Sbapt printf("%d (fixed)\n", sc->cur_rxl_index); 256262395Sbapt} 257262395Sbapt 258262395Sbapt/* -------------------------------------------------------------------------- */ 259262395Sbapt 260262395Sbaptstatic void 261262395Sbaptsbni_init(void *xsc) 262262395Sbapt{ 263262395Sbapt struct sbni_softc *sc; 264266636Sbapt struct ifnet *ifp; 265266636Sbapt int s; 266266636Sbapt 267266636Sbapt sc = (struct sbni_softc *)xsc; 268266636Sbapt ifp = sc->ifp; 269266636Sbapt 270266636Sbapt /* 271266636Sbapt * kludge to avoid multiple initialization when more than once 272266636Sbapt * protocols configured 273266636Sbapt */ 274266636Sbapt if (ifp->if_flags & IFF_RUNNING) 275266636Sbapt return; 276266636Sbapt 277262395Sbapt s = splimp(); 278262395Sbapt ifp->if_timer = 0; 279262395Sbapt card_start(sc); 280262395Sbapt sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 281262395Sbapt 282262395Sbapt ifp->if_flags |= IFF_RUNNING; 283262395Sbapt ifp->if_flags &= ~IFF_OACTIVE; 284262395Sbapt 285262395Sbapt /* attempt to start output */ 286262395Sbapt sbni_start(ifp); 287262395Sbapt splx(s); 288262395Sbapt} 289262395Sbapt 290266636Sbapt 291266636Sbaptstatic void 292262395Sbaptsbni_start(struct ifnet *ifp) 293262395Sbapt{ 294262395Sbapt struct sbni_softc *sc = ifp->if_softc; 295262395Sbapt if (sc->tx_frameno == 0) 296262395Sbapt prepare_to_send(sc); 297262395Sbapt} 298262395Sbapt 299262395Sbapt 300262395Sbaptstatic void 301262395Sbaptsbni_stop(struct sbni_softc *sc) 302266636Sbapt{ 303266636Sbapt sbni_outb(sc, CSR0, 0); 304262395Sbapt drop_xmit_queue(sc); 305262395Sbapt 306262395Sbapt if (sc->rx_buf_p) { 307262395Sbapt m_freem(sc->rx_buf_p); 308262395Sbapt sc->rx_buf_p = NULL; 309262395Sbapt } 310262395Sbapt 311262395Sbapt untimeout(sbni_timeout, sc, sc->wch); 312262395Sbapt sc->wch.callout = NULL; 313262395Sbapt} 314262395Sbapt 315262395Sbapt/* -------------------------------------------------------------------------- */ 316262395Sbapt 317262395Sbapt/* interrupt handler */ 318262395Sbapt 319262395Sbapt/* 320262395Sbapt * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 321262395Sbapt * be looked as two independent single-channel devices. Every channel seems 322262395Sbapt * as Ethernet interface but interrupt handler must be common. Really, first 323262395Sbapt * channel ("master") driver only registers the handler. In it's struct softc 324262395Sbapt * it has got pointer to "slave" channel's struct softc and handles that's 325262395Sbapt * interrupts too. 326262395Sbapt * softc of successfully attached ISA SBNI boards is linked to list. 327262395Sbapt * While next board driver is initialized, it scans this list. If one 328262395Sbapt * has found softc with same irq and ioaddr different by 4 then it assumes 329262395Sbapt * this board to be "master". 330262395Sbapt */ 331262395Sbapt 332262395Sbaptvoid 333262395Sbaptsbni_intr(void *arg) 334262395Sbapt{ 335262395Sbapt struct sbni_softc *sc; 336262395Sbapt int repeat; 337262395Sbapt 338262395Sbapt sc = (struct sbni_softc *)arg; 339262395Sbapt 340262395Sbapt do { 341262395Sbapt repeat = 0; 342262395Sbapt if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 343262395Sbapt handle_channel(sc); 344262395Sbapt repeat = 1; 345262395Sbapt } 346262395Sbapt if (sc->slave_sc && /* second channel present */ 347262395Sbapt (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) { 348262395Sbapt handle_channel(sc->slave_sc); 349266636Sbapt repeat = 1; 350262395Sbapt } 351262395Sbapt } while (repeat); 352266636Sbapt} 353266636Sbapt 354262395Sbapt 355266636Sbaptstatic void 356262395Sbapthandle_channel(struct sbni_softc *sc) 357262395Sbapt{ 358262395Sbapt int req_ans; 359262395Sbapt u_char csr0; 360262395Sbapt 361262395Sbapt sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 362262395Sbapt 363262395Sbapt sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 364262395Sbapt for (;;) { 365262395Sbapt csr0 = sbni_inb(sc, CSR0); 366262395Sbapt if ((csr0 & (RC_RDY | TR_RDY)) == 0) 367266636Sbapt break; 368262395Sbapt 369262395Sbapt req_ans = !(sc->state & FL_PREV_OK); 370262395Sbapt 371262395Sbapt if (csr0 & RC_RDY) 372262395Sbapt req_ans = recv_frame(sc); 373262395Sbapt 374262395Sbapt /* 375262395Sbapt * TR_RDY always equals 1 here because we have owned the marker, 376262395Sbapt * and we set TR_REQ when disabled interrupts 377262395Sbapt */ 378262395Sbapt csr0 = sbni_inb(sc, CSR0); 379262395Sbapt if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 380262395Sbapt printf("sbni: internal error!\n"); 381262395Sbapt 382262395Sbapt /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 383262395Sbapt if (req_ans || sc->tx_frameno != 0) 384266636Sbapt send_frame(sc); 385266636Sbapt else { 386266636Sbapt /* send the marker without any data */ 387266636Sbapt sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 388266636Sbapt } 389266636Sbapt } 390266636Sbapt 391266636Sbapt sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 392266636Sbapt} 393266636Sbapt 394266636Sbapt 395266636Sbapt/* 396266636Sbapt * Routine returns 1 if it need to acknoweledge received frame. 397266636Sbapt * Empty frame received without errors won't be acknoweledged. 398266636Sbapt */ 399266636Sbapt 400262395Sbaptstatic int 401262395Sbaptrecv_frame(struct sbni_softc *sc) 402262395Sbapt{ 403262395Sbapt u_int32_t crc; 404262395Sbapt u_int framelen, frameno, ack; 405262395Sbapt u_int is_first, frame_ok; 406262395Sbapt 407262395Sbapt crc = CRC32_INITIAL; 408262395Sbapt if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 409262395Sbapt frame_ok = framelen > 4 ? 410262395Sbapt upload_data(sc, framelen, frameno, is_first, crc) : 411262395Sbapt skip_tail(sc, framelen, crc); 412262395Sbapt if (frame_ok) 413262395Sbapt interpret_ack(sc, ack); 414262395Sbapt } else 415262395Sbapt frame_ok = 0; 416262395Sbapt 417262395Sbapt sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 418262395Sbapt if (frame_ok) { 419262395Sbapt sc->state |= FL_PREV_OK; 420262395Sbapt if (framelen > 4) 421262395Sbapt sc->in_stats.all_rx_number++; 422262395Sbapt } else { 423262395Sbapt sc->state &= ~FL_PREV_OK; 424262395Sbapt change_level(sc); 425262395Sbapt sc->in_stats.all_rx_number++; 426262395Sbapt sc->in_stats.bad_rx_number++; 427262395Sbapt } 428262395Sbapt 429262395Sbapt return (!frame_ok || framelen > 4); 430262395Sbapt} 431262395Sbapt 432262395Sbapt 433262395Sbaptstatic void 434262395Sbaptsend_frame(struct sbni_softc *sc) 435262395Sbapt{ 436262395Sbapt u_int32_t crc; 437262395Sbapt u_char csr0; 438262395Sbapt 439262395Sbapt crc = CRC32_INITIAL; 440262395Sbapt if (sc->state & FL_NEED_RESEND) { 441262395Sbapt 442262395Sbapt /* if frame was sended but not ACK'ed - resend it */ 443262395Sbapt if (sc->trans_errors) { 444262395Sbapt sc->trans_errors--; 445262395Sbapt if (sc->framelen != 0) 446262395Sbapt sc->in_stats.resend_tx_number++; 447262395Sbapt } else { 448262395Sbapt /* cannot xmit with many attempts */ 449262395Sbapt drop_xmit_queue(sc); 450262395Sbapt goto do_send; 451262395Sbapt } 452262395Sbapt } else 453262395Sbapt sc->trans_errors = TR_ERROR_COUNT; 454262395Sbapt 455262395Sbapt send_frame_header(sc, &crc); 456262395Sbapt sc->state |= FL_NEED_RESEND; 457262395Sbapt /* 458262395Sbapt * FL_NEED_RESEND will be cleared after ACK, but if empty 459262395Sbapt * frame sended then in prepare_to_send next frame 460262395Sbapt */ 461262395Sbapt 462262395Sbapt 463262395Sbapt if (sc->framelen) { 464262395Sbapt download_data(sc, &crc); 465262395Sbapt sc->in_stats.all_tx_number++; 466262395Sbapt sc->state |= FL_WAIT_ACK; 467262395Sbapt } 468262395Sbapt 469262395Sbapt sbni_outsb(sc, (u_char *)&crc, sizeof crc); 470262395Sbapt 471262395Sbaptdo_send: 472262395Sbapt csr0 = sbni_inb(sc, CSR0); 473262395Sbapt sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 474262395Sbapt 475262395Sbapt if (sc->tx_frameno) { 476262395Sbapt /* next frame exists - request to send */ 477262395Sbapt sbni_outb(sc, CSR0, csr0 | TR_REQ); 478262395Sbapt } 479262395Sbapt} 480262395Sbapt 481262395Sbapt 482262395Sbaptstatic void 483262395Sbaptdownload_data(struct sbni_softc *sc, u_int32_t *crc_p) 484262395Sbapt{ 485262395Sbapt struct mbuf *m; 486262395Sbapt caddr_t data_p; 487262395Sbapt u_int data_len, pos, slice; 488262395Sbapt 489262395Sbapt data_p = NULL; /* initialized to avoid warn */ 490262395Sbapt pos = 0; 491262395Sbapt 492262395Sbapt for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 493262395Sbapt if (pos + m->m_len > sc->outpos) { 494262395Sbapt data_len = m->m_len - (sc->outpos - pos); 495262395Sbapt data_p = mtod(m, caddr_t) + (sc->outpos - pos); 496262395Sbapt 497262395Sbapt goto do_copy; 498262395Sbapt } else 499262395Sbapt pos += m->m_len; 500262395Sbapt } 501262395Sbapt 502262395Sbapt data_len = 0; 503262395Sbapt 504262395Sbaptdo_copy: 505262395Sbapt pos = 0; 506262395Sbapt do { 507262395Sbapt if (data_len) { 508262395Sbapt slice = min(data_len, sc->framelen - pos); 509262395Sbapt sbni_outsb(sc, data_p, slice); 510262395Sbapt *crc_p = calc_crc32(*crc_p, data_p, slice); 511262395Sbapt 512262395Sbapt pos += slice; 513262395Sbapt if (data_len -= slice) 514262395Sbapt data_p += slice; 515262395Sbapt else { 516262395Sbapt do { 517262395Sbapt m = m->m_next; 518262395Sbapt } while (m != NULL && m->m_len == 0); 519262395Sbapt 520262395Sbapt if (m) { 521262395Sbapt data_len = m->m_len; 522262395Sbapt data_p = mtod(m, caddr_t); 523262395Sbapt } 524262395Sbapt } 525262395Sbapt } else { 526262395Sbapt /* frame too short - zero padding */ 527262395Sbapt 528262395Sbapt pos = sc->framelen - pos; 529262395Sbapt while (pos--) { 530262395Sbapt sbni_outb(sc, DAT, 0); 531262395Sbapt *crc_p = CRC32(0, *crc_p); 532262395Sbapt } 533262395Sbapt return; 534262395Sbapt } 535262395Sbapt } while (pos < sc->framelen); 536262395Sbapt} 537262395Sbapt 538262395Sbapt 539262395Sbaptstatic int 540262395Sbaptupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 541262395Sbapt u_int is_first, u_int32_t crc) 542262395Sbapt{ 543262395Sbapt int frame_ok; 544262395Sbapt 545262395Sbapt if (is_first) { 546262395Sbapt sc->wait_frameno = frameno; 547262395Sbapt sc->inppos = 0; 548262395Sbapt } 549262395Sbapt 550262395Sbapt if (sc->wait_frameno == frameno) { 551262395Sbapt 552262395Sbapt if (sc->inppos + framelen <= ETHER_MAX_LEN) { 553262395Sbapt frame_ok = append_frame_to_pkt(sc, framelen, crc); 554263648Sbapt 555263648Sbapt /* 556263648Sbapt * if CRC is right but framelen incorrect then transmitter 557263648Sbapt * error was occured... drop entire packet 558262395Sbapt */ 559262395Sbapt } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 560262395Sbapt sc->wait_frameno = 0; 561262395Sbapt sc->inppos = 0; 562262395Sbapt sc->ifp->if_ierrors++; 563262395Sbapt /* now skip all frames until is_first != 0 */ 564262395Sbapt } 565262395Sbapt } else 566262395Sbapt frame_ok = skip_tail(sc, framelen, crc); 567262395Sbapt 568263648Sbapt if (is_first && !frame_ok) { 569263648Sbapt /* 570262395Sbapt * Frame has been violated, but we have stored 571262395Sbapt * is_first already... Drop entire packet. 572262395Sbapt */ 573262395Sbapt sc->wait_frameno = 0; 574263648Sbapt sc->ifp->if_ierrors++; 575262395Sbapt } 576262395Sbapt 577262395Sbapt return (frame_ok); 578262395Sbapt} 579262395Sbapt 580262395Sbapt 581262395Sbaptstatic __inline void send_complete(struct sbni_softc *); 582262395Sbapt 583262395Sbaptstatic __inline void 584262395Sbaptsend_complete(struct sbni_softc *sc) 585262395Sbapt{ 586262395Sbapt m_freem(sc->tx_buf_p); 587262395Sbapt sc->tx_buf_p = NULL; 588262395Sbapt sc->ifp->if_opackets++; 589262395Sbapt} 590262395Sbapt 591262395Sbapt 592262395Sbaptstatic void 593262395Sbaptinterpret_ack(struct sbni_softc *sc, u_int ack) 594262395Sbapt{ 595262395Sbapt if (ack == FRAME_SENT_OK) { 596262395Sbapt sc->state &= ~FL_NEED_RESEND; 597262395Sbapt 598262395Sbapt if (sc->state & FL_WAIT_ACK) { 599262395Sbapt sc->outpos += sc->framelen; 600262395Sbapt 601262395Sbapt if (--sc->tx_frameno) { 602262395Sbapt sc->framelen = min( 603262395Sbapt sc->maxframe, sc->pktlen - sc->outpos); 604262395Sbapt } else { 605262395Sbapt send_complete(sc); 606262395Sbapt prepare_to_send(sc); 607262395Sbapt } 608262395Sbapt } 609262395Sbapt } 610262395Sbapt 611262395Sbapt sc->state &= ~FL_WAIT_ACK; 612262395Sbapt} 613262395Sbapt 614262395Sbapt 615262395Sbapt/* 616262395Sbapt * Glue received frame with previous fragments of packet. 617262395Sbapt * Indicate packet when last frame would be accepted. 618262395Sbapt */ 619262395Sbapt 620262395Sbaptstatic int 621262395Sbaptappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 622262395Sbapt{ 623262395Sbapt caddr_t p; 624262395Sbapt 625262395Sbapt if (sc->inppos + framelen > ETHER_MAX_LEN) 626262395Sbapt return (0); 627262395Sbapt 628262395Sbapt if (!sc->rx_buf_p && !get_rx_buf(sc)) 629262395Sbapt return (0); 630262395Sbapt 631262395Sbapt p = sc->rx_buf_p->m_data + sc->inppos; 632262395Sbapt sbni_insb(sc, p, framelen); 633262395Sbapt if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 634262395Sbapt return (0); 635262395Sbapt 636262395Sbapt sc->inppos += framelen - 4; 637262395Sbapt if (--sc->wait_frameno == 0) { /* last frame received */ 638262395Sbapt indicate_pkt(sc); 639262395Sbapt sc->ifp->if_ipackets++; 640262395Sbapt } 641262395Sbapt 642262395Sbapt return (1); 643262395Sbapt} 644262395Sbapt 645262395Sbapt 646262395Sbapt/* 647262395Sbapt * Prepare to start output on adapter. Current priority must be set to splimp 648262395Sbapt * before this routine is called. 649262395Sbapt * Transmitter will be actually activated when marker has been accepted. 650262395Sbapt */ 651262395Sbapt 652262395Sbaptstatic void 653262395Sbaptprepare_to_send(struct sbni_softc *sc) 654262395Sbapt{ 655262395Sbapt struct mbuf *m; 656262395Sbapt u_int len; 657262395Sbapt 658262395Sbapt /* sc->tx_buf_p == NULL here! */ 659262395Sbapt if (sc->tx_buf_p) 660262395Sbapt printf("sbni: memory leak!\n"); 661262395Sbapt 662262395Sbapt sc->outpos = 0; 663262395Sbapt sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 664262395Sbapt 665262395Sbapt for (;;) { 666262395Sbapt IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p); 667262395Sbapt if (!sc->tx_buf_p) { 668262395Sbapt /* nothing to transmit... */ 669262395Sbapt sc->pktlen = 0; 670262395Sbapt sc->tx_frameno = 0; 671262395Sbapt sc->framelen = 0; 672263648Sbapt sc->ifp->if_flags &= ~IFF_OACTIVE; 673263648Sbapt return; 674262395Sbapt } 675262395Sbapt 676262395Sbapt for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 677262395Sbapt len += m->m_len; 678262395Sbapt 679262395Sbapt if (len != 0) 680262395Sbapt break; 681262395Sbapt m_freem(sc->tx_buf_p); 682262395Sbapt } 683262395Sbapt 684262395Sbapt if (len < SBNI_MIN_LEN) 685262395Sbapt len = SBNI_MIN_LEN; 686262395Sbapt 687262395Sbapt sc->pktlen = len; 688262395Sbapt sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe; 689262395Sbapt sc->framelen = min(len, sc->maxframe); 690262395Sbapt 691262395Sbapt sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 692262395Sbapt sc->ifp->if_flags |= IFF_OACTIVE; 693262395Sbapt BPF_MTAP(sc->ifp, sc->tx_buf_p); 694263648Sbapt} 695262395Sbapt 696262395Sbapt 697262395Sbaptstatic void 698262395Sbaptdrop_xmit_queue(struct sbni_softc *sc) 699262395Sbapt{ 700262395Sbapt struct mbuf *m; 701262395Sbapt 702262395Sbapt if (sc->tx_buf_p) { 703262395Sbapt m_freem(sc->tx_buf_p); 704262395Sbapt sc->tx_buf_p = NULL; 705262395Sbapt sc->ifp->if_oerrors++; 706262395Sbapt } 707262395Sbapt 708262395Sbapt for (;;) { 709262395Sbapt IF_DEQUEUE(&sc->ifp->if_snd, m); 710262395Sbapt if (m == NULL) 711262395Sbapt break; 712262395Sbapt m_freem(m); 713262395Sbapt sc->ifp->if_oerrors++; 714262395Sbapt } 715262395Sbapt 716262395Sbapt sc->tx_frameno = 0; 717262395Sbapt sc->framelen = 0; 718262395Sbapt sc->outpos = 0; 719262395Sbapt sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 720262395Sbapt sc->ifp->if_flags &= ~IFF_OACTIVE; 721262395Sbapt} 722262395Sbapt 723262395Sbapt 724263648Sbaptstatic void 725262395Sbaptsend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 726262395Sbapt{ 727262395Sbapt u_int32_t crc; 728262395Sbapt u_int len_field; 729262395Sbapt u_char value; 730262395Sbapt 731262395Sbapt crc = *crc_p; 732262395Sbapt len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 733263648Sbapt 734262395Sbapt if (sc->state & FL_NEED_RESEND) 735262395Sbapt len_field |= FRAME_RETRY; /* non-first attempt... */ 736262395Sbapt 737262395Sbapt if (sc->outpos == 0) 738262395Sbapt len_field |= FRAME_FIRST; 739262395Sbapt 740262395Sbapt len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 741262395Sbapt sbni_outb(sc, DAT, SBNI_SIG); 742262395Sbapt 743262395Sbapt value = (u_char)len_field; 744262395Sbapt sbni_outb(sc, DAT, value); 745262395Sbapt crc = CRC32(value, crc); 746262395Sbapt value = (u_char)(len_field >> 8); 747262395Sbapt sbni_outb(sc, DAT, value); 748262395Sbapt crc = CRC32(value, crc); 749262395Sbapt 750262395Sbapt sbni_outb(sc, DAT, sc->tx_frameno); 751262395Sbapt crc = CRC32(sc->tx_frameno, crc); 752262395Sbapt sbni_outb(sc, DAT, 0); 753263648Sbapt crc = CRC32(0, crc); 754263648Sbapt *crc_p = crc; 755262395Sbapt} 756262395Sbapt 757262395Sbapt 758262395Sbapt/* 759262395Sbapt * if frame tail not needed (incorrect number or received twice), 760263648Sbapt * it won't store, but CRC will be calculated 761262395Sbapt */ 762262395Sbapt 763262395Sbaptstatic int 764262395Sbaptskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 765262395Sbapt{ 766262395Sbapt while (tail_len--) 767262395Sbapt crc = CRC32(sbni_inb(sc, DAT), crc); 768262395Sbapt 769262395Sbapt return (crc == CRC32_REMAINDER); 770262395Sbapt} 771262395Sbapt 772263648Sbapt 773263648Sbaptstatic int 774262395Sbaptcheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 775262395Sbapt u_int *ack, u_int *is_first, u_int32_t *crc_p) 776262395Sbapt{ 777262395Sbapt u_int32_t crc; 778263648Sbapt u_char value; 779262395Sbapt 780262395Sbapt crc = *crc_p; 781262395Sbapt if (sbni_inb(sc, DAT) != SBNI_SIG) 782262395Sbapt return (0); 783262395Sbapt 784262395Sbapt value = sbni_inb(sc, DAT); 785262395Sbapt *framelen = (u_int)value; 786262395Sbapt crc = CRC32(value, crc); 787262395Sbapt value = sbni_inb(sc, DAT); 788262395Sbapt *framelen |= ((u_int)value) << 8; 789262395Sbapt crc = CRC32(value, crc); 790262395Sbapt 791263648Sbapt *ack = *framelen & FRAME_ACK_MASK; 792263648Sbapt *is_first = (*framelen & FRAME_FIRST) != 0; 793262395Sbapt 794262395Sbapt if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 795262395Sbapt return (0); 796262395Sbapt 797262395Sbapt value = sbni_inb(sc, DAT); 798262395Sbapt *frameno = (u_int)value; 799262395Sbapt crc = CRC32(value, crc); 800262395Sbapt 801262395Sbapt crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 802262395Sbapt *framelen -= 2; 803262395Sbapt 804262395Sbapt *crc_p = crc; 805262395Sbapt return (1); 806262395Sbapt} 807262395Sbapt 808262395Sbapt 809262395Sbaptstatic int 810262395Sbaptget_rx_buf(struct sbni_softc *sc) 811262395Sbapt{ 812262395Sbapt struct mbuf *m; 813262395Sbapt 814262395Sbapt MGETHDR(m, M_DONTWAIT, MT_DATA); 815262395Sbapt if (m == NULL) { 816262395Sbapt if_printf(sc->ifp, "cannot allocate header mbuf\n"); 817262395Sbapt return (0); 818262395Sbapt } 819262395Sbapt 820262395Sbapt /* 821263648Sbapt * We always put the received packet in a single buffer - 822263648Sbapt * either with just an mbuf header or in a cluster attached 823262395Sbapt * to the header. The +2 is to compensate for the alignment 824262395Sbapt * fixup below. 825262395Sbapt */ 826262395Sbapt if (ETHER_MAX_LEN + 2 > MHLEN) { 827262395Sbapt /* Attach an mbuf cluster */ 828262395Sbapt MCLGET(m, M_DONTWAIT); 829262395Sbapt if ((m->m_flags & M_EXT) == 0) { 830262395Sbapt m_freem(m); 831262395Sbapt return (0); 832262395Sbapt } 833262395Sbapt } 834262395Sbapt m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 835262395Sbapt 836262395Sbapt /* 837262395Sbapt * The +2 is to longword align the start of the real packet. 838262395Sbapt * (sizeof ether_header == 14) 839262395Sbapt * This is important for NFS. 840262395Sbapt */ 841262395Sbapt m_adj(m, 2); 842262395Sbapt sc->rx_buf_p = m; 843262395Sbapt return (1); 844262395Sbapt} 845262395Sbapt 846262395Sbapt 847262395Sbaptstatic void 848262395Sbaptindicate_pkt(struct sbni_softc *sc) 849262395Sbapt{ 850262395Sbapt struct ifnet *ifp = sc->ifp; 851262395Sbapt struct mbuf *m; 852262395Sbapt 853262395Sbapt m = sc->rx_buf_p; 854262395Sbapt m->m_pkthdr.rcvif = ifp; 855262395Sbapt m->m_pkthdr.len = m->m_len = sc->inppos; 856262395Sbapt 857262395Sbapt (*ifp->if_input)(ifp, m); 858262395Sbapt sc->rx_buf_p = NULL; 859262395Sbapt} 860262395Sbapt 861262395Sbapt/* -------------------------------------------------------------------------- */ 862262395Sbapt 863262395Sbapt/* 864262395Sbapt * Routine checks periodically wire activity and regenerates marker if 865262395Sbapt * connect was inactive for a long time. 866262395Sbapt */ 867262395Sbapt 868262395Sbaptstatic void 869262395Sbaptsbni_timeout(void *xsc) 870262395Sbapt{ 871262395Sbapt struct sbni_softc *sc; 872262395Sbapt int s; 873262395Sbapt u_char csr0; 874262395Sbapt 875262395Sbapt sc = (struct sbni_softc *)xsc; 876262395Sbapt s = splimp(); 877262395Sbapt 878262395Sbapt csr0 = sbni_inb(sc, CSR0); 879262395Sbapt if (csr0 & RC_CHK) { 880262395Sbapt 881262395Sbapt if (sc->timer_ticks) { 882262395Sbapt if (csr0 & (RC_RDY | BU_EMP)) 883262395Sbapt /* receiving not active */ 884262395Sbapt sc->timer_ticks--; 885262395Sbapt } else { 886262395Sbapt sc->in_stats.timeout_number++; 887262395Sbapt if (sc->delta_rxl) 888262395Sbapt timeout_change_level(sc); 889262395Sbapt 890262395Sbapt sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 891262395Sbapt csr0 = sbni_inb(sc, CSR0); 892262395Sbapt } 893262395Sbapt } 894262395Sbapt 895262395Sbapt sbni_outb(sc, CSR0, csr0 | RC_CHK); 896262395Sbapt sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 897262395Sbapt splx(s); 898262395Sbapt} 899262395Sbapt 900262395Sbapt/* -------------------------------------------------------------------------- */ 901262395Sbapt 902262395Sbaptstatic void 903262395Sbaptcard_start(struct sbni_softc *sc) 904262395Sbapt{ 905262395Sbapt sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 906262395Sbapt sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 907262395Sbapt sc->state |= FL_PREV_OK; 908262395Sbapt 909262395Sbapt sc->inppos = 0; 910262395Sbapt sc->wait_frameno = 0; 911262395Sbapt 912262395Sbapt sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 913262395Sbapt sbni_outb(sc, CSR0, EN_INT); 914262395Sbapt} 915262395Sbapt 916262395Sbapt/* -------------------------------------------------------------------------- */ 917262395Sbapt 918262395Sbapt/* 919262395Sbapt * Device timeout/watchdog routine. Entered if the device neglects to 920262395Sbapt * generate an interrupt after a transmit has been started on it. 921262395Sbapt */ 922262395Sbapt 923262395Sbaptstatic void 924262395Sbaptsbni_watchdog(struct ifnet *ifp) 925262395Sbapt{ 926262395Sbapt log(LOG_ERR, "%s: device timeout\n", ifp->if_xname); 927262395Sbapt ifp->if_oerrors++; 928262395Sbapt} 929262395Sbapt 930262395Sbapt 931262395Sbaptstatic u_char rxl_tab[] = { 932262395Sbapt 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 933262395Sbapt 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 934262395Sbapt}; 935262395Sbapt 936262395Sbapt#define SIZE_OF_TIMEOUT_RXL_TAB 4 937262395Sbaptstatic u_char timeout_rxl_tab[] = { 938262395Sbapt 0x03, 0x05, 0x08, 0x0b 939262395Sbapt}; 940262395Sbapt 941262395Sbaptstatic void 942262395Sbaptset_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 943262395Sbapt{ 944262395Sbapt if (flags.fixed_rxl) { 945262395Sbapt sc->delta_rxl = 0; /* disable receive level autodetection */ 946262395Sbapt sc->cur_rxl_index = flags.rxl; 947262395Sbapt } else { 948262395Sbapt sc->delta_rxl = DEF_RXL_DELTA; 949262395Sbapt sc->cur_rxl_index = DEF_RXL; 950262395Sbapt } 951262395Sbapt 952262395Sbapt sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 953262395Sbapt sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 954262395Sbapt sc->maxframe = DEFAULT_FRAME_LEN; 955262395Sbapt 956262395Sbapt /* 957262395Sbapt * generate Ethernet address (0x00ff01xxxxxx) 958262395Sbapt */ 959262395Sbapt *(u_int16_t *) sc->enaddr = htons(0x00ff); 960262395Sbapt if (flags.mac_addr) { 961262395Sbapt *(u_int32_t *) (sc->enaddr + 2) = 962262395Sbapt htonl(flags.mac_addr | 0x01000000); 963262395Sbapt } else { 964262395Sbapt *(u_char *) (sc->enaddr + 2) = 0x01; 965262395Sbapt read_random(sc->enaddr + 3, 3); 966262395Sbapt } 967262395Sbapt} 968262395Sbapt 969262395Sbapt 970262395Sbapt#ifdef SBNI_DUAL_COMPOUND 971262395Sbapt 972262395Sbaptstruct sbni_softc * 973262395Sbaptconnect_to_master(struct sbni_softc *sc) 974262395Sbapt{ 975262395Sbapt struct sbni_softc *p, *p_prev; 976262395Sbapt 977262395Sbapt for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { 978262395Sbapt if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || 979262395Sbapt rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { 980262395Sbapt p->slave_sc = sc; 981262395Sbapt if (p_prev) 982262395Sbapt p_prev->link = p->link; 983262395Sbapt else 984262395Sbapt sbni_headlist = p->link; 985262395Sbapt return p; 986262395Sbapt } 987262395Sbapt } 988262395Sbapt 989262395Sbapt return (NULL); 990262395Sbapt} 991262395Sbapt 992262395Sbapt#endif /* SBNI_DUAL_COMPOUND */ 993262395Sbapt 994262395Sbapt 995262395Sbapt/* Receive level auto-selection */ 996262395Sbapt 997262395Sbaptstatic void 998262395Sbaptchange_level(struct sbni_softc *sc) 999262395Sbapt{ 1000262395Sbapt if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 1001262395Sbapt return; 1002262395Sbapt 1003262395Sbapt if (sc->cur_rxl_index == 0) 1004262395Sbapt sc->delta_rxl = 1; 1005262395Sbapt else if (sc->cur_rxl_index == 15) 1006262395Sbapt sc->delta_rxl = -1; 1007262395Sbapt else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 1008262395Sbapt sc->delta_rxl = -sc->delta_rxl; 1009262395Sbapt 1010262395Sbapt sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 1011262395Sbapt sbni_inb(sc, CSR0); /* it needed for PCI cards */ 1012262395Sbapt sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1013262395Sbapt 1014262395Sbapt sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1015262395Sbapt sc->cur_rxl_rcvd = 0; 1016262395Sbapt} 1017262395Sbapt 1018262395Sbapt 1019262395Sbaptstatic void 1020262395Sbapttimeout_change_level(struct sbni_softc *sc) 1021262395Sbapt{ 1022262395Sbapt sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 1023262395Sbapt if (++sc->timeout_rxl >= 4) 1024262395Sbapt sc->timeout_rxl = 0; 1025262395Sbapt 1026262395Sbapt sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1027262395Sbapt sbni_inb(sc, CSR0); 1028262395Sbapt sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1029262395Sbapt 1030262395Sbapt sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1031262395Sbapt sc->cur_rxl_rcvd = 0; 1032262395Sbapt} 1033262395Sbapt 1034262395Sbapt/* -------------------------------------------------------------------------- */ 1035262395Sbapt 1036262395Sbapt/* 1037262395Sbapt * Process an ioctl request. This code needs some work - it looks 1038262395Sbapt * pretty ugly. 1039262395Sbapt */ 1040262395Sbapt 1041262395Sbaptstatic int 1042262395Sbaptsbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1043262395Sbapt{ 1044262395Sbapt struct sbni_softc *sc; 1045262395Sbapt struct ifreq *ifr; 1046262395Sbapt struct thread *td; 1047262395Sbapt struct sbni_in_stats *in_stats; 1048262395Sbapt struct sbni_flags flags; 1049262395Sbapt int error, s; 1050262395Sbapt 1051262395Sbapt sc = ifp->if_softc; 1052262395Sbapt ifr = (struct ifreq *)data; 1053262395Sbapt td = curthread; 1054262395Sbapt error = 0; 1055262395Sbapt 1056262395Sbapt s = splimp(); 1057262395Sbapt 1058262395Sbapt switch (command) { 1059262395Sbapt case SIOCSIFFLAGS: 1060262395Sbapt /* 1061262395Sbapt * If the interface is marked up and stopped, then start it. 1062262395Sbapt * If it is marked down and running, then stop it. 1063262395Sbapt */ 1064262395Sbapt if (ifp->if_flags & IFF_UP) { 1065262395Sbapt if (!(ifp->if_flags & IFF_RUNNING)) 1066262395Sbapt sbni_init(sc); 1067262395Sbapt } else { 1068262395Sbapt if (ifp->if_flags & IFF_RUNNING) { 1069262395Sbapt sbni_stop(sc); 1070262395Sbapt ifp->if_flags &= ~IFF_RUNNING; 1071262395Sbapt } 1072262395Sbapt } 1073262395Sbapt break; 1074262395Sbapt 1075262395Sbapt case SIOCADDMULTI: 1076262395Sbapt case SIOCDELMULTI: 1077262395Sbapt /* 1078262395Sbapt * Multicast list has changed; set the hardware filter 1079262395Sbapt * accordingly. 1080262395Sbapt */ 1081262395Sbapt error = 0; 1082262395Sbapt /* if (ifr == NULL) 1083262395Sbapt error = EAFNOSUPPORT; */ 1084262395Sbapt break; 1085262395Sbapt 1086262395Sbapt case SIOCSIFMTU: 1087262395Sbapt if (ifr->ifr_mtu > ETHERMTU) 1088262395Sbapt error = EINVAL; 1089262395Sbapt else 1090262395Sbapt ifp->if_mtu = ifr->ifr_mtu; 1091262395Sbapt break; 1092262395Sbapt 1093262395Sbapt /* 1094262395Sbapt * SBNI specific ioctl 1095262395Sbapt */ 1096264789Sbapt case SIOCGHWFLAGS: /* get flags */ 1097262395Sbapt bcopy((caddr_t)IFP2ENADDR(sc->ifp)+3, (caddr_t) &flags, 3); 1098262395Sbapt flags.rxl = sc->cur_rxl_index; 1099262395Sbapt flags.rate = sc->csr1.rate; 1100262395Sbapt flags.fixed_rxl = (sc->delta_rxl == 0); 1101264789Sbapt flags.fixed_rate = 1; 1102262395Sbapt ifr->ifr_data = *(caddr_t*) &flags; 1103262395Sbapt break; 1104262395Sbapt 1105262395Sbapt case SIOCGINSTATS: 1106262395Sbapt in_stats = (struct sbni_in_stats *)ifr->ifr_data; 1107262395Sbapt bcopy((void *)(&(sc->in_stats)), (void *)in_stats, 1108264789Sbapt sizeof(struct sbni_in_stats)); 1109262395Sbapt break; 1110262395Sbapt 1111262395Sbapt case SIOCSHWFLAGS: /* set flags */ 1112262395Sbapt /* root only */ 1113262395Sbapt error = suser(td); 1114262395Sbapt if (error) 1115262395Sbapt break; 1116262395Sbapt flags = *(struct sbni_flags*)&ifr->ifr_data; 1117262395Sbapt if (flags.fixed_rxl) { 1118262395Sbapt sc->delta_rxl = 0; 1119262395Sbapt sc->cur_rxl_index = flags.rxl; 1120262395Sbapt } else { 1121262395Sbapt sc->delta_rxl = DEF_RXL_DELTA; 1122262395Sbapt sc->cur_rxl_index = DEF_RXL; 1123262395Sbapt } 1124262395Sbapt sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1125262395Sbapt sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 1126262395Sbapt if (flags.mac_addr) 1127262395Sbapt bcopy((caddr_t) &flags, 1128262395Sbapt (caddr_t) IFP2ENADDR(sc->ifp)+3, 3); 1129262395Sbapt 1130262395Sbapt /* Don't be afraid... */ 1131262395Sbapt sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 1132262395Sbapt break; 1133262395Sbapt 1134262395Sbapt case SIOCRINSTATS: 1135262395Sbapt if (!(error = suser(td))) /* root only */ 1136262395Sbapt bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 1137262395Sbapt break; 1138262395Sbapt 1139262395Sbapt default: 1140262395Sbapt error = ether_ioctl(ifp, command, data); 1141262395Sbapt break; 1142262395Sbapt } 1143262395Sbapt 1144262395Sbapt splx(s); 1145262395Sbapt return (error); 1146262395Sbapt} 1147262395Sbapt 1148262395Sbapt/* -------------------------------------------------------------------------- */ 1149262395Sbapt 1150262395Sbapt#ifdef ASM_CRC 1151262395Sbapt 1152262395Sbaptstatic u_int32_t 1153262395Sbaptcalc_crc32(u_int32_t crc, caddr_t p, u_int len) 1154262395Sbapt{ 1155262395Sbapt register u_int32_t _crc __asm ("ax"); 1156262395Sbapt _crc = crc; 1157262395Sbapt 1158262395Sbapt __asm __volatile ( 1159262395Sbapt "xorl %%ebx, %%ebx\n" 1160262395Sbapt "movl %1, %%esi\n" 1161262395Sbapt "movl %2, %%ecx\n" 1162262395Sbapt "movl $crc32tab, %%edi\n" 1163262395Sbapt "shrl $2, %%ecx\n" 1164262395Sbapt "jz 1f\n" 1165262395Sbapt 1166262395Sbapt ".align 4\n" 1167262395Sbapt "0:\n" 1168262395Sbapt "movb %%al, %%bl\n" 1169262395Sbapt "movl (%%esi), %%edx\n" 1170262395Sbapt "shrl $8, %%eax\n" 1171262395Sbapt "xorb %%dl, %%bl\n" 1172262395Sbapt "shrl $8, %%edx\n" 1173262395Sbapt "xorl (%%edi,%%ebx,4), %%eax\n" 1174262395Sbapt 1175262395Sbapt "movb %%al, %%bl\n" 1176262395Sbapt "shrl $8, %%eax\n" 1177262395Sbapt "xorb %%dl, %%bl\n" 1178262395Sbapt "shrl $8, %%edx\n" 1179262395Sbapt "xorl (%%edi,%%ebx,4), %%eax\n" 1180262395Sbapt 1181262395Sbapt "movb %%al, %%bl\n" 1182262395Sbapt "shrl $8, %%eax\n" 1183262395Sbapt "xorb %%dl, %%bl\n" 1184262395Sbapt "movb %%dh, %%dl\n" 1185262395Sbapt "xorl (%%edi,%%ebx,4), %%eax\n" 1186262395Sbapt 1187262395Sbapt "movb %%al, %%bl\n" 1188262395Sbapt "shrl $8, %%eax\n" 1189262395Sbapt "xorb %%dl, %%bl\n" 1190262395Sbapt "addl $4, %%esi\n" 1191262395Sbapt "xorl (%%edi,%%ebx,4), %%eax\n" 1192262395Sbapt 1193262395Sbapt "decl %%ecx\n" 1194262395Sbapt "jnz 0b\n" 1195262395Sbapt 1196262395Sbapt "1:\n" 1197262395Sbapt "movl %2, %%ecx\n" 1198262395Sbapt "andl $3, %%ecx\n" 1199262395Sbapt "jz 2f\n" 1200262395Sbapt 1201262395Sbapt "movb %%al, %%bl\n" 1202262395Sbapt "shrl $8, %%eax\n" 1203262395Sbapt "xorb (%%esi), %%bl\n" 1204262395Sbapt "xorl (%%edi,%%ebx,4), %%eax\n" 1205262395Sbapt 1206262395Sbapt "decl %%ecx\n" 1207262395Sbapt "jz 2f\n" 1208262395Sbapt 1209262395Sbapt "movb %%al, %%bl\n" 1210262395Sbapt "shrl $8, %%eax\n" 1211262395Sbapt "xorb 1(%%esi), %%bl\n" 1212262395Sbapt "xorl (%%edi,%%ebx,4), %%eax\n" 1213262395Sbapt 1214262395Sbapt "decl %%ecx\n" 1215262395Sbapt "jz 2f\n" 1216262395Sbapt 1217262395Sbapt "movb %%al, %%bl\n" 1218262395Sbapt "shrl $8, %%eax\n" 1219262395Sbapt "xorb 2(%%esi), %%bl\n" 1220262395Sbapt "xorl (%%edi,%%ebx,4), %%eax\n" 1221262395Sbapt "2:\n" 1222262395Sbapt : "=a" (_crc) 1223262395Sbapt : "g" (p), "g" (len) 1224262395Sbapt : "bx", "cx", "dx", "si", "di" 1225262395Sbapt ); 1226262395Sbapt 1227262395Sbapt return (_crc); 1228262395Sbapt} 1229262395Sbapt 1230262395Sbapt#else /* ASM_CRC */ 1231262395Sbapt 1232262395Sbaptstatic u_int32_t 1233262395Sbaptcalc_crc32(u_int32_t crc, caddr_t p, u_int len) 1234262395Sbapt{ 1235262395Sbapt while (len--) 1236262395Sbapt crc = CRC32(*p++, crc); 1237262395Sbapt 1238262395Sbapt return (crc); 1239262395Sbapt} 1240262395Sbapt 1241262395Sbapt#endif /* ASM_CRC */ 1242262395Sbapt 1243262395Sbapt 1244262395Sbaptstatic u_int32_t crc32tab[] __aligned(8) = { 1245262395Sbapt 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 1246262395Sbapt 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 1247262395Sbapt 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 1248262395Sbapt 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 1249262395Sbapt 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 1250262395Sbapt 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 1251262395Sbapt 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 1252262975Sbapt 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 1253262975Sbapt 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 1254262975Sbapt 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 1255262975Sbapt 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 1256262975Sbapt 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 1257262975Sbapt 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 1258262975Sbapt 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 1259262975Sbapt 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 1260262975Sbapt 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 1261262975Sbapt 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 1262262975Sbapt 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 1263262975Sbapt 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 1264262975Sbapt 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 1265262975Sbapt 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 1266262975Sbapt 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 1267262975Sbapt 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 1268262975Sbapt 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 1269262975Sbapt 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 1270262975Sbapt 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 1271262975Sbapt 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 1272262975Sbapt 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 1273262975Sbapt 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 1274262395Sbapt 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 1275262395Sbapt 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 1276262395Sbapt 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 1277262395Sbapt 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 1278262395Sbapt 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 1279262395Sbapt 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 1280262395Sbapt 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 1281262395Sbapt 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 1282262395Sbapt 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 1283262395Sbapt 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 1284262975Sbapt 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 1285262395Sbapt 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 1286262395Sbapt 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 1287262395Sbapt 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 1288262395Sbapt 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 1289262395Sbapt 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 1290262395Sbapt 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 1291262975Sbapt 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 1292262975Sbapt 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 1293262975Sbapt 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 1294262975Sbapt 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 1295262975Sbapt 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 1296262975Sbapt 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 1297262975Sbapt 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 1298262975Sbapt 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 1299262975Sbapt 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 1300262975Sbapt 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 1301262975Sbapt 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 1302262975Sbapt 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 1303262395Sbapt 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 1304262395Sbapt 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 1305262395Sbapt 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 1306262395Sbapt 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 1307262975Sbapt 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 1308262395Sbapt 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 1309262395Sbapt}; 1310262395Sbapt