1139825Simp/*- 2139740Sphk * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org> 350974Swpaul * Copyright (c) 1997, 1998, 1999 450974Swpaul * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 550974Swpaul * 650974Swpaul * Redistribution and use in source and binary forms, with or without 750974Swpaul * modification, are permitted provided that the following conditions 850974Swpaul * are met: 950974Swpaul * 1. Redistributions of source code must retain the above copyright 1050974Swpaul * notice, this list of conditions and the following disclaimer. 1150974Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1250974Swpaul * notice, this list of conditions and the following disclaimer in the 1350974Swpaul * documentation and/or other materials provided with the distribution. 1450974Swpaul * 3. All advertising materials mentioning features or use of this software 1550974Swpaul * must display the following acknowledgement: 1650974Swpaul * This product includes software developed by Bill Paul. 1750974Swpaul * 4. Neither the name of the author nor the names of any co-contributors 1850974Swpaul * may be used to endorse or promote products derived from this software 1950974Swpaul * without specific prior written permission. 2050974Swpaul * 2150974Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2250974Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2350974Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2450974Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2550974Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2650974Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2750974Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2850974Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2950974Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3050974Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3150974Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3250974Swpaul */ 3350974Swpaul 34122678Sobrien#include <sys/cdefs.h> 35122678Sobrien__FBSDID("$FreeBSD$"); 36122678Sobrien 3750974Swpaul/* 3850974Swpaul * SiS 900/SiS 7016 fast ethernet PCI NIC driver. Datasheets are 3950974Swpaul * available from http://www.sis.com.tw. 4050974Swpaul * 4164963Swpaul * This driver also supports the NatSemi DP83815. Datasheets are 4264963Swpaul * available from http://www.national.com. 4364963Swpaul * 4450974Swpaul * Written by Bill Paul <wpaul@ee.columbia.edu> 4550974Swpaul * Electrical Engineering Department 4650974Swpaul * Columbia University, New York City 4750974Swpaul */ 4850974Swpaul/* 4950974Swpaul * The SiS 900 is a fairly simple chip. It uses bus master DMA with 5050974Swpaul * simple TX and RX descriptors of 3 longwords in size. The receiver 5150974Swpaul * has a single perfect filter entry for the station address and a 5250974Swpaul * 128-bit multicast hash table. The SiS 900 has a built-in MII-based 5350974Swpaul * transceiver while the 7016 requires an external transceiver chip. 5450974Swpaul * Both chips offer the standard bit-bang MII interface as well as 5550974Swpaul * an enchanced PHY interface which simplifies accessing MII registers. 5650974Swpaul * 5750974Swpaul * The only downside to this chipset is that RX descriptors must be 5850974Swpaul * longword aligned. 5950974Swpaul */ 6050974Swpaul 61150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS 62150968Sglebius#include "opt_device_polling.h" 63150968Sglebius#endif 64150968Sglebius 6550974Swpaul#include <sys/param.h> 6650974Swpaul#include <sys/systm.h> 67212109Syongari#include <sys/bus.h> 68212109Syongari#include <sys/endian.h> 69212109Syongari#include <sys/kernel.h> 70212109Syongari#include <sys/lock.h> 71212109Syongari#include <sys/malloc.h> 7250974Swpaul#include <sys/mbuf.h> 73129876Sphk#include <sys/module.h> 7450974Swpaul#include <sys/socket.h> 75212109Syongari#include <sys/sockio.h> 76212157Syongari#include <sys/sysctl.h> 7750974Swpaul 7850974Swpaul#include <net/if.h> 7950974Swpaul#include <net/if_arp.h> 8050974Swpaul#include <net/ethernet.h> 8150974Swpaul#include <net/if_dl.h> 8250974Swpaul#include <net/if_media.h> 8387390Sjhay#include <net/if_types.h> 8487390Sjhay#include <net/if_vlan_var.h> 8550974Swpaul 8650974Swpaul#include <net/bpf.h> 8750974Swpaul 8850974Swpaul#include <machine/bus.h> 8950974Swpaul#include <machine/resource.h> 9050974Swpaul#include <sys/rman.h> 9150974Swpaul 9250974Swpaul#include <dev/mii/mii.h> 93226995Smarius#include <dev/mii/mii_bitbang.h> 9450974Swpaul#include <dev/mii/miivar.h> 9550974Swpaul 96119288Simp#include <dev/pci/pcireg.h> 97119288Simp#include <dev/pci/pcivar.h> 9850974Swpaul 9950974Swpaul#define SIS_USEIOSPACE 10050974Swpaul 101181524Simp#include <dev/sis/if_sisreg.h> 10250974Swpaul 103113506SmdoddMODULE_DEPEND(sis, pci, 1, 1, 1); 104113506SmdoddMODULE_DEPEND(sis, ether, 1, 1, 1); 10559758SpeterMODULE_DEPEND(sis, miibus, 1, 1, 1); 10659758Speter 107151545Simp/* "device miibus" required. See GENERIC if you get errors here. */ 10850974Swpaul#include "miibus_if.h" 10950974Swpaul 110150369Sphk#define SIS_LOCK(_sc) mtx_lock(&(_sc)->sis_mtx) 111150369Sphk#define SIS_UNLOCK(_sc) mtx_unlock(&(_sc)->sis_mtx) 112150369Sphk#define SIS_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sis_mtx, MA_OWNED) 113150369Sphk 11450974Swpaul/* 115150369Sphk * register space access macros 116150369Sphk */ 117150526Sphk#define CSR_WRITE_4(sc, reg, val) bus_write_4(sc->sis_res[0], reg, val) 118150369Sphk 119150526Sphk#define CSR_READ_4(sc, reg) bus_read_4(sc->sis_res[0], reg) 120150369Sphk 121150526Sphk#define CSR_READ_2(sc, reg) bus_read_2(sc->sis_res[0], reg) 122150369Sphk 123226995Smarius#define CSR_BARRIER(sc, reg, length, flags) \ 124226995Smarius bus_barrier(sc->sis_res[0], reg, length, flags) 125226995Smarius 126150369Sphk/* 12750974Swpaul * Various supported device vendors/types and their names. 12850974Swpaul */ 129242625Sdimstatic const struct sis_type sis_devs[] = { 13050974Swpaul { SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" }, 13150974Swpaul { SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" }, 132119712Sphk { NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP8381[56] 10/100BaseTX" }, 13350974Swpaul { 0, 0, NULL } 13450974Swpaul}; 13550974Swpaul 136139801Sphkstatic int sis_detach(device_t); 137212109Syongaristatic __inline void sis_discard_rxbuf(struct sis_rxdesc *); 138212109Syongaristatic int sis_dma_alloc(struct sis_softc *); 139212109Syongaristatic void sis_dma_free(struct sis_softc *); 140212109Syongaristatic int sis_dma_ring_alloc(struct sis_softc *, bus_size_t, bus_size_t, 141212109Syongari bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *); 142212109Syongaristatic void sis_dmamap_cb(void *, bus_dma_segment_t *, int, int); 143212109Syongari#ifndef __NO_STRICT_ALIGNMENT 144212109Syongaristatic __inline void sis_fixup_rx(struct mbuf *); 145212109Syongari#endif 146139801Sphkstatic void sis_ifmedia_sts(struct ifnet *, struct ifmediareq *); 147139801Sphkstatic int sis_ifmedia_upd(struct ifnet *); 148139801Sphkstatic void sis_init(void *); 149139801Sphkstatic void sis_initl(struct sis_softc *); 150139801Sphkstatic void sis_intr(void *); 151139801Sphkstatic int sis_ioctl(struct ifnet *, u_long, caddr_t); 152226995Smariusstatic uint32_t sis_mii_bitbang_read(device_t); 153226995Smariusstatic void sis_mii_bitbang_write(device_t, uint32_t); 154212109Syongaristatic int sis_newbuf(struct sis_softc *, struct sis_rxdesc *); 155212167Syongaristatic int sis_resume(device_t); 156212109Syongaristatic int sis_rxeof(struct sis_softc *); 157217548Syongaristatic void sis_rxfilter(struct sis_softc *); 158217548Syongaristatic void sis_rxfilter_ns(struct sis_softc *); 159217548Syongaristatic void sis_rxfilter_sis(struct sis_softc *); 160139801Sphkstatic void sis_start(struct ifnet *); 161139801Sphkstatic void sis_startl(struct ifnet *); 162139801Sphkstatic void sis_stop(struct sis_softc *); 163212167Syongaristatic int sis_suspend(device_t); 164212157Syongaristatic void sis_add_sysctls(struct sis_softc *); 165166940Sdelphijstatic void sis_watchdog(struct sis_softc *); 166212167Syongaristatic void sis_wol(struct sis_softc *); 16750974Swpaul 168226995Smarius/* 169226995Smarius * MII bit-bang glue 170226995Smarius */ 171226995Smariusstatic const struct mii_bitbang_ops sis_mii_bitbang_ops = { 172226995Smarius sis_mii_bitbang_read, 173226995Smarius sis_mii_bitbang_write, 174226995Smarius { 175226995Smarius SIS_MII_DATA, /* MII_BIT_MDO */ 176226995Smarius SIS_MII_DATA, /* MII_BIT_MDI */ 177226995Smarius SIS_MII_CLK, /* MII_BIT_MDC */ 178226995Smarius SIS_MII_DIR, /* MII_BIT_DIR_HOST_PHY */ 179226995Smarius 0, /* MII_BIT_DIR_PHY_HOST */ 180226995Smarius } 181226995Smarius}; 182150526Sphk 183150526Sphkstatic struct resource_spec sis_res_spec[] = { 18450974Swpaul#ifdef SIS_USEIOSPACE 185150526Sphk { SYS_RES_IOPORT, SIS_PCI_LOIO, RF_ACTIVE}, 18650974Swpaul#else 187150526Sphk { SYS_RES_MEMORY, SIS_PCI_LOMEM, RF_ACTIVE}, 18850974Swpaul#endif 189150526Sphk { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE}, 190150526Sphk { -1, 0 } 191150526Sphk}; 19250974Swpaul 19350974Swpaul#define SIS_SETBIT(sc, reg, x) \ 19450974Swpaul CSR_WRITE_4(sc, reg, \ 19550974Swpaul CSR_READ_4(sc, reg) | (x)) 19650974Swpaul 19750974Swpaul#define SIS_CLRBIT(sc, reg, x) \ 19850974Swpaul CSR_WRITE_4(sc, reg, \ 19950974Swpaul CSR_READ_4(sc, reg) & ~(x)) 20050974Swpaul 20150974Swpaul#define SIO_SET(x) \ 20250974Swpaul CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) | x) 20350974Swpaul 20450974Swpaul#define SIO_CLR(x) \ 20550974Swpaul CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x) 20650974Swpaul 20762672Swpaul/* 20862672Swpaul * Routine to reverse the bits in a word. Stolen almost 20962672Swpaul * verbatim from /usr/games/fortune. 21062672Swpaul */ 211139740Sphkstatic uint16_t 212139740Sphksis_reverse(uint16_t n) 21362672Swpaul{ 21462672Swpaul n = ((n >> 1) & 0x5555) | ((n << 1) & 0xaaaa); 21562672Swpaul n = ((n >> 2) & 0x3333) | ((n << 2) & 0xcccc); 21662672Swpaul n = ((n >> 4) & 0x0f0f) | ((n << 4) & 0xf0f0); 21762672Swpaul n = ((n >> 8) & 0x00ff) | ((n << 8) & 0xff00); 21862672Swpaul 219212104Syongari return (n); 22062672Swpaul} 22162672Swpaul 222102334Salfredstatic void 223139740Sphksis_delay(struct sis_softc *sc) 22450974Swpaul{ 22550974Swpaul int idx; 22650974Swpaul 22750974Swpaul for (idx = (300 / 33) + 1; idx > 0; idx--) 22850974Swpaul CSR_READ_4(sc, SIS_CSR); 22950974Swpaul} 23050974Swpaul 231102334Salfredstatic void 232139740Sphksis_eeprom_idle(struct sis_softc *sc) 23350974Swpaul{ 234139708Sphk int i; 23550974Swpaul 23650974Swpaul SIO_SET(SIS_EECTL_CSEL); 23750974Swpaul sis_delay(sc); 23850974Swpaul SIO_SET(SIS_EECTL_CLK); 23950974Swpaul sis_delay(sc); 24050974Swpaul 24150974Swpaul for (i = 0; i < 25; i++) { 24250974Swpaul SIO_CLR(SIS_EECTL_CLK); 24350974Swpaul sis_delay(sc); 24450974Swpaul SIO_SET(SIS_EECTL_CLK); 24550974Swpaul sis_delay(sc); 24650974Swpaul } 24750974Swpaul 24850974Swpaul SIO_CLR(SIS_EECTL_CLK); 24950974Swpaul sis_delay(sc); 25050974Swpaul SIO_CLR(SIS_EECTL_CSEL); 25150974Swpaul sis_delay(sc); 25250974Swpaul CSR_WRITE_4(sc, SIS_EECTL, 0x00000000); 25350974Swpaul} 25450974Swpaul 25550974Swpaul/* 25650974Swpaul * Send a read command and address to the EEPROM, check for ACK. 25750974Swpaul */ 258102334Salfredstatic void 259139740Sphksis_eeprom_putbyte(struct sis_softc *sc, int addr) 26050974Swpaul{ 261139708Sphk int d, i; 26250974Swpaul 26350974Swpaul d = addr | SIS_EECMD_READ; 26450974Swpaul 26550974Swpaul /* 26650974Swpaul * Feed in each bit and stobe the clock. 26750974Swpaul */ 26850974Swpaul for (i = 0x400; i; i >>= 1) { 26950974Swpaul if (d & i) { 27050974Swpaul SIO_SET(SIS_EECTL_DIN); 27150974Swpaul } else { 27250974Swpaul SIO_CLR(SIS_EECTL_DIN); 27350974Swpaul } 27450974Swpaul sis_delay(sc); 27550974Swpaul SIO_SET(SIS_EECTL_CLK); 27650974Swpaul sis_delay(sc); 27750974Swpaul SIO_CLR(SIS_EECTL_CLK); 27850974Swpaul sis_delay(sc); 27950974Swpaul } 28050974Swpaul} 28150974Swpaul 28250974Swpaul/* 28350974Swpaul * Read a word of data stored in the EEPROM at address 'addr.' 28450974Swpaul */ 285102334Salfredstatic void 286139740Sphksis_eeprom_getword(struct sis_softc *sc, int addr, uint16_t *dest) 28750974Swpaul{ 288139708Sphk int i; 289212113Syongari uint16_t word = 0; 29050974Swpaul 29150974Swpaul /* Force EEPROM to idle state. */ 29250974Swpaul sis_eeprom_idle(sc); 29350974Swpaul 29450974Swpaul /* Enter EEPROM access mode. */ 29550974Swpaul sis_delay(sc); 29662672Swpaul SIO_CLR(SIS_EECTL_CLK); 29762672Swpaul sis_delay(sc); 29850974Swpaul SIO_SET(SIS_EECTL_CSEL); 29950974Swpaul sis_delay(sc); 30050974Swpaul 30150974Swpaul /* 30250974Swpaul * Send address of word we want to read. 30350974Swpaul */ 30450974Swpaul sis_eeprom_putbyte(sc, addr); 30550974Swpaul 30650974Swpaul /* 30750974Swpaul * Start reading bits from EEPROM. 30850974Swpaul */ 30950974Swpaul for (i = 0x8000; i; i >>= 1) { 31050974Swpaul SIO_SET(SIS_EECTL_CLK); 31150974Swpaul sis_delay(sc); 31250974Swpaul if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECTL_DOUT) 31350974Swpaul word |= i; 31450974Swpaul sis_delay(sc); 31550974Swpaul SIO_CLR(SIS_EECTL_CLK); 31650974Swpaul sis_delay(sc); 31750974Swpaul } 31850974Swpaul 31950974Swpaul /* Turn off EEPROM access mode. */ 32050974Swpaul sis_eeprom_idle(sc); 32150974Swpaul 32250974Swpaul *dest = word; 32350974Swpaul} 32450974Swpaul 32550974Swpaul/* 32650974Swpaul * Read a sequence of words from the EEPROM. 32750974Swpaul */ 328102334Salfredstatic void 329139740Sphksis_read_eeprom(struct sis_softc *sc, caddr_t dest, int off, int cnt, int swap) 33050974Swpaul{ 33150974Swpaul int i; 332212113Syongari uint16_t word = 0, *ptr; 33350974Swpaul 33450974Swpaul for (i = 0; i < cnt; i++) { 33550974Swpaul sis_eeprom_getword(sc, off + i, &word); 336212113Syongari ptr = (uint16_t *)(dest + (i * 2)); 33750974Swpaul if (swap) 33850974Swpaul *ptr = ntohs(word); 33950974Swpaul else 34050974Swpaul *ptr = word; 34150974Swpaul } 34250974Swpaul} 34350974Swpaul 344144243Sobrien#if defined(__i386__) || defined(__amd64__) 345102334Salfredstatic device_t 346139740Sphksis_find_bridge(device_t dev) 34772197Swpaul{ 34872197Swpaul devclass_t pci_devclass; 34972197Swpaul device_t *pci_devices; 35072197Swpaul int pci_count = 0; 35172197Swpaul device_t *pci_children; 35272197Swpaul int pci_childcount = 0; 35372197Swpaul device_t *busp, *childp; 35487994Sarchie device_t child = NULL; 35572197Swpaul int i, j; 35672197Swpaul 35772197Swpaul if ((pci_devclass = devclass_find("pci")) == NULL) 358212104Syongari return (NULL); 35972197Swpaul 36072197Swpaul devclass_get_devices(pci_devclass, &pci_devices, &pci_count); 36172197Swpaul 36272197Swpaul for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) { 363182065Simp if (device_get_children(*busp, &pci_children, &pci_childcount)) 364182065Simp continue; 36572197Swpaul for (j = 0, childp = pci_children; 36672197Swpaul j < pci_childcount; j++, childp++) { 36772197Swpaul if (pci_get_vendor(*childp) == SIS_VENDORID && 36872197Swpaul pci_get_device(*childp) == 0x0008) { 36987994Sarchie child = *childp; 370182065Simp free(pci_children, M_TEMP); 37187994Sarchie goto done; 37272197Swpaul } 37372197Swpaul } 374182065Simp free(pci_children, M_TEMP); 37572197Swpaul } 37672197Swpaul 37787994Sarchiedone: 37872197Swpaul free(pci_devices, M_TEMP); 379212104Syongari return (child); 38072197Swpaul} 38172197Swpaul 382102334Salfredstatic void 383139740Sphksis_read_cmos(struct sis_softc *sc, device_t dev, caddr_t dest, int off, int cnt) 38472197Swpaul{ 38572197Swpaul device_t bridge; 386212113Syongari uint8_t reg; 38772197Swpaul int i; 38872197Swpaul bus_space_tag_t btag; 38972197Swpaul 39072197Swpaul bridge = sis_find_bridge(dev); 39172197Swpaul if (bridge == NULL) 39272197Swpaul return; 39372197Swpaul reg = pci_read_config(bridge, 0x48, 1); 39472197Swpaul pci_write_config(bridge, 0x48, reg|0x40, 1); 39572197Swpaul 39672197Swpaul /* XXX */ 397216592Stijl#if defined(__amd64__) || defined(__i386__) 398216592Stijl btag = X86_BUS_SPACE_IO; 399144243Sobrien#endif 40072197Swpaul 40172197Swpaul for (i = 0; i < cnt; i++) { 40272197Swpaul bus_space_write_1(btag, 0x0, 0x70, i + off); 40372197Swpaul *(dest + i) = bus_space_read_1(btag, 0x0, 0x71); 40472197Swpaul } 40572197Swpaul 40672197Swpaul pci_write_config(bridge, 0x48, reg & ~0x40, 1); 40772197Swpaul} 40889296Swpaul 409102334Salfredstatic void 410139740Sphksis_read_mac(struct sis_softc *sc, device_t dev, caddr_t dest) 41189296Swpaul{ 412212113Syongari uint32_t filtsave, csrsave; 41389296Swpaul 41489296Swpaul filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); 41589296Swpaul csrsave = CSR_READ_4(sc, SIS_CSR); 41689296Swpaul 41789296Swpaul CSR_WRITE_4(sc, SIS_CSR, SIS_CSR_RELOAD | filtsave); 41889296Swpaul CSR_WRITE_4(sc, SIS_CSR, 0); 419212103Syongari 42089296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE); 42189296Swpaul 42289296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 423212113Syongari ((uint16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); 42489296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1); 425212113Syongari ((uint16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); 42689296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 427212113Syongari ((uint16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); 42889296Swpaul 42989296Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); 43089296Swpaul CSR_WRITE_4(sc, SIS_CSR, csrsave); 43189296Swpaul} 43272197Swpaul#endif 43372197Swpaul 434109060Smbr/* 435226995Smarius * Read the MII serial port for the MII bit-bang module. 436109060Smbr */ 437226995Smariusstatic uint32_t 438226995Smariussis_mii_bitbang_read(device_t dev) 439109060Smbr{ 440226995Smarius struct sis_softc *sc; 441226995Smarius uint32_t val; 442212103Syongari 443226995Smarius sc = device_get_softc(dev); 444212103Syongari 445226995Smarius val = CSR_READ_4(sc, SIS_EECTL); 446226995Smarius CSR_BARRIER(sc, SIS_EECTL, 4, 447226995Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 448226995Smarius return (val); 449109060Smbr} 450212103Syongari 451109060Smbr/* 452226995Smarius * Write the MII serial port for the MII bit-bang module. 453109060Smbr */ 454139740Sphkstatic void 455226995Smariussis_mii_bitbang_write(device_t dev, uint32_t val) 456109060Smbr{ 457226995Smarius struct sis_softc *sc; 458212103Syongari 459226995Smarius sc = device_get_softc(dev); 460212103Syongari 461226995Smarius CSR_WRITE_4(sc, SIS_EECTL, val); 462226995Smarius CSR_BARRIER(sc, SIS_EECTL, 4, 463226995Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 464109060Smbr} 465212103Syongari 466139740Sphkstatic int 467139740Sphksis_miibus_readreg(device_t dev, int phy, int reg) 46850974Swpaul{ 46950974Swpaul struct sis_softc *sc; 47050974Swpaul 47150974Swpaul sc = device_get_softc(dev); 47250974Swpaul 47362672Swpaul if (sc->sis_type == SIS_TYPE_83815) { 47462672Swpaul if (phy != 0) 475212104Syongari return (0); 47662672Swpaul /* 47762672Swpaul * The NatSemi chip can take a while after 47862672Swpaul * a reset to come ready, during which the BMSR 47962672Swpaul * returns a value of 0. This is *never* supposed 48062672Swpaul * to happen: some of the BMSR bits are meant to 48162672Swpaul * be hardwired in the on position, and this can 48262672Swpaul * confuse the miibus code a bit during the probe 48362672Swpaul * and attach phase. So we make an effort to check 48462672Swpaul * for this condition and wait for it to clear. 48562672Swpaul */ 48662672Swpaul if (!CSR_READ_4(sc, NS_BMSR)) 48762672Swpaul DELAY(1000); 488109060Smbr return CSR_READ_4(sc, NS_BMCR + (reg * 4)); 48962672Swpaul } 49062672Swpaul 491109976Smbr /* 492109976Smbr * Chipsets < SIS_635 seem not to be able to read/write 493109976Smbr * through mdio. Use the enhanced PHY access register 494109976Smbr * again for them. 495109976Smbr */ 49689296Swpaul if (sc->sis_type == SIS_TYPE_900 && 497109976Smbr sc->sis_rev < SIS_REV_635) { 498109976Smbr int i, val = 0; 49950974Swpaul 500109976Smbr if (phy != 0) 501212104Syongari return (0); 50250974Swpaul 503109976Smbr CSR_WRITE_4(sc, SIS_PHYCTL, 504109976Smbr (phy << 11) | (reg << 6) | SIS_PHYOP_READ); 505109976Smbr SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS); 50650974Swpaul 507109976Smbr for (i = 0; i < SIS_TIMEOUT; i++) { 508109976Smbr if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS)) 509109976Smbr break; 510109976Smbr } 511109976Smbr 512109976Smbr if (i == SIS_TIMEOUT) { 513226995Smarius device_printf(sc->sis_dev, 514226995Smarius "PHY failed to come ready\n"); 515212104Syongari return (0); 516109976Smbr } 517109976Smbr 518109976Smbr val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF; 519109976Smbr 520109976Smbr if (val == 0xFFFF) 521212104Syongari return (0); 522109976Smbr 523212104Syongari return (val); 524226995Smarius } else 525226995Smarius return (mii_bitbang_readreg(dev, &sis_mii_bitbang_ops, phy, 526226995Smarius reg)); 52750974Swpaul} 52850974Swpaul 529102334Salfredstatic int 530139740Sphksis_miibus_writereg(device_t dev, int phy, int reg, int data) 53150974Swpaul{ 53250974Swpaul struct sis_softc *sc; 53350974Swpaul 53450974Swpaul sc = device_get_softc(dev); 53550974Swpaul 53662672Swpaul if (sc->sis_type == SIS_TYPE_83815) { 53762672Swpaul if (phy != 0) 538212104Syongari return (0); 53962672Swpaul CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data); 540212104Syongari return (0); 54162672Swpaul } 54262672Swpaul 543109976Smbr /* 544109976Smbr * Chipsets < SIS_635 seem not to be able to read/write 545109976Smbr * through mdio. Use the enhanced PHY access register 546109976Smbr * again for them. 547109976Smbr */ 548109976Smbr if (sc->sis_type == SIS_TYPE_900 && 549109976Smbr sc->sis_rev < SIS_REV_635) { 550109976Smbr int i; 55150974Swpaul 552109976Smbr if (phy != 0) 553212104Syongari return (0); 55450974Swpaul 555109976Smbr CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) | 556109976Smbr (reg << 6) | SIS_PHYOP_WRITE); 557109976Smbr SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS); 55850974Swpaul 559109976Smbr for (i = 0; i < SIS_TIMEOUT; i++) { 560109976Smbr if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS)) 561109976Smbr break; 562109976Smbr } 56350974Swpaul 564109976Smbr if (i == SIS_TIMEOUT) 565226995Smarius device_printf(sc->sis_dev, 566226995Smarius "PHY failed to come ready\n"); 567226995Smarius } else 568226995Smarius mii_bitbang_writereg(dev, &sis_mii_bitbang_ops, phy, reg, 569226995Smarius data); 570212104Syongari return (0); 57150974Swpaul} 57250974Swpaul 573102334Salfredstatic void 574139717Sphksis_miibus_statchg(device_t dev) 57550974Swpaul{ 57650974Swpaul struct sis_softc *sc; 577212116Syongari struct mii_data *mii; 578212116Syongari struct ifnet *ifp; 579212116Syongari uint32_t reg; 58050974Swpaul 58150974Swpaul sc = device_get_softc(dev); 582139717Sphk SIS_LOCK_ASSERT(sc); 583212116Syongari 584212116Syongari mii = device_get_softc(sc->sis_miibus); 585212116Syongari ifp = sc->sis_ifp; 586212116Syongari if (mii == NULL || ifp == NULL || 587212116Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 588212116Syongari return; 589212116Syongari 590212157Syongari sc->sis_flags &= ~SIS_FLAG_LINK; 591212116Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 592212116Syongari (IFM_ACTIVE | IFM_AVALID)) { 593212116Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 594212116Syongari case IFM_10_T: 595212116Syongari CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10); 596212157Syongari sc->sis_flags |= SIS_FLAG_LINK; 597212116Syongari break; 598212116Syongari case IFM_100_TX: 599212116Syongari CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); 600212157Syongari sc->sis_flags |= SIS_FLAG_LINK; 601212116Syongari break; 602212116Syongari default: 603212116Syongari break; 604212116Syongari } 605212116Syongari } 606212116Syongari 607212157Syongari if ((sc->sis_flags & SIS_FLAG_LINK) == 0) { 608212116Syongari /* 609212116Syongari * Stopping MACs seem to reset SIS_TX_LISTPTR and 610212116Syongari * SIS_RX_LISTPTR which in turn requires resetting 611212116Syongari * TX/RX buffers. So just don't do anything for 612212116Syongari * lost link. 613212116Syongari */ 614212116Syongari return; 615212116Syongari } 616212116Syongari 617212116Syongari /* Set full/half duplex mode. */ 618212116Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 619212116Syongari SIS_SETBIT(sc, SIS_TX_CFG, 620212116Syongari (SIS_TXCFG_IGN_HBEAT | SIS_TXCFG_IGN_CARR)); 621212116Syongari SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); 622212116Syongari } else { 623212116Syongari SIS_CLRBIT(sc, SIS_TX_CFG, 624212116Syongari (SIS_TXCFG_IGN_HBEAT | SIS_TXCFG_IGN_CARR)); 625212116Syongari SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); 626212116Syongari } 627212116Syongari 628248456Syongari if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr >= NS_SRR_16A) { 629212116Syongari /* 630212116Syongari * MPII03.D: Half Duplex Excessive Collisions. 631212116Syongari * Also page 49 in 83816 manual 632212116Syongari */ 633212116Syongari SIS_SETBIT(sc, SIS_TX_CFG, SIS_TXCFG_MPII03D); 634212116Syongari } 635212116Syongari 636212116Syongari if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr < NS_SRR_16A && 637212116Syongari IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { 638212116Syongari /* 639212116Syongari * Short Cable Receive Errors (MP21.E) 640212116Syongari */ 641212116Syongari CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); 642212116Syongari reg = CSR_READ_4(sc, NS_PHY_DSPCFG) & 0xfff; 643212116Syongari CSR_WRITE_4(sc, NS_PHY_DSPCFG, reg | 0x1000); 644212116Syongari DELAY(100); 645212116Syongari reg = CSR_READ_4(sc, NS_PHY_TDATA) & 0xff; 646212116Syongari if ((reg & 0x0080) == 0 || (reg > 0xd8 && reg <= 0xff)) { 647212116Syongari device_printf(sc->sis_dev, 648212116Syongari "Applying short cable fix (reg=%x)\n", reg); 649212116Syongari CSR_WRITE_4(sc, NS_PHY_TDATA, 0x00e8); 650212116Syongari SIS_SETBIT(sc, NS_PHY_DSPCFG, 0x20); 651212116Syongari } 652212116Syongari CSR_WRITE_4(sc, NS_PHY_PAGE, 0); 653212116Syongari } 654212116Syongari /* Enable TX/RX MACs. */ 655212116Syongari SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE); 656212116Syongari SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE | SIS_CSR_RX_ENABLE); 65750974Swpaul} 65850974Swpaul 659139740Sphkstatic uint32_t 660139740Sphksis_mchash(struct sis_softc *sc, const uint8_t *addr) 66150974Swpaul{ 662130270Snaddy uint32_t crc; 66350974Swpaul 66450974Swpaul /* Compute CRC for the address value. */ 665130270Snaddy crc = ether_crc32_be(addr, ETHER_ADDR_LEN); 66650974Swpaul 66762672Swpaul /* 66862672Swpaul * return the filter bit position 66962672Swpaul * 67062672Swpaul * The NatSemi chip has a 512-bit filter, which is 67162672Swpaul * different than the SiS, so we special-case it. 67262672Swpaul */ 67362672Swpaul if (sc->sis_type == SIS_TYPE_83815) 674109060Smbr return (crc >> 23); 675109976Smbr else if (sc->sis_rev >= SIS_REV_635 || 676109976Smbr sc->sis_rev == SIS_REV_900B) 677109060Smbr return (crc >> 24); 678109976Smbr else 679109976Smbr return (crc >> 25); 68050974Swpaul} 68150974Swpaul 682102334Salfredstatic void 683217548Syongarisis_rxfilter(struct sis_softc *sc) 68450974Swpaul{ 685217548Syongari 686217548Syongari SIS_LOCK_ASSERT(sc); 687217548Syongari 688217548Syongari if (sc->sis_type == SIS_TYPE_83815) 689217548Syongari sis_rxfilter_ns(sc); 690217548Syongari else 691217548Syongari sis_rxfilter_sis(sc); 692217548Syongari} 693217548Syongari 694217548Syongaristatic void 695217548Syongarisis_rxfilter_ns(struct sis_softc *sc) 696217548Syongari{ 69750974Swpaul struct ifnet *ifp; 69850974Swpaul struct ifmultiaddr *ifma; 699217548Syongari uint32_t h, i, filter; 70062672Swpaul int bit, index; 70150974Swpaul 702147256Sbrooks ifp = sc->sis_ifp; 703217548Syongari filter = CSR_READ_4(sc, SIS_RXFILT_CTL); 704217548Syongari if (filter & SIS_RXFILTCTL_ENABLE) { 705217548Syongari /* 706217548Syongari * Filter should be disabled to program other bits. 707217548Syongari */ 708217548Syongari CSR_WRITE_4(sc, SIS_RXFILT_CTL, filter & ~SIS_RXFILTCTL_ENABLE); 709217548Syongari CSR_READ_4(sc, SIS_RXFILT_CTL); 71050974Swpaul } 711217548Syongari filter &= ~(NS_RXFILTCTL_ARP | NS_RXFILTCTL_PERFECT | 712217548Syongari NS_RXFILTCTL_MCHASH | SIS_RXFILTCTL_ALLPHYS | SIS_RXFILTCTL_BROAD | 713217548Syongari SIS_RXFILTCTL_ALLMULTI); 71450974Swpaul 715217548Syongari if (ifp->if_flags & IFF_BROADCAST) 716217548Syongari filter |= SIS_RXFILTCTL_BROAD; 71762672Swpaul /* 718217548Syongari * For the NatSemi chip, we have to explicitly enable the 719217548Syongari * reception of ARP frames, as well as turn on the 'perfect 720217548Syongari * match' filter where we store the station address, otherwise 721217548Syongari * we won't receive unicasts meant for this host. 72262672Swpaul */ 723217548Syongari filter |= NS_RXFILTCTL_ARP | NS_RXFILTCTL_PERFECT; 72450974Swpaul 725217548Syongari if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 726217548Syongari filter |= SIS_RXFILTCTL_ALLMULTI; 727217548Syongari if (ifp->if_flags & IFF_PROMISC) 728217548Syongari filter |= SIS_RXFILTCTL_ALLPHYS; 729217548Syongari } else { 730217548Syongari /* 731217548Syongari * We have to explicitly enable the multicast hash table 732217548Syongari * on the NatSemi chip if we want to use it, which we do. 733217548Syongari */ 734217548Syongari filter |= NS_RXFILTCTL_MCHASH; 73550974Swpaul 736217548Syongari /* first, zot all the existing hash bits */ 737217548Syongari for (i = 0; i < 32; i++) { 738217548Syongari CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + 739217548Syongari (i * 2)); 740217548Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0); 741217548Syongari } 74262672Swpaul 743217548Syongari if_maddr_rlock(ifp); 744217548Syongari TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 745217548Syongari if (ifma->ifma_addr->sa_family != AF_LINK) 746217548Syongari continue; 747217548Syongari h = sis_mchash(sc, 748217548Syongari LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 749217548Syongari index = h >> 3; 750217548Syongari bit = h & 0x1F; 751217548Syongari CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + 752217548Syongari index); 753217548Syongari if (bit > 0xF) 754217548Syongari bit -= 0x10; 755217548Syongari SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit)); 756217548Syongari } 757217548Syongari if_maddr_runlock(ifp); 75862672Swpaul } 75962672Swpaul 760217548Syongari CSR_WRITE_4(sc, SIS_RXFILT_CTL, filter); 761217548Syongari CSR_READ_4(sc, SIS_RXFILT_CTL); 76262672Swpaul} 76362672Swpaul 764102334Salfredstatic void 765217548Syongarisis_rxfilter_sis(struct sis_softc *sc) 76662672Swpaul{ 76762672Swpaul struct ifnet *ifp; 76862672Swpaul struct ifmultiaddr *ifma; 769217548Syongari uint32_t filter, h, i, n; 770212113Syongari uint16_t hashes[16]; 77162672Swpaul 772147256Sbrooks ifp = sc->sis_ifp; 77362672Swpaul 774109060Smbr /* hash table size */ 775217548Syongari if (sc->sis_rev >= SIS_REV_635 || sc->sis_rev == SIS_REV_900B) 776109976Smbr n = 16; 777109976Smbr else 778109976Smbr n = 8; 77962672Swpaul 780217548Syongari filter = CSR_READ_4(sc, SIS_RXFILT_CTL); 781217548Syongari if (filter & SIS_RXFILTCTL_ENABLE) { 782217548Syongari CSR_WRITE_4(sc, SIS_RXFILT_CTL, filter & ~SIS_RXFILT_CTL); 783217548Syongari CSR_READ_4(sc, SIS_RXFILT_CTL); 784217548Syongari } 785217548Syongari filter &= ~(SIS_RXFILTCTL_ALLPHYS | SIS_RXFILTCTL_BROAD | 786217548Syongari SIS_RXFILTCTL_ALLMULTI); 787109060Smbr if (ifp->if_flags & IFF_BROADCAST) 788217548Syongari filter |= SIS_RXFILTCTL_BROAD; 78962672Swpaul 790217548Syongari if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { 791217548Syongari filter |= SIS_RXFILTCTL_ALLMULTI; 792109060Smbr if (ifp->if_flags & IFF_PROMISC) 793217548Syongari filter |= SIS_RXFILTCTL_ALLPHYS; 794109060Smbr for (i = 0; i < n; i++) 795109060Smbr hashes[i] = ~0; 796109060Smbr } else { 797109060Smbr for (i = 0; i < n; i++) 798109060Smbr hashes[i] = 0; 799109060Smbr i = 0; 800195049Srwatson if_maddr_rlock(ifp); 801109060Smbr TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 802109060Smbr if (ifma->ifma_addr->sa_family != AF_LINK) 803109060Smbr continue; 804122625Sobrien h = sis_mchash(sc, 805109060Smbr LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 806109060Smbr hashes[h >> 4] |= 1 << (h & 0xf); 807109060Smbr i++; 808109060Smbr } 809195049Srwatson if_maddr_runlock(ifp); 810109060Smbr if (i > n) { 811217548Syongari filter |= SIS_RXFILTCTL_ALLMULTI; 812109060Smbr for (i = 0; i < n; i++) 813109060Smbr hashes[i] = ~0; 814109060Smbr } 81550974Swpaul } 81650974Swpaul 817109060Smbr for (i = 0; i < n; i++) { 818109060Smbr CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + i) << 16); 819109060Smbr CSR_WRITE_4(sc, SIS_RXFILT_DATA, hashes[i]); 82050974Swpaul } 82150974Swpaul 822217548Syongari CSR_WRITE_4(sc, SIS_RXFILT_CTL, filter); 823217548Syongari CSR_READ_4(sc, SIS_RXFILT_CTL); 82450974Swpaul} 82550974Swpaul 826102334Salfredstatic void 827139717Sphksis_reset(struct sis_softc *sc) 82850974Swpaul{ 829139708Sphk int i; 83050974Swpaul 83150974Swpaul SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RESET); 83250974Swpaul 83350974Swpaul for (i = 0; i < SIS_TIMEOUT; i++) { 83450974Swpaul if (!(CSR_READ_4(sc, SIS_CSR) & SIS_CSR_RESET)) 83550974Swpaul break; 83650974Swpaul } 83750974Swpaul 83850974Swpaul if (i == SIS_TIMEOUT) 839162315Sglebius device_printf(sc->sis_dev, "reset never completed\n"); 84050974Swpaul 84150974Swpaul /* Wait a little while for the chip to get its brains in order. */ 84250974Swpaul DELAY(1000); 84372813Swpaul 84472813Swpaul /* 84572813Swpaul * If this is a NetSemi chip, make sure to clear 84672813Swpaul * PME mode. 84772813Swpaul */ 84872813Swpaul if (sc->sis_type == SIS_TYPE_83815) { 84972813Swpaul CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS); 85072813Swpaul CSR_WRITE_4(sc, NS_CLKRUN, 0); 851212167Syongari } else { 852212167Syongari /* Disable WOL functions. */ 853212167Syongari CSR_WRITE_4(sc, SIS_PWRMAN_CTL, 0); 85472813Swpaul } 85550974Swpaul} 85650974Swpaul 85750974Swpaul/* 85850974Swpaul * Probe for an SiS chip. Check the PCI vendor and device 85950974Swpaul * IDs against our list and return a device name if we find a match. 86050974Swpaul */ 861102334Salfredstatic int 862139740Sphksis_probe(device_t dev) 86350974Swpaul{ 864226995Smarius const struct sis_type *t; 86550974Swpaul 86650974Swpaul t = sis_devs; 86750974Swpaul 868212104Syongari while (t->sis_name != NULL) { 86950974Swpaul if ((pci_get_vendor(dev) == t->sis_vid) && 87050974Swpaul (pci_get_device(dev) == t->sis_did)) { 87150974Swpaul device_set_desc(dev, t->sis_name); 872142398Simp return (BUS_PROBE_DEFAULT); 87350974Swpaul } 87450974Swpaul t++; 87550974Swpaul } 87650974Swpaul 877212104Syongari return (ENXIO); 87850974Swpaul} 87950974Swpaul 88050974Swpaul/* 88150974Swpaul * Attach the interface. Allocate softc structures, do ifmedia 88250974Swpaul * setup and ethernet/BPF attach. 88350974Swpaul */ 884102334Salfredstatic int 885139740Sphksis_attach(device_t dev) 88650974Swpaul{ 88750974Swpaul u_char eaddr[ETHER_ADDR_LEN]; 88850974Swpaul struct sis_softc *sc; 88950974Swpaul struct ifnet *ifp; 890212167Syongari int error = 0, pmc, waittime = 0; 89150974Swpaul 892109061Smbr waittime = 0; 89350974Swpaul sc = device_get_softc(dev); 89450974Swpaul 895162315Sglebius sc->sis_dev = dev; 896119712Sphk 89793818Sjhb mtx_init(&sc->sis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 898139810Sphk MTX_DEF); 899150583Sjhb callout_init_mtx(&sc->sis_stat_ch, &sc->sis_mtx, 0); 90069583Swpaul 90150974Swpaul if (pci_get_device(dev) == SIS_DEVICEID_900) 90250974Swpaul sc->sis_type = SIS_TYPE_900; 90350974Swpaul if (pci_get_device(dev) == SIS_DEVICEID_7016) 90450974Swpaul sc->sis_type = SIS_TYPE_7016; 90562672Swpaul if (pci_get_vendor(dev) == NS_VENDORID) 90662672Swpaul sc->sis_type = SIS_TYPE_83815; 90750974Swpaul 90889296Swpaul sc->sis_rev = pci_read_config(dev, PCIR_REVID, 1); 90950974Swpaul /* 91050974Swpaul * Map control/status registers. 91150974Swpaul */ 91272813Swpaul pci_enable_busmaster(dev); 91350974Swpaul 914150526Sphk error = bus_alloc_resources(dev, sis_res_spec, sc->sis_res); 915150583Sjhb if (error) { 916150583Sjhb device_printf(dev, "couldn't allocate resources\n"); 917150583Sjhb goto fail; 918150583Sjhb } 91950974Swpaul 92050974Swpaul /* Reset the adapter. */ 92150974Swpaul sis_reset(sc); 92250974Swpaul 923109976Smbr if (sc->sis_type == SIS_TYPE_900 && 924212103Syongari (sc->sis_rev == SIS_REV_635 || 925212103Syongari sc->sis_rev == SIS_REV_900B)) { 926109976Smbr SIO_SET(SIS_CFG_RND_CNT); 927109976Smbr SIO_SET(SIS_CFG_PERR_DETECT); 928109976Smbr } 929109976Smbr 93050974Swpaul /* 93150974Swpaul * Get station address from the EEPROM. 93250974Swpaul */ 93362672Swpaul switch (pci_get_vendor(dev)) { 93462672Swpaul case NS_VENDORID: 935119712Sphk sc->sis_srr = CSR_READ_4(sc, NS_SRR); 936119712Sphk 937119712Sphk /* We can't update the device description, so spew */ 938119712Sphk if (sc->sis_srr == NS_SRR_15C) 939119712Sphk device_printf(dev, "Silicon Revision: DP83815C\n"); 940119712Sphk else if (sc->sis_srr == NS_SRR_15D) 941119712Sphk device_printf(dev, "Silicon Revision: DP83815D\n"); 942119712Sphk else if (sc->sis_srr == NS_SRR_16A) 943119712Sphk device_printf(dev, "Silicon Revision: DP83816A\n"); 944119712Sphk else 945119712Sphk device_printf(dev, "Silicon Revision %x\n", sc->sis_srr); 946119712Sphk 94762672Swpaul /* 94862672Swpaul * Reading the MAC address out of the EEPROM on 94962672Swpaul * the NatSemi chip takes a bit more work than 95062672Swpaul * you'd expect. The address spans 4 16-bit words, 95162672Swpaul * with the first word containing only a single bit. 95262672Swpaul * You have to shift everything over one bit to 95362672Swpaul * get it aligned properly. Also, the bits are 95462672Swpaul * stored backwards (the LSB is really the MSB, 95562672Swpaul * and so on) so you have to reverse them in order 95662672Swpaul * to get the MAC address into the form we want. 95762672Swpaul * Why? Who the hell knows. 95862672Swpaul */ 95962672Swpaul { 960212113Syongari uint16_t tmp[4]; 96150974Swpaul 96262672Swpaul sis_read_eeprom(sc, (caddr_t)&tmp, 96362672Swpaul NS_EE_NODEADDR, 4, 0); 96462672Swpaul 96562672Swpaul /* Shift everything over one bit. */ 96662672Swpaul tmp[3] = tmp[3] >> 1; 96762681Swpaul tmp[3] |= tmp[2] << 15; 96862672Swpaul tmp[2] = tmp[2] >> 1; 96962681Swpaul tmp[2] |= tmp[1] << 15; 97062672Swpaul tmp[1] = tmp[1] >> 1; 97162681Swpaul tmp[1] |= tmp[0] << 15; 97262672Swpaul 97362672Swpaul /* Now reverse all the bits. */ 97462672Swpaul tmp[3] = sis_reverse(tmp[3]); 97562672Swpaul tmp[2] = sis_reverse(tmp[2]); 97662672Swpaul tmp[1] = sis_reverse(tmp[1]); 97762672Swpaul 978212156Syongari eaddr[0] = (tmp[1] >> 0) & 0xFF; 979212156Syongari eaddr[1] = (tmp[1] >> 8) & 0xFF; 980212156Syongari eaddr[2] = (tmp[2] >> 0) & 0xFF; 981212156Syongari eaddr[3] = (tmp[2] >> 8) & 0xFF; 982212156Syongari eaddr[4] = (tmp[3] >> 0) & 0xFF; 983212156Syongari eaddr[5] = (tmp[3] >> 8) & 0xFF; 98462672Swpaul } 98562672Swpaul break; 98662672Swpaul case SIS_VENDORID: 98762672Swpaul default: 988144243Sobrien#if defined(__i386__) || defined(__amd64__) 98972197Swpaul /* 99072197Swpaul * If this is a SiS 630E chipset with an embedded 99172197Swpaul * SiS 900 controller, we have to read the MAC address 99272197Swpaul * from the APC CMOS RAM. Our method for doing this 99372197Swpaul * is very ugly since we have to reach out and grab 99472197Swpaul * ahold of hardware for which we cannot properly 99572197Swpaul * allocate resources. This code is only compiled on 99672197Swpaul * the i386 architecture since the SiS 630E chipset 99772197Swpaul * is for x86 motherboards only. Note that there are 99872197Swpaul * a lot of magic numbers in this hack. These are 99972197Swpaul * taken from SiS's Linux driver. I'd like to replace 100072197Swpaul * them with proper symbolic definitions, but that 100172197Swpaul * requires some datasheets that I don't have access 100272197Swpaul * to at the moment. 100372197Swpaul */ 100489296Swpaul if (sc->sis_rev == SIS_REV_630S || 100589296Swpaul sc->sis_rev == SIS_REV_630E || 100690328Sambrisko sc->sis_rev == SIS_REV_630EA1) 100772197Swpaul sis_read_cmos(sc, dev, (caddr_t)&eaddr, 0x9, 6); 100889296Swpaul 100990328Sambrisko else if (sc->sis_rev == SIS_REV_635 || 101090328Sambrisko sc->sis_rev == SIS_REV_630ET) 101189296Swpaul sis_read_mac(sc, dev, (caddr_t)&eaddr); 1012109061Smbr else if (sc->sis_rev == SIS_REV_96x) { 1013109061Smbr /* Allow to read EEPROM from LAN. It is shared 1014109061Smbr * between a 1394 controller and the NIC and each 1015109061Smbr * time we access it, we need to set SIS_EECMD_REQ. 1016109061Smbr */ 1017109061Smbr SIO_SET(SIS_EECMD_REQ); 1018109061Smbr for (waittime = 0; waittime < SIS_TIMEOUT; 1019109061Smbr waittime++) { 1020109061Smbr /* Force EEPROM to idle state. */ 1021109061Smbr sis_eeprom_idle(sc); 1022109061Smbr if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECMD_GNT) { 1023109061Smbr sis_read_eeprom(sc, (caddr_t)&eaddr, 1024109061Smbr SIS_EE_NODEADDR, 3, 0); 1025109061Smbr break; 1026109061Smbr } 1027109061Smbr DELAY(1); 1028109061Smbr } 1029109061Smbr /* 1030109061Smbr * Set SIS_EECTL_CLK to high, so a other master 1031109061Smbr * can operate on the i2c bus. 1032109061Smbr */ 1033109061Smbr SIO_SET(SIS_EECTL_CLK); 1034109061Smbr /* Refuse EEPROM access by LAN */ 1035109061Smbr SIO_SET(SIS_EECMD_DONE); 1036109061Smbr } else 103772197Swpaul#endif 103872197Swpaul sis_read_eeprom(sc, (caddr_t)&eaddr, 103972197Swpaul SIS_EE_NODEADDR, 3, 0); 104062672Swpaul break; 104162672Swpaul } 104262672Swpaul 1043212157Syongari sis_add_sysctls(sc); 1044212157Syongari 1045212109Syongari /* Allocate DMA'able memory. */ 1046212109Syongari if ((error = sis_dma_alloc(sc)) != 0) 1047112872Snjl goto fail; 104850974Swpaul 1049147256Sbrooks ifp = sc->sis_ifp = if_alloc(IFT_ETHER); 1050147256Sbrooks if (ifp == NULL) { 1051150583Sjhb device_printf(dev, "can not if_alloc()\n"); 1052147256Sbrooks error = ENOSPC; 1053147256Sbrooks goto fail; 1054147256Sbrooks } 105550974Swpaul ifp->if_softc = sc; 1056121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 105750974Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 105850974Swpaul ifp->if_ioctl = sis_ioctl; 105950974Swpaul ifp->if_start = sis_start; 106050974Swpaul ifp->if_init = sis_init; 1061131455Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, SIS_TX_LIST_CNT - 1); 1062131455Smlaier ifp->if_snd.ifq_drv_maxlen = SIS_TX_LIST_CNT - 1; 1063131455Smlaier IFQ_SET_READY(&ifp->if_snd); 106450974Swpaul 1065219902Sjhb if (pci_find_cap(sc->sis_dev, PCIY_PMG, &pmc) == 0) { 1066212167Syongari if (sc->sis_type == SIS_TYPE_83815) 1067212167Syongari ifp->if_capabilities |= IFCAP_WOL; 1068212167Syongari else 1069212167Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC; 1070212167Syongari ifp->if_capenable = ifp->if_capabilities; 1071212167Syongari } 1072212167Syongari 107350974Swpaul /* 107450974Swpaul * Do MII setup. 107550974Swpaul */ 1076213894Smarius error = mii_attach(dev, &sc->sis_miibus, ifp, sis_ifmedia_upd, 1077213894Smarius sis_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 1078213894Smarius if (error != 0) { 1079213894Smarius device_printf(dev, "attaching PHYs failed\n"); 108050974Swpaul goto fail; 108150974Swpaul } 108250974Swpaul 108350974Swpaul /* 108463090Sarchie * Call MI attach routine. 108550974Swpaul */ 1086106936Ssam ether_ifattach(ifp, eaddr); 1087212103Syongari 108887390Sjhay /* 108987390Sjhay * Tell the upper layer(s) we support long frames. 109087390Sjhay */ 109187390Sjhay ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1092106936Ssam ifp->if_capabilities |= IFCAP_VLAN_MTU; 1093150789Sglebius ifp->if_capenable = ifp->if_capabilities; 1094128138Sru#ifdef DEVICE_POLLING 1095128138Sru ifp->if_capabilities |= IFCAP_POLLING; 1096128138Sru#endif 1097128138Sru 1098113609Snjl /* Hook interrupt last to avoid having to lock softc */ 1099150526Sphk error = bus_setup_intr(dev, sc->sis_res[1], INTR_TYPE_NET | INTR_MPSAFE, 1100166901Spiso NULL, sis_intr, sc, &sc->sis_intrhand); 110150974Swpaul 1102112872Snjl if (error) { 1103150583Sjhb device_printf(dev, "couldn't set up irq\n"); 1104113609Snjl ether_ifdetach(ifp); 1105112872Snjl goto fail; 1106112872Snjl } 1107112872Snjl 110850974Swpaulfail: 1109112872Snjl if (error) 1110112872Snjl sis_detach(dev); 1111112872Snjl 1112212104Syongari return (error); 111350974Swpaul} 111450974Swpaul 1115113609Snjl/* 1116113609Snjl * Shutdown hardware and free up resources. This can be called any 1117113609Snjl * time after the mutex has been initialized. It is called in both 1118113609Snjl * the error case in attach and the normal detach case so it needs 1119113609Snjl * to be careful about only freeing resources that have actually been 1120113609Snjl * allocated. 1121113609Snjl */ 1122102334Salfredstatic int 1123139740Sphksis_detach(device_t dev) 112450974Swpaul{ 112550974Swpaul struct sis_softc *sc; 112650974Swpaul struct ifnet *ifp; 112750974Swpaul 112850974Swpaul sc = device_get_softc(dev); 1129112880Sjhb KASSERT(mtx_initialized(&sc->sis_mtx), ("sis mutex not initialized")); 1130147256Sbrooks ifp = sc->sis_ifp; 113150974Swpaul 1132150789Sglebius#ifdef DEVICE_POLLING 1133150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1134150789Sglebius ether_poll_deregister(ifp); 1135150789Sglebius#endif 1136150789Sglebius 1137118089Smux /* These should only be active if attach succeeded. */ 1138113812Simp if (device_is_attached(dev)) { 1139150583Sjhb SIS_LOCK(sc); 1140113609Snjl sis_stop(sc); 1141150583Sjhb SIS_UNLOCK(sc); 1142150583Sjhb callout_drain(&sc->sis_stat_ch); 1143112872Snjl ether_ifdetach(ifp); 1144150213Sru } 1145113609Snjl if (sc->sis_miibus) 1146112872Snjl device_delete_child(dev, sc->sis_miibus); 1147113609Snjl bus_generic_detach(dev); 114850974Swpaul 1149112872Snjl if (sc->sis_intrhand) 1150150526Sphk bus_teardown_intr(dev, sc->sis_res[1], sc->sis_intrhand); 1151150526Sphk bus_release_resources(dev, sis_res_spec, sc->sis_res); 115250974Swpaul 1153151297Sru if (ifp) 1154151297Sru if_free(ifp); 1155151297Sru 1156212109Syongari sis_dma_free(sc); 1157212109Syongari 1158212109Syongari mtx_destroy(&sc->sis_mtx); 1159212109Syongari 1160212109Syongari return (0); 1161212109Syongari} 1162212109Syongari 1163212109Syongaristruct sis_dmamap_arg { 1164212109Syongari bus_addr_t sis_busaddr; 1165212109Syongari}; 1166212109Syongari 1167212109Syongaristatic void 1168212109Syongarisis_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1169212109Syongari{ 1170212109Syongari struct sis_dmamap_arg *ctx; 1171212109Syongari 1172212109Syongari if (error != 0) 1173212109Syongari return; 1174212109Syongari 1175212109Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1176212109Syongari 1177212109Syongari ctx = (struct sis_dmamap_arg *)arg; 1178212109Syongari ctx->sis_busaddr = segs[0].ds_addr; 1179212109Syongari} 1180212109Syongari 1181212109Syongaristatic int 1182212109Syongarisis_dma_ring_alloc(struct sis_softc *sc, bus_size_t alignment, 1183212109Syongari bus_size_t maxsize, bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map, 1184212109Syongari bus_addr_t *paddr, const char *msg) 1185212109Syongari{ 1186212109Syongari struct sis_dmamap_arg ctx; 1187212109Syongari int error; 1188212109Syongari 1189212109Syongari error = bus_dma_tag_create(sc->sis_parent_tag, alignment, 0, 1190212109Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, maxsize, 1, 1191212109Syongari maxsize, 0, NULL, NULL, tag); 1192212109Syongari if (error != 0) { 1193212109Syongari device_printf(sc->sis_dev, 1194212109Syongari "could not create %s dma tag\n", msg); 1195212109Syongari return (ENOMEM); 1196112872Snjl } 1197212109Syongari /* Allocate DMA'able memory for ring. */ 1198212109Syongari error = bus_dmamem_alloc(*tag, (void **)ring, 1199212109Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map); 1200212109Syongari if (error != 0) { 1201212109Syongari device_printf(sc->sis_dev, 1202212109Syongari "could not allocate DMA'able memory for %s\n", msg); 1203212109Syongari return (ENOMEM); 1204112872Snjl } 1205212109Syongari /* Load the address of the ring. */ 1206212109Syongari ctx.sis_busaddr = 0; 1207212109Syongari error = bus_dmamap_load(*tag, *map, *ring, maxsize, sis_dmamap_cb, 1208212109Syongari &ctx, BUS_DMA_NOWAIT); 1209212109Syongari if (error != 0) { 1210212109Syongari device_printf(sc->sis_dev, 1211212109Syongari "could not load DMA'able memory for %s\n", msg); 1212212109Syongari return (ENOMEM); 1213212109Syongari } 1214212109Syongari *paddr = ctx.sis_busaddr; 1215212109Syongari return (0); 1216212109Syongari} 121750974Swpaul 1218212109Syongaristatic int 1219212109Syongarisis_dma_alloc(struct sis_softc *sc) 1220212109Syongari{ 1221212109Syongari struct sis_rxdesc *rxd; 1222212109Syongari struct sis_txdesc *txd; 1223212109Syongari int error, i; 122450974Swpaul 1225212109Syongari /* Allocate the parent bus DMA tag appropriate for PCI. */ 1226212109Syongari error = bus_dma_tag_create(bus_get_dma_tag(sc->sis_dev), 1227212109Syongari 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1228212109Syongari NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 1229212109Syongari 0, NULL, NULL, &sc->sis_parent_tag); 1230212109Syongari if (error != 0) { 1231212109Syongari device_printf(sc->sis_dev, 1232212109Syongari "could not allocate parent dma tag\n"); 1233212109Syongari return (ENOMEM); 1234212109Syongari } 1235212109Syongari 1236212109Syongari /* Create RX ring. */ 1237212109Syongari error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_RX_LIST_SZ, 1238212109Syongari &sc->sis_rx_list_tag, (uint8_t **)&sc->sis_rx_list, 1239212109Syongari &sc->sis_rx_list_map, &sc->sis_rx_paddr, "RX ring"); 1240212109Syongari if (error) 1241212109Syongari return (error); 1242212109Syongari 1243212109Syongari /* Create TX ring. */ 1244212109Syongari error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_TX_LIST_SZ, 1245212109Syongari &sc->sis_tx_list_tag, (uint8_t **)&sc->sis_tx_list, 1246212109Syongari &sc->sis_tx_list_map, &sc->sis_tx_paddr, "TX ring"); 1247212109Syongari if (error) 1248212109Syongari return (error); 1249212109Syongari 1250212109Syongari /* Create tag for RX mbufs. */ 1251212109Syongari error = bus_dma_tag_create(sc->sis_parent_tag, SIS_RX_BUF_ALIGN, 0, 1252212109Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, 1253212109Syongari MCLBYTES, 0, NULL, NULL, &sc->sis_rx_tag); 1254212109Syongari if (error) { 1255212109Syongari device_printf(sc->sis_dev, "could not allocate RX dma tag\n"); 1256212109Syongari return (error); 1257212109Syongari } 1258212109Syongari 1259212109Syongari /* Create tag for TX mbufs. */ 1260212109Syongari error = bus_dma_tag_create(sc->sis_parent_tag, 1, 0, 1261212109Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 1262212109Syongari MCLBYTES * SIS_MAXTXSEGS, SIS_MAXTXSEGS, MCLBYTES, 0, NULL, NULL, 1263212109Syongari &sc->sis_tx_tag); 1264212109Syongari if (error) { 1265212109Syongari device_printf(sc->sis_dev, "could not allocate TX dma tag\n"); 1266212109Syongari return (error); 1267212109Syongari } 1268212109Syongari 1269212109Syongari /* Create DMA maps for RX buffers. */ 1270212109Syongari error = bus_dmamap_create(sc->sis_rx_tag, 0, &sc->sis_rx_sparemap); 1271212109Syongari if (error) { 1272212109Syongari device_printf(sc->sis_dev, 1273212109Syongari "can't create spare DMA map for RX\n"); 1274212109Syongari return (error); 1275212109Syongari } 1276212109Syongari for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1277212109Syongari rxd = &sc->sis_rxdesc[i]; 1278212109Syongari rxd->rx_m = NULL; 1279212109Syongari error = bus_dmamap_create(sc->sis_rx_tag, 0, &rxd->rx_dmamap); 1280212109Syongari if (error) { 1281212109Syongari device_printf(sc->sis_dev, 1282212109Syongari "can't create DMA map for RX\n"); 1283212109Syongari return (error); 1284212109Syongari } 1285212109Syongari } 1286212109Syongari 1287212109Syongari /* Create DMA maps for TX buffers. */ 1288212109Syongari for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1289212109Syongari txd = &sc->sis_txdesc[i]; 1290212109Syongari txd->tx_m = NULL; 1291212109Syongari error = bus_dmamap_create(sc->sis_tx_tag, 0, &txd->tx_dmamap); 1292212109Syongari if (error) { 1293212109Syongari device_printf(sc->sis_dev, 1294212109Syongari "can't create DMA map for TX\n"); 1295212109Syongari return (error); 1296212109Syongari } 1297212109Syongari } 1298212109Syongari 1299212104Syongari return (0); 130050974Swpaul} 130150974Swpaul 1302212109Syongaristatic void 1303212109Syongarisis_dma_free(struct sis_softc *sc) 1304212109Syongari{ 1305212109Syongari struct sis_rxdesc *rxd; 1306212109Syongari struct sis_txdesc *txd; 1307212109Syongari int i; 1308212109Syongari 1309212109Syongari /* Destroy DMA maps for RX buffers. */ 1310212109Syongari for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1311212109Syongari rxd = &sc->sis_rxdesc[i]; 1312212109Syongari if (rxd->rx_dmamap) 1313212109Syongari bus_dmamap_destroy(sc->sis_rx_tag, rxd->rx_dmamap); 1314212109Syongari } 1315212109Syongari if (sc->sis_rx_sparemap) 1316212109Syongari bus_dmamap_destroy(sc->sis_rx_tag, sc->sis_rx_sparemap); 1317212109Syongari 1318212109Syongari /* Destroy DMA maps for TX buffers. */ 1319212109Syongari for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1320212109Syongari txd = &sc->sis_txdesc[i]; 1321212109Syongari if (txd->tx_dmamap) 1322212109Syongari bus_dmamap_destroy(sc->sis_tx_tag, txd->tx_dmamap); 1323212109Syongari } 1324212109Syongari 1325212109Syongari if (sc->sis_rx_tag) 1326212109Syongari bus_dma_tag_destroy(sc->sis_rx_tag); 1327212109Syongari if (sc->sis_tx_tag) 1328212109Syongari bus_dma_tag_destroy(sc->sis_tx_tag); 1329212109Syongari 1330212109Syongari /* Destroy RX ring. */ 1331212109Syongari if (sc->sis_rx_list_map) 1332212109Syongari bus_dmamap_unload(sc->sis_rx_list_tag, sc->sis_rx_list_map); 1333212109Syongari if (sc->sis_rx_list_map && sc->sis_rx_list) 1334212109Syongari bus_dmamem_free(sc->sis_rx_list_tag, sc->sis_rx_list, 1335212109Syongari sc->sis_rx_list_map); 1336212109Syongari 1337212109Syongari if (sc->sis_rx_list_tag) 1338212109Syongari bus_dma_tag_destroy(sc->sis_rx_list_tag); 1339212109Syongari 1340212109Syongari /* Destroy TX ring. */ 1341212109Syongari if (sc->sis_tx_list_map) 1342212109Syongari bus_dmamap_unload(sc->sis_tx_list_tag, sc->sis_tx_list_map); 1343212109Syongari 1344212109Syongari if (sc->sis_tx_list_map && sc->sis_tx_list) 1345212109Syongari bus_dmamem_free(sc->sis_tx_list_tag, sc->sis_tx_list, 1346212109Syongari sc->sis_tx_list_map); 1347212109Syongari 1348212109Syongari if (sc->sis_tx_list_tag) 1349212109Syongari bus_dma_tag_destroy(sc->sis_tx_list_tag); 1350212109Syongari 1351212109Syongari /* Destroy the parent tag. */ 1352212109Syongari if (sc->sis_parent_tag) 1353212109Syongari bus_dma_tag_destroy(sc->sis_parent_tag); 1354212109Syongari} 1355212109Syongari 135650974Swpaul/* 1357139802Sphk * Initialize the TX and RX descriptors and allocate mbufs for them. Note that 1358139802Sphk * we arrange the descriptors in a closed ring, so that the last descriptor 1359139802Sphk * points back to the first. 136050974Swpaul */ 1361102334Salfredstatic int 1362139802Sphksis_ring_init(struct sis_softc *sc) 136350974Swpaul{ 1364212109Syongari struct sis_rxdesc *rxd; 1365212109Syongari struct sis_txdesc *txd; 1366212109Syongari bus_addr_t next; 1367212109Syongari int error, i; 136850974Swpaul 1369212109Syongari bzero(&sc->sis_tx_list[0], SIS_TX_LIST_SZ); 1370212109Syongari for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1371212109Syongari txd = &sc->sis_txdesc[i]; 1372212109Syongari txd->tx_m = NULL; 1373212109Syongari if (i == SIS_TX_LIST_CNT - 1) 1374212109Syongari next = SIS_TX_RING_ADDR(sc, 0); 1375139802Sphk else 1376212109Syongari next = SIS_TX_RING_ADDR(sc, i + 1); 1377212109Syongari sc->sis_tx_list[i].sis_next = htole32(SIS_ADDR_LO(next)); 137850974Swpaul } 1379139690Sphk sc->sis_tx_prod = sc->sis_tx_cons = sc->sis_tx_cnt = 0; 1380212109Syongari bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1381212109Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 138250974Swpaul 1383212109Syongari sc->sis_rx_cons = 0; 1384212109Syongari bzero(&sc->sis_rx_list[0], SIS_RX_LIST_SZ); 1385212109Syongari for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1386212109Syongari rxd = &sc->sis_rxdesc[i]; 1387212109Syongari rxd->rx_desc = &sc->sis_rx_list[i]; 1388212109Syongari if (i == SIS_RX_LIST_CNT - 1) 1389212109Syongari next = SIS_RX_RING_ADDR(sc, 0); 1390212109Syongari else 1391212109Syongari next = SIS_RX_RING_ADDR(sc, i + 1); 1392212109Syongari rxd->rx_desc->sis_next = htole32(SIS_ADDR_LO(next)); 1393212109Syongari error = sis_newbuf(sc, rxd); 1394139802Sphk if (error) 1395212104Syongari return (error); 1396212109Syongari } 1397212109Syongari bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1398212109Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 139950974Swpaul 1400212104Syongari return (0); 140150974Swpaul} 140250974Swpaul 140350974Swpaul/* 140450974Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 140550974Swpaul */ 1406102334Salfredstatic int 1407212109Syongarisis_newbuf(struct sis_softc *sc, struct sis_rxdesc *rxd) 140850974Swpaul{ 1409212109Syongari struct mbuf *m; 1410212109Syongari bus_dma_segment_t segs[1]; 1411212109Syongari bus_dmamap_t map; 1412212109Syongari int nsegs; 141350974Swpaul 1414243857Sglebius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1415212109Syongari if (m == NULL) 1416212109Syongari return (ENOBUFS); 1417212109Syongari m->m_len = m->m_pkthdr.len = SIS_RXLEN; 1418212109Syongari#ifndef __NO_STRICT_ALIGNMENT 1419212109Syongari m_adj(m, SIS_RX_BUF_ALIGN); 1420212109Syongari#endif 142181713Swpaul 1422212109Syongari if (bus_dmamap_load_mbuf_sg(sc->sis_rx_tag, sc->sis_rx_sparemap, m, 1423212109Syongari segs, &nsegs, 0) != 0) { 1424212109Syongari m_freem(m); 1425212109Syongari return (ENOBUFS); 1426212109Syongari } 1427212109Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 142850974Swpaul 1429212109Syongari if (rxd->rx_m != NULL) { 1430212109Syongari bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, 1431212109Syongari BUS_DMASYNC_POSTREAD); 1432212109Syongari bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap); 1433212109Syongari } 1434212109Syongari map = rxd->rx_dmamap; 1435212109Syongari rxd->rx_dmamap = sc->sis_rx_sparemap; 1436212109Syongari sc->sis_rx_sparemap = map; 1437212109Syongari bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_PREREAD); 1438212109Syongari rxd->rx_m = m; 1439219102Syongari rxd->rx_desc->sis_ptr = htole32(SIS_ADDR_LO(segs[0].ds_addr)); 1440212109Syongari rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN); 1441212109Syongari return (0); 1442212109Syongari} 144350974Swpaul 1444212109Syongaristatic __inline void 1445212109Syongarisis_discard_rxbuf(struct sis_rxdesc *rxd) 1446212109Syongari{ 144781713Swpaul 1448212109Syongari rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN); 144950974Swpaul} 145050974Swpaul 1451212109Syongari#ifndef __NO_STRICT_ALIGNMENT 1452212109Syongaristatic __inline void 1453212109Syongarisis_fixup_rx(struct mbuf *m) 1454212109Syongari{ 1455212109Syongari uint16_t *src, *dst; 1456212109Syongari int i; 1457212109Syongari 1458212109Syongari src = mtod(m, uint16_t *); 1459212109Syongari dst = src - (SIS_RX_BUF_ALIGN - ETHER_ALIGN) / sizeof(*src); 1460212109Syongari 1461212109Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1462212109Syongari *dst++ = *src++; 1463212109Syongari 1464212109Syongari m->m_data -= SIS_RX_BUF_ALIGN - ETHER_ALIGN; 1465212109Syongari} 1466212109Syongari#endif 1467212109Syongari 146850974Swpaul/* 146950974Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 147050974Swpaul * the higher level protocols. 147150974Swpaul */ 1472193096Sattiliostatic int 1473139740Sphksis_rxeof(struct sis_softc *sc) 147450974Swpaul{ 1475212109Syongari struct mbuf *m; 1476163773Smarius struct ifnet *ifp; 1477212109Syongari struct sis_rxdesc *rxd; 147850974Swpaul struct sis_desc *cur_rx; 1479212109Syongari int prog, rx_cons, rx_npkts = 0, total_len; 1480212109Syongari uint32_t rxstat; 148150974Swpaul 1482122689Ssam SIS_LOCK_ASSERT(sc); 1483122689Ssam 1484212109Syongari bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1485212109Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1486212109Syongari 1487212109Syongari rx_cons = sc->sis_rx_cons; 1488147256Sbrooks ifp = sc->sis_ifp; 148950974Swpaul 1490212109Syongari for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; 1491212109Syongari SIS_INC(rx_cons, SIS_RX_LIST_CNT), prog++) { 149287902Sluigi#ifdef DEVICE_POLLING 1493150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 149487902Sluigi if (sc->rxcycles <= 0) 149587902Sluigi break; 149687902Sluigi sc->rxcycles--; 149787902Sluigi } 1498150789Sglebius#endif 1499212109Syongari cur_rx = &sc->sis_rx_list[rx_cons]; 1500212109Syongari rxstat = le32toh(cur_rx->sis_cmdsts); 1501212109Syongari if ((rxstat & SIS_CMDSTS_OWN) == 0) 1502212109Syongari break; 1503212109Syongari rxd = &sc->sis_rxdesc[rx_cons]; 150450974Swpaul 1505212109Syongari total_len = (rxstat & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN; 1506185784Syongari if ((ifp->if_capenable & IFCAP_VLAN_MTU) != 0 && 1507185784Syongari total_len <= (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN - 1508185784Syongari ETHER_CRC_LEN)) 1509185784Syongari rxstat &= ~SIS_RXSTAT_GIANT; 1510185784Syongari if (SIS_RXSTAT_ERROR(rxstat) != 0) { 151150974Swpaul ifp->if_ierrors++; 151250974Swpaul if (rxstat & SIS_RXSTAT_COLL) 151350974Swpaul ifp->if_collisions++; 1514212109Syongari sis_discard_rxbuf(rxd); 151550974Swpaul continue; 151650974Swpaul } 151750974Swpaul 1518212109Syongari /* Add a new receive buffer to the ring. */ 1519212109Syongari m = rxd->rx_m; 1520212109Syongari if (sis_newbuf(sc, rxd) != 0) { 1521212109Syongari ifp->if_iqdrops++; 1522212109Syongari sis_discard_rxbuf(rxd); 1523212109Syongari continue; 1524212109Syongari } 1525212109Syongari 1526212103Syongari /* No errors; receive the packet. */ 1527212109Syongari m->m_pkthdr.len = m->m_len = total_len; 1528212109Syongari#ifndef __NO_STRICT_ALIGNMENT 152987059Sluigi /* 1530163773Smarius * On architectures without alignment problems we try to 153187059Sluigi * allocate a new buffer for the receive ring, and pass up 153287059Sluigi * the one where the packet is already, saving the expensive 1533212109Syongari * copy operation. 153487059Sluigi */ 1535212109Syongari sis_fixup_rx(m); 153687059Sluigi#endif 153750974Swpaul ifp->if_ipackets++; 1538106936Ssam m->m_pkthdr.rcvif = ifp; 1539106936Ssam 1540122689Ssam SIS_UNLOCK(sc); 1541106936Ssam (*ifp->if_input)(ifp, m); 1542122689Ssam SIS_LOCK(sc); 1543193096Sattilio rx_npkts++; 154450974Swpaul } 154550974Swpaul 1546212109Syongari if (prog > 0) { 1547212109Syongari sc->sis_rx_cons = rx_cons; 1548212109Syongari bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1549212109Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1550212109Syongari } 1551212109Syongari 1552193096Sattilio return (rx_npkts); 155350974Swpaul} 155450974Swpaul 155550974Swpaul/* 155650974Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 155750974Swpaul * the list buffers. 155850974Swpaul */ 155950974Swpaul 1560102334Salfredstatic void 1561139740Sphksis_txeof(struct sis_softc *sc) 156250974Swpaul{ 156350974Swpaul struct ifnet *ifp; 1564212109Syongari struct sis_desc *cur_tx; 1565212109Syongari struct sis_txdesc *txd; 1566212109Syongari uint32_t cons, txstat; 156750974Swpaul 1568139715Sphk SIS_LOCK_ASSERT(sc); 1569212109Syongari 1570212109Syongari cons = sc->sis_tx_cons; 1571212109Syongari if (cons == sc->sis_tx_prod) 1572212109Syongari return; 1573212109Syongari 1574147256Sbrooks ifp = sc->sis_ifp; 1575212109Syongari bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1576212109Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 157750974Swpaul 157850974Swpaul /* 157950974Swpaul * Go through our tx list and free mbufs for those 158050974Swpaul * frames that have been transmitted. 158150974Swpaul */ 1582212109Syongari for (; cons != sc->sis_tx_prod; SIS_INC(cons, SIS_TX_LIST_CNT)) { 1583212109Syongari cur_tx = &sc->sis_tx_list[cons]; 1584212109Syongari txstat = le32toh(cur_tx->sis_cmdsts); 1585212109Syongari if ((txstat & SIS_CMDSTS_OWN) != 0) 158650974Swpaul break; 1587212109Syongari txd = &sc->sis_txdesc[cons]; 1588212109Syongari if (txd->tx_m != NULL) { 1589212109Syongari bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, 1590212109Syongari BUS_DMASYNC_POSTWRITE); 1591212109Syongari bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 1592212109Syongari m_freem(txd->tx_m); 1593212109Syongari txd->tx_m = NULL; 1594212109Syongari if ((txstat & SIS_CMDSTS_PKT_OK) != 0) { 1595212109Syongari ifp->if_opackets++; 1596212109Syongari ifp->if_collisions += 1597212109Syongari (txstat & SIS_TXSTAT_COLLCNT) >> 16; 1598212109Syongari } else { 1599212109Syongari ifp->if_oerrors++; 1600212109Syongari if (txstat & SIS_TXSTAT_EXCESSCOLLS) 1601212109Syongari ifp->if_collisions++; 1602212109Syongari if (txstat & SIS_TXSTAT_OUTOFWINCOLL) 1603212109Syongari ifp->if_collisions++; 1604212109Syongari } 160550974Swpaul } 1606212109Syongari sc->sis_tx_cnt--; 1607148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 160850974Swpaul } 1609212109Syongari sc->sis_tx_cons = cons; 1610212109Syongari if (sc->sis_tx_cnt == 0) 1611212109Syongari sc->sis_watchdog_timer = 0; 161250974Swpaul} 161350974Swpaul 1614102334Salfredstatic void 1615139740Sphksis_tick(void *xsc) 161650974Swpaul{ 161750974Swpaul struct sis_softc *sc; 161850974Swpaul struct mii_data *mii; 161950974Swpaul 162050974Swpaul sc = xsc; 1621150583Sjhb SIS_LOCK_ASSERT(sc); 162264963Swpaul 162350974Swpaul mii = device_get_softc(sc->sis_miibus); 162450974Swpaul mii_tick(mii); 1625166940Sdelphij sis_watchdog(sc); 1626212157Syongari if ((sc->sis_flags & SIS_FLAG_LINK) == 0) 1627212116Syongari sis_miibus_statchg(sc->sis_dev); 1628119785Ssam callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); 162950974Swpaul} 163050974Swpaul 163187902Sluigi#ifdef DEVICE_POLLING 163287902Sluigistatic poll_handler_t sis_poll; 163387902Sluigi 1634193096Sattiliostatic int 163587902Sluigisis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 163687902Sluigi{ 163787973Speter struct sis_softc *sc = ifp->if_softc; 1638193096Sattilio int rx_npkts = 0; 163987973Speter 164087902Sluigi SIS_LOCK(sc); 1641150789Sglebius if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1642150789Sglebius SIS_UNLOCK(sc); 1643193096Sattilio return (rx_npkts); 1644128138Sru } 164587902Sluigi 164687902Sluigi /* 164787902Sluigi * On the sis, reading the status register also clears it. 164887902Sluigi * So before returning to intr mode we must make sure that all 164987902Sluigi * possible pending sources of interrupts have been served. 165087902Sluigi * In practice this means run to completion the *eof routines, 165187902Sluigi * and then call the interrupt routine 165287902Sluigi */ 165387902Sluigi sc->rxcycles = count; 1654193096Sattilio rx_npkts = sis_rxeof(sc); 165587902Sluigi sis_txeof(sc); 1656131455Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1657139714Sphk sis_startl(ifp); 165887902Sluigi 165987902Sluigi if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1660212113Syongari uint32_t status; 166187902Sluigi 166287902Sluigi /* Reading the ISR register clears all interrupts. */ 166387902Sluigi status = CSR_READ_4(sc, SIS_ISR); 166487902Sluigi 166587902Sluigi if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW)) 1666206909Sbrucec ifp->if_ierrors++; 166787902Sluigi 166887902Sluigi if (status & (SIS_ISR_RX_IDLE)) 166987902Sluigi SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 167087902Sluigi 167187902Sluigi if (status & SIS_ISR_SYSERR) { 1672212120Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1673139715Sphk sis_initl(sc); 167487902Sluigi } 167587902Sluigi } 1676150789Sglebius 167787902Sluigi SIS_UNLOCK(sc); 1678193096Sattilio return (rx_npkts); 167987902Sluigi} 168087902Sluigi#endif /* DEVICE_POLLING */ 168187902Sluigi 1682102334Salfredstatic void 1683139740Sphksis_intr(void *arg) 168450974Swpaul{ 168550974Swpaul struct sis_softc *sc; 168650974Swpaul struct ifnet *ifp; 1687212113Syongari uint32_t status; 168850974Swpaul 168950974Swpaul sc = arg; 1690147256Sbrooks ifp = sc->sis_ifp; 169150974Swpaul 169286984Sluigi SIS_LOCK(sc); 169387902Sluigi#ifdef DEVICE_POLLING 1694150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 1695150789Sglebius SIS_UNLOCK(sc); 1696150789Sglebius return; 169787902Sluigi } 1698150789Sglebius#endif 169987902Sluigi 1700212116Syongari /* Reading the ISR register clears all interrupts. */ 1701212116Syongari status = CSR_READ_4(sc, SIS_ISR); 1702212116Syongari if ((status & SIS_INTRS) == 0) { 1703212116Syongari /* Not ours. */ 1704212116Syongari SIS_UNLOCK(sc); 1705214089Syongari return; 1706212116Syongari } 1707212116Syongari 170850974Swpaul /* Disable interrupts. */ 170950974Swpaul CSR_WRITE_4(sc, SIS_IER, 0); 171050974Swpaul 1711212116Syongari for (;(status & SIS_INTRS) != 0;) { 1712214089Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1713214089Syongari break; 171486984Sluigi if (status & 171586984Sluigi (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR | 1716212103Syongari SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) ) 171750974Swpaul sis_txeof(sc); 171850974Swpaul 1719188550Syongari if (status & (SIS_ISR_RX_DESC_OK | SIS_ISR_RX_OK | 1720188550Syongari SIS_ISR_RX_ERR | SIS_ISR_RX_IDLE)) 172150974Swpaul sis_rxeof(sc); 172250974Swpaul 1723188550Syongari if (status & SIS_ISR_RX_OFLOW) 1724206909Sbrucec ifp->if_ierrors++; 172550974Swpaul 172686984Sluigi if (status & (SIS_ISR_RX_IDLE)) 172786984Sluigi SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 172886984Sluigi 172950974Swpaul if (status & SIS_ISR_SYSERR) { 1730212120Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1731139715Sphk sis_initl(sc); 1732212116Syongari SIS_UNLOCK(sc); 1733212116Syongari return; 173450974Swpaul } 1735212116Syongari status = CSR_READ_4(sc, SIS_ISR); 173650974Swpaul } 173750974Swpaul 1738214089Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1739214089Syongari /* Re-enable interrupts. */ 1740214089Syongari CSR_WRITE_4(sc, SIS_IER, 1); 174150974Swpaul 1742214089Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1743214089Syongari sis_startl(ifp); 1744214089Syongari } 1745139809Sphk 174667087Swpaul SIS_UNLOCK(sc); 174750974Swpaul} 174850974Swpaul 174950974Swpaul/* 175050974Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 175150974Swpaul * pointers to the fragment pointers. 175250974Swpaul */ 1753102334Salfredstatic int 1754212109Syongarisis_encap(struct sis_softc *sc, struct mbuf **m_head) 175550974Swpaul{ 175650974Swpaul struct mbuf *m; 1757212109Syongari struct sis_txdesc *txd; 1758212109Syongari struct sis_desc *f; 1759212109Syongari bus_dma_segment_t segs[SIS_MAXTXSEGS]; 1760212109Syongari bus_dmamap_t map; 1761212109Syongari int error, i, frag, nsegs, prod; 1762212157Syongari int padlen; 176350974Swpaul 1764212109Syongari prod = sc->sis_tx_prod; 1765212109Syongari txd = &sc->sis_txdesc[prod]; 1766212157Syongari if ((sc->sis_flags & SIS_FLAG_MANUAL_PAD) != 0 && 1767212157Syongari (*m_head)->m_pkthdr.len < SIS_MIN_FRAMELEN) { 1768212157Syongari m = *m_head; 1769212157Syongari padlen = SIS_MIN_FRAMELEN - m->m_pkthdr.len; 1770212157Syongari if (M_WRITABLE(m) == 0) { 1771212157Syongari /* Get a writable copy. */ 1772243857Sglebius m = m_dup(*m_head, M_NOWAIT); 1773212157Syongari m_freem(*m_head); 1774212157Syongari if (m == NULL) { 1775212157Syongari *m_head = NULL; 1776212157Syongari return (ENOBUFS); 1777212157Syongari } 1778212157Syongari *m_head = m; 1779212157Syongari } 1780212157Syongari if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) { 1781243857Sglebius m = m_defrag(m, M_NOWAIT); 1782212157Syongari if (m == NULL) { 1783212157Syongari m_freem(*m_head); 1784212157Syongari *m_head = NULL; 1785212157Syongari return (ENOBUFS); 1786212157Syongari } 1787212157Syongari } 1788212157Syongari /* 1789212157Syongari * Manually pad short frames, and zero the pad space 1790212157Syongari * to avoid leaking data. 1791212157Syongari */ 1792212157Syongari bzero(mtod(m, char *) + m->m_pkthdr.len, padlen); 1793212157Syongari m->m_pkthdr.len += padlen; 1794212157Syongari m->m_len = m->m_pkthdr.len; 1795212157Syongari *m_head = m; 1796212157Syongari } 1797212109Syongari error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap, 1798212109Syongari *m_head, segs, &nsegs, 0); 1799212109Syongari if (error == EFBIG) { 1800243857Sglebius m = m_collapse(*m_head, M_NOWAIT, SIS_MAXTXSEGS); 1801212109Syongari if (m == NULL) { 1802212109Syongari m_freem(*m_head); 1803212109Syongari *m_head = NULL; 1804112808Ssilby return (ENOBUFS); 1805212109Syongari } 1806121262Ssilby *m_head = m; 1807212109Syongari error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap, 1808212109Syongari *m_head, segs, &nsegs, 0); 1809212109Syongari if (error != 0) { 1810212109Syongari m_freem(*m_head); 1811212109Syongari *m_head = NULL; 1812212109Syongari return (error); 1813212109Syongari } 1814212109Syongari } else if (error != 0) 1815212109Syongari return (error); 1816212109Syongari 1817212109Syongari /* Check for descriptor overruns. */ 1818212109Syongari if (sc->sis_tx_cnt + nsegs > SIS_TX_LIST_CNT - 1) { 1819212109Syongari bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 1820212109Syongari return (ENOBUFS); 1821112808Ssilby } 1822212103Syongari 1823212109Syongari bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, BUS_DMASYNC_PREWRITE); 182450974Swpaul 1825212109Syongari frag = prod; 1826212109Syongari for (i = 0; i < nsegs; i++) { 1827212109Syongari f = &sc->sis_tx_list[prod]; 1828212109Syongari if (i == 0) 1829212109Syongari f->sis_cmdsts = htole32(segs[i].ds_len | 1830212109Syongari SIS_CMDSTS_MORE); 1831212109Syongari else 1832212109Syongari f->sis_cmdsts = htole32(segs[i].ds_len | 1833212109Syongari SIS_CMDSTS_OWN | SIS_CMDSTS_MORE); 1834212109Syongari f->sis_ptr = htole32(SIS_ADDR_LO(segs[i].ds_addr)); 1835212109Syongari SIS_INC(prod, SIS_TX_LIST_CNT); 1836212109Syongari sc->sis_tx_cnt++; 183750974Swpaul } 183850974Swpaul 1839212109Syongari /* Update producer index. */ 1840212109Syongari sc->sis_tx_prod = prod; 184150974Swpaul 1842212109Syongari /* Remove MORE flag on the last descriptor. */ 1843212109Syongari prod = (prod - 1) & (SIS_TX_LIST_CNT - 1); 1844212109Syongari f = &sc->sis_tx_list[prod]; 1845212109Syongari f->sis_cmdsts &= ~htole32(SIS_CMDSTS_MORE); 184650974Swpaul 1847212109Syongari /* Lastly transfer ownership of packet to the controller. */ 1848212109Syongari f = &sc->sis_tx_list[frag]; 1849212109Syongari f->sis_cmdsts |= htole32(SIS_CMDSTS_OWN); 1850212109Syongari 1851212109Syongari /* Swap the last and the first dmamaps. */ 1852212109Syongari map = txd->tx_dmamap; 1853212124Syongari txd->tx_dmamap = sc->sis_txdesc[prod].tx_dmamap; 1854212124Syongari sc->sis_txdesc[prod].tx_dmamap = map; 1855212185Syongari sc->sis_txdesc[prod].tx_m = *m_head; 1856212109Syongari 1857212104Syongari return (0); 185850974Swpaul} 185950974Swpaul 1860102334Salfredstatic void 1861139717Sphksis_start(struct ifnet *ifp) 186250974Swpaul{ 186350974Swpaul struct sis_softc *sc; 1864139714Sphk 1865139714Sphk sc = ifp->if_softc; 1866139714Sphk SIS_LOCK(sc); 1867139714Sphk sis_startl(ifp); 1868139714Sphk SIS_UNLOCK(sc); 1869139714Sphk} 1870139714Sphk 1871139714Sphkstatic void 1872139714Sphksis_startl(struct ifnet *ifp) 1873139714Sphk{ 1874139714Sphk struct sis_softc *sc; 1875212109Syongari struct mbuf *m_head; 1876212109Syongari int queued; 187750974Swpaul 187850974Swpaul sc = ifp->if_softc; 187950974Swpaul 1880139714Sphk SIS_LOCK_ASSERT(sc); 1881139714Sphk 1882212109Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1883212157Syongari IFF_DRV_RUNNING || (sc->sis_flags & SIS_FLAG_LINK) == 0) 188464963Swpaul return; 188564963Swpaul 1886212109Syongari for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 1887212109Syongari sc->sis_tx_cnt < SIS_TX_LIST_CNT - 4;) { 1888131455Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 188950974Swpaul if (m_head == NULL) 189050974Swpaul break; 189150974Swpaul 1892212109Syongari if (sis_encap(sc, &m_head) != 0) { 1893212109Syongari if (m_head == NULL) 1894212109Syongari break; 1895131455Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1896148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 189750974Swpaul break; 189850974Swpaul } 189950974Swpaul 1900136269Smlaier queued++; 1901136269Smlaier 190250974Swpaul /* 190350974Swpaul * If there's a BPF listener, bounce a copy of this frame 190450974Swpaul * to him. 190550974Swpaul */ 1906106936Ssam BPF_MTAP(ifp, m_head); 190750974Swpaul } 190850974Swpaul 1909136269Smlaier if (queued) { 1910136269Smlaier /* Transmit */ 1911212109Syongari bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1912212109Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1913136269Smlaier SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE); 191450974Swpaul 1915136269Smlaier /* 1916136269Smlaier * Set a timeout in case the chip goes out to lunch. 1917136269Smlaier */ 1918166940Sdelphij sc->sis_watchdog_timer = 5; 1919136269Smlaier } 192050974Swpaul} 192150974Swpaul 1922102334Salfredstatic void 1923139715Sphksis_init(void *xsc) 192450974Swpaul{ 192550974Swpaul struct sis_softc *sc = xsc; 1926139715Sphk 1927139715Sphk SIS_LOCK(sc); 1928139717Sphk sis_initl(sc); 1929139715Sphk SIS_UNLOCK(sc); 1930139715Sphk} 1931139715Sphk 1932139715Sphkstatic void 1933139717Sphksis_initl(struct sis_softc *sc) 1934139715Sphk{ 1935147256Sbrooks struct ifnet *ifp = sc->sis_ifp; 193650974Swpaul struct mii_data *mii; 1937212156Syongari uint8_t *eaddr; 193850974Swpaul 1939139715Sphk SIS_LOCK_ASSERT(sc); 194050974Swpaul 1941212120Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1942212120Syongari return; 1943212120Syongari 194450974Swpaul /* 194550974Swpaul * Cancel pending I/O and free all RX/TX buffers. 194650974Swpaul */ 194750974Swpaul sis_stop(sc); 1948212121Syongari /* 1949212121Syongari * Reset the chip to a known state. 1950212121Syongari */ 1951212121Syongari sis_reset(sc); 1952119712Sphk#ifdef notyet 1953119712Sphk if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr >= NS_SRR_16A) { 1954119712Sphk /* 1955119712Sphk * Configure 400usec of interrupt holdoff. This is based 1956119712Sphk * on emperical tests on a Soekris 4801. 1957119712Sphk */ 1958119712Sphk CSR_WRITE_4(sc, NS_IHR, 0x100 | 4); 1959119712Sphk } 1960119712Sphk#endif 1961119712Sphk 196250974Swpaul mii = device_get_softc(sc->sis_miibus); 196350974Swpaul 196450974Swpaul /* Set MAC address */ 1965212156Syongari eaddr = IF_LLADDR(sc->sis_ifp); 196662672Swpaul if (sc->sis_type == SIS_TYPE_83815) { 196762672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); 1968212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[0] | eaddr[1] << 8); 196962672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); 1970212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[2] | eaddr[3] << 8); 197162672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); 1972212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[4] | eaddr[5] << 8); 197362672Swpaul } else { 197462672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 1975212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[0] | eaddr[1] << 8); 197662672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1); 1977212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[2] | eaddr[3] << 8); 197862672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 1979212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[4] | eaddr[5] << 8); 198062672Swpaul } 198150974Swpaul 1982139802Sphk /* Init circular TX/RX lists. */ 1983139802Sphk if (sis_ring_init(sc) != 0) { 1984162315Sglebius device_printf(sc->sis_dev, 1985150583Sjhb "initialization failed: no memory for rx buffers\n"); 198650974Swpaul sis_stop(sc); 198750974Swpaul return; 198850974Swpaul } 198950974Swpaul 1990248456Syongari if (sc->sis_type == SIS_TYPE_83815) { 1991212157Syongari if (sc->sis_manual_pad != 0) 1992212157Syongari sc->sis_flags |= SIS_FLAG_MANUAL_PAD; 1993212157Syongari else 1994212157Syongari sc->sis_flags &= ~SIS_FLAG_MANUAL_PAD; 1995212157Syongari } 1996212157Syongari 199750974Swpaul /* 1998139806Sphk * Short Cable Receive Errors (MP21.E) 1999139806Sphk * also: Page 78 of the DP83815 data sheet (september 2002 version) 2000123491Sphk * recommends the following register settings "for optimum 2001181002Sjhb * performance." for rev 15C. Set this also for 15D parts as 2002181002Sjhb * they require it in practice. 2003123491Sphk */ 2004139806Sphk if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr <= NS_SRR_15D) { 2005123491Sphk CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); 2006123491Sphk CSR_WRITE_4(sc, NS_PHY_CR, 0x189C); 2007181002Sjhb /* set val for c2 */ 2008181002Sjhb CSR_WRITE_4(sc, NS_PHY_TDATA, 0x0000); 2009181002Sjhb /* load/kill c2 */ 2010181002Sjhb CSR_WRITE_4(sc, NS_PHY_DSPCFG, 0x5040); 2011181002Sjhb /* rais SD off, from 4 to c */ 2012181002Sjhb CSR_WRITE_4(sc, NS_PHY_SDCFG, 0x008C); 2013123491Sphk CSR_WRITE_4(sc, NS_PHY_PAGE, 0); 2014123491Sphk } 2015123491Sphk 2016217548Syongari sis_rxfilter(sc); 201750974Swpaul /* Turn the receive filter on */ 201850974Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE); 201950974Swpaul 202050974Swpaul /* 202150974Swpaul * Load the address of the RX and TX lists. 202250974Swpaul */ 2023212109Syongari CSR_WRITE_4(sc, SIS_RX_LISTPTR, SIS_ADDR_LO(sc->sis_rx_paddr)); 2024212109Syongari CSR_WRITE_4(sc, SIS_TX_LISTPTR, SIS_ADDR_LO(sc->sis_tx_paddr)); 202550974Swpaul 2026109059Smbr /* SIS_CFG_EDB_MASTER_EN indicates the EDB bus is used instead of 2027109059Smbr * the PCI bus. When this bit is set, the Max DMA Burst Size 2028109059Smbr * for TX/RX DMA should be no larger than 16 double words. 2029109059Smbr */ 2030109059Smbr if (CSR_READ_4(sc, SIS_CFG) & SIS_CFG_EDB_MASTER_EN) { 2031109059Smbr CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG64); 2032109059Smbr } else { 2033109059Smbr CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG256); 2034109059Smbr } 203564963Swpaul 203687390Sjhay /* Accept Long Packets for VLAN support */ 203787390Sjhay SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER); 203887390Sjhay 2039212116Syongari /* 2040212116Syongari * Assume 100Mbps link, actual MAC configuration is done 2041212116Syongari * after getting a valid link. 2042212116Syongari */ 2043212116Syongari CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); 204450974Swpaul 204550974Swpaul /* 204650974Swpaul * Enable interrupts. 204750974Swpaul */ 204850974Swpaul CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS); 204987902Sluigi#ifdef DEVICE_POLLING 205087902Sluigi /* 205187902Sluigi * ... only enable interrupts if we are not polling, make sure 205287902Sluigi * they are off otherwise. 205387902Sluigi */ 2054150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 205587902Sluigi CSR_WRITE_4(sc, SIS_IER, 0); 205687902Sluigi else 2057150789Sglebius#endif 205850974Swpaul CSR_WRITE_4(sc, SIS_IER, 1); 205950974Swpaul 2060212116Syongari /* Clear MAC disable. */ 2061212116Syongari SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE); 206250974Swpaul 2063212157Syongari sc->sis_flags &= ~SIS_FLAG_LINK; 206450974Swpaul mii_mediachg(mii); 206550974Swpaul 2066148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2067148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 206850974Swpaul 2069212116Syongari callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); 207050974Swpaul} 207150974Swpaul 207250974Swpaul/* 207350974Swpaul * Set media options. 207450974Swpaul */ 2075102334Salfredstatic int 2076139740Sphksis_ifmedia_upd(struct ifnet *ifp) 207750974Swpaul{ 207850974Swpaul struct sis_softc *sc; 207964963Swpaul struct mii_data *mii; 2080221407Smarius struct mii_softc *miisc; 2081212117Syongari int error; 208250974Swpaul 208350974Swpaul sc = ifp->if_softc; 208450974Swpaul 2085150583Sjhb SIS_LOCK(sc); 208664963Swpaul mii = device_get_softc(sc->sis_miibus); 2087221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 2088221407Smarius PHY_RESET(miisc); 2089212117Syongari error = mii_mediachg(mii); 2090150583Sjhb SIS_UNLOCK(sc); 209150974Swpaul 2092212117Syongari return (error); 209350974Swpaul} 209450974Swpaul 209550974Swpaul/* 209650974Swpaul * Report current media status. 209750974Swpaul */ 2098102334Salfredstatic void 2099139740Sphksis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 210050974Swpaul{ 210150974Swpaul struct sis_softc *sc; 210250974Swpaul struct mii_data *mii; 210350974Swpaul 210450974Swpaul sc = ifp->if_softc; 210550974Swpaul 2106150583Sjhb SIS_LOCK(sc); 210750974Swpaul mii = device_get_softc(sc->sis_miibus); 210850974Swpaul mii_pollstat(mii); 210950974Swpaul ifmr->ifm_active = mii->mii_media_active; 211050974Swpaul ifmr->ifm_status = mii->mii_media_status; 2111226478Syongari SIS_UNLOCK(sc); 211250974Swpaul} 211350974Swpaul 2114102334Salfredstatic int 2115139740Sphksis_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 211650974Swpaul{ 211750974Swpaul struct sis_softc *sc = ifp->if_softc; 211850974Swpaul struct ifreq *ifr = (struct ifreq *) data; 211950974Swpaul struct mii_data *mii; 2120212167Syongari int error = 0, mask; 212150974Swpaul 2122212104Syongari switch (command) { 212350974Swpaul case SIOCSIFFLAGS: 2124150583Sjhb SIS_LOCK(sc); 212550974Swpaul if (ifp->if_flags & IFF_UP) { 2126212119Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 2127212119Syongari ((ifp->if_flags ^ sc->sis_if_flags) & 2128217548Syongari (IFF_PROMISC | IFF_ALLMULTI)) != 0) 2129217548Syongari sis_rxfilter(sc); 2130217548Syongari else 2131212119Syongari sis_initl(sc); 2132217548Syongari } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2133139741Sphk sis_stop(sc); 2134212119Syongari sc->sis_if_flags = ifp->if_flags; 2135150583Sjhb SIS_UNLOCK(sc); 213650974Swpaul break; 213750974Swpaul case SIOCADDMULTI: 213850974Swpaul case SIOCDELMULTI: 213981713Swpaul SIS_LOCK(sc); 2140217548Syongari sis_rxfilter(sc); 214181713Swpaul SIS_UNLOCK(sc); 214250974Swpaul break; 214350974Swpaul case SIOCGIFMEDIA: 214450974Swpaul case SIOCSIFMEDIA: 214550974Swpaul mii = device_get_softc(sc->sis_miibus); 214650974Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 214750974Swpaul break; 2148128138Sru case SIOCSIFCAP: 2149212167Syongari SIS_LOCK(sc); 2150212167Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2151150789Sglebius#ifdef DEVICE_POLLING 2152212167Syongari if ((mask & IFCAP_POLLING) != 0 && 2153212167Syongari (IFCAP_POLLING & ifp->if_capabilities) != 0) { 2154212167Syongari ifp->if_capenable ^= IFCAP_POLLING; 2155212167Syongari if ((IFCAP_POLLING & ifp->if_capenable) != 0) { 2156212167Syongari error = ether_poll_register(sis_poll, ifp); 2157212167Syongari if (error != 0) { 2158212167Syongari SIS_UNLOCK(sc); 2159212167Syongari break; 2160212167Syongari } 2161212167Syongari /* Disable interrupts. */ 2162212167Syongari CSR_WRITE_4(sc, SIS_IER, 0); 2163212167Syongari } else { 2164212167Syongari error = ether_poll_deregister(ifp); 2165212167Syongari /* Enable interrupts. */ 2166212167Syongari CSR_WRITE_4(sc, SIS_IER, 1); 2167212167Syongari } 2168150789Sglebius } 2169212167Syongari#endif /* DEVICE_POLLING */ 2170212167Syongari if ((mask & IFCAP_WOL) != 0 && 2171212167Syongari (ifp->if_capabilities & IFCAP_WOL) != 0) { 2172212167Syongari if ((mask & IFCAP_WOL_UCAST) != 0) 2173212167Syongari ifp->if_capenable ^= IFCAP_WOL_UCAST; 2174212167Syongari if ((mask & IFCAP_WOL_MCAST) != 0) 2175212167Syongari ifp->if_capenable ^= IFCAP_WOL_MCAST; 2176212167Syongari if ((mask & IFCAP_WOL_MAGIC) != 0) 2177212167Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 2178150789Sglebius } 2179212167Syongari SIS_UNLOCK(sc); 2180128138Sru break; 218150974Swpaul default: 2182106936Ssam error = ether_ioctl(ifp, command, data); 218350974Swpaul break; 218450974Swpaul } 218550974Swpaul 2186212104Syongari return (error); 218750974Swpaul} 218850974Swpaul 2189102334Salfredstatic void 2190166940Sdelphijsis_watchdog(struct sis_softc *sc) 219150974Swpaul{ 219250974Swpaul 2193166940Sdelphij SIS_LOCK_ASSERT(sc); 219467087Swpaul 2195166940Sdelphij if (sc->sis_watchdog_timer == 0 || --sc->sis_watchdog_timer >0) 2196166940Sdelphij return; 219750974Swpaul 2198166940Sdelphij device_printf(sc->sis_dev, "watchdog timeout\n"); 2199166940Sdelphij sc->sis_ifp->if_oerrors++; 2200166940Sdelphij 2201212121Syongari sc->sis_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2202139715Sphk sis_initl(sc); 220350974Swpaul 2204166940Sdelphij if (!IFQ_DRV_IS_EMPTY(&sc->sis_ifp->if_snd)) 2205166940Sdelphij sis_startl(sc->sis_ifp); 220650974Swpaul} 220750974Swpaul 220850974Swpaul/* 220950974Swpaul * Stop the adapter and free any mbufs allocated to the 221050974Swpaul * RX and TX lists. 221150974Swpaul */ 2212102334Salfredstatic void 2213139740Sphksis_stop(struct sis_softc *sc) 221450974Swpaul{ 2215212109Syongari struct ifnet *ifp; 2216212109Syongari struct sis_rxdesc *rxd; 2217212109Syongari struct sis_txdesc *txd; 2218139805Sphk int i; 221950974Swpaul 2220139717Sphk SIS_LOCK_ASSERT(sc); 2221212116Syongari 2222147256Sbrooks ifp = sc->sis_ifp; 2223166940Sdelphij sc->sis_watchdog_timer = 0; 222450974Swpaul 2225119785Ssam callout_stop(&sc->sis_stat_ch); 222687472Speter 2227148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 222850974Swpaul CSR_WRITE_4(sc, SIS_IER, 0); 222950974Swpaul CSR_WRITE_4(sc, SIS_IMR, 0); 2230139798Sphk CSR_READ_4(sc, SIS_ISR); /* clear any interrupts already pending */ 223150974Swpaul SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE); 223250974Swpaul DELAY(1000); 223350974Swpaul CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0); 223450974Swpaul CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); 223550974Swpaul 2236212157Syongari sc->sis_flags &= ~SIS_FLAG_LINK; 223764963Swpaul 223850974Swpaul /* 223950974Swpaul * Free data in the RX lists. 224050974Swpaul */ 2241212109Syongari for (i = 0; i < SIS_RX_LIST_CNT; i++) { 2242212109Syongari rxd = &sc->sis_rxdesc[i]; 2243212109Syongari if (rxd->rx_m != NULL) { 2244212109Syongari bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, 2245212109Syongari BUS_DMASYNC_POSTREAD); 2246212109Syongari bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap); 2247212109Syongari m_freem(rxd->rx_m); 2248212109Syongari rxd->rx_m = NULL; 2249212109Syongari } 225050974Swpaul } 225150974Swpaul 225250974Swpaul /* 225350974Swpaul * Free the TX list buffers. 225450974Swpaul */ 2255212109Syongari for (i = 0; i < SIS_TX_LIST_CNT; i++) { 2256212109Syongari txd = &sc->sis_txdesc[i]; 2257212109Syongari if (txd->tx_m != NULL) { 2258212109Syongari bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, 2259212109Syongari BUS_DMASYNC_POSTWRITE); 2260212109Syongari bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 2261212109Syongari m_freem(txd->tx_m); 2262212109Syongari txd->tx_m = NULL; 2263212109Syongari } 226450974Swpaul } 226550974Swpaul} 226650974Swpaul 226750974Swpaul/* 226850974Swpaul * Stop all chip I/O so that the kernel's probe routines don't 226950974Swpaul * get confused by errant DMAs when rebooting. 227050974Swpaul */ 2271188463Simpstatic int 2272139717Sphksis_shutdown(device_t dev) 227350974Swpaul{ 227450974Swpaul 2275212167Syongari return (sis_suspend(dev)); 227650974Swpaul} 2277139800Sphk 2278212166Syongaristatic int 2279212166Syongarisis_suspend(device_t dev) 2280212166Syongari{ 2281212166Syongari struct sis_softc *sc; 2282212166Syongari 2283212166Syongari sc = device_get_softc(dev); 2284212166Syongari SIS_LOCK(sc); 2285212166Syongari sis_stop(sc); 2286212167Syongari sis_wol(sc); 2287212166Syongari SIS_UNLOCK(sc); 2288212166Syongari return (0); 2289212166Syongari} 2290212166Syongari 2291212166Syongaristatic int 2292212166Syongarisis_resume(device_t dev) 2293212166Syongari{ 2294212166Syongari struct sis_softc *sc; 2295212166Syongari struct ifnet *ifp; 2296212166Syongari 2297212166Syongari sc = device_get_softc(dev); 2298212166Syongari SIS_LOCK(sc); 2299212166Syongari ifp = sc->sis_ifp; 2300212166Syongari if ((ifp->if_flags & IFF_UP) != 0) { 2301212166Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2302212166Syongari sis_initl(sc); 2303212166Syongari } 2304212166Syongari SIS_UNLOCK(sc); 2305212166Syongari return (0); 2306212166Syongari} 2307212166Syongari 2308212157Syongaristatic void 2309212167Syongarisis_wol(struct sis_softc *sc) 2310212167Syongari{ 2311212167Syongari struct ifnet *ifp; 2312212167Syongari uint32_t val; 2313212167Syongari uint16_t pmstat; 2314212167Syongari int pmc; 2315212167Syongari 2316212167Syongari ifp = sc->sis_ifp; 2317212167Syongari if ((ifp->if_capenable & IFCAP_WOL) == 0) 2318212167Syongari return; 2319212167Syongari 2320212167Syongari if (sc->sis_type == SIS_TYPE_83815) { 2321212167Syongari /* Reset RXDP. */ 2322212167Syongari CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); 2323212167Syongari 2324212167Syongari /* Configure WOL events. */ 2325212167Syongari CSR_READ_4(sc, NS_WCSR); 2326212167Syongari val = 0; 2327212167Syongari if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0) 2328212167Syongari val |= NS_WCSR_WAKE_UCAST; 2329212167Syongari if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) 2330212167Syongari val |= NS_WCSR_WAKE_MCAST; 2331212167Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2332212167Syongari val |= NS_WCSR_WAKE_MAGIC; 2333212167Syongari CSR_WRITE_4(sc, NS_WCSR, val); 2334212167Syongari /* Enable PME and clear PMESTS. */ 2335212167Syongari val = CSR_READ_4(sc, NS_CLKRUN); 2336212167Syongari val |= NS_CLKRUN_PMEENB | NS_CLKRUN_PMESTS; 2337212167Syongari CSR_WRITE_4(sc, NS_CLKRUN, val); 2338212167Syongari /* Enable silent RX mode. */ 2339212167Syongari SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 2340212167Syongari } else { 2341219902Sjhb if (pci_find_cap(sc->sis_dev, PCIY_PMG, &pmc) != 0) 2342212167Syongari return; 2343212167Syongari val = 0; 2344212167Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2345212167Syongari val |= SIS_PWRMAN_WOL_MAGIC; 2346212167Syongari CSR_WRITE_4(sc, SIS_PWRMAN_CTL, val); 2347212167Syongari /* Request PME. */ 2348212167Syongari pmstat = pci_read_config(sc->sis_dev, 2349212167Syongari pmc + PCIR_POWER_STATUS, 2); 2350212167Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 2351212167Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2352212167Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 2353212167Syongari pci_write_config(sc->sis_dev, 2354212167Syongari pmc + PCIR_POWER_STATUS, pmstat, 2); 2355212167Syongari } 2356212167Syongari} 2357212167Syongari 2358212167Syongaristatic void 2359212157Syongarisis_add_sysctls(struct sis_softc *sc) 2360212157Syongari{ 2361212157Syongari struct sysctl_ctx_list *ctx; 2362212157Syongari struct sysctl_oid_list *children; 2363212157Syongari char tn[32]; 2364212157Syongari int unit; 2365212157Syongari 2366212157Syongari ctx = device_get_sysctl_ctx(sc->sis_dev); 2367212157Syongari children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sis_dev)); 2368212157Syongari 2369212157Syongari unit = device_get_unit(sc->sis_dev); 2370212157Syongari /* 2371212157Syongari * Unlike most other controllers, NS DP83815/DP83816 controllers 2372212157Syongari * seem to pad with 0xFF when it encounter short frames. According 2373212157Syongari * to RFC 1042 the pad bytes should be 0x00. Turning this tunable 2374212157Syongari * on will have driver pad manully but it's disabled by default 2375212157Syongari * because it will consume extra CPU cycles for short frames. 2376212157Syongari */ 2377212157Syongari sc->sis_manual_pad = 0; 2378212157Syongari snprintf(tn, sizeof(tn), "dev.sis.%d.manual_pad", unit); 2379212157Syongari TUNABLE_INT_FETCH(tn, &sc->sis_manual_pad); 2380212157Syongari SYSCTL_ADD_INT(ctx, children, OID_AUTO, "manual_pad", 2381212157Syongari CTLFLAG_RW, &sc->sis_manual_pad, 0, "Manually pad short frames"); 2382212157Syongari} 2383212157Syongari 2384139800Sphkstatic device_method_t sis_methods[] = { 2385139800Sphk /* Device interface */ 2386139800Sphk DEVMETHOD(device_probe, sis_probe), 2387139800Sphk DEVMETHOD(device_attach, sis_attach), 2388139800Sphk DEVMETHOD(device_detach, sis_detach), 2389139800Sphk DEVMETHOD(device_shutdown, sis_shutdown), 2390212166Syongari DEVMETHOD(device_suspend, sis_suspend), 2391212166Syongari DEVMETHOD(device_resume, sis_resume), 2392139800Sphk 2393139800Sphk /* MII interface */ 2394139800Sphk DEVMETHOD(miibus_readreg, sis_miibus_readreg), 2395139800Sphk DEVMETHOD(miibus_writereg, sis_miibus_writereg), 2396139800Sphk DEVMETHOD(miibus_statchg, sis_miibus_statchg), 2397139800Sphk 2398227843Smarius DEVMETHOD_END 2399139800Sphk}; 2400139800Sphk 2401139800Sphkstatic driver_t sis_driver = { 2402139800Sphk "sis", 2403139800Sphk sis_methods, 2404139800Sphk sizeof(struct sis_softc) 2405139800Sphk}; 2406139800Sphk 2407139800Sphkstatic devclass_t sis_devclass; 2408139800Sphk 2409139800SphkDRIVER_MODULE(sis, pci, sis_driver, sis_devclass, 0, 0); 2410139800SphkDRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0); 2411