if_sbni.c revision 101393
1/* 2 * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved. 3 * Author: Denis I.Timofeev <timofeev@granch.ru> 4 * 5 * Redistributon and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/dev/sbni/if_sbni.c 101393 2002-08-05 17:20:17Z fjoe $ 28 */ 29 30/* 31 * Device driver for Granch SBNI12 leased line adapters 32 * 33 * Revision 2.0.0 1997/08/06 34 * Initial revision by Alexey Zverev 35 * 36 * Revision 2.0.1 1997/08/11 37 * Additional internal statistics support (tx statistics) 38 * 39 * Revision 2.0.2 1997/11/05 40 * if_bpf bug has been fixed 41 * 42 * Revision 2.0.3 1998/12/20 43 * Memory leakage has been eliminated in 44 * the sbni_st and sbni_timeout routines. 45 * 46 * Revision 3.0 2000/08/10 by Yaroslav Polyakov 47 * Support for PCI cards. 4.1 modification. 48 * 49 * Revision 3.1 2000/09/12 50 * Removed extra #defines around bpf functions 51 * 52 * Revision 4.0 2000/11/23 by Denis Timofeev 53 * Completely redesigned the buffer management 54 * 55 * Revision 4.1 2001/01/21 56 * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards 57 * 58 * Written with reference to NE2000 driver developed by David Greenman. 59 */ 60 61 62#include <sys/param.h> 63#include <sys/systm.h> 64#include <sys/socket.h> 65#include <sys/sockio.h> 66#include <sys/mbuf.h> 67#include <sys/kernel.h> 68#include <sys/proc.h> 69#include <sys/callout.h> 70#include <sys/syslog.h> 71 72#include <net/if.h> 73#include <net/ethernet.h> 74#include <net/if_arp.h> 75#include <net/bpf.h> 76 77#include <dev/sbni/if_sbnireg.h> 78#include <dev/sbni/if_sbnivar.h> 79 80#define ASM_CRC 1 81 82static void sbni_init(void *); 83static void sbni_start(struct ifnet *); 84static int sbni_ioctl(struct ifnet *, u_long, caddr_t); 85static void sbni_watchdog(struct ifnet *); 86static void sbni_stop(struct sbni_softc *); 87static void handle_channel(struct sbni_softc *); 88 89static void card_start(struct sbni_softc *); 90static int recv_frame(struct sbni_softc *); 91static void send_frame(struct sbni_softc *); 92static int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 93static int skip_tail(struct sbni_softc *, u_int, u_int32_t); 94static void interpret_ack(struct sbni_softc *, u_int); 95static void download_data(struct sbni_softc *, u_int32_t *); 96static void prepare_to_send(struct sbni_softc *); 97static void drop_xmit_queue(struct sbni_softc *); 98static int get_rx_buf(struct sbni_softc *); 99static void indicate_pkt(struct sbni_softc *); 100static void change_level(struct sbni_softc *); 101static int check_fhdr(struct sbni_softc *, u_int *, u_int *, 102 u_int *, u_int *, u_int32_t *); 103static int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 104static void timeout_change_level(struct sbni_softc *); 105static void send_frame_header(struct sbni_softc *, u_int32_t *); 106static void set_initial_values(struct sbni_softc *, struct sbni_flags); 107 108static u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 109static timeout_t sbni_timeout; 110 111static __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 112static __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 113static __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 114static __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 115 116static u_int32_t crc32tab[]; 117 118#ifdef SBNI_DUAL_COMPOUND 119struct sbni_softc *sbni_headlist; 120#endif 121 122u_int32_t next_sbni_unit; 123 124/* -------------------------------------------------------------------------- */ 125 126static __inline u_char 127sbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 128{ 129 return (inb(sc->base_addr + reg)); 130} 131 132static __inline void 133sbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 134{ 135 outb(sc->base_addr + reg, value); 136} 137 138static __inline void 139sbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 140{ 141 insb(sc->base_addr + DAT, to, len); 142} 143 144static __inline void 145sbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 146{ 147 outsb(sc->base_addr + DAT, from, len); 148} 149 150 151/* 152 Valid combinations in CSR0 (for probing): 153 154 VALID_DECODER 0000,0011,1011,1010 155 156 ; 0 ; - 157 TR_REQ ; 1 ; + 158 TR_RDY ; 2 ; - 159 TR_RDY TR_REQ ; 3 ; + 160 BU_EMP ; 4 ; + 161 BU_EMP TR_REQ ; 5 ; + 162 BU_EMP TR_RDY ; 6 ; - 163 BU_EMP TR_RDY TR_REQ ; 7 ; + 164 RC_RDY ; 8 ; + 165 RC_RDY TR_REQ ; 9 ; + 166 RC_RDY TR_RDY ; 10 ; - 167 RC_RDY TR_RDY TR_REQ ; 11 ; - 168 RC_RDY BU_EMP ; 12 ; - 169 RC_RDY BU_EMP TR_REQ ; 13 ; - 170 RC_RDY BU_EMP TR_RDY ; 14 ; - 171 RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 172*/ 173 174#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 175 176 177int 178sbni_probe(struct sbni_softc *sc) 179{ 180 u_char csr0; 181 182 csr0 = sbni_inb(sc, CSR0); 183 if (csr0 != 0xff && csr0 != 0x00) { 184 csr0 &= ~EN_INT; 185 if (csr0 & BU_EMP) 186 csr0 |= EN_INT; 187 188 if (VALID_DECODER & (1 << (csr0 >> 4))) 189 return (0); 190 } 191 192 return (ENXIO); 193} 194 195 196/* 197 * Install interface into kernel networking data structures 198 */ 199void 200sbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 201{ 202 struct ifnet *ifp; 203 u_char csr0; 204 205 ifp = &sc->arpcom.ac_if; 206 sbni_outb(sc, CSR0, 0); 207 set_initial_values(sc, flags); 208 209 callout_handle_init(&sc->wch); 210 if (!ifp->if_name) { 211 /* Initialize ifnet structure */ 212 ifp->if_softc = sc; 213 ifp->if_unit = unit; 214 ifp->if_name = "sbni"; 215 ifp->if_init = sbni_init; 216 ifp->if_start = sbni_start; 217 ifp->if_output = ether_output; 218 ifp->if_ioctl = sbni_ioctl; 219 ifp->if_watchdog = sbni_watchdog; 220 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 221 222 /* report real baud rate */ 223 csr0 = sbni_inb(sc, CSR0); 224 ifp->if_baudrate = 225 (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 226 227 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 228 ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 229 } 230 /* device attach does transition from UNCONFIGURED to IDLE state */ 231 232 printf("%s%d: speed %ld, address %6D, rxl ", ifp->if_name, 233 ifp->if_unit, ifp->if_baudrate, sc->arpcom.ac_enaddr, ":"); 234 if (sc->delta_rxl) 235 printf("auto\n"); 236 else 237 printf("%d (fixed)\n", sc->cur_rxl_index); 238} 239 240/* -------------------------------------------------------------------------- */ 241 242static void 243sbni_init(void *xsc) 244{ 245 struct sbni_softc *sc; 246 struct ifnet *ifp; 247 int s; 248 249 sc = (struct sbni_softc *)xsc; 250 ifp = &sc->arpcom.ac_if; 251 252 /* address not known */ 253 if (TAILQ_EMPTY(&ifp->if_addrhead)) 254 return; 255 256 /* 257 * kludge to avoid multiple initialization when more than once 258 * protocols configured 259 */ 260 if (ifp->if_flags & IFF_RUNNING) 261 return; 262 263 s = splimp(); 264 ifp->if_timer = 0; 265 card_start(sc); 266 sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 267 268 ifp->if_flags |= IFF_RUNNING; 269 ifp->if_flags &= ~IFF_OACTIVE; 270 271 /* attempt to start output */ 272 sbni_start(ifp); 273 splx(s); 274} 275 276 277static void 278sbni_start(struct ifnet *ifp) 279{ 280 struct sbni_softc *sc = ifp->if_softc; 281 if (sc->tx_frameno == 0) 282 prepare_to_send(sc); 283} 284 285 286static void 287sbni_stop(struct sbni_softc *sc) 288{ 289 sbni_outb(sc, CSR0, 0); 290 drop_xmit_queue(sc); 291 292 if (sc->rx_buf_p) { 293 m_freem(sc->rx_buf_p); 294 sc->rx_buf_p = NULL; 295 } 296 297 untimeout(sbni_timeout, sc, sc->wch); 298 sc->wch.callout = NULL; 299} 300 301/* -------------------------------------------------------------------------- */ 302 303/* interrupt handler */ 304 305/* 306 * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 307 * be looked as two independent single-channel devices. Every channel seems 308 * as Ethernet interface but interrupt handler must be common. Really, first 309 * channel ("master") driver only registers the handler. In it's struct softc 310 * it has got pointer to "slave" channel's struct softc and handles that's 311 * interrupts too. 312 * softc of successfully attached ISA SBNI boards is linked to list. 313 * While next board driver is initialized, it scans this list. If one 314 * has found softc with same irq and ioaddr different by 4 then it assumes 315 * this board to be "master". 316 */ 317 318void 319sbni_intr(void *arg) 320{ 321 struct sbni_softc *sc; 322 int repeat; 323 324 sc = (struct sbni_softc *)arg; 325 326 do { 327 repeat = 0; 328 if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 329 handle_channel(sc); 330 repeat = 1; 331 } 332 if (sc->slave_sc && /* second channel present */ 333 (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) { 334 handle_channel(sc->slave_sc); 335 repeat = 1; 336 } 337 } while (repeat); 338} 339 340 341static void 342handle_channel(struct sbni_softc *sc) 343{ 344 int req_ans; 345 u_char csr0; 346 347 sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 348 349 sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 350 for (;;) { 351 csr0 = sbni_inb(sc, CSR0); 352 if ((csr0 & (RC_RDY | TR_RDY)) == 0) 353 break; 354 355 req_ans = !(sc->state & FL_PREV_OK); 356 357 if (csr0 & RC_RDY) 358 req_ans = recv_frame(sc); 359 360 /* 361 * TR_RDY always equals 1 here because we have owned the marker, 362 * and we set TR_REQ when disabled interrupts 363 */ 364 csr0 = sbni_inb(sc, CSR0); 365 if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 366 printf("sbni: internal error!\n"); 367 368 /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 369 if (req_ans || sc->tx_frameno != 0) 370 send_frame(sc); 371 else { 372 /* send the marker without any data */ 373 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 374 } 375 } 376 377 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 378} 379 380 381/* 382 * Routine returns 1 if it need to acknoweledge received frame. 383 * Empty frame received without errors won't be acknoweledged. 384 */ 385 386static int 387recv_frame(struct sbni_softc *sc) 388{ 389 u_int32_t crc; 390 u_int framelen, frameno, ack; 391 u_int is_first, frame_ok; 392 393 crc = CRC32_INITIAL; 394 if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 395 frame_ok = framelen > 4 ? 396 upload_data(sc, framelen, frameno, is_first, crc) : 397 skip_tail(sc, framelen, crc); 398 if (frame_ok) 399 interpret_ack(sc, ack); 400 } else 401 frame_ok = 0; 402 403 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 404 if (frame_ok) { 405 sc->state |= FL_PREV_OK; 406 if (framelen > 4) 407 sc->in_stats.all_rx_number++; 408 } else { 409 sc->state &= ~FL_PREV_OK; 410 change_level(sc); 411 sc->in_stats.all_rx_number++; 412 sc->in_stats.bad_rx_number++; 413 } 414 415 return (!frame_ok || framelen > 4); 416} 417 418 419static void 420send_frame(struct sbni_softc *sc) 421{ 422 u_int32_t crc; 423 u_char csr0; 424 425 crc = CRC32_INITIAL; 426 if (sc->state & FL_NEED_RESEND) { 427 428 /* if frame was sended but not ACK'ed - resend it */ 429 if (sc->trans_errors) { 430 sc->trans_errors--; 431 if (sc->framelen != 0) 432 sc->in_stats.resend_tx_number++; 433 } else { 434 /* cannot xmit with many attempts */ 435 drop_xmit_queue(sc); 436 goto do_send; 437 } 438 } else 439 sc->trans_errors = TR_ERROR_COUNT; 440 441 send_frame_header(sc, &crc); 442 sc->state |= FL_NEED_RESEND; 443 /* 444 * FL_NEED_RESEND will be cleared after ACK, but if empty 445 * frame sended then in prepare_to_send next frame 446 */ 447 448 449 if (sc->framelen) { 450 download_data(sc, &crc); 451 sc->in_stats.all_tx_number++; 452 sc->state |= FL_WAIT_ACK; 453 } 454 455 sbni_outsb(sc, (u_char *)&crc, sizeof crc); 456 457do_send: 458 csr0 = sbni_inb(sc, CSR0); 459 sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 460 461 if (sc->tx_frameno) { 462 /* next frame exists - request to send */ 463 sbni_outb(sc, CSR0, csr0 | TR_REQ); 464 } 465} 466 467 468static void 469download_data(struct sbni_softc *sc, u_int32_t *crc_p) 470{ 471 struct mbuf *m; 472 caddr_t data_p; 473 u_int data_len, pos, slice; 474 475 data_p = NULL; /* initialized to avoid warn */ 476 pos = 0; 477 478 for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 479 if (pos + m->m_len > sc->outpos) { 480 data_len = m->m_len - (sc->outpos - pos); 481 data_p = mtod(m, caddr_t) + (sc->outpos - pos); 482 483 goto do_copy; 484 } else 485 pos += m->m_len; 486 } 487 488 data_len = 0; 489 490do_copy: 491 pos = 0; 492 do { 493 if (data_len) { 494 slice = min(data_len, sc->framelen - pos); 495 sbni_outsb(sc, data_p, slice); 496 *crc_p = calc_crc32(*crc_p, data_p, slice); 497 498 pos += slice; 499 if (data_len -= slice) 500 data_p += slice; 501 else { 502 do { 503 m = m->m_next; 504 } while (m != NULL && m->m_len == 0); 505 506 if (m) { 507 data_len = m->m_len; 508 data_p = mtod(m, caddr_t); 509 } 510 } 511 } else { 512 /* frame too short - zero padding */ 513 514 pos = sc->framelen - pos; 515 while (pos--) { 516 sbni_outb(sc, DAT, 0); 517 *crc_p = CRC32(0, *crc_p); 518 } 519 return; 520 } 521 } while (pos < sc->framelen); 522} 523 524 525static int 526upload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 527 u_int is_first, u_int32_t crc) 528{ 529 int frame_ok; 530 531 if (is_first) { 532 sc->wait_frameno = frameno; 533 sc->inppos = 0; 534 } 535 536 if (sc->wait_frameno == frameno) { 537 538 if (sc->inppos + framelen <= ETHER_MAX_LEN) { 539 frame_ok = append_frame_to_pkt(sc, framelen, crc); 540 541 /* 542 * if CRC is right but framelen incorrect then transmitter 543 * error was occured... drop entire packet 544 */ 545 } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 546 sc->wait_frameno = 0; 547 sc->inppos = 0; 548 sc->arpcom.ac_if.if_ierrors++; 549 /* now skip all frames until is_first != 0 */ 550 } 551 } else 552 frame_ok = skip_tail(sc, framelen, crc); 553 554 if (is_first && !frame_ok) { 555 /* 556 * Frame has been violated, but we have stored 557 * is_first already... Drop entire packet. 558 */ 559 sc->wait_frameno = 0; 560 sc->arpcom.ac_if.if_ierrors++; 561 } 562 563 return (frame_ok); 564} 565 566 567static __inline void send_complete(struct sbni_softc *); 568 569static __inline void 570send_complete(struct sbni_softc *sc) 571{ 572 m_freem(sc->tx_buf_p); 573 sc->tx_buf_p = NULL; 574 sc->arpcom.ac_if.if_opackets++; 575} 576 577 578static void 579interpret_ack(struct sbni_softc *sc, u_int ack) 580{ 581 if (ack == FRAME_SENT_OK) { 582 sc->state &= ~FL_NEED_RESEND; 583 584 if (sc->state & FL_WAIT_ACK) { 585 sc->outpos += sc->framelen; 586 587 if (--sc->tx_frameno) { 588 sc->framelen = min( 589 sc->maxframe, sc->pktlen - sc->outpos); 590 } else { 591 send_complete(sc); 592 prepare_to_send(sc); 593 } 594 } 595 } 596 597 sc->state &= ~FL_WAIT_ACK; 598} 599 600 601/* 602 * Glue received frame with previous fragments of packet. 603 * Indicate packet when last frame would be accepted. 604 */ 605 606static int 607append_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 608{ 609 caddr_t p; 610 611 if (sc->inppos + framelen > ETHER_MAX_LEN) 612 return (0); 613 614 if (!sc->rx_buf_p && !get_rx_buf(sc)) 615 return (0); 616 617 p = sc->rx_buf_p->m_data + sc->inppos; 618 sbni_insb(sc, p, framelen); 619 if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 620 return (0); 621 622 sc->inppos += framelen - 4; 623 if (--sc->wait_frameno == 0) { /* last frame received */ 624 indicate_pkt(sc); 625 sc->arpcom.ac_if.if_ipackets++; 626 } 627 628 return (1); 629} 630 631 632/* 633 * Prepare to start output on adapter. Current priority must be set to splimp 634 * before this routine is called. 635 * Transmitter will be actually activated when marker has been accepted. 636 */ 637 638static void 639prepare_to_send(struct sbni_softc *sc) 640{ 641 struct mbuf *m; 642 u_int len; 643 644 /* sc->tx_buf_p == NULL here! */ 645 if (sc->tx_buf_p) 646 printf("sbni: memory leak!\n"); 647 648 sc->outpos = 0; 649 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 650 651 for (;;) { 652 IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, sc->tx_buf_p); 653 if (!sc->tx_buf_p) { 654 /* nothing to transmit... */ 655 sc->pktlen = 0; 656 sc->tx_frameno = 0; 657 sc->framelen = 0; 658 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 659 return; 660 } 661 662 for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 663 len += m->m_len; 664 665 if (len != 0) 666 break; 667 m_freem(sc->tx_buf_p); 668 } 669 670 if (len < SBNI_MIN_LEN) 671 len = SBNI_MIN_LEN; 672 673 sc->pktlen = len; 674 sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe; 675 sc->framelen = min(len, sc->maxframe); 676 677 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 678 sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; 679 if (sc->arpcom.ac_if.if_bpf) 680 bpf_mtap(&sc->arpcom.ac_if, sc->tx_buf_p); 681} 682 683 684static void 685drop_xmit_queue(struct sbni_softc *sc) 686{ 687 struct mbuf *m; 688 689 if (sc->tx_buf_p) { 690 m_freem(sc->tx_buf_p); 691 sc->tx_buf_p = NULL; 692 sc->arpcom.ac_if.if_oerrors++; 693 } 694 695 for (;;) { 696 IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); 697 if (m == NULL) 698 break; 699 m_freem(m); 700 sc->arpcom.ac_if.if_oerrors++; 701 } 702 703 sc->tx_frameno = 0; 704 sc->framelen = 0; 705 sc->outpos = 0; 706 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 707 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 708} 709 710 711static void 712send_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 713{ 714 u_int32_t crc; 715 u_int len_field; 716 u_char value; 717 718 crc = *crc_p; 719 len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 720 721 if (sc->state & FL_NEED_RESEND) 722 len_field |= FRAME_RETRY; /* non-first attempt... */ 723 724 if (sc->outpos == 0) 725 len_field |= FRAME_FIRST; 726 727 len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 728 sbni_outb(sc, DAT, SBNI_SIG); 729 730 value = (u_char)len_field; 731 sbni_outb(sc, DAT, value); 732 crc = CRC32(value, crc); 733 value = (u_char)(len_field >> 8); 734 sbni_outb(sc, DAT, value); 735 crc = CRC32(value, crc); 736 737 sbni_outb(sc, DAT, sc->tx_frameno); 738 crc = CRC32(sc->tx_frameno, crc); 739 sbni_outb(sc, DAT, 0); 740 crc = CRC32(0, crc); 741 *crc_p = crc; 742} 743 744 745/* 746 * if frame tail not needed (incorrect number or received twice), 747 * it won't store, but CRC will be calculated 748 */ 749 750static int 751skip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 752{ 753 while (tail_len--) 754 crc = CRC32(sbni_inb(sc, DAT), crc); 755 756 return (crc == CRC32_REMAINDER); 757} 758 759 760static int 761check_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 762 u_int *ack, u_int *is_first, u_int32_t *crc_p) 763{ 764 u_int32_t crc; 765 u_char value; 766 767 crc = *crc_p; 768 if (sbni_inb(sc, DAT) != SBNI_SIG) 769 return (0); 770 771 value = sbni_inb(sc, DAT); 772 *framelen = (u_int)value; 773 crc = CRC32(value, crc); 774 value = sbni_inb(sc, DAT); 775 *framelen |= ((u_int)value) << 8; 776 crc = CRC32(value, crc); 777 778 *ack = *framelen & FRAME_ACK_MASK; 779 *is_first = (*framelen & FRAME_FIRST) != 0; 780 781 if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 782 return (0); 783 784 value = sbni_inb(sc, DAT); 785 *frameno = (u_int)value; 786 crc = CRC32(value, crc); 787 788 crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 789 *framelen -= 2; 790 791 *crc_p = crc; 792 return (1); 793} 794 795 796static int 797get_rx_buf(struct sbni_softc *sc) 798{ 799 struct mbuf *m; 800 801 MGETHDR(m, M_DONTWAIT, MT_DATA); 802 if (m == NULL) { 803 printf("sbni%d: cannot allocate header mbuf\n", 804 sc->arpcom.ac_if.if_unit); 805 return (0); 806 } 807 808 /* 809 * We always put the received packet in a single buffer - 810 * either with just an mbuf header or in a cluster attached 811 * to the header. The +2 is to compensate for the alignment 812 * fixup below. 813 */ 814 if (ETHER_MAX_LEN + 2 > MHLEN) { 815 /* Attach an mbuf cluster */ 816 MCLGET(m, M_DONTWAIT); 817 if ((m->m_flags & M_EXT) == 0) { 818 m_freem(m); 819 return (0); 820 } 821 } 822 m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 823 824 /* 825 * The +2 is to longword align the start of the real packet. 826 * (sizeof ether_header == 14) 827 * This is important for NFS. 828 */ 829 m_adj(m, 2); 830 sc->rx_buf_p = m; 831 return (1); 832} 833 834 835static void 836indicate_pkt(struct sbni_softc *sc) 837{ 838 struct mbuf *m; 839 struct ether_header *eh; 840 841 m = sc->rx_buf_p; 842 m->m_pkthdr.rcvif = &sc->arpcom.ac_if; 843 m->m_pkthdr.len = m->m_len = sc->inppos; 844 eh = mtod(m, struct ether_header *); 845 846 /* Remove link layer address and indicate packet */ 847 m_adj(m, sizeof(struct ether_header)); 848 ether_input(&sc->arpcom.ac_if, eh, m); 849 sc->rx_buf_p = NULL; 850} 851 852/* -------------------------------------------------------------------------- */ 853 854/* 855 * Routine checks periodically wire activity and regenerates marker if 856 * connect was inactive for a long time. 857 */ 858 859static void 860sbni_timeout(void *xsc) 861{ 862 struct sbni_softc *sc; 863 int s; 864 u_char csr0; 865 866 sc = (struct sbni_softc *)xsc; 867 s = splimp(); 868 869 csr0 = sbni_inb(sc, CSR0); 870 if (csr0 & RC_CHK) { 871 872 if (sc->timer_ticks) { 873 if (csr0 & (RC_RDY | BU_EMP)) 874 /* receiving not active */ 875 sc->timer_ticks--; 876 } else { 877 sc->in_stats.timeout_number++; 878 if (sc->delta_rxl) 879 timeout_change_level(sc); 880 881 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 882 csr0 = sbni_inb(sc, CSR0); 883 } 884 } 885 886 sbni_outb(sc, CSR0, csr0 | RC_CHK); 887 sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 888 splx(s); 889} 890 891/* -------------------------------------------------------------------------- */ 892 893static void 894card_start(struct sbni_softc *sc) 895{ 896 sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 897 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 898 sc->state |= FL_PREV_OK; 899 900 sc->inppos = 0; 901 sc->wait_frameno = 0; 902 903 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 904 sbni_outb(sc, CSR0, EN_INT); 905} 906 907/* -------------------------------------------------------------------------- */ 908 909/* 910 * Device timeout/watchdog routine. Entered if the device neglects to 911 * generate an interrupt after a transmit has been started on it. 912 */ 913 914static void 915sbni_watchdog(struct ifnet *ifp) 916{ 917 log(LOG_ERR, "sbni%d: device timeout\n", ifp->if_unit); 918 ifp->if_oerrors++; 919} 920 921 922static u_char rxl_tab[] = { 923 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 924 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 925}; 926 927#define SIZE_OF_TIMEOUT_RXL_TAB 4 928static u_char timeout_rxl_tab[] = { 929 0x03, 0x05, 0x08, 0x0b 930}; 931 932static void 933set_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 934{ 935 if (flags.fixed_rxl) { 936 sc->delta_rxl = 0; /* disable receive level autodetection */ 937 sc->cur_rxl_index = flags.rxl; 938 } else { 939 sc->delta_rxl = DEF_RXL_DELTA; 940 sc->cur_rxl_index = DEF_RXL; 941 } 942 943 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 944 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 945 sc->maxframe = DEFAULT_FRAME_LEN; 946 947 /* 948 * generate Ethernet address (0x00ff01xxxxxx) 949 */ 950 *(u_int16_t*)sc->arpcom.ac_enaddr = htons(0x00ff); 951 if (flags.mac_addr) 952 *(u_int32_t*)(sc->arpcom.ac_enaddr+2) = 953 htonl(flags.mac_addr | 0x01000000); 954 else { 955 /* reading timer value */ 956 outb(0x43, 0); 957 insb(0x40, sc->arpcom.ac_enaddr + 3, 4); 958 *(u_char*)(sc->arpcom.ac_enaddr + 2) = 0x01; 959 } 960} 961 962 963#ifdef SBNI_DUAL_COMPOUND 964 965#ifndef offsetof 966#define offsetof(type, member) ((u_int32_t)(&((type *)0)->member)) 967#endif 968 969 970struct sbni_softc * 971connect_to_master(struct sbni_softc *sc) 972{ 973 struct sbni_softc *p; 974 975 p = (struct sbni_softc *)(((char *)&sbni_headlist) 976 - offsetof(struct sbni_softc, link)); 977 978 for (; p->link; p = p->link) { 979 if (p->link->irq == sc->irq 980 && (p->link->base_addr == sc->base_addr + 4 981 || p->link->base_addr == sc->base_addr - 4)) { 982 983 struct sbni_softc *t = p->link; 984 t->slave_sc = sc; 985 p->link = p->link->link; 986 return (t); 987 } 988 } 989 990 return (NULL); 991} 992 993#endif /* SBNI_DUAL_COMPOUND */ 994 995 996/* Receive level auto-selection */ 997 998static void 999change_level(struct sbni_softc *sc) 1000{ 1001 if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 1002 return; 1003 1004 if (sc->cur_rxl_index == 0) 1005 sc->delta_rxl = 1; 1006 else if (sc->cur_rxl_index == 15) 1007 sc->delta_rxl = -1; 1008 else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 1009 sc->delta_rxl = -sc->delta_rxl; 1010 1011 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 1012 sbni_inb(sc, CSR0); /* it needed for PCI cards */ 1013 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1014 1015 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1016 sc->cur_rxl_rcvd = 0; 1017} 1018 1019 1020static void 1021timeout_change_level(struct sbni_softc *sc) 1022{ 1023 sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 1024 if (++sc->timeout_rxl >= 4) 1025 sc->timeout_rxl = 0; 1026 1027 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1028 sbni_inb(sc, CSR0); 1029 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1030 1031 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1032 sc->cur_rxl_rcvd = 0; 1033} 1034 1035/* -------------------------------------------------------------------------- */ 1036 1037/* 1038 * Process an ioctl request. This code needs some work - it looks 1039 * pretty ugly. 1040 */ 1041 1042static int 1043sbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1044{ 1045 struct sbni_softc *sc; 1046 struct ifreq *ifr; 1047 struct thread *td; 1048 struct proc *p; 1049 struct sbni_in_stats *in_stats; 1050 struct sbni_flags flags; 1051 int error, s; 1052 1053 sc = ifp->if_softc; 1054 ifr = (struct ifreq *)data; 1055 td = curthread; 1056 p = td->td_proc; 1057 error = 0; 1058 1059 s = splimp(); 1060 1061 switch (command) { 1062 case SIOCSIFADDR: 1063 case SIOCGIFADDR: 1064 ether_ioctl(ifp, command, data); 1065 break; 1066 1067 case SIOCSIFFLAGS: 1068 /* 1069 * If the interface is marked up and stopped, then start it. 1070 * If it is marked down and running, then stop it. 1071 */ 1072 if (ifp->if_flags & IFF_UP) { 1073 if (!(ifp->if_flags & IFF_RUNNING)) 1074 sbni_init(sc); 1075 } else { 1076 if (ifp->if_flags & IFF_RUNNING) { 1077 sbni_stop(sc); 1078 ifp->if_flags &= ~IFF_RUNNING; 1079 } 1080 } 1081 break; 1082 1083 case SIOCADDMULTI: 1084 case SIOCDELMULTI: 1085 /* 1086 * Multicast list has changed; set the hardware filter 1087 * accordingly. 1088 */ 1089 error = 0; 1090 /* if (ifr == NULL) 1091 error = EAFNOSUPPORT; */ 1092 break; 1093 1094 case SIOCSIFMTU: 1095 if (ifr->ifr_mtu > ETHERMTU) 1096 error = EINVAL; 1097 else 1098 ifp->if_mtu = ifr->ifr_mtu; 1099 break; 1100 1101 /* 1102 * SBNI specific ioctl 1103 */ 1104 case SIOCGHWFLAGS: /* get flags */ 1105 bcopy((caddr_t) sc->arpcom.ac_enaddr+3, (caddr_t) &flags, 3); 1106 flags.rxl = sc->cur_rxl_index; 1107 flags.rate = sc->csr1.rate; 1108 flags.fixed_rxl = (sc->delta_rxl == 0); 1109 flags.fixed_rate = 1; 1110 ifr->ifr_data = *(caddr_t*) &flags; 1111 break; 1112 1113 case SIOCGINSTATS: 1114 in_stats = (struct sbni_in_stats *)ifr->ifr_data; 1115 bcopy((void *)(&(sc->in_stats)), (void *)in_stats, 1116 sizeof(struct sbni_in_stats)); 1117 break; 1118 1119 case SIOCSHWFLAGS: /* set flags */ 1120 /* root only */ 1121 error = suser(td); 1122 if (error) 1123 break; 1124 flags = *(struct sbni_flags*)&ifr->ifr_data; 1125 if (flags.fixed_rxl) { 1126 sc->delta_rxl = 0; 1127 sc->cur_rxl_index = flags.rxl; 1128 } else { 1129 sc->delta_rxl = DEF_RXL_DELTA; 1130 sc->cur_rxl_index = DEF_RXL; 1131 } 1132 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1133 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 1134 if (flags.mac_addr) 1135 bcopy((caddr_t) &flags, 1136 (caddr_t) sc->arpcom.ac_enaddr+3, 3); 1137 1138 /* Don't be afraid... */ 1139 sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 1140 break; 1141 1142 case SIOCRINSTATS: 1143 if (!(error = suser(td))) /* root only */ 1144 bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 1145 break; 1146 1147 default: 1148 error = EINVAL; 1149 } 1150 1151 splx(s); 1152 return (error); 1153} 1154 1155/* -------------------------------------------------------------------------- */ 1156 1157#ifdef ASM_CRC 1158 1159static u_int32_t 1160calc_crc32(u_int32_t crc, caddr_t p, u_int len) 1161{ 1162 register u_int32_t _crc __asm ("ax"); 1163 _crc = crc; 1164 1165 __asm __volatile ( 1166 "xorl %%ebx, %%ebx\n" 1167 "movl %1, %%esi\n" 1168 "movl %2, %%ecx\n" 1169 "movl $crc32tab, %%edi\n" 1170 "shrl $2, %%ecx\n" 1171 "jz 1f\n" 1172 1173 ".align 4\n" 1174 "0:\n" 1175 "movb %%al, %%bl\n" 1176 "movl (%%esi), %%edx\n" 1177 "shrl $8, %%eax\n" 1178 "xorb %%dl, %%bl\n" 1179 "shrl $8, %%edx\n" 1180 "xorl (%%edi,%%ebx,4), %%eax\n" 1181 1182 "movb %%al, %%bl\n" 1183 "shrl $8, %%eax\n" 1184 "xorb %%dl, %%bl\n" 1185 "shrl $8, %%edx\n" 1186 "xorl (%%edi,%%ebx,4), %%eax\n" 1187 1188 "movb %%al, %%bl\n" 1189 "shrl $8, %%eax\n" 1190 "xorb %%dl, %%bl\n" 1191 "movb %%dh, %%dl\n" 1192 "xorl (%%edi,%%ebx,4), %%eax\n" 1193 1194 "movb %%al, %%bl\n" 1195 "shrl $8, %%eax\n" 1196 "xorb %%dl, %%bl\n" 1197 "addl $4, %%esi\n" 1198 "xorl (%%edi,%%ebx,4), %%eax\n" 1199 1200 "decl %%ecx\n" 1201 "jnz 0b\n" 1202 1203 "1:\n" 1204 "movl %2, %%ecx\n" 1205 "andl $3, %%ecx\n" 1206 "jz 2f\n" 1207 1208 "movb %%al, %%bl\n" 1209 "shrl $8, %%eax\n" 1210 "xorb (%%esi), %%bl\n" 1211 "xorl (%%edi,%%ebx,4), %%eax\n" 1212 1213 "decl %%ecx\n" 1214 "jz 2f\n" 1215 1216 "movb %%al, %%bl\n" 1217 "shrl $8, %%eax\n" 1218 "xorb 1(%%esi), %%bl\n" 1219 "xorl (%%edi,%%ebx,4), %%eax\n" 1220 1221 "decl %%ecx\n" 1222 "jz 2f\n" 1223 1224 "movb %%al, %%bl\n" 1225 "shrl $8, %%eax\n" 1226 "xorb 2(%%esi), %%bl\n" 1227 "xorl (%%edi,%%ebx,4), %%eax\n" 1228 "2:\n" 1229 : 1230 : "a" (_crc), "g" (p), "g" (len) 1231 : "ax", "bx", "cx", "dx", "si", "di" 1232 ); 1233 1234 return (_crc); 1235} 1236 1237#else /* ASM_CRC */ 1238 1239static u_int32_t 1240calc_crc32(u_int32_t crc, caddr_t p, u_int len) 1241{ 1242 while (len--) 1243 crc = CRC32(*p++, crc); 1244 1245 return (crc); 1246} 1247 1248#endif /* ASM_CRC */ 1249 1250 1251static u_int32_t crc32tab[] __attribute__ ((aligned(8))) = { 1252 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 1253 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 1254 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 1255 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 1256 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 1257 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 1258 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 1259 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 1260 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 1261 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 1262 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 1263 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 1264 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 1265 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 1266 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 1267 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 1268 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 1269 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 1270 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 1271 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 1272 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 1273 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 1274 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 1275 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 1276 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 1277 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 1278 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 1279 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 1280 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 1281 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 1282 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 1283 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 1284 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 1285 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 1286 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 1287 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 1288 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 1289 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 1290 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 1291 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 1292 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 1293 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 1294 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 1295 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 1296 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 1297 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 1298 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 1299 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 1300 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 1301 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 1302 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 1303 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 1304 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 1305 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 1306 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 1307 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 1308 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 1309 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 1310 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 1311 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 1312 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 1313 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 1314 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 1315 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 1316}; 1317