if_cs.c revision 140925
116566Ssos/*- 216566Ssos * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko. 316566Ssos * All rights reserved. 416566Ssos * 516566Ssos * Redistribution and use in source and binary forms, with or without 616566Ssos * modification, are permitted provided that the following conditions 716566Ssos * are met: 816566Ssos * 1. Redistributions of source code must retain the above copyright 916566Ssos * notice unmodified, this list of conditions, and the following 1016566Ssos * disclaimer. 1116566Ssos * 2. Redistributions in binary form must reproduce the above copyright 1216566Ssos * notice, this list of conditions and the following disclaimer in the 1316566Ssos * documentation and/or other materials provided with the distribution. 1416566Ssos * 1516566Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1616566Ssos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1716566Ssos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1816566Ssos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1916566Ssos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2016566Ssos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2116566Ssos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2216566Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2316566Ssos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2416566Ssos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2516566Ssos * SUCH DAMAGE. 2616566Ssos * 2716566Ssos */ 2816566Ssos 2916566Ssos#include <sys/cdefs.h> 3016566Ssos__FBSDID("$FreeBSD: head/sys/dev/cs/if_cs.c 140925 2005-01-28 06:13:29Z imp $"); 3116566Ssos 3216566Ssos/* 3316566Ssos * 3416566Ssos * Device driver for Crystal Semiconductor CS8920 based ethernet 3516566Ssos * adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997 3616566Ssos */ 3731604Syokota 38122605Sdes/* 3931604Syokota#define CS_DEBUG 4016566Ssos */ 4116566Ssos 4216566Ssos#include <sys/param.h> 4316566Ssos#include <sys/systm.h> 44122605Sdes#include <sys/malloc.h> 4516566Ssos#include <sys/mbuf.h> 4616566Ssos#include <sys/socket.h> 47122854Sdes#include <sys/sockio.h> 48122854Sdes#include <sys/kernel.h> 4929849Scharnier#include <sys/sysctl.h> 50122853Sdes#include <sys/syslog.h> 51122853Sdes 52122853Sdes#include <sys/module.h> 53122853Sdes#include <sys/bus.h> 54122853Sdes#include <machine/bus.h> 55122853Sdes#include <sys/rman.h> 56122853Sdes#include <machine/resource.h> 57122853Sdes 5858231Syokota#include <net/if.h> 5929849Scharnier#include <net/if_arp.h> 6029849Scharnier#include <net/if_media.h> 6129849Scharnier#include <net/ethernet.h> 62149426Spjd#include <net/bpf.h> 6329849Scharnier 64122853Sdes#include <dev/cs/if_csvar.h> 65122853Sdes#include <dev/cs/if_csreg.h> 66122853Sdes 67176889Sjkim#ifdef CS_USE_64K_DMA 6816566Ssos#define CS_DMA_BUFFER_SIZE 65536 6916566Ssos#else 7016566Ssos#define CS_DMA_BUFFER_SIZE 16384 71122853Sdes#endif 7216566Ssos 7321885Ssosstatic void cs_init(void *); 74167461Sphilipstatic int cs_ioctl(struct ifnet *, u_long, caddr_t); 7516566Ssosstatic void cs_start(struct ifnet *); 7631604Syokotastatic void cs_stop(struct cs_softc *); 7758344Syokotastatic void cs_reset(struct cs_softc *); 7858344Syokotastatic void cs_watchdog(struct ifnet *); 7959465Syokota 80136372Sphilipstatic int cs_mediachange(struct ifnet *); 81179015Sphilipstatic void cs_mediastatus(struct ifnet *, struct ifmediareq *); 8231604Syokotastatic int cs_mediaset(struct cs_softc *, int); 8379430Siedowse 8479430Siedowsestatic void cs_write_mbufs(struct cs_softc*, struct mbuf*); 8579430Siedowsestatic void cs_xmit_buf(struct cs_softc*); 8631604Syokotastatic int cs_get_packet(struct cs_softc*); 8731604Syokotastatic void cs_setmode(struct cs_softc*); 8831604Syokota 8931604Syokotastatic int get_eeprom_data(struct cs_softc *sc, int, int, uint16_t *); 9031604Syokotastatic int get_eeprom_cksum(int, int, uint16_t *); 9131604Syokotastatic int wait_eeprom_ready( struct cs_softc *); 9248778Syokotastatic void control_dc_dc( struct cs_softc *, int ); 9348778Syokotastatic int send_test_pkt( struct cs_softc * ); 9448778Syokotastatic int enable_tp(struct cs_softc *); 9548778Syokotastatic int enable_aui(struct cs_softc *); 9648778Syokotastatic int enable_bnc(struct cs_softc *); 9748778Syokotastatic int cs_duplex_auto(struct cs_softc *); 9831604Syokota 9931604Syokotadevclass_t cs_devclass; 10031604Syokota 10131604Syokota/* sysctl vars */ 10231604SyokotaSYSCTL_NODE(_hw, OID_AUTO, cs, CTLFLAG_RD, 0, "cs device parameters"); 103136372Sphilip 104148161Sphilipint cs_debug = 0; 105167461SphilipTUNABLE_INT("hw.cs.debug", &cs_debug); 106122605SdesSYSCTL_INT(_hw_cs, OID_AUTO, debug, CTLFLAG_RW, 10731604Syokota &cs_debug, 0, 10831604Syokota "cs debug"); 10931604Syokota 110136372Sphilipint cs_ignore_cksum_failure = 0; 11131604SyokotaTUNABLE_INT("hw.cs.ignore_checksum_failure", &cs_ignore_cksum_failure); 11231604SyokotaSYSCTL_INT(_hw_cs, OID_AUTO, ignore_checksum_failure, CTLFLAG_RW, 11331604Syokota &cs_ignore_cksum_failure, 0, 114176854Sjkim "ignore checksum errors in cs card EEPROM"); 115176854Sjkim 116176854Sjkimstatic int cs_recv_delay = 570; 117176854SjkimTUNABLE_INT("hw.cs.recv_delay", &cs_recv_delay); 118176854SjkimSYSCTL_INT(_hw_cs, OID_AUTO, recv_delay, CTLFLAG_RW, &cs_recv_delay, 570, ""); 119176854Sjkim 120176854Sjkimstatic int 121176854Sjkimget_eeprom_data(struct cs_softc *sc, int off, int len, uint16_t *buffer) 122176854Sjkim{ 123176854Sjkim int i; 124176854Sjkim 125176854Sjkim#ifdef CS_DEBUG 126176854Sjkim printf(CS_NAME":EEPROM data from %x for %x:\n", off, len); 127176854Sjkim#endif 128176854Sjkim 129176854Sjkim for (i=0; i < len; i++) { 130160523Sstefanf if (wait_eeprom_ready(sc) < 0) 13195629Siedowse return (-1); 132160523Sstefanf /* Send command to EEPROM to read */ 13395629Siedowse cs_writereg(sc, PP_EECMD, (off + i) | EEPROM_READ_CMD); 13416566Ssos if (wait_eeprom_ready(sc) < 0) 135160523Sstefanf return (-1); 136160523Sstefanf buffer[i] = cs_readreg(sc, PP_EEData); 13795629Siedowse 13895629Siedowse#ifdef CS_DEBUG 13931604Syokota printf("%02x %02x ",(unsigned char)buffer[i], 140160523Sstefanf (unsigned char)buffer[i] >> 8); 141160523Sstefanf#endif 14295629Siedowse } 14395629Siedowse 14431604Syokota#ifdef CS_DEBUG 145160523Sstefanf printf("\n"); 146160523Sstefanf#endif 14731604Syokota return (0); 148160523Sstefanf} 149160523Sstefanf 15031604Syokotastatic int 15131604Syokotaget_eeprom_cksum(int off, int len, uint16_t *buffer) 15231604Syokota{ 15331604Syokota int i; 15431604Syokota uint16_t cksum=0; 155176855Sjkim 15631604Syokota for (i = 0; i < len; i++) 15731604Syokota cksum += buffer[i]; 15831604Syokota cksum &= 0xffff; 15931604Syokota if (cksum==0) 16031604Syokota return (0); 16131604Syokota if (cs_ignore_cksum_failure) { 16231604Syokota printf(CS_NAME": checksum mismatch, ignoring\n"); 163176855Sjkim return (0); 16431604Syokota } 165176855Sjkim return (-1); 16631604Syokota} 16731604Syokota 16831604Syokotastatic int 16931604Syokotawait_eeprom_ready(struct cs_softc *sc) 17031604Syokota{ 17131604Syokota DELAY(30000); /* XXX should we do some checks here ? */ 17231604Syokota return 0; 17331604Syokota} 17431604Syokota 17531604Syokotastatic void 17631604Syokotacontrol_dc_dc(struct cs_softc *sc, int on_not_off) 177227256Sed{ 178227256Sed unsigned int self_control = HCB1_ENBL; 179227256Sed 180227256Sed if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0) ^ on_not_off) 181227256Sed self_control |= HCB1; 182227256Sed else 183227256Sed self_control &= ~HCB1; 184227256Sed cs_writereg(sc, PP_SelfCTL, self_control); 18516566Ssos 186136372Sphilip DELAY(500000); 187136372Sphilip} 188136372Sphilip 189136372Sphilip 190136372Sphilipstatic int 191136372Sphilipcs_duplex_auto(struct cs_softc *sc) 192148161Sphilip{ 193136372Sphilip int i, error=0; 19431604Syokota 19516566Ssos cs_writereg(sc, PP_AutoNegCTL, 19631604Syokota RE_NEG_NOW | ALLOW_FDX | AUTO_NEG_ENABLE); 19731604Syokota for (i=0; cs_readreg(sc, PP_AutoNegST) & AUTO_NEG_BUSY; i++) { 198176855Sjkim if (i > 40000) { 199176855Sjkim if_printf(&sc->arpcom.ac_if, 200176855Sjkim "full/half duplex auto negotiation timeout\n"); 201176855Sjkim error = ETIMEDOUT; 202176855Sjkim break; 203176855Sjkim } 204176855Sjkim DELAY(1000); 20531604Syokota } 20616566Ssos DELAY( 1000000 ); 20731604Syokota return error; 208176855Sjkim} 20916566Ssos 21016566Ssosstatic int 21131604Syokotaenable_tp(struct cs_softc *sc) 21216566Ssos{ 21331604Syokota 21416566Ssos cs_writereg(sc, PP_LineCTL, sc->line_ctl & ~AUI_ONLY); 21531604Syokota control_dc_dc(sc, 0); 21616566Ssos DELAY( 150000 ); 21718222Speter 21831604Syokota if ((cs_readreg(sc, PP_LineST) & LINK_OK)==0) { 21931604Syokota if_printf(&sc->arpcom.ac_if, "failed to enable TP\n"); 22031604Syokota return EINVAL; 22131604Syokota } 22236991Sahasty 22341271Syokota return 0; 22493071Swill} 22593071Swill 22631604Syokota/* 22731604Syokota * XXX This was rewritten from Linux driver without any tests. 22831604Syokota */ 229145001Smdoddstatic int 23016566Ssossend_test_pkt(struct cs_softc *sc) 23116566Ssos{ 23216566Ssos char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, 23331604Syokota 0, 46, /* A 46 in network order */ 23431604Syokota 0, 0, /* DSAP=0 & SSAP=0 fields */ 235176855Sjkim 0xf3, 0 /* Control (Test Req + P bit set) */ }; 236176855Sjkim int i; 237176855Sjkim u_char ether_address_backup[ETHER_ADDR_LEN]; 238176855Sjkim 239176855Sjkim for (i = 0; i < ETHER_ADDR_LEN; i++) 240176855Sjkim ether_address_backup[i] = sc->arpcom.ac_enaddr[i]; 241176855Sjkim 242176855Sjkim cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | SERIAL_TX_ON); 243176855Sjkim bcopy(test_packet, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 244176855Sjkim bcopy(test_packet+ETHER_ADDR_LEN, 245176855Sjkim sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 246176855Sjkim cs_outw(sc, TX_CMD_PORT, sc->send_cmd); 247176855Sjkim cs_outw(sc, TX_LEN_PORT, sizeof(test_packet)); 248248478Sjkim 249176855Sjkim /* Wait for chip to allocate memory */ 250176855Sjkim DELAY(50000); 25131604Syokota if (!(cs_readreg(sc, PP_BusST) & READY_FOR_TX_NOW)) { 25231604Syokota for (i = 0; i < ETHER_ADDR_LEN; i++) 25331604Syokota sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; 25431604Syokota return 0; 25531604Syokota } 25631604Syokota 25731604Syokota outsw(sc->nic_addr + TX_FRAME_PORT, test_packet, sizeof(test_packet)); 25831604Syokota 25931604Syokota DELAY(30000); 26031604Syokota 26158099Sache for (i = 0; i < ETHER_ADDR_LEN; i++) 26258099Sache sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; 26333074Sache if ((cs_readreg(sc, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) 26433074Sache return 1; 26556524Syokota return 0; 26656524Syokota} 26733074Sache 26833074Sache/* 26941271Syokota * XXX This was rewritten from Linux driver without any tests. 27041271Syokota */ 27131604Syokotastatic int 272122605Sdesenable_aui(struct cs_softc *sc) 27356335Syokota{ 27456335Syokota 27531949Syokota control_dc_dc(sc, 0); 27631949Syokota cs_writereg(sc, PP_LineCTL, 27731604Syokota (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); 27831604Syokota 27931604Syokota if (!send_test_pkt(sc)) { 28031604Syokota if_printf(&sc->arpcom.ac_if, "failed to enable AUI\n"); 28132634Syokota return EINVAL; 28232634Syokota } 28358231Syokota return 0; 28458231Syokota} 28558231Syokota 28658231Syokota/* 28758328Syokota * XXX This was rewritten from Linux driver without any tests. 28858328Syokota */ 28931604Syokotastatic int 29031604Syokotaenable_bnc(struct cs_softc *sc) 29131604Syokota{ 29231604Syokota 293122605Sdes control_dc_dc(sc, 1); 29431604Syokota cs_writereg(sc, PP_LineCTL, 295122605Sdes (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); 29631604Syokota 297122605Sdes if (!send_test_pkt(sc)) { 29831604Syokota if_printf(&sc->arpcom.ac_if, "failed to enable BNC\n"); 29931604Syokota return EINVAL; 30031604Syokota } 30131604Syokota return 0; 302122605Sdes} 303122605Sdes 304122605Sdesint 305122605Sdescs_cs89x0_probe(device_t dev) 30631604Syokota{ 307122605Sdes int i; 308122854Sdes int error; 309122605Sdes u_long irq, junk; 310122854Sdes struct cs_softc *sc = device_get_softc(dev); 31131604Syokota unsigned rev_type = 0; 31231604Syokota uint16_t id; 31331604Syokota char chip_revision; 31431604Syokota uint16_t eeprom_buff[CHKSUM_LEN]; 315122605Sdes int chip_type, pp_isaint, pp_isadma; 31631604Syokota 317122605Sdes error = cs_alloc_port(dev, 0, CS_89x0_IO_PORTS); 31831604Syokota if (error) 319122605Sdes return (error); 32031604Syokota 321122605Sdes sc->nic_addr = rman_get_start(sc->port_res); 32231604Syokota 323122605Sdes if ((cs_inw(sc, ADD_PORT) & ADD_MASK) != ADD_SIG) { 32431604Syokota /* Chip not detected. Let's try to reset it */ 325122605Sdes if (bootverbose) 32631604Syokota device_printf(dev, "trying to reset the chip.\n"); 327122605Sdes cs_outw(sc, ADD_PORT, PP_SelfCTL); 32831604Syokota i = cs_inw(sc, DATA_PORT); 32931604Syokota cs_outw(sc, ADD_PORT, PP_SelfCTL); 330122854Sdes cs_outw(sc, DATA_PORT, i | POWER_ON_RESET); 33131604Syokota if ((cs_inw(sc, ADD_PORT) & ADD_MASK) != ADD_SIG) 33231604Syokota return (ENXIO); 333122605Sdes } 33431604Syokota 33531604Syokota for (i = 0; i < 10000; i++) { 33631604Syokota id = cs_readreg(sc, PP_ChipID); 33731604Syokota if (id == CHIP_EISA_ID_SIG) 33831604Syokota break; 33931604Syokota } 340122854Sdes if (i == 10000) 34131604Syokota return (ENXIO); 342122605Sdes 34331604Syokota rev_type = cs_readreg(sc, PRODUCT_ID_ADD); 34431604Syokota chip_type = rev_type & ~REVISON_BITS; 34531604Syokota chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; 346122854Sdes 34731604Syokota sc->chip_type = chip_type; 34831604Syokota 34931604Syokota if(chip_type==CS8900) { 35031604Syokota pp_isaint = PP_CS8900_ISAINT; 35131604Syokota pp_isadma = PP_CS8900_ISADMA; 35231604Syokota sc->send_cmd = TX_CS8900_AFTER_ALL; 35331604Syokota } else { 35431604Syokota pp_isaint = PP_CS8920_ISAINT; 35531604Syokota pp_isadma = PP_CS8920_ISADMA; 356122854Sdes sc->send_cmd = TX_CS8920_AFTER_ALL; 35731604Syokota } 358122854Sdes 35931604Syokota /* 360122854Sdes * Clear some fields so that fail of EEPROM will left them clean 36131604Syokota */ 362122854Sdes sc->auto_neg_cnf = 0; 36331604Syokota sc->adapter_cnf = 0; 364122854Sdes sc->isa_config = 0; 36531604Syokota 36649967Syokota /* 36749967Syokota * If no interrupt specified (or "?"), use what the board tells us. 36831604Syokota */ 36931604Syokota error = bus_get_resource(dev, SYS_RES_IRQ, 0, &irq, &junk); 37031604Syokota 37131604Syokota /* 37231604Syokota * Get data from EEPROM 37331604Syokota */ 37416566Ssos if((cs_readreg(sc, PP_SelfST) & EEPROM_PRESENT) == 0) { 375122854Sdes device_printf(dev, "No EEPROM, assuming defaults.\n"); 376122854Sdes } else { 377122854Sdes if (get_eeprom_data(sc,START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) { 378122854Sdes device_printf(dev, "EEPROM read failed, " 379122854Sdes "assuming defaults.\n"); 38031604Syokota } else { 38131604Syokota if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) { 38218222Speter device_printf(dev, "EEPROM cheksum bad, " 383122854Sdes "assuming defaults.\n"); 384122854Sdes } else { 385122854Sdes sc->auto_neg_cnf = 386122854Sdes eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; 387122854Sdes sc->adapter_cnf = 388122854Sdes eeprom_buff[ADAPTER_CNF_OFFSET/2]; 389122854Sdes sc->isa_config = 390122854Sdes eeprom_buff[ISA_CNF_OFFSET/2]; 39193071Swill 39231604Syokota for (i=0; i<ETHER_ADDR_LEN/2; i++) { 393122854Sdes sc->arpcom.ac_enaddr[i*2]= 39431604Syokota eeprom_buff[i]; 395145001Smdodd sc->arpcom.ac_enaddr[i*2+1]= 39616566Ssos eeprom_buff[i] >> 8; 39716566Ssos } 39831604Syokota 39931604Syokota /* 400176855Sjkim * If no interrupt specified (or "?"), 40131604Syokota * use what the board tells us. 40231604Syokota */ 40331604Syokota if (error) { 40431604Syokota irq = sc->isa_config & INT_NO_MASK; 40531604Syokota if (chip_type==CS8900) { 40658231Syokota switch(irq) { 40741270Syokota case 0: 40831604Syokota irq=10; 40931604Syokota error=0; 41036991Sahasty break; 41136991Sahasty case 1: 412240891Shselasky irq=11; 41331604Syokota error=0; 41458344Syokota break; 41531604Syokota case 2: 41631604Syokota irq=12; 41778770Sgreid error=0; 41878770Sgreid break; 419167461Sphilip case 3: 420167461Sphilip irq=5; 421170895Sphilip error=0; 422170895Sphilip break; 423136372Sphilip default: 424179015Sphilip device_printf(dev, "invalid irq in EEPROM.\n"); 425122605Sdes error=EINVAL; 426131525Sstefanf } 427131525Sstefanf } else { 428131525Sstefanf if (irq>CS8920_NO_INTS) { 429131525Sstefanf device_printf(dev, "invalid irq in EEPROM.\n"); 430131525Sstefanf error=EINVAL; 431131525Sstefanf } else { 432131525Sstefanf error=0; 433131525Sstefanf } 434131525Sstefanf } 435131525Sstefanf 436131525Sstefanf if (!error) 437131525Sstefanf bus_set_resource(dev, SYS_RES_IRQ, 0, 438131525Sstefanf irq, 1); 439240891Shselasky } 440131525Sstefanf } 441131525Sstefanf } 442131525Sstefanf } 443131525Sstefanf 444167461Sphilip if (!error) { 445167461Sphilip if (chip_type == CS8900) { 446170895Sphilip switch(irq) { 447170895Sphilip case 5: 448136372Sphilip irq = 3; 449179015Sphilip break; 45031604Syokota case 10: 45116566Ssos irq = 0; 45231604Syokota break; 45358344Syokota case 11: 45431604Syokota irq = 1; 455176854Sjkim break; 45658344Syokota case 12: 457176855Sjkim irq = 2; 45858344Syokota break; 45958344Syokota default: 46016566Ssos error=EINVAL; 46158344Syokota } 46258344Syokota } else { 46358344Syokota if (irq > CS8920_NO_INTS) { 46458344Syokota error = EINVAL; 46558344Syokota } 46658344Syokota } 46758344Syokota } 46858344Syokota 46958344Syokota if (!error) { 47058344Syokota cs_writereg(sc, pp_isaint, irq); 47158344Syokota } else { 47258344Syokota device_printf(dev, "Unknown or invalid irq\n"); 47358344Syokota return (ENXIO); 47458344Syokota } 47558344Syokota 47679430Siedowse /* 47758344Syokota * Temporary disabled 47858344Syokota * 47958344Syokota if (drq>0) 48058344Syokota cs_writereg(sc, pp_isadma, drq); 48158344Syokota else { 48259090Syokota device_printf(dev, "incorrect drq\n",); 48358344Syokota return 0; 48458344Syokota } 48559090Syokota */ 48658344Syokota 48759090Syokota if (bootverbose) 48858344Syokota device_printf(dev, "CS89%c0%s rev %c media%s%s%s\n", 48959090Syokota chip_type==CS8900 ? '0' : '2', 49058344Syokota chip_type==CS8920M ? "M" : "", 49159090Syokota chip_revision, 49258344Syokota (sc->adapter_cnf & A_CNF_10B_T) ? " TP" : "", 49359090Syokota (sc->adapter_cnf & A_CNF_AUI) ? " AUI" : "", 49458344Syokota (sc->adapter_cnf & A_CNF_10B_2) ? " BNC" : ""); 49559090Syokota 49658344Syokota if ((sc->adapter_cnf & A_CNF_EXTND_10B_2) && 49759090Syokota (sc->adapter_cnf & A_CNF_LOW_RX_SQUELCH)) 49858344Syokota sc->line_ctl = LOW_RX_SQUELCH; 49959090Syokota else 50058344Syokota sc->line_ctl = 0; 50159090Syokota 50258344Syokota 50359090Syokota return 0; 50458344Syokota} 50558344Syokota 506176854Sjkim/* 50779430Siedowse * Allocate a port resource with the given resource id. 50858344Syokota */ 50931604Syokotaint cs_alloc_port(device_t dev, int rid, int size) 51016566Ssos{ 511176854Sjkim struct cs_softc *sc = device_get_softc(dev); 512176854Sjkim struct resource *res; 513176854Sjkim 514176854Sjkim res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 515176854Sjkim 0ul, ~0ul, size, RF_ACTIVE); 516176854Sjkim if (res) { 517176854Sjkim sc->port_rid = rid; 518176854Sjkim sc->port_res = res; 519176854Sjkim sc->port_used = size; 520176854Sjkim return (0); 521150310Sphilip } else { 522176854Sjkim return (ENOENT); 523176854Sjkim } 524176854Sjkim} 525176854Sjkim 526176855Sjkim/* 527176855Sjkim * Allocate a memory resource with the given resource id. 528150310Sphilip */ 52931604Syokotaint cs_alloc_memory(device_t dev, int rid, int size) 53016566Ssos{ 531170895Sphilip struct cs_softc *sc = device_get_softc(dev); 532167461Sphilip struct resource *res; 53331604Syokota 53431604Syokota res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 53536991Sahasty 0ul, ~0ul, size, RF_ACTIVE); 536153070Sphilip if (res) { 53731604Syokota sc->mem_rid = rid; 53895629Siedowse sc->mem_res = res; 53995629Siedowse sc->mem_used = size; 54031604Syokota return (0); 54131604Syokota } else { 542176855Sjkim return (ENOENT); 543176855Sjkim } 544176855Sjkim} 54531604Syokota 54631604Syokota/* 54758344Syokota * Allocate an irq resource with the given resource id. 54831604Syokota */ 54931604Syokotaint cs_alloc_irq(device_t dev, int rid, int flags) 55058344Syokota{ 55158344Syokota struct cs_softc *sc = device_get_softc(dev); 55231604Syokota struct resource *res; 55331604Syokota 55431604Syokota res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 55540255Syokota (RF_ACTIVE | flags)); 55640255Syokota if (res) { 55731604Syokota sc->irq_rid = rid; 55831604Syokota sc->irq_res = res; 55931604Syokota return (0); 56031604Syokota } else { 561176855Sjkim return (ENOENT); 562176855Sjkim } 56331604Syokota} 564176855Sjkim 56536991Sahasty/* 56636991Sahasty * Release all resources 567122854Sdes */ 568145001Smdoddvoid cs_release_resources(device_t dev) 56941271Syokota{ 57051287Speter struct cs_softc *sc = device_get_softc(dev); 57116566Ssos 57216566Ssos if (sc->port_res) { 57331604Syokota bus_release_resource(dev, SYS_RES_IOPORT, 57431604Syokota sc->port_rid, sc->port_res); 57558231Syokota sc->port_res = 0; 57616566Ssos } 57758344Syokota if (sc->mem_res) { 57858344Syokota bus_release_resource(dev, SYS_RES_MEMORY, 57958344Syokota sc->mem_rid, sc->mem_res); 580179015Sphilip sc->mem_res = 0; 58131604Syokota } 58231604Syokota if (sc->irq_res) { 58331604Syokota bus_release_resource(dev, SYS_RES_IRQ, 58431604Syokota sc->irq_rid, sc->irq_res); 58531604Syokota sc->irq_res = 0; 58631604Syokota } 58758344Syokota} 58858344Syokota 589122605Sdes/* 590122605Sdes * Install the interface into kernel networking data structures 591122605Sdes */ 592122605Sdesint 59358344Syokotacs_attach(device_t dev) 59458344Syokota{ 59558344Syokota int media=0; 59678770Sgreid struct cs_softc *sc = device_get_softc(dev);; 59778770Sgreid struct ifnet *ifp = &(sc->arpcom.ac_if); 59878770Sgreid 599167461Sphilip cs_stop( sc ); 60078770Sgreid 60178770Sgreid ifp->if_softc=sc; 602122605Sdes if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 60378770Sgreid ifp->if_start=cs_start; 60478770Sgreid ifp->if_ioctl=cs_ioctl; 605122605Sdes ifp->if_watchdog=cs_watchdog; 60678770Sgreid ifp->if_init=cs_init; 607122605Sdes ifp->if_snd.ifq_maxlen= IFQ_MAXLEN; 608167461Sphilip /* 609167461Sphilip * MIB DATA 610167461Sphilip */ 611167461Sphilip /* 612167461Sphilip ifp->if_linkmib=&sc->mibdata; 613167461Sphilip ifp->if_linkmiblen=sizeof sc->mibdata; 614167461Sphilip */ 615167461Sphilip 616167461Sphilip ifp->if_flags=(IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | 617167461Sphilip IFF_NEEDSGIANT); 618167461Sphilip 619167461Sphilip /* 620167461Sphilip * this code still in progress (DMA support) 62116566Ssos * 62216566Ssos 62316566Ssos sc->recv_ring=malloc(CS_DMA_BUFFER_SIZE<<1, M_DEVBUF, M_NOWAIT); 62416566Ssos if (sc->recv_ring == NULL) { 62516566Ssos log(LOG_ERR, 62631604Syokota "%s: Couldn't allocate memory for NIC\n", ifp->if_xname); 62716566Ssos return(0); 62816566Ssos } 62916566Ssos if ((sc->recv_ring-(sc->recv_ring & 0x1FFFF)) 63031604Syokota < (128*1024-CS_DMA_BUFFER_SIZE)) 63116566Ssos sc->recv_ring+=16*1024; 63216566Ssos 63331604Syokota */ 63431604Syokota 635122605Sdes sc->buffer=malloc(ETHER_MAX_LEN-ETHER_CRC_LEN,M_DEVBUF,M_NOWAIT); 63631604Syokota if (sc->buffer == NULL) { 637122605Sdes if_printf(ifp, "Couldn't allocate memory for NIC\n"); 63831604Syokota return(0); 639122605Sdes } 64031604Syokota 641122605Sdes /* 64231604Syokota * Initialize the media structures. 643122605Sdes */ 64431604Syokota ifmedia_init(&sc->media, 0, cs_mediachange, cs_mediastatus); 645122605Sdes 646122605Sdes if (sc->adapter_cnf & A_CNF_10B_T) { 64731604Syokota ifmedia_add(&sc->media, IFM_ETHER|IFM_10_T, 0, NULL); 64831604Syokota if (sc->chip_type != CS8900) { 64931604Syokota ifmedia_add(&sc->media, 65031604Syokota IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 65131604Syokota ifmedia_add(&sc->media, 65231604Syokota IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 65331604Syokota } 654122605Sdes } 655122605Sdes 65631604Syokota if (sc->adapter_cnf & A_CNF_10B_2) 65731604Syokota ifmedia_add(&sc->media, IFM_ETHER|IFM_10_2, 0, NULL); 65831604Syokota 65931604Syokota if (sc->adapter_cnf & A_CNF_AUI) 66031604Syokota ifmedia_add(&sc->media, IFM_ETHER|IFM_10_5, 0, NULL); 661122605Sdes 662122605Sdes if (sc->adapter_cnf & A_CNF_MEDIA) 66331604Syokota ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL); 66431604Syokota 66531604Syokota /* Set default media from EEPROM */ 66616566Ssos switch (sc->adapter_cnf & A_CNF_MEDIA_TYPE) { 66716566Ssos case A_CNF_MEDIA_AUTO: media = IFM_ETHER|IFM_AUTO; break; 66816566Ssos case A_CNF_MEDIA_10B_T: media = IFM_ETHER|IFM_10_T; break; 66916566Ssos case A_CNF_MEDIA_10B_2: media = IFM_ETHER|IFM_10_2; break; 67024377Speter case A_CNF_MEDIA_AUI: media = IFM_ETHER|IFM_10_5; break; 67131604Syokota default: 672122605Sdes if_printf(ifp, "no media, assuming 10baseT\n"); 67331604Syokota sc->adapter_cnf |= A_CNF_10B_T; 674122605Sdes ifmedia_add(&sc->media, IFM_ETHER|IFM_10_T, 0, NULL); 67531604Syokota if (sc->chip_type != CS8900) { 676122605Sdes ifmedia_add(&sc->media, 67731604Syokota IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 678122605Sdes ifmedia_add(&sc->media, 67931604Syokota IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 680122605Sdes } 68131604Syokota media = IFM_ETHER | IFM_10_T; 682122605Sdes break; 683122605Sdes } 684122605Sdes ifmedia_set(&sc->media, media); 685122605Sdes cs_mediaset(sc, media); 686122605Sdes 68731604Syokota ether_ifattach(ifp, sc->arpcom.ac_enaddr); 68824377Speter 68924377Speter return (0); 69016566Ssos} 69116566Ssos 69218222Speterint 69316566Ssoscs_detach(device_t dev) 69441270Syokota{ 69541270Syokota struct cs_softc *sc; 69641270Syokota struct ifnet *ifp; 69741270Syokota 69841270Syokota sc = device_get_softc(dev); 69941270Syokota ifp = &sc->arpcom.ac_if; 70041270Syokota 70141270Syokota cs_stop(sc); 70241270Syokota ifp->if_flags &= ~IFF_RUNNING; 70331604Syokota ether_ifdetach(ifp); 70431604Syokota cs_release_resources(dev); 70558231Syokota return (0); 70631604Syokota} 70758231Syokota 708122605Sdes/* 70931604Syokota * Initialize the board 710122605Sdes */ 711122605Sdesstatic void 71231604Syokotacs_init(void *xsc) 71331604Syokota{ 71431604Syokota struct cs_softc *sc=(struct cs_softc *)xsc; 715122605Sdes struct ifnet *ifp = &sc->arpcom.ac_if; 716122605Sdes int i, s, rx_cfg; 71731604Syokota 71858344Syokota /* 71958344Syokota * reset whatchdog timer 72058861Syokota */ 72158231Syokota ifp->if_timer=0; 72258231Syokota sc->buf_len = 0; 72358231Syokota 72458231Syokota s=splimp(); 72558231Syokota 72658231Syokota /* 72758231Syokota * Hardware initialization of cs 72858231Syokota */ 72958344Syokota 73058231Syokota /* Enable receiver and transmitter */ 73158231Syokota cs_writereg(sc, PP_LineCTL, 73259090Syokota cs_readreg(sc, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); 73358344Syokota 73431604Syokota /* Configure the receiver mode */ 73518222Speter cs_setmode(sc); 73618222Speter 73731604Syokota /* 73831604Syokota * This defines what type of frames will cause interrupts 739122605Sdes * Bad frames should generate interrupts so that the driver 740122605Sdes * could track statistics of discarded packets 741122605Sdes */ 742122605Sdes rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | 74331604Syokota RX_EXTRA_DATA_ENBL; 74431604Syokota if (sc->isa_config & STREAM_TRANSFER) 74531604Syokota rx_cfg |= RX_STREAM_ENBL; 74618222Speter cs_writereg(sc, PP_RxCFG, rx_cfg); 74731604Syokota cs_writereg(sc, PP_TxCFG, TX_LOST_CRS_ENBL | 74818222Speter TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL | 74918222Speter TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); 75031604Syokota cs_writereg(sc, PP_BufCFG, READY_FOR_TX_ENBL | 75131604Syokota RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL | 75231604Syokota TX_UNDERRUN_ENBL /*| RX_DMA_ENBL*/); 753122605Sdes 754122605Sdes /* Write MAC address into IA filter */ 75531604Syokota for (i=0; i<ETHER_ADDR_LEN/2; i++) 75631604Syokota cs_writereg(sc, PP_IA + i * 2, 75731604Syokota sc->arpcom.ac_enaddr[i * 2] | 758148161Sphilip (sc->arpcom.ac_enaddr[i * 2 + 1] << 8) ); 759148161Sphilip 760148161Sphilip /* 761176855Sjkim * Now enable everything 76234152Sjkh */ 76334152Sjkh/* 76434152Sjkh#ifdef CS_USE_64K_DMA 76534152Sjkh cs_writereg(sc, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K); 766179015Sphilip#else 767179015Sphilip cs_writereg(sc, PP_BusCTL, ENABLE_IRQ); 768179015Sphilip#endif 769179015Sphilip*/ 770179015Sphilip cs_writereg(sc, PP_BusCTL, ENABLE_IRQ); 771179015Sphilip 772179015Sphilip /* 773179015Sphilip * Set running and clear output active flags 77431604Syokota */ 77531604Syokota sc->arpcom.ac_if.if_flags |= IFF_RUNNING; 77631604Syokota sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 77731604Syokota 77831604Syokota /* 77931604Syokota * Start sending process 78031604Syokota */ 78131604Syokota cs_start(ifp); 78218222Speter 78318222Speter (void) splx(s); 78431604Syokota} 785122605Sdes 786122605Sdes/* 78731604Syokota * Get the packet from the board and send it to the upper layer. 78818222Speter */ 78918222Speterstatic int 79018222Spetercs_get_packet(struct cs_softc *sc) 791150310Sphilip{ 792150310Sphilip struct ifnet *ifp = &(sc->arpcom.ac_if); 793150310Sphilip int iobase = sc->nic_addr, status, length; 794150310Sphilip struct ether_header *eh; 795150310Sphilip struct mbuf *m; 796150310Sphilip 797150310Sphilip#ifdef CS_DEBUG 798150310Sphilip int i; 799150310Sphilip#endif 800150310Sphilip 801176854Sjkim status = cs_inw(sc, RX_FRAME_PORT); 802176854Sjkim length = cs_inw(sc, RX_FRAME_PORT); 803176854Sjkim 804176854Sjkim#ifdef CS_DEBUG 805176854Sjkim if_printf(ifp, "rcvd: stat %x, len %d\n", 806176854Sjkim status, length); 807150310Sphilip#endif 808150310Sphilip 80916566Ssos if (!(status & RX_OK)) { 81031949Syokota#ifdef CS_DEBUG 81131949Syokota if_printf(ifp, "bad pkt stat %x\n", status); 81231949Syokota#endif 81331949Syokota ifp->if_ierrors++; 81431949Syokota return -1; 81531949Syokota } 816176855Sjkim 81731949Syokota MGETHDR(m, M_DONTWAIT, MT_DATA); 81816566Ssos if (m==NULL) 81931949Syokota return -1; 82031949Syokota 82116566Ssos if (length > MHLEN) { 82216566Ssos MCLGET(m, M_DONTWAIT); 823176855Sjkim if (!(m->m_flags & M_EXT)) { 824176855Sjkim m_freem(m); 825176855Sjkim return -1; 826176855Sjkim } 827176855Sjkim } 82816566Ssos 829136372Sphilip /* Initialize packet's header info */ 830136372Sphilip m->m_pkthdr.rcvif = ifp; 831136372Sphilip m->m_pkthdr.len = length; 832136372Sphilip m->m_len = length; 833136372Sphilip 834136372Sphilip /* Get the data */ 835136372Sphilip insw(iobase + RX_FRAME_PORT, m->m_data, (length+1)>>1); 836136372Sphilip 837136372Sphilip eh = mtod(m, struct ether_header *); 838136372Sphilip 839136372Sphilip#ifdef CS_DEBUG 84016566Ssos for (i=0;i<length;i++) 84116566Ssos printf(" %02x",(unsigned char)*((char *)(m->m_data+i))); 84216566Ssos printf( "\n" ); 84316566Ssos#endif 84416566Ssos 84516566Ssos if (status & (RX_IA | RX_BROADCAST) || 84659090Syokota (ifp->if_flags & IFF_MULTICAST && status & RX_HASHED)) { 84759090Syokota /* Feed the packet to the upper layer */ 84859090Syokota (*ifp->if_input)(ifp, m); 84959090Syokota ifp->if_ipackets++; 85059090Syokota if (length == ETHER_MAX_LEN-ETHER_CRC_LEN) 85159090Syokota DELAY(cs_recv_delay); 85259090Syokota } else { 85359090Syokota m_freem(m); 85459090Syokota } 85559090Syokota 85659090Syokota return 0; 85731604Syokota} 85831604Syokota 85931604Syokota/* 86031604Syokota * Handle interrupts 861122605Sdes */ 86231604Syokotavoid 863102413Scharniercsintr(void *arg) 86431604Syokota{ 86516566Ssos struct cs_softc *sc = (struct cs_softc*) arg; 86616566Ssos struct ifnet *ifp = &(sc->arpcom.ac_if); 86716566Ssos int status; 86831604Syokota 86931604Syokota#ifdef CS_DEBUG 87016566Ssos if_printf(ifp, "Interrupt.\n"); 87116566Ssos#endif 87216566Ssos 87331604Syokota while ((status=cs_inw(sc, ISQ_PORT))) { 87416566Ssos 87516566Ssos#ifdef CS_DEBUG 87616566Ssos if_printf(ifp, "from ISQ: %04x\n", status); 87729849Scharnier#endif 87816566Ssos 87916566Ssos switch (status & ISQ_EVENT_MASK) { 88016566Ssos case ISQ_RECEIVER_EVENT: 881240891Shselasky cs_get_packet(sc); 882240891Shselasky break; 883122630Sdes 88431604Syokota case ISQ_TRANSMITTER_EVENT: 88531604Syokota if (status & TX_OK) 88631604Syokota ifp->if_opackets++; 88736991Sahasty else 88836991Sahasty ifp->if_oerrors++; 88936991Sahasty ifp->if_flags &= ~IFF_OACTIVE; 890153070Sphilip ifp->if_timer = 0; 891240891Shselasky break; 892240891Shselasky 893122630Sdes case ISQ_BUFFER_EVENT: 894122605Sdes if (status & READY_FOR_TX) { 895122605Sdes ifp->if_flags &= ~IFF_OACTIVE; 896122605Sdes ifp->if_timer = 0; 897122605Sdes } 898122605Sdes 899122605Sdes if (status & TX_UNDERRUN) { 90031604Syokota ifp->if_flags &= ~IFF_OACTIVE; 90131604Syokota ifp->if_timer = 0; 902122605Sdes ifp->if_oerrors++; 90331604Syokota } 904122605Sdes break; 905122605Sdes 906122605Sdes case ISQ_RX_MISS_EVENT: 90731604Syokota ifp->if_ierrors+=(status>>6); 90831604Syokota break; 90931604Syokota 91031604Syokota case ISQ_TX_COL_EVENT: 91131604Syokota ifp->if_collisions+=(status>>6); 91231604Syokota break; 91331604Syokota } 91431604Syokota } 91531604Syokota 91631604Syokota if (!(ifp->if_flags & IFF_OACTIVE)) { 917122605Sdes cs_start(ifp); 91831604Syokota } 91931604Syokota} 92031604Syokota 92131604Syokota/* 92231604Syokota * Save the data in buffer 923122605Sdes */ 924122605Sdes 925122605Sdesstatic void 926218909Sbruceccs_write_mbufs( struct cs_softc *sc, struct mbuf *m ) 927122605Sdes{ 928122605Sdes int len; 92931604Syokota struct mbuf *mp; 930122605Sdes unsigned char *data, *buf; 93131604Syokota 93231604Syokota for (mp=m, buf=sc->buffer, sc->buf_len=0; mp != NULL; mp=mp->m_next) { 933122605Sdes len = mp->m_len; 93431604Syokota 93531604Syokota /* 93631604Syokota * Ignore empty parts 93731604Syokota */ 93831604Syokota if (!len) 93931604Syokota continue; 94031604Syokota 94131604Syokota /* 942240891Shselasky * Find actual data address 943240891Shselasky */ 94416566Ssos data = mtod(mp, caddr_t); 94531604Syokota 94616566Ssos bcopy((caddr_t) data, (caddr_t) buf, len); 94731604Syokota buf += len; 94831604Syokota sc->buf_len += len; 94916566Ssos } 950167461Sphilip} 951170895Sphilip 952170895Sphilip 953170895Sphilipstatic void 954170895Sphilipcs_xmit_buf( struct cs_softc *sc ) 955170895Sphilip{ 956170895Sphilip outsw(sc->nic_addr+TX_FRAME_PORT, sc->buffer, (sc->buf_len+1)>>1); 957170895Sphilip sc->buf_len = 0; 958170895Sphilip} 959170895Sphilip 960170895Sphilipstatic void 961170895Sphilipcs_start(struct ifnet *ifp) 962170895Sphilip{ 963170895Sphilip int s, length; 964170895Sphilip struct mbuf *m, *mp; 965170895Sphilip struct cs_softc *sc = ifp->if_softc; 966170895Sphilip 967170895Sphilip s = splimp(); 968170895Sphilip 969170895Sphilip for (;;) { 970170895Sphilip if (sc->buf_len) 971170895Sphilip length = sc->buf_len; 972170895Sphilip else { 973170895Sphilip IF_DEQUEUE( &ifp->if_snd, m ); 974170895Sphilip 975170895Sphilip if (m==NULL) { 976167461Sphilip (void) splx(s); 977170895Sphilip return; 978167461Sphilip } 979167461Sphilip 980167461Sphilip for (length=0, mp=m; mp != NULL; mp=mp->m_next) 981167461Sphilip length += mp->m_len; 982167461Sphilip 983167461Sphilip /* Skip zero-length packets */ 98431604Syokota if (length == 0) { 985167461Sphilip m_freem(m); 986167461Sphilip continue; 987167461Sphilip } 988167461Sphilip 989167461Sphilip cs_write_mbufs(sc, m); 990167461Sphilip 991167461Sphilip BPF_MTAP(ifp, m); 992167461Sphilip 993167461Sphilip m_freem(m); 994167461Sphilip } 995167461Sphilip 996167461Sphilip /* 997167461Sphilip * Issue a SEND command 998167461Sphilip */ 999167461Sphilip cs_outw(sc, TX_CMD_PORT, sc->send_cmd); 1000170895Sphilip cs_outw(sc, TX_LEN_PORT, length ); 1001170895Sphilip 1002170895Sphilip /* 1003170895Sphilip * If there's no free space in the buffer then leave 1004170895Sphilip * this packet for the next time: indicate output active 1005170895Sphilip * and return. 1006167461Sphilip */ 1007167461Sphilip if (!(cs_readreg(sc, PP_BusST) & READY_FOR_TX_NOW)) { 1008167461Sphilip ifp->if_timer = sc->buf_len; 1009167461Sphilip (void) splx(s); 1010167461Sphilip ifp->if_flags |= IFF_OACTIVE; 1011167461Sphilip return; 101231604Syokota } 101331604Syokota 101431604Syokota cs_xmit_buf(sc); 101558344Syokota 1016228990Suqs /* 101731604Syokota * Set the watchdog timer in case we never hear 101858344Syokota * from board again. (I don't know about correct 101931604Syokota * value for this timeout) 102031604Syokota */ 1021149426Spjd ifp->if_timer = length; 102258344Syokota 102358344Syokota (void) splx(s); 102458344Syokota ifp->if_flags |= IFF_OACTIVE; 102531604Syokota return; 102631604Syokota } 102795629Siedowse} 102831604Syokota 102995629Siedowse/* 1030150214Spjd * Stop everything on the interface 1031149426Spjd */ 1032149426Spjdstatic void 1033149426Spjdcs_stop(struct cs_softc *sc) 1034149426Spjd{ 1035149426Spjd int s = splimp(); 103631604Syokota 1037149426Spjd cs_writereg(sc, PP_RxCFG, 0); 1038149426Spjd cs_writereg(sc, PP_TxCFG, 0); 1039149426Spjd cs_writereg(sc, PP_BufCFG, 0); 104095629Siedowse cs_writereg(sc, PP_BusCTL, 0); 104131604Syokota 104231604Syokota sc->arpcom.ac_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1043149426Spjd sc->arpcom.ac_if.if_timer = 0; 104416566Ssos 104595629Siedowse (void) splx(s); 104616566Ssos} 104731604Syokota 104858344Syokota/* 104931604Syokota * Reset the interface 105031604Syokota */ 105131604Syokotastatic void 105258344Syokotacs_reset(struct cs_softc *sc) 1053176854Sjkim{ 105479430Siedowse cs_stop(sc); 105558344Syokota cs_init(sc); 105658344Syokota} 1057176854Sjkim 105858344Syokotastatic void 1059176855Sjkimcs_setmode(struct cs_softc *sc) 106058344Syokota{ 1061176854Sjkim struct ifnet *ifp = &(sc->arpcom.ac_if); 106258344Syokota int rx_ctl; 106331604Syokota 106431604Syokota /* Stop the receiver while changing filters */ 106531604Syokota cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) & ~SERIAL_RX_ON); 106631604Syokota 106731604Syokota if (ifp->if_flags & IFF_PROMISC) { 106831604Syokota /* Turn on promiscuous mode. */ 106958344Syokota rx_ctl = RX_OK_ACCEPT | RX_PROM_ACCEPT; 107058344Syokota } else { 107131604Syokota if (ifp->if_flags & IFF_MULTICAST) { 107231604Syokota /* Allow receiving frames with multicast addresses */ 107321885Ssos rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | 107431604Syokota RX_OK_ACCEPT | RX_MULTCAST_ACCEPT; 107558344Syokota /* 107658344Syokota * Here the reconfiguration of chip's multicast 107758344Syokota * filters should be done but I've no idea about 107858344Syokota * hash transformation in this chip. If you can 107936991Sahasty * add this code or describe me the transformation 108058344Syokota * I'd be very glad. 1081209214Smav */ 1082209214Smav } else { 108358344Syokota /* 108495629Siedowse * Receive only good frames addressed for us and 108536991Sahasty * good broadcasts. 108658344Syokota */ 108758344Syokota rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | 108858344Syokota RX_OK_ACCEPT; 108958344Syokota } 109058344Syokota } 109158344Syokota 109258344Syokota /* Set up the filter */ 109358344Syokota cs_writereg(sc, PP_RxCTL, RX_DEF_ACCEPT | rx_ctl); 109458344Syokota 109558344Syokota /* Turn on receiver */ 109658344Syokota cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | SERIAL_RX_ON); 109758344Syokota} 109858344Syokota 109958344Syokotastatic int 110058344Syokotacs_ioctl(register struct ifnet *ifp, u_long command, caddr_t data) 110158344Syokota{ 110258344Syokota struct cs_softc *sc=ifp->if_softc; 110358344Syokota struct ifreq *ifr = (struct ifreq *)data; 110458344Syokota int s,error=0; 110558344Syokota 110658344Syokota#ifdef CS_DEBUG 110758344Syokota if_printf(ifp, "ioctl(%lx)\n", command); 110858344Syokota#endif 110958344Syokota 111058344Syokota s=splimp(); 111158344Syokota 111258344Syokota switch (command) { 111358344Syokota case SIOCSIFFLAGS: 111458344Syokota /* 111558344Syokota * Switch interface state between "running" and 111658344Syokota * "stopped", reflecting the UP flag. 111758344Syokota */ 1118136372Sphilip if (sc->arpcom.ac_if.if_flags & IFF_UP) { 1119148161Sphilip if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)==0) { 1120136372Sphilip cs_init(sc); 1121136372Sphilip } 1122136372Sphilip } else { 1123136372Sphilip if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)!=0) { 1124179015Sphilip cs_stop(sc); 1125136372Sphilip } 1126136372Sphilip } 1127136372Sphilip /* 1128136372Sphilip * Promiscuous and/or multicast flags may have changed, 1129136372Sphilip * so reprogram the multicast filter and/or receive mode. 1130136372Sphilip * 1131136372Sphilip * See note about multicasts in cs_setmode 1132136372Sphilip */ 1133136372Sphilip cs_setmode(sc); 1134176855Sjkim break; 1135176855Sjkim 1136136372Sphilip case SIOCADDMULTI: 1137136372Sphilip case SIOCDELMULTI: 1138136372Sphilip /* 1139136372Sphilip * Multicast list has changed; set the hardware filter 1140136372Sphilip * accordingly. 1141136372Sphilip * 1142136372Sphilip * See note about multicasts in cs_setmode 1143136372Sphilip */ 1144136372Sphilip cs_setmode(sc); 1145136372Sphilip error = 0; 1146136372Sphilip break; 1147136372Sphilip 1148136372Sphilip case SIOCSIFMEDIA: 1149136372Sphilip case SIOCGIFMEDIA: 1150136372Sphilip error = ifmedia_ioctl(ifp, ifr, &sc->media, command); 1151136372Sphilip break; 1152136372Sphilip 1153136372Sphilip default: 1154136372Sphilip error = ether_ioctl(ifp, command, data); 1155136372Sphilip break; 1156136372Sphilip } 1157136372Sphilip 1158136372Sphilip (void) splx(s); 1159176855Sjkim return error; 1160136372Sphilip} 1161136372Sphilip 1162136372Sphilip/* 116358344Syokota * Device timeout/watchdog routine. Entered if the device neglects to 1164122605Sdes * generate an interrupt after a transmit has been started on it. 1165122605Sdes */ 1166122605Sdesstatic void 116758344Syokotacs_watchdog(struct ifnet *ifp) 116858344Syokota{ 116936991Sahasty struct cs_softc *sc = ifp->if_softc; 117058344Syokota 117158344Syokota ifp->if_oerrors++; 117258344Syokota log(LOG_ERR, "%s: device timeout\n", ifp->if_xname); 117358344Syokota 117436991Sahasty /* Reset the interface */ 117558344Syokota if (ifp->if_flags & IFF_UP) 117631604Syokota cs_reset(sc); 117731604Syokota else 117831604Syokota cs_stop(sc); 117931604Syokota} 1180148161Sphilip 1181176855Sjkimstatic int 1182136372Sphilipcs_mediachange(struct ifnet *ifp) 1183136372Sphilip{ 1184136372Sphilip struct cs_softc *sc = ifp->if_softc; 1185136372Sphilip struct ifmedia *ifm = &sc->media; 1186179015Sphilip 1187179015Sphilip if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1188179015Sphilip return EINVAL; 1189179015Sphilip 1190179015Sphilip return cs_mediaset(sc, ifm->ifm_media); 1191179015Sphilip} 1192179015Sphilip 1193179015Sphilipstatic void 1194179015Sphilipcs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1195179015Sphilip{ 1196179015Sphilip int line_status; 1197179015Sphilip struct cs_softc *sc = ifp->if_softc; 1198179015Sphilip 1199179015Sphilip ifmr->ifm_active = IFM_ETHER; 1200179015Sphilip line_status = cs_readreg(sc, PP_LineST); 1201179015Sphilip if (line_status & TENBASET_ON) { 1202179015Sphilip ifmr->ifm_active |= IFM_10_T; 1203179015Sphilip if (sc->chip_type != CS8900) { 1204179015Sphilip if (cs_readreg(sc, PP_AutoNegST) & FDX_ACTIVE) 1205179015Sphilip ifmr->ifm_active |= IFM_FDX; 1206179015Sphilip if (cs_readreg(sc, PP_AutoNegST) & HDX_ACTIVE) 1207148161Sphilip ifmr->ifm_active |= IFM_HDX; 1208148161Sphilip } 1209148161Sphilip ifmr->ifm_status = IFM_AVALID; 1210179015Sphilip if (line_status & LINK_OK) 1211148161Sphilip ifmr->ifm_status |= IFM_ACTIVE; 1212148161Sphilip } else { 1213148161Sphilip if (line_status & AUI_ON) { 1214148161Sphilip cs_writereg(sc, PP_SelfCTL, cs_readreg(sc, PP_SelfCTL) | 1215179015Sphilip HCB1_ENBL); 1216148161Sphilip if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^ 1217148161Sphilip (cs_readreg(sc, PP_SelfCTL) & HCB1)) 1218148161Sphilip ifmr->ifm_active |= IFM_10_2; 1219148161Sphilip else 1220148161Sphilip ifmr->ifm_active |= IFM_10_5; 1221148161Sphilip } 1222148161Sphilip } 1223148161Sphilip} 1224136372Sphilip 1225179015Sphilipstatic int 1226148161Sphilipcs_mediaset(struct cs_softc *sc, int media) 1227148161Sphilip{ 1228148161Sphilip int error; 1229179015Sphilip 1230148161Sphilip /* Stop the receiver & transmitter */ 1231148161Sphilip cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) & 1232148161Sphilip ~(SERIAL_RX_ON | SERIAL_TX_ON)); 1233148161Sphilip 1234148161Sphilip#ifdef CS_DEBUG 1235136372Sphilip if_printf(&sc->arpcom.ac_if, "cs_setmedia(%x)\n", media); 1236136372Sphilip#endif 1237136372Sphilip 1238136372Sphilip switch (IFM_SUBTYPE(media)) { 1239136372Sphilip default: 1240150310Sphilip case IFM_AUTO: 1241176855Sjkim if ((error=enable_tp(sc))==0) 1242176854Sjkim error = cs_duplex_auto(sc); 1243150310Sphilip else if ((error=enable_bnc(sc)) != 0) 1244150310Sphilip error = enable_aui(sc); 1245176854Sjkim break; 1246176854Sjkim case IFM_10_T: 1247176854Sjkim if ((error=enable_tp(sc)) != 0) 1248176854Sjkim break; 1249150310Sphilip if (media & IFM_FDX) 1250150310Sphilip cs_duplex_full(sc); 1251150310Sphilip else if (media & IFM_HDX) 1252150310Sphilip cs_duplex_half(sc); 1253176854Sjkim else 1254150310Sphilip error = cs_duplex_auto(sc); 1255150310Sphilip break; 1256150310Sphilip case IFM_10_2: 1257150310Sphilip error = enable_bnc(sc); 1258150310Sphilip break; 1259176854Sjkim case IFM_10_5: 1260150310Sphilip error = enable_aui(sc); 1261150310Sphilip break; 1262150310Sphilip } 1263150310Sphilip 1264150310Sphilip /* 1265150310Sphilip * Turn the transmitter & receiver back on 1266150310Sphilip */ 1267176854Sjkim cs_writereg(sc, PP_LineCTL, cs_readreg(sc, PP_LineCTL) | 1268150310Sphilip SERIAL_RX_ON | SERIAL_TX_ON); 1269150310Sphilip 1270176854Sjkim return error; 1271150310Sphilip} 1272150310Sphilip