1d2155f2fSWarner Losh /*- 2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 3df57947fSPedro F. Giffuni * 4d2155f2fSWarner Losh * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org> 5d2155f2fSWarner Losh * Copyright (c) 1997, 1998, 1999 6d2155f2fSWarner Losh * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 7d2155f2fSWarner Losh * 8d2155f2fSWarner Losh * Redistribution and use in source and binary forms, with or without 9d2155f2fSWarner Losh * modification, are permitted provided that the following conditions 10d2155f2fSWarner Losh * are met: 11d2155f2fSWarner Losh * 1. Redistributions of source code must retain the above copyright 12d2155f2fSWarner Losh * notice, this list of conditions and the following disclaimer. 13d2155f2fSWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 14d2155f2fSWarner Losh * notice, this list of conditions and the following disclaimer in the 15d2155f2fSWarner Losh * documentation and/or other materials provided with the distribution. 16d2155f2fSWarner Losh * 3. All advertising materials mentioning features or use of this software 17d2155f2fSWarner Losh * must display the following acknowledgement: 18d2155f2fSWarner Losh * This product includes software developed by Bill Paul. 19d2155f2fSWarner Losh * 4. Neither the name of the author nor the names of any co-contributors 20d2155f2fSWarner Losh * may be used to endorse or promote products derived from this software 21d2155f2fSWarner Losh * without specific prior written permission. 22d2155f2fSWarner Losh * 23d2155f2fSWarner Losh * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 24d2155f2fSWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25d2155f2fSWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26d2155f2fSWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 27d2155f2fSWarner Losh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28d2155f2fSWarner Losh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29d2155f2fSWarner Losh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30d2155f2fSWarner Losh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31d2155f2fSWarner Losh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32d2155f2fSWarner Losh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 33d2155f2fSWarner Losh * THE POSSIBILITY OF SUCH DAMAGE. 34d2155f2fSWarner Losh */ 35d2155f2fSWarner Losh 36d2155f2fSWarner Losh #include <sys/cdefs.h> 37d2155f2fSWarner Losh /* 38d2155f2fSWarner Losh * SiS 900/SiS 7016 fast ethernet PCI NIC driver. Datasheets are 39d2155f2fSWarner Losh * available from http://www.sis.com.tw. 40d2155f2fSWarner Losh * 41d2155f2fSWarner Losh * This driver also supports the NatSemi DP83815. Datasheets are 42d2155f2fSWarner Losh * available from http://www.national.com. 43d2155f2fSWarner Losh * 44d2155f2fSWarner Losh * Written by Bill Paul <wpaul@ee.columbia.edu> 45d2155f2fSWarner Losh * Electrical Engineering Department 46d2155f2fSWarner Losh * Columbia University, New York City 47d2155f2fSWarner Losh */ 48d2155f2fSWarner Losh /* 49d2155f2fSWarner Losh * The SiS 900 is a fairly simple chip. It uses bus master DMA with 50d2155f2fSWarner Losh * simple TX and RX descriptors of 3 longwords in size. The receiver 51d2155f2fSWarner Losh * has a single perfect filter entry for the station address and a 52d2155f2fSWarner Losh * 128-bit multicast hash table. The SiS 900 has a built-in MII-based 53d2155f2fSWarner Losh * transceiver while the 7016 requires an external transceiver chip. 54d2155f2fSWarner Losh * Both chips offer the standard bit-bang MII interface as well as 55d2155f2fSWarner Losh * an enchanced PHY interface which simplifies accessing MII registers. 56d2155f2fSWarner Losh * 57d2155f2fSWarner Losh * The only downside to this chipset is that RX descriptors must be 58d2155f2fSWarner Losh * longword aligned. 59d2155f2fSWarner Losh */ 60d2155f2fSWarner Losh 61d2155f2fSWarner Losh #ifdef HAVE_KERNEL_OPTION_HEADERS 62d2155f2fSWarner Losh #include "opt_device_polling.h" 63d2155f2fSWarner Losh #endif 64d2155f2fSWarner Losh 65d2155f2fSWarner Losh #include <sys/param.h> 66d2155f2fSWarner Losh #include <sys/systm.h> 67a629f2b1SPyun YongHyeon #include <sys/bus.h> 68a629f2b1SPyun YongHyeon #include <sys/endian.h> 69d2155f2fSWarner Losh #include <sys/kernel.h> 70a629f2b1SPyun YongHyeon #include <sys/lock.h> 71a629f2b1SPyun YongHyeon #include <sys/malloc.h> 72a629f2b1SPyun YongHyeon #include <sys/mbuf.h> 73d2155f2fSWarner Losh #include <sys/module.h> 74d2155f2fSWarner Losh #include <sys/socket.h> 75a629f2b1SPyun YongHyeon #include <sys/sockio.h> 7694222398SPyun YongHyeon #include <sys/sysctl.h> 77d2155f2fSWarner Losh 78d2155f2fSWarner Losh #include <net/if.h> 7976039bc8SGleb Smirnoff #include <net/if_var.h> 80d2155f2fSWarner Losh #include <net/if_arp.h> 81d2155f2fSWarner Losh #include <net/ethernet.h> 82d2155f2fSWarner Losh #include <net/if_dl.h> 83d2155f2fSWarner Losh #include <net/if_media.h> 84d2155f2fSWarner Losh #include <net/if_types.h> 85d2155f2fSWarner Losh #include <net/if_vlan_var.h> 86d2155f2fSWarner Losh 87d2155f2fSWarner Losh #include <net/bpf.h> 88d2155f2fSWarner Losh 89d2155f2fSWarner Losh #include <machine/bus.h> 90d2155f2fSWarner Losh #include <machine/resource.h> 91d2155f2fSWarner Losh #include <sys/rman.h> 92d2155f2fSWarner Losh 93d2155f2fSWarner Losh #include <dev/mii/mii.h> 948c1093fcSMarius Strobl #include <dev/mii/mii_bitbang.h> 95d2155f2fSWarner Losh #include <dev/mii/miivar.h> 96d2155f2fSWarner Losh 97d2155f2fSWarner Losh #include <dev/pci/pcireg.h> 98d2155f2fSWarner Losh #include <dev/pci/pcivar.h> 99d2155f2fSWarner Losh 100d2155f2fSWarner Losh #define SIS_USEIOSPACE 101d2155f2fSWarner Losh 102d2155f2fSWarner Losh #include <dev/sis/if_sisreg.h> 103d2155f2fSWarner Losh 104d2155f2fSWarner Losh MODULE_DEPEND(sis, pci, 1, 1, 1); 105d2155f2fSWarner Losh MODULE_DEPEND(sis, ether, 1, 1, 1); 106d2155f2fSWarner Losh MODULE_DEPEND(sis, miibus, 1, 1, 1); 107d2155f2fSWarner Losh 108d2155f2fSWarner Losh /* "device miibus" required. See GENERIC if you get errors here. */ 109d2155f2fSWarner Losh #include "miibus_if.h" 110d2155f2fSWarner Losh 111d2155f2fSWarner Losh #define SIS_LOCK(_sc) mtx_lock(&(_sc)->sis_mtx) 112d2155f2fSWarner Losh #define SIS_UNLOCK(_sc) mtx_unlock(&(_sc)->sis_mtx) 113d2155f2fSWarner Losh #define SIS_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sis_mtx, MA_OWNED) 114d2155f2fSWarner Losh 115d2155f2fSWarner Losh /* 116d2155f2fSWarner Losh * register space access macros 117d2155f2fSWarner Losh */ 118d2155f2fSWarner Losh #define CSR_WRITE_4(sc, reg, val) bus_write_4(sc->sis_res[0], reg, val) 119d2155f2fSWarner Losh 120d2155f2fSWarner Losh #define CSR_READ_4(sc, reg) bus_read_4(sc->sis_res[0], reg) 121d2155f2fSWarner Losh 122d2155f2fSWarner Losh #define CSR_READ_2(sc, reg) bus_read_2(sc->sis_res[0], reg) 123d2155f2fSWarner Losh 1248c1093fcSMarius Strobl #define CSR_BARRIER(sc, reg, length, flags) \ 1258c1093fcSMarius Strobl bus_barrier(sc->sis_res[0], reg, length, flags) 1268c1093fcSMarius Strobl 127d2155f2fSWarner Losh /* 128d2155f2fSWarner Losh * Various supported device vendors/types and their names. 129d2155f2fSWarner Losh */ 13029658c96SDimitry Andric static const struct sis_type sis_devs[] = { 131d2155f2fSWarner Losh { SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" }, 132d2155f2fSWarner Losh { SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" }, 133d2155f2fSWarner Losh { NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP8381[56] 10/100BaseTX" }, 134d2155f2fSWarner Losh { 0, 0, NULL } 135d2155f2fSWarner Losh }; 136d2155f2fSWarner Losh 137d2155f2fSWarner Losh static int sis_detach(device_t); 138a629f2b1SPyun YongHyeon static __inline void sis_discard_rxbuf(struct sis_rxdesc *); 139a629f2b1SPyun YongHyeon static int sis_dma_alloc(struct sis_softc *); 140a629f2b1SPyun YongHyeon static void sis_dma_free(struct sis_softc *); 141a629f2b1SPyun YongHyeon static int sis_dma_ring_alloc(struct sis_softc *, bus_size_t, bus_size_t, 142a629f2b1SPyun YongHyeon bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *); 143a629f2b1SPyun YongHyeon static void sis_dmamap_cb(void *, bus_dma_segment_t *, int, int); 144a629f2b1SPyun YongHyeon #ifndef __NO_STRICT_ALIGNMENT 145a629f2b1SPyun YongHyeon static __inline void sis_fixup_rx(struct mbuf *); 146a629f2b1SPyun YongHyeon #endif 147*1125d093SJustin Hibbits static void sis_ifmedia_sts(if_t, struct ifmediareq *); 148*1125d093SJustin Hibbits static int sis_ifmedia_upd(if_t); 149d2155f2fSWarner Losh static void sis_init(void *); 150d2155f2fSWarner Losh static void sis_initl(struct sis_softc *); 151d2155f2fSWarner Losh static void sis_intr(void *); 152*1125d093SJustin Hibbits static int sis_ioctl(if_t, u_long, caddr_t); 1538c1093fcSMarius Strobl static uint32_t sis_mii_bitbang_read(device_t); 1548c1093fcSMarius Strobl static void sis_mii_bitbang_write(device_t, uint32_t); 155a629f2b1SPyun YongHyeon static int sis_newbuf(struct sis_softc *, struct sis_rxdesc *); 1560af3989bSPyun YongHyeon static int sis_resume(device_t); 157a629f2b1SPyun YongHyeon static int sis_rxeof(struct sis_softc *); 158ed15702fSPyun YongHyeon static void sis_rxfilter(struct sis_softc *); 159ed15702fSPyun YongHyeon static void sis_rxfilter_ns(struct sis_softc *); 160ed15702fSPyun YongHyeon static void sis_rxfilter_sis(struct sis_softc *); 161*1125d093SJustin Hibbits static void sis_start(if_t); 162*1125d093SJustin Hibbits static void sis_startl(if_t); 163d2155f2fSWarner Losh static void sis_stop(struct sis_softc *); 1640af3989bSPyun YongHyeon static int sis_suspend(device_t); 16594222398SPyun YongHyeon static void sis_add_sysctls(struct sis_softc *); 166d2155f2fSWarner Losh static void sis_watchdog(struct sis_softc *); 1670af3989bSPyun YongHyeon static void sis_wol(struct sis_softc *); 168d2155f2fSWarner Losh 1698c1093fcSMarius Strobl /* 1708c1093fcSMarius Strobl * MII bit-bang glue 1718c1093fcSMarius Strobl */ 1728c1093fcSMarius Strobl static const struct mii_bitbang_ops sis_mii_bitbang_ops = { 1738c1093fcSMarius Strobl sis_mii_bitbang_read, 1748c1093fcSMarius Strobl sis_mii_bitbang_write, 1758c1093fcSMarius Strobl { 1768c1093fcSMarius Strobl SIS_MII_DATA, /* MII_BIT_MDO */ 1778c1093fcSMarius Strobl SIS_MII_DATA, /* MII_BIT_MDI */ 1788c1093fcSMarius Strobl SIS_MII_CLK, /* MII_BIT_MDC */ 1798c1093fcSMarius Strobl SIS_MII_DIR, /* MII_BIT_DIR_HOST_PHY */ 1808c1093fcSMarius Strobl 0, /* MII_BIT_DIR_PHY_HOST */ 1818c1093fcSMarius Strobl } 1828c1093fcSMarius Strobl }; 183d2155f2fSWarner Losh 184d2155f2fSWarner Losh static struct resource_spec sis_res_spec[] = { 185d2155f2fSWarner Losh #ifdef SIS_USEIOSPACE 186d2155f2fSWarner Losh { SYS_RES_IOPORT, SIS_PCI_LOIO, RF_ACTIVE}, 187d2155f2fSWarner Losh #else 188d2155f2fSWarner Losh { SYS_RES_MEMORY, SIS_PCI_LOMEM, RF_ACTIVE}, 189d2155f2fSWarner Losh #endif 190d2155f2fSWarner Losh { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE}, 191d2155f2fSWarner Losh { -1, 0 } 192d2155f2fSWarner Losh }; 193d2155f2fSWarner Losh 194d2155f2fSWarner Losh #define SIS_SETBIT(sc, reg, x) \ 195d2155f2fSWarner Losh CSR_WRITE_4(sc, reg, \ 196d2155f2fSWarner Losh CSR_READ_4(sc, reg) | (x)) 197d2155f2fSWarner Losh 198d2155f2fSWarner Losh #define SIS_CLRBIT(sc, reg, x) \ 199d2155f2fSWarner Losh CSR_WRITE_4(sc, reg, \ 200d2155f2fSWarner Losh CSR_READ_4(sc, reg) & ~(x)) 201d2155f2fSWarner Losh 202d2155f2fSWarner Losh #define SIO_SET(x) \ 203d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) | x) 204d2155f2fSWarner Losh 205d2155f2fSWarner Losh #define SIO_CLR(x) \ 206d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x) 207d2155f2fSWarner Losh 208d2155f2fSWarner Losh /* 209d2155f2fSWarner Losh * Routine to reverse the bits in a word. Stolen almost 210d2155f2fSWarner Losh * verbatim from /usr/games/fortune. 211d2155f2fSWarner Losh */ 212d2155f2fSWarner Losh static uint16_t 213d2155f2fSWarner Losh sis_reverse(uint16_t n) 214d2155f2fSWarner Losh { 215d2155f2fSWarner Losh n = ((n >> 1) & 0x5555) | ((n << 1) & 0xaaaa); 216d2155f2fSWarner Losh n = ((n >> 2) & 0x3333) | ((n << 2) & 0xcccc); 217d2155f2fSWarner Losh n = ((n >> 4) & 0x0f0f) | ((n << 4) & 0xf0f0); 218d2155f2fSWarner Losh n = ((n >> 8) & 0x00ff) | ((n << 8) & 0xff00); 219d2155f2fSWarner Losh 220d2155f2fSWarner Losh return (n); 221d2155f2fSWarner Losh } 222d2155f2fSWarner Losh 223d2155f2fSWarner Losh static void 224d2155f2fSWarner Losh sis_delay(struct sis_softc *sc) 225d2155f2fSWarner Losh { 226d2155f2fSWarner Losh int idx; 227d2155f2fSWarner Losh 228d2155f2fSWarner Losh for (idx = (300 / 33) + 1; idx > 0; idx--) 229d2155f2fSWarner Losh CSR_READ_4(sc, SIS_CSR); 230d2155f2fSWarner Losh } 231d2155f2fSWarner Losh 232d2155f2fSWarner Losh static void 233d2155f2fSWarner Losh sis_eeprom_idle(struct sis_softc *sc) 234d2155f2fSWarner Losh { 235d2155f2fSWarner Losh int i; 236d2155f2fSWarner Losh 237d2155f2fSWarner Losh SIO_SET(SIS_EECTL_CSEL); 238d2155f2fSWarner Losh sis_delay(sc); 239d2155f2fSWarner Losh SIO_SET(SIS_EECTL_CLK); 240d2155f2fSWarner Losh sis_delay(sc); 241d2155f2fSWarner Losh 242d2155f2fSWarner Losh for (i = 0; i < 25; i++) { 243d2155f2fSWarner Losh SIO_CLR(SIS_EECTL_CLK); 244d2155f2fSWarner Losh sis_delay(sc); 245d2155f2fSWarner Losh SIO_SET(SIS_EECTL_CLK); 246d2155f2fSWarner Losh sis_delay(sc); 247d2155f2fSWarner Losh } 248d2155f2fSWarner Losh 249d2155f2fSWarner Losh SIO_CLR(SIS_EECTL_CLK); 250d2155f2fSWarner Losh sis_delay(sc); 251d2155f2fSWarner Losh SIO_CLR(SIS_EECTL_CSEL); 252d2155f2fSWarner Losh sis_delay(sc); 253d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_EECTL, 0x00000000); 254d2155f2fSWarner Losh } 255d2155f2fSWarner Losh 256d2155f2fSWarner Losh /* 257d2155f2fSWarner Losh * Send a read command and address to the EEPROM, check for ACK. 258d2155f2fSWarner Losh */ 259d2155f2fSWarner Losh static void 260d2155f2fSWarner Losh sis_eeprom_putbyte(struct sis_softc *sc, int addr) 261d2155f2fSWarner Losh { 262d2155f2fSWarner Losh int d, i; 263d2155f2fSWarner Losh 264d2155f2fSWarner Losh d = addr | SIS_EECMD_READ; 265d2155f2fSWarner Losh 266d2155f2fSWarner Losh /* 267d2155f2fSWarner Losh * Feed in each bit and stobe the clock. 268d2155f2fSWarner Losh */ 269d2155f2fSWarner Losh for (i = 0x400; i; i >>= 1) { 270d2155f2fSWarner Losh if (d & i) { 271d2155f2fSWarner Losh SIO_SET(SIS_EECTL_DIN); 272d2155f2fSWarner Losh } else { 273d2155f2fSWarner Losh SIO_CLR(SIS_EECTL_DIN); 274d2155f2fSWarner Losh } 275d2155f2fSWarner Losh sis_delay(sc); 276d2155f2fSWarner Losh SIO_SET(SIS_EECTL_CLK); 277d2155f2fSWarner Losh sis_delay(sc); 278d2155f2fSWarner Losh SIO_CLR(SIS_EECTL_CLK); 279d2155f2fSWarner Losh sis_delay(sc); 280d2155f2fSWarner Losh } 281d2155f2fSWarner Losh } 282d2155f2fSWarner Losh 283d2155f2fSWarner Losh /* 284d2155f2fSWarner Losh * Read a word of data stored in the EEPROM at address 'addr.' 285d2155f2fSWarner Losh */ 286d2155f2fSWarner Losh static void 287d2155f2fSWarner Losh sis_eeprom_getword(struct sis_softc *sc, int addr, uint16_t *dest) 288d2155f2fSWarner Losh { 289d2155f2fSWarner Losh int i; 29091c265b8SPyun YongHyeon uint16_t word = 0; 291d2155f2fSWarner Losh 292d2155f2fSWarner Losh /* Force EEPROM to idle state. */ 293d2155f2fSWarner Losh sis_eeprom_idle(sc); 294d2155f2fSWarner Losh 295d2155f2fSWarner Losh /* Enter EEPROM access mode. */ 296d2155f2fSWarner Losh sis_delay(sc); 297d2155f2fSWarner Losh SIO_CLR(SIS_EECTL_CLK); 298d2155f2fSWarner Losh sis_delay(sc); 299d2155f2fSWarner Losh SIO_SET(SIS_EECTL_CSEL); 300d2155f2fSWarner Losh sis_delay(sc); 301d2155f2fSWarner Losh 302d2155f2fSWarner Losh /* 303d2155f2fSWarner Losh * Send address of word we want to read. 304d2155f2fSWarner Losh */ 305d2155f2fSWarner Losh sis_eeprom_putbyte(sc, addr); 306d2155f2fSWarner Losh 307d2155f2fSWarner Losh /* 308d2155f2fSWarner Losh * Start reading bits from EEPROM. 309d2155f2fSWarner Losh */ 310d2155f2fSWarner Losh for (i = 0x8000; i; i >>= 1) { 311d2155f2fSWarner Losh SIO_SET(SIS_EECTL_CLK); 312d2155f2fSWarner Losh sis_delay(sc); 313d2155f2fSWarner Losh if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECTL_DOUT) 314d2155f2fSWarner Losh word |= i; 315d2155f2fSWarner Losh sis_delay(sc); 316d2155f2fSWarner Losh SIO_CLR(SIS_EECTL_CLK); 317d2155f2fSWarner Losh sis_delay(sc); 318d2155f2fSWarner Losh } 319d2155f2fSWarner Losh 320d2155f2fSWarner Losh /* Turn off EEPROM access mode. */ 321d2155f2fSWarner Losh sis_eeprom_idle(sc); 322d2155f2fSWarner Losh 323d2155f2fSWarner Losh *dest = word; 324d2155f2fSWarner Losh } 325d2155f2fSWarner Losh 326d2155f2fSWarner Losh /* 327d2155f2fSWarner Losh * Read a sequence of words from the EEPROM. 328d2155f2fSWarner Losh */ 329d2155f2fSWarner Losh static void 330d2155f2fSWarner Losh sis_read_eeprom(struct sis_softc *sc, caddr_t dest, int off, int cnt, int swap) 331d2155f2fSWarner Losh { 332d2155f2fSWarner Losh int i; 33391c265b8SPyun YongHyeon uint16_t word = 0, *ptr; 334d2155f2fSWarner Losh 335d2155f2fSWarner Losh for (i = 0; i < cnt; i++) { 336d2155f2fSWarner Losh sis_eeprom_getword(sc, off + i, &word); 33791c265b8SPyun YongHyeon ptr = (uint16_t *)(dest + (i * 2)); 338d2155f2fSWarner Losh if (swap) 339d2155f2fSWarner Losh *ptr = ntohs(word); 340d2155f2fSWarner Losh else 341d2155f2fSWarner Losh *ptr = word; 342d2155f2fSWarner Losh } 343d2155f2fSWarner Losh } 344d2155f2fSWarner Losh 345d2155f2fSWarner Losh #if defined(__i386__) || defined(__amd64__) 346d2155f2fSWarner Losh static device_t 347d2155f2fSWarner Losh sis_find_bridge(device_t dev) 348d2155f2fSWarner Losh { 349d2155f2fSWarner Losh devclass_t pci_devclass; 350d2155f2fSWarner Losh device_t *pci_devices; 351d2155f2fSWarner Losh int pci_count = 0; 352d2155f2fSWarner Losh device_t *pci_children; 353d2155f2fSWarner Losh int pci_childcount = 0; 354d2155f2fSWarner Losh device_t *busp, *childp; 355d2155f2fSWarner Losh device_t child = NULL; 356d2155f2fSWarner Losh int i, j; 357d2155f2fSWarner Losh 358d2155f2fSWarner Losh if ((pci_devclass = devclass_find("pci")) == NULL) 359d2155f2fSWarner Losh return (NULL); 360d2155f2fSWarner Losh 361d2155f2fSWarner Losh devclass_get_devices(pci_devclass, &pci_devices, &pci_count); 362d2155f2fSWarner Losh 363d2155f2fSWarner Losh for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) { 36431063462SWarner Losh if (device_get_children(*busp, &pci_children, &pci_childcount)) 36531063462SWarner Losh continue; 366d2155f2fSWarner Losh for (j = 0, childp = pci_children; 367d2155f2fSWarner Losh j < pci_childcount; j++, childp++) { 368d2155f2fSWarner Losh if (pci_get_vendor(*childp) == SIS_VENDORID && 369d2155f2fSWarner Losh pci_get_device(*childp) == 0x0008) { 370d2155f2fSWarner Losh child = *childp; 37131063462SWarner Losh free(pci_children, M_TEMP); 372d2155f2fSWarner Losh goto done; 373d2155f2fSWarner Losh } 374d2155f2fSWarner Losh } 37531063462SWarner Losh free(pci_children, M_TEMP); 376d2155f2fSWarner Losh } 377d2155f2fSWarner Losh 378d2155f2fSWarner Losh done: 379d2155f2fSWarner Losh free(pci_devices, M_TEMP); 380d2155f2fSWarner Losh return (child); 381d2155f2fSWarner Losh } 382d2155f2fSWarner Losh 383d2155f2fSWarner Losh static void 384d2155f2fSWarner Losh sis_read_cmos(struct sis_softc *sc, device_t dev, caddr_t dest, int off, int cnt) 385d2155f2fSWarner Losh { 386d2155f2fSWarner Losh device_t bridge; 38791c265b8SPyun YongHyeon uint8_t reg; 388d2155f2fSWarner Losh int i; 389d2155f2fSWarner Losh bus_space_tag_t btag; 390d2155f2fSWarner Losh 391d2155f2fSWarner Losh bridge = sis_find_bridge(dev); 392d2155f2fSWarner Losh if (bridge == NULL) 393d2155f2fSWarner Losh return; 394d2155f2fSWarner Losh reg = pci_read_config(bridge, 0x48, 1); 395d2155f2fSWarner Losh pci_write_config(bridge, 0x48, reg|0x40, 1); 396d2155f2fSWarner Losh 397d2155f2fSWarner Losh /* XXX */ 39881bd5041STijl Coosemans #if defined(__amd64__) || defined(__i386__) 39981bd5041STijl Coosemans btag = X86_BUS_SPACE_IO; 400d2155f2fSWarner Losh #endif 401d2155f2fSWarner Losh 402d2155f2fSWarner Losh for (i = 0; i < cnt; i++) { 403d2155f2fSWarner Losh bus_space_write_1(btag, 0x0, 0x70, i + off); 404d2155f2fSWarner Losh *(dest + i) = bus_space_read_1(btag, 0x0, 0x71); 405d2155f2fSWarner Losh } 406d2155f2fSWarner Losh 407d2155f2fSWarner Losh pci_write_config(bridge, 0x48, reg & ~0x40, 1); 408d2155f2fSWarner Losh } 409d2155f2fSWarner Losh 410d2155f2fSWarner Losh static void 411d2155f2fSWarner Losh sis_read_mac(struct sis_softc *sc, device_t dev, caddr_t dest) 412d2155f2fSWarner Losh { 41391c265b8SPyun YongHyeon uint32_t filtsave, csrsave; 414d2155f2fSWarner Losh 415d2155f2fSWarner Losh filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); 416d2155f2fSWarner Losh csrsave = CSR_READ_4(sc, SIS_CSR); 417d2155f2fSWarner Losh 418d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_CSR, SIS_CSR_RELOAD | filtsave); 419d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_CSR, 0); 420d2155f2fSWarner Losh 421d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE); 422d2155f2fSWarner Losh 423d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 42491c265b8SPyun YongHyeon ((uint16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); 425d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1); 42691c265b8SPyun YongHyeon ((uint16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); 427d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 42891c265b8SPyun YongHyeon ((uint16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); 429d2155f2fSWarner Losh 430d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); 431d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_CSR, csrsave); 432d2155f2fSWarner Losh } 433d2155f2fSWarner Losh #endif 434d2155f2fSWarner Losh 435d2155f2fSWarner Losh /* 4368c1093fcSMarius Strobl * Read the MII serial port for the MII bit-bang module. 4378c1093fcSMarius Strobl */ 4388c1093fcSMarius Strobl static uint32_t 4398c1093fcSMarius Strobl sis_mii_bitbang_read(device_t dev) 4408c1093fcSMarius Strobl { 4418c1093fcSMarius Strobl struct sis_softc *sc; 4428c1093fcSMarius Strobl uint32_t val; 4438c1093fcSMarius Strobl 4448c1093fcSMarius Strobl sc = device_get_softc(dev); 4458c1093fcSMarius Strobl 4468c1093fcSMarius Strobl val = CSR_READ_4(sc, SIS_EECTL); 4478c1093fcSMarius Strobl CSR_BARRIER(sc, SIS_EECTL, 4, 4488c1093fcSMarius Strobl BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 4498c1093fcSMarius Strobl return (val); 4508c1093fcSMarius Strobl } 4518c1093fcSMarius Strobl 4528c1093fcSMarius Strobl /* 4538c1093fcSMarius Strobl * Write the MII serial port for the MII bit-bang module. 454d2155f2fSWarner Losh */ 455d2155f2fSWarner Losh static void 4568c1093fcSMarius Strobl sis_mii_bitbang_write(device_t dev, uint32_t val) 457d2155f2fSWarner Losh { 4588c1093fcSMarius Strobl struct sis_softc *sc; 459d2155f2fSWarner Losh 4608c1093fcSMarius Strobl sc = device_get_softc(dev); 461d2155f2fSWarner Losh 4628c1093fcSMarius Strobl CSR_WRITE_4(sc, SIS_EECTL, val); 4638c1093fcSMarius Strobl CSR_BARRIER(sc, SIS_EECTL, 4, 4648c1093fcSMarius Strobl BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 465d2155f2fSWarner Losh } 466d2155f2fSWarner Losh 467d2155f2fSWarner Losh static int 468d2155f2fSWarner Losh sis_miibus_readreg(device_t dev, int phy, int reg) 469d2155f2fSWarner Losh { 470d2155f2fSWarner Losh struct sis_softc *sc; 471d2155f2fSWarner Losh 472d2155f2fSWarner Losh sc = device_get_softc(dev); 473d2155f2fSWarner Losh 474d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_83815) { 475d2155f2fSWarner Losh if (phy != 0) 476d2155f2fSWarner Losh return (0); 477d2155f2fSWarner Losh /* 478d2155f2fSWarner Losh * The NatSemi chip can take a while after 479d2155f2fSWarner Losh * a reset to come ready, during which the BMSR 480d2155f2fSWarner Losh * returns a value of 0. This is *never* supposed 481d2155f2fSWarner Losh * to happen: some of the BMSR bits are meant to 482d2155f2fSWarner Losh * be hardwired in the on position, and this can 483d2155f2fSWarner Losh * confuse the miibus code a bit during the probe 484d2155f2fSWarner Losh * and attach phase. So we make an effort to check 485d2155f2fSWarner Losh * for this condition and wait for it to clear. 486d2155f2fSWarner Losh */ 487d2155f2fSWarner Losh if (!CSR_READ_4(sc, NS_BMSR)) 488d2155f2fSWarner Losh DELAY(1000); 489d2155f2fSWarner Losh return CSR_READ_4(sc, NS_BMCR + (reg * 4)); 490d2155f2fSWarner Losh } 491d2155f2fSWarner Losh 492d2155f2fSWarner Losh /* 493d2155f2fSWarner Losh * Chipsets < SIS_635 seem not to be able to read/write 494d2155f2fSWarner Losh * through mdio. Use the enhanced PHY access register 495d2155f2fSWarner Losh * again for them. 496d2155f2fSWarner Losh */ 497d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_900 && 498d2155f2fSWarner Losh sc->sis_rev < SIS_REV_635) { 499d2155f2fSWarner Losh int i, val = 0; 500d2155f2fSWarner Losh 501d2155f2fSWarner Losh if (phy != 0) 502d2155f2fSWarner Losh return (0); 503d2155f2fSWarner Losh 504d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_PHYCTL, 505d2155f2fSWarner Losh (phy << 11) | (reg << 6) | SIS_PHYOP_READ); 506d2155f2fSWarner Losh SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS); 507d2155f2fSWarner Losh 508d2155f2fSWarner Losh for (i = 0; i < SIS_TIMEOUT; i++) { 509d2155f2fSWarner Losh if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS)) 510d2155f2fSWarner Losh break; 511d2155f2fSWarner Losh } 512d2155f2fSWarner Losh 513d2155f2fSWarner Losh if (i == SIS_TIMEOUT) { 5148c1093fcSMarius Strobl device_printf(sc->sis_dev, 5158c1093fcSMarius Strobl "PHY failed to come ready\n"); 516d2155f2fSWarner Losh return (0); 517d2155f2fSWarner Losh } 518d2155f2fSWarner Losh 519d2155f2fSWarner Losh val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF; 520d2155f2fSWarner Losh 521d2155f2fSWarner Losh if (val == 0xFFFF) 522d2155f2fSWarner Losh return (0); 523d2155f2fSWarner Losh 524d2155f2fSWarner Losh return (val); 5258c1093fcSMarius Strobl } else 5268c1093fcSMarius Strobl return (mii_bitbang_readreg(dev, &sis_mii_bitbang_ops, phy, 5278c1093fcSMarius Strobl reg)); 528d2155f2fSWarner Losh } 529d2155f2fSWarner Losh 530d2155f2fSWarner Losh static int 531d2155f2fSWarner Losh sis_miibus_writereg(device_t dev, int phy, int reg, int data) 532d2155f2fSWarner Losh { 533d2155f2fSWarner Losh struct sis_softc *sc; 534d2155f2fSWarner Losh 535d2155f2fSWarner Losh sc = device_get_softc(dev); 536d2155f2fSWarner Losh 537d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_83815) { 538d2155f2fSWarner Losh if (phy != 0) 539d2155f2fSWarner Losh return (0); 540d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data); 541d2155f2fSWarner Losh return (0); 542d2155f2fSWarner Losh } 543d2155f2fSWarner Losh 544d2155f2fSWarner Losh /* 545d2155f2fSWarner Losh * Chipsets < SIS_635 seem not to be able to read/write 546d2155f2fSWarner Losh * through mdio. Use the enhanced PHY access register 547d2155f2fSWarner Losh * again for them. 548d2155f2fSWarner Losh */ 549d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_900 && 550d2155f2fSWarner Losh sc->sis_rev < SIS_REV_635) { 551d2155f2fSWarner Losh int i; 552d2155f2fSWarner Losh 553d2155f2fSWarner Losh if (phy != 0) 554d2155f2fSWarner Losh return (0); 555d2155f2fSWarner Losh 556d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) | 557d2155f2fSWarner Losh (reg << 6) | SIS_PHYOP_WRITE); 558d2155f2fSWarner Losh SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS); 559d2155f2fSWarner Losh 560d2155f2fSWarner Losh for (i = 0; i < SIS_TIMEOUT; i++) { 561d2155f2fSWarner Losh if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS)) 562d2155f2fSWarner Losh break; 563d2155f2fSWarner Losh } 564d2155f2fSWarner Losh 565d2155f2fSWarner Losh if (i == SIS_TIMEOUT) 5668c1093fcSMarius Strobl device_printf(sc->sis_dev, 5678c1093fcSMarius Strobl "PHY failed to come ready\n"); 5688c1093fcSMarius Strobl } else 5698c1093fcSMarius Strobl mii_bitbang_writereg(dev, &sis_mii_bitbang_ops, phy, reg, 5708c1093fcSMarius Strobl data); 571d2155f2fSWarner Losh return (0); 572d2155f2fSWarner Losh } 573d2155f2fSWarner Losh 574d2155f2fSWarner Losh static void 575d2155f2fSWarner Losh sis_miibus_statchg(device_t dev) 576d2155f2fSWarner Losh { 577d2155f2fSWarner Losh struct sis_softc *sc; 578d7b57e79SPyun YongHyeon struct mii_data *mii; 579*1125d093SJustin Hibbits if_t ifp; 580d7b57e79SPyun YongHyeon uint32_t reg; 581d2155f2fSWarner Losh 582d2155f2fSWarner Losh sc = device_get_softc(dev); 583d2155f2fSWarner Losh SIS_LOCK_ASSERT(sc); 584d7b57e79SPyun YongHyeon 585d7b57e79SPyun YongHyeon mii = device_get_softc(sc->sis_miibus); 586d7b57e79SPyun YongHyeon ifp = sc->sis_ifp; 587d7b57e79SPyun YongHyeon if (mii == NULL || ifp == NULL || 588*1125d093SJustin Hibbits (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 589d7b57e79SPyun YongHyeon return; 590d7b57e79SPyun YongHyeon 59194222398SPyun YongHyeon sc->sis_flags &= ~SIS_FLAG_LINK; 592d7b57e79SPyun YongHyeon if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 593d7b57e79SPyun YongHyeon (IFM_ACTIVE | IFM_AVALID)) { 594d7b57e79SPyun YongHyeon switch (IFM_SUBTYPE(mii->mii_media_active)) { 595d7b57e79SPyun YongHyeon case IFM_10_T: 596d7b57e79SPyun YongHyeon CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10); 59794222398SPyun YongHyeon sc->sis_flags |= SIS_FLAG_LINK; 598d7b57e79SPyun YongHyeon break; 599d7b57e79SPyun YongHyeon case IFM_100_TX: 600d7b57e79SPyun YongHyeon CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); 60194222398SPyun YongHyeon sc->sis_flags |= SIS_FLAG_LINK; 602d7b57e79SPyun YongHyeon break; 603d7b57e79SPyun YongHyeon default: 604d7b57e79SPyun YongHyeon break; 605d7b57e79SPyun YongHyeon } 606d7b57e79SPyun YongHyeon } 607d7b57e79SPyun YongHyeon 60894222398SPyun YongHyeon if ((sc->sis_flags & SIS_FLAG_LINK) == 0) { 609d7b57e79SPyun YongHyeon /* 610d7b57e79SPyun YongHyeon * Stopping MACs seem to reset SIS_TX_LISTPTR and 611d7b57e79SPyun YongHyeon * SIS_RX_LISTPTR which in turn requires resetting 612d7b57e79SPyun YongHyeon * TX/RX buffers. So just don't do anything for 613d7b57e79SPyun YongHyeon * lost link. 614d7b57e79SPyun YongHyeon */ 615d7b57e79SPyun YongHyeon return; 616d7b57e79SPyun YongHyeon } 617d7b57e79SPyun YongHyeon 618d7b57e79SPyun YongHyeon /* Set full/half duplex mode. */ 619d7b57e79SPyun YongHyeon if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 620d7b57e79SPyun YongHyeon SIS_SETBIT(sc, SIS_TX_CFG, 621d7b57e79SPyun YongHyeon (SIS_TXCFG_IGN_HBEAT | SIS_TXCFG_IGN_CARR)); 622d7b57e79SPyun YongHyeon SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); 623d7b57e79SPyun YongHyeon } else { 624d7b57e79SPyun YongHyeon SIS_CLRBIT(sc, SIS_TX_CFG, 625d7b57e79SPyun YongHyeon (SIS_TXCFG_IGN_HBEAT | SIS_TXCFG_IGN_CARR)); 626d7b57e79SPyun YongHyeon SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); 627d7b57e79SPyun YongHyeon } 628d7b57e79SPyun YongHyeon 629e8bedbd2SPyun YongHyeon if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr >= NS_SRR_16A) { 630d7b57e79SPyun YongHyeon /* 631d7b57e79SPyun YongHyeon * MPII03.D: Half Duplex Excessive Collisions. 632d7b57e79SPyun YongHyeon * Also page 49 in 83816 manual 633d7b57e79SPyun YongHyeon */ 634d7b57e79SPyun YongHyeon SIS_SETBIT(sc, SIS_TX_CFG, SIS_TXCFG_MPII03D); 635d7b57e79SPyun YongHyeon } 636d7b57e79SPyun YongHyeon 637d7b57e79SPyun YongHyeon if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr < NS_SRR_16A && 638d7b57e79SPyun YongHyeon IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { 639d7b57e79SPyun YongHyeon /* 640d7b57e79SPyun YongHyeon * Short Cable Receive Errors (MP21.E) 641d7b57e79SPyun YongHyeon */ 642d7b57e79SPyun YongHyeon CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); 643d7b57e79SPyun YongHyeon reg = CSR_READ_4(sc, NS_PHY_DSPCFG) & 0xfff; 644d7b57e79SPyun YongHyeon CSR_WRITE_4(sc, NS_PHY_DSPCFG, reg | 0x1000); 645d7b57e79SPyun YongHyeon DELAY(100); 646d7b57e79SPyun YongHyeon reg = CSR_READ_4(sc, NS_PHY_TDATA) & 0xff; 647d7b57e79SPyun YongHyeon if ((reg & 0x0080) == 0 || (reg > 0xd8 && reg <= 0xff)) { 648d7b57e79SPyun YongHyeon device_printf(sc->sis_dev, 649d7b57e79SPyun YongHyeon "Applying short cable fix (reg=%x)\n", reg); 650d7b57e79SPyun YongHyeon CSR_WRITE_4(sc, NS_PHY_TDATA, 0x00e8); 651d7b57e79SPyun YongHyeon SIS_SETBIT(sc, NS_PHY_DSPCFG, 0x20); 652d7b57e79SPyun YongHyeon } 653d7b57e79SPyun YongHyeon CSR_WRITE_4(sc, NS_PHY_PAGE, 0); 654d7b57e79SPyun YongHyeon } 655d7b57e79SPyun YongHyeon /* Enable TX/RX MACs. */ 656d7b57e79SPyun YongHyeon SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE); 657d7b57e79SPyun YongHyeon SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE | SIS_CSR_RX_ENABLE); 658d2155f2fSWarner Losh } 659d2155f2fSWarner Losh 660d2155f2fSWarner Losh static uint32_t 661d2155f2fSWarner Losh sis_mchash(struct sis_softc *sc, const uint8_t *addr) 662d2155f2fSWarner Losh { 663d2155f2fSWarner Losh uint32_t crc; 664d2155f2fSWarner Losh 665d2155f2fSWarner Losh /* Compute CRC for the address value. */ 666d2155f2fSWarner Losh crc = ether_crc32_be(addr, ETHER_ADDR_LEN); 667d2155f2fSWarner Losh 668d2155f2fSWarner Losh /* 669d2155f2fSWarner Losh * return the filter bit position 670d2155f2fSWarner Losh * 671d2155f2fSWarner Losh * The NatSemi chip has a 512-bit filter, which is 672d2155f2fSWarner Losh * different than the SiS, so we special-case it. 673d2155f2fSWarner Losh */ 674d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_83815) 675d2155f2fSWarner Losh return (crc >> 23); 676d2155f2fSWarner Losh else if (sc->sis_rev >= SIS_REV_635 || 677d2155f2fSWarner Losh sc->sis_rev == SIS_REV_900B) 678d2155f2fSWarner Losh return (crc >> 24); 679d2155f2fSWarner Losh else 680d2155f2fSWarner Losh return (crc >> 25); 681d2155f2fSWarner Losh } 682d2155f2fSWarner Losh 683d2155f2fSWarner Losh static void 684ed15702fSPyun YongHyeon sis_rxfilter(struct sis_softc *sc) 685ed15702fSPyun YongHyeon { 686ed15702fSPyun YongHyeon 687ed15702fSPyun YongHyeon SIS_LOCK_ASSERT(sc); 688ed15702fSPyun YongHyeon 689ed15702fSPyun YongHyeon if (sc->sis_type == SIS_TYPE_83815) 690ed15702fSPyun YongHyeon sis_rxfilter_ns(sc); 691ed15702fSPyun YongHyeon else 692ed15702fSPyun YongHyeon sis_rxfilter_sis(sc); 693ed15702fSPyun YongHyeon } 694ed15702fSPyun YongHyeon 69533253a37SGleb Smirnoff static u_int 69633253a37SGleb Smirnoff sis_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 69733253a37SGleb Smirnoff { 69833253a37SGleb Smirnoff struct sis_softc *sc = arg; 69933253a37SGleb Smirnoff uint32_t h; 70033253a37SGleb Smirnoff int bit, index; 70133253a37SGleb Smirnoff 70233253a37SGleb Smirnoff h = sis_mchash(sc, LLADDR(sdl)); 70333253a37SGleb Smirnoff index = h >> 3; 70433253a37SGleb Smirnoff bit = h & 0x1F; 70533253a37SGleb Smirnoff CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index); 70633253a37SGleb Smirnoff if (bit > 0xF) 70733253a37SGleb Smirnoff bit -= 0x10; 70833253a37SGleb Smirnoff SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit)); 70933253a37SGleb Smirnoff 71033253a37SGleb Smirnoff return (1); 71133253a37SGleb Smirnoff } 71233253a37SGleb Smirnoff 713ed15702fSPyun YongHyeon static void 714ed15702fSPyun YongHyeon sis_rxfilter_ns(struct sis_softc *sc) 715d2155f2fSWarner Losh { 716*1125d093SJustin Hibbits if_t ifp; 71733253a37SGleb Smirnoff uint32_t i, filter; 718d2155f2fSWarner Losh 719d2155f2fSWarner Losh ifp = sc->sis_ifp; 720ed15702fSPyun YongHyeon filter = CSR_READ_4(sc, SIS_RXFILT_CTL); 721ed15702fSPyun YongHyeon if (filter & SIS_RXFILTCTL_ENABLE) { 722ed15702fSPyun YongHyeon /* 723ed15702fSPyun YongHyeon * Filter should be disabled to program other bits. 724ed15702fSPyun YongHyeon */ 725ed15702fSPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_CTL, filter & ~SIS_RXFILTCTL_ENABLE); 726ed15702fSPyun YongHyeon CSR_READ_4(sc, SIS_RXFILT_CTL); 727d2155f2fSWarner Losh } 728ed15702fSPyun YongHyeon filter &= ~(NS_RXFILTCTL_ARP | NS_RXFILTCTL_PERFECT | 729ed15702fSPyun YongHyeon NS_RXFILTCTL_MCHASH | SIS_RXFILTCTL_ALLPHYS | SIS_RXFILTCTL_BROAD | 730ed15702fSPyun YongHyeon SIS_RXFILTCTL_ALLMULTI); 731d2155f2fSWarner Losh 732*1125d093SJustin Hibbits if (if_getflags(ifp) & IFF_BROADCAST) 733ed15702fSPyun YongHyeon filter |= SIS_RXFILTCTL_BROAD; 734ed15702fSPyun YongHyeon /* 735ed15702fSPyun YongHyeon * For the NatSemi chip, we have to explicitly enable the 736ed15702fSPyun YongHyeon * reception of ARP frames, as well as turn on the 'perfect 737ed15702fSPyun YongHyeon * match' filter where we store the station address, otherwise 738ed15702fSPyun YongHyeon * we won't receive unicasts meant for this host. 739ed15702fSPyun YongHyeon */ 740ed15702fSPyun YongHyeon filter |= NS_RXFILTCTL_ARP | NS_RXFILTCTL_PERFECT; 741ed15702fSPyun YongHyeon 742*1125d093SJustin Hibbits if (if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) { 743ed15702fSPyun YongHyeon filter |= SIS_RXFILTCTL_ALLMULTI; 744*1125d093SJustin Hibbits if (if_getflags(ifp) & IFF_PROMISC) 745ed15702fSPyun YongHyeon filter |= SIS_RXFILTCTL_ALLPHYS; 746ed15702fSPyun YongHyeon } else { 747d2155f2fSWarner Losh /* 748d2155f2fSWarner Losh * We have to explicitly enable the multicast hash table 749d2155f2fSWarner Losh * on the NatSemi chip if we want to use it, which we do. 750d2155f2fSWarner Losh */ 751ed15702fSPyun YongHyeon filter |= NS_RXFILTCTL_MCHASH; 752d2155f2fSWarner Losh 753d2155f2fSWarner Losh /* first, zot all the existing hash bits */ 754d2155f2fSWarner Losh for (i = 0; i < 32; i++) { 755ed15702fSPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + 756ed15702fSPyun YongHyeon (i * 2)); 757d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0); 758d2155f2fSWarner Losh } 759d2155f2fSWarner Losh 76033253a37SGleb Smirnoff if_foreach_llmaddr(ifp, sis_write_maddr, sc); 761ed15702fSPyun YongHyeon } 762d2155f2fSWarner Losh 7638e5e2376SPyun YongHyeon /* Turn the receive filter on */ 7648e5e2376SPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_CTL, filter | SIS_RXFILTCTL_ENABLE); 765ed15702fSPyun YongHyeon CSR_READ_4(sc, SIS_RXFILT_CTL); 766d2155f2fSWarner Losh } 767d2155f2fSWarner Losh 76833253a37SGleb Smirnoff struct sis_hash_maddr_ctx { 76933253a37SGleb Smirnoff struct sis_softc *sc; 77033253a37SGleb Smirnoff uint16_t hashes[16]; 77133253a37SGleb Smirnoff }; 77233253a37SGleb Smirnoff 77333253a37SGleb Smirnoff static u_int 77433253a37SGleb Smirnoff sis_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 77533253a37SGleb Smirnoff { 77633253a37SGleb Smirnoff struct sis_hash_maddr_ctx *ctx = arg; 77733253a37SGleb Smirnoff uint32_t h; 77833253a37SGleb Smirnoff 77933253a37SGleb Smirnoff h = sis_mchash(ctx->sc, LLADDR(sdl)); 78033253a37SGleb Smirnoff ctx->hashes[h >> 4] |= 1 << (h & 0xf); 78133253a37SGleb Smirnoff 78233253a37SGleb Smirnoff return (1); 78333253a37SGleb Smirnoff } 78433253a37SGleb Smirnoff 785d2155f2fSWarner Losh static void 786ed15702fSPyun YongHyeon sis_rxfilter_sis(struct sis_softc *sc) 787d2155f2fSWarner Losh { 788*1125d093SJustin Hibbits if_t ifp; 78933253a37SGleb Smirnoff struct sis_hash_maddr_ctx ctx; 79033253a37SGleb Smirnoff uint32_t filter, i, n; 791d2155f2fSWarner Losh 792d2155f2fSWarner Losh ifp = sc->sis_ifp; 793d2155f2fSWarner Losh 794d2155f2fSWarner Losh /* hash table size */ 795ed15702fSPyun YongHyeon if (sc->sis_rev >= SIS_REV_635 || sc->sis_rev == SIS_REV_900B) 796d2155f2fSWarner Losh n = 16; 797d2155f2fSWarner Losh else 798d2155f2fSWarner Losh n = 8; 799d2155f2fSWarner Losh 800ed15702fSPyun YongHyeon filter = CSR_READ_4(sc, SIS_RXFILT_CTL); 801ed15702fSPyun YongHyeon if (filter & SIS_RXFILTCTL_ENABLE) { 802e01343ccSPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_CTL, filter & ~SIS_RXFILTCTL_ENABLE); 803ed15702fSPyun YongHyeon CSR_READ_4(sc, SIS_RXFILT_CTL); 804ed15702fSPyun YongHyeon } 805ed15702fSPyun YongHyeon filter &= ~(SIS_RXFILTCTL_ALLPHYS | SIS_RXFILTCTL_BROAD | 806ed15702fSPyun YongHyeon SIS_RXFILTCTL_ALLMULTI); 807*1125d093SJustin Hibbits if (if_getflags(ifp) & IFF_BROADCAST) 808ed15702fSPyun YongHyeon filter |= SIS_RXFILTCTL_BROAD; 809d2155f2fSWarner Losh 810*1125d093SJustin Hibbits if (if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) { 811ed15702fSPyun YongHyeon filter |= SIS_RXFILTCTL_ALLMULTI; 812*1125d093SJustin Hibbits if (if_getflags(ifp) & IFF_PROMISC) 813ed15702fSPyun YongHyeon filter |= SIS_RXFILTCTL_ALLPHYS; 814d2155f2fSWarner Losh for (i = 0; i < n; i++) 81533253a37SGleb Smirnoff ctx.hashes[i] = ~0; 816d2155f2fSWarner Losh } else { 817d2155f2fSWarner Losh for (i = 0; i < n; i++) 81833253a37SGleb Smirnoff ctx.hashes[i] = 0; 81933253a37SGleb Smirnoff ctx.sc = sc; 82033253a37SGleb Smirnoff if (if_foreach_llmaddr(ifp, sis_hash_maddr, &ctx) > n) { 821ed15702fSPyun YongHyeon filter |= SIS_RXFILTCTL_ALLMULTI; 822d2155f2fSWarner Losh for (i = 0; i < n; i++) 82333253a37SGleb Smirnoff ctx.hashes[i] = ~0; 824d2155f2fSWarner Losh } 825d2155f2fSWarner Losh } 826d2155f2fSWarner Losh 827d2155f2fSWarner Losh for (i = 0; i < n; i++) { 828d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + i) << 16); 82933253a37SGleb Smirnoff CSR_WRITE_4(sc, SIS_RXFILT_DATA, ctx.hashes[i]); 830d2155f2fSWarner Losh } 831d2155f2fSWarner Losh 8328e5e2376SPyun YongHyeon /* Turn the receive filter on */ 8338e5e2376SPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_CTL, filter | SIS_RXFILTCTL_ENABLE); 834ed15702fSPyun YongHyeon CSR_READ_4(sc, SIS_RXFILT_CTL); 835d2155f2fSWarner Losh } 836d2155f2fSWarner Losh 837d2155f2fSWarner Losh static void 838d2155f2fSWarner Losh sis_reset(struct sis_softc *sc) 839d2155f2fSWarner Losh { 840d2155f2fSWarner Losh int i; 841d2155f2fSWarner Losh 842d2155f2fSWarner Losh SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RESET); 843d2155f2fSWarner Losh 844d2155f2fSWarner Losh for (i = 0; i < SIS_TIMEOUT; i++) { 845d2155f2fSWarner Losh if (!(CSR_READ_4(sc, SIS_CSR) & SIS_CSR_RESET)) 846d2155f2fSWarner Losh break; 847d2155f2fSWarner Losh } 848d2155f2fSWarner Losh 849d2155f2fSWarner Losh if (i == SIS_TIMEOUT) 850d2155f2fSWarner Losh device_printf(sc->sis_dev, "reset never completed\n"); 851d2155f2fSWarner Losh 852d2155f2fSWarner Losh /* Wait a little while for the chip to get its brains in order. */ 853d2155f2fSWarner Losh DELAY(1000); 854d2155f2fSWarner Losh 855d2155f2fSWarner Losh /* 856d2155f2fSWarner Losh * If this is a NetSemi chip, make sure to clear 857d2155f2fSWarner Losh * PME mode. 858d2155f2fSWarner Losh */ 859d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_83815) { 860d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS); 861d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_CLKRUN, 0); 8620af3989bSPyun YongHyeon } else { 8630af3989bSPyun YongHyeon /* Disable WOL functions. */ 8640af3989bSPyun YongHyeon CSR_WRITE_4(sc, SIS_PWRMAN_CTL, 0); 865d2155f2fSWarner Losh } 866d2155f2fSWarner Losh } 867d2155f2fSWarner Losh 868d2155f2fSWarner Losh /* 869d2155f2fSWarner Losh * Probe for an SiS chip. Check the PCI vendor and device 870d2155f2fSWarner Losh * IDs against our list and return a device name if we find a match. 871d2155f2fSWarner Losh */ 872d2155f2fSWarner Losh static int 873d2155f2fSWarner Losh sis_probe(device_t dev) 874d2155f2fSWarner Losh { 8758c1093fcSMarius Strobl const struct sis_type *t; 876d2155f2fSWarner Losh 877d2155f2fSWarner Losh t = sis_devs; 878d2155f2fSWarner Losh 879d2155f2fSWarner Losh while (t->sis_name != NULL) { 880d2155f2fSWarner Losh if ((pci_get_vendor(dev) == t->sis_vid) && 881d2155f2fSWarner Losh (pci_get_device(dev) == t->sis_did)) { 882d2155f2fSWarner Losh device_set_desc(dev, t->sis_name); 883d2155f2fSWarner Losh return (BUS_PROBE_DEFAULT); 884d2155f2fSWarner Losh } 885d2155f2fSWarner Losh t++; 886d2155f2fSWarner Losh } 887d2155f2fSWarner Losh 888d2155f2fSWarner Losh return (ENXIO); 889d2155f2fSWarner Losh } 890d2155f2fSWarner Losh 891d2155f2fSWarner Losh /* 892d2155f2fSWarner Losh * Attach the interface. Allocate softc structures, do ifmedia 893d2155f2fSWarner Losh * setup and ethernet/BPF attach. 894d2155f2fSWarner Losh */ 895d2155f2fSWarner Losh static int 896d2155f2fSWarner Losh sis_attach(device_t dev) 897d2155f2fSWarner Losh { 898d2155f2fSWarner Losh u_char eaddr[ETHER_ADDR_LEN]; 899d2155f2fSWarner Losh struct sis_softc *sc; 900*1125d093SJustin Hibbits if_t ifp; 901c9439e23SWarner Losh int error = 0, pmc; 902d2155f2fSWarner Losh 903d2155f2fSWarner Losh sc = device_get_softc(dev); 904d2155f2fSWarner Losh 905d2155f2fSWarner Losh sc->sis_dev = dev; 906d2155f2fSWarner Losh 907d2155f2fSWarner Losh mtx_init(&sc->sis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 908d2155f2fSWarner Losh MTX_DEF); 909d2155f2fSWarner Losh callout_init_mtx(&sc->sis_stat_ch, &sc->sis_mtx, 0); 910d2155f2fSWarner Losh 911d2155f2fSWarner Losh if (pci_get_device(dev) == SIS_DEVICEID_900) 912d2155f2fSWarner Losh sc->sis_type = SIS_TYPE_900; 913d2155f2fSWarner Losh if (pci_get_device(dev) == SIS_DEVICEID_7016) 914d2155f2fSWarner Losh sc->sis_type = SIS_TYPE_7016; 915d2155f2fSWarner Losh if (pci_get_vendor(dev) == NS_VENDORID) 916d2155f2fSWarner Losh sc->sis_type = SIS_TYPE_83815; 917d2155f2fSWarner Losh 918d2155f2fSWarner Losh sc->sis_rev = pci_read_config(dev, PCIR_REVID, 1); 919d2155f2fSWarner Losh /* 920d2155f2fSWarner Losh * Map control/status registers. 921d2155f2fSWarner Losh */ 922d2155f2fSWarner Losh pci_enable_busmaster(dev); 923d2155f2fSWarner Losh 924d2155f2fSWarner Losh error = bus_alloc_resources(dev, sis_res_spec, sc->sis_res); 925d2155f2fSWarner Losh if (error) { 926d2155f2fSWarner Losh device_printf(dev, "couldn't allocate resources\n"); 927d2155f2fSWarner Losh goto fail; 928d2155f2fSWarner Losh } 929d2155f2fSWarner Losh 930d2155f2fSWarner Losh /* Reset the adapter. */ 931d2155f2fSWarner Losh sis_reset(sc); 932d2155f2fSWarner Losh 933d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_900 && 934d2155f2fSWarner Losh (sc->sis_rev == SIS_REV_635 || 935d2155f2fSWarner Losh sc->sis_rev == SIS_REV_900B)) { 936d2155f2fSWarner Losh SIO_SET(SIS_CFG_RND_CNT); 937d2155f2fSWarner Losh SIO_SET(SIS_CFG_PERR_DETECT); 938d2155f2fSWarner Losh } 939d2155f2fSWarner Losh 940d2155f2fSWarner Losh /* 941d2155f2fSWarner Losh * Get station address from the EEPROM. 942d2155f2fSWarner Losh */ 943d2155f2fSWarner Losh switch (pci_get_vendor(dev)) { 944d2155f2fSWarner Losh case NS_VENDORID: 945d2155f2fSWarner Losh sc->sis_srr = CSR_READ_4(sc, NS_SRR); 946d2155f2fSWarner Losh 947d2155f2fSWarner Losh /* We can't update the device description, so spew */ 948d2155f2fSWarner Losh if (sc->sis_srr == NS_SRR_15C) 949d2155f2fSWarner Losh device_printf(dev, "Silicon Revision: DP83815C\n"); 950d2155f2fSWarner Losh else if (sc->sis_srr == NS_SRR_15D) 951d2155f2fSWarner Losh device_printf(dev, "Silicon Revision: DP83815D\n"); 952d2155f2fSWarner Losh else if (sc->sis_srr == NS_SRR_16A) 953d2155f2fSWarner Losh device_printf(dev, "Silicon Revision: DP83816A\n"); 954d2155f2fSWarner Losh else 955d2155f2fSWarner Losh device_printf(dev, "Silicon Revision %x\n", sc->sis_srr); 956d2155f2fSWarner Losh 957d2155f2fSWarner Losh /* 958d2155f2fSWarner Losh * Reading the MAC address out of the EEPROM on 959d2155f2fSWarner Losh * the NatSemi chip takes a bit more work than 960d2155f2fSWarner Losh * you'd expect. The address spans 4 16-bit words, 961d2155f2fSWarner Losh * with the first word containing only a single bit. 962d2155f2fSWarner Losh * You have to shift everything over one bit to 963d2155f2fSWarner Losh * get it aligned properly. Also, the bits are 964d2155f2fSWarner Losh * stored backwards (the LSB is really the MSB, 965d2155f2fSWarner Losh * and so on) so you have to reverse them in order 966d2155f2fSWarner Losh * to get the MAC address into the form we want. 967d2155f2fSWarner Losh * Why? Who the hell knows. 968d2155f2fSWarner Losh */ 969d2155f2fSWarner Losh { 97091c265b8SPyun YongHyeon uint16_t tmp[4]; 971d2155f2fSWarner Losh 972d2155f2fSWarner Losh sis_read_eeprom(sc, (caddr_t)&tmp, 973d2155f2fSWarner Losh NS_EE_NODEADDR, 4, 0); 974d2155f2fSWarner Losh 975d2155f2fSWarner Losh /* Shift everything over one bit. */ 976d2155f2fSWarner Losh tmp[3] = tmp[3] >> 1; 977d2155f2fSWarner Losh tmp[3] |= tmp[2] << 15; 978d2155f2fSWarner Losh tmp[2] = tmp[2] >> 1; 979d2155f2fSWarner Losh tmp[2] |= tmp[1] << 15; 980d2155f2fSWarner Losh tmp[1] = tmp[1] >> 1; 981d2155f2fSWarner Losh tmp[1] |= tmp[0] << 15; 982d2155f2fSWarner Losh 983d2155f2fSWarner Losh /* Now reverse all the bits. */ 984d2155f2fSWarner Losh tmp[3] = sis_reverse(tmp[3]); 985d2155f2fSWarner Losh tmp[2] = sis_reverse(tmp[2]); 986d2155f2fSWarner Losh tmp[1] = sis_reverse(tmp[1]); 987d2155f2fSWarner Losh 98874e8a323SPyun YongHyeon eaddr[0] = (tmp[1] >> 0) & 0xFF; 98974e8a323SPyun YongHyeon eaddr[1] = (tmp[1] >> 8) & 0xFF; 99074e8a323SPyun YongHyeon eaddr[2] = (tmp[2] >> 0) & 0xFF; 99174e8a323SPyun YongHyeon eaddr[3] = (tmp[2] >> 8) & 0xFF; 99274e8a323SPyun YongHyeon eaddr[4] = (tmp[3] >> 0) & 0xFF; 99374e8a323SPyun YongHyeon eaddr[5] = (tmp[3] >> 8) & 0xFF; 994d2155f2fSWarner Losh } 995d2155f2fSWarner Losh break; 996d2155f2fSWarner Losh case SIS_VENDORID: 997d2155f2fSWarner Losh default: 998d2155f2fSWarner Losh #if defined(__i386__) || defined(__amd64__) 999d2155f2fSWarner Losh /* 1000d2155f2fSWarner Losh * If this is a SiS 630E chipset with an embedded 1001d2155f2fSWarner Losh * SiS 900 controller, we have to read the MAC address 1002d2155f2fSWarner Losh * from the APC CMOS RAM. Our method for doing this 1003d2155f2fSWarner Losh * is very ugly since we have to reach out and grab 1004d2155f2fSWarner Losh * ahold of hardware for which we cannot properly 1005d2155f2fSWarner Losh * allocate resources. This code is only compiled on 1006d2155f2fSWarner Losh * the i386 architecture since the SiS 630E chipset 1007d2155f2fSWarner Losh * is for x86 motherboards only. Note that there are 1008d2155f2fSWarner Losh * a lot of magic numbers in this hack. These are 1009d2155f2fSWarner Losh * taken from SiS's Linux driver. I'd like to replace 1010d2155f2fSWarner Losh * them with proper symbolic definitions, but that 1011d2155f2fSWarner Losh * requires some datasheets that I don't have access 1012d2155f2fSWarner Losh * to at the moment. 1013d2155f2fSWarner Losh */ 1014d2155f2fSWarner Losh if (sc->sis_rev == SIS_REV_630S || 1015d2155f2fSWarner Losh sc->sis_rev == SIS_REV_630E || 1016d2155f2fSWarner Losh sc->sis_rev == SIS_REV_630EA1) 1017d2155f2fSWarner Losh sis_read_cmos(sc, dev, (caddr_t)&eaddr, 0x9, 6); 1018d2155f2fSWarner Losh 1019d2155f2fSWarner Losh else if (sc->sis_rev == SIS_REV_635 || 1020d2155f2fSWarner Losh sc->sis_rev == SIS_REV_630ET) 1021d2155f2fSWarner Losh sis_read_mac(sc, dev, (caddr_t)&eaddr); 1022d2155f2fSWarner Losh else if (sc->sis_rev == SIS_REV_96x) { 1023d2155f2fSWarner Losh /* Allow to read EEPROM from LAN. It is shared 1024d2155f2fSWarner Losh * between a 1394 controller and the NIC and each 1025d2155f2fSWarner Losh * time we access it, we need to set SIS_EECMD_REQ. 1026d2155f2fSWarner Losh */ 1027d2155f2fSWarner Losh SIO_SET(SIS_EECMD_REQ); 1028c9439e23SWarner Losh for (int waittime = 0; waittime < SIS_TIMEOUT; 1029d2155f2fSWarner Losh waittime++) { 1030d2155f2fSWarner Losh /* Force EEPROM to idle state. */ 1031d2155f2fSWarner Losh sis_eeprom_idle(sc); 1032d2155f2fSWarner Losh if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECMD_GNT) { 1033d2155f2fSWarner Losh sis_read_eeprom(sc, (caddr_t)&eaddr, 1034d2155f2fSWarner Losh SIS_EE_NODEADDR, 3, 0); 1035d2155f2fSWarner Losh break; 1036d2155f2fSWarner Losh } 1037d2155f2fSWarner Losh DELAY(1); 1038d2155f2fSWarner Losh } 1039d2155f2fSWarner Losh /* 1040d2155f2fSWarner Losh * Set SIS_EECTL_CLK to high, so a other master 1041d2155f2fSWarner Losh * can operate on the i2c bus. 1042d2155f2fSWarner Losh */ 1043d2155f2fSWarner Losh SIO_SET(SIS_EECTL_CLK); 1044d2155f2fSWarner Losh /* Refuse EEPROM access by LAN */ 1045d2155f2fSWarner Losh SIO_SET(SIS_EECMD_DONE); 1046d2155f2fSWarner Losh } else 1047d2155f2fSWarner Losh #endif 1048d2155f2fSWarner Losh sis_read_eeprom(sc, (caddr_t)&eaddr, 1049d2155f2fSWarner Losh SIS_EE_NODEADDR, 3, 0); 1050d2155f2fSWarner Losh break; 1051d2155f2fSWarner Losh } 1052d2155f2fSWarner Losh 105394222398SPyun YongHyeon sis_add_sysctls(sc); 105494222398SPyun YongHyeon 1055a629f2b1SPyun YongHyeon /* Allocate DMA'able memory. */ 1056a629f2b1SPyun YongHyeon if ((error = sis_dma_alloc(sc)) != 0) 1057d2155f2fSWarner Losh goto fail; 1058d2155f2fSWarner Losh 1059d2155f2fSWarner Losh ifp = sc->sis_ifp = if_alloc(IFT_ETHER); 1060*1125d093SJustin Hibbits if_setsoftc(ifp, sc); 1061d2155f2fSWarner Losh if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1062*1125d093SJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 1063*1125d093SJustin Hibbits if_setioctlfn(ifp, sis_ioctl); 1064*1125d093SJustin Hibbits if_setstartfn(ifp, sis_start); 1065*1125d093SJustin Hibbits if_setinitfn(ifp, sis_init); 1066*1125d093SJustin Hibbits if_setsendqlen(ifp, SIS_TX_LIST_CNT - 1); 1067*1125d093SJustin Hibbits if_setsendqready(ifp); 1068d2155f2fSWarner Losh 10693b0a4aefSJohn Baldwin if (pci_find_cap(sc->sis_dev, PCIY_PMG, &pmc) == 0) { 10700af3989bSPyun YongHyeon if (sc->sis_type == SIS_TYPE_83815) 1071*1125d093SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_WOL, 0); 10720af3989bSPyun YongHyeon else 1073*1125d093SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_WOL_MAGIC, 0); 1074*1125d093SJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp)); 10750af3989bSPyun YongHyeon } 10760af3989bSPyun YongHyeon 1077d2155f2fSWarner Losh /* 1078d2155f2fSWarner Losh * Do MII setup. 1079d2155f2fSWarner Losh */ 1080d6c65d27SMarius Strobl error = mii_attach(dev, &sc->sis_miibus, ifp, sis_ifmedia_upd, 1081d6c65d27SMarius Strobl sis_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); 1082d6c65d27SMarius Strobl if (error != 0) { 1083d6c65d27SMarius Strobl device_printf(dev, "attaching PHYs failed\n"); 1084d2155f2fSWarner Losh goto fail; 1085d2155f2fSWarner Losh } 1086d2155f2fSWarner Losh 1087d2155f2fSWarner Losh /* 1088d2155f2fSWarner Losh * Call MI attach routine. 1089d2155f2fSWarner Losh */ 1090d2155f2fSWarner Losh ether_ifattach(ifp, eaddr); 1091d2155f2fSWarner Losh 1092d2155f2fSWarner Losh /* 1093d2155f2fSWarner Losh * Tell the upper layer(s) we support long frames. 1094d2155f2fSWarner Losh */ 1095*1125d093SJustin Hibbits if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); 1096*1125d093SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0); 1097*1125d093SJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp)); 1098d2155f2fSWarner Losh #ifdef DEVICE_POLLING 1099*1125d093SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_POLLING, 0); 1100d2155f2fSWarner Losh #endif 1101d2155f2fSWarner Losh 1102d2155f2fSWarner Losh /* Hook interrupt last to avoid having to lock softc */ 1103d2155f2fSWarner Losh error = bus_setup_intr(dev, sc->sis_res[1], INTR_TYPE_NET | INTR_MPSAFE, 1104d2155f2fSWarner Losh NULL, sis_intr, sc, &sc->sis_intrhand); 1105d2155f2fSWarner Losh 1106d2155f2fSWarner Losh if (error) { 1107d2155f2fSWarner Losh device_printf(dev, "couldn't set up irq\n"); 1108d2155f2fSWarner Losh ether_ifdetach(ifp); 1109d2155f2fSWarner Losh goto fail; 1110d2155f2fSWarner Losh } 1111d2155f2fSWarner Losh 1112d2155f2fSWarner Losh fail: 1113d2155f2fSWarner Losh if (error) 1114d2155f2fSWarner Losh sis_detach(dev); 1115d2155f2fSWarner Losh 1116d2155f2fSWarner Losh return (error); 1117d2155f2fSWarner Losh } 1118d2155f2fSWarner Losh 1119d2155f2fSWarner Losh /* 1120d2155f2fSWarner Losh * Shutdown hardware and free up resources. This can be called any 1121d2155f2fSWarner Losh * time after the mutex has been initialized. It is called in both 1122d2155f2fSWarner Losh * the error case in attach and the normal detach case so it needs 1123d2155f2fSWarner Losh * to be careful about only freeing resources that have actually been 1124d2155f2fSWarner Losh * allocated. 1125d2155f2fSWarner Losh */ 1126d2155f2fSWarner Losh static int 1127d2155f2fSWarner Losh sis_detach(device_t dev) 1128d2155f2fSWarner Losh { 1129d2155f2fSWarner Losh struct sis_softc *sc; 1130*1125d093SJustin Hibbits if_t ifp; 1131d2155f2fSWarner Losh 1132d2155f2fSWarner Losh sc = device_get_softc(dev); 1133d2155f2fSWarner Losh KASSERT(mtx_initialized(&sc->sis_mtx), ("sis mutex not initialized")); 1134d2155f2fSWarner Losh ifp = sc->sis_ifp; 1135d2155f2fSWarner Losh 1136d2155f2fSWarner Losh #ifdef DEVICE_POLLING 1137*1125d093SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_POLLING) 1138d2155f2fSWarner Losh ether_poll_deregister(ifp); 1139d2155f2fSWarner Losh #endif 1140d2155f2fSWarner Losh 1141d2155f2fSWarner Losh /* These should only be active if attach succeeded. */ 1142d2155f2fSWarner Losh if (device_is_attached(dev)) { 1143d2155f2fSWarner Losh SIS_LOCK(sc); 1144d2155f2fSWarner Losh sis_stop(sc); 1145d2155f2fSWarner Losh SIS_UNLOCK(sc); 1146d2155f2fSWarner Losh callout_drain(&sc->sis_stat_ch); 1147d2155f2fSWarner Losh ether_ifdetach(ifp); 1148d2155f2fSWarner Losh } 1149d2155f2fSWarner Losh bus_generic_detach(dev); 1150d2155f2fSWarner Losh 1151d2155f2fSWarner Losh if (sc->sis_intrhand) 1152d2155f2fSWarner Losh bus_teardown_intr(dev, sc->sis_res[1], sc->sis_intrhand); 1153d2155f2fSWarner Losh bus_release_resources(dev, sis_res_spec, sc->sis_res); 1154d2155f2fSWarner Losh 1155d2155f2fSWarner Losh if (ifp) 1156d2155f2fSWarner Losh if_free(ifp); 1157d2155f2fSWarner Losh 1158a629f2b1SPyun YongHyeon sis_dma_free(sc); 1159d2155f2fSWarner Losh 1160d2155f2fSWarner Losh mtx_destroy(&sc->sis_mtx); 1161d2155f2fSWarner Losh 1162d2155f2fSWarner Losh return (0); 1163d2155f2fSWarner Losh } 1164d2155f2fSWarner Losh 1165a629f2b1SPyun YongHyeon struct sis_dmamap_arg { 1166a629f2b1SPyun YongHyeon bus_addr_t sis_busaddr; 1167a629f2b1SPyun YongHyeon }; 1168a629f2b1SPyun YongHyeon 1169a629f2b1SPyun YongHyeon static void 1170a629f2b1SPyun YongHyeon sis_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 1171a629f2b1SPyun YongHyeon { 1172a629f2b1SPyun YongHyeon struct sis_dmamap_arg *ctx; 1173a629f2b1SPyun YongHyeon 1174a629f2b1SPyun YongHyeon if (error != 0) 1175a629f2b1SPyun YongHyeon return; 1176a629f2b1SPyun YongHyeon 1177a629f2b1SPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1178a629f2b1SPyun YongHyeon 1179a629f2b1SPyun YongHyeon ctx = (struct sis_dmamap_arg *)arg; 1180a629f2b1SPyun YongHyeon ctx->sis_busaddr = segs[0].ds_addr; 1181a629f2b1SPyun YongHyeon } 1182a629f2b1SPyun YongHyeon 1183a629f2b1SPyun YongHyeon static int 1184a629f2b1SPyun YongHyeon sis_dma_ring_alloc(struct sis_softc *sc, bus_size_t alignment, 1185a629f2b1SPyun YongHyeon bus_size_t maxsize, bus_dma_tag_t *tag, uint8_t **ring, bus_dmamap_t *map, 1186a629f2b1SPyun YongHyeon bus_addr_t *paddr, const char *msg) 1187a629f2b1SPyun YongHyeon { 1188a629f2b1SPyun YongHyeon struct sis_dmamap_arg ctx; 1189a629f2b1SPyun YongHyeon int error; 1190a629f2b1SPyun YongHyeon 1191a629f2b1SPyun YongHyeon error = bus_dma_tag_create(sc->sis_parent_tag, alignment, 0, 1192a629f2b1SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, maxsize, 1, 1193a629f2b1SPyun YongHyeon maxsize, 0, NULL, NULL, tag); 1194a629f2b1SPyun YongHyeon if (error != 0) { 1195a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, 1196a629f2b1SPyun YongHyeon "could not create %s dma tag\n", msg); 1197a629f2b1SPyun YongHyeon return (ENOMEM); 1198a629f2b1SPyun YongHyeon } 1199a629f2b1SPyun YongHyeon /* Allocate DMA'able memory for ring. */ 1200a629f2b1SPyun YongHyeon error = bus_dmamem_alloc(*tag, (void **)ring, 1201a629f2b1SPyun YongHyeon BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, map); 1202a629f2b1SPyun YongHyeon if (error != 0) { 1203a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, 1204a629f2b1SPyun YongHyeon "could not allocate DMA'able memory for %s\n", msg); 1205a629f2b1SPyun YongHyeon return (ENOMEM); 1206a629f2b1SPyun YongHyeon } 1207a629f2b1SPyun YongHyeon /* Load the address of the ring. */ 1208a629f2b1SPyun YongHyeon ctx.sis_busaddr = 0; 1209a629f2b1SPyun YongHyeon error = bus_dmamap_load(*tag, *map, *ring, maxsize, sis_dmamap_cb, 1210a629f2b1SPyun YongHyeon &ctx, BUS_DMA_NOWAIT); 1211a629f2b1SPyun YongHyeon if (error != 0) { 1212a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, 1213a629f2b1SPyun YongHyeon "could not load DMA'able memory for %s\n", msg); 1214a629f2b1SPyun YongHyeon return (ENOMEM); 1215a629f2b1SPyun YongHyeon } 1216a629f2b1SPyun YongHyeon *paddr = ctx.sis_busaddr; 1217a629f2b1SPyun YongHyeon return (0); 1218a629f2b1SPyun YongHyeon } 1219a629f2b1SPyun YongHyeon 1220a629f2b1SPyun YongHyeon static int 1221a629f2b1SPyun YongHyeon sis_dma_alloc(struct sis_softc *sc) 1222a629f2b1SPyun YongHyeon { 1223a629f2b1SPyun YongHyeon struct sis_rxdesc *rxd; 1224a629f2b1SPyun YongHyeon struct sis_txdesc *txd; 1225a629f2b1SPyun YongHyeon int error, i; 1226a629f2b1SPyun YongHyeon 1227a629f2b1SPyun YongHyeon /* Allocate the parent bus DMA tag appropriate for PCI. */ 1228a629f2b1SPyun YongHyeon error = bus_dma_tag_create(bus_get_dma_tag(sc->sis_dev), 1229a629f2b1SPyun YongHyeon 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1230a629f2b1SPyun YongHyeon NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 1231a629f2b1SPyun YongHyeon 0, NULL, NULL, &sc->sis_parent_tag); 1232a629f2b1SPyun YongHyeon if (error != 0) { 1233a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, 1234a629f2b1SPyun YongHyeon "could not allocate parent dma tag\n"); 1235a629f2b1SPyun YongHyeon return (ENOMEM); 1236a629f2b1SPyun YongHyeon } 1237a629f2b1SPyun YongHyeon 1238a629f2b1SPyun YongHyeon /* Create RX ring. */ 1239a629f2b1SPyun YongHyeon error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_RX_LIST_SZ, 1240a629f2b1SPyun YongHyeon &sc->sis_rx_list_tag, (uint8_t **)&sc->sis_rx_list, 1241a629f2b1SPyun YongHyeon &sc->sis_rx_list_map, &sc->sis_rx_paddr, "RX ring"); 1242a629f2b1SPyun YongHyeon if (error) 1243a629f2b1SPyun YongHyeon return (error); 1244a629f2b1SPyun YongHyeon 1245a629f2b1SPyun YongHyeon /* Create TX ring. */ 1246a629f2b1SPyun YongHyeon error = sis_dma_ring_alloc(sc, SIS_DESC_ALIGN, SIS_TX_LIST_SZ, 1247a629f2b1SPyun YongHyeon &sc->sis_tx_list_tag, (uint8_t **)&sc->sis_tx_list, 1248a629f2b1SPyun YongHyeon &sc->sis_tx_list_map, &sc->sis_tx_paddr, "TX ring"); 1249a629f2b1SPyun YongHyeon if (error) 1250a629f2b1SPyun YongHyeon return (error); 1251a629f2b1SPyun YongHyeon 1252a629f2b1SPyun YongHyeon /* Create tag for RX mbufs. */ 1253a629f2b1SPyun YongHyeon error = bus_dma_tag_create(sc->sis_parent_tag, SIS_RX_BUF_ALIGN, 0, 1254a629f2b1SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, 1255a629f2b1SPyun YongHyeon MCLBYTES, 0, NULL, NULL, &sc->sis_rx_tag); 1256a629f2b1SPyun YongHyeon if (error) { 1257a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, "could not allocate RX dma tag\n"); 1258a629f2b1SPyun YongHyeon return (error); 1259a629f2b1SPyun YongHyeon } 1260a629f2b1SPyun YongHyeon 1261a629f2b1SPyun YongHyeon /* Create tag for TX mbufs. */ 1262a629f2b1SPyun YongHyeon error = bus_dma_tag_create(sc->sis_parent_tag, 1, 0, 1263a629f2b1SPyun YongHyeon BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 1264a629f2b1SPyun YongHyeon MCLBYTES * SIS_MAXTXSEGS, SIS_MAXTXSEGS, MCLBYTES, 0, NULL, NULL, 1265a629f2b1SPyun YongHyeon &sc->sis_tx_tag); 1266a629f2b1SPyun YongHyeon if (error) { 1267a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, "could not allocate TX dma tag\n"); 1268a629f2b1SPyun YongHyeon return (error); 1269a629f2b1SPyun YongHyeon } 1270a629f2b1SPyun YongHyeon 1271a629f2b1SPyun YongHyeon /* Create DMA maps for RX buffers. */ 1272a629f2b1SPyun YongHyeon error = bus_dmamap_create(sc->sis_rx_tag, 0, &sc->sis_rx_sparemap); 1273a629f2b1SPyun YongHyeon if (error) { 1274a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, 1275a629f2b1SPyun YongHyeon "can't create spare DMA map for RX\n"); 1276a629f2b1SPyun YongHyeon return (error); 1277a629f2b1SPyun YongHyeon } 1278a629f2b1SPyun YongHyeon for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1279a629f2b1SPyun YongHyeon rxd = &sc->sis_rxdesc[i]; 1280a629f2b1SPyun YongHyeon rxd->rx_m = NULL; 1281a629f2b1SPyun YongHyeon error = bus_dmamap_create(sc->sis_rx_tag, 0, &rxd->rx_dmamap); 1282a629f2b1SPyun YongHyeon if (error) { 1283a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, 1284a629f2b1SPyun YongHyeon "can't create DMA map for RX\n"); 1285a629f2b1SPyun YongHyeon return (error); 1286a629f2b1SPyun YongHyeon } 1287a629f2b1SPyun YongHyeon } 1288a629f2b1SPyun YongHyeon 1289a629f2b1SPyun YongHyeon /* Create DMA maps for TX buffers. */ 1290a629f2b1SPyun YongHyeon for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1291a629f2b1SPyun YongHyeon txd = &sc->sis_txdesc[i]; 1292a629f2b1SPyun YongHyeon txd->tx_m = NULL; 1293a629f2b1SPyun YongHyeon error = bus_dmamap_create(sc->sis_tx_tag, 0, &txd->tx_dmamap); 1294a629f2b1SPyun YongHyeon if (error) { 1295a629f2b1SPyun YongHyeon device_printf(sc->sis_dev, 1296a629f2b1SPyun YongHyeon "can't create DMA map for TX\n"); 1297a629f2b1SPyun YongHyeon return (error); 1298a629f2b1SPyun YongHyeon } 1299a629f2b1SPyun YongHyeon } 1300a629f2b1SPyun YongHyeon 1301a629f2b1SPyun YongHyeon return (0); 1302a629f2b1SPyun YongHyeon } 1303a629f2b1SPyun YongHyeon 1304a629f2b1SPyun YongHyeon static void 1305a629f2b1SPyun YongHyeon sis_dma_free(struct sis_softc *sc) 1306a629f2b1SPyun YongHyeon { 1307a629f2b1SPyun YongHyeon struct sis_rxdesc *rxd; 1308a629f2b1SPyun YongHyeon struct sis_txdesc *txd; 1309a629f2b1SPyun YongHyeon int i; 1310a629f2b1SPyun YongHyeon 1311a629f2b1SPyun YongHyeon /* Destroy DMA maps for RX buffers. */ 1312a629f2b1SPyun YongHyeon for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1313a629f2b1SPyun YongHyeon rxd = &sc->sis_rxdesc[i]; 1314a629f2b1SPyun YongHyeon if (rxd->rx_dmamap) 1315a629f2b1SPyun YongHyeon bus_dmamap_destroy(sc->sis_rx_tag, rxd->rx_dmamap); 1316a629f2b1SPyun YongHyeon } 1317a629f2b1SPyun YongHyeon if (sc->sis_rx_sparemap) 1318a629f2b1SPyun YongHyeon bus_dmamap_destroy(sc->sis_rx_tag, sc->sis_rx_sparemap); 1319a629f2b1SPyun YongHyeon 1320a629f2b1SPyun YongHyeon /* Destroy DMA maps for TX buffers. */ 1321a629f2b1SPyun YongHyeon for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1322a629f2b1SPyun YongHyeon txd = &sc->sis_txdesc[i]; 1323a629f2b1SPyun YongHyeon if (txd->tx_dmamap) 1324a629f2b1SPyun YongHyeon bus_dmamap_destroy(sc->sis_tx_tag, txd->tx_dmamap); 1325a629f2b1SPyun YongHyeon } 1326a629f2b1SPyun YongHyeon 1327a629f2b1SPyun YongHyeon if (sc->sis_rx_tag) 1328a629f2b1SPyun YongHyeon bus_dma_tag_destroy(sc->sis_rx_tag); 1329a629f2b1SPyun YongHyeon if (sc->sis_tx_tag) 1330a629f2b1SPyun YongHyeon bus_dma_tag_destroy(sc->sis_tx_tag); 1331a629f2b1SPyun YongHyeon 1332a629f2b1SPyun YongHyeon /* Destroy RX ring. */ 1333068d8643SJohn Baldwin if (sc->sis_rx_paddr) 1334a629f2b1SPyun YongHyeon bus_dmamap_unload(sc->sis_rx_list_tag, sc->sis_rx_list_map); 1335068d8643SJohn Baldwin if (sc->sis_rx_list) 1336a629f2b1SPyun YongHyeon bus_dmamem_free(sc->sis_rx_list_tag, sc->sis_rx_list, 1337a629f2b1SPyun YongHyeon sc->sis_rx_list_map); 1338a629f2b1SPyun YongHyeon 1339a629f2b1SPyun YongHyeon if (sc->sis_rx_list_tag) 1340a629f2b1SPyun YongHyeon bus_dma_tag_destroy(sc->sis_rx_list_tag); 1341a629f2b1SPyun YongHyeon 1342a629f2b1SPyun YongHyeon /* Destroy TX ring. */ 1343068d8643SJohn Baldwin if (sc->sis_tx_paddr) 1344a629f2b1SPyun YongHyeon bus_dmamap_unload(sc->sis_tx_list_tag, sc->sis_tx_list_map); 1345a629f2b1SPyun YongHyeon 1346068d8643SJohn Baldwin if (sc->sis_tx_list) 1347a629f2b1SPyun YongHyeon bus_dmamem_free(sc->sis_tx_list_tag, sc->sis_tx_list, 1348a629f2b1SPyun YongHyeon sc->sis_tx_list_map); 1349a629f2b1SPyun YongHyeon 1350a629f2b1SPyun YongHyeon if (sc->sis_tx_list_tag) 1351a629f2b1SPyun YongHyeon bus_dma_tag_destroy(sc->sis_tx_list_tag); 1352a629f2b1SPyun YongHyeon 1353a629f2b1SPyun YongHyeon /* Destroy the parent tag. */ 1354a629f2b1SPyun YongHyeon if (sc->sis_parent_tag) 1355a629f2b1SPyun YongHyeon bus_dma_tag_destroy(sc->sis_parent_tag); 1356a629f2b1SPyun YongHyeon } 1357a629f2b1SPyun YongHyeon 1358d2155f2fSWarner Losh /* 1359d2155f2fSWarner Losh * Initialize the TX and RX descriptors and allocate mbufs for them. Note that 1360d2155f2fSWarner Losh * we arrange the descriptors in a closed ring, so that the last descriptor 1361d2155f2fSWarner Losh * points back to the first. 1362d2155f2fSWarner Losh */ 1363d2155f2fSWarner Losh static int 1364d2155f2fSWarner Losh sis_ring_init(struct sis_softc *sc) 1365d2155f2fSWarner Losh { 1366a629f2b1SPyun YongHyeon struct sis_rxdesc *rxd; 1367a629f2b1SPyun YongHyeon struct sis_txdesc *txd; 1368a629f2b1SPyun YongHyeon bus_addr_t next; 1369a629f2b1SPyun YongHyeon int error, i; 1370d2155f2fSWarner Losh 1371a629f2b1SPyun YongHyeon bzero(&sc->sis_tx_list[0], SIS_TX_LIST_SZ); 1372a629f2b1SPyun YongHyeon for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1373a629f2b1SPyun YongHyeon txd = &sc->sis_txdesc[i]; 1374a629f2b1SPyun YongHyeon txd->tx_m = NULL; 1375a629f2b1SPyun YongHyeon if (i == SIS_TX_LIST_CNT - 1) 1376a629f2b1SPyun YongHyeon next = SIS_TX_RING_ADDR(sc, 0); 1377d2155f2fSWarner Losh else 1378a629f2b1SPyun YongHyeon next = SIS_TX_RING_ADDR(sc, i + 1); 1379a629f2b1SPyun YongHyeon sc->sis_tx_list[i].sis_next = htole32(SIS_ADDR_LO(next)); 1380d2155f2fSWarner Losh } 1381d2155f2fSWarner Losh sc->sis_tx_prod = sc->sis_tx_cons = sc->sis_tx_cnt = 0; 1382a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1383a629f2b1SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1384d2155f2fSWarner Losh 1385a629f2b1SPyun YongHyeon sc->sis_rx_cons = 0; 1386a629f2b1SPyun YongHyeon bzero(&sc->sis_rx_list[0], SIS_RX_LIST_SZ); 1387a629f2b1SPyun YongHyeon for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1388a629f2b1SPyun YongHyeon rxd = &sc->sis_rxdesc[i]; 1389a629f2b1SPyun YongHyeon rxd->rx_desc = &sc->sis_rx_list[i]; 1390a629f2b1SPyun YongHyeon if (i == SIS_RX_LIST_CNT - 1) 1391a629f2b1SPyun YongHyeon next = SIS_RX_RING_ADDR(sc, 0); 1392a629f2b1SPyun YongHyeon else 1393a629f2b1SPyun YongHyeon next = SIS_RX_RING_ADDR(sc, i + 1); 1394a629f2b1SPyun YongHyeon rxd->rx_desc->sis_next = htole32(SIS_ADDR_LO(next)); 1395a629f2b1SPyun YongHyeon error = sis_newbuf(sc, rxd); 1396d2155f2fSWarner Losh if (error) 1397d2155f2fSWarner Losh return (error); 1398d2155f2fSWarner Losh } 1399a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1400a629f2b1SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1401d2155f2fSWarner Losh 1402d2155f2fSWarner Losh return (0); 1403d2155f2fSWarner Losh } 1404d2155f2fSWarner Losh 1405d2155f2fSWarner Losh /* 1406d2155f2fSWarner Losh * Initialize an RX descriptor and attach an MBUF cluster. 1407d2155f2fSWarner Losh */ 1408d2155f2fSWarner Losh static int 1409a629f2b1SPyun YongHyeon sis_newbuf(struct sis_softc *sc, struct sis_rxdesc *rxd) 1410d2155f2fSWarner Losh { 1411a629f2b1SPyun YongHyeon struct mbuf *m; 1412a629f2b1SPyun YongHyeon bus_dma_segment_t segs[1]; 1413a629f2b1SPyun YongHyeon bus_dmamap_t map; 1414a629f2b1SPyun YongHyeon int nsegs; 1415d2155f2fSWarner Losh 1416c6499eccSGleb Smirnoff m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1417d2155f2fSWarner Losh if (m == NULL) 1418d2155f2fSWarner Losh return (ENOBUFS); 1419a629f2b1SPyun YongHyeon m->m_len = m->m_pkthdr.len = SIS_RXLEN; 1420a629f2b1SPyun YongHyeon #ifndef __NO_STRICT_ALIGNMENT 1421a629f2b1SPyun YongHyeon m_adj(m, SIS_RX_BUF_ALIGN); 1422a629f2b1SPyun YongHyeon #endif 1423d2155f2fSWarner Losh 1424a629f2b1SPyun YongHyeon if (bus_dmamap_load_mbuf_sg(sc->sis_rx_tag, sc->sis_rx_sparemap, m, 1425a629f2b1SPyun YongHyeon segs, &nsegs, 0) != 0) { 1426a629f2b1SPyun YongHyeon m_freem(m); 1427a629f2b1SPyun YongHyeon return (ENOBUFS); 1428a629f2b1SPyun YongHyeon } 1429a629f2b1SPyun YongHyeon KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1430d2155f2fSWarner Losh 1431a629f2b1SPyun YongHyeon if (rxd->rx_m != NULL) { 1432a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, 1433a629f2b1SPyun YongHyeon BUS_DMASYNC_POSTREAD); 1434a629f2b1SPyun YongHyeon bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap); 1435a629f2b1SPyun YongHyeon } 1436a629f2b1SPyun YongHyeon map = rxd->rx_dmamap; 1437a629f2b1SPyun YongHyeon rxd->rx_dmamap = sc->sis_rx_sparemap; 1438a629f2b1SPyun YongHyeon sc->sis_rx_sparemap = map; 1439a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_PREREAD); 1440a629f2b1SPyun YongHyeon rxd->rx_m = m; 1441a629f2b1SPyun YongHyeon rxd->rx_desc->sis_ptr = htole32(SIS_ADDR_LO(segs[0].ds_addr)); 14425ed8e782SPyun YongHyeon rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN); 1443d2155f2fSWarner Losh return (0); 1444d2155f2fSWarner Losh } 1445d2155f2fSWarner Losh 1446a629f2b1SPyun YongHyeon static __inline void 1447a629f2b1SPyun YongHyeon sis_discard_rxbuf(struct sis_rxdesc *rxd) 1448a629f2b1SPyun YongHyeon { 1449a629f2b1SPyun YongHyeon 1450a629f2b1SPyun YongHyeon rxd->rx_desc->sis_cmdsts = htole32(SIS_RXLEN); 1451a629f2b1SPyun YongHyeon } 1452a629f2b1SPyun YongHyeon 1453a629f2b1SPyun YongHyeon #ifndef __NO_STRICT_ALIGNMENT 1454a629f2b1SPyun YongHyeon static __inline void 1455a629f2b1SPyun YongHyeon sis_fixup_rx(struct mbuf *m) 1456a629f2b1SPyun YongHyeon { 1457a629f2b1SPyun YongHyeon uint16_t *src, *dst; 1458a629f2b1SPyun YongHyeon int i; 1459a629f2b1SPyun YongHyeon 1460a629f2b1SPyun YongHyeon src = mtod(m, uint16_t *); 1461a629f2b1SPyun YongHyeon dst = src - (SIS_RX_BUF_ALIGN - ETHER_ALIGN) / sizeof(*src); 1462a629f2b1SPyun YongHyeon 1463a629f2b1SPyun YongHyeon for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1464a629f2b1SPyun YongHyeon *dst++ = *src++; 1465a629f2b1SPyun YongHyeon 1466a629f2b1SPyun YongHyeon m->m_data -= SIS_RX_BUF_ALIGN - ETHER_ALIGN; 1467a629f2b1SPyun YongHyeon } 1468a629f2b1SPyun YongHyeon #endif 1469a629f2b1SPyun YongHyeon 1470d2155f2fSWarner Losh /* 1471d2155f2fSWarner Losh * A frame has been uploaded: pass the resulting mbuf chain up to 1472d2155f2fSWarner Losh * the higher level protocols. 1473d2155f2fSWarner Losh */ 14741abcdbd1SAttilio Rao static int 1475d2155f2fSWarner Losh sis_rxeof(struct sis_softc *sc) 1476d2155f2fSWarner Losh { 1477a629f2b1SPyun YongHyeon struct mbuf *m; 1478*1125d093SJustin Hibbits if_t ifp; 1479a629f2b1SPyun YongHyeon struct sis_rxdesc *rxd; 1480d2155f2fSWarner Losh struct sis_desc *cur_rx; 1481a629f2b1SPyun YongHyeon int prog, rx_cons, rx_npkts = 0, total_len; 1482a629f2b1SPyun YongHyeon uint32_t rxstat; 1483d2155f2fSWarner Losh 1484d2155f2fSWarner Losh SIS_LOCK_ASSERT(sc); 1485d2155f2fSWarner Losh 1486a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1487a629f2b1SPyun YongHyeon BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1488a629f2b1SPyun YongHyeon 1489a629f2b1SPyun YongHyeon rx_cons = sc->sis_rx_cons; 1490d2155f2fSWarner Losh ifp = sc->sis_ifp; 1491d2155f2fSWarner Losh 1492*1125d093SJustin Hibbits for (prog = 0; (if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0; 1493a629f2b1SPyun YongHyeon SIS_INC(rx_cons, SIS_RX_LIST_CNT), prog++) { 1494d2155f2fSWarner Losh #ifdef DEVICE_POLLING 1495*1125d093SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_POLLING) { 1496d2155f2fSWarner Losh if (sc->rxcycles <= 0) 1497d2155f2fSWarner Losh break; 1498d2155f2fSWarner Losh sc->rxcycles--; 1499d2155f2fSWarner Losh } 1500d2155f2fSWarner Losh #endif 1501a629f2b1SPyun YongHyeon cur_rx = &sc->sis_rx_list[rx_cons]; 1502a629f2b1SPyun YongHyeon rxstat = le32toh(cur_rx->sis_cmdsts); 1503a629f2b1SPyun YongHyeon if ((rxstat & SIS_CMDSTS_OWN) == 0) 1504a629f2b1SPyun YongHyeon break; 1505a629f2b1SPyun YongHyeon rxd = &sc->sis_rxdesc[rx_cons]; 1506d2155f2fSWarner Losh 1507a629f2b1SPyun YongHyeon total_len = (rxstat & SIS_CMDSTS_BUFLEN) - ETHER_CRC_LEN; 1508*1125d093SJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_VLAN_MTU) != 0 && 150992483efaSPyun YongHyeon total_len <= (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN - 151092483efaSPyun YongHyeon ETHER_CRC_LEN)) 151192483efaSPyun YongHyeon rxstat &= ~SIS_RXSTAT_GIANT; 151292483efaSPyun YongHyeon if (SIS_RXSTAT_ERROR(rxstat) != 0) { 1513e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1514d2155f2fSWarner Losh if (rxstat & SIS_RXSTAT_COLL) 1515e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1); 1516a629f2b1SPyun YongHyeon sis_discard_rxbuf(rxd); 1517a629f2b1SPyun YongHyeon continue; 1518a629f2b1SPyun YongHyeon } 1519a629f2b1SPyun YongHyeon 1520a629f2b1SPyun YongHyeon /* Add a new receive buffer to the ring. */ 1521a629f2b1SPyun YongHyeon m = rxd->rx_m; 1522a629f2b1SPyun YongHyeon if (sis_newbuf(sc, rxd) != 0) { 1523e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); 1524a629f2b1SPyun YongHyeon sis_discard_rxbuf(rxd); 1525d2155f2fSWarner Losh continue; 1526d2155f2fSWarner Losh } 1527d2155f2fSWarner Losh 1528d2155f2fSWarner Losh /* No errors; receive the packet. */ 1529a629f2b1SPyun YongHyeon m->m_pkthdr.len = m->m_len = total_len; 1530a629f2b1SPyun YongHyeon #ifndef __NO_STRICT_ALIGNMENT 1531d2155f2fSWarner Losh /* 1532d2155f2fSWarner Losh * On architectures without alignment problems we try to 1533d2155f2fSWarner Losh * allocate a new buffer for the receive ring, and pass up 1534d2155f2fSWarner Losh * the one where the packet is already, saving the expensive 1535a629f2b1SPyun YongHyeon * copy operation. 1536d2155f2fSWarner Losh */ 1537a629f2b1SPyun YongHyeon sis_fixup_rx(m); 1538d2155f2fSWarner Losh #endif 1539e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 1540d2155f2fSWarner Losh m->m_pkthdr.rcvif = ifp; 1541d2155f2fSWarner Losh 1542d2155f2fSWarner Losh SIS_UNLOCK(sc); 1543*1125d093SJustin Hibbits if_input(ifp, m); 1544d2155f2fSWarner Losh SIS_LOCK(sc); 15451abcdbd1SAttilio Rao rx_npkts++; 1546d2155f2fSWarner Losh } 1547d2155f2fSWarner Losh 1548a629f2b1SPyun YongHyeon if (prog > 0) { 1549a629f2b1SPyun YongHyeon sc->sis_rx_cons = rx_cons; 1550a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_rx_list_tag, sc->sis_rx_list_map, 1551a629f2b1SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1552a629f2b1SPyun YongHyeon } 1553a629f2b1SPyun YongHyeon 15541abcdbd1SAttilio Rao return (rx_npkts); 1555d2155f2fSWarner Losh } 1556d2155f2fSWarner Losh 1557d2155f2fSWarner Losh /* 1558d2155f2fSWarner Losh * A frame was downloaded to the chip. It's safe for us to clean up 1559d2155f2fSWarner Losh * the list buffers. 1560d2155f2fSWarner Losh */ 1561d2155f2fSWarner Losh 1562d2155f2fSWarner Losh static void 1563d2155f2fSWarner Losh sis_txeof(struct sis_softc *sc) 1564d2155f2fSWarner Losh { 1565*1125d093SJustin Hibbits if_t ifp; 1566a629f2b1SPyun YongHyeon struct sis_desc *cur_tx; 1567a629f2b1SPyun YongHyeon struct sis_txdesc *txd; 1568a629f2b1SPyun YongHyeon uint32_t cons, txstat; 1569d2155f2fSWarner Losh 1570d2155f2fSWarner Losh SIS_LOCK_ASSERT(sc); 1571a629f2b1SPyun YongHyeon 1572a629f2b1SPyun YongHyeon cons = sc->sis_tx_cons; 1573a629f2b1SPyun YongHyeon if (cons == sc->sis_tx_prod) 1574a629f2b1SPyun YongHyeon return; 1575a629f2b1SPyun YongHyeon 1576d2155f2fSWarner Losh ifp = sc->sis_ifp; 1577a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1578a629f2b1SPyun YongHyeon BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1579d2155f2fSWarner Losh 1580d2155f2fSWarner Losh /* 1581d2155f2fSWarner Losh * Go through our tx list and free mbufs for those 1582d2155f2fSWarner Losh * frames that have been transmitted. 1583d2155f2fSWarner Losh */ 1584a629f2b1SPyun YongHyeon for (; cons != sc->sis_tx_prod; SIS_INC(cons, SIS_TX_LIST_CNT)) { 1585a629f2b1SPyun YongHyeon cur_tx = &sc->sis_tx_list[cons]; 1586a629f2b1SPyun YongHyeon txstat = le32toh(cur_tx->sis_cmdsts); 1587a629f2b1SPyun YongHyeon if ((txstat & SIS_CMDSTS_OWN) != 0) 1588d2155f2fSWarner Losh break; 1589a629f2b1SPyun YongHyeon txd = &sc->sis_txdesc[cons]; 1590a629f2b1SPyun YongHyeon if (txd->tx_m != NULL) { 1591a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, 1592a629f2b1SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 1593a629f2b1SPyun YongHyeon bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 1594a629f2b1SPyun YongHyeon m_freem(txd->tx_m); 1595a629f2b1SPyun YongHyeon txd->tx_m = NULL; 1596a629f2b1SPyun YongHyeon if ((txstat & SIS_CMDSTS_PKT_OK) != 0) { 1597e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 1598e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1599e1ed7fe8SGleb Smirnoff (txstat & SIS_TXSTAT_COLLCNT) >> 16); 1600a629f2b1SPyun YongHyeon } else { 1601e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 1602a629f2b1SPyun YongHyeon if (txstat & SIS_TXSTAT_EXCESSCOLLS) 1603e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1); 1604a629f2b1SPyun YongHyeon if (txstat & SIS_TXSTAT_OUTOFWINCOLL) 1605e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1); 1606d2155f2fSWarner Losh } 1607d2155f2fSWarner Losh } 1608a629f2b1SPyun YongHyeon sc->sis_tx_cnt--; 1609*1125d093SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 1610d2155f2fSWarner Losh } 1611a629f2b1SPyun YongHyeon sc->sis_tx_cons = cons; 1612a629f2b1SPyun YongHyeon if (sc->sis_tx_cnt == 0) 1613a629f2b1SPyun YongHyeon sc->sis_watchdog_timer = 0; 1614d2155f2fSWarner Losh } 1615d2155f2fSWarner Losh 1616d2155f2fSWarner Losh static void 1617d2155f2fSWarner Losh sis_tick(void *xsc) 1618d2155f2fSWarner Losh { 1619d2155f2fSWarner Losh struct sis_softc *sc; 1620d2155f2fSWarner Losh struct mii_data *mii; 1621d2155f2fSWarner Losh 1622d2155f2fSWarner Losh sc = xsc; 1623d2155f2fSWarner Losh SIS_LOCK_ASSERT(sc); 1624d2155f2fSWarner Losh 1625d2155f2fSWarner Losh mii = device_get_softc(sc->sis_miibus); 1626d2155f2fSWarner Losh mii_tick(mii); 1627d2155f2fSWarner Losh sis_watchdog(sc); 162894222398SPyun YongHyeon if ((sc->sis_flags & SIS_FLAG_LINK) == 0) 1629d7b57e79SPyun YongHyeon sis_miibus_statchg(sc->sis_dev); 1630d2155f2fSWarner Losh callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); 1631d2155f2fSWarner Losh } 1632d2155f2fSWarner Losh 1633d2155f2fSWarner Losh #ifdef DEVICE_POLLING 1634d2155f2fSWarner Losh static poll_handler_t sis_poll; 1635d2155f2fSWarner Losh 16361abcdbd1SAttilio Rao static int 1637*1125d093SJustin Hibbits sis_poll(if_t ifp, enum poll_cmd cmd, int count) 1638d2155f2fSWarner Losh { 1639*1125d093SJustin Hibbits struct sis_softc *sc = if_getsoftc(ifp); 16401abcdbd1SAttilio Rao int rx_npkts = 0; 1641d2155f2fSWarner Losh 1642d2155f2fSWarner Losh SIS_LOCK(sc); 1643*1125d093SJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) { 1644d2155f2fSWarner Losh SIS_UNLOCK(sc); 16451abcdbd1SAttilio Rao return (rx_npkts); 1646d2155f2fSWarner Losh } 1647d2155f2fSWarner Losh 1648d2155f2fSWarner Losh /* 1649d2155f2fSWarner Losh * On the sis, reading the status register also clears it. 1650d2155f2fSWarner Losh * So before returning to intr mode we must make sure that all 1651d2155f2fSWarner Losh * possible pending sources of interrupts have been served. 1652d2155f2fSWarner Losh * In practice this means run to completion the *eof routines, 1653d2155f2fSWarner Losh * and then call the interrupt routine 1654d2155f2fSWarner Losh */ 1655d2155f2fSWarner Losh sc->rxcycles = count; 16561abcdbd1SAttilio Rao rx_npkts = sis_rxeof(sc); 1657d2155f2fSWarner Losh sis_txeof(sc); 1658*1125d093SJustin Hibbits if (!if_sendq_empty(ifp)) 1659d2155f2fSWarner Losh sis_startl(ifp); 1660d2155f2fSWarner Losh 1661d2155f2fSWarner Losh if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 166291c265b8SPyun YongHyeon uint32_t status; 1663d2155f2fSWarner Losh 1664d2155f2fSWarner Losh /* Reading the ISR register clears all interrupts. */ 1665d2155f2fSWarner Losh status = CSR_READ_4(sc, SIS_ISR); 1666d2155f2fSWarner Losh 1667d2155f2fSWarner Losh if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW)) 1668e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1669d2155f2fSWarner Losh 1670d2155f2fSWarner Losh if (status & (SIS_ISR_RX_IDLE)) 1671d2155f2fSWarner Losh SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 1672d2155f2fSWarner Losh 1673d2155f2fSWarner Losh if (status & SIS_ISR_SYSERR) { 1674*1125d093SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1675d2155f2fSWarner Losh sis_initl(sc); 1676d2155f2fSWarner Losh } 1677d2155f2fSWarner Losh } 1678d2155f2fSWarner Losh 1679d2155f2fSWarner Losh SIS_UNLOCK(sc); 16801abcdbd1SAttilio Rao return (rx_npkts); 1681d2155f2fSWarner Losh } 1682d2155f2fSWarner Losh #endif /* DEVICE_POLLING */ 1683d2155f2fSWarner Losh 1684d2155f2fSWarner Losh static void 1685d2155f2fSWarner Losh sis_intr(void *arg) 1686d2155f2fSWarner Losh { 1687d2155f2fSWarner Losh struct sis_softc *sc; 1688*1125d093SJustin Hibbits if_t ifp; 168991c265b8SPyun YongHyeon uint32_t status; 1690d2155f2fSWarner Losh 1691d2155f2fSWarner Losh sc = arg; 1692d2155f2fSWarner Losh ifp = sc->sis_ifp; 1693d2155f2fSWarner Losh 1694d2155f2fSWarner Losh SIS_LOCK(sc); 1695d2155f2fSWarner Losh #ifdef DEVICE_POLLING 1696*1125d093SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_POLLING) { 1697d2155f2fSWarner Losh SIS_UNLOCK(sc); 1698d2155f2fSWarner Losh return; 1699d2155f2fSWarner Losh } 1700d2155f2fSWarner Losh #endif 1701d2155f2fSWarner Losh 1702d7b57e79SPyun YongHyeon /* Reading the ISR register clears all interrupts. */ 1703d7b57e79SPyun YongHyeon status = CSR_READ_4(sc, SIS_ISR); 1704d7b57e79SPyun YongHyeon if ((status & SIS_INTRS) == 0) { 1705d7b57e79SPyun YongHyeon /* Not ours. */ 1706d7b57e79SPyun YongHyeon SIS_UNLOCK(sc); 170769b5727fSPyun YongHyeon return; 1708d7b57e79SPyun YongHyeon } 1709d7b57e79SPyun YongHyeon 1710d2155f2fSWarner Losh /* Disable interrupts. */ 1711d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_IER, 0); 1712d2155f2fSWarner Losh 1713d7b57e79SPyun YongHyeon for (;(status & SIS_INTRS) != 0;) { 1714*1125d093SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) 171569b5727fSPyun YongHyeon break; 1716d2155f2fSWarner Losh if (status & 1717d2155f2fSWarner Losh (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR | 1718d2155f2fSWarner Losh SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) ) 1719d2155f2fSWarner Losh sis_txeof(sc); 1720d2155f2fSWarner Losh 172153414a48SPyun YongHyeon if (status & (SIS_ISR_RX_DESC_OK | SIS_ISR_RX_OK | 172253414a48SPyun YongHyeon SIS_ISR_RX_ERR | SIS_ISR_RX_IDLE)) 1723d2155f2fSWarner Losh sis_rxeof(sc); 1724d2155f2fSWarner Losh 172553414a48SPyun YongHyeon if (status & SIS_ISR_RX_OFLOW) 1726e1ed7fe8SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1727d2155f2fSWarner Losh 1728d2155f2fSWarner Losh if (status & (SIS_ISR_RX_IDLE)) 1729d2155f2fSWarner Losh SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 1730d2155f2fSWarner Losh 1731d2155f2fSWarner Losh if (status & SIS_ISR_SYSERR) { 1732*1125d093SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1733d2155f2fSWarner Losh sis_initl(sc); 1734d7b57e79SPyun YongHyeon SIS_UNLOCK(sc); 1735d7b57e79SPyun YongHyeon return; 1736d2155f2fSWarner Losh } 1737d7b57e79SPyun YongHyeon status = CSR_READ_4(sc, SIS_ISR); 1738d2155f2fSWarner Losh } 1739d2155f2fSWarner Losh 1740*1125d093SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 1741d2155f2fSWarner Losh /* Re-enable interrupts. */ 1742d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_IER, 1); 1743d2155f2fSWarner Losh 1744*1125d093SJustin Hibbits if (!if_sendq_empty(ifp)) 1745d2155f2fSWarner Losh sis_startl(ifp); 174669b5727fSPyun YongHyeon } 1747d2155f2fSWarner Losh 1748d2155f2fSWarner Losh SIS_UNLOCK(sc); 1749d2155f2fSWarner Losh } 1750d2155f2fSWarner Losh 1751d2155f2fSWarner Losh /* 1752d2155f2fSWarner Losh * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 1753d2155f2fSWarner Losh * pointers to the fragment pointers. 1754d2155f2fSWarner Losh */ 1755d2155f2fSWarner Losh static int 1756a629f2b1SPyun YongHyeon sis_encap(struct sis_softc *sc, struct mbuf **m_head) 1757d2155f2fSWarner Losh { 1758d2155f2fSWarner Losh struct mbuf *m; 1759a629f2b1SPyun YongHyeon struct sis_txdesc *txd; 1760a629f2b1SPyun YongHyeon struct sis_desc *f; 1761a629f2b1SPyun YongHyeon bus_dma_segment_t segs[SIS_MAXTXSEGS]; 1762a629f2b1SPyun YongHyeon bus_dmamap_t map; 1763a629f2b1SPyun YongHyeon int error, i, frag, nsegs, prod; 176494222398SPyun YongHyeon int padlen; 1765d2155f2fSWarner Losh 1766a629f2b1SPyun YongHyeon prod = sc->sis_tx_prod; 1767a629f2b1SPyun YongHyeon txd = &sc->sis_txdesc[prod]; 176894222398SPyun YongHyeon if ((sc->sis_flags & SIS_FLAG_MANUAL_PAD) != 0 && 176994222398SPyun YongHyeon (*m_head)->m_pkthdr.len < SIS_MIN_FRAMELEN) { 177094222398SPyun YongHyeon m = *m_head; 177194222398SPyun YongHyeon padlen = SIS_MIN_FRAMELEN - m->m_pkthdr.len; 177294222398SPyun YongHyeon if (M_WRITABLE(m) == 0) { 177394222398SPyun YongHyeon /* Get a writable copy. */ 1774c6499eccSGleb Smirnoff m = m_dup(*m_head, M_NOWAIT); 177594222398SPyun YongHyeon m_freem(*m_head); 177694222398SPyun YongHyeon if (m == NULL) { 177794222398SPyun YongHyeon *m_head = NULL; 177894222398SPyun YongHyeon return (ENOBUFS); 177994222398SPyun YongHyeon } 178094222398SPyun YongHyeon *m_head = m; 178194222398SPyun YongHyeon } 178294222398SPyun YongHyeon if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) { 1783c6499eccSGleb Smirnoff m = m_defrag(m, M_NOWAIT); 178494222398SPyun YongHyeon if (m == NULL) { 178594222398SPyun YongHyeon m_freem(*m_head); 178694222398SPyun YongHyeon *m_head = NULL; 178794222398SPyun YongHyeon return (ENOBUFS); 178894222398SPyun YongHyeon } 178994222398SPyun YongHyeon } 179094222398SPyun YongHyeon /* 179194222398SPyun YongHyeon * Manually pad short frames, and zero the pad space 179294222398SPyun YongHyeon * to avoid leaking data. 179394222398SPyun YongHyeon */ 179494222398SPyun YongHyeon bzero(mtod(m, char *) + m->m_pkthdr.len, padlen); 179594222398SPyun YongHyeon m->m_pkthdr.len += padlen; 179694222398SPyun YongHyeon m->m_len = m->m_pkthdr.len; 179794222398SPyun YongHyeon *m_head = m; 179894222398SPyun YongHyeon } 1799a629f2b1SPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap, 1800a629f2b1SPyun YongHyeon *m_head, segs, &nsegs, 0); 1801a629f2b1SPyun YongHyeon if (error == EFBIG) { 1802c6499eccSGleb Smirnoff m = m_collapse(*m_head, M_NOWAIT, SIS_MAXTXSEGS); 1803a629f2b1SPyun YongHyeon if (m == NULL) { 1804a629f2b1SPyun YongHyeon m_freem(*m_head); 1805a629f2b1SPyun YongHyeon *m_head = NULL; 1806d2155f2fSWarner Losh return (ENOBUFS); 1807a629f2b1SPyun YongHyeon } 1808d2155f2fSWarner Losh *m_head = m; 1809a629f2b1SPyun YongHyeon error = bus_dmamap_load_mbuf_sg(sc->sis_tx_tag, txd->tx_dmamap, 1810a629f2b1SPyun YongHyeon *m_head, segs, &nsegs, 0); 1811a629f2b1SPyun YongHyeon if (error != 0) { 1812a629f2b1SPyun YongHyeon m_freem(*m_head); 1813a629f2b1SPyun YongHyeon *m_head = NULL; 1814a629f2b1SPyun YongHyeon return (error); 1815a629f2b1SPyun YongHyeon } 1816a629f2b1SPyun YongHyeon } else if (error != 0) 1817a629f2b1SPyun YongHyeon return (error); 1818a629f2b1SPyun YongHyeon 1819a629f2b1SPyun YongHyeon /* Check for descriptor overruns. */ 1820a629f2b1SPyun YongHyeon if (sc->sis_tx_cnt + nsegs > SIS_TX_LIST_CNT - 1) { 1821a629f2b1SPyun YongHyeon bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 1822a629f2b1SPyun YongHyeon return (ENOBUFS); 1823d2155f2fSWarner Losh } 1824d2155f2fSWarner Losh 1825a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, BUS_DMASYNC_PREWRITE); 1826d2155f2fSWarner Losh 1827a629f2b1SPyun YongHyeon frag = prod; 1828a629f2b1SPyun YongHyeon for (i = 0; i < nsegs; i++) { 1829a629f2b1SPyun YongHyeon f = &sc->sis_tx_list[prod]; 1830a629f2b1SPyun YongHyeon if (i == 0) 1831a629f2b1SPyun YongHyeon f->sis_cmdsts = htole32(segs[i].ds_len | 1832a629f2b1SPyun YongHyeon SIS_CMDSTS_MORE); 1833a629f2b1SPyun YongHyeon else 1834a629f2b1SPyun YongHyeon f->sis_cmdsts = htole32(segs[i].ds_len | 1835a629f2b1SPyun YongHyeon SIS_CMDSTS_OWN | SIS_CMDSTS_MORE); 1836a629f2b1SPyun YongHyeon f->sis_ptr = htole32(SIS_ADDR_LO(segs[i].ds_addr)); 1837a629f2b1SPyun YongHyeon SIS_INC(prod, SIS_TX_LIST_CNT); 1838a629f2b1SPyun YongHyeon sc->sis_tx_cnt++; 1839a629f2b1SPyun YongHyeon } 1840a629f2b1SPyun YongHyeon 1841a629f2b1SPyun YongHyeon /* Update producer index. */ 1842a629f2b1SPyun YongHyeon sc->sis_tx_prod = prod; 1843a629f2b1SPyun YongHyeon 1844a629f2b1SPyun YongHyeon /* Remove MORE flag on the last descriptor. */ 1845a629f2b1SPyun YongHyeon prod = (prod - 1) & (SIS_TX_LIST_CNT - 1); 1846a629f2b1SPyun YongHyeon f = &sc->sis_tx_list[prod]; 1847a629f2b1SPyun YongHyeon f->sis_cmdsts &= ~htole32(SIS_CMDSTS_MORE); 1848a629f2b1SPyun YongHyeon 1849a629f2b1SPyun YongHyeon /* Lastly transfer ownership of packet to the controller. */ 1850d2155f2fSWarner Losh f = &sc->sis_tx_list[frag]; 1851a629f2b1SPyun YongHyeon f->sis_cmdsts |= htole32(SIS_CMDSTS_OWN); 1852d2155f2fSWarner Losh 1853a629f2b1SPyun YongHyeon /* Swap the last and the first dmamaps. */ 1854a629f2b1SPyun YongHyeon map = txd->tx_dmamap; 18558c6cd863SPyun YongHyeon txd->tx_dmamap = sc->sis_txdesc[prod].tx_dmamap; 18568c6cd863SPyun YongHyeon sc->sis_txdesc[prod].tx_dmamap = map; 1857443f331eSPyun YongHyeon sc->sis_txdesc[prod].tx_m = *m_head; 1858d2155f2fSWarner Losh 1859d2155f2fSWarner Losh return (0); 1860d2155f2fSWarner Losh } 1861d2155f2fSWarner Losh 1862d2155f2fSWarner Losh static void 1863*1125d093SJustin Hibbits sis_start(if_t ifp) 1864d2155f2fSWarner Losh { 1865d2155f2fSWarner Losh struct sis_softc *sc; 1866d2155f2fSWarner Losh 1867*1125d093SJustin Hibbits sc = if_getsoftc(ifp); 1868d2155f2fSWarner Losh SIS_LOCK(sc); 1869d2155f2fSWarner Losh sis_startl(ifp); 1870d2155f2fSWarner Losh SIS_UNLOCK(sc); 1871d2155f2fSWarner Losh } 1872d2155f2fSWarner Losh 1873d2155f2fSWarner Losh static void 1874*1125d093SJustin Hibbits sis_startl(if_t ifp) 1875d2155f2fSWarner Losh { 1876d2155f2fSWarner Losh struct sis_softc *sc; 1877a629f2b1SPyun YongHyeon struct mbuf *m_head; 1878a629f2b1SPyun YongHyeon int queued; 1879d2155f2fSWarner Losh 1880*1125d093SJustin Hibbits sc = if_getsoftc(ifp); 1881d2155f2fSWarner Losh 1882d2155f2fSWarner Losh SIS_LOCK_ASSERT(sc); 1883d2155f2fSWarner Losh 1884*1125d093SJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 188594222398SPyun YongHyeon IFF_DRV_RUNNING || (sc->sis_flags & SIS_FLAG_LINK) == 0) 1886d2155f2fSWarner Losh return; 1887d2155f2fSWarner Losh 1888*1125d093SJustin Hibbits for (queued = 0; !if_sendq_empty(ifp) && 1889a629f2b1SPyun YongHyeon sc->sis_tx_cnt < SIS_TX_LIST_CNT - 4;) { 1890*1125d093SJustin Hibbits m_head = if_dequeue(ifp); 1891d2155f2fSWarner Losh if (m_head == NULL) 1892d2155f2fSWarner Losh break; 1893d2155f2fSWarner Losh 1894a629f2b1SPyun YongHyeon if (sis_encap(sc, &m_head) != 0) { 1895a629f2b1SPyun YongHyeon if (m_head == NULL) 1896a629f2b1SPyun YongHyeon break; 1897*1125d093SJustin Hibbits if_sendq_prepend(ifp, m_head); 1898*1125d093SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); 1899d2155f2fSWarner Losh break; 1900d2155f2fSWarner Losh } 1901d2155f2fSWarner Losh 1902d2155f2fSWarner Losh queued++; 1903d2155f2fSWarner Losh 1904d2155f2fSWarner Losh /* 1905d2155f2fSWarner Losh * If there's a BPF listener, bounce a copy of this frame 1906d2155f2fSWarner Losh * to him. 1907d2155f2fSWarner Losh */ 1908d2155f2fSWarner Losh BPF_MTAP(ifp, m_head); 1909d2155f2fSWarner Losh } 1910d2155f2fSWarner Losh 1911d2155f2fSWarner Losh if (queued) { 1912d2155f2fSWarner Losh /* Transmit */ 1913a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_tx_list_tag, sc->sis_tx_list_map, 1914a629f2b1SPyun YongHyeon BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1915d2155f2fSWarner Losh SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE); 1916d2155f2fSWarner Losh 1917d2155f2fSWarner Losh /* 1918d2155f2fSWarner Losh * Set a timeout in case the chip goes out to lunch. 1919d2155f2fSWarner Losh */ 1920d2155f2fSWarner Losh sc->sis_watchdog_timer = 5; 1921d2155f2fSWarner Losh } 1922d2155f2fSWarner Losh } 1923d2155f2fSWarner Losh 1924d2155f2fSWarner Losh static void 1925d2155f2fSWarner Losh sis_init(void *xsc) 1926d2155f2fSWarner Losh { 1927d2155f2fSWarner Losh struct sis_softc *sc = xsc; 1928d2155f2fSWarner Losh 1929d2155f2fSWarner Losh SIS_LOCK(sc); 1930d2155f2fSWarner Losh sis_initl(sc); 1931d2155f2fSWarner Losh SIS_UNLOCK(sc); 1932d2155f2fSWarner Losh } 1933d2155f2fSWarner Losh 1934d2155f2fSWarner Losh static void 1935d2155f2fSWarner Losh sis_initl(struct sis_softc *sc) 1936d2155f2fSWarner Losh { 1937*1125d093SJustin Hibbits if_t ifp = sc->sis_ifp; 1938d2155f2fSWarner Losh struct mii_data *mii; 193974e8a323SPyun YongHyeon uint8_t *eaddr; 1940d2155f2fSWarner Losh 1941d2155f2fSWarner Losh SIS_LOCK_ASSERT(sc); 1942d2155f2fSWarner Losh 1943*1125d093SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) 1944d199ef7eSPyun YongHyeon return; 1945d199ef7eSPyun YongHyeon 1946d2155f2fSWarner Losh /* 1947d2155f2fSWarner Losh * Cancel pending I/O and free all RX/TX buffers. 1948d2155f2fSWarner Losh */ 1949d2155f2fSWarner Losh sis_stop(sc); 19507723fa2eSPyun YongHyeon /* 19517723fa2eSPyun YongHyeon * Reset the chip to a known state. 19527723fa2eSPyun YongHyeon */ 19537723fa2eSPyun YongHyeon sis_reset(sc); 1954d2155f2fSWarner Losh #ifdef notyet 1955d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr >= NS_SRR_16A) { 1956d2155f2fSWarner Losh /* 1957d2155f2fSWarner Losh * Configure 400usec of interrupt holdoff. This is based 19583c2ea3caSGordon Bergling * on empirical tests on a Soekris 4801. 1959d2155f2fSWarner Losh */ 1960d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_IHR, 0x100 | 4); 1961d2155f2fSWarner Losh } 1962d2155f2fSWarner Losh #endif 1963d2155f2fSWarner Losh 1964d2155f2fSWarner Losh mii = device_get_softc(sc->sis_miibus); 1965d2155f2fSWarner Losh 1966d2155f2fSWarner Losh /* Set MAC address */ 1967*1125d093SJustin Hibbits eaddr = if_getlladdr(sc->sis_ifp); 1968d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_83815) { 1969d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); 197074e8a323SPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[0] | eaddr[1] << 8); 1971d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); 197274e8a323SPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[2] | eaddr[3] << 8); 1973d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); 197474e8a323SPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[4] | eaddr[5] << 8); 1975d2155f2fSWarner Losh } else { 1976d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 197774e8a323SPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[0] | eaddr[1] << 8); 1978d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1); 197974e8a323SPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[2] | eaddr[3] << 8); 1980d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 198174e8a323SPyun YongHyeon CSR_WRITE_4(sc, SIS_RXFILT_DATA, eaddr[4] | eaddr[5] << 8); 1982d2155f2fSWarner Losh } 1983d2155f2fSWarner Losh 1984d2155f2fSWarner Losh /* Init circular TX/RX lists. */ 1985d2155f2fSWarner Losh if (sis_ring_init(sc) != 0) { 1986d2155f2fSWarner Losh device_printf(sc->sis_dev, 1987d2155f2fSWarner Losh "initialization failed: no memory for rx buffers\n"); 1988d2155f2fSWarner Losh sis_stop(sc); 1989d2155f2fSWarner Losh return; 1990d2155f2fSWarner Losh } 1991d2155f2fSWarner Losh 1992e8bedbd2SPyun YongHyeon if (sc->sis_type == SIS_TYPE_83815) { 199394222398SPyun YongHyeon if (sc->sis_manual_pad != 0) 199494222398SPyun YongHyeon sc->sis_flags |= SIS_FLAG_MANUAL_PAD; 199594222398SPyun YongHyeon else 199694222398SPyun YongHyeon sc->sis_flags &= ~SIS_FLAG_MANUAL_PAD; 199794222398SPyun YongHyeon } 199894222398SPyun YongHyeon 1999d2155f2fSWarner Losh /* 2000d2155f2fSWarner Losh * Short Cable Receive Errors (MP21.E) 2001d2155f2fSWarner Losh * also: Page 78 of the DP83815 data sheet (september 2002 version) 2002d2155f2fSWarner Losh * recommends the following register settings "for optimum 2003d2155f2fSWarner Losh * performance." for rev 15C. Set this also for 15D parts as 2004d2155f2fSWarner Losh * they require it in practice. 2005d2155f2fSWarner Losh */ 2006d2155f2fSWarner Losh if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr <= NS_SRR_15D) { 2007d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); 2008d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_PHY_CR, 0x189C); 2009d2155f2fSWarner Losh /* set val for c2 */ 2010d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_PHY_TDATA, 0x0000); 2011d2155f2fSWarner Losh /* load/kill c2 */ 2012d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_PHY_DSPCFG, 0x5040); 2013d2155f2fSWarner Losh /* rais SD off, from 4 to c */ 2014d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_PHY_SDCFG, 0x008C); 2015d2155f2fSWarner Losh CSR_WRITE_4(sc, NS_PHY_PAGE, 0); 2016d2155f2fSWarner Losh } 2017d2155f2fSWarner Losh 2018ed15702fSPyun YongHyeon sis_rxfilter(sc); 2019d2155f2fSWarner Losh 2020d2155f2fSWarner Losh /* 2021d2155f2fSWarner Losh * Load the address of the RX and TX lists. 2022d2155f2fSWarner Losh */ 2023a629f2b1SPyun YongHyeon CSR_WRITE_4(sc, SIS_RX_LISTPTR, SIS_ADDR_LO(sc->sis_rx_paddr)); 2024a629f2b1SPyun YongHyeon CSR_WRITE_4(sc, SIS_TX_LISTPTR, SIS_ADDR_LO(sc->sis_tx_paddr)); 2025d2155f2fSWarner Losh 2026d2155f2fSWarner Losh /* SIS_CFG_EDB_MASTER_EN indicates the EDB bus is used instead of 2027d2155f2fSWarner Losh * the PCI bus. When this bit is set, the Max DMA Burst Size 2028d2155f2fSWarner Losh * for TX/RX DMA should be no larger than 16 double words. 2029d2155f2fSWarner Losh */ 2030d2155f2fSWarner Losh if (CSR_READ_4(sc, SIS_CFG) & SIS_CFG_EDB_MASTER_EN) { 2031d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG64); 2032d2155f2fSWarner Losh } else { 2033d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG256); 2034d2155f2fSWarner Losh } 2035d2155f2fSWarner Losh 2036d2155f2fSWarner Losh /* Accept Long Packets for VLAN support */ 2037d2155f2fSWarner Losh SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER); 2038d2155f2fSWarner Losh 2039d7b57e79SPyun YongHyeon /* 2040d7b57e79SPyun YongHyeon * Assume 100Mbps link, actual MAC configuration is done 2041d7b57e79SPyun YongHyeon * after getting a valid link. 2042d7b57e79SPyun YongHyeon */ 2043d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); 2044d2155f2fSWarner Losh 2045d2155f2fSWarner Losh /* 2046d2155f2fSWarner Losh * Enable interrupts. 2047d2155f2fSWarner Losh */ 2048d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS); 2049d2155f2fSWarner Losh #ifdef DEVICE_POLLING 2050d2155f2fSWarner Losh /* 2051d2155f2fSWarner Losh * ... only enable interrupts if we are not polling, make sure 2052d2155f2fSWarner Losh * they are off otherwise. 2053d2155f2fSWarner Losh */ 2054*1125d093SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_POLLING) 2055d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_IER, 0); 2056d2155f2fSWarner Losh else 2057d2155f2fSWarner Losh #endif 2058d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_IER, 1); 2059d2155f2fSWarner Losh 2060d7b57e79SPyun YongHyeon /* Clear MAC disable. */ 2061d2155f2fSWarner Losh SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE | SIS_CSR_RX_DISABLE); 2062d2155f2fSWarner Losh 206394222398SPyun YongHyeon sc->sis_flags &= ~SIS_FLAG_LINK; 2064d2155f2fSWarner Losh mii_mediachg(mii); 2065d2155f2fSWarner Losh 2066*1125d093SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 2067*1125d093SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 2068d2155f2fSWarner Losh 2069d2155f2fSWarner Losh callout_reset(&sc->sis_stat_ch, hz, sis_tick, sc); 2070d2155f2fSWarner Losh } 2071d2155f2fSWarner Losh 2072d2155f2fSWarner Losh /* 2073d2155f2fSWarner Losh * Set media options. 2074d2155f2fSWarner Losh */ 2075d2155f2fSWarner Losh static int 2076*1125d093SJustin Hibbits sis_ifmedia_upd(if_t ifp) 2077d2155f2fSWarner Losh { 2078d2155f2fSWarner Losh struct sis_softc *sc; 2079d2155f2fSWarner Losh struct mii_data *mii; 20803fcb7a53SMarius Strobl struct mii_softc *miisc; 2081fc58ee15SPyun YongHyeon int error; 2082d2155f2fSWarner Losh 2083*1125d093SJustin Hibbits sc = if_getsoftc(ifp); 2084d2155f2fSWarner Losh 2085d2155f2fSWarner Losh SIS_LOCK(sc); 2086d2155f2fSWarner Losh mii = device_get_softc(sc->sis_miibus); 2087d2155f2fSWarner Losh LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 20883fcb7a53SMarius Strobl PHY_RESET(miisc); 2089fc58ee15SPyun YongHyeon error = mii_mediachg(mii); 2090d2155f2fSWarner Losh SIS_UNLOCK(sc); 2091d2155f2fSWarner Losh 2092fc58ee15SPyun YongHyeon return (error); 2093d2155f2fSWarner Losh } 2094d2155f2fSWarner Losh 2095d2155f2fSWarner Losh /* 2096d2155f2fSWarner Losh * Report current media status. 2097d2155f2fSWarner Losh */ 2098d2155f2fSWarner Losh static void 2099*1125d093SJustin Hibbits sis_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) 2100d2155f2fSWarner Losh { 2101d2155f2fSWarner Losh struct sis_softc *sc; 2102d2155f2fSWarner Losh struct mii_data *mii; 2103d2155f2fSWarner Losh 2104*1125d093SJustin Hibbits sc = if_getsoftc(ifp); 2105d2155f2fSWarner Losh 2106d2155f2fSWarner Losh SIS_LOCK(sc); 2107d2155f2fSWarner Losh mii = device_get_softc(sc->sis_miibus); 2108d2155f2fSWarner Losh mii_pollstat(mii); 2109d2155f2fSWarner Losh ifmr->ifm_active = mii->mii_media_active; 2110d2155f2fSWarner Losh ifmr->ifm_status = mii->mii_media_status; 211157c81d92SPyun YongHyeon SIS_UNLOCK(sc); 2112d2155f2fSWarner Losh } 2113d2155f2fSWarner Losh 2114d2155f2fSWarner Losh static int 2115*1125d093SJustin Hibbits sis_ioctl(if_t ifp, u_long command, caddr_t data) 2116d2155f2fSWarner Losh { 2117*1125d093SJustin Hibbits struct sis_softc *sc = if_getsoftc(ifp); 2118d2155f2fSWarner Losh struct ifreq *ifr = (struct ifreq *) data; 2119d2155f2fSWarner Losh struct mii_data *mii; 21200af3989bSPyun YongHyeon int error = 0, mask; 2121d2155f2fSWarner Losh 2122d2155f2fSWarner Losh switch (command) { 2123d2155f2fSWarner Losh case SIOCSIFFLAGS: 2124d2155f2fSWarner Losh SIS_LOCK(sc); 2125*1125d093SJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 2126*1125d093SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0 && 2127*1125d093SJustin Hibbits ((if_getflags(ifp) ^ sc->sis_if_flags) & 2128ed15702fSPyun YongHyeon (IFF_PROMISC | IFF_ALLMULTI)) != 0) 2129ed15702fSPyun YongHyeon sis_rxfilter(sc); 2130ae9e8d49SPyun YongHyeon else 2131d2155f2fSWarner Losh sis_initl(sc); 2132*1125d093SJustin Hibbits } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 2133d2155f2fSWarner Losh sis_stop(sc); 2134*1125d093SJustin Hibbits sc->sis_if_flags = if_getflags(ifp); 2135d2155f2fSWarner Losh SIS_UNLOCK(sc); 2136d2155f2fSWarner Losh break; 2137d2155f2fSWarner Losh case SIOCADDMULTI: 2138d2155f2fSWarner Losh case SIOCDELMULTI: 2139d2155f2fSWarner Losh SIS_LOCK(sc); 2140*1125d093SJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) 2141ed15702fSPyun YongHyeon sis_rxfilter(sc); 2142d2155f2fSWarner Losh SIS_UNLOCK(sc); 2143d2155f2fSWarner Losh break; 2144d2155f2fSWarner Losh case SIOCGIFMEDIA: 2145d2155f2fSWarner Losh case SIOCSIFMEDIA: 2146d2155f2fSWarner Losh mii = device_get_softc(sc->sis_miibus); 2147d2155f2fSWarner Losh error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 2148d2155f2fSWarner Losh break; 2149d2155f2fSWarner Losh case SIOCSIFCAP: 2150d2155f2fSWarner Losh SIS_LOCK(sc); 2151*1125d093SJustin Hibbits mask = ifr->ifr_reqcap ^ if_getcapenable(ifp); 21520af3989bSPyun YongHyeon #ifdef DEVICE_POLLING 21530af3989bSPyun YongHyeon if ((mask & IFCAP_POLLING) != 0 && 2154*1125d093SJustin Hibbits (IFCAP_POLLING & if_getcapabilities(ifp)) != 0) { 2155*1125d093SJustin Hibbits if_togglecapenable(ifp, IFCAP_POLLING); 2156*1125d093SJustin Hibbits if ((IFCAP_POLLING & if_getcapenable(ifp)) != 0) { 21570af3989bSPyun YongHyeon error = ether_poll_register(sis_poll, ifp); 21580af3989bSPyun YongHyeon if (error != 0) { 2159d2155f2fSWarner Losh SIS_UNLOCK(sc); 21600af3989bSPyun YongHyeon break; 2161d2155f2fSWarner Losh } 21620af3989bSPyun YongHyeon /* Disable interrupts. */ 21630af3989bSPyun YongHyeon CSR_WRITE_4(sc, SIS_IER, 0); 21640af3989bSPyun YongHyeon } else { 2165d2155f2fSWarner Losh error = ether_poll_deregister(ifp); 2166d2155f2fSWarner Losh /* Enable interrupts. */ 2167d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_IER, 1); 21680af3989bSPyun YongHyeon } 2169d2155f2fSWarner Losh } 2170d2155f2fSWarner Losh #endif /* DEVICE_POLLING */ 21710af3989bSPyun YongHyeon if ((mask & IFCAP_WOL) != 0 && 2172*1125d093SJustin Hibbits (if_getcapabilities(ifp) & IFCAP_WOL) != 0) { 21730af3989bSPyun YongHyeon if ((mask & IFCAP_WOL_UCAST) != 0) 2174*1125d093SJustin Hibbits if_togglecapenable(ifp, IFCAP_WOL_UCAST); 21750af3989bSPyun YongHyeon if ((mask & IFCAP_WOL_MCAST) != 0) 2176*1125d093SJustin Hibbits if_togglecapenable(ifp, IFCAP_WOL_MCAST); 21770af3989bSPyun YongHyeon if ((mask & IFCAP_WOL_MAGIC) != 0) 2178*1125d093SJustin Hibbits if_togglecapenable(ifp, IFCAP_WOL_MAGIC); 21790af3989bSPyun YongHyeon } 21800af3989bSPyun YongHyeon SIS_UNLOCK(sc); 2181d2155f2fSWarner Losh break; 2182d2155f2fSWarner Losh default: 2183d2155f2fSWarner Losh error = ether_ioctl(ifp, command, data); 2184d2155f2fSWarner Losh break; 2185d2155f2fSWarner Losh } 2186d2155f2fSWarner Losh 2187d2155f2fSWarner Losh return (error); 2188d2155f2fSWarner Losh } 2189d2155f2fSWarner Losh 2190d2155f2fSWarner Losh static void 2191d2155f2fSWarner Losh sis_watchdog(struct sis_softc *sc) 2192d2155f2fSWarner Losh { 2193d2155f2fSWarner Losh 2194d2155f2fSWarner Losh SIS_LOCK_ASSERT(sc); 2195d2155f2fSWarner Losh 2196d2155f2fSWarner Losh if (sc->sis_watchdog_timer == 0 || --sc->sis_watchdog_timer >0) 2197d2155f2fSWarner Losh return; 2198d2155f2fSWarner Losh 2199d2155f2fSWarner Losh device_printf(sc->sis_dev, "watchdog timeout\n"); 2200e1ed7fe8SGleb Smirnoff if_inc_counter(sc->sis_ifp, IFCOUNTER_OERRORS, 1); 2201d2155f2fSWarner Losh 2202*1125d093SJustin Hibbits if_setdrvflagbits(sc->sis_ifp, 0, IFF_DRV_RUNNING); 2203d2155f2fSWarner Losh sis_initl(sc); 2204d2155f2fSWarner Losh 2205*1125d093SJustin Hibbits if (!if_sendq_empty(sc->sis_ifp)) 2206d2155f2fSWarner Losh sis_startl(sc->sis_ifp); 2207d2155f2fSWarner Losh } 2208d2155f2fSWarner Losh 2209d2155f2fSWarner Losh /* 2210d2155f2fSWarner Losh * Stop the adapter and free any mbufs allocated to the 2211d2155f2fSWarner Losh * RX and TX lists. 2212d2155f2fSWarner Losh */ 2213d2155f2fSWarner Losh static void 2214d2155f2fSWarner Losh sis_stop(struct sis_softc *sc) 2215d2155f2fSWarner Losh { 2216*1125d093SJustin Hibbits if_t ifp; 2217a629f2b1SPyun YongHyeon struct sis_rxdesc *rxd; 2218a629f2b1SPyun YongHyeon struct sis_txdesc *txd; 2219a629f2b1SPyun YongHyeon int i; 2220d2155f2fSWarner Losh 2221d2155f2fSWarner Losh SIS_LOCK_ASSERT(sc); 2222d7b57e79SPyun YongHyeon 2223d2155f2fSWarner Losh ifp = sc->sis_ifp; 2224d2155f2fSWarner Losh sc->sis_watchdog_timer = 0; 2225d2155f2fSWarner Losh 2226d2155f2fSWarner Losh callout_stop(&sc->sis_stat_ch); 2227d2155f2fSWarner Losh 2228*1125d093SJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 2229d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_IER, 0); 2230d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_IMR, 0); 2231d2155f2fSWarner Losh CSR_READ_4(sc, SIS_ISR); /* clear any interrupts already pending */ 2232d2155f2fSWarner Losh SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE); 2233d2155f2fSWarner Losh DELAY(1000); 2234d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0); 2235d2155f2fSWarner Losh CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); 2236d2155f2fSWarner Losh 223794222398SPyun YongHyeon sc->sis_flags &= ~SIS_FLAG_LINK; 2238d2155f2fSWarner Losh 2239d2155f2fSWarner Losh /* 2240d2155f2fSWarner Losh * Free data in the RX lists. 2241d2155f2fSWarner Losh */ 2242a629f2b1SPyun YongHyeon for (i = 0; i < SIS_RX_LIST_CNT; i++) { 2243a629f2b1SPyun YongHyeon rxd = &sc->sis_rxdesc[i]; 2244a629f2b1SPyun YongHyeon if (rxd->rx_m != NULL) { 2245a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_rx_tag, rxd->rx_dmamap, 2246a629f2b1SPyun YongHyeon BUS_DMASYNC_POSTREAD); 2247a629f2b1SPyun YongHyeon bus_dmamap_unload(sc->sis_rx_tag, rxd->rx_dmamap); 2248a629f2b1SPyun YongHyeon m_freem(rxd->rx_m); 2249a629f2b1SPyun YongHyeon rxd->rx_m = NULL; 2250d2155f2fSWarner Losh } 2251a629f2b1SPyun YongHyeon } 2252d2155f2fSWarner Losh 2253d2155f2fSWarner Losh /* 2254d2155f2fSWarner Losh * Free the TX list buffers. 2255d2155f2fSWarner Losh */ 2256a629f2b1SPyun YongHyeon for (i = 0; i < SIS_TX_LIST_CNT; i++) { 2257a629f2b1SPyun YongHyeon txd = &sc->sis_txdesc[i]; 2258a629f2b1SPyun YongHyeon if (txd->tx_m != NULL) { 2259a629f2b1SPyun YongHyeon bus_dmamap_sync(sc->sis_tx_tag, txd->tx_dmamap, 2260a629f2b1SPyun YongHyeon BUS_DMASYNC_POSTWRITE); 2261a629f2b1SPyun YongHyeon bus_dmamap_unload(sc->sis_tx_tag, txd->tx_dmamap); 2262a629f2b1SPyun YongHyeon m_freem(txd->tx_m); 2263a629f2b1SPyun YongHyeon txd->tx_m = NULL; 2264d2155f2fSWarner Losh } 2265a629f2b1SPyun YongHyeon } 2266d2155f2fSWarner Losh } 2267d2155f2fSWarner Losh 2268d2155f2fSWarner Losh /* 2269d2155f2fSWarner Losh * Stop all chip I/O so that the kernel's probe routines don't 2270d2155f2fSWarner Losh * get confused by errant DMAs when rebooting. 2271d2155f2fSWarner Losh */ 2272e436c382SWarner Losh static int 2273d2155f2fSWarner Losh sis_shutdown(device_t dev) 2274d2155f2fSWarner Losh { 2275d2155f2fSWarner Losh 22760af3989bSPyun YongHyeon return (sis_suspend(dev)); 2277d2155f2fSWarner Losh } 2278d2155f2fSWarner Losh 22797968da57SPyun YongHyeon static int 22807968da57SPyun YongHyeon sis_suspend(device_t dev) 22817968da57SPyun YongHyeon { 22827968da57SPyun YongHyeon struct sis_softc *sc; 22837968da57SPyun YongHyeon 22847968da57SPyun YongHyeon sc = device_get_softc(dev); 22857968da57SPyun YongHyeon SIS_LOCK(sc); 22867968da57SPyun YongHyeon sis_stop(sc); 22870af3989bSPyun YongHyeon sis_wol(sc); 22887968da57SPyun YongHyeon SIS_UNLOCK(sc); 22897968da57SPyun YongHyeon return (0); 22907968da57SPyun YongHyeon } 22917968da57SPyun YongHyeon 22927968da57SPyun YongHyeon static int 22937968da57SPyun YongHyeon sis_resume(device_t dev) 22947968da57SPyun YongHyeon { 22957968da57SPyun YongHyeon struct sis_softc *sc; 2296*1125d093SJustin Hibbits if_t ifp; 22977968da57SPyun YongHyeon 22987968da57SPyun YongHyeon sc = device_get_softc(dev); 22997968da57SPyun YongHyeon SIS_LOCK(sc); 23007968da57SPyun YongHyeon ifp = sc->sis_ifp; 2301*1125d093SJustin Hibbits if ((if_getflags(ifp) & IFF_UP) != 0) { 2302*1125d093SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 23037968da57SPyun YongHyeon sis_initl(sc); 23047968da57SPyun YongHyeon } 23057968da57SPyun YongHyeon SIS_UNLOCK(sc); 23067968da57SPyun YongHyeon return (0); 23077968da57SPyun YongHyeon } 23087968da57SPyun YongHyeon 230994222398SPyun YongHyeon static void 23100af3989bSPyun YongHyeon sis_wol(struct sis_softc *sc) 23110af3989bSPyun YongHyeon { 2312*1125d093SJustin Hibbits if_t ifp; 23130af3989bSPyun YongHyeon uint32_t val; 23140af3989bSPyun YongHyeon uint16_t pmstat; 23150af3989bSPyun YongHyeon int pmc; 23160af3989bSPyun YongHyeon 23170af3989bSPyun YongHyeon ifp = sc->sis_ifp; 2318*1125d093SJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_WOL) == 0) 23190af3989bSPyun YongHyeon return; 23200af3989bSPyun YongHyeon 23210af3989bSPyun YongHyeon if (sc->sis_type == SIS_TYPE_83815) { 23220af3989bSPyun YongHyeon /* Reset RXDP. */ 23230af3989bSPyun YongHyeon CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); 23240af3989bSPyun YongHyeon 23250af3989bSPyun YongHyeon /* Configure WOL events. */ 23260af3989bSPyun YongHyeon CSR_READ_4(sc, NS_WCSR); 23270af3989bSPyun YongHyeon val = 0; 2328*1125d093SJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_WOL_UCAST) != 0) 23290af3989bSPyun YongHyeon val |= NS_WCSR_WAKE_UCAST; 2330*1125d093SJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_WOL_MCAST) != 0) 23310af3989bSPyun YongHyeon val |= NS_WCSR_WAKE_MCAST; 2332*1125d093SJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0) 23330af3989bSPyun YongHyeon val |= NS_WCSR_WAKE_MAGIC; 23340af3989bSPyun YongHyeon CSR_WRITE_4(sc, NS_WCSR, val); 23350af3989bSPyun YongHyeon /* Enable PME and clear PMESTS. */ 23360af3989bSPyun YongHyeon val = CSR_READ_4(sc, NS_CLKRUN); 23370af3989bSPyun YongHyeon val |= NS_CLKRUN_PMEENB | NS_CLKRUN_PMESTS; 23380af3989bSPyun YongHyeon CSR_WRITE_4(sc, NS_CLKRUN, val); 23390af3989bSPyun YongHyeon /* Enable silent RX mode. */ 23400af3989bSPyun YongHyeon SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 23410af3989bSPyun YongHyeon } else { 23423b0a4aefSJohn Baldwin if (pci_find_cap(sc->sis_dev, PCIY_PMG, &pmc) != 0) 23430af3989bSPyun YongHyeon return; 23440af3989bSPyun YongHyeon val = 0; 2345*1125d093SJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0) 23460af3989bSPyun YongHyeon val |= SIS_PWRMAN_WOL_MAGIC; 23470af3989bSPyun YongHyeon CSR_WRITE_4(sc, SIS_PWRMAN_CTL, val); 23480af3989bSPyun YongHyeon /* Request PME. */ 23490af3989bSPyun YongHyeon pmstat = pci_read_config(sc->sis_dev, 23500af3989bSPyun YongHyeon pmc + PCIR_POWER_STATUS, 2); 23510af3989bSPyun YongHyeon pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE); 2352*1125d093SJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_WOL_MAGIC) != 0) 23530af3989bSPyun YongHyeon pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE; 23540af3989bSPyun YongHyeon pci_write_config(sc->sis_dev, 23550af3989bSPyun YongHyeon pmc + PCIR_POWER_STATUS, pmstat, 2); 23560af3989bSPyun YongHyeon } 23570af3989bSPyun YongHyeon } 23580af3989bSPyun YongHyeon 23590af3989bSPyun YongHyeon static void 236094222398SPyun YongHyeon sis_add_sysctls(struct sis_softc *sc) 236194222398SPyun YongHyeon { 236294222398SPyun YongHyeon struct sysctl_ctx_list *ctx; 236394222398SPyun YongHyeon struct sysctl_oid_list *children; 236494222398SPyun YongHyeon 236594222398SPyun YongHyeon ctx = device_get_sysctl_ctx(sc->sis_dev); 236694222398SPyun YongHyeon children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sis_dev)); 236794222398SPyun YongHyeon 236894222398SPyun YongHyeon /* 236994222398SPyun YongHyeon * Unlike most other controllers, NS DP83815/DP83816 controllers 237094222398SPyun YongHyeon * seem to pad with 0xFF when it encounter short frames. According 237194222398SPyun YongHyeon * to RFC 1042 the pad bytes should be 0x00. Turning this tunable 237294222398SPyun YongHyeon * on will have driver pad manully but it's disabled by default 237394222398SPyun YongHyeon * because it will consume extra CPU cycles for short frames. 237494222398SPyun YongHyeon */ 237594222398SPyun YongHyeon sc->sis_manual_pad = 0; 237694222398SPyun YongHyeon SYSCTL_ADD_INT(ctx, children, OID_AUTO, "manual_pad", 2377af3b2549SHans Petter Selasky CTLFLAG_RWTUN, &sc->sis_manual_pad, 0, "Manually pad short frames"); 237894222398SPyun YongHyeon } 237994222398SPyun YongHyeon 2380d2155f2fSWarner Losh static device_method_t sis_methods[] = { 2381d2155f2fSWarner Losh /* Device interface */ 2382d2155f2fSWarner Losh DEVMETHOD(device_probe, sis_probe), 2383d2155f2fSWarner Losh DEVMETHOD(device_attach, sis_attach), 2384d2155f2fSWarner Losh DEVMETHOD(device_detach, sis_detach), 2385d2155f2fSWarner Losh DEVMETHOD(device_shutdown, sis_shutdown), 23867968da57SPyun YongHyeon DEVMETHOD(device_suspend, sis_suspend), 23877968da57SPyun YongHyeon DEVMETHOD(device_resume, sis_resume), 2388d2155f2fSWarner Losh 2389d2155f2fSWarner Losh /* MII interface */ 2390d2155f2fSWarner Losh DEVMETHOD(miibus_readreg, sis_miibus_readreg), 2391d2155f2fSWarner Losh DEVMETHOD(miibus_writereg, sis_miibus_writereg), 2392d2155f2fSWarner Losh DEVMETHOD(miibus_statchg, sis_miibus_statchg), 2393d2155f2fSWarner Losh 23944b7ec270SMarius Strobl DEVMETHOD_END 2395d2155f2fSWarner Losh }; 2396d2155f2fSWarner Losh 2397d2155f2fSWarner Losh static driver_t sis_driver = { 2398d2155f2fSWarner Losh "sis", 2399d2155f2fSWarner Losh sis_methods, 2400d2155f2fSWarner Losh sizeof(struct sis_softc) 2401d2155f2fSWarner Losh }; 2402d2155f2fSWarner Losh 24039a0b4345SJohn Baldwin DRIVER_MODULE(sis, pci, sis_driver, 0, 0); 24043e38757dSJohn Baldwin DRIVER_MODULE(miibus, sis, miibus_driver, 0, 0); 2405