if_cs.c revision 38305
185587Sobrien/* 285587Sobrien * Copyright (c) 1997,1998 Maxim Bolotin and Oleg Sharoiko. 385587Sobrien * All rights reserved. 485587Sobrien * 585587Sobrien * Redistribution and use in source and binary forms, with or without 685587Sobrien * modification, are permitted provided that the following conditions 785587Sobrien * are met: 885587Sobrien * 1. Redistributions of source code must retain the above copyright 985587Sobrien * notice unmodified, this list of conditions, and the following 1085587Sobrien * disclaimer. 1185587Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1285587Sobrien * notice, this list of conditions and the following disclaimer in the 1385587Sobrien * documentation and/or other materials provided with the distribution. 1485587Sobrien * 1585587Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1685587Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1785587Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1885587Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1985587Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2085587Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2185587Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2285587Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2385587Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2485587Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2585587Sobrien * SUCH DAMAGE. 2685587Sobrien * 2785587Sobrien */ 28125601Sru 29125601Sru/* 30125601Sru * $Id: if_cs.c,v 1.2 1998/08/12 18:02:48 bde Exp $ 31125601Sru * 32125601Sru * Device driver for Crystal Semiconductor CS8920 based ethernet 33125601Sru * adapters. By Maxim Bolotin and Oleg Sharoiko, 27-April-1997 34125601Sru */ 35125601Sru 36125601Sru/* #define CS_DEBUG */ 37125601Sru#include "cs.h" 38125601Sru#include "bpfilter.h" 39125601Sru 40125601Sru#include <sys/param.h> 41125601Sru#include <sys/systm.h> 42125601Sru#include <sys/malloc.h> 43125601Sru#include <sys/sockio.h> 44125601Sru#include <sys/kernel.h> 45125601Sru#include <sys/mbuf.h> 46118194Sru#include <sys/socket.h> 47118194Sru#include <sys/syslog.h> 48118194Sru 49118194Sru#include <net/if.h> 50118194Sru#include <net/if_arp.h> 51118194Sru#include <net/if_media.h> 52118194Sru#include <net/ethernet.h> 53118194Sru 54118194Sru#if NBPFILTER > 0 55118194Sru#include <net/bpf.h> 56118194Sru#endif 57118194Sru 58118194Sru#include <machine/clock.h> 59118194Sru 60118194Sru#include <i386/isa/isa_device.h> 61118194Sru#include <i386/isa/if_csreg.h> 62118194Sru 63118194Sru#include "pnp.h" 64118194Sru 65118194Sru#if NPNP > 0 66118194Sru#include <i386/isa/pnp.h> 67118194Sru#endif 68118194Sru 69118194Sru#ifdef CS_USE_64K_DMA 70118194Sru#define CS_DMA_BUFFER_SIZE 65536 71118194Sru#else 72118194Sru#define CS_DMA_BUFFER_SIZE 16384 73118194Sru#endif 74118194Sru 75118194Sru#ifndef CS_WAIT_NEXT_PACKET 76118194Sru#define CS_WAIT_NEXT_PACKET 570 77118194Sru#endif 78118194Sru 79118194Sru/* 80118194Sru * cs_softc: per line info and status 81118194Sru */ 82118194Srustatic struct cs_softc { 83118194Sru 84118194Sru /* Ethernet common code */ 85118194Sru struct arpcom arpcom; 86118194Sru 87118194Sru /* Configuration words from EEPROM */ 88118194Sru int auto_neg_cnf; /* AutoNegotitation configuration */ 89118194Sru int adapter_cnf; /* Adapter configuration */ 90118194Sru int isa_config; /* ISA configuration */ 91118194Sru int chip_type; /* Type of chip */ 92112336Sobrien 93112336Sobrien struct ifmedia media; /* Media information */ 94112336Sobrien 95112336Sobrien int nic_addr; /* Base IO address of card */ 96112336Sobrien int send_cmd; 97112336Sobrien int line_ctl; /* */ 98112336Sobrien int send_underrun; 99112336Sobrien void *recv_ring; 100112336Sobrien 101112336Sobrien unsigned char *buffer; 102112336Sobrien int buf_len; 103112336Sobrien 104112336Sobrien} cs_softc[NCS]; 105112336Sobrien 106112336Sobrienstatic u_long cs_unit = NCS; 107108072Sobrien 108108072Sobrienstatic int cs_attach __P((struct cs_softc *, int, int)); 109108072Sobrienstatic int cs_attach_isa __P((struct isa_device *)); 110108072Sobrienstatic void cs_init __P((void *)); 111108072Sobrienstatic int cs_ioctl __P((struct ifnet *, u_long, caddr_t)); 112108072Sobrienstatic int cs_probe __P((struct isa_device *)); 113107806Sobrienstatic int cs_cs89x0_probe __P((struct cs_softc *, 114107806Sobrien u_int *, int *, int, int, int)); 115107806Sobrienstatic void cs_start __P((struct ifnet *)); 116107806Sobrienstatic void cs_stop __P((struct cs_softc *)); 117107806Sobrienstatic void cs_reset __P((struct cs_softc *)); 118107806Sobrienstatic void cs_watchdog __P((struct ifnet *)); 119107806Sobrien 120107806Sobrienstatic int cs_mediachange __P((struct ifnet *)); 121107806Sobrienstatic void cs_mediastatus __P((struct ifnet *, struct ifmediareq *)); 122107806Sobrienstatic int cs_mediaset __P((struct cs_softc *, int)); 123107806Sobrien 124107806Sobrienstatic void cs_write_mbufs(struct cs_softc*, struct mbuf*); 125107806Sobrienstatic void cs_xmit_buf(struct cs_softc*); 126107806Sobrienstatic int cs_get_packet(struct cs_softc*); 127107806Sobrienstatic void cs_setmode(struct cs_softc*); 128107806Sobrien 129107806Sobrienstatic int get_eeprom_data(struct cs_softc *sc, int, int, int *); 130107806Sobrienstatic int get_eeprom_cksum(int, int, int *); 131107806Sobrienstatic int wait_eeprom_ready( struct cs_softc *); 132107806Sobrienstatic void control_dc_dc( struct cs_softc *, int ); 133107806Sobrienstatic int send_test_pkt( struct cs_softc * ); 134107806Sobrienstatic int enable_tp(struct cs_softc *); 135107806Sobrienstatic int enable_aui(struct cs_softc *); 136107806Sobrienstatic int enable_bnc(struct cs_softc *); 137107806Sobrienstatic int cs_duplex_auto(struct cs_softc *); 138107806Sobrien 139107806Sobrienstruct isa_driver csdriver = { 140107806Sobrien cs_probe, 141107806Sobrien cs_attach_isa, 142107806Sobrien CS_NAME, 143107806Sobrien 0 144107806Sobrien}; 145107806Sobrien 146107806Sobrienstatic int 147107806Sobrienget_eeprom_data( struct cs_softc *sc, int off, int len, int *buffer) 148107806Sobrien{ 149107806Sobrien int i; 15090902Sdes 15190902Sdes#ifdef CS_DEBUG 15290902Sdes printf(CS_NAME":EEPROM data from %x for %x:\n", off,len); 15390902Sdes#endif 15490902Sdes 15590902Sdes for (i=0;i<len;i++) { 15690902Sdes if (wait_eeprom_ready(sc) < 0) return -1; 15790902Sdes /* Send command to EEPROM to read */ 15890902Sdes cs_writereg(sc->nic_addr, PP_EECMD, (off+i)|EEPROM_READ_CMD ); 15990902Sdes if (wait_eeprom_ready(sc)<0) 16090902Sdes return -1; 16190902Sdes buffer[i] = cs_readreg (sc->nic_addr, PP_EEData); 16290902Sdes 16390902Sdes#ifdef CS_DEBUG 16490902Sdes printf("%02x %02x ",(unsigned char)buffer[i], 16590902Sdes (unsigned char)buffer[i+1]); 16690902Sdes#endif 16790902Sdes } 16890902Sdes 16990902Sdes#ifdef CS_DEBUG 17090902Sdes printf("\n"); 17190902Sdes#endif 17290902Sdes 17390902Sdes return 0; 17490902Sdes} 17590902Sdes 17690902Sdesstatic int 17790902Sdesget_eeprom_cksum(int off, int len, int *buffer) 17890902Sdes{ 17990902Sdes int i,cksum=0; 18090902Sdes 18190902Sdes for (i=0;i<len;i++) 18285587Sobrien cksum+=buffer[i]; 18385587Sobrien cksum &= 0xffff; 18485587Sobrien if (cksum==0) 18585587Sobrien return 0; 18685587Sobrien return -1; 18785587Sobrien} 18885587Sobrien 18985587Sobrienstatic int 19085587Sobrienwait_eeprom_ready(struct cs_softc *sc) 19185587Sobrien{ 19285587Sobrien int timeout=1000; 19385587Sobrien DELAY ( 30000 ); /* XXX should we do some checks here ? */ 19485587Sobrien return 0; 19585587Sobrien} 19685587Sobrien 19785587Sobrienstatic void 19885587Sobriencontrol_dc_dc(struct cs_softc *sc, int on_not_off) 19985587Sobrien{ 20085587Sobrien unsigned int self_control = HCB1_ENBL; 20185587Sobrien 20285587Sobrien if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0) ^ on_not_off) 20385587Sobrien self_control |= HCB1; 20485587Sobrien else 20585587Sobrien self_control &= ~HCB1; 20685587Sobrien cs_writereg( sc->nic_addr, PP_SelfCTL, self_control ); 20785587Sobrien 20885587Sobrien DELAY( 500000 ); 20985587Sobrien} 21085587Sobrien 21185587Sobrien 21285587Sobrienstatic int 21385587Sobriencs_duplex_auto(struct cs_softc *sc) 21485587Sobrien{ 21585587Sobrien int i, error=0, unit=sc->arpcom.ac_if.if_unit; 21685587Sobrien 21785587Sobrien cs_writereg(sc->nic_addr, PP_AutoNegCTL, 21885587Sobrien RE_NEG_NOW | ALLOW_FDX | AUTO_NEG_ENABLE ); 21985587Sobrien for (i=0; cs_readreg(sc->nic_addr,PP_AutoNegST)&AUTO_NEG_BUSY; i++) { 22085587Sobrien if (i > 40000) { 22185587Sobrien printf(CS_NAME"%1d: full/half duplex " 22285587Sobrien "auto negotiation timeout\n", unit); 22385587Sobrien error = ETIMEDOUT; 22485587Sobrien break; 22585587Sobrien } 22685587Sobrien DELAY(1000); 22785587Sobrien } 22885587Sobrien DELAY( 1000000 ); 22985587Sobrien return error; 23085587Sobrien} 23185587Sobrien 23285587Sobrienstatic int 23385587Sobrienenable_tp(struct cs_softc *sc) 23485587Sobrien{ 23585587Sobrien int i; 23685587Sobrien int unit = sc->arpcom.ac_if.if_unit; 23785587Sobrien 23885587Sobrien cs_writereg(sc->nic_addr, PP_LineCTL, sc->line_ctl & ~AUI_ONLY); 23985587Sobrien control_dc_dc(sc, 0); 24085587Sobrien DELAY( 150000 ); 24185587Sobrien 24285587Sobrien if ((cs_readreg(sc->nic_addr, PP_LineST) & LINK_OK)==0) { 24385587Sobrien printf(CS_NAME"%1d: failed to enable TP\n", unit); 24485587Sobrien return EINVAL; 24585587Sobrien } 24685587Sobrien 24785587Sobrien return 0; 24885587Sobrien} 24985587Sobrien 25085587Sobrien/* 25185587Sobrien * XXX This was rewritten from Linux driver without any tests. 25285587Sobrien */ 25385587Sobrienstatic int 25485587Sobriensend_test_pkt(struct cs_softc *sc) 25585587Sobrien{ 25685587Sobrien int unit = sc->arpcom.ac_if.if_unit; 25785587Sobrien char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, 25885587Sobrien 0, 46, /* A 46 in network order */ 25985587Sobrien 0, 0, /* DSAP=0 & SSAP=0 fields */ 26085587Sobrien 0xf3, 0 /* Control (Test Req + P bit set) */ }; 26185587Sobrien int i; 26285587Sobrien u_char ether_address_backup[ETHER_ADDR_LEN]; 26385587Sobrien 26485587Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 26585587Sobrien ether_address_backup[i] = sc->arpcom.ac_enaddr[i]; 26685587Sobrien } 26785587Sobrien 26885587Sobrien cs_writereg(sc->nic_addr, PP_LineCTL, 26985587Sobrien cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_TX_ON ); 27085587Sobrien bcopy(test_packet, 27185587Sobrien sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 27285587Sobrien bcopy(test_packet+ETHER_ADDR_LEN, 27385587Sobrien sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 27485587Sobrien outw(sc->nic_addr + TX_CMD_PORT, sc->send_cmd); 27585587Sobrien outw(sc->nic_addr + TX_LEN_PORT, sizeof(test_packet)); 27685587Sobrien 27785587Sobrien /* Wait for chip to allocate memory */ 27885587Sobrien DELAY(50000); 27985587Sobrien if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) { 28085587Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 28185587Sobrien sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; 28285587Sobrien } 28385587Sobrien return 0; 28485587Sobrien } 28585587Sobrien 28685587Sobrien outsw(sc->nic_addr + TX_FRAME_PORT, test_packet, sizeof(test_packet)); 28785587Sobrien 28885587Sobrien DELAY(30000); 28985587Sobrien 29085587Sobrien if ((cs_readreg(sc->nic_addr,PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) { 29185587Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 29285587Sobrien sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; 29385587Sobrien } 29485587Sobrien return 1; 29585587Sobrien } 29685587Sobrien for (i = 0; i < ETHER_ADDR_LEN; i++) { 29785587Sobrien sc->arpcom.ac_enaddr[i] = ether_address_backup[i]; 29885587Sobrien } 29985587Sobrien return 0; 30085587Sobrien} 30185587Sobrien 30285587Sobrien/* 30385587Sobrien * XXX This was rewritten from Linux driver without any tests. 30485587Sobrien */ 30585587Sobrienstatic int 30685587Sobrienenable_aui(struct cs_softc *sc) 30785587Sobrien{ 30885587Sobrien int unit = sc->arpcom.ac_if.if_unit; 30985587Sobrien 31085587Sobrien control_dc_dc(sc, 0); 31185587Sobrien cs_writereg(sc->nic_addr, PP_LineCTL, 31285587Sobrien (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); 31385587Sobrien 31485587Sobrien if (!send_test_pkt(sc)) { 31585587Sobrien printf(CS_NAME"%1d failed to enable AUI\n", unit); 31685587Sobrien return EINVAL; 31785587Sobrien } 31885587Sobrien return 0; 31985587Sobrien} 32085587Sobrien 32185587Sobrien/* 32285587Sobrien * XXX This was rewritten from Linux driver without any tests. 32385587Sobrien */ 32485587Sobrienstatic int 32585587Sobrienenable_bnc(struct cs_softc *sc) 32685587Sobrien{ 32785587Sobrien int unit = sc->arpcom.ac_if.if_unit; 32885587Sobrien 32985587Sobrien control_dc_dc(sc, 1); 33085587Sobrien cs_writereg(sc->nic_addr, PP_LineCTL, 33185587Sobrien (sc->line_ctl & ~AUTO_AUI_10BASET) | AUI_ONLY); 33285587Sobrien 33385587Sobrien if (!send_test_pkt(sc)) { 33485587Sobrien printf(CS_NAME"%1d failed to enable BNC\n", unit); 33585587Sobrien return EINVAL; 33685587Sobrien } 33785587Sobrien return 0; 33885587Sobrien} 33985587Sobrien 34085587Sobrienstatic int 34185587Sobriencs_cs89x0_probe(struct cs_softc *sc, u_int *dev_irq, 34285587Sobrien int *dev_drq, int iobase, int unit, int flags) 34385587Sobrien{ 34485587Sobrien unsigned rev_type = 0; 34585587Sobrien int i, irq=0, result; 34685587Sobrien int eeprom_buff[CHKSUM_LEN]; 34785587Sobrien int chip_type, pp_isaint, pp_isadma; 34885587Sobrien char chip_revision; 34985587Sobrien 35085587Sobrien if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG) { 35185587Sobrien /* Chip not detected. Let's try to reset it */ 35285587Sobrien if (bootverbose) 35385587Sobrien printf(CS_NAME"%1d: trying to reset the chip.\n", unit); 35485587Sobrien outw(iobase+ADD_PORT, PP_SelfCTL); 35585587Sobrien i = inw(iobase+DATA_PORT); 35685587Sobrien outw(iobase+ADD_PORT, PP_SelfCTL); 35785587Sobrien outw(iobase+DATA_PORT, i | POWER_ON_RESET); 35885587Sobrien if ((inw(iobase+ADD_PORT) & ADD_MASK) != ADD_SIG) 35985587Sobrien return 0; 36085587Sobrien } 36185587Sobrien 36285587Sobrien outw(iobase+ADD_PORT, PP_ChipID); 36385587Sobrien if (inw(iobase+DATA_PORT) != CHIP_EISA_ID_SIG) 36485587Sobrien return 0; 36585587Sobrien 36685587Sobrien rev_type = cs_readreg(iobase, PRODUCT_ID_ADD); 36785587Sobrien chip_type = rev_type & ~REVISON_BITS; 36885587Sobrien chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; 36985587Sobrien 37085587Sobrien sc->nic_addr = iobase; 37185587Sobrien sc->chip_type = chip_type; 37285587Sobrien if(chip_type==CS8900) { 37385587Sobrien pp_isaint = PP_CS8900_ISAINT; 37485587Sobrien pp_isadma = PP_CS8900_ISADMA; 37585587Sobrien sc->send_cmd = TX_CS8900_AFTER_ALL; 37685587Sobrien } else { 37785587Sobrien pp_isaint = PP_CS8920_ISAINT; 37885587Sobrien pp_isadma = PP_CS8920_ISADMA; 37985587Sobrien sc->send_cmd = TX_CS8920_AFTER_ALL; 38085587Sobrien } 38185587Sobrien 38285587Sobrien /* 38385587Sobrien * Clear some fields so that fail of EEPROM will left them clean 38485587Sobrien */ 38585587Sobrien sc->auto_neg_cnf = 0; 38685587Sobrien sc->adapter_cnf = 0; 38785587Sobrien sc->isa_config = 0; 38885587Sobrien 38985587Sobrien /* 39085587Sobrien * EEPROM 39185587Sobrien */ 39285587Sobrien if((cs_readreg(iobase, PP_SelfST) & EEPROM_PRESENT) == 0) { 39385587Sobrien printf(CS_NAME"%1d: No EEPROM, assuming defaults.\n", 39485587Sobrien unit); 39585587Sobrien } else { 39685587Sobrien if (get_eeprom_data(sc,START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) { 39785587Sobrien printf(CS_NAME"%1d: EEPROM read failed, " 39885587Sobrien "assuming defaults..\n", unit); 39985587Sobrien } else { 40085587Sobrien if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN, eeprom_buff)<0) { 40185587Sobrien printf( CS_NAME"%1d: EEPROM cheksum bad, " 40285587Sobrien "assuming defaults..\n", unit ); 40385587Sobrien } else { 40485587Sobrien sc->auto_neg_cnf = 40585587Sobrien eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; 40685587Sobrien sc->adapter_cnf = 40785587Sobrien eeprom_buff[ADAPTER_CNF_OFFSET/2]; 40885587Sobrien sc->isa_config = 40985587Sobrien eeprom_buff[ISA_CNF_OFFSET/2]; 41085587Sobrien 41185587Sobrien for (i=0; i<ETHER_ADDR_LEN/2; i++) { 41285587Sobrien sc->arpcom.ac_enaddr[i*2]= 41385587Sobrien eeprom_buff[i]; 41485587Sobrien sc->arpcom.ac_enaddr[i*2+1]= 41585587Sobrien eeprom_buff[i] >> 8; 41685587Sobrien } 41785587Sobrien 41885587Sobrien /* 41985587Sobrien * If no interrupt specified (or "?"), 42085587Sobrien * use what the board tells us. 42185587Sobrien */ 42285587Sobrien if (*dev_irq <= 0) { 42385587Sobrien irq = sc->isa_config & INT_NO_MASK; 42485587Sobrien if (chip_type==CS8900) { 42585587Sobrien switch(irq) { 42685587Sobrien case 0: irq=10; break; 42785587Sobrien case 1: irq=11; break; 42885587Sobrien case 2: irq=12; break; 42985587Sobrien case 3: irq=5; break; 43085587Sobrien default: printf(CS_NAME"%1d: invalid irq in EEPROM.\n",unit); 43185587Sobrien } 43285587Sobrien if (irq!=0) 43385587Sobrien *dev_irq=(u_short)(1<<irq); 43485587Sobrien } else { 43585587Sobrien if (irq!=0 && irq<=CS8920_NO_INTS) 43685587Sobrien *dev_irq=(u_short)(1<<irq); 43785587Sobrien } 43885587Sobrien } 43985587Sobrien } 44085587Sobrien } 44185587Sobrien } 44285587Sobrien 44385587Sobrien if ((irq=ffs(*dev_irq))) { 44485587Sobrien irq--; 44585587Sobrien if (chip_type == CS8900) { 44685587Sobrien switch(irq) { 44785587Sobrien case 5: irq = 3; break; 44885587Sobrien case 10: irq = 0; break; 44985587Sobrien case 11: irq = 1; break; 45085587Sobrien case 12: irq = 2; break; 45185587Sobrien default: printf(CS_NAME"%1d: invalid irq\n", unit); 45285587Sobrien return 0; 45385587Sobrien } 45485587Sobrien } else { 45585587Sobrien if (irq > CS8920_NO_INTS) { 45685587Sobrien printf(CS_NAME"%1d: invalid irq\n", unit); 45785587Sobrien return 0; 45885587Sobrien } 45985587Sobrien } 46085587Sobrien cs_writereg(iobase, pp_isaint, irq); 46185587Sobrien } else { 46285587Sobrien printf(CS_NAME"%1d: invalid irq\n", unit); 46385587Sobrien return 0; 46485587Sobrien } 46585587Sobrien 46685587Sobrien /* 46785587Sobrien * Temporary disabled 46885587Sobrien * 46985587Sobrien if (drq>0) 47085587Sobrien cs_writereg(iobase, pp_isadma, drq); 47185587Sobrien else { 47285587Sobrien printf( CS_NAME"%1d: incorrect drq\n", unit ); 47385587Sobrien return 0; 47485587Sobrien } 47585587Sobrien */ 47685587Sobrien 47785587Sobrien if (bootverbose) 47885587Sobrien printf(CS_NAME"%1d: model CS89%c0%s rev %c\n" 47985587Sobrien CS_NAME"%1d: media%s%s%s\n" 48085587Sobrien CS_NAME"%1d: irq %d drq %d\n", 48185587Sobrien unit, 48285587Sobrien chip_type==CS8900 ? '0' : '2', 48385587Sobrien chip_type==CS8920M ? "M" : "", 48485587Sobrien chip_revision, 48585587Sobrien unit, 48685587Sobrien (sc->adapter_cnf & A_CNF_10B_T) ? " TP" : "", 48785587Sobrien (sc->adapter_cnf & A_CNF_AUI) ? " AUI" : "", 48885587Sobrien (sc->adapter_cnf & A_CNF_10B_2) ? " BNC" : "", 48985587Sobrien unit, (int)*dev_irq, (int)*dev_drq); 49085587Sobrien 49185587Sobrien if ((sc->adapter_cnf & A_CNF_EXTND_10B_2) && 49285587Sobrien (sc->adapter_cnf & A_CNF_LOW_RX_SQUELCH)) 49385587Sobrien sc->line_ctl = LOW_RX_SQUELCH; 49485587Sobrien else 49585587Sobrien sc->line_ctl = 0; 49685587Sobrien 49785587Sobrien 49885587Sobrien return PP_ISAIOB; 49985587Sobrien} 50085587Sobrien 50185587Sobrien/* 50285587Sobrien * Determine if the device is present 50385587Sobrien * 50485587Sobrien * on entry: 50585587Sobrien * a pointer to an isa_device struct 50685587Sobrien * on exit: 50785587Sobrien * NULL if device not found 50885587Sobrien * or # of i/o addresses used (if found) 50985587Sobrien */ 51085587Sobrienstatic int 51185587Sobriencs_probe(struct isa_device *dev) 51285587Sobrien{ 51385587Sobrien int nports; 51485587Sobrien 51585587Sobrien struct cs_softc *sc=&cs_softc[dev->id_unit]; 51685587Sobrien 51785587Sobrien nports=cs_cs89x0_probe(sc, &(dev->id_irq), &(dev->id_drq), 51885587Sobrien (dev->id_iobase), (dev->id_unit), (dev->id_flags)); 51985587Sobrien 52085587Sobrien if (nports) 52185587Sobrien return (nports); 52285587Sobrien 52385587Sobrien return (0); 52485587Sobrien} 52585587Sobrien 52685587Sobrien/* 52785587Sobrien * Install the interface into kernel networking data structures 52885587Sobrien */ 52985587Sobrienstatic int 53085587Sobriencs_attach(struct cs_softc *sc, int unit, int flags) 53185587Sobrien{ 53285587Sobrien int media=0; 53385587Sobrien/* struct cs_softc *sc = &cs_softc[dev->id_unit]; */ 53485587Sobrien struct ifnet *ifp = &(sc->arpcom.ac_if); 53585587Sobrien 53685587Sobrien if (!ifp->if_name) { 53785587Sobrien ifp->if_softc=sc; 53885587Sobrien ifp->if_unit=unit; 53985587Sobrien ifp->if_name=csdriver.name; 54085587Sobrien ifp->if_output=ether_output; 54185587Sobrien ifp->if_start=cs_start; 54285587Sobrien ifp->if_ioctl=cs_ioctl; 54385587Sobrien ifp->if_watchdog=cs_watchdog; 54485587Sobrien ifp->if_init=cs_init; 54585587Sobrien ifp->if_snd.ifq_maxlen= IFQ_MAXLEN; 54685587Sobrien /* 54785587Sobrien * MIB DATA 54885587Sobrien */ 54985587Sobrien /* 55085587Sobrien ifp->if_linkmib=&sc->mibdata; 55185587Sobrien ifp->if_linkmiblen=sizeof sc->mibdata; 55285587Sobrien */ 55385587Sobrien 55485587Sobrien ifp->if_flags=(IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST ); 55585587Sobrien 55685587Sobrien /* 55785587Sobrien * this code still in progress (DMA support) 55885587Sobrien * 55985587Sobrien 56085587Sobrien sc->recv_ring=malloc(CS_DMA_BUFFER_SIZE<<1, M_DEVBUF, M_NOWAIT); 56185587Sobrien if (sc->recv_ring == NULL) { 56285587Sobrien log(LOG_ERR,CS_NAME 56385587Sobrien "%d: Couldn't allocate memory for NIC\n", unit); 56485587Sobrien return(0); 56585587Sobrien } 56685587Sobrien if ((sc->recv_ring-(sc->recv_ring & 0x1FFFF)) 56785587Sobrien < (128*1024-CS_DMA_BUFFER_SIZE)) 56885587Sobrien sc->recv_ring+=16*1024; 56985587Sobrien 57085587Sobrien */ 57185587Sobrien 57285587Sobrien sc->buffer=malloc(ETHER_MAX_LEN-ETHER_CRC_LEN,M_DEVBUF,M_NOWAIT); 57385587Sobrien if (sc->buffer == NULL) { 57485587Sobrien printf(CS_NAME"%d: Couldn't allocate memory for NIC\n", 57585587Sobrien unit); 57685587Sobrien return(0); 57785587Sobrien } 57885587Sobrien 57985587Sobrien /* 58085587Sobrien * Initialize the media structures. 58185587Sobrien */ 58285587Sobrien ifmedia_init(&sc->media, 0, cs_mediachange, cs_mediastatus); 58385587Sobrien 58485587Sobrien if (sc->adapter_cnf & A_CNF_10B_T) { 58585587Sobrien ifmedia_add(&sc->media, IFM_ETHER|IFM_10_T, 0, NULL); 58685587Sobrien if (sc->chip_type != CS8900) { 58785587Sobrien ifmedia_add(&sc->media, 58885587Sobrien IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 58985587Sobrien ifmedia_add(&sc->media, 59085587Sobrien IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 59185587Sobrien } 59285587Sobrien } 59385587Sobrien 59485587Sobrien if (sc->adapter_cnf & A_CNF_10B_2) 59585587Sobrien ifmedia_add(&sc->media, IFM_ETHER|IFM_10_2, 0, NULL); 59685587Sobrien 59785587Sobrien if (sc->adapter_cnf & A_CNF_AUI) 59885587Sobrien ifmedia_add(&sc->media, IFM_ETHER|IFM_10_5, 0, NULL); 59985587Sobrien 60085587Sobrien if (sc->adapter_cnf & A_CNF_MEDIA) 60185587Sobrien ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL); 60285587Sobrien 60385587Sobrien /* Set default media from EEPROM */ 60485587Sobrien switch (sc->adapter_cnf & A_CNF_MEDIA_TYPE) { 60585587Sobrien case A_CNF_MEDIA_AUTO: media = IFM_ETHER|IFM_AUTO; break; 60685587Sobrien case A_CNF_MEDIA_10B_T: media = IFM_ETHER|IFM_10_T; break; 60785587Sobrien case A_CNF_MEDIA_10B_2: media = IFM_ETHER|IFM_10_2; break; 60885587Sobrien case A_CNF_MEDIA_AUI: media = IFM_ETHER|IFM_10_5; break; 60985587Sobrien default: printf(CS_NAME"%d: adapter has no media\n", unit); 61085587Sobrien } 61185587Sobrien ifmedia_set(&sc->media, media); 61285587Sobrien cs_mediaset(sc, media); 61385587Sobrien 61485587Sobrien if_attach(ifp); 61585587Sobrien cs_stop( sc ); 61685587Sobrien ether_ifattach(ifp); 61785587Sobrien } 61885587Sobrien 61985587Sobrien if (bootverbose) 62085587Sobrien printf(CS_NAME"%d: ethernet address %6D\n", 62185587Sobrien ifp->if_unit, sc->arpcom.ac_enaddr, ":"); 62285587Sobrien 62385587Sobrien#if NBPFILTER > 0 62485587Sobrien bpfattach(ifp, DLT_EN10MB, sizeof (struct ether_header)); 62585587Sobrien#endif 62685587Sobrien return 1; 62785587Sobrien} 62885587Sobrien 62985587Sobrienstatic int 63085587Sobriencs_attach_isa(struct isa_device *dev) 63185587Sobrien{ 63285587Sobrien int unit=dev->id_unit; 63385587Sobrien struct cs_softc *sc=&cs_softc[unit]; 63485587Sobrien int flags=dev->id_flags; 63585587Sobrien 63685587Sobrien return cs_attach(sc, unit, flags); 63785587Sobrien} 63885587Sobrien 63985587Sobrien/* 64085587Sobrien * Initialize the board 64185587Sobrien */ 64285587Sobrienstatic void 64385587Sobriencs_init(void *xsc) 64485587Sobrien{ 64585587Sobrien struct cs_softc *sc=(struct cs_softc *)xsc; 64685587Sobrien struct ifnet *ifp = &sc->arpcom.ac_if; 64785587Sobrien int i, s, result, rx_cfg; 64885587Sobrien 64985587Sobrien /* address not known */ 65085587Sobrien if (TAILQ_EMPTY(&ifp->if_addrhead)) /* unlikely? XXX */ 65185587Sobrien return; 65285587Sobrien 65385587Sobrien /* 65485587Sobrien * reset whatchdog timer 65585587Sobrien */ 65685587Sobrien ifp->if_timer=0; 65785587Sobrien sc->buf_len = 0; 65885587Sobrien 65985587Sobrien s=splimp(); 66085587Sobrien 66185587Sobrien /* 66285587Sobrien * Hardware initialization of cs 66385587Sobrien */ 66485587Sobrien 66585587Sobrien /* Enable receiver and transmitter */ 66685587Sobrien cs_writereg(sc->nic_addr, PP_LineCTL, 66785587Sobrien cs_readreg( sc->nic_addr, PP_LineCTL ) | 66885587Sobrien SERIAL_RX_ON | SERIAL_TX_ON); 66985587Sobrien 67085587Sobrien /* Configure the receiver mode */ 67185587Sobrien cs_setmode(sc); 67285587Sobrien 67385587Sobrien /* 67485587Sobrien * This defines what type of frames will cause interrupts 67585587Sobrien * Bad frames should generate interrupts so that the driver 67685587Sobrien * could track statistics of discarded packets 67785587Sobrien */ 67885587Sobrien rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | 67985587Sobrien RX_EXTRA_DATA_ENBL; 68085587Sobrien if (sc->isa_config & STREAM_TRANSFER) 68185587Sobrien rx_cfg |= RX_STREAM_ENBL; 68285587Sobrien cs_writereg(sc->nic_addr, PP_RxCFG, rx_cfg); 68385587Sobrien 68485587Sobrien cs_writereg(sc->nic_addr, PP_TxCFG, TX_LOST_CRS_ENBL | 68585587Sobrien TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL | 68685587Sobrien TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); 68785587Sobrien 68885587Sobrien cs_writereg(sc->nic_addr, PP_BufCFG, READY_FOR_TX_ENBL | 68985587Sobrien RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL | 69085587Sobrien TX_UNDERRUN_ENBL /*| RX_DMA_ENBL*/); 69185587Sobrien 69285587Sobrien /* Write MAC address into IA filter */ 69385587Sobrien for (i=0; i<ETHER_ADDR_LEN/2; i++) 69485587Sobrien cs_writereg(sc->nic_addr, PP_IA+i*2, 69585587Sobrien sc->arpcom.ac_enaddr[i*2] | 69685587Sobrien (sc->arpcom.ac_enaddr[i*2+1] << 8) ); 69785587Sobrien 69885587Sobrien /* 69985587Sobrien * Now enable everything 70085587Sobrien */ 70185587Sobrien/* 70285587Sobrien#ifdef CS_USE_64K_DMA 70385587Sobrien cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ | RX_DMA_SIZE_64K); 70485587Sobrien #else 70585587Sobrien 70685587Sobrien cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ); 70785587Sobrien#endif 70885587Sobrien*/ 70985587Sobrien cs_writereg(sc->nic_addr, PP_BusCTL, ENABLE_IRQ); 71085587Sobrien 71185587Sobrien /* 71285587Sobrien * Set running and clear output active flags 71385587Sobrien */ 71485587Sobrien sc->arpcom.ac_if.if_flags |= IFF_RUNNING; 71585587Sobrien sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; 71685587Sobrien 71785587Sobrien /* 71885587Sobrien * Start sending process 71985587Sobrien */ 72085587Sobrien cs_start(ifp); 72185587Sobrien 72285587Sobrien (void) splx(s); 72385587Sobrien} 72485587Sobrien 72585587Sobrien/* 72685587Sobrien * Get the packet from the board and send it to the upper layer 72785587Sobrien * via ether_input(). 72885587Sobrien */ 72985587Sobrienstatic int 73085587Sobriencs_get_packet(struct cs_softc *sc) 73185587Sobrien{ 73285587Sobrien struct ifnet *ifp = &(sc->arpcom.ac_if); 73385587Sobrien int iobase = sc->nic_addr, status, length; 73485587Sobrien struct ether_header *eh; 73585587Sobrien struct mbuf *m; 73685587Sobrien 73785587Sobrien#ifdef CS_DEBUG 73885587Sobrien int i; 73985587Sobrien#endif 74085587Sobrien 74185587Sobrien status = inw(iobase + RX_FRAME_PORT); 74285587Sobrien length = inw(iobase + RX_FRAME_PORT); 74385587Sobrien 74485587Sobrien#ifdef CS_DEBUG 74585587Sobrien printf(CS_NAME"%1d: rcvd: stat %x, len %d\n", 74685587Sobrien ifp->if_unit, status, length); 74785587Sobrien#endif 74885587Sobrien 74985587Sobrien if (!(status & RX_OK)) { 75085587Sobrien#ifdef CS_DEBUG 75185587Sobrien printf(CS_NAME"%1d: bad pkt stat %x\n", ifp->if_unit, status); 75285587Sobrien#endif 75385587Sobrien ifp->if_ierrors++; 75485587Sobrien return -1; 75585587Sobrien } 75685587Sobrien 75785587Sobrien MGETHDR(m, M_DONTWAIT, MT_DATA); 75885587Sobrien if (m==NULL) 75985587Sobrien return -1; 76085587Sobrien 76185587Sobrien if (length > MHLEN) { 76285587Sobrien MCLGET(m, M_DONTWAIT); 76385587Sobrien if (!(m->m_flags & M_EXT)) { 76485587Sobrien m_freem(m); 76585587Sobrien return -1; 76685587Sobrien } 76785587Sobrien } 76885587Sobrien 76985587Sobrien /* Initialize packet's header info */ 77085587Sobrien m->m_pkthdr.rcvif = ifp; 77185587Sobrien m->m_pkthdr.len = length; 77285587Sobrien m->m_len = length; 77385587Sobrien 77485587Sobrien /* Get the data */ 77585587Sobrien insw(iobase + RX_FRAME_PORT, m->m_data, (length+1)>>1); 77685587Sobrien 77785587Sobrien eh = mtod(m, struct ether_header *); 77885587Sobrien 77985587Sobrien#if NBPFILTER > 0 78085587Sobrien if (ifp->if_bpf) 78185587Sobrien bpf_mtap(ifp, m); 78285587Sobrien#endif 78385587Sobrien 78485587Sobrien#ifdef CS_DEBUG 78585587Sobrien for (i=0;i<length;i++) 78685587Sobrien printf(" %02x",(unsigned char)*((char *)(m->m_data+i))); 78785587Sobrien printf( "\n" ); 78885587Sobrien#endif 78985587Sobrien 79085587Sobrien if (status & (RX_IA | RX_BROADCAST) || 79185587Sobrien (ifp->if_flags & IFF_MULTICAST && status & RX_HASHED)) { 79285587Sobrien m->m_pkthdr.len -= sizeof(struct ether_header); 79385587Sobrien m->m_len -= sizeof(struct ether_header); 79485587Sobrien m->m_data += sizeof(struct ether_header); 79585587Sobrien 79685587Sobrien /* Feed the packet to the upper layer */ 79785587Sobrien ether_input(ifp, eh, m); 79885587Sobrien 79985587Sobrien ifp->if_ipackets++; 80085587Sobrien 80185587Sobrien if (length==ETHER_MAX_LEN-ETHER_CRC_LEN) 80285587Sobrien DELAY( CS_WAIT_NEXT_PACKET ); 80385587Sobrien } else { 80485587Sobrien m_freem(m); 80585587Sobrien } 80685587Sobrien 80785587Sobrien return 0; 80885587Sobrien} 80985587Sobrien 81085587Sobrien/* 81185587Sobrien * Software calls interrupt handler 81285587Sobrien */ 81385587Sobrienstatic void 81485587Sobriencsintr_sc(struct cs_softc *sc, int unit) 81585587Sobrien{ 81685587Sobrien struct ifnet *ifp = &(sc->arpcom.ac_if); 81785587Sobrien int status, s; 81885587Sobrien 81985587Sobrien#ifdef CS_DEBUG 82085587Sobrien printf(CS_NAME"%1d: Interrupt.\n", unit); 82185587Sobrien#endif 82285587Sobrien 82385587Sobrien while ((status=cs_readword(sc->nic_addr, ISQ_PORT))) { 82485587Sobrien 82585587Sobrien#ifdef CS_DEBUG 82685587Sobrien printf( CS_NAME"%1d:from ISQ: %04x\n", unit, status ); 82785587Sobrien#endif 82885587Sobrien 82985587Sobrien switch (status & ISQ_EVENT_MASK) { 83085587Sobrien case ISQ_RECEIVER_EVENT: 83185587Sobrien cs_get_packet(sc); 83285587Sobrien break; 83385587Sobrien 83485587Sobrien case ISQ_TRANSMITTER_EVENT: 83585587Sobrien if (status & TX_OK) 83685587Sobrien ifp->if_opackets++; 83785587Sobrien else 83885587Sobrien ifp->if_oerrors++; 83985587Sobrien ifp->if_flags &= ~IFF_OACTIVE; 84085587Sobrien ifp->if_timer = 0; 84185587Sobrien break; 84285587Sobrien 84385587Sobrien case ISQ_BUFFER_EVENT: 84485587Sobrien if (status & READY_FOR_TX) { 84585587Sobrien ifp->if_flags &= ~IFF_OACTIVE; 84685587Sobrien ifp->if_timer = 0; 84785587Sobrien } 84885587Sobrien 84985587Sobrien if (status & TX_UNDERRUN) { 85085587Sobrien ifp->if_flags &= ~IFF_OACTIVE; 85185587Sobrien ifp->if_timer = 0; 85285587Sobrien ifp->if_oerrors++; 85385587Sobrien } 85485587Sobrien break; 85585587Sobrien 85685587Sobrien case ISQ_RX_MISS_EVENT: 85785587Sobrien ifp->if_ierrors+=(status>>6); 858 break; 859 860 case ISQ_TX_COL_EVENT: 861 ifp->if_collisions+=(status>>6); 862 break; 863 } 864 } 865 866 if (!(ifp->if_flags & IFF_OACTIVE)) { 867 cs_start(ifp); 868 } 869} 870 871/* 872 * Handle interrupts 873 */ 874void 875csintr(int unit) 876{ 877 struct cs_softc *sc = &cs_softc[unit]; 878 879 csintr_sc(sc, unit); 880} 881 882/* 883 * Save the data in buffer 884 */ 885 886static void 887cs_write_mbufs( struct cs_softc *sc, struct mbuf *m ) 888{ 889 int len; 890 struct mbuf *mp; 891 unsigned char *data, *buf; 892 893 for (mp=m, buf=sc->buffer, sc->buf_len=0; mp != NULL; mp=mp->m_next) { 894 len = mp->m_len; 895 896 /* 897 * Ignore empty parts 898 */ 899 if (!len) 900 continue; 901 902 /* 903 * Find actual data address 904 */ 905 data = mtod(mp, caddr_t); 906 907 bcopy((caddr_t) data, (caddr_t) buf, len); 908 buf += len; 909 sc->buf_len += len; 910 } 911} 912 913 914static void 915cs_xmit_buf( struct cs_softc *sc ) 916{ 917 outsw(sc->nic_addr+TX_FRAME_PORT, sc->buffer, (sc->buf_len+1)>>1); 918 sc->buf_len = 0; 919} 920 921static void 922cs_start(struct ifnet *ifp) 923{ 924 int s, length; 925 struct mbuf *m, *mp; 926 struct cs_softc *sc = ifp->if_softc; 927 928 s = splimp(); 929 930 for (;;) { 931 if (sc->buf_len) 932 length = sc->buf_len; 933 else { 934 IF_DEQUEUE( &ifp->if_snd, m ); 935 936 if (m==NULL) { 937 (void) splx(s); 938 return; 939 } 940 941 for (length=0, mp=m; mp != NULL; mp=mp->m_next) 942 length += mp->m_len; 943 944 /* Skip zero-length packets */ 945 if (length == 0) { 946 m_freem(m); 947 continue; 948 } 949 950 cs_write_mbufs(sc, m); 951 952#if NBPFILTER > 0 953 if (ifp->if_bpf) { 954 bpf_mtap(ifp, m); 955 } 956#endif 957 958 m_freem(m); 959 } 960 961 /* 962 * Issue a SEND command 963 */ 964 outw(sc->nic_addr+TX_CMD_PORT, sc->send_cmd); 965 outw(sc->nic_addr+TX_LEN_PORT, length ); 966 967 /* 968 * If there's no free space in the buffer then leave 969 * this packet for the next time: indicate output active 970 * and return. 971 */ 972 if (!(cs_readreg(sc->nic_addr, PP_BusST) & READY_FOR_TX_NOW)) { 973 ifp->if_timer = sc->buf_len; 974 (void) splx(s); 975 ifp->if_flags |= IFF_OACTIVE; 976 return; 977 } 978 979 cs_xmit_buf(sc); 980 981 /* 982 * Set the watchdog timer in case we never hear 983 * from board again. (I don't know about correct 984 * value for this timeout) 985 */ 986 ifp->if_timer = length; 987 988 (void) splx(s); 989 ifp->if_flags |= IFF_OACTIVE; 990 return; 991 } 992} 993 994/* 995 * Stop everything on the interface 996 */ 997static void 998cs_stop(struct cs_softc *sc) 999{ 1000 int s = splimp(); 1001 1002 cs_writereg(sc->nic_addr, PP_RxCFG, 0); 1003 cs_writereg(sc->nic_addr, PP_TxCFG, 0); 1004 cs_writereg(sc->nic_addr, PP_BufCFG, 0); 1005 cs_writereg(sc->nic_addr, PP_BusCTL, 0); 1006 1007 sc->arpcom.ac_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1008 sc->arpcom.ac_if.if_timer = 0; 1009 1010 (void) splx(s); 1011} 1012 1013/* 1014 * Reset the interface 1015 */ 1016static void 1017cs_reset(struct cs_softc *sc) 1018{ 1019 cs_stop(sc); 1020 cs_init(sc); 1021} 1022 1023static void 1024cs_setmode(struct cs_softc *sc) 1025{ 1026 struct ifnet *ifp = &(sc->arpcom.ac_if); 1027 int rx_ctl; 1028 1029 /* Stop the receiver while changing filters */ 1030 cs_writereg(sc->nic_addr, PP_LineCTL, 1031 cs_readreg(sc->nic_addr, PP_LineCTL) & ~SERIAL_RX_ON); 1032 1033 if (ifp->if_flags & IFF_PROMISC) { 1034 /* Turn on promiscuous mode. */ 1035 rx_ctl = RX_OK_ACCEPT | RX_PROM_ACCEPT; 1036 } else { 1037 if (ifp->if_flags & IFF_MULTICAST) { 1038 /* Allow receiving frames with multicast addresses */ 1039 rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | 1040 RX_OK_ACCEPT | RX_MULTCAST_ACCEPT; 1041 /* 1042 * Here the reconfiguration of chip's multicast 1043 * filters should be done but I've no idea about 1044 * hash transformation in this chip. If you can 1045 * add this code or describe me the transformation 1046 * I'd be very glad. 1047 */ 1048 } else { 1049 /* 1050 * Receive only good frames addressed for us and 1051 * good broadcasts. 1052 */ 1053 rx_ctl = RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | 1054 RX_OK_ACCEPT; 1055 } 1056 } 1057 1058 /* Set up the filter */ 1059 cs_writereg(sc->nic_addr, PP_RxCTL, RX_DEF_ACCEPT | RX_MULTCAST_ACCEPT); 1060 1061 /* Turn on receiver */ 1062 cs_writereg(sc->nic_addr, PP_LineCTL, 1063 cs_readreg(sc->nic_addr, PP_LineCTL) | SERIAL_RX_ON); 1064} 1065 1066static int 1067cs_ioctl(register struct ifnet *ifp, u_long command, caddr_t data) 1068{ 1069 struct cs_softc *sc=ifp->if_softc; 1070 struct ifreq *ifr = (struct ifreq *)data; 1071 int s,error=0; 1072 1073#ifdef CS_DEBUG 1074 printf(CS_NAME"%d: ioctl(%x)\n",sc->arpcom.ac_if.if_unit,command); 1075#endif 1076 1077 s=splimp(); 1078 1079 switch (command) { 1080 case SIOCSIFADDR: 1081 case SIOCGIFADDR: 1082 case SIOCSIFMTU: 1083 ether_ioctl(ifp, command, data); 1084 break; 1085 1086 case SIOCSIFFLAGS: 1087 /* 1088 * Switch interface state between "running" and 1089 * "stopped", reflecting the UP flag. 1090 */ 1091 if (sc->arpcom.ac_if.if_flags & IFF_UP) { 1092 if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)==0) { 1093 cs_init(sc); 1094 } 1095 } else { 1096 if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING)!=0) { 1097 cs_stop(sc); 1098 } 1099 } 1100 /* 1101 * Promiscuous and/or multicast flags may have changed, 1102 * so reprogram the multicast filter and/or receive mode. 1103 * 1104 * See note about multicasts in cs_setmode 1105 */ 1106 cs_setmode(sc); 1107 break; 1108 1109 case SIOCADDMULTI: 1110 case SIOCDELMULTI: 1111 /* 1112 * Multicast list has changed; set the hardware filter 1113 * accordingly. 1114 * 1115 * See note about multicasts in cs_setmode 1116 */ 1117 cs_setmode(sc); 1118 error = 0; 1119 break; 1120 1121 case SIOCSIFMEDIA: 1122 case SIOCGIFMEDIA: 1123 error = ifmedia_ioctl(ifp, ifr, &sc->media, command); 1124 break; 1125 1126 default: 1127 error = EINVAL; 1128 } 1129 1130 (void) splx(s); 1131 return error; 1132} 1133 1134/* 1135 * Device timeout/watchdog routine. Entered if the device neglects to 1136 * generate an interrupt after a transmit has been started on it. 1137 */ 1138static void 1139cs_watchdog(struct ifnet *ifp) 1140{ 1141 struct cs_softc *sc = &cs_softc[ifp->if_unit]; 1142 1143 ifp->if_oerrors++; 1144 log(LOG_ERR, CS_NAME"%d: device timeout\n", ifp->if_unit); 1145 1146 /* Reset the interface */ 1147 if (ifp->if_flags & IFF_UP) 1148 cs_reset(sc); 1149 else 1150 cs_stop(sc); 1151} 1152 1153static int 1154cs_mediachange(struct ifnet *ifp) 1155{ 1156 struct cs_softc *sc = ifp->if_softc; 1157 struct ifmedia *ifm = &sc->media; 1158 1159 if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1160 return EINVAL; 1161 1162 return cs_mediaset(sc, ifm->ifm_media); 1163} 1164 1165static void 1166cs_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) 1167{ 1168 int line_status; 1169 struct cs_softc *sc = ifp->if_softc; 1170 1171 ifmr->ifm_active = IFM_ETHER; 1172 line_status = cs_readreg(sc->nic_addr, PP_LineST); 1173 if (line_status & TENBASET_ON) { 1174 ifmr->ifm_active |= IFM_10_T; 1175 if (sc->chip_type != CS8900) { 1176 if (cs_readreg(sc->nic_addr, PP_AutoNegST) & FDX_ACTIVE) 1177 ifmr->ifm_active |= IFM_FDX; 1178 if (cs_readreg(sc->nic_addr, PP_AutoNegST) & HDX_ACTIVE) 1179 ifmr->ifm_active |= IFM_HDX; 1180 } 1181 ifmr->ifm_status = IFM_AVALID; 1182 if (line_status & LINK_OK) 1183 ifmr->ifm_status |= IFM_ACTIVE; 1184 } else { 1185 if (line_status & AUI_ON) { 1186 cs_writereg(sc->nic_addr, PP_SelfCTL, 1187 cs_readreg(sc->nic_addr, PP_SelfCTL) | 1188 HCB1_ENBL); 1189 if (((sc->adapter_cnf & A_CNF_DC_DC_POLARITY)!=0)^ 1190 (cs_readreg(sc->nic_addr, PP_SelfCTL)&HCB1)) 1191 ifmr->ifm_active |= IFM_10_2; 1192 else 1193 ifmr->ifm_active |= IFM_10_5; 1194 } 1195 } 1196} 1197 1198static int 1199cs_mediaset(struct cs_softc *sc, int media) 1200{ 1201 int error; 1202 1203 /* Stop the receiver & transmitter */ 1204 cs_writereg(sc->nic_addr, PP_LineCTL, 1205 cs_readreg(sc->nic_addr, PP_LineCTL) & 1206 ~(SERIAL_RX_ON | SERIAL_TX_ON)); 1207 1208#ifdef CS_DEBUG 1209 printf(CS_NAME"%d: cs_setmedia(%x)\n",sc->arpcom.ac_if.if_unit,media); 1210#endif 1211 1212 switch (IFM_SUBTYPE(media)) { 1213 default: 1214 case IFM_AUTO: 1215 if (error=enable_tp(sc)) 1216 if (error=enable_bnc(sc)) 1217 error=enable_aui(sc); 1218 break; 1219 case IFM_10_T: 1220 if (error=enable_tp(sc)) 1221 break; 1222 if (media & IFM_FDX) 1223 cs_duplex_full(sc); 1224 else if (media & IFM_HDX) 1225 cs_duplex_half(sc); 1226 else 1227 error = cs_duplex_auto(sc); 1228 break; 1229 case IFM_10_2: 1230 error = enable_bnc(sc); 1231 break; 1232 case IFM_10_5: 1233 error = enable_aui(sc); 1234 break; 1235 } 1236 1237 /* 1238 * Turn the transmitter & receiver back on 1239 */ 1240 cs_writereg(sc->nic_addr, PP_LineCTL, 1241 cs_readreg( sc->nic_addr, PP_LineCTL ) | 1242 SERIAL_RX_ON | SERIAL_TX_ON); 1243 1244 return error; 1245} 1246 1247 1248#if NPNP > 0 1249 1250static struct cspnp_ids { 1251 u_long vend_id; 1252 char *id_str; 1253} cspnp_ids[]= { 1254 { 0x4060630e, "CSC6040" }, 1255 { 0x10104d24, "IBM EtherJet" }, 1256 { 0 } 1257}; 1258 1259static char *cs_pnp_probe(u_long, u_long); 1260static void cs_pnp_attach(u_long, u_long, char *, struct isa_device *); 1261 1262struct pnp_device cs_pnp = { 1263 "CS8920 based PnP Ethernet", 1264 cs_pnp_probe, 1265 cs_pnp_attach, 1266 &cs_unit, 1267 &net_imask /* imask */ 1268}; 1269 1270DATA_SET (pnpdevice_set, cs_pnp); 1271 1272struct csintr_list { 1273 struct cs_softc *sc; 1274 int unit; 1275 struct csintr_list *next; 1276}; 1277 1278static struct csintr_list *csintr_head; 1279 1280static void csintr_pnp_add(struct cs_softc *sc, int unit); 1281static void csintr_pnp(int unit); 1282 1283static void 1284csintr_pnp_add(struct cs_softc *sc, int unit) 1285{ 1286 struct csintr_list *intr; 1287 1288 if (!sc) return; 1289 1290 intr = malloc (sizeof (*intr), M_DEVBUF, M_WAITOK); 1291 if (!intr) return; 1292 1293 intr->sc = sc; 1294 intr->unit = unit; 1295 intr->next = csintr_head; 1296 csintr_head = intr; 1297} 1298 1299/* 1300 * Interrupt handler for PNP installed card 1301 * We have to find the number of the card. 1302 */ 1303static void 1304csintr_pnp(int unit) 1305{ 1306 struct cs_softc *sc; 1307 struct csintr_list *intr; 1308 1309 for (intr=csintr_head; intr; intr=intr->next) { 1310 if (intr->unit == unit) 1311 csintr_sc(intr->sc, unit); 1312 break; 1313 } 1314} 1315 1316static char * 1317cs_pnp_probe(u_long csn, u_long vend_id) 1318{ 1319 struct cspnp_ids *ids; 1320 char *s=NULL; 1321 1322 for(ids = cspnp_ids; ids->vend_id != 0; ids++) { 1323 if (vend_id == ids->vend_id) { 1324 s = ids->id_str; 1325 break; 1326 } 1327 } 1328 1329 if (s) { 1330 struct pnp_cinfo d; 1331 int ldn = 0; 1332 1333 read_pnp_parms(&d, ldn); 1334 if (d.enable == 0) { 1335 printf("This is a %s, but LDN %d is disabled\n", s, ldn); 1336 return NULL ; 1337 } 1338 return s; 1339 } 1340 1341 return NULL ; 1342} 1343 1344static void 1345cs_pnp_attach(u_long csn, u_long vend_id, char *name, 1346 struct isa_device *dev) 1347{ 1348 1349 struct pnp_cinfo d; 1350 int ldn = 0; 1351 int iobase, unit, flags; 1352 u_short irq; 1353 short drq; 1354 struct isa_device *dvp; 1355 struct cs_softc *sc = malloc(sizeof *sc, M_DEVBUF, M_NOWAIT); 1356 1357 if (read_pnp_parms ( &d , ldn ) == 0 ) { 1358 printf("failed to read pnp parms\n"); 1359 return; 1360 } 1361 1362 write_pnp_parms( &d, ldn ); 1363 enable_pnp_card(); 1364 1365 iobase = dev->id_iobase = d.port[0]; 1366 irq = dev->id_irq = (1 << d.irq[0] ); 1367 drq = dev->id_drq = d.drq[0]; 1368 dev->id_maddr = 0; 1369 dev->id_intr = csintr_pnp; 1370 flags = dev->id_flags = 0; 1371 unit = dev->id_unit; 1372 1373 if (dev->id_driver == NULL) { 1374 dev->id_driver = &csdriver; 1375 dvp = find_isadev(isa_devtab_net, &csdriver, 0); 1376 if (dvp != NULL) 1377 dev->id_id = dvp->id_id; 1378 } 1379 1380 if (!sc) return; 1381 1382 bzero(sc, sizeof *sc); 1383 if (cs_cs89x0_probe(sc, &irq, &drq, iobase, unit, flags) == 0 1384 || cs_attach(sc, unit, flags) == 0) { 1385 free(sc, M_DEVBUF); 1386 } else { 1387 if ((irq != dev->id_irq) 1388 || (drq != dev->id_drq) 1389 || (iobase != dev->id_iobase) 1390 || (unit != dev->id_unit) 1391 || (flags != dev->id_flags) 1392 ) { 1393 printf("failed to pnp card parametars\n"); 1394 } 1395 } 1396 csintr_pnp_add(sc, dev->id_unit); 1397} 1398#endif /* NPNP */ 1399