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> 93227277Smarius#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 123227277Smarius#define CSR_BARRIER(sc, reg, length, flags) \ 124227277Smarius bus_barrier(sc->sis_res[0], reg, length, flags) 125227277Smarius 126150369Sphk/* 12750974Swpaul * Various supported device vendors/types and their names. 12850974Swpaul */ 129242908Sdimstatic 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); 152227277Smariusstatic uint32_t sis_mii_bitbang_read(device_t); 153227277Smariusstatic 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 168227277Smarius/* 169227277Smarius * MII bit-bang glue 170227277Smarius */ 171227277Smariusstatic const struct mii_bitbang_ops sis_mii_bitbang_ops = { 172227277Smarius sis_mii_bitbang_read, 173227277Smarius sis_mii_bitbang_write, 174227277Smarius { 175227277Smarius SIS_MII_DATA, /* MII_BIT_MDO */ 176227277Smarius SIS_MII_DATA, /* MII_BIT_MDI */ 177227277Smarius SIS_MII_CLK, /* MII_BIT_MDC */ 178227277Smarius SIS_MII_DIR, /* MII_BIT_DIR_HOST_PHY */ 179227277Smarius 0, /* MII_BIT_DIR_PHY_HOST */ 180227277Smarius } 181227277Smarius}; 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/* 435227277Smarius * Read the MII serial port for the MII bit-bang module. 436109060Smbr */ 437227277Smariusstatic uint32_t 438227277Smariussis_mii_bitbang_read(device_t dev) 439109060Smbr{ 440227277Smarius struct sis_softc *sc; 441227277Smarius uint32_t val; 442212103Syongari 443227277Smarius sc = device_get_softc(dev); 444212103Syongari 445227277Smarius val = CSR_READ_4(sc, SIS_EECTL); 446227277Smarius CSR_BARRIER(sc, SIS_EECTL, 4, 447227277Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 448227277Smarius return (val); 449109060Smbr} 450212103Syongari 451109060Smbr/* 452227277Smarius * Write the MII serial port for the MII bit-bang module. 453109060Smbr */ 454139740Sphkstatic void 455227277Smariussis_mii_bitbang_write(device_t dev, uint32_t val) 456109060Smbr{ 457227277Smarius struct sis_softc *sc; 458212103Syongari 459227277Smarius sc = device_get_softc(dev); 460212103Syongari 461227277Smarius CSR_WRITE_4(sc, SIS_EECTL, val); 462227277Smarius CSR_BARRIER(sc, SIS_EECTL, 4, 463227277Smarius 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) { 513227277Smarius device_printf(sc->sis_dev, 514227277Smarius "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); 524227277Smarius } else 525227277Smarius return (mii_bitbang_readreg(dev, &sis_mii_bitbang_ops, phy, 526227277Smarius 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) 565227277Smarius device_printf(sc->sis_dev, 566227277Smarius "PHY failed to come ready\n"); 567227277Smarius } else 568227277Smarius mii_bitbang_writereg(dev, &sis_mii_bitbang_ops, phy, reg, 569227277Smarius 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 628250646Syongari 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{ 864227277Smarius 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_mtu = ETHERMTU; 105850974Swpaul ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 105950974Swpaul ifp->if_ioctl = sis_ioctl; 106050974Swpaul ifp->if_start = sis_start; 106150974Swpaul ifp->if_init = sis_init; 1062131455Smlaier IFQ_SET_MAXLEN(&ifp->if_snd, SIS_TX_LIST_CNT - 1); 1063131455Smlaier ifp->if_snd.ifq_drv_maxlen = SIS_TX_LIST_CNT - 1; 1064131455Smlaier IFQ_SET_READY(&ifp->if_snd); 106550974Swpaul 1066219902Sjhb if (pci_find_cap(sc->sis_dev, PCIY_PMG, &pmc) == 0) { 1067212167Syongari if (sc->sis_type == SIS_TYPE_83815) 1068212167Syongari ifp->if_capabilities |= IFCAP_WOL; 1069212167Syongari else 1070212167Syongari ifp->if_capabilities |= IFCAP_WOL_MAGIC; 1071212167Syongari ifp->if_capenable = ifp->if_capabilities; 1072212167Syongari } 1073212167Syongari 107450974Swpaul /* 107550974Swpaul * Do MII setup. 107650974Swpaul */ 1077213894Smarius error = mii_attach(dev, &sc->sis_miibus, ifp, sis_ifmedia_upd, 1078213894Smarius sis_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 1079213894Smarius if (error != 0) { 1080213894Smarius device_printf(dev, "attaching PHYs failed\n"); 108150974Swpaul goto fail; 108250974Swpaul } 108350974Swpaul 108450974Swpaul /* 108563090Sarchie * Call MI attach routine. 108650974Swpaul */ 1087106936Ssam ether_ifattach(ifp, eaddr); 1088212103Syongari 108987390Sjhay /* 109087390Sjhay * Tell the upper layer(s) we support long frames. 109187390Sjhay */ 109287390Sjhay ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1093106936Ssam ifp->if_capabilities |= IFCAP_VLAN_MTU; 1094150789Sglebius ifp->if_capenable = ifp->if_capabilities; 1095128138Sru#ifdef DEVICE_POLLING 1096128138Sru ifp->if_capabilities |= IFCAP_POLLING; 1097128138Sru#endif 1098128138Sru 1099113609Snjl /* Hook interrupt last to avoid having to lock softc */ 1100150526Sphk error = bus_setup_intr(dev, sc->sis_res[1], INTR_TYPE_NET | INTR_MPSAFE, 1101166901Spiso NULL, sis_intr, sc, &sc->sis_intrhand); 110250974Swpaul 1103112872Snjl if (error) { 1104150583Sjhb device_printf(dev, "couldn't set up irq\n"); 1105113609Snjl ether_ifdetach(ifp); 1106112872Snjl goto fail; 1107112872Snjl } 1108112872Snjl 110950974Swpaulfail: 1110112872Snjl if (error) 1111112872Snjl sis_detach(dev); 1112112872Snjl 1113212104Syongari return (error); 111450974Swpaul} 111550974Swpaul 1116113609Snjl/* 1117113609Snjl * Shutdown hardware and free up resources. This can be called any 1118113609Snjl * time after the mutex has been initialized. It is called in both 1119113609Snjl * the error case in attach and the normal detach case so it needs 1120113609Snjl * to be careful about only freeing resources that have actually been 1121113609Snjl * allocated. 1122113609Snjl */ 1123102334Salfredstatic int 1124139740Sphksis_detach(device_t dev) 112550974Swpaul{ 112650974Swpaul struct sis_softc *sc; 112750974Swpaul struct ifnet *ifp; 112850974Swpaul 112950974Swpaul sc = device_get_softc(dev); 1130112880Sjhb KASSERT(mtx_initialized(&sc->sis_mtx), ("sis mutex not initialized")); 1131147256Sbrooks ifp = sc->sis_ifp; 113250974Swpaul 1133150789Sglebius#ifdef DEVICE_POLLING 1134150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 1135150789Sglebius ether_poll_deregister(ifp); 1136150789Sglebius#endif 1137150789Sglebius 1138118089Smux /* These should only be active if attach succeeded. */ 1139113812Simp if (device_is_attached(dev)) { 1140150583Sjhb SIS_LOCK(sc); 1141113609Snjl sis_stop(sc); 1142150583Sjhb SIS_UNLOCK(sc); 1143150583Sjhb callout_drain(&sc->sis_stat_ch); 1144112872Snjl ether_ifdetach(ifp); 1145150213Sru } 1146113609Snjl if (sc->sis_miibus) 1147112872Snjl device_delete_child(dev, sc->sis_miibus); 1148113609Snjl bus_generic_detach(dev); 114950974Swpaul 1150112872Snjl if (sc->sis_intrhand) 1151150526Sphk bus_teardown_intr(dev, sc->sis_res[1], sc->sis_intrhand); 1152150526Sphk bus_release_resources(dev, sis_res_spec, sc->sis_res); 115350974Swpaul 1154151297Sru if (ifp) 1155151297Sru if_free(ifp); 1156151297Sru 1157212109Syongari sis_dma_free(sc); 1158212109Syongari 1159212109Syongari mtx_destroy(&sc->sis_mtx); 1160212109Syongari 1161212109Syongari return (0); 1162212109Syongari} 1163212109Syongari 1164212109Syongaristruct sis_dmamap_arg { 1165212109Syongari bus_addr_t sis_busaddr; 1166212109Syongari}; 1167212109Syongari 1168212109Syongaristatic void 1169212109Syongarisis_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1170212109Syongari{ 1171212109Syongari struct sis_dmamap_arg *ctx; 1172212109Syongari 1173212109Syongari if (error != 0) 1174212109Syongari return; 1175212109Syongari 1176212109Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1177212109Syongari 1178212109Syongari ctx = (struct sis_dmamap_arg *)arg; 1179212109Syongari ctx->sis_busaddr = segs[0].ds_addr; 1180212109Syongari} 1181212109Syongari 1182212109Syongaristatic int 1183212109Syongarisis_dma_ring_alloc(struct sis_softc *sc, bus_size_t alignment, 1184212109Syongari bus_size_t maxsize, bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map, 1185212109Syongari bus_addr_t *paddr, const char *msg) 1186212109Syongari{ 1187212109Syongari struct sis_dmamap_arg ctx; 1188212109Syongari int error; 1189212109Syongari 1190212109Syongari error = bus_dma_tag_create(sc->sis_parent_tag, alignment, 0, 1191212109Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, maxsize, 1, 1192212109Syongari maxsize, 0, NULL, NULL, tag); 1193212109Syongari if (error != 0) { 1194212109Syongari device_printf(sc->sis_dev, 1195212109Syongari "could not create %s dma tag\n", msg); 1196212109Syongari return (ENOMEM); 1197112872Snjl } 1198212109Syongari /* Allocate DMA'able memory for ring. */ 1199212109Syongari error = bus_dmamem_alloc(*tag, (void **)ring, 1200212109Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map); 1201212109Syongari if (error != 0) { 1202212109Syongari device_printf(sc->sis_dev, 1203212109Syongari "could not allocate DMA'able memory for %s\n", msg); 1204212109Syongari return (ENOMEM); 1205112872Snjl } 1206212109Syongari /* Load the address of the ring. */ 1207212109Syongari ctx.sis_busaddr = 0; 1208212109Syongari error = bus_dmamap_load(*tag, *map, *ring, maxsize, sis_dmamap_cb, 1209212109Syongari &ctx, BUS_DMA_NOWAIT); 1210212109Syongari if (error != 0) { 1211212109Syongari device_printf(sc->sis_dev, 1212212109Syongari "could not load DMA'able memory for %s\n", msg); 1213212109Syongari return (ENOMEM); 1214212109Syongari } 1215212109Syongari *paddr = ctx.sis_busaddr; 1216212109Syongari return (0); 1217212109Syongari} 121850974Swpaul 1219212109Syongaristatic int 1220212109Syongarisis_dma_alloc(struct sis_softc *sc) 1221212109Syongari{ 1222212109Syongari struct sis_rxdesc *rxd; 1223212109Syongari struct sis_txdesc *txd; 1224212109Syongari int error, i; 122550974Swpaul 1226212109Syongari /* Allocate the parent bus DMA tag appropriate for PCI. */ 1227212109Syongari error = bus_dma_tag_create(bus_get_dma_tag(sc->sis_dev), 1228212109Syongari 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1229212109Syongari NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 1230212109Syongari 0, NULL, NULL, &sc->sis_parent_tag); 1231212109Syongari if (error != 0) { 1232212109Syongari device_printf(sc->sis_dev, 1233212109Syongari "could not allocate parent dma tag\n"); 1234212109Syongari return (ENOMEM); 1235212109Syongari } 1236212109Syongari 1237212109Syongari /* Create RX ring. */ 1238212109Syongari error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_RX_LIST_SZ, 1239212109Syongari &sc->sis_rx_list_tag, (uint8_t **)&sc->sis_rx_list, 1240212109Syongari &sc->sis_rx_list_map, &sc->sis_rx_paddr, "RX ring"); 1241212109Syongari if (error) 1242212109Syongari return (error); 1243212109Syongari 1244212109Syongari /* Create TX ring. */ 1245212109Syongari error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_TX_LIST_SZ, 1246212109Syongari &sc->sis_tx_list_tag, (uint8_t **)&sc->sis_tx_list, 1247212109Syongari &sc->sis_tx_list_map, &sc->sis_tx_paddr, "TX ring"); 1248212109Syongari if (error) 1249212109Syongari return (error); 1250212109Syongari 1251212109Syongari /* Create tag for RX mbufs. */ 1252212109Syongari error = bus_dma_tag_create(sc->sis_parent_tag, SIS_RX_BUF_ALIGN, 0, 1253212109Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, 1254212109Syongari MCLBYTES, 0, NULL, NULL, &sc->sis_rx_tag); 1255212109Syongari if (error) { 1256212109Syongari device_printf(sc->sis_dev, "could not allocate RX dma tag\n"); 1257212109Syongari return (error); 1258212109Syongari } 1259212109Syongari 1260212109Syongari /* Create tag for TX mbufs. */ 1261212109Syongari error = bus_dma_tag_create(sc->sis_parent_tag, 1, 0, 1262212109Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 1263212109Syongari MCLBYTES * SIS_MAXTXSEGS, SIS_MAXTXSEGS, MCLBYTES, 0, NULL, NULL, 1264212109Syongari &sc->sis_tx_tag); 1265212109Syongari if (error) { 1266212109Syongari device_printf(sc->sis_dev, "could not allocate TX dma tag\n"); 1267212109Syongari return (error); 1268212109Syongari } 1269212109Syongari 1270212109Syongari /* Create DMA maps for RX buffers. */ 1271212109Syongari error = bus_dmamap_create(sc->sis_rx_tag, 0, &sc->sis_rx_sparemap); 1272212109Syongari if (error) { 1273212109Syongari device_printf(sc->sis_dev, 1274212109Syongari "can't create spare DMA map for RX\n"); 1275212109Syongari return (error); 1276212109Syongari } 1277212109Syongari for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1278212109Syongari rxd = &sc->sis_rxdesc[i]; 1279212109Syongari rxd->rx_m = NULL; 1280212109Syongari error = bus_dmamap_create(sc->sis_rx_tag, 0, &rxd->rx_dmamap); 1281212109Syongari if (error) { 1282212109Syongari device_printf(sc->sis_dev, 1283212109Syongari "can't create DMA map for RX\n"); 1284212109Syongari return (error); 1285212109Syongari } 1286212109Syongari } 1287212109Syongari 1288212109Syongari /* Create DMA maps for TX buffers. */ 1289212109Syongari for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1290212109Syongari txd = &sc->sis_txdesc[i]; 1291212109Syongari txd->tx_m = NULL; 1292212109Syongari error = bus_dmamap_create(sc->sis_tx_tag, 0, &txd->tx_dmamap); 1293212109Syongari if (error) { 1294212109Syongari device_printf(sc->sis_dev, 1295212109Syongari "can't create DMA map for TX\n"); 1296212109Syongari return (error); 1297212109Syongari } 1298212109Syongari } 1299212109Syongari 1300212104Syongari return (0); 130150974Swpaul} 130250974Swpaul 1303212109Syongaristatic void 1304212109Syongarisis_dma_free(struct sis_softc *sc) 1305212109Syongari{ 1306212109Syongari struct sis_rxdesc *rxd; 1307212109Syongari struct sis_txdesc *txd; 1308212109Syongari int i; 1309212109Syongari 1310212109Syongari /* Destroy DMA maps for RX buffers. */ 1311212109Syongari for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1312212109Syongari rxd = &sc->sis_rxdesc[i]; 1313212109Syongari if (rxd->rx_dmamap) 1314212109Syongari bus_dmamap_destroy(sc->sis_rx_tag, rxd->rx_dmamap); 1315212109Syongari } 1316212109Syongari if (sc->sis_rx_sparemap) 1317212109Syongari bus_dmamap_destroy(sc->sis_rx_tag, sc->sis_rx_sparemap); 1318212109Syongari 1319212109Syongari /* Destroy DMA maps for TX buffers. */ 1320212109Syongari for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1321212109Syongari txd = &sc->sis_txdesc[i]; 1322212109Syongari if (txd->tx_dmamap) 1323212109Syongari bus_dmamap_destroy(sc->sis_tx_tag, txd->tx_dmamap); 1324212109Syongari } 1325212109Syongari 1326212109Syongari if (sc->sis_rx_tag) 1327212109Syongari bus_dma_tag_destroy(sc->sis_rx_tag); 1328212109Syongari if (sc->sis_tx_tag) 1329212109Syongari bus_dma_tag_destroy(sc->sis_tx_tag); 1330212109Syongari 1331212109Syongari /* Destroy RX ring. */ 1332212109Syongari if (sc->sis_rx_list_map) 1333212109Syongari bus_dmamap_unload(sc->sis_rx_list_tag, sc->sis_rx_list_map); 1334212109Syongari if (sc->sis_rx_list_map && sc->sis_rx_list) 1335212109Syongari bus_dmamem_free(sc->sis_rx_list_tag, sc->sis_rx_list, 1336212109Syongari sc->sis_rx_list_map); 1337212109Syongari 1338212109Syongari if (sc->sis_rx_list_tag) 1339212109Syongari bus_dma_tag_destroy(sc->sis_rx_list_tag); 1340212109Syongari 1341212109Syongari /* Destroy TX ring. */ 1342212109Syongari if (sc->sis_tx_list_map) 1343212109Syongari bus_dmamap_unload(sc->sis_tx_list_tag, sc->sis_tx_list_map); 1344212109Syongari 1345212109Syongari if (sc->sis_tx_list_map && sc->sis_tx_list) 1346212109Syongari bus_dmamem_free(sc->sis_tx_list_tag, sc->sis_tx_list, 1347212109Syongari sc->sis_tx_list_map); 1348212109Syongari 1349212109Syongari if (sc->sis_tx_list_tag) 1350212109Syongari bus_dma_tag_destroy(sc->sis_tx_list_tag); 1351212109Syongari 1352212109Syongari /* Destroy the parent tag. */ 1353212109Syongari if (sc->sis_parent_tag) 1354212109Syongari bus_dma_tag_destroy(sc->sis_parent_tag); 1355212109Syongari} 1356212109Syongari 135750974Swpaul/* 1358139802Sphk * Initialize the TX and RX descriptors and allocate mbufs for them. Note that 1359139802Sphk * we arrange the descriptors in a closed ring, so that the last descriptor 1360139802Sphk * points back to the first. 136150974Swpaul */ 1362102334Salfredstatic int 1363139802Sphksis_ring_init(struct sis_softc *sc) 136450974Swpaul{ 1365212109Syongari struct sis_rxdesc *rxd; 1366212109Syongari struct sis_txdesc *txd; 1367212109Syongari bus_addr_t next; 1368212109Syongari int error, i; 136950974Swpaul 1370212109Syongari bzero(&sc->sis_tx_list[0], SIS_TX_LIST_SZ); 1371212109Syongari for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1372212109Syongari txd = &sc->sis_txdesc[i]; 1373212109Syongari txd->tx_m = NULL; 1374212109Syongari if (i == SIS_TX_LIST_CNT - 1) 1375212109Syongari next = SIS_TX_RING_ADDR(sc, 0); 1376139802Sphk else 1377212109Syongari next = SIS_TX_RING_ADDR(sc, i + 1); 1378212109Syongari sc->sis_tx_list[i].sis_next = htole32(SIS_ADDR_LO(next)); 137950974Swpaul } 1380139690Sphk sc->sis_tx_prod = sc->sis_tx_cons = sc->sis_tx_cnt = 0; 1381212109Syongari bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1382212109Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 138350974Swpaul 1384212109Syongari sc->sis_rx_cons = 0; 1385212109Syongari bzero(&sc->sis_rx_list[0], SIS_RX_LIST_SZ); 1386212109Syongari for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1387212109Syongari rxd = &sc->sis_rxdesc[i]; 1388212109Syongari rxd->rx_desc = &sc->sis_rx_list[i]; 1389212109Syongari if (i == SIS_RX_LIST_CNT - 1) 1390212109Syongari next = SIS_RX_RING_ADDR(sc, 0); 1391212109Syongari else 1392212109Syongari next = SIS_RX_RING_ADDR(sc, i + 1); 1393212109Syongari rxd->rx_desc->sis_next = htole32(SIS_ADDR_LO(next)); 1394212109Syongari error = sis_newbuf(sc, rxd); 1395139802Sphk if (error) 1396212104Syongari return (error); 1397212109Syongari } 1398212109Syongari bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1399212109Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 140050974Swpaul 1401212104Syongari return (0); 140250974Swpaul} 140350974Swpaul 140450974Swpaul/* 140550974Swpaul * Initialize an RX descriptor and attach an MBUF cluster. 140650974Swpaul */ 1407102334Salfredstatic int 1408212109Syongarisis_newbuf(struct sis_softc *sc, struct sis_rxdesc *rxd) 140950974Swpaul{ 1410212109Syongari struct mbuf *m; 1411212109Syongari bus_dma_segment_t segs[1]; 1412212109Syongari bus_dmamap_t map; 1413212109Syongari int nsegs; 141450974Swpaul 1415248078Smarius m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1416212109Syongari if (m == NULL) 1417212109Syongari return (ENOBUFS); 1418212109Syongari m->m_len = m->m_pkthdr.len = SIS_RXLEN; 1419212109Syongari#ifndef __NO_STRICT_ALIGNMENT 1420212109Syongari m_adj(m, SIS_RX_BUF_ALIGN); 1421212109Syongari#endif 142281713Swpaul 1423212109Syongari if (bus_dmamap_load_mbuf_sg(sc->sis_rx_tag, sc->sis_rx_sparemap, m, 1424212109Syongari segs, &nsegs, 0) != 0) { 1425212109Syongari m_freem(m); 1426212109Syongari return (ENOBUFS); 1427212109Syongari } 1428212109Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 142950974Swpaul 1430212109Syongari if (rxd->rx_m != NULL) { 1431212109Syongari bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, 1432212109Syongari BUS_DMASYNC_POSTREAD); 1433212109Syongari bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap); 1434212109Syongari } 1435212109Syongari map = rxd->rx_dmamap; 1436212109Syongari rxd->rx_dmamap = sc->sis_rx_sparemap; 1437212109Syongari sc->sis_rx_sparemap = map; 1438212109Syongari bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_PREREAD); 1439212109Syongari rxd->rx_m = m; 1440219102Syongari rxd->rx_desc->sis_ptr = htole32(SIS_ADDR_LO(segs[0].ds_addr)); 1441212109Syongari rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN); 1442212109Syongari return (0); 1443212109Syongari} 144450974Swpaul 1445212109Syongaristatic __inline void 1446212109Syongarisis_discard_rxbuf(struct sis_rxdesc *rxd) 1447212109Syongari{ 144881713Swpaul 1449212109Syongari rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN); 145050974Swpaul} 145150974Swpaul 1452212109Syongari#ifndef __NO_STRICT_ALIGNMENT 1453212109Syongaristatic __inline void 1454212109Syongarisis_fixup_rx(struct mbuf *m) 1455212109Syongari{ 1456212109Syongari uint16_t *src, *dst; 1457212109Syongari int i; 1458212109Syongari 1459212109Syongari src = mtod(m, uint16_t *); 1460212109Syongari dst = src - (SIS_RX_BUF_ALIGN - ETHER_ALIGN) / sizeof(*src); 1461212109Syongari 1462212109Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1463212109Syongari *dst++ = *src++; 1464212109Syongari 1465212109Syongari m->m_data -= SIS_RX_BUF_ALIGN - ETHER_ALIGN; 1466212109Syongari} 1467212109Syongari#endif 1468212109Syongari 146950974Swpaul/* 147050974Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to 147150974Swpaul * the higher level protocols. 147250974Swpaul */ 1473193096Sattiliostatic int 1474139740Sphksis_rxeof(struct sis_softc *sc) 147550974Swpaul{ 1476212109Syongari struct mbuf *m; 1477163773Smarius struct ifnet *ifp; 1478212109Syongari struct sis_rxdesc *rxd; 147950974Swpaul struct sis_desc *cur_rx; 1480212109Syongari int prog, rx_cons, rx_npkts = 0, total_len; 1481212109Syongari uint32_t rxstat; 148250974Swpaul 1483122689Ssam SIS_LOCK_ASSERT(sc); 1484122689Ssam 1485212109Syongari bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1486212109Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1487212109Syongari 1488212109Syongari rx_cons = sc->sis_rx_cons; 1489147256Sbrooks ifp = sc->sis_ifp; 149050974Swpaul 1491212109Syongari for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; 1492212109Syongari SIS_INC(rx_cons, SIS_RX_LIST_CNT), prog++) { 149387902Sluigi#ifdef DEVICE_POLLING 1494150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 149587902Sluigi if (sc->rxcycles <= 0) 149687902Sluigi break; 149787902Sluigi sc->rxcycles--; 149887902Sluigi } 1499150789Sglebius#endif 1500212109Syongari cur_rx = &sc->sis_rx_list[rx_cons]; 1501212109Syongari rxstat = le32toh(cur_rx->sis_cmdsts); 1502212109Syongari if ((rxstat & SIS_CMDSTS_OWN) == 0) 1503212109Syongari break; 1504212109Syongari rxd = &sc->sis_rxdesc[rx_cons]; 150550974Swpaul 1506212109Syongari total_len = (rxstat & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN; 1507185784Syongari if ((ifp->if_capenable & IFCAP_VLAN_MTU) != 0 && 1508185784Syongari total_len <= (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN - 1509185784Syongari ETHER_CRC_LEN)) 1510185784Syongari rxstat &= ~SIS_RXSTAT_GIANT; 1511185784Syongari if (SIS_RXSTAT_ERROR(rxstat) != 0) { 151250974Swpaul ifp->if_ierrors++; 151350974Swpaul if (rxstat & SIS_RXSTAT_COLL) 151450974Swpaul ifp->if_collisions++; 1515212109Syongari sis_discard_rxbuf(rxd); 151650974Swpaul continue; 151750974Swpaul } 151850974Swpaul 1519212109Syongari /* Add a new receive buffer to the ring. */ 1520212109Syongari m = rxd->rx_m; 1521212109Syongari if (sis_newbuf(sc, rxd) != 0) { 1522212109Syongari ifp->if_iqdrops++; 1523212109Syongari sis_discard_rxbuf(rxd); 1524212109Syongari continue; 1525212109Syongari } 1526212109Syongari 1527212103Syongari /* No errors; receive the packet. */ 1528212109Syongari m->m_pkthdr.len = m->m_len = total_len; 1529212109Syongari#ifndef __NO_STRICT_ALIGNMENT 153087059Sluigi /* 1531163773Smarius * On architectures without alignment problems we try to 153287059Sluigi * allocate a new buffer for the receive ring, and pass up 153387059Sluigi * the one where the packet is already, saving the expensive 1534212109Syongari * copy operation. 153587059Sluigi */ 1536212109Syongari sis_fixup_rx(m); 153787059Sluigi#endif 153850974Swpaul ifp->if_ipackets++; 1539106936Ssam m->m_pkthdr.rcvif = ifp; 1540106936Ssam 1541122689Ssam SIS_UNLOCK(sc); 1542106936Ssam (*ifp->if_input)(ifp, m); 1543122689Ssam SIS_LOCK(sc); 1544193096Sattilio rx_npkts++; 154550974Swpaul } 154650974Swpaul 1547212109Syongari if (prog > 0) { 1548212109Syongari sc->sis_rx_cons = rx_cons; 1549212109Syongari bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1550212109Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1551212109Syongari } 1552212109Syongari 1553193096Sattilio return (rx_npkts); 155450974Swpaul} 155550974Swpaul 155650974Swpaul/* 155750974Swpaul * A frame was downloaded to the chip. It's safe for us to clean up 155850974Swpaul * the list buffers. 155950974Swpaul */ 156050974Swpaul 1561102334Salfredstatic void 1562139740Sphksis_txeof(struct sis_softc *sc) 156350974Swpaul{ 156450974Swpaul struct ifnet *ifp; 1565212109Syongari struct sis_desc *cur_tx; 1566212109Syongari struct sis_txdesc *txd; 1567212109Syongari uint32_t cons, txstat; 156850974Swpaul 1569139715Sphk SIS_LOCK_ASSERT(sc); 1570212109Syongari 1571212109Syongari cons = sc->sis_tx_cons; 1572212109Syongari if (cons == sc->sis_tx_prod) 1573212109Syongari return; 1574212109Syongari 1575147256Sbrooks ifp = sc->sis_ifp; 1576212109Syongari bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1577212109Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 157850974Swpaul 157950974Swpaul /* 158050974Swpaul * Go through our tx list and free mbufs for those 158150974Swpaul * frames that have been transmitted. 158250974Swpaul */ 1583212109Syongari for (; cons != sc->sis_tx_prod; SIS_INC(cons, SIS_TX_LIST_CNT)) { 1584212109Syongari cur_tx = &sc->sis_tx_list[cons]; 1585212109Syongari txstat = le32toh(cur_tx->sis_cmdsts); 1586212109Syongari if ((txstat & SIS_CMDSTS_OWN) != 0) 158750974Swpaul break; 1588212109Syongari txd = &sc->sis_txdesc[cons]; 1589212109Syongari if (txd->tx_m != NULL) { 1590212109Syongari bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, 1591212109Syongari BUS_DMASYNC_POSTWRITE); 1592212109Syongari bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 1593212109Syongari m_freem(txd->tx_m); 1594212109Syongari txd->tx_m = NULL; 1595212109Syongari if ((txstat & SIS_CMDSTS_PKT_OK) != 0) { 1596212109Syongari ifp->if_opackets++; 1597212109Syongari ifp->if_collisions += 1598212109Syongari (txstat & SIS_TXSTAT_COLLCNT) >> 16; 1599212109Syongari } else { 1600212109Syongari ifp->if_oerrors++; 1601212109Syongari if (txstat & SIS_TXSTAT_EXCESSCOLLS) 1602212109Syongari ifp->if_collisions++; 1603212109Syongari if (txstat & SIS_TXSTAT_OUTOFWINCOLL) 1604212109Syongari ifp->if_collisions++; 1605212109Syongari } 160650974Swpaul } 1607212109Syongari sc->sis_tx_cnt--; 1608148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 160950974Swpaul } 1610212109Syongari sc->sis_tx_cons = cons; 1611212109Syongari if (sc->sis_tx_cnt == 0) 1612212109Syongari sc->sis_watchdog_timer = 0; 161350974Swpaul} 161450974Swpaul 1615102334Salfredstatic void 1616139740Sphksis_tick(void *xsc) 161750974Swpaul{ 161850974Swpaul struct sis_softc *sc; 161950974Swpaul struct mii_data *mii; 162050974Swpaul 162150974Swpaul sc = xsc; 1622150583Sjhb SIS_LOCK_ASSERT(sc); 162364963Swpaul 162450974Swpaul mii = device_get_softc(sc->sis_miibus); 162550974Swpaul mii_tick(mii); 1626166940Sdelphij sis_watchdog(sc); 1627212157Syongari if ((sc->sis_flags & SIS_FLAG_LINK) == 0) 1628212116Syongari sis_miibus_statchg(sc->sis_dev); 1629119785Ssam callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); 163050974Swpaul} 163150974Swpaul 163287902Sluigi#ifdef DEVICE_POLLING 163387902Sluigistatic poll_handler_t sis_poll; 163487902Sluigi 1635193096Sattiliostatic int 163687902Sluigisis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 163787902Sluigi{ 163887973Speter struct sis_softc *sc = ifp->if_softc; 1639193096Sattilio int rx_npkts = 0; 164087973Speter 164187902Sluigi SIS_LOCK(sc); 1642150789Sglebius if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1643150789Sglebius SIS_UNLOCK(sc); 1644193096Sattilio return (rx_npkts); 1645128138Sru } 164687902Sluigi 164787902Sluigi /* 164887902Sluigi * On the sis, reading the status register also clears it. 164987902Sluigi * So before returning to intr mode we must make sure that all 165087902Sluigi * possible pending sources of interrupts have been served. 165187902Sluigi * In practice this means run to completion the *eof routines, 165287902Sluigi * and then call the interrupt routine 165387902Sluigi */ 165487902Sluigi sc->rxcycles = count; 1655193096Sattilio rx_npkts = sis_rxeof(sc); 165687902Sluigi sis_txeof(sc); 1657131455Smlaier if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1658139714Sphk sis_startl(ifp); 165987902Sluigi 166087902Sluigi if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1661212113Syongari uint32_t status; 166287902Sluigi 166387902Sluigi /* Reading the ISR register clears all interrupts. */ 166487902Sluigi status = CSR_READ_4(sc, SIS_ISR); 166587902Sluigi 166687902Sluigi if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW)) 1667206909Sbrucec ifp->if_ierrors++; 166887902Sluigi 166987902Sluigi if (status & (SIS_ISR_RX_IDLE)) 167087902Sluigi SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 167187902Sluigi 167287902Sluigi if (status & SIS_ISR_SYSERR) { 1673212120Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1674139715Sphk sis_initl(sc); 167587902Sluigi } 167687902Sluigi } 1677150789Sglebius 167887902Sluigi SIS_UNLOCK(sc); 1679193096Sattilio return (rx_npkts); 168087902Sluigi} 168187902Sluigi#endif /* DEVICE_POLLING */ 168287902Sluigi 1683102334Salfredstatic void 1684139740Sphksis_intr(void *arg) 168550974Swpaul{ 168650974Swpaul struct sis_softc *sc; 168750974Swpaul struct ifnet *ifp; 1688212113Syongari uint32_t status; 168950974Swpaul 169050974Swpaul sc = arg; 1691147256Sbrooks ifp = sc->sis_ifp; 169250974Swpaul 169386984Sluigi SIS_LOCK(sc); 169487902Sluigi#ifdef DEVICE_POLLING 1695150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) { 1696150789Sglebius SIS_UNLOCK(sc); 1697150789Sglebius return; 169887902Sluigi } 1699150789Sglebius#endif 170087902Sluigi 1701212116Syongari /* Reading the ISR register clears all interrupts. */ 1702212116Syongari status = CSR_READ_4(sc, SIS_ISR); 1703212116Syongari if ((status & SIS_INTRS) == 0) { 1704212116Syongari /* Not ours. */ 1705212116Syongari SIS_UNLOCK(sc); 1706214089Syongari return; 1707212116Syongari } 1708212116Syongari 170950974Swpaul /* Disable interrupts. */ 171050974Swpaul CSR_WRITE_4(sc, SIS_IER, 0); 171150974Swpaul 1712212116Syongari for (;(status & SIS_INTRS) != 0;) { 1713214089Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1714214089Syongari break; 171586984Sluigi if (status & 171686984Sluigi (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR | 1717212103Syongari SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) ) 171850974Swpaul sis_txeof(sc); 171950974Swpaul 1720188550Syongari if (status & (SIS_ISR_RX_DESC_OK | SIS_ISR_RX_OK | 1721188550Syongari SIS_ISR_RX_ERR | SIS_ISR_RX_IDLE)) 172250974Swpaul sis_rxeof(sc); 172350974Swpaul 1724188550Syongari if (status & SIS_ISR_RX_OFLOW) 1725206909Sbrucec ifp->if_ierrors++; 172650974Swpaul 172786984Sluigi if (status & (SIS_ISR_RX_IDLE)) 172886984Sluigi SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 172986984Sluigi 173050974Swpaul if (status & SIS_ISR_SYSERR) { 1731212120Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1732139715Sphk sis_initl(sc); 1733212116Syongari SIS_UNLOCK(sc); 1734212116Syongari return; 173550974Swpaul } 1736212116Syongari status = CSR_READ_4(sc, SIS_ISR); 173750974Swpaul } 173850974Swpaul 1739214089Syongari if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1740214089Syongari /* Re-enable interrupts. */ 1741214089Syongari CSR_WRITE_4(sc, SIS_IER, 1); 174250974Swpaul 1743214089Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1744214089Syongari sis_startl(ifp); 1745214089Syongari } 1746139809Sphk 174767087Swpaul SIS_UNLOCK(sc); 174850974Swpaul} 174950974Swpaul 175050974Swpaul/* 175150974Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 175250974Swpaul * pointers to the fragment pointers. 175350974Swpaul */ 1754102334Salfredstatic int 1755212109Syongarisis_encap(struct sis_softc *sc, struct mbuf **m_head) 175650974Swpaul{ 175750974Swpaul struct mbuf *m; 1758212109Syongari struct sis_txdesc *txd; 1759212109Syongari struct sis_desc *f; 1760212109Syongari bus_dma_segment_t segs[SIS_MAXTXSEGS]; 1761212109Syongari bus_dmamap_t map; 1762212109Syongari int error, i, frag, nsegs, prod; 1763212157Syongari int padlen; 176450974Swpaul 1765212109Syongari prod = sc->sis_tx_prod; 1766212109Syongari txd = &sc->sis_txdesc[prod]; 1767212157Syongari if ((sc->sis_flags & SIS_FLAG_MANUAL_PAD) != 0 && 1768212157Syongari (*m_head)->m_pkthdr.len < SIS_MIN_FRAMELEN) { 1769212157Syongari m = *m_head; 1770212157Syongari padlen = SIS_MIN_FRAMELEN - m->m_pkthdr.len; 1771212157Syongari if (M_WRITABLE(m) == 0) { 1772212157Syongari /* Get a writable copy. */ 1773248078Smarius m = m_dup(*m_head, M_NOWAIT); 1774212157Syongari m_freem(*m_head); 1775212157Syongari if (m == NULL) { 1776212157Syongari *m_head = NULL; 1777212157Syongari return (ENOBUFS); 1778212157Syongari } 1779212157Syongari *m_head = m; 1780212157Syongari } 1781212157Syongari if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) { 1782248078Smarius m = m_defrag(m, M_NOWAIT); 1783212157Syongari if (m == NULL) { 1784212157Syongari m_freem(*m_head); 1785212157Syongari *m_head = NULL; 1786212157Syongari return (ENOBUFS); 1787212157Syongari } 1788212157Syongari } 1789212157Syongari /* 1790212157Syongari * Manually pad short frames, and zero the pad space 1791212157Syongari * to avoid leaking data. 1792212157Syongari */ 1793212157Syongari bzero(mtod(m, char *) + m->m_pkthdr.len, padlen); 1794212157Syongari m->m_pkthdr.len += padlen; 1795212157Syongari m->m_len = m->m_pkthdr.len; 1796212157Syongari *m_head = m; 1797212157Syongari } 1798212109Syongari error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap, 1799212109Syongari *m_head, segs, &nsegs, 0); 1800212109Syongari if (error == EFBIG) { 1801248078Smarius m = m_collapse(*m_head, M_NOWAIT, SIS_MAXTXSEGS); 1802212109Syongari if (m == NULL) { 1803212109Syongari m_freem(*m_head); 1804212109Syongari *m_head = NULL; 1805112808Ssilby return (ENOBUFS); 1806212109Syongari } 1807121262Ssilby *m_head = m; 1808212109Syongari error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap, 1809212109Syongari *m_head, segs, &nsegs, 0); 1810212109Syongari if (error != 0) { 1811212109Syongari m_freem(*m_head); 1812212109Syongari *m_head = NULL; 1813212109Syongari return (error); 1814212109Syongari } 1815212109Syongari } else if (error != 0) 1816212109Syongari return (error); 1817212109Syongari 1818212109Syongari /* Check for descriptor overruns. */ 1819212109Syongari if (sc->sis_tx_cnt + nsegs > SIS_TX_LIST_CNT - 1) { 1820212109Syongari bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 1821212109Syongari return (ENOBUFS); 1822112808Ssilby } 1823212103Syongari 1824212109Syongari bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, BUS_DMASYNC_PREWRITE); 182550974Swpaul 1826212109Syongari frag = prod; 1827212109Syongari for (i = 0; i < nsegs; i++) { 1828212109Syongari f = &sc->sis_tx_list[prod]; 1829212109Syongari if (i == 0) 1830212109Syongari f->sis_cmdsts = htole32(segs[i].ds_len | 1831212109Syongari SIS_CMDSTS_MORE); 1832212109Syongari else 1833212109Syongari f->sis_cmdsts = htole32(segs[i].ds_len | 1834212109Syongari SIS_CMDSTS_OWN | SIS_CMDSTS_MORE); 1835212109Syongari f->sis_ptr = htole32(SIS_ADDR_LO(segs[i].ds_addr)); 1836212109Syongari SIS_INC(prod, SIS_TX_LIST_CNT); 1837212109Syongari sc->sis_tx_cnt++; 183850974Swpaul } 183950974Swpaul 1840212109Syongari /* Update producer index. */ 1841212109Syongari sc->sis_tx_prod = prod; 184250974Swpaul 1843212109Syongari /* Remove MORE flag on the last descriptor. */ 1844212109Syongari prod = (prod - 1) & (SIS_TX_LIST_CNT - 1); 1845212109Syongari f = &sc->sis_tx_list[prod]; 1846212109Syongari f->sis_cmdsts &= ~htole32(SIS_CMDSTS_MORE); 184750974Swpaul 1848212109Syongari /* Lastly transfer ownership of packet to the controller. */ 1849212109Syongari f = &sc->sis_tx_list[frag]; 1850212109Syongari f->sis_cmdsts |= htole32(SIS_CMDSTS_OWN); 1851212109Syongari 1852212109Syongari /* Swap the last and the first dmamaps. */ 1853212109Syongari map = txd->tx_dmamap; 1854212124Syongari txd->tx_dmamap = sc->sis_txdesc[prod].tx_dmamap; 1855212124Syongari sc->sis_txdesc[prod].tx_dmamap = map; 1856212185Syongari sc->sis_txdesc[prod].tx_m = *m_head; 1857212109Syongari 1858212104Syongari return (0); 185950974Swpaul} 186050974Swpaul 1861102334Salfredstatic void 1862139717Sphksis_start(struct ifnet *ifp) 186350974Swpaul{ 186450974Swpaul struct sis_softc *sc; 1865139714Sphk 1866139714Sphk sc = ifp->if_softc; 1867139714Sphk SIS_LOCK(sc); 1868139714Sphk sis_startl(ifp); 1869139714Sphk SIS_UNLOCK(sc); 1870139714Sphk} 1871139714Sphk 1872139714Sphkstatic void 1873139714Sphksis_startl(struct ifnet *ifp) 1874139714Sphk{ 1875139714Sphk struct sis_softc *sc; 1876212109Syongari struct mbuf *m_head; 1877212109Syongari int queued; 187850974Swpaul 187950974Swpaul sc = ifp->if_softc; 188050974Swpaul 1881139714Sphk SIS_LOCK_ASSERT(sc); 1882139714Sphk 1883212109Syongari if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1884212157Syongari IFF_DRV_RUNNING || (sc->sis_flags & SIS_FLAG_LINK) == 0) 188564963Swpaul return; 188664963Swpaul 1887212109Syongari for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && 1888212109Syongari sc->sis_tx_cnt < SIS_TX_LIST_CNT - 4;) { 1889131455Smlaier IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 189050974Swpaul if (m_head == NULL) 189150974Swpaul break; 189250974Swpaul 1893212109Syongari if (sis_encap(sc, &m_head) != 0) { 1894212109Syongari if (m_head == NULL) 1895212109Syongari break; 1896131455Smlaier IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1897148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 189850974Swpaul break; 189950974Swpaul } 190050974Swpaul 1901136269Smlaier queued++; 1902136269Smlaier 190350974Swpaul /* 190450974Swpaul * If there's a BPF listener, bounce a copy of this frame 190550974Swpaul * to him. 190650974Swpaul */ 1907106936Ssam BPF_MTAP(ifp, m_head); 190850974Swpaul } 190950974Swpaul 1910136269Smlaier if (queued) { 1911136269Smlaier /* Transmit */ 1912212109Syongari bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1913212109Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1914136269Smlaier SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE); 191550974Swpaul 1916136269Smlaier /* 1917136269Smlaier * Set a timeout in case the chip goes out to lunch. 1918136269Smlaier */ 1919166940Sdelphij sc->sis_watchdog_timer = 5; 1920136269Smlaier } 192150974Swpaul} 192250974Swpaul 1923102334Salfredstatic void 1924139715Sphksis_init(void *xsc) 192550974Swpaul{ 192650974Swpaul struct sis_softc *sc = xsc; 1927139715Sphk 1928139715Sphk SIS_LOCK(sc); 1929139717Sphk sis_initl(sc); 1930139715Sphk SIS_UNLOCK(sc); 1931139715Sphk} 1932139715Sphk 1933139715Sphkstatic void 1934139717Sphksis_initl(struct sis_softc *sc) 1935139715Sphk{ 1936147256Sbrooks struct ifnet *ifp = sc->sis_ifp; 193750974Swpaul struct mii_data *mii; 1938212156Syongari uint8_t *eaddr; 193950974Swpaul 1940139715Sphk SIS_LOCK_ASSERT(sc); 194150974Swpaul 1942212120Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1943212120Syongari return; 1944212120Syongari 194550974Swpaul /* 194650974Swpaul * Cancel pending I/O and free all RX/TX buffers. 194750974Swpaul */ 194850974Swpaul sis_stop(sc); 1949212121Syongari /* 1950212121Syongari * Reset the chip to a known state. 1951212121Syongari */ 1952212121Syongari sis_reset(sc); 1953119712Sphk#ifdef notyet 1954119712Sphk if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr >= NS_SRR_16A) { 1955119712Sphk /* 1956119712Sphk * Configure 400usec of interrupt holdoff. This is based 1957119712Sphk * on emperical tests on a Soekris 4801. 1958119712Sphk */ 1959119712Sphk CSR_WRITE_4(sc, NS_IHR, 0x100 | 4); 1960119712Sphk } 1961119712Sphk#endif 1962119712Sphk 196350974Swpaul mii = device_get_softc(sc->sis_miibus); 196450974Swpaul 196550974Swpaul /* Set MAC address */ 1966212156Syongari eaddr = IF_LLADDR(sc->sis_ifp); 196762672Swpaul if (sc->sis_type == SIS_TYPE_83815) { 196862672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); 1969212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[0] | eaddr[1] << 8); 197062672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); 1971212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[2] | eaddr[3] << 8); 197262672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); 1973212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[4] | eaddr[5] << 8); 197462672Swpaul } else { 197562672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 1976212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[0] | eaddr[1] << 8); 197762672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1); 1978212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[2] | eaddr[3] << 8); 197962672Swpaul CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 1980212156Syongari CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[4] | eaddr[5] << 8); 198162672Swpaul } 198250974Swpaul 1983139802Sphk /* Init circular TX/RX lists. */ 1984139802Sphk if (sis_ring_init(sc) != 0) { 1985162315Sglebius device_printf(sc->sis_dev, 1986150583Sjhb "initialization failed: no memory for rx buffers\n"); 198750974Swpaul sis_stop(sc); 198850974Swpaul return; 198950974Swpaul } 199050974Swpaul 1991250646Syongari if (sc->sis_type == SIS_TYPE_83815) { 1992212157Syongari if (sc->sis_manual_pad != 0) 1993212157Syongari sc->sis_flags |= SIS_FLAG_MANUAL_PAD; 1994212157Syongari else 1995212157Syongari sc->sis_flags &= ~SIS_FLAG_MANUAL_PAD; 1996212157Syongari } 1997212157Syongari 199850974Swpaul /* 1999139806Sphk * Short Cable Receive Errors (MP21.E) 2000139806Sphk * also: Page 78 of the DP83815 data sheet (september 2002 version) 2001123491Sphk * recommends the following register settings "for optimum 2002181002Sjhb * performance." for rev 15C. Set this also for 15D parts as 2003181002Sjhb * they require it in practice. 2004123491Sphk */ 2005139806Sphk if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr <= NS_SRR_15D) { 2006123491Sphk CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); 2007123491Sphk CSR_WRITE_4(sc, NS_PHY_CR, 0x189C); 2008181002Sjhb /* set val for c2 */ 2009181002Sjhb CSR_WRITE_4(sc, NS_PHY_TDATA, 0x0000); 2010181002Sjhb /* load/kill c2 */ 2011181002Sjhb CSR_WRITE_4(sc, NS_PHY_DSPCFG, 0x5040); 2012181002Sjhb /* rais SD off, from 4 to c */ 2013181002Sjhb CSR_WRITE_4(sc, NS_PHY_SDCFG, 0x008C); 2014123491Sphk CSR_WRITE_4(sc, NS_PHY_PAGE, 0); 2015123491Sphk } 2016123491Sphk 2017217548Syongari sis_rxfilter(sc); 201850974Swpaul /* Turn the receive filter on */ 201950974Swpaul SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE); 202050974Swpaul 202150974Swpaul /* 202250974Swpaul * Load the address of the RX and TX lists. 202350974Swpaul */ 2024212109Syongari CSR_WRITE_4(sc, SIS_RX_LISTPTR, SIS_ADDR_LO(sc->sis_rx_paddr)); 2025212109Syongari CSR_WRITE_4(sc, SIS_TX_LISTPTR, SIS_ADDR_LO(sc->sis_tx_paddr)); 202650974Swpaul 2027109059Smbr /* SIS_CFG_EDB_MASTER_EN indicates the EDB bus is used instead of 2028109059Smbr * the PCI bus. When this bit is set, the Max DMA Burst Size 2029109059Smbr * for TX/RX DMA should be no larger than 16 double words. 2030109059Smbr */ 2031109059Smbr if (CSR_READ_4(sc, SIS_CFG) & SIS_CFG_EDB_MASTER_EN) { 2032109059Smbr CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG64); 2033109059Smbr } else { 2034109059Smbr CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG256); 2035109059Smbr } 203664963Swpaul 203787390Sjhay /* Accept Long Packets for VLAN support */ 203887390Sjhay SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER); 203987390Sjhay 2040212116Syongari /* 2041212116Syongari * Assume 100Mbps link, actual MAC configuration is done 2042212116Syongari * after getting a valid link. 2043212116Syongari */ 2044212116Syongari CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); 204550974Swpaul 204650974Swpaul /* 204750974Swpaul * Enable interrupts. 204850974Swpaul */ 204950974Swpaul CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS); 205087902Sluigi#ifdef DEVICE_POLLING 205187902Sluigi /* 205287902Sluigi * ... only enable interrupts if we are not polling, make sure 205387902Sluigi * they are off otherwise. 205487902Sluigi */ 2055150789Sglebius if (ifp->if_capenable & IFCAP_POLLING) 205687902Sluigi CSR_WRITE_4(sc, SIS_IER, 0); 205787902Sluigi else 2058150789Sglebius#endif 205950974Swpaul CSR_WRITE_4(sc, SIS_IER, 1); 206050974Swpaul 2061212116Syongari /* Clear MAC disable. */ 2062212116Syongari SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE); 206350974Swpaul 2064212157Syongari sc->sis_flags &= ~SIS_FLAG_LINK; 206550974Swpaul mii_mediachg(mii); 206650974Swpaul 2067148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 2068148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 206950974Swpaul 2070212116Syongari callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); 207150974Swpaul} 207250974Swpaul 207350974Swpaul/* 207450974Swpaul * Set media options. 207550974Swpaul */ 2076102334Salfredstatic int 2077139740Sphksis_ifmedia_upd(struct ifnet *ifp) 207850974Swpaul{ 207950974Swpaul struct sis_softc *sc; 208064963Swpaul struct mii_data *mii; 2081221407Smarius struct mii_softc *miisc; 2082212117Syongari int error; 208350974Swpaul 208450974Swpaul sc = ifp->if_softc; 208550974Swpaul 2086150583Sjhb SIS_LOCK(sc); 208764963Swpaul mii = device_get_softc(sc->sis_miibus); 2088221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 2089221407Smarius PHY_RESET(miisc); 2090212117Syongari error = mii_mediachg(mii); 2091150583Sjhb SIS_UNLOCK(sc); 209250974Swpaul 2093212117Syongari return (error); 209450974Swpaul} 209550974Swpaul 209650974Swpaul/* 209750974Swpaul * Report current media status. 209850974Swpaul */ 2099102334Salfredstatic void 2100139740Sphksis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 210150974Swpaul{ 210250974Swpaul struct sis_softc *sc; 210350974Swpaul struct mii_data *mii; 210450974Swpaul 210550974Swpaul sc = ifp->if_softc; 210650974Swpaul 2107150583Sjhb SIS_LOCK(sc); 210850974Swpaul mii = device_get_softc(sc->sis_miibus); 210950974Swpaul mii_pollstat(mii); 211050974Swpaul ifmr->ifm_active = mii->mii_media_active; 211150974Swpaul ifmr->ifm_status = mii->mii_media_status; 2112229057Syongari SIS_UNLOCK(sc); 211350974Swpaul} 211450974Swpaul 2115102334Salfredstatic int 2116139740Sphksis_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 211750974Swpaul{ 211850974Swpaul struct sis_softc *sc = ifp->if_softc; 211950974Swpaul struct ifreq *ifr = (struct ifreq *) data; 212050974Swpaul struct mii_data *mii; 2121212167Syongari int error = 0, mask; 212250974Swpaul 2123212104Syongari switch (command) { 212450974Swpaul case SIOCSIFFLAGS: 2125150583Sjhb SIS_LOCK(sc); 212650974Swpaul if (ifp->if_flags & IFF_UP) { 2127212119Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 2128212119Syongari ((ifp->if_flags ^ sc->sis_if_flags) & 2129217548Syongari (IFF_PROMISC | IFF_ALLMULTI)) != 0) 2130217548Syongari sis_rxfilter(sc); 2131217548Syongari else 2132212119Syongari sis_initl(sc); 2133217548Syongari } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2134139741Sphk sis_stop(sc); 2135212119Syongari sc->sis_if_flags = ifp->if_flags; 2136150583Sjhb SIS_UNLOCK(sc); 213750974Swpaul break; 213850974Swpaul case SIOCADDMULTI: 213950974Swpaul case SIOCDELMULTI: 214081713Swpaul SIS_LOCK(sc); 2141217548Syongari sis_rxfilter(sc); 214281713Swpaul SIS_UNLOCK(sc); 214350974Swpaul break; 214450974Swpaul case SIOCGIFMEDIA: 214550974Swpaul case SIOCSIFMEDIA: 214650974Swpaul mii = device_get_softc(sc->sis_miibus); 214750974Swpaul error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 214850974Swpaul break; 2149128138Sru case SIOCSIFCAP: 2150212167Syongari SIS_LOCK(sc); 2151212167Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2152150789Sglebius#ifdef DEVICE_POLLING 2153212167Syongari if ((mask & IFCAP_POLLING) != 0 && 2154212167Syongari (IFCAP_POLLING & ifp->if_capabilities) != 0) { 2155212167Syongari ifp->if_capenable ^= IFCAP_POLLING; 2156212167Syongari if ((IFCAP_POLLING & ifp->if_capenable) != 0) { 2157212167Syongari error = ether_poll_register(sis_poll, ifp); 2158212167Syongari if (error != 0) { 2159212167Syongari SIS_UNLOCK(sc); 2160212167Syongari break; 2161212167Syongari } 2162212167Syongari /* Disable interrupts. */ 2163212167Syongari CSR_WRITE_4(sc, SIS_IER, 0); 2164212167Syongari } else { 2165212167Syongari error = ether_poll_deregister(ifp); 2166212167Syongari /* Enable interrupts. */ 2167212167Syongari CSR_WRITE_4(sc, SIS_IER, 1); 2168212167Syongari } 2169150789Sglebius } 2170212167Syongari#endif /* DEVICE_POLLING */ 2171212167Syongari if ((mask & IFCAP_WOL) != 0 && 2172212167Syongari (ifp->if_capabilities & IFCAP_WOL) != 0) { 2173212167Syongari if ((mask & IFCAP_WOL_UCAST) != 0) 2174212167Syongari ifp->if_capenable ^= IFCAP_WOL_UCAST; 2175212167Syongari if ((mask & IFCAP_WOL_MCAST) != 0) 2176212167Syongari ifp->if_capenable ^= IFCAP_WOL_MCAST; 2177212167Syongari if ((mask & IFCAP_WOL_MAGIC) != 0) 2178212167Syongari ifp->if_capenable ^= IFCAP_WOL_MAGIC; 2179150789Sglebius } 2180212167Syongari SIS_UNLOCK(sc); 2181128138Sru break; 218250974Swpaul default: 2183106936Ssam error = ether_ioctl(ifp, command, data); 218450974Swpaul break; 218550974Swpaul } 218650974Swpaul 2187212104Syongari return (error); 218850974Swpaul} 218950974Swpaul 2190102334Salfredstatic void 2191166940Sdelphijsis_watchdog(struct sis_softc *sc) 219250974Swpaul{ 219350974Swpaul 2194166940Sdelphij SIS_LOCK_ASSERT(sc); 219567087Swpaul 2196166940Sdelphij if (sc->sis_watchdog_timer == 0 || --sc->sis_watchdog_timer >0) 2197166940Sdelphij return; 219850974Swpaul 2199166940Sdelphij device_printf(sc->sis_dev, "watchdog timeout\n"); 2200166940Sdelphij sc->sis_ifp->if_oerrors++; 2201166940Sdelphij 2202212121Syongari sc->sis_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2203139715Sphk sis_initl(sc); 220450974Swpaul 2205166940Sdelphij if (!IFQ_DRV_IS_EMPTY(&sc->sis_ifp->if_snd)) 2206166940Sdelphij sis_startl(sc->sis_ifp); 220750974Swpaul} 220850974Swpaul 220950974Swpaul/* 221050974Swpaul * Stop the adapter and free any mbufs allocated to the 221150974Swpaul * RX and TX lists. 221250974Swpaul */ 2213102334Salfredstatic void 2214139740Sphksis_stop(struct sis_softc *sc) 221550974Swpaul{ 2216212109Syongari struct ifnet *ifp; 2217212109Syongari struct sis_rxdesc *rxd; 2218212109Syongari struct sis_txdesc *txd; 2219139805Sphk int i; 222050974Swpaul 2221139717Sphk SIS_LOCK_ASSERT(sc); 2222212116Syongari 2223147256Sbrooks ifp = sc->sis_ifp; 2224166940Sdelphij sc->sis_watchdog_timer = 0; 222550974Swpaul 2226119785Ssam callout_stop(&sc->sis_stat_ch); 222787472Speter 2228148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 222950974Swpaul CSR_WRITE_4(sc, SIS_IER, 0); 223050974Swpaul CSR_WRITE_4(sc, SIS_IMR, 0); 2231139798Sphk CSR_READ_4(sc, SIS_ISR); /* clear any interrupts already pending */ 223250974Swpaul SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE); 223350974Swpaul DELAY(1000); 223450974Swpaul CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0); 223550974Swpaul CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); 223650974Swpaul 2237212157Syongari sc->sis_flags &= ~SIS_FLAG_LINK; 223864963Swpaul 223950974Swpaul /* 224050974Swpaul * Free data in the RX lists. 224150974Swpaul */ 2242212109Syongari for (i = 0; i < SIS_RX_LIST_CNT; i++) { 2243212109Syongari rxd = &sc->sis_rxdesc[i]; 2244212109Syongari if (rxd->rx_m != NULL) { 2245212109Syongari bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, 2246212109Syongari BUS_DMASYNC_POSTREAD); 2247212109Syongari bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap); 2248212109Syongari m_freem(rxd->rx_m); 2249212109Syongari rxd->rx_m = NULL; 2250212109Syongari } 225150974Swpaul } 225250974Swpaul 225350974Swpaul /* 225450974Swpaul * Free the TX list buffers. 225550974Swpaul */ 2256212109Syongari for (i = 0; i < SIS_TX_LIST_CNT; i++) { 2257212109Syongari txd = &sc->sis_txdesc[i]; 2258212109Syongari if (txd->tx_m != NULL) { 2259212109Syongari bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, 2260212109Syongari BUS_DMASYNC_POSTWRITE); 2261212109Syongari bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 2262212109Syongari m_freem(txd->tx_m); 2263212109Syongari txd->tx_m = NULL; 2264212109Syongari } 226550974Swpaul } 226650974Swpaul} 226750974Swpaul 226850974Swpaul/* 226950974Swpaul * Stop all chip I/O so that the kernel's probe routines don't 227050974Swpaul * get confused by errant DMAs when rebooting. 227150974Swpaul */ 2272188463Simpstatic int 2273139717Sphksis_shutdown(device_t dev) 227450974Swpaul{ 227550974Swpaul 2276212167Syongari return (sis_suspend(dev)); 227750974Swpaul} 2278139800Sphk 2279212166Syongaristatic int 2280212166Syongarisis_suspend(device_t dev) 2281212166Syongari{ 2282212166Syongari struct sis_softc *sc; 2283212166Syongari 2284212166Syongari sc = device_get_softc(dev); 2285212166Syongari SIS_LOCK(sc); 2286212166Syongari sis_stop(sc); 2287212167Syongari sis_wol(sc); 2288212166Syongari SIS_UNLOCK(sc); 2289212166Syongari return (0); 2290212166Syongari} 2291212166Syongari 2292212166Syongaristatic int 2293212166Syongarisis_resume(device_t dev) 2294212166Syongari{ 2295212166Syongari struct sis_softc *sc; 2296212166Syongari struct ifnet *ifp; 2297212166Syongari 2298212166Syongari sc = device_get_softc(dev); 2299212166Syongari SIS_LOCK(sc); 2300212166Syongari ifp = sc->sis_ifp; 2301212166Syongari if ((ifp->if_flags & IFF_UP) != 0) { 2302212166Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2303212166Syongari sis_initl(sc); 2304212166Syongari } 2305212166Syongari SIS_UNLOCK(sc); 2306212166Syongari return (0); 2307212166Syongari} 2308212166Syongari 2309212157Syongaristatic void 2310212167Syongarisis_wol(struct sis_softc *sc) 2311212167Syongari{ 2312212167Syongari struct ifnet *ifp; 2313212167Syongari uint32_t val; 2314212167Syongari uint16_t pmstat; 2315212167Syongari int pmc; 2316212167Syongari 2317212167Syongari ifp = sc->sis_ifp; 2318212167Syongari if ((ifp->if_capenable & IFCAP_WOL) == 0) 2319212167Syongari return; 2320212167Syongari 2321212167Syongari if (sc->sis_type == SIS_TYPE_83815) { 2322212167Syongari /* Reset RXDP. */ 2323212167Syongari CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); 2324212167Syongari 2325212167Syongari /* Configure WOL events. */ 2326212167Syongari CSR_READ_4(sc, NS_WCSR); 2327212167Syongari val = 0; 2328212167Syongari if ((ifp->if_capenable & IFCAP_WOL_UCAST) != 0) 2329212167Syongari val |= NS_WCSR_WAKE_UCAST; 2330212167Syongari if ((ifp->if_capenable & IFCAP_WOL_MCAST) != 0) 2331212167Syongari val |= NS_WCSR_WAKE_MCAST; 2332212167Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2333212167Syongari val |= NS_WCSR_WAKE_MAGIC; 2334212167Syongari CSR_WRITE_4(sc, NS_WCSR, val); 2335212167Syongari /* Enable PME and clear PMESTS. */ 2336212167Syongari val = CSR_READ_4(sc, NS_CLKRUN); 2337212167Syongari val |= NS_CLKRUN_PMEENB | NS_CLKRUN_PMESTS; 2338212167Syongari CSR_WRITE_4(sc, NS_CLKRUN, val); 2339212167Syongari /* Enable silent RX mode. */ 2340212167Syongari SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 2341212167Syongari } else { 2342219902Sjhb if (pci_find_cap(sc->sis_dev, PCIY_PMG, &pmc) != 0) 2343212167Syongari return; 2344212167Syongari val = 0; 2345212167Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2346212167Syongari val |= SIS_PWRMAN_WOL_MAGIC; 2347212167Syongari CSR_WRITE_4(sc, SIS_PWRMAN_CTL, val); 2348212167Syongari /* Request PME. */ 2349212167Syongari pmstat = pci_read_config(sc->sis_dev, 2350212167Syongari pmc + PCIR_POWER_STATUS, 2); 2351212167Syongari pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 2352212167Syongari if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0) 2353212167Syongari pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 2354212167Syongari pci_write_config(sc->sis_dev, 2355212167Syongari pmc + PCIR_POWER_STATUS, pmstat, 2); 2356212167Syongari } 2357212167Syongari} 2358212167Syongari 2359212167Syongaristatic void 2360212157Syongarisis_add_sysctls(struct sis_softc *sc) 2361212157Syongari{ 2362212157Syongari struct sysctl_ctx_list *ctx; 2363212157Syongari struct sysctl_oid_list *children; 2364212157Syongari char tn[32]; 2365212157Syongari int unit; 2366212157Syongari 2367212157Syongari ctx = device_get_sysctl_ctx(sc->sis_dev); 2368212157Syongari children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sis_dev)); 2369212157Syongari 2370212157Syongari unit = device_get_unit(sc->sis_dev); 2371212157Syongari /* 2372212157Syongari * Unlike most other controllers, NS DP83815/DP83816 controllers 2373212157Syongari * seem to pad with 0xFF when it encounter short frames. According 2374212157Syongari * to RFC 1042 the pad bytes should be 0x00. Turning this tunable 2375212157Syongari * on will have driver pad manully but it's disabled by default 2376212157Syongari * because it will consume extra CPU cycles for short frames. 2377212157Syongari */ 2378212157Syongari sc->sis_manual_pad = 0; 2379212157Syongari snprintf(tn, sizeof(tn), "dev.sis.%d.manual_pad", unit); 2380212157Syongari TUNABLE_INT_FETCH(tn, &sc->sis_manual_pad); 2381212157Syongari SYSCTL_ADD_INT(ctx, children, OID_AUTO, "manual_pad", 2382212157Syongari CTLFLAG_RW, &sc->sis_manual_pad, 0, "Manually pad short frames"); 2383212157Syongari} 2384212157Syongari 2385139800Sphkstatic device_method_t sis_methods[] = { 2386139800Sphk /* Device interface */ 2387139800Sphk DEVMETHOD(device_probe, sis_probe), 2388139800Sphk DEVMETHOD(device_attach, sis_attach), 2389139800Sphk DEVMETHOD(device_detach, sis_detach), 2390139800Sphk DEVMETHOD(device_shutdown, sis_shutdown), 2391212166Syongari DEVMETHOD(device_suspend, sis_suspend), 2392212166Syongari DEVMETHOD(device_resume, sis_resume), 2393139800Sphk 2394139800Sphk /* MII interface */ 2395139800Sphk DEVMETHOD(miibus_readreg, sis_miibus_readreg), 2396139800Sphk DEVMETHOD(miibus_writereg, sis_miibus_writereg), 2397139800Sphk DEVMETHOD(miibus_statchg, sis_miibus_statchg), 2398139800Sphk 2399229093Shselasky DEVMETHOD_END 2400139800Sphk}; 2401139800Sphk 2402139800Sphkstatic driver_t sis_driver = { 2403139800Sphk "sis", 2404139800Sphk sis_methods, 2405139800Sphk sizeof(struct sis_softc) 2406139800Sphk}; 2407139800Sphk 2408139800Sphkstatic devclass_t sis_devclass; 2409139800Sphk 2410139800SphkDRIVER_MODULE(sis, pci, sis_driver, sis_devclass, 0, 0); 2411139800SphkDRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0); 2412