if_cs.c revision 104252
1258210Srpaulo/* 2258210Srpaulo * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko. 3258210Srpaulo * All rights reserved. 4258210Srpaulo * 5258210Srpaulo * Redistribution and use in source and binary forms, with or without 6258210Srpaulo * modification, are permitted provided that the following conditions 7258210Srpaulo * are met: 8258210Srpaulo * 1. Redistributions of source code must retain the above copyright 9258210Srpaulo * notice unmodified, this list of conditions, and the following 10258210Srpaulo * disclaimer. 11258210Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 12258210Srpaulo * notice, this list of conditions and the following disclaimer in the 13258210Srpaulo * documentation and/or other materials provided with the distribution. 14258210Srpaulo * 15258210Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16258210Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17258210Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18258210Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19258210Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20258210Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21258210Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22258210Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23258210Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24258210Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25258210Srpaulo * SUCH DAMAGE. 26258210Srpaulo * 27258210Srpaulo */ 28258210Srpaulo 29258210Srpaulo/* 30258210Srpaulo * $FreeBSD: head/sys/dev/cs/if_cs.c 104252 2002-10-01 00:46:41Z brooks $ 31258210Srpaulo * 32258210Srpaulo * Device driver for Crystal Semiconductor CS8920 based ethernet 33258210Srpaulo * adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997 34258210Srpaulo */ 35258210Srpaulo 36258210Srpaulo/* 37#define CS_DEBUG 38 */ 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/malloc.h> 43#include <sys/mbuf.h> 44#include <sys/socket.h> 45#include <sys/sockio.h> 46#include <sys/kernel.h> 47#include <sys/sysctl.h> 48#include <sys/syslog.h> 49 50#include <sys/module.h> 51#include <sys/bus.h> 52#include <machine/bus.h> 53#include <sys/rman.h> 54#include <machine/resource.h> 55 56#include <net/if.h> 57#include <net/if_arp.h> 58#include <net/if_media.h> 59#include <net/ethernet.h> 60#include <net/bpf.h> 61 62#include <dev/cs/if_csvar.h> 63#include <dev/cs/if_csreg.h> 64 65#ifdef CS_USE_64K_DMA 66#define CS_DMA_BUFFER_SIZE 65536 67#else 68#define CS_DMA_BUFFER_SIZE 16384 69#endif 70 71static int cs_recv_delay = 570; 72SYSCTL_INT(_machdep, OID_AUTO, cs_recv_delay, CTLFLAG_RW, &cs_recv_delay, 0, ""); 73 74static void cs_init (void *); 75static int cs_ioctl (struct ifnet *, u_long, caddr_t); 76static void cs_start (struct ifnet *); 77static void cs_stop (struct cs_softc *); 78static void cs_reset (struct cs_softc *); 79static void cs_watchdog (struct ifnet *); 80 81static int cs_mediachange (struct ifnet *); 82static void cs_mediastatus (struct ifnet *, struct ifmediareq *); 83static int cs_mediaset (struct cs_softc *, int); 84 85static void cs_write_mbufs(struct cs_softc*, struct mbuf*); 86static void cs_xmit_buf(struct cs_softc*); 87static int cs_get_packet(struct cs_softc*); 88static void cs_setmode(struct cs_softc*); 89 90static int get_eeprom_data(struct cs_softc *sc, int, int, int *); 91static int get_eeprom_cksum(int, int, int *); 92static int wait_eeprom_ready( struct cs_softc *); 93static void control_dc_dc( struct cs_softc *, int ); 94static int send_test_pkt( struct cs_softc * ); 95static int enable_tp(struct cs_softc *); 96static int enable_aui(struct cs_softc *); 97static int enable_bnc(struct cs_softc *); 98static int cs_duplex_auto(struct cs_softc *); 99 100devclass_t cs_devclass; 101 102static int 103get_eeprom_data( struct cs_softc *sc, int off, int len, int *buffer) 104{ 105 int i; 106 107#ifdef CS_DEBUG 108 printf(CS_NAME":EEPROM data from %x for %x:\n", off,len); 109#endif 110 111 for (i=0;i<len;i++) { 112 if (wait_eeprom_ready(sc) < 0) return -1; 113 /* Send command to EEPROM to read */ 114 cs_writereg(sc, PP_EECMD, (off + i) | EEPROM_READ_CMD); 115 if (wait_eeprom_ready(sc)<0) 116 return (-1); 117 buffer[i] = cs_readreg(sc, PP_EEData); 118 119#ifdef CS_DEBUG 120 printf("%02x %02x ",(unsigned char)buffer[i], 121 (unsigned char)buffer[i+1]); 122#endif 123 } 124 125#ifdef CS_DEBUG 126 printf("\n"); 127#endif 128 return (0); 129} 130 131static int 132get_eeprom_cksum(int off, int len, int *buffer) 133{ 134 int i,cksum=0; 135 136 for (i=0;i<len;i++) 137 cksum+=buffer[i]; 138 cksum &= 0xffff; 139 if (cksum==0) 140 return 0; 141 return -1; 142} 143 144static int 145wait_eeprom_ready(struct cs_softc *sc) 146{ 147 DELAY ( 30000 ); /* XXX should we do some checks here ? */ 148 return 0; 149} 150 151static void 152control_dc_dc(struct cs_softc *sc, int on_not_off) 153{ 154 unsigned int self_control = HCB1_ENBL; 155 156 if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0) ^ on_not_off) 157 self_control |= HCB1; 158 else 159 self_control &= ~HCB1; 160 cs_writereg(sc, PP_SelfCTL, self_control); 161 162 DELAY( 500000 ); 163} 164 165 166static int 167cs_duplex_auto(struct cs_softc *sc) 168{ 169 int i, error=0; 170 171 cs_writereg(sc, PP_AutoNegCTL, 172 RE_NEG_NOW | ALLOW_FDX | AUTO_NEG_ENABLE); 173 for (i=0; cs_readreg(sc, PP_AutoNegST) & AUTO_NEG_BUSY; i++) { 174 if (i > 40000) { 175 if_printf(&sc->arpcom.ac_if, 176 "full/half duplex auto negotiation timeout\n"); 177 error = ETIMEDOUT; 178 break; 179 } 180 DELAY(1000); 181 } 182 DELAY( 1000000 ); 183 return error; 184} 185 186static int 187enable_tp(struct cs_softc *sc) 188{ 189 190 cs_writereg(sc, PP_LineCTL, sc->line_ctl & ~AUI_ONLY); 191 control_dc_dc(sc, 0); 192 DELAY( 150000 ); 193 194 if ((cs_readreg(sc, PP_LineST) & LINK_OK)==0) { 195 if_printf(&sc->arpcom.ac_if, "failed to enable TP\n"); 196 return EINVAL; 197 } 198 199 return 0; 200} 201 202/* 203 * XXX This was rewritten from Linux driver without any tests. 204 */ 205static int 206send_test_pkt(struct cs_softc *sc) 207{ 208 char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, 209 0, 46, /* A 46 in network order */ 210 0, 0, /* DSAP=0 & SSAP=0 fields */ 211 0xf3, 0 /* Control (Test Req + P bit set) */ }; 212 int i; 213 u_char ether_address_backup[ETHER_ADDR_LEN]; 214 215 for (i = 0; i < ETHER_ADDR_LEN; i++) { 216 ether_address_backup[i] = sc->arpcom.ac_enaddr[i]; 217 } 218 219 cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | SERIAL_TX_ON); 220 bcopy(test_packet, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 221 bcopy(test_packet+ETHER_ADDR_LEN, 222 sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 223 cs_outw(sc, TX_CMD_PORT, sc->send_cmd); 224 cs_outw(sc, TX_LEN_PORT, sizeof(test_packet)); 225 226 /* Wait for chip to allocate memory */ 227 DELAY(50000); 228 if (!(cs_readreg(sc, PP_BusST) & READY_FOR_TX_NOW)) { 229 for (i = 0; i < ETHER_ADDR_LEN; i++) { 230 sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; 231 } 232 return 0; 233 } 234 235 outsw(sc->nic_addr + TX_FRAME_PORT, test_packet, sizeof(test_packet)); 236 237 DELAY(30000); 238 239 if ((cs_readreg(sc, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) { 240 for (i = 0; i < ETHER_ADDR_LEN; i++) { 241 sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; 242 } 243 return 1; 244 } 245 for (i = 0; i < ETHER_ADDR_LEN; i++) { 246 sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; 247 } 248 return 0; 249} 250 251/* 252 * XXX This was rewritten from Linux driver without any tests. 253 */ 254static int 255enable_aui(struct cs_softc *sc) 256{ 257 258 control_dc_dc(sc, 0); 259 cs_writereg(sc, PP_LineCTL, 260 (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); 261 262 if (!send_test_pkt(sc)) { 263 if_printf(&sc->arpcom.ac_if, "failed to enable AUI\n"); 264 return EINVAL; 265 } 266 return 0; 267} 268 269/* 270 * XXX This was rewritten from Linux driver without any tests. 271 */ 272static int 273enable_bnc(struct cs_softc *sc) 274{ 275 276 control_dc_dc(sc, 1); 277 cs_writereg(sc, PP_LineCTL, 278 (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); 279 280 if (!send_test_pkt(sc)) { 281 if_printf(&sc->arpcom.ac_if, "failed to enable BNC\n"); 282 return EINVAL; 283 } 284 return 0; 285} 286 287int 288cs_cs89x0_probe(device_t dev) 289{ 290 int i; 291 int error; 292 u_long irq, junk; 293 struct cs_softc *sc = device_get_softc(dev); 294 unsigned rev_type = 0; 295 u_int16_t id; 296 char chip_revision; 297 int eeprom_buff[CHKSUM_LEN]; 298 int chip_type, pp_isaint, pp_isadma; 299 300 error = cs_alloc_port(dev, 0, CS_89x0_IO_PORTS); 301 if (error) 302 return (error); 303 304 sc->nic_addr = rman_get_start(sc->port_res); 305 306 if ((cs_inw(sc, ADD_PORT) & ADD_MASK) != ADD_SIG) { 307 /* Chip not detected. Let's try to reset it */ 308 if (bootverbose) 309 device_printf(dev, "trying to reset the chip.\n"); 310 cs_outw(sc, ADD_PORT, PP_SelfCTL); 311 i = cs_inw(sc, DATA_PORT); 312 cs_outw(sc, ADD_PORT, PP_SelfCTL); 313 cs_outw(sc, DATA_PORT, i | POWER_ON_RESET); 314 if ((cs_inw(sc, ADD_PORT) & ADD_MASK) != ADD_SIG) 315 return (ENXIO); 316 } 317 318 for (i = 0; i < 10000; i++) { 319 id = cs_readreg(sc, PP_ChipID); 320 if (id == CHIP_EISA_ID_SIG) 321 break; 322 } 323 if (i == 10000) 324 return (ENXIO); 325 326 rev_type = cs_readreg(sc, PRODUCT_ID_ADD); 327 chip_type = rev_type & ~REVISON_BITS; 328 chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; 329 330 sc->chip_type = chip_type; 331 332 if(chip_type==CS8900) { 333 pp_isaint = PP_CS8900_ISAINT; 334 pp_isadma = PP_CS8900_ISADMA; 335 sc->send_cmd = TX_CS8900_AFTER_ALL; 336 } else { 337 pp_isaint = PP_CS8920_ISAINT; 338 pp_isadma = PP_CS8920_ISADMA; 339 sc->send_cmd = TX_CS8920_AFTER_ALL; 340 } 341 342 /* 343 * Clear some fields so that fail of EEPROM will left them clean 344 */ 345 sc->auto_neg_cnf = 0; 346 sc->adapter_cnf = 0; 347 sc->isa_config = 0; 348 349 /* 350 * If no interrupt specified (or "?"), use what the board tells us. 351 */ 352 error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 353 354 /* 355 * Get data from EEPROM 356 */ 357 if((cs_readreg(sc, PP_SelfST) & EEPROM_PRESENT) == 0) { 358 device_printf(dev, "No EEPROM, assuming defaults.\n"); 359 } else { 360 if (get_eeprom_data(sc,START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) { 361 device_printf(dev, "EEPROM read failed, " 362 "assuming defaults.\n"); 363 } else { 364 if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) { 365 device_printf(dev, "EEPROM cheksum bad, " 366 "assuming defaults.\n"); 367 } else { 368 sc->auto_neg_cnf = 369 eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; 370 sc->adapter_cnf = 371 eeprom_buff[ADAPTER_CNF_OFFSET/2]; 372 sc->isa_config = 373 eeprom_buff[ISA_CNF_OFFSET/2]; 374 375 for (i=0; i<ETHER_ADDR_LEN/2; i++) { 376 sc->arpcom.ac_enaddr[i*2]= 377 eeprom_buff[i]; 378 sc->arpcom.ac_enaddr[i*2+1]= 379 eeprom_buff[i] >> 8; 380 } 381 382 /* 383 * If no interrupt specified (or "?"), 384 * use what the board tells us. 385 */ 386 if (error) { 387 irq = sc->isa_config & INT_NO_MASK; 388 if (chip_type==CS8900) { 389 switch(irq) { 390 case 0: 391 irq=10; 392 error=0; 393 break; 394 case 1: 395 irq=11; 396 error=0; 397 break; 398 case 2: 399 irq=12; 400 error=0; 401 break; 402 case 3: 403 irq=5; 404 error=0; 405 break; 406 default: 407 device_printf(dev, "invalid irq in EEPROM.\n"); 408 error=EINVAL; 409 } 410 } else { 411 if (irq>CS8920_NO_INTS) { 412 device_printf(dev, "invalid irq in EEPROM.\n"); 413 error=EINVAL; 414 } else { 415 error=0; 416 } 417 } 418 419 if (!error) 420 bus_set_resource(dev, SYS_RES_IRQ, 0, 421 irq, 1); 422 } 423 } 424 } 425 } 426 427 if (!error) { 428 if (chip_type == CS8900) { 429 switch(irq) { 430 case 5: 431 irq = 3; 432 break; 433 case 10: 434 irq = 0; 435 break; 436 case 11: 437 irq = 1; 438 break; 439 case 12: 440 irq = 2; 441 break; 442 default: 443 error=EINVAL; 444 } 445 } else { 446 if (irq > CS8920_NO_INTS) { 447 error = EINVAL; 448 } 449 } 450 } 451 452 if (!error) { 453 cs_writereg(sc, pp_isaint, irq); 454 } else { 455 device_printf(dev, "Unknown or invalid irq\n"); 456 return (ENXIO); 457 } 458 459 /* 460 * Temporary disabled 461 * 462 if (drq>0) 463 cs_writereg(sc, pp_isadma, drq); 464 else { 465 device_printf(dev, "incorrect drq\n",); 466 return 0; 467 } 468 */ 469 470 if (bootverbose) 471 device_printf(dev, "CS89%c0%s rev %c media%s%s%s\n", 472 chip_type==CS8900 ? '0' : '2', 473 chip_type==CS8920M ? "M" : "", 474 chip_revision, 475 (sc->adapter_cnf & A_CNF_10B_T) ? " TP" : "", 476 (sc->adapter_cnf & A_CNF_AUI) ? " AUI" : "", 477 (sc->adapter_cnf & A_CNF_10B_2) ? " BNC" : ""); 478 479 if ((sc->adapter_cnf & A_CNF_EXTND_10B_2) && 480 (sc->adapter_cnf & A_CNF_LOW_RX_SQUELCH)) 481 sc->line_ctl = LOW_RX_SQUELCH; 482 else 483 sc->line_ctl = 0; 484 485 486 return 0; 487} 488 489/* 490 * Allocate a port resource with the given resource id. 491 */ 492int cs_alloc_port(device_t dev, int rid, int size) 493{ 494 struct cs_softc *sc = device_get_softc(dev); 495 struct resource *res; 496 497 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 498 0ul, ~0ul, size, RF_ACTIVE); 499 if (res) { 500 sc->port_rid = rid; 501 sc->port_res = res; 502 sc->port_used = size; 503 return (0); 504 } else { 505 return (ENOENT); 506 } 507} 508 509/* 510 * Allocate a memory resource with the given resource id. 511 */ 512int cs_alloc_memory(device_t dev, int rid, int size) 513{ 514 struct cs_softc *sc = device_get_softc(dev); 515 struct resource *res; 516 517 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 518 0ul, ~0ul, size, RF_ACTIVE); 519 if (res) { 520 sc->mem_rid = rid; 521 sc->mem_res = res; 522 sc->mem_used = size; 523 return (0); 524 } else { 525 return (ENOENT); 526 } 527} 528 529/* 530 * Allocate an irq resource with the given resource id. 531 */ 532int cs_alloc_irq(device_t dev, int rid, int flags) 533{ 534 struct cs_softc *sc = device_get_softc(dev); 535 struct resource *res; 536 537 res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 538 0ul, ~0ul, 1, (RF_ACTIVE | flags)); 539 if (res) { 540 sc->irq_rid = rid; 541 sc->irq_res = res; 542 return (0); 543 } else { 544 return (ENOENT); 545 } 546} 547 548/* 549 * Release all resources 550 */ 551void cs_release_resources(device_t dev) 552{ 553 struct cs_softc *sc = device_get_softc(dev); 554 555 if (sc->port_res) { 556 bus_release_resource(dev, SYS_RES_IOPORT, 557 sc->port_rid, sc->port_res); 558 sc->port_res = 0; 559 } 560 if (sc->mem_res) { 561 bus_release_resource(dev, SYS_RES_MEMORY, 562 sc->mem_rid, sc->mem_res); 563 sc->mem_res = 0; 564 } 565 if (sc->irq_res) { 566 bus_release_resource(dev, SYS_RES_IRQ, 567 sc->irq_rid, sc->irq_res); 568 sc->irq_res = 0; 569 } 570} 571 572/* 573 * Install the interface into kernel networking data structures 574 */ 575int 576cs_attach(struct cs_softc *sc, int unit, int flags) 577{ 578 int media=0; 579 struct ifnet *ifp = &(sc->arpcom.ac_if); 580 581 cs_stop( sc ); 582 583 if (!ifp->if_name) { 584 ifp->if_softc=sc; 585 ifp->if_unit=unit; 586 ifp->if_name="cs"; 587 ifp->if_output=ether_output; 588 ifp->if_start=cs_start; 589 ifp->if_ioctl=cs_ioctl; 590 ifp->if_watchdog=cs_watchdog; 591 ifp->if_init=cs_init; 592 ifp->if_snd.ifq_maxlen= IFQ_MAXLEN; 593 /* 594 * MIB DATA 595 */ 596 /* 597 ifp->if_linkmib=&sc->mibdata; 598 ifp->if_linkmiblen=sizeof sc->mibdata; 599 */ 600 601 ifp->if_flags=(IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST ); 602 603 /* 604 * this code still in progress (DMA support) 605 * 606 607 sc->recv_ring=malloc(CS_DMA_BUFFER_SIZE<<1, M_DEVBUF, M_NOWAIT); 608 if (sc->recv_ring == NULL) { 609 log(LOG_ERR,CS_NAME 610 "%d: Couldn't allocate memory for NIC\n", unit); 611 return(0); 612 } 613 if ((sc->recv_ring-(sc->recv_ring & 0x1FFFF)) 614 < (128*1024-CS_DMA_BUFFER_SIZE)) 615 sc->recv_ring+=16*1024; 616 617 */ 618 619 sc->buffer=malloc(ETHER_MAX_LEN-ETHER_CRC_LEN,M_DEVBUF,M_NOWAIT); 620 if (sc->buffer == NULL) { 621 if_printf(ifp, "Couldn't allocate memory for NIC\n"); 622 return(0); 623 } 624 625 /* 626 * Initialize the media structures. 627 */ 628 ifmedia_init(&sc->media, 0, cs_mediachange, cs_mediastatus); 629 630 if (sc->adapter_cnf & A_CNF_10B_T) { 631 ifmedia_add(&sc->media, IFM_ETHER|IFM_10_T, 0, NULL); 632 if (sc->chip_type != CS8900) { 633 ifmedia_add(&sc->media, 634 IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 635 ifmedia_add(&sc->media, 636 IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 637 } 638 } 639 640 if (sc->adapter_cnf & A_CNF_10B_2) 641 ifmedia_add(&sc->media, IFM_ETHER|IFM_10_2, 0, NULL); 642 643 if (sc->adapter_cnf & A_CNF_AUI) 644 ifmedia_add(&sc->media, IFM_ETHER|IFM_10_5, 0, NULL); 645 646 if (sc->adapter_cnf & A_CNF_MEDIA) 647 ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL); 648 649 /* Set default media from EEPROM */ 650 switch (sc->adapter_cnf & A_CNF_MEDIA_TYPE) { 651 case A_CNF_MEDIA_AUTO: media = IFM_ETHER|IFM_AUTO; break; 652 case A_CNF_MEDIA_10B_T: media = IFM_ETHER|IFM_10_T; break; 653 case A_CNF_MEDIA_10B_2: media = IFM_ETHER|IFM_10_2; break; 654 case A_CNF_MEDIA_AUI: media = IFM_ETHER|IFM_10_5; break; 655 default: if_printf(ifp, "adapter has no media\n"); 656 } 657 ifmedia_set(&sc->media, media); 658 cs_mediaset(sc, media); 659 660 ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 661 } 662 663 if (bootverbose) 664 if_printf(ifp, "ethernet address %6D\n", 665 sc->arpcom.ac_enaddr, ":"); 666 667 return (0); 668} 669 670/* 671 * Initialize the board 672 */ 673static void 674cs_init(void *xsc) 675{ 676 struct cs_softc *sc=(struct cs_softc *)xsc; 677 struct ifnet *ifp = &sc->arpcom.ac_if; 678 int i, s, rx_cfg; 679 680 /* address not known */ 681 if (TAILQ_EMPTY(&ifp->if_addrhead)) /* unlikely? XXX */ 682 return; 683 684 /* 685 * reset whatchdog timer 686 */ 687 ifp->if_timer=0; 688 sc->buf_len = 0; 689 690 s=splimp(); 691 692 /* 693 * Hardware initialization of cs 694 */ 695 696 /* Enable receiver and transmitter */ 697 cs_writereg(sc, PP_LineCTL, 698 cs_readreg(sc, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); 699 700 /* Configure the receiver mode */ 701 cs_setmode(sc); 702 703 /* 704 * This defines what type of frames will cause interrupts 705 * Bad frames should generate interrupts so that the driver 706 * could track statistics of discarded packets 707 */ 708 rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | 709 RX_EXTRA_DATA_ENBL; 710 if (sc->isa_config & STREAM_TRANSFER) 711 rx_cfg |= RX_STREAM_ENBL; 712 cs_writereg(sc, PP_RxCFG, rx_cfg); 713 cs_writereg(sc, PP_TxCFG, TX_LOST_CRS_ENBL | 714 TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL | 715 TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); 716 cs_writereg(sc, PP_BufCFG, READY_FOR_TX_ENBL | 717 RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL | 718 TX_UNDERRUN_ENBL /*| RX_DMA_ENBL*/); 719 720 /* Write MAC address into IA filter */ 721 for (i=0; i<ETHER_ADDR_LEN/2; i++) 722 cs_writereg(sc, PP_IA + i * 2, 723 sc->arpcom.ac_enaddr[i * 2] | 724 (sc->arpcom.ac_enaddr[i * 2 + 1] << 8) ); 725 726 /* 727 * Now enable everything 728 */ 729/* 730#ifdef CS_USE_64K_DMA 731 cs_writereg(sc, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K); 732#else 733 cs_writereg(sc, PP_BusCTL, ENABLE_IRQ); 734#endif 735*/ 736 cs_writereg(sc, PP_BusCTL, ENABLE_IRQ); 737 738 /* 739 * Set running and clear output active flags 740 */ 741 sc->arpcom.ac_if.if_flags |= IFF_RUNNING; 742 sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 743 744 /* 745 * Start sending process 746 */ 747 cs_start(ifp); 748 749 (void) splx(s); 750} 751 752/* 753 * Get the packet from the board and send it to the upper layer 754 * via ether_input(). 755 */ 756static int 757cs_get_packet(struct cs_softc *sc) 758{ 759 struct ifnet *ifp = &(sc->arpcom.ac_if); 760 int iobase = sc->nic_addr, status, length; 761 struct ether_header *eh; 762 struct mbuf *m; 763 764#ifdef CS_DEBUG 765 int i; 766#endif 767 768 status = cs_inw(sc, RX_FRAME_PORT); 769 length = cs_inw(sc, RX_FRAME_PORT); 770 771#ifdef CS_DEBUG 772 if_printf(ifp, "rcvd: stat %x, len %d\n", 773 status, length); 774#endif 775 776 if (!(status & RX_OK)) { 777#ifdef CS_DEBUG 778 if_printf(ifp, "bad pkt stat %x\n", status); 779#endif 780 ifp->if_ierrors++; 781 return -1; 782 } 783 784 MGETHDR(m, M_DONTWAIT, MT_DATA); 785 if (m==NULL) 786 return -1; 787 788 if (length > MHLEN) { 789 MCLGET(m, M_DONTWAIT); 790 if (!(m->m_flags & M_EXT)) { 791 m_freem(m); 792 return -1; 793 } 794 } 795 796 /* Initialize packet's header info */ 797 m->m_pkthdr.rcvif = ifp; 798 m->m_pkthdr.len = length; 799 m->m_len = length; 800 801 /* Get the data */ 802 insw(iobase + RX_FRAME_PORT, m->m_data, (length+1)>>1); 803 804 eh = mtod(m, struct ether_header *); 805 806#ifdef CS_DEBUG 807 for (i=0;i<length;i++) 808 printf(" %02x",(unsigned char)*((char *)(m->m_data+i))); 809 printf( "\n" ); 810#endif 811 812 if (status & (RX_IA | RX_BROADCAST) || 813 (ifp->if_flags & IFF_MULTICAST && status & RX_HASHED)) { 814 m->m_pkthdr.len -= sizeof(struct ether_header); 815 m->m_len -= sizeof(struct ether_header); 816 m->m_data += sizeof(struct ether_header); 817 818 /* Feed the packet to the upper layer */ 819 ether_input(ifp, eh, m); 820 821 ifp->if_ipackets++; 822 823 if (length==ETHER_MAX_LEN-ETHER_CRC_LEN) 824 DELAY( cs_recv_delay ); 825 } else { 826 m_freem(m); 827 } 828 829 return 0; 830} 831 832/* 833 * Handle interrupts 834 */ 835void 836csintr(void *arg) 837{ 838 struct cs_softc *sc = (struct cs_softc*) arg; 839 struct ifnet *ifp = &(sc->arpcom.ac_if); 840 int status; 841 842#ifdef CS_DEBUG 843 if_printf(ifp, "Interrupt.\n"); 844#endif 845 846 while ((status=cs_inw(sc, ISQ_PORT))) { 847 848#ifdef CS_DEBUG 849 if_printf(ifp, "from ISQ: %04x\n", status); 850#endif 851 852 switch (status & ISQ_EVENT_MASK) { 853 case ISQ_RECEIVER_EVENT: 854 cs_get_packet(sc); 855 break; 856 857 case ISQ_TRANSMITTER_EVENT: 858 if (status & TX_OK) 859 ifp->if_opackets++; 860 else 861 ifp->if_oerrors++; 862 ifp->if_flags &= ~IFF_OACTIVE; 863 ifp->if_timer = 0; 864 break; 865 866 case ISQ_BUFFER_EVENT: 867 if (status & READY_FOR_TX) { 868 ifp->if_flags &= ~IFF_OACTIVE; 869 ifp->if_timer = 0; 870 } 871 872 if (status & TX_UNDERRUN) { 873 ifp->if_flags &= ~IFF_OACTIVE; 874 ifp->if_timer = 0; 875 ifp->if_oerrors++; 876 } 877 break; 878 879 case ISQ_RX_MISS_EVENT: 880 ifp->if_ierrors+=(status>>6); 881 break; 882 883 case ISQ_TX_COL_EVENT: 884 ifp->if_collisions+=(status>>6); 885 break; 886 } 887 } 888 889 if (!(ifp->if_flags & IFF_OACTIVE)) { 890 cs_start(ifp); 891 } 892} 893 894/* 895 * Save the data in buffer 896 */ 897 898static void 899cs_write_mbufs( struct cs_softc *sc, struct mbuf *m ) 900{ 901 int len; 902 struct mbuf *mp; 903 unsigned char *data, *buf; 904 905 for (mp=m, buf=sc->buffer, sc->buf_len=0; mp != NULL; mp=mp->m_next) { 906 len = mp->m_len; 907 908 /* 909 * Ignore empty parts 910 */ 911 if (!len) 912 continue; 913 914 /* 915 * Find actual data address 916 */ 917 data = mtod(mp, caddr_t); 918 919 bcopy((caddr_t) data, (caddr_t) buf, len); 920 buf += len; 921 sc->buf_len += len; 922 } 923} 924 925 926static void 927cs_xmit_buf( struct cs_softc *sc ) 928{ 929 outsw(sc->nic_addr+TX_FRAME_PORT, sc->buffer, (sc->buf_len+1)>>1); 930 sc->buf_len = 0; 931} 932 933static void 934cs_start(struct ifnet *ifp) 935{ 936 int s, length; 937 struct mbuf *m, *mp; 938 struct cs_softc *sc = ifp->if_softc; 939 940 s = splimp(); 941 942 for (;;) { 943 if (sc->buf_len) 944 length = sc->buf_len; 945 else { 946 IF_DEQUEUE( &ifp->if_snd, m ); 947 948 if (m==NULL) { 949 (void) splx(s); 950 return; 951 } 952 953 for (length=0, mp=m; mp != NULL; mp=mp->m_next) 954 length += mp->m_len; 955 956 /* Skip zero-length packets */ 957 if (length == 0) { 958 m_freem(m); 959 continue; 960 } 961 962 cs_write_mbufs(sc, m); 963 964 if (ifp->if_bpf) { 965 bpf_mtap(ifp, m); 966 } 967 968 m_freem(m); 969 } 970 971 /* 972 * Issue a SEND command 973 */ 974 cs_outw(sc, TX_CMD_PORT, sc->send_cmd); 975 cs_outw(sc, TX_LEN_PORT, length ); 976 977 /* 978 * If there's no free space in the buffer then leave 979 * this packet for the next time: indicate output active 980 * and return. 981 */ 982 if (!(cs_readreg(sc, PP_BusST) & READY_FOR_TX_NOW)) { 983 ifp->if_timer = sc->buf_len; 984 (void) splx(s); 985 ifp->if_flags |= IFF_OACTIVE; 986 return; 987 } 988 989 cs_xmit_buf(sc); 990 991 /* 992 * Set the watchdog timer in case we never hear 993 * from board again. (I don't know about correct 994 * value for this timeout) 995 */ 996 ifp->if_timer = length; 997 998 (void) splx(s); 999 ifp->if_flags |= IFF_OACTIVE; 1000 return; 1001 } 1002} 1003 1004/* 1005 * Stop everything on the interface 1006 */ 1007static void 1008cs_stop(struct cs_softc *sc) 1009{ 1010 int s = splimp(); 1011 1012 cs_writereg(sc, PP_RxCFG, 0); 1013 cs_writereg(sc, PP_TxCFG, 0); 1014 cs_writereg(sc, PP_BufCFG, 0); 1015 cs_writereg(sc, PP_BusCTL, 0); 1016 1017 sc->arpcom.ac_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1018 sc->arpcom.ac_if.if_timer = 0; 1019 1020 (void) splx(s); 1021} 1022 1023/* 1024 * Reset the interface 1025 */ 1026static void 1027cs_reset(struct cs_softc *sc) 1028{ 1029 cs_stop(sc); 1030 cs_init(sc); 1031} 1032 1033static void 1034cs_setmode(struct cs_softc *sc) 1035{ 1036 struct ifnet *ifp = &(sc->arpcom.ac_if); 1037 int rx_ctl; 1038 1039 /* Stop the receiver while changing filters */ 1040 cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) & ~SERIAL_RX_ON); 1041 1042 if (ifp->if_flags & IFF_PROMISC) { 1043 /* Turn on promiscuous mode. */ 1044 rx_ctl = RX_OK_ACCEPT | RX_PROM_ACCEPT; 1045 } else { 1046 if (ifp->if_flags & IFF_MULTICAST) { 1047 /* Allow receiving frames with multicast addresses */ 1048 rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | 1049 RX_OK_ACCEPT | RX_MULTCAST_ACCEPT; 1050 /* 1051 * Here the reconfiguration of chip's multicast 1052 * filters should be done but I've no idea about 1053 * hash transformation in this chip. If you can 1054 * add this code or describe me the transformation 1055 * I'd be very glad. 1056 */ 1057 } else { 1058 /* 1059 * Receive only good frames addressed for us and 1060 * good broadcasts. 1061 */ 1062 rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | 1063 RX_OK_ACCEPT; 1064 } 1065 } 1066 1067 /* Set up the filter */ 1068 cs_writereg(sc, PP_RxCTL, RX_DEF_ACCEPT | rx_ctl); 1069 1070 /* Turn on receiver */ 1071 cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | SERIAL_RX_ON); 1072} 1073 1074static int 1075cs_ioctl(register struct ifnet *ifp, u_long command, caddr_t data) 1076{ 1077 struct cs_softc *sc=ifp->if_softc; 1078 struct ifreq *ifr = (struct ifreq *)data; 1079 int s,error=0; 1080 1081#ifdef CS_DEBUG 1082 if_printf(ifp, "ioctl(%lx)\n", command); 1083#endif 1084 1085 s=splimp(); 1086 1087 switch (command) { 1088 case SIOCSIFADDR: 1089 case SIOCGIFADDR: 1090 case SIOCSIFMTU: 1091 ether_ioctl(ifp, command, data); 1092 break; 1093 1094 case SIOCSIFFLAGS: 1095 /* 1096 * Switch interface state between "running" and 1097 * "stopped", reflecting the UP flag. 1098 */ 1099 if (sc->arpcom.ac_if.if_flags & IFF_UP) { 1100 if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)==0) { 1101 cs_init(sc); 1102 } 1103 } else { 1104 if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)!=0) { 1105 cs_stop(sc); 1106 } 1107 } 1108 /* 1109 * Promiscuous and/or multicast flags may have changed, 1110 * so reprogram the multicast filter and/or receive mode. 1111 * 1112 * See note about multicasts in cs_setmode 1113 */ 1114 cs_setmode(sc); 1115 break; 1116 1117 case SIOCADDMULTI: 1118 case SIOCDELMULTI: 1119 /* 1120 * Multicast list has changed; set the hardware filter 1121 * accordingly. 1122 * 1123 * See note about multicasts in cs_setmode 1124 */ 1125 cs_setmode(sc); 1126 error = 0; 1127 break; 1128 1129 case SIOCSIFMEDIA: 1130 case SIOCGIFMEDIA: 1131 error = ifmedia_ioctl(ifp, ifr, &sc->media, command); 1132 break; 1133 1134 default: 1135 error = EINVAL; 1136 } 1137 1138 (void) splx(s); 1139 return error; 1140} 1141 1142/* 1143 * Device timeout/watchdog routine. Entered if the device neglects to 1144 * generate an interrupt after a transmit has been started on it. 1145 */ 1146static void 1147cs_watchdog(struct ifnet *ifp) 1148{ 1149 struct cs_softc *sc = ifp->if_softc; 1150 1151 ifp->if_oerrors++; 1152 log(LOG_ERR, CS_NAME"%d: device timeout\n", ifp->if_unit); 1153 1154 /* Reset the interface */ 1155 if (ifp->if_flags & IFF_UP) 1156 cs_reset(sc); 1157 else 1158 cs_stop(sc); 1159} 1160 1161static int 1162cs_mediachange(struct ifnet *ifp) 1163{ 1164 struct cs_softc *sc = ifp->if_softc; 1165 struct ifmedia *ifm = &sc->media; 1166 1167 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1168 return EINVAL; 1169 1170 return cs_mediaset(sc, ifm->ifm_media); 1171} 1172 1173static void 1174cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1175{ 1176 int line_status; 1177 struct cs_softc *sc = ifp->if_softc; 1178 1179 ifmr->ifm_active = IFM_ETHER; 1180 line_status = cs_readreg(sc, PP_LineST); 1181 if (line_status & TENBASET_ON) { 1182 ifmr->ifm_active |= IFM_10_T; 1183 if (sc->chip_type != CS8900) { 1184 if (cs_readreg(sc, PP_AutoNegST) & FDX_ACTIVE) 1185 ifmr->ifm_active |= IFM_FDX; 1186 if (cs_readreg(sc, PP_AutoNegST) & HDX_ACTIVE) 1187 ifmr->ifm_active |= IFM_HDX; 1188 } 1189 ifmr->ifm_status = IFM_AVALID; 1190 if (line_status & LINK_OK) 1191 ifmr->ifm_status |= IFM_ACTIVE; 1192 } else { 1193 if (line_status & AUI_ON) { 1194 cs_writereg(sc, PP_SelfCTL, cs_readreg(sc, PP_SelfCTL) | 1195 HCB1_ENBL); 1196 if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^ 1197 (cs_readreg(sc, PP_SelfCTL) & HCB1)) 1198 ifmr->ifm_active |= IFM_10_2; 1199 else 1200 ifmr->ifm_active |= IFM_10_5; 1201 } 1202 } 1203} 1204 1205static int 1206cs_mediaset(struct cs_softc *sc, int media) 1207{ 1208 int error; 1209 1210 /* Stop the receiver & transmitter */ 1211 cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) & 1212 ~(SERIAL_RX_ON | SERIAL_TX_ON)); 1213 1214#ifdef CS_DEBUG 1215 if_printf(&sc->arpcom.ac_if, "cs_setmedia(%x)\n", media); 1216#endif 1217 1218 switch (IFM_SUBTYPE(media)) { 1219 default: 1220 case IFM_AUTO: 1221 if ((error=enable_tp(sc))==0) 1222 error = cs_duplex_auto(sc); 1223 else if ((error=enable_bnc(sc)) != 0) 1224 error = enable_aui(sc); 1225 break; 1226 case IFM_10_T: 1227 if ((error=enable_tp(sc)) != 0) 1228 break; 1229 if (media & IFM_FDX) 1230 cs_duplex_full(sc); 1231 else if (media & IFM_HDX) 1232 cs_duplex_half(sc); 1233 else 1234 error = cs_duplex_auto(sc); 1235 break; 1236 case IFM_10_2: 1237 error = enable_bnc(sc); 1238 break; 1239 case IFM_10_5: 1240 error = enable_aui(sc); 1241 break; 1242 } 1243 1244 /* 1245 * Turn the transmitter & receiver back on 1246 */ 1247 cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | 1248 SERIAL_RX_ON | SERIAL_TX_ON); 1249 1250 return error; 1251} 1252