if_sis.c revision 90328
150974Swpaul/* 250974Swpaul * Copyright (c) 1997, 1998, 1999 350974Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 450974Swpaul * 550974Swpaul * Redistribution and use in source and binary forms, with or without 650974Swpaul * modification, are permitted provided that the following conditions 750974Swpaul * are met: 850974Swpaul * 1. Redistributions of source code must retain the above copyright 950974Swpaul * notice, this list of conditions and the following disclaimer. 1050974Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1150974Swpaul * notice, this list of conditions and the following disclaimer in the 1250974Swpaul * documentation and/or other materials provided with the distribution. 1350974Swpaul * 3. All advertising materials mentioning features or use of this software 1450974Swpaul * must display the following acknowledgement: 1550974Swpaul * This product includes software developed by Bill Paul. 1650974Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1750974Swpaul * may be used to endorse or promote products derived from this software 1850974Swpaul * without specific prior written permission. 1950974Swpaul * 2050974Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2150974Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2250974Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2350974Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2450974Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2550974Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2650974Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2750974Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2850974Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2950974Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3050974Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3150974Swpaul * 3250974Swpaul * $FreeBSD: head/sys/pci/if_sis.c 90328 2002-02-06 22:06:47Z ambrisko $ 3350974Swpaul */ 3450974Swpaul 3550974Swpaul/* 3650974Swpaul * SiS 900/SiS 7016 fast ethernet PCI NIC driver. Datasheets are 3750974Swpaul * available from http://www.sis.com.tw. 3850974Swpaul * 3964963Swpaul * This driver also supports the NatSemi DP83815. Datasheets are 4064963Swpaul * available from http://www.national.com. 4164963Swpaul * 4250974Swpaul * Written by Bill Paul <wpaul@ee.columbia.edu> 4350974Swpaul * Electrical Engineering Department 4450974Swpaul * Columbia University, New York City 4550974Swpaul */ 4650974Swpaul 4750974Swpaul/* 4850974Swpaul * The SiS 900 is a fairly simple chip. It uses bus master DMA with 4950974Swpaul * simple TX and RX descriptors of 3 longwords in size. The receiver 5050974Swpaul * has a single perfect filter entry for the station address and a 5150974Swpaul * 128-bit multicast hash table. The SiS 900 has a built-in MII-based 5250974Swpaul * transceiver while the 7016 requires an external transceiver chip. 5350974Swpaul * Both chips offer the standard bit-bang MII interface as well as 5450974Swpaul * an enchanced PHY interface which simplifies accessing MII registers. 5550974Swpaul * 5650974Swpaul * The only downside to this chipset is that RX descriptors must be 5750974Swpaul * longword aligned. 5850974Swpaul */ 5950974Swpaul 6050974Swpaul#include <sys/param.h> 6150974Swpaul#include <sys/systm.h> 6250974Swpaul#include <sys/sockio.h> 6350974Swpaul#include <sys/mbuf.h> 6450974Swpaul#include <sys/malloc.h> 6550974Swpaul#include <sys/kernel.h> 6650974Swpaul#include <sys/socket.h> 6787059Sluigi#include <sys/sysctl.h> 6850974Swpaul 6950974Swpaul#include <net/if.h> 7050974Swpaul#include <net/if_arp.h> 7150974Swpaul#include <net/ethernet.h> 7250974Swpaul#include <net/if_dl.h> 7350974Swpaul#include <net/if_media.h> 7487390Sjhay#include <net/if_types.h> 7587390Sjhay#include <net/if_vlan_var.h> 7650974Swpaul 7750974Swpaul#include <net/bpf.h> 7850974Swpaul 7950974Swpaul#include <machine/bus_pio.h> 8050974Swpaul#include <machine/bus_memio.h> 8150974Swpaul#include <machine/bus.h> 8250974Swpaul#include <machine/resource.h> 8350974Swpaul#include <sys/bus.h> 8450974Swpaul#include <sys/rman.h> 8550974Swpaul 8650974Swpaul#include <dev/mii/mii.h> 8750974Swpaul#include <dev/mii/miivar.h> 8850974Swpaul 8950974Swpaul#include <pci/pcireg.h> 9050974Swpaul#include <pci/pcivar.h> 9150974Swpaul 9250974Swpaul#define SIS_USEIOSPACE 9350974Swpaul 9450974Swpaul#include <pci/if_sisreg.h> 9550974Swpaul 9659758SpeterMODULE_DEPEND(sis, miibus, 1, 1, 1); 9759758Speter 9851089Speter/* "controller miibus0" required. See GENERIC if you get errors here. */ 9950974Swpaul#include "miibus_if.h" 10050974Swpaul 10150974Swpaul#ifndef lint 10250974Swpaulstatic const char rcsid[] = 10350974Swpaul "$FreeBSD: head/sys/pci/if_sis.c 90328 2002-02-06 22:06:47Z ambrisko $"; 10450974Swpaul#endif 10550974Swpaul 10650974Swpaul/* 10750974Swpaul * Various supported device vendors/types and their names. 10850974Swpaul */ 10950974Swpaulstatic struct sis_type sis_devs[] = { 11050974Swpaul { SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" }, 11150974Swpaul { SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" }, 11262672Swpaul { NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP83815 10/100BaseTX" }, 11350974Swpaul { 0, 0, NULL } 11450974Swpaul}; 11550974Swpaul 11650974Swpaulstatic int sis_probe __P((device_t)); 11750974Swpaulstatic int sis_attach __P((device_t)); 11850974Swpaulstatic int sis_detach __P((device_t)); 11950974Swpaul 12050974Swpaulstatic int sis_newbuf __P((struct sis_softc *, 12150974Swpaul struct sis_desc *, 12250974Swpaul struct mbuf *)); 12350974Swpaulstatic int sis_encap __P((struct sis_softc *, 12450974Swpaul struct mbuf *, u_int32_t *)); 12550974Swpaulstatic void sis_rxeof __P((struct sis_softc *)); 12650974Swpaulstatic void sis_rxeoc __P((struct sis_softc *)); 12750974Swpaulstatic void sis_txeof __P((struct sis_softc *)); 12850974Swpaulstatic void sis_intr __P((void *)); 12950974Swpaulstatic void sis_tick __P((void *)); 13050974Swpaulstatic void sis_start __P((struct ifnet *)); 13150974Swpaulstatic int sis_ioctl __P((struct ifnet *, u_long, caddr_t)); 13250974Swpaulstatic void sis_init __P((void *)); 13350974Swpaulstatic void sis_stop __P((struct sis_softc *)); 13450974Swpaulstatic void sis_watchdog __P((struct ifnet *)); 13550974Swpaulstatic void sis_shutdown __P((device_t)); 13650974Swpaulstatic int sis_ifmedia_upd __P((struct ifnet *)); 13750974Swpaulstatic void sis_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); 13850974Swpaul 13962672Swpaulstatic u_int16_t sis_reverse __P((u_int16_t)); 14050974Swpaulstatic void sis_delay __P((struct sis_softc *)); 14150974Swpaulstatic void sis_eeprom_idle __P((struct sis_softc *)); 14250974Swpaulstatic void sis_eeprom_putbyte __P((struct sis_softc *, int)); 14350974Swpaulstatic void sis_eeprom_getword __P((struct sis_softc *, int, u_int16_t *)); 14450974Swpaulstatic void sis_read_eeprom __P((struct sis_softc *, caddr_t, int, 14550974Swpaul int, int)); 14672197Swpaul#ifdef __i386__ 14772197Swpaulstatic void sis_read_cmos __P((struct sis_softc *, device_t, caddr_t, 14872197Swpaul int, int)); 14989296Swpaulstatic void sis_read_mac __P((struct sis_softc *, device_t, caddr_t)); 15072197Swpaulstatic device_t sis_find_bridge __P((device_t)); 15172197Swpaul#endif 15272197Swpaul 15350974Swpaulstatic int sis_miibus_readreg __P((device_t, int, int)); 15450974Swpaulstatic int sis_miibus_writereg __P((device_t, int, int, int)); 15550974Swpaulstatic void sis_miibus_statchg __P((device_t)); 15650974Swpaul 15762672Swpaulstatic void sis_setmulti_sis __P((struct sis_softc *)); 15862672Swpaulstatic void sis_setmulti_ns __P((struct sis_softc *)); 15962672Swpaulstatic u_int32_t sis_crc __P((struct sis_softc *, caddr_t)); 16050974Swpaulstatic void sis_reset __P((struct sis_softc *)); 16150974Swpaulstatic int sis_list_rx_init __P((struct sis_softc *)); 16250974Swpaulstatic int sis_list_tx_init __P((struct sis_softc *)); 16350974Swpaul 16481713Swpaulstatic void sis_dma_map_desc_ptr __P((void *, bus_dma_segment_t *, 16581713Swpaul int, int)); 16681713Swpaulstatic void sis_dma_map_desc_next __P((void *, bus_dma_segment_t *, 16781713Swpaul int, int)); 16881713Swpaulstatic void sis_dma_map_ring __P((void *, bus_dma_segment_t *, 16981713Swpaul int, int)); 17050974Swpaul#ifdef SIS_USEIOSPACE 17150974Swpaul#define SIS_RES SYS_RES_IOPORT 17250974Swpaul#define SIS_RID SIS_PCI_LOIO 17350974Swpaul#else 17451030Swpaul#define SIS_RES SYS_RES_MEMORY 17551030Swpaul#define SIS_RID SIS_PCI_LOMEM 17650974Swpaul#endif 17750974Swpaul 17850974Swpaulstatic device_method_t sis_methods[] = { 17950974Swpaul /* Device interface */ 18050974Swpaul DEVMETHOD(device_probe, sis_probe), 18150974Swpaul DEVMETHOD(device_attach, sis_attach), 18250974Swpaul DEVMETHOD(device_detach, sis_detach), 18350974Swpaul DEVMETHOD(device_shutdown, sis_shutdown), 18450974Swpaul 18550974Swpaul /* bus interface */ 18650974Swpaul DEVMETHOD(bus_print_child, bus_generic_print_child), 18750974Swpaul DEVMETHOD(bus_driver_added, bus_generic_driver_added), 18850974Swpaul 18950974Swpaul /* MII interface */ 19050974Swpaul DEVMETHOD(miibus_readreg, sis_miibus_readreg), 19150974Swpaul DEVMETHOD(miibus_writereg, sis_miibus_writereg), 19250974Swpaul DEVMETHOD(miibus_statchg, sis_miibus_statchg), 19350974Swpaul 19450974Swpaul { 0, 0 } 19550974Swpaul}; 19650974Swpaul 19750974Swpaulstatic driver_t sis_driver = { 19851455Swpaul "sis", 19950974Swpaul sis_methods, 20050974Swpaul sizeof(struct sis_softc) 20150974Swpaul}; 20250974Swpaul 20350974Swpaulstatic devclass_t sis_devclass; 20450974Swpaul 20587059Sluigi#ifdef __i386__ 20687059Sluigistatic int sis_quick=1; 20787059SluigiSYSCTL_INT(_hw, OID_AUTO, sis_quick, CTLFLAG_RW, 20887059Sluigi &sis_quick,0,"do not mdevget in sis driver"); 20987059Sluigi#endif 21087059Sluigi 21151533SwpaulDRIVER_MODULE(if_sis, pci, sis_driver, sis_devclass, 0, 0); 21251473SwpaulDRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0); 21350974Swpaul 21450974Swpaul#define SIS_SETBIT(sc, reg, x) \ 21550974Swpaul CSR_WRITE_4(sc, reg, \ 21650974Swpaul CSR_READ_4(sc, reg) | (x)) 21750974Swpaul 21850974Swpaul#define SIS_CLRBIT(sc, reg, x) \ 21950974Swpaul CSR_WRITE_4(sc, reg, \ 22050974Swpaul CSR_READ_4(sc, reg) & ~(x)) 22150974Swpaul 22250974Swpaul#define SIO_SET(x) \ 22350974Swpaul CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) | x) 22450974Swpaul 22550974Swpaul#define SIO_CLR(x) \ 22650974Swpaul CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x) 22750974Swpaul 22881713Swpaulstatic void 22981713Swpaulsis_dma_map_desc_next(arg, segs, nseg, error) 23081713Swpaul void *arg; 23181713Swpaul bus_dma_segment_t *segs; 23281713Swpaul int nseg, error; 23381713Swpaul{ 23481713Swpaul struct sis_desc *r; 23581713Swpaul 23681713Swpaul r = arg; 23781713Swpaul r->sis_next = segs->ds_addr; 23881713Swpaul 23981713Swpaul return; 24081713Swpaul} 24181713Swpaul 24281713Swpaulstatic void 24381713Swpaulsis_dma_map_desc_ptr(arg, segs, nseg, error) 24481713Swpaul void *arg; 24581713Swpaul bus_dma_segment_t *segs; 24681713Swpaul int nseg, error; 24781713Swpaul{ 24881713Swpaul struct sis_desc *r; 24981713Swpaul 25081713Swpaul r = arg; 25181713Swpaul r->sis_ptr = segs->ds_addr; 25281713Swpaul 25381713Swpaul return; 25481713Swpaul} 25581713Swpaul 25681713Swpaulstatic void 25781713Swpaulsis_dma_map_ring(arg, segs, nseg, error) 25881713Swpaul void *arg; 25981713Swpaul bus_dma_segment_t *segs; 26081713Swpaul int nseg, error; 26181713Swpaul{ 26281713Swpaul u_int32_t *p; 26381713Swpaul 26481713Swpaul p = arg; 26581713Swpaul *p = segs->ds_addr; 26681713Swpaul 26781713Swpaul return; 26881713Swpaul} 26981713Swpaul 27062672Swpaul/* 27162672Swpaul * Routine to reverse the bits in a word. Stolen almost 27262672Swpaul * verbatim from /usr/games/fortune. 27362672Swpaul */ 27462672Swpaulstatic u_int16_t sis_reverse(n) 27562672Swpaul u_int16_t n; 27662672Swpaul{ 27762672Swpaul n = ((n >> 1) & 0x5555) | ((n << 1) & 0xaaaa); 27862672Swpaul n = ((n >> 2) & 0x3333) | ((n << 2) & 0xcccc); 27962672Swpaul n = ((n >> 4) & 0x0f0f) | ((n << 4) & 0xf0f0); 28062672Swpaul n = ((n >> 8) & 0x00ff) | ((n << 8) & 0xff00); 28162672Swpaul 28262672Swpaul return(n); 28362672Swpaul} 28462672Swpaul 28550974Swpaulstatic void sis_delay(sc) 28650974Swpaul struct sis_softc *sc; 28750974Swpaul{ 28850974Swpaul int idx; 28950974Swpaul 29050974Swpaul for (idx = (300 / 33) + 1; idx > 0; idx--) 29150974Swpaul CSR_READ_4(sc, SIS_CSR); 29250974Swpaul 29350974Swpaul return; 29450974Swpaul} 29550974Swpaul 29650974Swpaulstatic void sis_eeprom_idle(sc) 29750974Swpaul struct sis_softc *sc; 29850974Swpaul{ 29950974Swpaul register int i; 30050974Swpaul 30150974Swpaul SIO_SET(SIS_EECTL_CSEL); 30250974Swpaul sis_delay(sc); 30350974Swpaul SIO_SET(SIS_EECTL_CLK); 30450974Swpaul sis_delay(sc); 30550974Swpaul 30650974Swpaul for (i = 0; i < 25; i++) { 30750974Swpaul SIO_CLR(SIS_EECTL_CLK); 30850974Swpaul sis_delay(sc); 30950974Swpaul SIO_SET(SIS_EECTL_CLK); 31050974Swpaul sis_delay(sc); 31150974Swpaul } 31250974Swpaul 31350974Swpaul SIO_CLR(SIS_EECTL_CLK); 31450974Swpaul sis_delay(sc); 31550974Swpaul SIO_CLR(SIS_EECTL_CSEL); 31650974Swpaul sis_delay(sc); 31750974Swpaul CSR_WRITE_4(sc, SIS_EECTL, 0x00000000); 31850974Swpaul 31950974Swpaul return; 32050974Swpaul} 32150974Swpaul 32250974Swpaul/* 32350974Swpaul * Send a read command and address to the EEPROM, check for ACK. 32450974Swpaul */ 32550974Swpaulstatic void sis_eeprom_putbyte(sc, addr) 32650974Swpaul struct sis_softc *sc; 32750974Swpaul int addr; 32850974Swpaul{ 32950974Swpaul register int d, i; 33050974Swpaul 33150974Swpaul d = addr | SIS_EECMD_READ; 33250974Swpaul 33350974Swpaul /* 33450974Swpaul * Feed in each bit and stobe the clock. 33550974Swpaul */ 33650974Swpaul for (i = 0x400; i; i >>= 1) { 33750974Swpaul if (d & i) { 33850974Swpaul SIO_SET(SIS_EECTL_DIN); 33950974Swpaul } else { 34050974Swpaul SIO_CLR(SIS_EECTL_DIN); 34150974Swpaul } 34250974Swpaul sis_delay(sc); 34350974Swpaul SIO_SET(SIS_EECTL_CLK); 34450974Swpaul sis_delay(sc); 34550974Swpaul SIO_CLR(SIS_EECTL_CLK); 34650974Swpaul sis_delay(sc); 34750974Swpaul } 34850974Swpaul 34950974Swpaul return; 35050974Swpaul} 35150974Swpaul 35250974Swpaul/* 35350974Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 35450974Swpaul */ 35550974Swpaulstatic void sis_eeprom_getword(sc, addr, dest) 35650974Swpaul struct sis_softc *sc; 35750974Swpaul int addr; 35850974Swpaul u_int16_t *dest; 35950974Swpaul{ 36050974Swpaul register int i; 36150974Swpaul u_int16_t word = 0; 36250974Swpaul 36350974Swpaul /* Force EEPROM to idle state. */ 36450974Swpaul sis_eeprom_idle(sc); 36550974Swpaul 36650974Swpaul /* Enter EEPROM access mode. */ 36750974Swpaul sis_delay(sc); 36862672Swpaul SIO_CLR(SIS_EECTL_CLK); 36962672Swpaul sis_delay(sc); 37050974Swpaul SIO_SET(SIS_EECTL_CSEL); 37150974Swpaul sis_delay(sc); 37250974Swpaul 37350974Swpaul /* 37450974Swpaul * Send address of word we want to read. 37550974Swpaul */ 37650974Swpaul sis_eeprom_putbyte(sc, addr); 37750974Swpaul 37850974Swpaul /* 37950974Swpaul * Start reading bits from EEPROM. 38050974Swpaul */ 38150974Swpaul for (i = 0x8000; i; i >>= 1) { 38250974Swpaul SIO_SET(SIS_EECTL_CLK); 38350974Swpaul sis_delay(sc); 38450974Swpaul if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECTL_DOUT) 38550974Swpaul word |= i; 38650974Swpaul sis_delay(sc); 38750974Swpaul SIO_CLR(SIS_EECTL_CLK); 38850974Swpaul sis_delay(sc); 38950974Swpaul } 39050974Swpaul 39150974Swpaul /* Turn off EEPROM access mode. */ 39250974Swpaul sis_eeprom_idle(sc); 39350974Swpaul 39450974Swpaul *dest = word; 39550974Swpaul 39650974Swpaul return; 39750974Swpaul} 39850974Swpaul 39950974Swpaul/* 40050974Swpaul * Read a sequence of words from the EEPROM. 40150974Swpaul */ 40250974Swpaulstatic void sis_read_eeprom(sc, dest, off, cnt, swap) 40350974Swpaul struct sis_softc *sc; 40450974Swpaul caddr_t dest; 40550974Swpaul int off; 40650974Swpaul int cnt; 40750974Swpaul int swap; 40850974Swpaul{ 40950974Swpaul int i; 41050974Swpaul u_int16_t word = 0, *ptr; 41150974Swpaul 41250974Swpaul for (i = 0; i < cnt; i++) { 41350974Swpaul sis_eeprom_getword(sc, off + i, &word); 41450974Swpaul ptr = (u_int16_t *)(dest + (i * 2)); 41550974Swpaul if (swap) 41650974Swpaul *ptr = ntohs(word); 41750974Swpaul else 41850974Swpaul *ptr = word; 41950974Swpaul } 42050974Swpaul 42150974Swpaul return; 42250974Swpaul} 42350974Swpaul 42472197Swpaul#ifdef __i386__ 42572197Swpaulstatic device_t sis_find_bridge(dev) 42672197Swpaul device_t dev; 42772197Swpaul{ 42872197Swpaul devclass_t pci_devclass; 42972197Swpaul device_t *pci_devices; 43072197Swpaul int pci_count = 0; 43172197Swpaul device_t *pci_children; 43272197Swpaul int pci_childcount = 0; 43372197Swpaul device_t *busp, *childp; 43487994Sarchie device_t child = NULL; 43572197Swpaul int i, j; 43672197Swpaul 43772197Swpaul if ((pci_devclass = devclass_find("pci")) == NULL) 43872197Swpaul return(NULL); 43972197Swpaul 44072197Swpaul devclass_get_devices(pci_devclass, &pci_devices, &pci_count); 44172197Swpaul 44272197Swpaul for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) { 44372197Swpaul pci_childcount = 0; 44472197Swpaul device_get_children(*busp, &pci_children, &pci_childcount); 44572197Swpaul for (j = 0, childp = pci_children; 44672197Swpaul j < pci_childcount; j++, childp++) { 44772197Swpaul if (pci_get_vendor(*childp) == SIS_VENDORID && 44872197Swpaul pci_get_device(*childp) == 0x0008) { 44987994Sarchie child = *childp; 45087994Sarchie goto done; 45172197Swpaul } 45272197Swpaul } 45372197Swpaul } 45472197Swpaul 45587994Sarchiedone: 45672197Swpaul free(pci_devices, M_TEMP); 45772197Swpaul free(pci_children, M_TEMP); 45887994Sarchie return(child); 45972197Swpaul} 46072197Swpaul 46172197Swpaulstatic void sis_read_cmos(sc, dev, dest, off, cnt) 46272197Swpaul struct sis_softc *sc; 46372197Swpaul device_t dev; 46472197Swpaul caddr_t dest; 46572197Swpaul int off; 46672197Swpaul int cnt; 46772197Swpaul{ 46872197Swpaul device_t bridge; 46972197Swpaul u_int8_t reg; 47072197Swpaul int i; 47172197Swpaul bus_space_tag_t btag; 47272197Swpaul 47372197Swpaul bridge = sis_find_bridge(dev); 47472197Swpaul if (bridge == NULL) 47572197Swpaul return; 47672197Swpaul reg = pci_read_config(bridge, 0x48, 1); 47772197Swpaul pci_write_config(bridge, 0x48, reg|0x40, 1); 47872197Swpaul 47972197Swpaul /* XXX */ 48072197Swpaul btag = I386_BUS_SPACE_IO; 48172197Swpaul 48272197Swpaul for (i = 0; i < cnt; i++) { 48372197Swpaul bus_space_write_1(btag, 0x0, 0x70, i + off); 48472197Swpaul *(dest + i) = bus_space_read_1(btag, 0x0, 0x71); 48572197Swpaul } 48672197Swpaul 48772197Swpaul pci_write_config(bridge, 0x48, reg & ~0x40, 1); 48872197Swpaul return; 48972197Swpaul} 49089296Swpaul 49189296Swpaulstatic void sis_read_mac(sc, dev, dest) 49289296Swpaul struct sis_softc *sc; 49389296Swpaul device_t dev; 49489296Swpaul caddr_t dest; 49589296Swpaul{ 49689296Swpaul u_int32_t filtsave, csrsave; 49789296Swpaul 49889296Swpaul filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); 49989296Swpaul csrsave = CSR_READ_4(sc, SIS_CSR); 50089296Swpaul 50189296Swpaul CSR_WRITE_4(sc, SIS_CSR, SIS_CSR_RELOAD | filtsave); 50289296Swpaul CSR_WRITE_4(sc, SIS_CSR, 0); 50389296Swpaul 50489296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE); 50589296Swpaul 50689296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 50789296Swpaul ((u_int16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); 50889296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1); 50989296Swpaul ((u_int16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); 51089296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 51189296Swpaul ((u_int16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); 51289296Swpaul 51389296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); 51489296Swpaul CSR_WRITE_4(sc, SIS_CSR, csrsave); 51589296Swpaul return; 51689296Swpaul} 51772197Swpaul#endif 51872197Swpaul 51950974Swpaulstatic int sis_miibus_readreg(dev, phy, reg) 52050974Swpaul device_t dev; 52150974Swpaul int phy, reg; 52250974Swpaul{ 52350974Swpaul struct sis_softc *sc; 52462672Swpaul int i, val = 0; 52550974Swpaul 52650974Swpaul sc = device_get_softc(dev); 52750974Swpaul 52862672Swpaul if (sc->sis_type == SIS_TYPE_83815) { 52962672Swpaul if (phy != 0) 53062672Swpaul return(0); 53162672Swpaul /* 53262672Swpaul * The NatSemi chip can take a while after 53362672Swpaul * a reset to come ready, during which the BMSR 53462672Swpaul * returns a value of 0. This is *never* supposed 53562672Swpaul * to happen: some of the BMSR bits are meant to 53662672Swpaul * be hardwired in the on position, and this can 53762672Swpaul * confuse the miibus code a bit during the probe 53862672Swpaul * and attach phase. So we make an effort to check 53962672Swpaul * for this condition and wait for it to clear. 54062672Swpaul */ 54162672Swpaul if (!CSR_READ_4(sc, NS_BMSR)) 54262672Swpaul DELAY(1000); 54362672Swpaul val = CSR_READ_4(sc, NS_BMCR + (reg * 4)); 54462672Swpaul return(val); 54562672Swpaul } 54662672Swpaul 54789296Swpaul if (sc->sis_type == SIS_TYPE_900 && 54889296Swpaul sc->sis_rev < SIS_REV_635 && phy != 0) 54950974Swpaul return(0); 55050974Swpaul 55150974Swpaul CSR_WRITE_4(sc, SIS_PHYCTL, (phy << 11) | (reg << 6) | SIS_PHYOP_READ); 55250974Swpaul SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS); 55350974Swpaul 55450974Swpaul for (i = 0; i < SIS_TIMEOUT; i++) { 55550974Swpaul if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS)) 55650974Swpaul break; 55750974Swpaul } 55850974Swpaul 55950974Swpaul if (i == SIS_TIMEOUT) { 56050974Swpaul printf("sis%d: PHY failed to come ready\n", sc->sis_unit); 56150974Swpaul return(0); 56250974Swpaul } 56350974Swpaul 56450974Swpaul val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF; 56550974Swpaul 56650974Swpaul if (val == 0xFFFF) 56750974Swpaul return(0); 56850974Swpaul 56950974Swpaul return(val); 57050974Swpaul} 57150974Swpaul 57250974Swpaulstatic int sis_miibus_writereg(dev, phy, reg, data) 57350974Swpaul device_t dev; 57450974Swpaul int phy, reg, data; 57550974Swpaul{ 57650974Swpaul struct sis_softc *sc; 57750974Swpaul int i; 57850974Swpaul 57950974Swpaul sc = device_get_softc(dev); 58050974Swpaul 58162672Swpaul if (sc->sis_type == SIS_TYPE_83815) { 58262672Swpaul if (phy != 0) 58362672Swpaul return(0); 58462672Swpaul CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data); 58562672Swpaul return(0); 58662672Swpaul } 58762672Swpaul 58850974Swpaul if (sc->sis_type == SIS_TYPE_900 && phy != 0) 58950974Swpaul return(0); 59050974Swpaul 59150974Swpaul CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) | 59250974Swpaul (reg << 6) | SIS_PHYOP_WRITE); 59350974Swpaul SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS); 59450974Swpaul 59550974Swpaul for (i = 0; i < SIS_TIMEOUT; i++) { 59650974Swpaul if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS)) 59750974Swpaul break; 59850974Swpaul } 59950974Swpaul 60050974Swpaul if (i == SIS_TIMEOUT) 60150974Swpaul printf("sis%d: PHY failed to come ready\n", sc->sis_unit); 60250974Swpaul 60350974Swpaul return(0); 60450974Swpaul} 60550974Swpaul 60650974Swpaulstatic void sis_miibus_statchg(dev) 60750974Swpaul device_t dev; 60850974Swpaul{ 60950974Swpaul struct sis_softc *sc; 61050974Swpaul 61150974Swpaul sc = device_get_softc(dev); 61264963Swpaul sis_init(sc); 61350974Swpaul 61450974Swpaul return; 61550974Swpaul} 61650974Swpaul 61762672Swpaulstatic u_int32_t sis_crc(sc, addr) 61862672Swpaul struct sis_softc *sc; 61950974Swpaul caddr_t addr; 62050974Swpaul{ 62150974Swpaul u_int32_t crc, carry; 62250974Swpaul int i, j; 62350974Swpaul u_int8_t c; 62450974Swpaul 62550974Swpaul /* Compute CRC for the address value. */ 62650974Swpaul crc = 0xFFFFFFFF; /* initial value */ 62750974Swpaul 62850974Swpaul for (i = 0; i < 6; i++) { 62950974Swpaul c = *(addr + i); 63050974Swpaul for (j = 0; j < 8; j++) { 63150974Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 63250974Swpaul crc <<= 1; 63350974Swpaul c >>= 1; 63450974Swpaul if (carry) 63550974Swpaul crc = (crc ^ 0x04c11db6) | carry; 63650974Swpaul } 63750974Swpaul } 63850974Swpaul 63962672Swpaul /* 64062672Swpaul * return the filter bit position 64162672Swpaul * 64262672Swpaul * The NatSemi chip has a 512-bit filter, which is 64362672Swpaul * different than the SiS, so we special-case it. 64462672Swpaul */ 64562672Swpaul if (sc->sis_type == SIS_TYPE_83815) 64662672Swpaul return((crc >> 23) & 0x1FF); 64762672Swpaul 64850974Swpaul return((crc >> 25) & 0x0000007F); 64950974Swpaul} 65050974Swpaul 65162672Swpaulstatic void sis_setmulti_ns(sc) 65250974Swpaul struct sis_softc *sc; 65350974Swpaul{ 65450974Swpaul struct ifnet *ifp; 65550974Swpaul struct ifmultiaddr *ifma; 65650974Swpaul u_int32_t h = 0, i, filtsave; 65762672Swpaul int bit, index; 65850974Swpaul 65950974Swpaul ifp = &sc->arpcom.ac_if; 66050974Swpaul 66150974Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 66262672Swpaul SIS_CLRBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH); 66350974Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); 66450974Swpaul return; 66550974Swpaul } 66650974Swpaul 66762672Swpaul /* 66862672Swpaul * We have to explicitly enable the multicast hash table 66962672Swpaul * on the NatSemi chip if we want to use it, which we do. 67062672Swpaul */ 67162672Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH); 67250974Swpaul SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); 67350974Swpaul 67450974Swpaul filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); 67550974Swpaul 67650974Swpaul /* first, zot all the existing hash bits */ 67762672Swpaul for (i = 0; i < 32; i++) { 67862672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + (i*2)); 67962672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0); 68062672Swpaul } 68162672Swpaul 68272084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 68362672Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 68462672Swpaul continue; 68562672Swpaul h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 68662672Swpaul index = h >> 3; 68762672Swpaul bit = h & 0x1F; 68862672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index); 68962672Swpaul if (bit > 0xF) 69062672Swpaul bit -= 0x10; 69162672Swpaul SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit)); 69262672Swpaul } 69362672Swpaul 69462672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); 69562672Swpaul 69662672Swpaul return; 69762672Swpaul} 69862672Swpaul 69962672Swpaulstatic void sis_setmulti_sis(sc) 70062672Swpaul struct sis_softc *sc; 70162672Swpaul{ 70262672Swpaul struct ifnet *ifp; 70362672Swpaul struct ifmultiaddr *ifma; 70462672Swpaul u_int32_t h = 0, i, filtsave; 70562672Swpaul 70662672Swpaul ifp = &sc->arpcom.ac_if; 70762672Swpaul 70862672Swpaul if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 70962672Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); 71062672Swpaul return; 71162672Swpaul } 71262672Swpaul 71362672Swpaul SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); 71462672Swpaul 71562672Swpaul filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); 71662672Swpaul 71762672Swpaul /* first, zot all the existing hash bits */ 71850974Swpaul for (i = 0; i < 8; i++) { 71950974Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + ((i * 16) >> 4)) << 16); 72050974Swpaul CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0); 72150974Swpaul } 72250974Swpaul 72350974Swpaul /* now program new ones */ 72472084Sphk TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 72550974Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 72650974Swpaul continue; 72762672Swpaul h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 72850974Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + (h >> 4)) << 16); 72950974Swpaul SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << (h & 0xF))); 73050974Swpaul } 73150974Swpaul 73250974Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); 73350974Swpaul 73450974Swpaul return; 73550974Swpaul} 73650974Swpaul 73750974Swpaulstatic void sis_reset(sc) 73850974Swpaul struct sis_softc *sc; 73950974Swpaul{ 74050974Swpaul register int i; 74150974Swpaul 74250974Swpaul SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RESET); 74350974Swpaul 74450974Swpaul for (i = 0; i < SIS_TIMEOUT; i++) { 74550974Swpaul if (!(CSR_READ_4(sc, SIS_CSR) & SIS_CSR_RESET)) 74650974Swpaul break; 74750974Swpaul } 74850974Swpaul 74950974Swpaul if (i == SIS_TIMEOUT) 75050974Swpaul printf("sis%d: reset never completed\n", sc->sis_unit); 75150974Swpaul 75250974Swpaul /* Wait a little while for the chip to get its brains in order. */ 75350974Swpaul DELAY(1000); 75472813Swpaul 75572813Swpaul /* 75672813Swpaul * If this is a NetSemi chip, make sure to clear 75772813Swpaul * PME mode. 75872813Swpaul */ 75972813Swpaul if (sc->sis_type == SIS_TYPE_83815) { 76072813Swpaul CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS); 76172813Swpaul CSR_WRITE_4(sc, NS_CLKRUN, 0); 76272813Swpaul } 76372813Swpaul 76450974Swpaul return; 76550974Swpaul} 76650974Swpaul 76750974Swpaul/* 76850974Swpaul * Probe for an SiS chip. Check the PCI vendor and device 76950974Swpaul * IDs against our list and return a device name if we find a match. 77050974Swpaul */ 77150974Swpaulstatic int sis_probe(dev) 77250974Swpaul device_t dev; 77350974Swpaul{ 77450974Swpaul struct sis_type *t; 77550974Swpaul 77650974Swpaul t = sis_devs; 77750974Swpaul 77850974Swpaul while(t->sis_name != NULL) { 77950974Swpaul if ((pci_get_vendor(dev) == t->sis_vid) && 78050974Swpaul (pci_get_device(dev) == t->sis_did)) { 78150974Swpaul device_set_desc(dev, t->sis_name); 78250974Swpaul return(0); 78350974Swpaul } 78450974Swpaul t++; 78550974Swpaul } 78650974Swpaul 78750974Swpaul return(ENXIO); 78850974Swpaul} 78950974Swpaul 79050974Swpaul/* 79150974Swpaul * Attach the interface. Allocate softc structures, do ifmedia 79250974Swpaul * setup and ethernet/BPF attach. 79350974Swpaul */ 79450974Swpaulstatic int sis_attach(dev) 79550974Swpaul device_t dev; 79650974Swpaul{ 79750974Swpaul u_char eaddr[ETHER_ADDR_LEN]; 79850974Swpaul u_int32_t command; 79950974Swpaul struct sis_softc *sc; 80050974Swpaul struct ifnet *ifp; 80150974Swpaul int unit, error = 0, rid; 80250974Swpaul 80350974Swpaul sc = device_get_softc(dev); 80450974Swpaul unit = device_get_unit(dev); 80550974Swpaul bzero(sc, sizeof(struct sis_softc)); 80650974Swpaul 80771228Sbmilekic mtx_init(&sc->sis_mtx, device_get_nameunit(dev), MTX_DEF | MTX_RECURSE); 80869583Swpaul SIS_LOCK(sc); 80969583Swpaul 81050974Swpaul if (pci_get_device(dev) == SIS_DEVICEID_900) 81150974Swpaul sc->sis_type = SIS_TYPE_900; 81250974Swpaul if (pci_get_device(dev) == SIS_DEVICEID_7016) 81350974Swpaul sc->sis_type = SIS_TYPE_7016; 81462672Swpaul if (pci_get_vendor(dev) == NS_VENDORID) 81562672Swpaul sc->sis_type = SIS_TYPE_83815; 81650974Swpaul 81789296Swpaul sc->sis_rev = pci_read_config(dev, PCIR_REVID, 1); 81889296Swpaul 81950974Swpaul /* 82050974Swpaul * Handle power management nonsense. 82150974Swpaul */ 82272813Swpaul if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 82372813Swpaul u_int32_t iobase, membase, irq; 82450974Swpaul 82572813Swpaul /* Save important PCI config data. */ 82672813Swpaul iobase = pci_read_config(dev, SIS_PCI_LOIO, 4); 82772813Swpaul membase = pci_read_config(dev, SIS_PCI_LOMEM, 4); 82872813Swpaul irq = pci_read_config(dev, SIS_PCI_INTLINE, 4); 82950974Swpaul 83072813Swpaul /* Reset the power state. */ 83172813Swpaul printf("sis%d: chip is in D%d power mode " 83272813Swpaul "-- setting to D0\n", unit, 83372813Swpaul pci_get_powerstate(dev)); 83472813Swpaul pci_set_powerstate(dev, PCI_POWERSTATE_D0); 83550974Swpaul 83672813Swpaul /* Restore PCI config data. */ 83772813Swpaul pci_write_config(dev, SIS_PCI_LOIO, iobase, 4); 83872813Swpaul pci_write_config(dev, SIS_PCI_LOMEM, membase, 4); 83972813Swpaul pci_write_config(dev, SIS_PCI_INTLINE, irq, 4); 84050974Swpaul } 84150974Swpaul 84250974Swpaul /* 84350974Swpaul * Map control/status registers. 84450974Swpaul */ 84572813Swpaul pci_enable_busmaster(dev); 84679472Swpaul pci_enable_io(dev, SYS_RES_IOPORT); 84779472Swpaul pci_enable_io(dev, SYS_RES_MEMORY); 84861041Speter command = pci_read_config(dev, PCIR_COMMAND, 4); 84950974Swpaul 85050974Swpaul#ifdef SIS_USEIOSPACE 85150974Swpaul if (!(command & PCIM_CMD_PORTEN)) { 85250974Swpaul printf("sis%d: failed to enable I/O ports!\n", unit); 85350974Swpaul error = ENXIO;; 85450974Swpaul goto fail; 85550974Swpaul } 85650974Swpaul#else 85750974Swpaul if (!(command & PCIM_CMD_MEMEN)) { 85850974Swpaul printf("sis%d: failed to enable memory mapping!\n", unit); 85950974Swpaul error = ENXIO;; 86050974Swpaul goto fail; 86150974Swpaul } 86250974Swpaul#endif 86350974Swpaul 86450974Swpaul rid = SIS_RID; 86550974Swpaul sc->sis_res = bus_alloc_resource(dev, SIS_RES, &rid, 86650974Swpaul 0, ~0, 1, RF_ACTIVE); 86750974Swpaul 86850974Swpaul if (sc->sis_res == NULL) { 86950974Swpaul printf("sis%d: couldn't map ports/memory\n", unit); 87050974Swpaul error = ENXIO; 87150974Swpaul goto fail; 87250974Swpaul } 87350974Swpaul 87450974Swpaul sc->sis_btag = rman_get_bustag(sc->sis_res); 87550974Swpaul sc->sis_bhandle = rman_get_bushandle(sc->sis_res); 87650974Swpaul 87750974Swpaul /* Allocate interrupt */ 87850974Swpaul rid = 0; 87950974Swpaul sc->sis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 88050974Swpaul RF_SHAREABLE | RF_ACTIVE); 88150974Swpaul 88250974Swpaul if (sc->sis_irq == NULL) { 88350974Swpaul printf("sis%d: couldn't map interrupt\n", unit); 88450974Swpaul bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 88550974Swpaul error = ENXIO; 88650974Swpaul goto fail; 88750974Swpaul } 88850974Swpaul 88950974Swpaul error = bus_setup_intr(dev, sc->sis_irq, INTR_TYPE_NET, 89050974Swpaul sis_intr, sc, &sc->sis_intrhand); 89150974Swpaul 89250974Swpaul if (error) { 89368216Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 89450974Swpaul bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 89550974Swpaul printf("sis%d: couldn't set up irq\n", unit); 89650974Swpaul goto fail; 89750974Swpaul } 89850974Swpaul 89950974Swpaul /* Reset the adapter. */ 90050974Swpaul sis_reset(sc); 90150974Swpaul 90250974Swpaul /* 90350974Swpaul * Get station address from the EEPROM. 90450974Swpaul */ 90562672Swpaul switch (pci_get_vendor(dev)) { 90662672Swpaul case NS_VENDORID: 90762672Swpaul /* 90862672Swpaul * Reading the MAC address out of the EEPROM on 90962672Swpaul * the NatSemi chip takes a bit more work than 91062672Swpaul * you'd expect. The address spans 4 16-bit words, 91162672Swpaul * with the first word containing only a single bit. 91262672Swpaul * You have to shift everything over one bit to 91362672Swpaul * get it aligned properly. Also, the bits are 91462672Swpaul * stored backwards (the LSB is really the MSB, 91562672Swpaul * and so on) so you have to reverse them in order 91662672Swpaul * to get the MAC address into the form we want. 91762672Swpaul * Why? Who the hell knows. 91862672Swpaul */ 91962672Swpaul { 92062672Swpaul u_int16_t tmp[4]; 92150974Swpaul 92262672Swpaul sis_read_eeprom(sc, (caddr_t)&tmp, 92362672Swpaul NS_EE_NODEADDR, 4, 0); 92462672Swpaul 92562672Swpaul /* Shift everything over one bit. */ 92662672Swpaul tmp[3] = tmp[3] >> 1; 92762681Swpaul tmp[3] |= tmp[2] << 15; 92862672Swpaul tmp[2] = tmp[2] >> 1; 92962681Swpaul tmp[2] |= tmp[1] << 15; 93062672Swpaul tmp[1] = tmp[1] >> 1; 93162681Swpaul tmp[1] |= tmp[0] << 15; 93262672Swpaul 93362672Swpaul /* Now reverse all the bits. */ 93462672Swpaul tmp[3] = sis_reverse(tmp[3]); 93562672Swpaul tmp[2] = sis_reverse(tmp[2]); 93662672Swpaul tmp[1] = sis_reverse(tmp[1]); 93762672Swpaul 93862672Swpaul bcopy((char *)&tmp[1], eaddr, ETHER_ADDR_LEN); 93962672Swpaul } 94062672Swpaul break; 94162672Swpaul case SIS_VENDORID: 94262672Swpaul default: 94372197Swpaul#ifdef __i386__ 94472197Swpaul /* 94572197Swpaul * If this is a SiS 630E chipset with an embedded 94672197Swpaul * SiS 900 controller, we have to read the MAC address 94772197Swpaul * from the APC CMOS RAM. Our method for doing this 94872197Swpaul * is very ugly since we have to reach out and grab 94972197Swpaul * ahold of hardware for which we cannot properly 95072197Swpaul * allocate resources. This code is only compiled on 95172197Swpaul * the i386 architecture since the SiS 630E chipset 95272197Swpaul * is for x86 motherboards only. Note that there are 95372197Swpaul * a lot of magic numbers in this hack. These are 95472197Swpaul * taken from SiS's Linux driver. I'd like to replace 95572197Swpaul * them with proper symbolic definitions, but that 95672197Swpaul * requires some datasheets that I don't have access 95772197Swpaul * to at the moment. 95872197Swpaul */ 95989296Swpaul if (sc->sis_rev == SIS_REV_630S || 96089296Swpaul sc->sis_rev == SIS_REV_630E || 96190328Sambrisko sc->sis_rev == SIS_REV_630EA1) 96272197Swpaul sis_read_cmos(sc, dev, (caddr_t)&eaddr, 0x9, 6); 96389296Swpaul 96490328Sambrisko else if (sc->sis_rev == SIS_REV_635 || 96590328Sambrisko sc->sis_rev == SIS_REV_630ET) 96689296Swpaul sis_read_mac(sc, dev, (caddr_t)&eaddr); 96772197Swpaul else 96872197Swpaul#endif 96972197Swpaul sis_read_eeprom(sc, (caddr_t)&eaddr, 97072197Swpaul SIS_EE_NODEADDR, 3, 0); 97162672Swpaul break; 97262672Swpaul } 97362672Swpaul 97450974Swpaul /* 97550974Swpaul * A SiS chip was detected. Inform the world. 97650974Swpaul */ 97750974Swpaul printf("sis%d: Ethernet address: %6D\n", unit, eaddr, ":"); 97850974Swpaul 97950974Swpaul sc->sis_unit = unit; 98050974Swpaul callout_handle_init(&sc->sis_stat_ch); 98150974Swpaul bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 98250974Swpaul 98381713Swpaul /* 98481713Swpaul * Allocate the parent bus DMA tag appropriate for PCI. 98581713Swpaul */ 98681713Swpaul#define SIS_NSEG_NEW 32 98781713Swpaul error = bus_dma_tag_create(NULL, /* parent */ 98881713Swpaul 1, 0, /* alignment, boundary */ 98981713Swpaul BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 99081713Swpaul BUS_SPACE_MAXADDR, /* highaddr */ 99181713Swpaul NULL, NULL, /* filter, filterarg */ 99281713Swpaul MAXBSIZE, SIS_NSEG_NEW, /* maxsize, nsegments */ 99381713Swpaul BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 99481713Swpaul BUS_DMA_ALLOCNOW, /* flags */ 99581713Swpaul &sc->sis_parent_tag); 99650974Swpaul 99781713Swpaul /* 99881713Swpaul * Now allocate a tag for the DMA descriptor lists. 99981713Swpaul * All of our lists are allocated as a contiguous block 100081713Swpaul * of memory. 100181713Swpaul */ 100281713Swpaul error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ 100381713Swpaul 1, 0, /* alignment, boundary */ 100481713Swpaul BUS_SPACE_MAXADDR, /* lowaddr */ 100581713Swpaul BUS_SPACE_MAXADDR, /* highaddr */ 100681713Swpaul NULL, NULL, /* filter, filterarg */ 100781713Swpaul SIS_RX_LIST_SZ, 1, /* maxsize,nsegments */ 100881713Swpaul BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 100981713Swpaul 0, /* flags */ 101081713Swpaul &sc->sis_ldata.sis_rx_tag); 101181713Swpaul 101281713Swpaul error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ 101381713Swpaul 1, 0, /* alignment, boundary */ 101481713Swpaul BUS_SPACE_MAXADDR, /* lowaddr */ 101581713Swpaul BUS_SPACE_MAXADDR, /* highaddr */ 101681713Swpaul NULL, NULL, /* filter, filterarg */ 101781713Swpaul SIS_TX_LIST_SZ, 1, /* maxsize,nsegments */ 101881713Swpaul BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 101981713Swpaul 0, /* flags */ 102081713Swpaul &sc->sis_ldata.sis_tx_tag); 102181713Swpaul 102281713Swpaul error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ 102381713Swpaul 1, 0, /* alignment, boundary */ 102481713Swpaul BUS_SPACE_MAXADDR, /* lowaddr */ 102581713Swpaul BUS_SPACE_MAXADDR, /* highaddr */ 102681713Swpaul NULL, NULL, /* filter, filterarg */ 102781713Swpaul SIS_TX_LIST_SZ, 1, /* maxsize,nsegments */ 102881713Swpaul BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 102981713Swpaul 0, /* flags */ 103081713Swpaul &sc->sis_tag); 103181713Swpaul 103281713Swpaul /* 103381713Swpaul * Now allocate a chunk of DMA-able memory based on the 103481713Swpaul * tag we just created. 103581713Swpaul */ 103681713Swpaul error = bus_dmamem_alloc(sc->sis_ldata.sis_tx_tag, 103781713Swpaul (void **)&sc->sis_ldata.sis_tx_list, BUS_DMA_NOWAIT, 103881713Swpaul &sc->sis_ldata.sis_tx_dmamap); 103981713Swpaul 104081713Swpaul if (error) { 104150974Swpaul printf("sis%d: no memory for list buffers!\n", unit); 104250974Swpaul bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); 104350974Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 104450974Swpaul bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 104581713Swpaul bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); 104681713Swpaul bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); 104750974Swpaul error = ENXIO; 104850974Swpaul goto fail; 104950974Swpaul } 105050974Swpaul 105181713Swpaul error = bus_dmamem_alloc(sc->sis_ldata.sis_rx_tag, 105281713Swpaul (void **)&sc->sis_ldata.sis_rx_list, BUS_DMA_NOWAIT, 105381713Swpaul &sc->sis_ldata.sis_rx_dmamap); 105481713Swpaul 105581713Swpaul if (error) { 105681713Swpaul printf("sis%d: no memory for list buffers!\n", unit); 105781713Swpaul bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); 105881713Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 105981713Swpaul bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 106081713Swpaul bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 106181713Swpaul sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); 106281713Swpaul bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); 106381713Swpaul bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); 106481713Swpaul error = ENXIO; 106581713Swpaul goto fail; 106681713Swpaul } 106781713Swpaul 106881713Swpaul 106981713Swpaul bzero(sc->sis_ldata.sis_tx_list, SIS_TX_LIST_SZ); 107081713Swpaul bzero(sc->sis_ldata.sis_rx_list, SIS_RX_LIST_SZ); 107181713Swpaul 107281713Swpaul /* 107381713Swpaul * Obtain the physical addresses of the RX and TX 107481713Swpaul * rings which we'll need later in the init routine. 107581713Swpaul */ 107681713Swpaul bus_dmamap_load(sc->sis_ldata.sis_tx_tag, 107781713Swpaul sc->sis_ldata.sis_tx_dmamap, &(sc->sis_ldata.sis_tx_list[0]), 107881713Swpaul sizeof(struct sis_desc), sis_dma_map_ring, 107981713Swpaul &sc->sis_cdata.sis_tx_paddr, 0); 108081713Swpaul bus_dmamap_load(sc->sis_ldata.sis_rx_tag, 108181713Swpaul sc->sis_ldata.sis_rx_dmamap, &(sc->sis_ldata.sis_rx_list[0]), 108281713Swpaul sizeof(struct sis_desc), sis_dma_map_ring, 108381713Swpaul &sc->sis_cdata.sis_rx_paddr, 0); 108481713Swpaul 108550974Swpaul ifp = &sc->arpcom.ac_if; 108650974Swpaul ifp->if_softc = sc; 108750974Swpaul ifp->if_unit = unit; 108850974Swpaul ifp->if_name = "sis"; 108950974Swpaul ifp->if_mtu = ETHERMTU; 109050974Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 109150974Swpaul ifp->if_ioctl = sis_ioctl; 109250974Swpaul ifp->if_output = ether_output; 109350974Swpaul ifp->if_start = sis_start; 109450974Swpaul ifp->if_watchdog = sis_watchdog; 109550974Swpaul ifp->if_init = sis_init; 109650974Swpaul ifp->if_baudrate = 10000000; 109750974Swpaul ifp->if_snd.ifq_maxlen = SIS_TX_LIST_CNT - 1; 109850974Swpaul 109950974Swpaul /* 110050974Swpaul * Do MII setup. 110150974Swpaul */ 110250974Swpaul if (mii_phy_probe(dev, &sc->sis_miibus, 110350974Swpaul sis_ifmedia_upd, sis_ifmedia_sts)) { 110450974Swpaul printf("sis%d: MII without any PHY!\n", sc->sis_unit); 110550974Swpaul bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); 110650974Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 110750974Swpaul bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 110881713Swpaul bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 110981713Swpaul sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap); 111081713Swpaul bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 111181713Swpaul sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); 111281713Swpaul bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); 111381713Swpaul bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); 111450974Swpaul error = ENXIO; 111550974Swpaul goto fail; 111650974Swpaul } 111750974Swpaul 111850974Swpaul /* 111963090Sarchie * Call MI attach routine. 112050974Swpaul */ 112163090Sarchie ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 112287390Sjhay 112387390Sjhay /* 112487390Sjhay * Tell the upper layer(s) we support long frames. 112587390Sjhay */ 112687390Sjhay ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 112787390Sjhay 112850974Swpaul callout_handle_init(&sc->sis_stat_ch); 112967087Swpaul SIS_UNLOCK(sc); 113067087Swpaul return(0); 113150974Swpaul 113250974Swpaulfail: 113367087Swpaul SIS_UNLOCK(sc); 113467087Swpaul mtx_destroy(&sc->sis_mtx); 113550974Swpaul return(error); 113650974Swpaul} 113750974Swpaul 113850974Swpaulstatic int sis_detach(dev) 113950974Swpaul device_t dev; 114050974Swpaul{ 114150974Swpaul struct sis_softc *sc; 114250974Swpaul struct ifnet *ifp; 114350974Swpaul 114450974Swpaul 114550974Swpaul sc = device_get_softc(dev); 114667087Swpaul SIS_LOCK(sc); 114750974Swpaul ifp = &sc->arpcom.ac_if; 114850974Swpaul 114950974Swpaul sis_reset(sc); 115050974Swpaul sis_stop(sc); 115163090Sarchie ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 115250974Swpaul 115350974Swpaul bus_generic_detach(dev); 115450974Swpaul device_delete_child(dev, sc->sis_miibus); 115550974Swpaul 115650974Swpaul bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); 115750974Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 115850974Swpaul bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 115950974Swpaul 116081713Swpaul bus_dmamap_unload(sc->sis_ldata.sis_rx_tag, 116181713Swpaul sc->sis_ldata.sis_rx_dmamap); 116281713Swpaul bus_dmamap_unload(sc->sis_ldata.sis_tx_tag, 116381713Swpaul sc->sis_ldata.sis_tx_dmamap); 116481713Swpaul bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 116581713Swpaul sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap); 116681713Swpaul bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 116781713Swpaul sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); 116881713Swpaul bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); 116981713Swpaul bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); 117081713Swpaul bus_dma_tag_destroy(sc->sis_parent_tag); 117150974Swpaul 117267087Swpaul SIS_UNLOCK(sc); 117367087Swpaul mtx_destroy(&sc->sis_mtx); 117450974Swpaul 117550974Swpaul return(0); 117650974Swpaul} 117750974Swpaul 117850974Swpaul/* 117950974Swpaul * Initialize the transmit descriptors. 118050974Swpaul */ 118150974Swpaulstatic int sis_list_tx_init(sc) 118250974Swpaul struct sis_softc *sc; 118350974Swpaul{ 118450974Swpaul struct sis_list_data *ld; 118550974Swpaul struct sis_ring_data *cd; 118687059Sluigi int i, nexti; 118750974Swpaul 118850974Swpaul cd = &sc->sis_cdata; 118981713Swpaul ld = &sc->sis_ldata; 119050974Swpaul 119150974Swpaul for (i = 0; i < SIS_TX_LIST_CNT; i++) { 119287102Sluigi nexti = (i == (SIS_TX_LIST_CNT - 1)) ? 0 : i+1; 119350974Swpaul ld->sis_tx_list[i].sis_nextdesc = 119487059Sluigi &ld->sis_tx_list[nexti]; 119581713Swpaul bus_dmamap_load(sc->sis_ldata.sis_tx_tag, 119681713Swpaul sc->sis_ldata.sis_tx_dmamap, 119787059Sluigi &ld->sis_tx_list[nexti], sizeof(struct sis_desc), 119881713Swpaul sis_dma_map_desc_next, &ld->sis_tx_list[i], 0); 119950974Swpaul ld->sis_tx_list[i].sis_mbuf = NULL; 120050974Swpaul ld->sis_tx_list[i].sis_ptr = 0; 120150974Swpaul ld->sis_tx_list[i].sis_ctl = 0; 120250974Swpaul } 120350974Swpaul 120450974Swpaul cd->sis_tx_prod = cd->sis_tx_cons = cd->sis_tx_cnt = 0; 120550974Swpaul 120681713Swpaul bus_dmamap_sync(sc->sis_ldata.sis_tx_tag, 120781713Swpaul sc->sis_ldata.sis_rx_dmamap, BUS_DMASYNC_PREWRITE); 120881713Swpaul 120950974Swpaul return(0); 121050974Swpaul} 121150974Swpaul 121250974Swpaul/* 121350974Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that 121450974Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor 121550974Swpaul * points back to the first. 121650974Swpaul */ 121750974Swpaulstatic int sis_list_rx_init(sc) 121850974Swpaul struct sis_softc *sc; 121950974Swpaul{ 122050974Swpaul struct sis_list_data *ld; 122150974Swpaul struct sis_ring_data *cd; 122287059Sluigi int i,nexti; 122350974Swpaul 122481713Swpaul ld = &sc->sis_ldata; 122550974Swpaul cd = &sc->sis_cdata; 122650974Swpaul 122750974Swpaul for (i = 0; i < SIS_RX_LIST_CNT; i++) { 122850974Swpaul if (sis_newbuf(sc, &ld->sis_rx_list[i], NULL) == ENOBUFS) 122950974Swpaul return(ENOBUFS); 123087102Sluigi nexti = (i == (SIS_RX_LIST_CNT - 1)) ? 0 : i+1; 123150974Swpaul ld->sis_rx_list[i].sis_nextdesc = 123287059Sluigi &ld->sis_rx_list[nexti]; 123381713Swpaul bus_dmamap_load(sc->sis_ldata.sis_rx_tag, 123481713Swpaul sc->sis_ldata.sis_rx_dmamap, 123587059Sluigi &ld->sis_rx_list[nexti], 123681713Swpaul sizeof(struct sis_desc), sis_dma_map_desc_next, 123781713Swpaul &ld->sis_rx_list[i], 0); 123850974Swpaul } 123950974Swpaul 124081713Swpaul bus_dmamap_sync(sc->sis_ldata.sis_rx_tag, 124181713Swpaul sc->sis_ldata.sis_rx_dmamap, BUS_DMASYNC_PREWRITE); 124281713Swpaul 124350974Swpaul cd->sis_rx_prod = 0; 124450974Swpaul 124550974Swpaul return(0); 124650974Swpaul} 124750974Swpaul 124850974Swpaul/* 124950974Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 125050974Swpaul */ 125150974Swpaulstatic int sis_newbuf(sc, c, m) 125250974Swpaul struct sis_softc *sc; 125350974Swpaul struct sis_desc *c; 125450974Swpaul struct mbuf *m; 125550974Swpaul{ 125650974Swpaul struct mbuf *m_new = NULL; 125750974Swpaul 125881713Swpaul if (c == NULL) 125981713Swpaul return(EINVAL); 126081713Swpaul 126150974Swpaul if (m == NULL) { 126250974Swpaul MGETHDR(m_new, M_DONTWAIT, MT_DATA); 126387330Sluigi if (m_new == NULL) 126450974Swpaul return(ENOBUFS); 126550974Swpaul 126650974Swpaul MCLGET(m_new, M_DONTWAIT); 126750974Swpaul if (!(m_new->m_flags & M_EXT)) { 126850974Swpaul m_freem(m_new); 126950974Swpaul return(ENOBUFS); 127050974Swpaul } 127150974Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 127250974Swpaul } else { 127350974Swpaul m_new = m; 127450974Swpaul m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 127550974Swpaul m_new->m_data = m_new->m_ext.ext_buf; 127650974Swpaul } 127750974Swpaul 127850974Swpaul m_adj(m_new, sizeof(u_int64_t)); 127950974Swpaul 128050974Swpaul c->sis_mbuf = m_new; 128150974Swpaul c->sis_ctl = SIS_RXLEN; 128250974Swpaul 128381713Swpaul bus_dmamap_create(sc->sis_tag, 0, &c->sis_map); 128481713Swpaul bus_dmamap_load(sc->sis_tag, c->sis_map, 128581713Swpaul mtod(m_new, void *), m_new->m_len, 128681713Swpaul sis_dma_map_desc_ptr, c, 0); 128781713Swpaul bus_dmamap_sync(sc->sis_tag, c->sis_map, BUS_DMASYNC_PREWRITE); 128881713Swpaul 128950974Swpaul return(0); 129050974Swpaul} 129150974Swpaul 129250974Swpaul/* 129350974Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 129450974Swpaul * the higher level protocols. 129550974Swpaul */ 129650974Swpaulstatic void sis_rxeof(sc) 129750974Swpaul struct sis_softc *sc; 129850974Swpaul{ 129950974Swpaul struct ether_header *eh; 130050974Swpaul struct mbuf *m; 130150974Swpaul struct ifnet *ifp; 130250974Swpaul struct sis_desc *cur_rx; 130350974Swpaul int i, total_len = 0; 130450974Swpaul u_int32_t rxstat; 130550974Swpaul 130650974Swpaul ifp = &sc->arpcom.ac_if; 130750974Swpaul i = sc->sis_cdata.sis_rx_prod; 130850974Swpaul 130981713Swpaul while(SIS_OWNDESC(&sc->sis_ldata.sis_rx_list[i])) { 131050974Swpaul 131187902Sluigi#ifdef DEVICE_POLLING 131287902Sluigi if (ifp->if_ipending & IFF_POLLING) { 131387902Sluigi if (sc->rxcycles <= 0) 131487902Sluigi break; 131587902Sluigi sc->rxcycles--; 131687902Sluigi } 131787902Sluigi#endif /* DEVICE_POLLING */ 131881713Swpaul cur_rx = &sc->sis_ldata.sis_rx_list[i]; 131950974Swpaul rxstat = cur_rx->sis_rxstat; 132081713Swpaul bus_dmamap_sync(sc->sis_tag, 132181713Swpaul cur_rx->sis_map, BUS_DMASYNC_POSTWRITE); 132281713Swpaul bus_dmamap_unload(sc->sis_tag, cur_rx->sis_map); 132381713Swpaul bus_dmamap_destroy(sc->sis_tag, cur_rx->sis_map); 132450974Swpaul m = cur_rx->sis_mbuf; 132550974Swpaul cur_rx->sis_mbuf = NULL; 132650974Swpaul total_len = SIS_RXBYTES(cur_rx); 132750974Swpaul SIS_INC(i, SIS_RX_LIST_CNT); 132850974Swpaul 132950974Swpaul /* 133050974Swpaul * If an error occurs, update stats, clear the 133150974Swpaul * status word and leave the mbuf cluster in place: 133250974Swpaul * it should simply get re-used next time this descriptor 133350974Swpaul * comes up in the ring. 133450974Swpaul */ 133550974Swpaul if (!(rxstat & SIS_CMDSTS_PKT_OK)) { 133650974Swpaul ifp->if_ierrors++; 133750974Swpaul if (rxstat & SIS_RXSTAT_COLL) 133850974Swpaul ifp->if_collisions++; 133950974Swpaul sis_newbuf(sc, cur_rx, m); 134050974Swpaul continue; 134150974Swpaul } 134250974Swpaul 134350974Swpaul /* No errors; receive the packet. */ 134487059Sluigi#ifdef __i386__ 134587059Sluigi /* 134687059Sluigi * On the x86 we do not have alignment problems, so try to 134787059Sluigi * allocate a new buffer for the receive ring, and pass up 134887059Sluigi * the one where the packet is already, saving the expensive 134987059Sluigi * copy done in m_devget(). 135087059Sluigi * If we are on an architecture with alignment problems, or 135187059Sluigi * if the allocation fails, then use m_devget and leave the 135287059Sluigi * existing buffer in the receive ring. 135387059Sluigi */ 135487059Sluigi if (sis_quick && sis_newbuf(sc, cur_rx, NULL) == 0) { 135587059Sluigi m->m_pkthdr.rcvif = ifp; 135687059Sluigi m->m_pkthdr.len = m->m_len = total_len; 135787059Sluigi } else 135887059Sluigi#endif 135987059Sluigi { 136087059Sluigi struct mbuf *m0; 136187059Sluigi m0 = m_devget(mtod(m, char *), total_len, 136287059Sluigi ETHER_ALIGN, ifp, NULL); 136387059Sluigi sis_newbuf(sc, cur_rx, m); 136487059Sluigi if (m0 == NULL) { 136587059Sluigi ifp->if_ierrors++; 136687059Sluigi continue; 136787059Sluigi } 136887059Sluigi m = m0; 136950974Swpaul } 137050974Swpaul 137150974Swpaul ifp->if_ipackets++; 137250974Swpaul eh = mtod(m, struct ether_header *); 137351583Swpaul 137450974Swpaul /* Remove header from mbuf and pass it on. */ 137550974Swpaul m_adj(m, sizeof(struct ether_header)); 137650974Swpaul ether_input(ifp, eh, m); 137750974Swpaul } 137850974Swpaul 137950974Swpaul sc->sis_cdata.sis_rx_prod = i; 138050974Swpaul 138150974Swpaul return; 138250974Swpaul} 138350974Swpaul 138450974Swpaulvoid sis_rxeoc(sc) 138550974Swpaul struct sis_softc *sc; 138650974Swpaul{ 138750974Swpaul sis_rxeof(sc); 138850974Swpaul sis_init(sc); 138950974Swpaul return; 139050974Swpaul} 139150974Swpaul 139250974Swpaul/* 139350974Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 139450974Swpaul * the list buffers. 139550974Swpaul */ 139650974Swpaul 139750974Swpaulstatic void sis_txeof(sc) 139850974Swpaul struct sis_softc *sc; 139950974Swpaul{ 140050974Swpaul struct sis_desc *cur_tx = NULL; 140150974Swpaul struct ifnet *ifp; 140250974Swpaul u_int32_t idx; 140350974Swpaul 140450974Swpaul ifp = &sc->arpcom.ac_if; 140550974Swpaul 140650974Swpaul /* Clear the timeout timer. */ 140750974Swpaul ifp->if_timer = 0; 140850974Swpaul 140950974Swpaul /* 141050974Swpaul * Go through our tx list and free mbufs for those 141150974Swpaul * frames that have been transmitted. 141250974Swpaul */ 141350974Swpaul idx = sc->sis_cdata.sis_tx_cons; 141450974Swpaul while (idx != sc->sis_cdata.sis_tx_prod) { 141581713Swpaul cur_tx = &sc->sis_ldata.sis_tx_list[idx]; 141650974Swpaul 141750974Swpaul if (SIS_OWNDESC(cur_tx)) 141850974Swpaul break; 141950974Swpaul 142050974Swpaul if (cur_tx->sis_ctl & SIS_CMDSTS_MORE) { 142150974Swpaul sc->sis_cdata.sis_tx_cnt--; 142250974Swpaul SIS_INC(idx, SIS_TX_LIST_CNT); 142350974Swpaul continue; 142450974Swpaul } 142550974Swpaul 142650974Swpaul if (!(cur_tx->sis_ctl & SIS_CMDSTS_PKT_OK)) { 142750974Swpaul ifp->if_oerrors++; 142850974Swpaul if (cur_tx->sis_txstat & SIS_TXSTAT_EXCESSCOLLS) 142950974Swpaul ifp->if_collisions++; 143050974Swpaul if (cur_tx->sis_txstat & SIS_TXSTAT_OUTOFWINCOLL) 143150974Swpaul ifp->if_collisions++; 143250974Swpaul } 143350974Swpaul 143450974Swpaul ifp->if_collisions += 143550974Swpaul (cur_tx->sis_txstat & SIS_TXSTAT_COLLCNT) >> 16; 143650974Swpaul 143750974Swpaul ifp->if_opackets++; 143850974Swpaul if (cur_tx->sis_mbuf != NULL) { 143950974Swpaul m_freem(cur_tx->sis_mbuf); 144050974Swpaul cur_tx->sis_mbuf = NULL; 144181713Swpaul bus_dmamap_unload(sc->sis_tag, cur_tx->sis_map); 144281713Swpaul bus_dmamap_destroy(sc->sis_tag, cur_tx->sis_map); 144350974Swpaul } 144450974Swpaul 144550974Swpaul sc->sis_cdata.sis_tx_cnt--; 144650974Swpaul SIS_INC(idx, SIS_TX_LIST_CNT); 144750974Swpaul ifp->if_timer = 0; 144850974Swpaul } 144950974Swpaul 145050974Swpaul sc->sis_cdata.sis_tx_cons = idx; 145150974Swpaul 145250974Swpaul if (cur_tx != NULL) 145350974Swpaul ifp->if_flags &= ~IFF_OACTIVE; 145450974Swpaul 145550974Swpaul return; 145650974Swpaul} 145750974Swpaul 145850974Swpaulstatic void sis_tick(xsc) 145950974Swpaul void *xsc; 146050974Swpaul{ 146150974Swpaul struct sis_softc *sc; 146250974Swpaul struct mii_data *mii; 146364963Swpaul struct ifnet *ifp; 146450974Swpaul 146550974Swpaul sc = xsc; 146667087Swpaul SIS_LOCK(sc); 146764963Swpaul ifp = &sc->arpcom.ac_if; 146864963Swpaul 146950974Swpaul mii = device_get_softc(sc->sis_miibus); 147050974Swpaul mii_tick(mii); 147164963Swpaul 147284147Sjlemon if (!sc->sis_link && mii->mii_media_status & IFM_ACTIVE && 147384147Sjlemon IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 147484147Sjlemon sc->sis_link++; 147584147Sjlemon if (ifp->if_snd.ifq_head != NULL) 147684147Sjlemon sis_start(ifp); 147764963Swpaul } 147864963Swpaul 147951031Swpaul sc->sis_stat_ch = timeout(sis_tick, sc, hz); 148050974Swpaul 148167087Swpaul SIS_UNLOCK(sc); 148250974Swpaul 148350974Swpaul return; 148450974Swpaul} 148550974Swpaul 148687902Sluigi#ifdef DEVICE_POLLING 148787902Sluigistatic poll_handler_t sis_poll; 148887902Sluigi 148987902Sluigistatic void 149087902Sluigisis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 149187902Sluigi{ 149287973Speter struct sis_softc *sc = ifp->if_softc; 149387973Speter 149487902Sluigi SIS_LOCK(sc); 149587902Sluigi if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ 149687902Sluigi CSR_WRITE_4(sc, SIS_IER, 1); 149787902Sluigi goto done; 149887902Sluigi } 149987902Sluigi 150087902Sluigi /* 150187902Sluigi * On the sis, reading the status register also clears it. 150287902Sluigi * So before returning to intr mode we must make sure that all 150387902Sluigi * possible pending sources of interrupts have been served. 150487902Sluigi * In practice this means run to completion the *eof routines, 150587902Sluigi * and then call the interrupt routine 150687902Sluigi */ 150787902Sluigi sc->rxcycles = count; 150887902Sluigi sis_rxeof(sc); 150987902Sluigi sis_txeof(sc); 151087902Sluigi if (ifp->if_snd.ifq_head != NULL) 151187902Sluigi sis_start(ifp); 151287902Sluigi 151387902Sluigi if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 151487902Sluigi u_int32_t status; 151587902Sluigi 151687902Sluigi /* Reading the ISR register clears all interrupts. */ 151787902Sluigi status = CSR_READ_4(sc, SIS_ISR); 151887902Sluigi 151987902Sluigi if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW)) 152087902Sluigi sis_rxeoc(sc); 152187902Sluigi 152287902Sluigi if (status & (SIS_ISR_RX_IDLE)) 152387902Sluigi SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 152487902Sluigi 152587902Sluigi if (status & SIS_ISR_SYSERR) { 152687902Sluigi sis_reset(sc); 152787902Sluigi sis_init(sc); 152887902Sluigi } 152987902Sluigi } 153087902Sluigidone: 153187902Sluigi SIS_UNLOCK(sc); 153287902Sluigi return; 153387902Sluigi} 153487902Sluigi#endif /* DEVICE_POLLING */ 153587902Sluigi 153650974Swpaulstatic void sis_intr(arg) 153750974Swpaul void *arg; 153850974Swpaul{ 153950974Swpaul struct sis_softc *sc; 154050974Swpaul struct ifnet *ifp; 154150974Swpaul u_int32_t status; 154250974Swpaul 154350974Swpaul sc = arg; 154450974Swpaul ifp = &sc->arpcom.ac_if; 154550974Swpaul 154686984Sluigi SIS_LOCK(sc); 154787902Sluigi#ifdef DEVICE_POLLING 154887902Sluigi if (ifp->if_ipending & IFF_POLLING) 154987902Sluigi goto done; 155087902Sluigi if (ether_poll_register(sis_poll, ifp)) { /* ok, disable interrupts */ 155187902Sluigi CSR_WRITE_4(sc, SIS_IER, 0); 155287902Sluigi goto done; 155387902Sluigi } 155487902Sluigi#endif /* DEVICE_POLLING */ 155587902Sluigi 155650974Swpaul /* Supress unwanted interrupts */ 155750974Swpaul if (!(ifp->if_flags & IFF_UP)) { 155850974Swpaul sis_stop(sc); 155986984Sluigi goto done; 156050974Swpaul } 156150974Swpaul 156250974Swpaul /* Disable interrupts. */ 156350974Swpaul CSR_WRITE_4(sc, SIS_IER, 0); 156450974Swpaul 156550974Swpaul for (;;) { 156650974Swpaul /* Reading the ISR register clears all interrupts. */ 156750974Swpaul status = CSR_READ_4(sc, SIS_ISR); 156850974Swpaul 156950974Swpaul if ((status & SIS_INTRS) == 0) 157050974Swpaul break; 157150974Swpaul 157286984Sluigi if (status & 157386984Sluigi (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR | 157486984Sluigi SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) ) 157550974Swpaul sis_txeof(sc); 157650974Swpaul 157786984Sluigi if (status & (SIS_ISR_RX_DESC_OK|SIS_ISR_RX_OK|SIS_ISR_RX_IDLE)) 157850974Swpaul sis_rxeof(sc); 157950974Swpaul 158086984Sluigi if (status & (SIS_ISR_RX_ERR | SIS_ISR_RX_OFLOW)) 158150974Swpaul sis_rxeoc(sc); 158250974Swpaul 158386984Sluigi if (status & (SIS_ISR_RX_IDLE)) 158486984Sluigi SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 158586984Sluigi 158650974Swpaul if (status & SIS_ISR_SYSERR) { 158750974Swpaul sis_reset(sc); 158850974Swpaul sis_init(sc); 158950974Swpaul } 159050974Swpaul } 159150974Swpaul 159250974Swpaul /* Re-enable interrupts. */ 159350974Swpaul CSR_WRITE_4(sc, SIS_IER, 1); 159450974Swpaul 159550974Swpaul if (ifp->if_snd.ifq_head != NULL) 159650974Swpaul sis_start(ifp); 159786984Sluigidone: 159867087Swpaul SIS_UNLOCK(sc); 159967087Swpaul 160050974Swpaul return; 160150974Swpaul} 160250974Swpaul 160350974Swpaul/* 160450974Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 160550974Swpaul * pointers to the fragment pointers. 160650974Swpaul */ 160750974Swpaulstatic int sis_encap(sc, m_head, txidx) 160850974Swpaul struct sis_softc *sc; 160950974Swpaul struct mbuf *m_head; 161050974Swpaul u_int32_t *txidx; 161150974Swpaul{ 161250974Swpaul struct sis_desc *f = NULL; 161350974Swpaul struct mbuf *m; 161450974Swpaul int frag, cur, cnt = 0; 161550974Swpaul 161650974Swpaul /* 161750974Swpaul * Start packing the mbufs in this chain into 161850974Swpaul * the fragment pointers. Stop when we run out 161950974Swpaul * of fragments or hit the end of the mbuf chain. 162050974Swpaul */ 162150974Swpaul m = m_head; 162250974Swpaul cur = frag = *txidx; 162350974Swpaul 162450974Swpaul for (m = m_head; m != NULL; m = m->m_next) { 162550974Swpaul if (m->m_len != 0) { 162651042Swpaul if ((SIS_TX_LIST_CNT - 162750974Swpaul (sc->sis_cdata.sis_tx_cnt + cnt)) < 2) 162850974Swpaul return(ENOBUFS); 162981713Swpaul f = &sc->sis_ldata.sis_tx_list[frag]; 163050974Swpaul f->sis_ctl = SIS_CMDSTS_MORE | m->m_len; 163181713Swpaul bus_dmamap_create(sc->sis_tag, 0, &f->sis_map); 163281713Swpaul bus_dmamap_load(sc->sis_tag, f->sis_map, 163381713Swpaul mtod(m, void *), m->m_len, 163481713Swpaul sis_dma_map_desc_ptr, f, 0); 163581713Swpaul bus_dmamap_sync(sc->sis_tag, 163681713Swpaul f->sis_map, BUS_DMASYNC_PREREAD); 163750974Swpaul if (cnt != 0) 163850974Swpaul f->sis_ctl |= SIS_CMDSTS_OWN; 163950974Swpaul cur = frag; 164050974Swpaul SIS_INC(frag, SIS_TX_LIST_CNT); 164150974Swpaul cnt++; 164250974Swpaul } 164350974Swpaul } 164450974Swpaul 164550974Swpaul if (m != NULL) 164650974Swpaul return(ENOBUFS); 164750974Swpaul 164881713Swpaul sc->sis_ldata.sis_tx_list[cur].sis_mbuf = m_head; 164981713Swpaul sc->sis_ldata.sis_tx_list[cur].sis_ctl &= ~SIS_CMDSTS_MORE; 165081713Swpaul sc->sis_ldata.sis_tx_list[*txidx].sis_ctl |= SIS_CMDSTS_OWN; 165150974Swpaul sc->sis_cdata.sis_tx_cnt += cnt; 165250974Swpaul *txidx = frag; 165350974Swpaul 165450974Swpaul return(0); 165550974Swpaul} 165650974Swpaul 165750974Swpaul/* 165850974Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers 165950974Swpaul * to the mbuf data regions directly in the transmit lists. We also save a 166050974Swpaul * copy of the pointers since the transmit list fragment pointers are 166150974Swpaul * physical addresses. 166250974Swpaul */ 166350974Swpaul 166450974Swpaulstatic void sis_start(ifp) 166550974Swpaul struct ifnet *ifp; 166650974Swpaul{ 166750974Swpaul struct sis_softc *sc; 166850974Swpaul struct mbuf *m_head = NULL; 166950974Swpaul u_int32_t idx; 167050974Swpaul 167150974Swpaul sc = ifp->if_softc; 167267087Swpaul SIS_LOCK(sc); 167350974Swpaul 167467087Swpaul if (!sc->sis_link) { 167567087Swpaul SIS_UNLOCK(sc); 167664963Swpaul return; 167767087Swpaul } 167864963Swpaul 167950974Swpaul idx = sc->sis_cdata.sis_tx_prod; 168050974Swpaul 168167087Swpaul if (ifp->if_flags & IFF_OACTIVE) { 168267087Swpaul SIS_UNLOCK(sc); 168350974Swpaul return; 168467087Swpaul } 168550974Swpaul 168681713Swpaul while(sc->sis_ldata.sis_tx_list[idx].sis_mbuf == NULL) { 168750974Swpaul IF_DEQUEUE(&ifp->if_snd, m_head); 168850974Swpaul if (m_head == NULL) 168950974Swpaul break; 169050974Swpaul 169150974Swpaul if (sis_encap(sc, m_head, &idx)) { 169250974Swpaul IF_PREPEND(&ifp->if_snd, m_head); 169350974Swpaul ifp->if_flags |= IFF_OACTIVE; 169450974Swpaul break; 169550974Swpaul } 169650974Swpaul 169750974Swpaul /* 169850974Swpaul * If there's a BPF listener, bounce a copy of this frame 169950974Swpaul * to him. 170050974Swpaul */ 170150974Swpaul if (ifp->if_bpf) 170250974Swpaul bpf_mtap(ifp, m_head); 170351583Swpaul 170450974Swpaul } 170550974Swpaul 170650974Swpaul /* Transmit */ 170750974Swpaul sc->sis_cdata.sis_tx_prod = idx; 170850974Swpaul SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE); 170950974Swpaul 171050974Swpaul /* 171150974Swpaul * Set a timeout in case the chip goes out to lunch. 171250974Swpaul */ 171350974Swpaul ifp->if_timer = 5; 171450974Swpaul 171567087Swpaul SIS_UNLOCK(sc); 171667087Swpaul 171750974Swpaul return; 171850974Swpaul} 171950974Swpaul 172050974Swpaulstatic void sis_init(xsc) 172150974Swpaul void *xsc; 172250974Swpaul{ 172350974Swpaul struct sis_softc *sc = xsc; 172450974Swpaul struct ifnet *ifp = &sc->arpcom.ac_if; 172550974Swpaul struct mii_data *mii; 172650974Swpaul 172767087Swpaul SIS_LOCK(sc); 172850974Swpaul 172950974Swpaul /* 173050974Swpaul * Cancel pending I/O and free all RX/TX buffers. 173150974Swpaul */ 173250974Swpaul sis_stop(sc); 173350974Swpaul 173450974Swpaul mii = device_get_softc(sc->sis_miibus); 173550974Swpaul 173650974Swpaul /* Set MAC address */ 173762672Swpaul if (sc->sis_type == SIS_TYPE_83815) { 173862672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); 173962672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_DATA, 174062672Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[0]); 174162672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); 174262672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_DATA, 174362672Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[1]); 174462672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); 174562672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_DATA, 174662672Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[2]); 174762672Swpaul } else { 174862672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 174962672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_DATA, 175062672Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[0]); 175162672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1); 175262672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_DATA, 175362672Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[1]); 175462672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 175562672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_DATA, 175662672Swpaul ((u_int16_t *)sc->arpcom.ac_enaddr)[2]); 175762672Swpaul } 175850974Swpaul 175950974Swpaul /* Init circular RX list. */ 176050974Swpaul if (sis_list_rx_init(sc) == ENOBUFS) { 176150974Swpaul printf("sis%d: initialization failed: no " 176250974Swpaul "memory for rx buffers\n", sc->sis_unit); 176350974Swpaul sis_stop(sc); 176467087Swpaul SIS_UNLOCK(sc); 176550974Swpaul return; 176650974Swpaul } 176750974Swpaul 176850974Swpaul /* 176950974Swpaul * Init tx descriptors. 177050974Swpaul */ 177150974Swpaul sis_list_tx_init(sc); 177250974Swpaul 177362672Swpaul /* 177462672Swpaul * For the NatSemi chip, we have to explicitly enable the 177562672Swpaul * reception of ARP frames, as well as turn on the 'perfect 177662672Swpaul * match' filter where we store the station address, otherwise 177762672Swpaul * we won't receive unicasts meant for this host. 177862672Swpaul */ 177962672Swpaul if (sc->sis_type == SIS_TYPE_83815) { 178062672Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_ARP); 178162672Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT); 178262672Swpaul } 178362672Swpaul 178450974Swpaul /* If we want promiscuous mode, set the allframes bit. */ 178550974Swpaul if (ifp->if_flags & IFF_PROMISC) { 178650974Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS); 178750974Swpaul } else { 178850974Swpaul SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS); 178950974Swpaul } 179050974Swpaul 179150974Swpaul /* 179250974Swpaul * Set the capture broadcast bit to capture broadcast frames. 179350974Swpaul */ 179450974Swpaul if (ifp->if_flags & IFF_BROADCAST) { 179550974Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD); 179650974Swpaul } else { 179750974Swpaul SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD); 179850974Swpaul } 179950974Swpaul 180050974Swpaul /* 180150974Swpaul * Load the multicast filter. 180250974Swpaul */ 180362672Swpaul if (sc->sis_type == SIS_TYPE_83815) 180462672Swpaul sis_setmulti_ns(sc); 180562672Swpaul else 180662672Swpaul sis_setmulti_sis(sc); 180750974Swpaul 180850974Swpaul /* Turn the receive filter on */ 180950974Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE); 181050974Swpaul 181150974Swpaul /* 181250974Swpaul * Load the address of the RX and TX lists. 181350974Swpaul */ 181481713Swpaul CSR_WRITE_4(sc, SIS_RX_LISTPTR, sc->sis_cdata.sis_rx_paddr); 181581713Swpaul CSR_WRITE_4(sc, SIS_TX_LISTPTR, sc->sis_cdata.sis_tx_paddr); 181650974Swpaul 181750974Swpaul /* Set RX configuration */ 181850974Swpaul CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG); 181964963Swpaul 182087390Sjhay /* Accept Long Packets for VLAN support */ 182187390Sjhay SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER); 182287390Sjhay 182350974Swpaul /* Set TX configuration */ 182464963Swpaul if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { 182564963Swpaul CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10); 182664963Swpaul } else { 182764963Swpaul CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); 182864963Swpaul } 182950974Swpaul 183064963Swpaul /* Set full/half duplex mode. */ 183164963Swpaul if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 183264963Swpaul SIS_SETBIT(sc, SIS_TX_CFG, 183364963Swpaul (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR)); 183464963Swpaul SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); 183564963Swpaul } else { 183664963Swpaul SIS_CLRBIT(sc, SIS_TX_CFG, 183764963Swpaul (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR)); 183864963Swpaul SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); 183964963Swpaul } 184064963Swpaul 184150974Swpaul /* 184250974Swpaul * Enable interrupts. 184350974Swpaul */ 184450974Swpaul CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS); 184587902Sluigi#ifdef DEVICE_POLLING 184687902Sluigi /* 184787902Sluigi * ... only enable interrupts if we are not polling, make sure 184887902Sluigi * they are off otherwise. 184987902Sluigi */ 185087902Sluigi if (ifp->if_ipending & IFF_POLLING) 185187902Sluigi CSR_WRITE_4(sc, SIS_IER, 0); 185287902Sluigi else 185387902Sluigi#endif /* DEVICE_POLLING */ 185450974Swpaul CSR_WRITE_4(sc, SIS_IER, 1); 185550974Swpaul 185650974Swpaul /* Enable receiver and transmitter. */ 185750974Swpaul SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE); 185850974Swpaul SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 185950974Swpaul 186064963Swpaul#ifdef notdef 186150974Swpaul mii_mediachg(mii); 186264963Swpaul#endif 186350974Swpaul 186464963Swpaul /* 186564963Swpaul * Page 75 of the DP83815 manual recommends the 186664963Swpaul * following register settings "for optimum 186764963Swpaul * performance." Note however that at least three 186864963Swpaul * of the registers are listed as "reserved" in 186964963Swpaul * the register map, so who knows what they do. 187064963Swpaul */ 187164963Swpaul if (sc->sis_type == SIS_TYPE_83815) { 187264963Swpaul CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); 187364963Swpaul CSR_WRITE_4(sc, NS_PHY_CR, 0x189C); 187464963Swpaul CSR_WRITE_4(sc, NS_PHY_TDATA, 0x0000); 187564963Swpaul CSR_WRITE_4(sc, NS_PHY_DSPCFG, 0x5040); 187664963Swpaul CSR_WRITE_4(sc, NS_PHY_SDCFG, 0x008C); 187764963Swpaul } 187864963Swpaul 187950974Swpaul ifp->if_flags |= IFF_RUNNING; 188050974Swpaul ifp->if_flags &= ~IFF_OACTIVE; 188150974Swpaul 188250974Swpaul sc->sis_stat_ch = timeout(sis_tick, sc, hz); 188350974Swpaul 188467087Swpaul SIS_UNLOCK(sc); 188567087Swpaul 188650974Swpaul return; 188750974Swpaul} 188850974Swpaul 188950974Swpaul/* 189050974Swpaul * Set media options. 189150974Swpaul */ 189250974Swpaulstatic int sis_ifmedia_upd(ifp) 189350974Swpaul struct ifnet *ifp; 189450974Swpaul{ 189550974Swpaul struct sis_softc *sc; 189664963Swpaul struct mii_data *mii; 189750974Swpaul 189850974Swpaul sc = ifp->if_softc; 189950974Swpaul 190064963Swpaul mii = device_get_softc(sc->sis_miibus); 190164963Swpaul sc->sis_link = 0; 190264963Swpaul if (mii->mii_instance) { 190364963Swpaul struct mii_softc *miisc; 190472012Sphk LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 190564963Swpaul mii_phy_reset(miisc); 190664963Swpaul } 190764963Swpaul mii_mediachg(mii); 190850974Swpaul 190950974Swpaul return(0); 191050974Swpaul} 191150974Swpaul 191250974Swpaul/* 191350974Swpaul * Report current media status. 191450974Swpaul */ 191550974Swpaulstatic void sis_ifmedia_sts(ifp, ifmr) 191650974Swpaul struct ifnet *ifp; 191750974Swpaul struct ifmediareq *ifmr; 191850974Swpaul{ 191950974Swpaul struct sis_softc *sc; 192050974Swpaul struct mii_data *mii; 192150974Swpaul 192250974Swpaul sc = ifp->if_softc; 192350974Swpaul 192450974Swpaul mii = device_get_softc(sc->sis_miibus); 192550974Swpaul mii_pollstat(mii); 192650974Swpaul ifmr->ifm_active = mii->mii_media_active; 192750974Swpaul ifmr->ifm_status = mii->mii_media_status; 192850974Swpaul 192950974Swpaul return; 193050974Swpaul} 193150974Swpaul 193250974Swpaulstatic int sis_ioctl(ifp, command, data) 193350974Swpaul struct ifnet *ifp; 193450974Swpaul u_long command; 193550974Swpaul caddr_t data; 193650974Swpaul{ 193750974Swpaul struct sis_softc *sc = ifp->if_softc; 193850974Swpaul struct ifreq *ifr = (struct ifreq *) data; 193950974Swpaul struct mii_data *mii; 194067087Swpaul int error = 0; 194150974Swpaul 194250974Swpaul switch(command) { 194350974Swpaul case SIOCSIFADDR: 194450974Swpaul case SIOCGIFADDR: 194550974Swpaul case SIOCSIFMTU: 194650974Swpaul error = ether_ioctl(ifp, command, data); 194750974Swpaul break; 194850974Swpaul case SIOCSIFFLAGS: 194950974Swpaul if (ifp->if_flags & IFF_UP) { 195050974Swpaul sis_init(sc); 195150974Swpaul } else { 195250974Swpaul if (ifp->if_flags & IFF_RUNNING) 195350974Swpaul sis_stop(sc); 195450974Swpaul } 195550974Swpaul error = 0; 195650974Swpaul break; 195750974Swpaul case SIOCADDMULTI: 195850974Swpaul case SIOCDELMULTI: 195981713Swpaul SIS_LOCK(sc); 196062672Swpaul if (sc->sis_type == SIS_TYPE_83815) 196162672Swpaul sis_setmulti_ns(sc); 196262672Swpaul else 196362672Swpaul sis_setmulti_sis(sc); 196481713Swpaul SIS_UNLOCK(sc); 196550974Swpaul error = 0; 196650974Swpaul break; 196750974Swpaul case SIOCGIFMEDIA: 196850974Swpaul case SIOCSIFMEDIA: 196950974Swpaul mii = device_get_softc(sc->sis_miibus); 197081713Swpaul SIS_LOCK(sc); 197150974Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 197281713Swpaul SIS_UNLOCK(sc); 197350974Swpaul break; 197450974Swpaul default: 197550974Swpaul error = EINVAL; 197650974Swpaul break; 197750974Swpaul } 197850974Swpaul 197950974Swpaul return(error); 198050974Swpaul} 198150974Swpaul 198250974Swpaulstatic void sis_watchdog(ifp) 198350974Swpaul struct ifnet *ifp; 198450974Swpaul{ 198550974Swpaul struct sis_softc *sc; 198650974Swpaul 198750974Swpaul sc = ifp->if_softc; 198850974Swpaul 198967087Swpaul SIS_LOCK(sc); 199067087Swpaul 199150974Swpaul ifp->if_oerrors++; 199250974Swpaul printf("sis%d: watchdog timeout\n", sc->sis_unit); 199350974Swpaul 199450974Swpaul sis_stop(sc); 199550974Swpaul sis_reset(sc); 199650974Swpaul sis_init(sc); 199750974Swpaul 199850974Swpaul if (ifp->if_snd.ifq_head != NULL) 199950974Swpaul sis_start(ifp); 200050974Swpaul 200167087Swpaul SIS_UNLOCK(sc); 200267087Swpaul 200350974Swpaul return; 200450974Swpaul} 200550974Swpaul 200650974Swpaul/* 200750974Swpaul * Stop the adapter and free any mbufs allocated to the 200850974Swpaul * RX and TX lists. 200950974Swpaul */ 201050974Swpaulstatic void sis_stop(sc) 201150974Swpaul struct sis_softc *sc; 201250974Swpaul{ 201350974Swpaul register int i; 201450974Swpaul struct ifnet *ifp; 201550974Swpaul 201667087Swpaul SIS_LOCK(sc); 201750974Swpaul ifp = &sc->arpcom.ac_if; 201850974Swpaul ifp->if_timer = 0; 201950974Swpaul 202050974Swpaul untimeout(sis_tick, sc, sc->sis_stat_ch); 202187472Speter 202287472Speter ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 202387902Sluigi#ifdef DEVICE_POLLING 202487902Sluigi ether_poll_deregister(ifp); 202587902Sluigi#endif 202650974Swpaul CSR_WRITE_4(sc, SIS_IER, 0); 202750974Swpaul CSR_WRITE_4(sc, SIS_IMR, 0); 202850974Swpaul SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE); 202950974Swpaul DELAY(1000); 203050974Swpaul CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0); 203150974Swpaul CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); 203250974Swpaul 203364963Swpaul sc->sis_link = 0; 203464963Swpaul 203550974Swpaul /* 203650974Swpaul * Free data in the RX lists. 203750974Swpaul */ 203850974Swpaul for (i = 0; i < SIS_RX_LIST_CNT; i++) { 203981713Swpaul if (sc->sis_ldata.sis_rx_list[i].sis_mbuf != NULL) { 204081713Swpaul bus_dmamap_unload(sc->sis_tag, 204181713Swpaul sc->sis_ldata.sis_rx_list[i].sis_map); 204281713Swpaul bus_dmamap_destroy(sc->sis_tag, 204381713Swpaul sc->sis_ldata.sis_rx_list[i].sis_map); 204481713Swpaul m_freem(sc->sis_ldata.sis_rx_list[i].sis_mbuf); 204581713Swpaul sc->sis_ldata.sis_rx_list[i].sis_mbuf = NULL; 204650974Swpaul } 204750974Swpaul } 204881713Swpaul bzero(sc->sis_ldata.sis_rx_list, 204981713Swpaul sizeof(sc->sis_ldata.sis_rx_list)); 205050974Swpaul 205150974Swpaul /* 205250974Swpaul * Free the TX list buffers. 205350974Swpaul */ 205450974Swpaul for (i = 0; i < SIS_TX_LIST_CNT; i++) { 205581713Swpaul if (sc->sis_ldata.sis_tx_list[i].sis_mbuf != NULL) { 205681713Swpaul bus_dmamap_unload(sc->sis_tag, 205781713Swpaul sc->sis_ldata.sis_tx_list[i].sis_map); 205881713Swpaul bus_dmamap_destroy(sc->sis_tag, 205981713Swpaul sc->sis_ldata.sis_tx_list[i].sis_map); 206081713Swpaul m_freem(sc->sis_ldata.sis_tx_list[i].sis_mbuf); 206181713Swpaul sc->sis_ldata.sis_tx_list[i].sis_mbuf = NULL; 206250974Swpaul } 206350974Swpaul } 206450974Swpaul 206581713Swpaul bzero(sc->sis_ldata.sis_tx_list, 206681713Swpaul sizeof(sc->sis_ldata.sis_tx_list)); 206750974Swpaul 206867087Swpaul SIS_UNLOCK(sc); 206967087Swpaul 207050974Swpaul return; 207150974Swpaul} 207250974Swpaul 207350974Swpaul/* 207450974Swpaul * Stop all chip I/O so that the kernel's probe routines don't 207550974Swpaul * get confused by errant DMAs when rebooting. 207650974Swpaul */ 207750974Swpaulstatic void sis_shutdown(dev) 207850974Swpaul device_t dev; 207950974Swpaul{ 208050974Swpaul struct sis_softc *sc; 208150974Swpaul 208250974Swpaul sc = device_get_softc(dev); 208367087Swpaul SIS_LOCK(sc); 208450974Swpaul sis_reset(sc); 208550974Swpaul sis_stop(sc); 208667087Swpaul SIS_UNLOCK(sc); 208750974Swpaul 208850974Swpaul return; 208950974Swpaul} 2090