if_sis.c revision 101464
1238405Sjkim/* 2238405Sjkim * Copyright (c) 1997, 1998, 1999 3238405Sjkim * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4238405Sjkim * 5238405Sjkim * Redistribution and use in source and binary forms, with or without 6238405Sjkim * modification, are permitted provided that the following conditions 7238405Sjkim * are met: 8238405Sjkim * 1. Redistributions of source code must retain the above copyright 9238405Sjkim * notice, this list of conditions and the following disclaimer. 10238405Sjkim * 2. Redistributions in binary form must reproduce the above copyright 11238405Sjkim * notice, this list of conditions and the following disclaimer in the 12238405Sjkim * documentation and/or other materials provided with the distribution. 13238405Sjkim * 3. All advertising materials mentioning features or use of this software 14238405Sjkim * must display the following acknowledgement: 15238405Sjkim * This product includes software developed by Bill Paul. 16238405Sjkim * 4. Neither the name of the author nor the names of any co-contributors 17238405Sjkim * may be used to endorse or promote products derived from this software 18238405Sjkim * without specific prior written permission. 19238405Sjkim * 20238405Sjkim * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21238405Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22238405Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23238405Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24238405Sjkim * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25238405Sjkim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26238405Sjkim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27238405Sjkim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28238405Sjkim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29238405Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30238405Sjkim * THE POSSIBILITY OF SUCH DAMAGE. 31238405Sjkim * 32238405Sjkim * $FreeBSD: head/sys/pci/if_sis.c 101464 2002-08-07 16:08:54Z luigi $ 33238405Sjkim */ 34238405Sjkim 35238405Sjkim/* 36238405Sjkim * SiS 900/SiS 7016 fast ethernet PCI NIC driver. Datasheets are 37238405Sjkim * available from http://www.sis.com.tw. 38238405Sjkim * 39238405Sjkim * This driver also supports the NatSemi DP83815. Datasheets are 40238405Sjkim * available from http://www.national.com. 41238405Sjkim * 42238405Sjkim * Written by Bill Paul <wpaul@ee.columbia.edu> 43238405Sjkim * Electrical Engineering Department 44238405Sjkim * Columbia University, New York City 45238405Sjkim */ 46238405Sjkim 47238405Sjkim/* 48238405Sjkim * The SiS 900 is a fairly simple chip. It uses bus master DMA with 49238405Sjkim * simple TX and RX descriptors of 3 longwords in size. The receiver 50238405Sjkim * has a single perfect filter entry for the station address and a 51238405Sjkim * 128-bit multicast hash table. The SiS 900 has a built-in MII-based 52238405Sjkim * transceiver while the 7016 requires an external transceiver chip. 53238405Sjkim * Both chips offer the standard bit-bang MII interface as well as 54238405Sjkim * an enchanced PHY interface which simplifies accessing MII registers. 55238405Sjkim * 56238405Sjkim * The only downside to this chipset is that RX descriptors must be 57238405Sjkim * longword aligned. 58238405Sjkim */ 59238405Sjkim 60238405Sjkim#include <sys/param.h> 61238405Sjkim#include <sys/systm.h> 62238405Sjkim#include <sys/sockio.h> 63238405Sjkim#include <sys/mbuf.h> 64238405Sjkim#include <sys/malloc.h> 65238405Sjkim#include <sys/kernel.h> 66238405Sjkim#include <sys/socket.h> 67238405Sjkim#include <sys/sysctl.h> 68238405Sjkim 69238405Sjkim#include <net/if.h> 70238405Sjkim#include <net/if_arp.h> 71238405Sjkim#include <net/ethernet.h> 72238405Sjkim#include <net/if_dl.h> 73238405Sjkim#include <net/if_media.h> 74238405Sjkim#include <net/if_types.h> 75238405Sjkim#include <net/if_vlan_var.h> 76238405Sjkim 77238405Sjkim#include <net/bpf.h> 78238405Sjkim 79238405Sjkim#include <machine/bus_pio.h> 80238405Sjkim#include <machine/bus_memio.h> 81238405Sjkim#include <machine/bus.h> 82238405Sjkim#include <machine/resource.h> 83238405Sjkim#include <sys/bus.h> 84238405Sjkim#include <sys/rman.h> 85238405Sjkim 86238405Sjkim#include <dev/mii/mii.h> 87238405Sjkim#include <dev/mii/miivar.h> 88238405Sjkim 89238405Sjkim#include <pci/pcireg.h> 90238405Sjkim#include <pci/pcivar.h> 91238405Sjkim 92238405Sjkim#define SIS_USEIOSPACE 93238405Sjkim 94238405Sjkim#include <pci/if_sisreg.h> 95238405Sjkim 96238405SjkimMODULE_DEPEND(sis, miibus, 1, 1, 1); 97238405Sjkim 98238405Sjkim/* "controller miibus0" required. See GENERIC if you get errors here. */ 99238405Sjkim#include "miibus_if.h" 100238405Sjkim 101238405Sjkim#ifndef lint 102238405Sjkimstatic const char rcsid[] = 103238405Sjkim "$FreeBSD: head/sys/pci/if_sis.c 101464 2002-08-07 16:08:54Z luigi $"; 104238405Sjkim#endif 105238405Sjkim 106238405Sjkim/* 107238405Sjkim * Various supported device vendors/types and their names. 108238405Sjkim */ 109238405Sjkimstatic struct sis_type sis_devs[] = { 110238405Sjkim { SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" }, 111238405Sjkim { SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" }, 112238405Sjkim { NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP83815 10/100BaseTX" }, 113238405Sjkim { 0, 0, NULL } 114238405Sjkim}; 115238405Sjkim 116238405Sjkimstatic int sis_probe (device_t); 117238405Sjkimstatic int sis_attach (device_t); 118238405Sjkimstatic int sis_detach (device_t); 119238405Sjkim 120238405Sjkimstatic int sis_newbuf (struct sis_softc *, 121238405Sjkim struct sis_desc *, struct mbuf *); 122238405Sjkimstatic int sis_encap (struct sis_softc *, 123238405Sjkim struct mbuf *, u_int32_t *); 124238405Sjkimstatic void sis_rxeof (struct sis_softc *); 125238405Sjkimstatic void sis_rxeoc (struct sis_softc *); 126238405Sjkimstatic void sis_txeof (struct sis_softc *); 127238405Sjkimstatic void sis_intr (void *); 128238405Sjkimstatic void sis_tick (void *); 129238405Sjkimstatic void sis_start (struct ifnet *); 130238405Sjkimstatic int sis_ioctl (struct ifnet *, u_long, caddr_t); 131238405Sjkimstatic void sis_init (void *); 132238405Sjkimstatic void sis_stop (struct sis_softc *); 133238405Sjkimstatic void sis_watchdog (struct ifnet *); 134238405Sjkimstatic void sis_shutdown (device_t); 135238405Sjkimstatic int sis_ifmedia_upd (struct ifnet *); 136238405Sjkimstatic void sis_ifmedia_sts (struct ifnet *, struct ifmediareq *); 137238405Sjkim 138238405Sjkimstatic u_int16_t sis_reverse (u_int16_t); 139238405Sjkimstatic void sis_delay (struct sis_softc *); 140238405Sjkimstatic void sis_eeprom_idle (struct sis_softc *); 141238405Sjkimstatic void sis_eeprom_putbyte (struct sis_softc *, int); 142238405Sjkimstatic void sis_eeprom_getword (struct sis_softc *, int, u_int16_t *); 143238405Sjkimstatic void sis_read_eeprom (struct sis_softc *, caddr_t, int, int, int); 144238405Sjkim#ifdef __i386__ 145238405Sjkimstatic void sis_read_cmos (struct sis_softc *, device_t, caddr_t, 146238405Sjkim int, int); 147238405Sjkimstatic void sis_read_mac (struct sis_softc *, device_t, caddr_t); 148238405Sjkimstatic device_t sis_find_bridge (device_t); 149238405Sjkim#endif 150238405Sjkim 151238405Sjkimstatic int sis_miibus_readreg (device_t, int, int); 152238405Sjkimstatic int sis_miibus_writereg (device_t, int, int, int); 153238405Sjkimstatic void sis_miibus_statchg (device_t); 154238405Sjkim 155238405Sjkimstatic void sis_setmulti_sis (struct sis_softc *); 156238405Sjkimstatic void sis_setmulti_ns (struct sis_softc *); 157238405Sjkimstatic u_int32_t sis_crc (struct sis_softc *, caddr_t); 158238405Sjkimstatic void sis_reset (struct sis_softc *); 159238405Sjkimstatic int sis_list_rx_init (struct sis_softc *); 160238405Sjkimstatic int sis_list_tx_init (struct sis_softc *); 161238405Sjkim 162238405Sjkimstatic void sis_dma_map_desc_ptr (void *, bus_dma_segment_t *, int, int); 163238405Sjkimstatic void sis_dma_map_desc_next (void *, bus_dma_segment_t *, int, int); 164238405Sjkimstatic void sis_dma_map_ring (void *, bus_dma_segment_t *, int, int); 165238405Sjkim#ifdef SIS_USEIOSPACE 166238405Sjkim#define SIS_RES SYS_RES_IOPORT 167238405Sjkim#define SIS_RID SIS_PCI_LOIO 168238405Sjkim#else 169238405Sjkim#define SIS_RES SYS_RES_MEMORY 170238405Sjkim#define SIS_RID SIS_PCI_LOMEM 171238405Sjkim#endif 172238405Sjkim 173238405Sjkimstatic device_method_t sis_methods[] = { 174238405Sjkim /* Device interface */ 175238405Sjkim DEVMETHOD(device_probe, sis_probe), 176238405Sjkim DEVMETHOD(device_attach, sis_attach), 177238405Sjkim DEVMETHOD(device_detach, sis_detach), 178238405Sjkim DEVMETHOD(device_shutdown, sis_shutdown), 179238405Sjkim 180238405Sjkim /* bus interface */ 181238405Sjkim DEVMETHOD(bus_print_child, bus_generic_print_child), 182238405Sjkim DEVMETHOD(bus_driver_added, bus_generic_driver_added), 183238405Sjkim 184238405Sjkim /* MII interface */ 185238405Sjkim DEVMETHOD(miibus_readreg, sis_miibus_readreg), 186238405Sjkim DEVMETHOD(miibus_writereg, sis_miibus_writereg), 187238405Sjkim DEVMETHOD(miibus_statchg, sis_miibus_statchg), 188238405Sjkim 189238405Sjkim { 0, 0 } 190238405Sjkim}; 191238405Sjkim 192238405Sjkimstatic driver_t sis_driver = { 193238405Sjkim "sis", 194238405Sjkim sis_methods, 195238405Sjkim sizeof(struct sis_softc) 196238405Sjkim}; 197238405Sjkim 198238405Sjkimstatic devclass_t sis_devclass; 199238405Sjkim 200238405SjkimDRIVER_MODULE(if_sis, pci, sis_driver, sis_devclass, 0, 0); 201238405SjkimDRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0); 202238405Sjkim 203238405Sjkim#define SIS_SETBIT(sc, reg, x) \ 204238405Sjkim CSR_WRITE_4(sc, reg, \ 205238405Sjkim CSR_READ_4(sc, reg) | (x)) 206238405Sjkim 207238405Sjkim#define SIS_CLRBIT(sc, reg, x) \ 208238405Sjkim CSR_WRITE_4(sc, reg, \ 209238405Sjkim CSR_READ_4(sc, reg) & ~(x)) 210238405Sjkim 211238405Sjkim#define SIO_SET(x) \ 212238405Sjkim CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) | x) 213238405Sjkim 214238405Sjkim#define SIO_CLR(x) \ 215238405Sjkim CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x) 216238405Sjkim 217238405Sjkimstatic void 218238405Sjkimsis_dma_map_desc_next(arg, segs, nseg, error) 219238405Sjkim void *arg; 220238405Sjkim bus_dma_segment_t *segs; 221238405Sjkim int nseg, error; 222238405Sjkim{ 223238405Sjkim struct sis_desc *r; 224238405Sjkim 225238405Sjkim r = arg; 226238405Sjkim r->sis_next = segs->ds_addr; 227238405Sjkim 228238405Sjkim return; 229238405Sjkim} 230238405Sjkim 231238405Sjkimstatic void 232238405Sjkimsis_dma_map_desc_ptr(arg, segs, nseg, error) 233238405Sjkim void *arg; 234238405Sjkim bus_dma_segment_t *segs; 235238405Sjkim int nseg, error; 236238405Sjkim{ 237238405Sjkim struct sis_desc *r; 238238405Sjkim 239238405Sjkim r = arg; 240238405Sjkim r->sis_ptr = segs->ds_addr; 241238405Sjkim 242238405Sjkim return; 243238405Sjkim} 244238405Sjkim 245238405Sjkimstatic void 246238405Sjkimsis_dma_map_ring(arg, segs, nseg, error) 247238405Sjkim void *arg; 248238405Sjkim bus_dma_segment_t *segs; 249238405Sjkim int nseg, error; 250238405Sjkim{ 251238405Sjkim u_int32_t *p; 252238405Sjkim 253238405Sjkim p = arg; 254238405Sjkim *p = segs->ds_addr; 255238405Sjkim 256238405Sjkim return; 257238405Sjkim} 258238405Sjkim 259238405Sjkim/* 260238405Sjkim * Routine to reverse the bits in a word. Stolen almost 261238405Sjkim * verbatim from /usr/games/fortune. 262238405Sjkim */ 263238405Sjkimstatic u_int16_t sis_reverse(n) 264238405Sjkim u_int16_t n; 265238405Sjkim{ 266238405Sjkim n = ((n >> 1) & 0x5555) | ((n << 1) & 0xaaaa); 267238405Sjkim n = ((n >> 2) & 0x3333) | ((n << 2) & 0xcccc); 268238405Sjkim n = ((n >> 4) & 0x0f0f) | ((n << 4) & 0xf0f0); 269238405Sjkim n = ((n >> 8) & 0x00ff) | ((n << 8) & 0xff00); 270238405Sjkim 271238405Sjkim return(n); 272238405Sjkim} 273238405Sjkim 274238405Sjkimstatic void sis_delay(sc) 275238405Sjkim struct sis_softc *sc; 276238405Sjkim{ 277238405Sjkim int idx; 278238405Sjkim 279238405Sjkim for (idx = (300 / 33) + 1; idx > 0; idx--) 280238405Sjkim CSR_READ_4(sc, SIS_CSR); 281238405Sjkim 282238405Sjkim return; 283238405Sjkim} 284238405Sjkim 285238405Sjkimstatic void sis_eeprom_idle(sc) 286238405Sjkim struct sis_softc *sc; 287238405Sjkim{ 288238405Sjkim register int i; 289238405Sjkim 290238405Sjkim SIO_SET(SIS_EECTL_CSEL); 291238405Sjkim sis_delay(sc); 292238405Sjkim SIO_SET(SIS_EECTL_CLK); 293238405Sjkim sis_delay(sc); 294238405Sjkim 295238405Sjkim for (i = 0; i < 25; i++) { 296238405Sjkim SIO_CLR(SIS_EECTL_CLK); 297238405Sjkim sis_delay(sc); 298238405Sjkim SIO_SET(SIS_EECTL_CLK); 299238405Sjkim sis_delay(sc); 300238405Sjkim } 301238405Sjkim 302238405Sjkim SIO_CLR(SIS_EECTL_CLK); 303238405Sjkim sis_delay(sc); 304238405Sjkim SIO_CLR(SIS_EECTL_CSEL); 305238405Sjkim sis_delay(sc); 306238405Sjkim CSR_WRITE_4(sc, SIS_EECTL, 0x00000000); 307238405Sjkim 308238405Sjkim return; 309238405Sjkim} 310238405Sjkim 311238405Sjkim/* 312238405Sjkim * Send a read command and address to the EEPROM, check for ACK. 313238405Sjkim */ 314238405Sjkimstatic void sis_eeprom_putbyte(sc, addr) 315238405Sjkim struct sis_softc *sc; 316238405Sjkim int addr; 317238405Sjkim{ 318238405Sjkim register int d, i; 319238405Sjkim 320238405Sjkim d = addr | SIS_EECMD_READ; 321238405Sjkim 322238405Sjkim /* 323238405Sjkim * Feed in each bit and stobe the clock. 324238405Sjkim */ 325238405Sjkim for (i = 0x400; i; i >>= 1) { 326238405Sjkim if (d & i) { 327238405Sjkim SIO_SET(SIS_EECTL_DIN); 328238405Sjkim } else { 329238405Sjkim SIO_CLR(SIS_EECTL_DIN); 330238405Sjkim } 331238405Sjkim sis_delay(sc); 332238405Sjkim SIO_SET(SIS_EECTL_CLK); 333238405Sjkim sis_delay(sc); 334238405Sjkim SIO_CLR(SIS_EECTL_CLK); 335238405Sjkim sis_delay(sc); 336238405Sjkim } 337238405Sjkim 338238405Sjkim return; 339238405Sjkim} 340238405Sjkim 341238405Sjkim/* 342238405Sjkim * Read a word of data stored in the EEPROM at address 'addr.' 343238405Sjkim */ 344238405Sjkimstatic void sis_eeprom_getword(sc, addr, dest) 345238405Sjkim struct sis_softc *sc; 346238405Sjkim int addr; 347238405Sjkim u_int16_t *dest; 348238405Sjkim{ 349238405Sjkim register int i; 350238405Sjkim u_int16_t word = 0; 351238405Sjkim 352238405Sjkim /* Force EEPROM to idle state. */ 353238405Sjkim sis_eeprom_idle(sc); 354238405Sjkim 355238405Sjkim /* Enter EEPROM access mode. */ 356238405Sjkim sis_delay(sc); 357238405Sjkim SIO_CLR(SIS_EECTL_CLK); 358238405Sjkim sis_delay(sc); 359238405Sjkim SIO_SET(SIS_EECTL_CSEL); 360238405Sjkim sis_delay(sc); 361238405Sjkim 362238405Sjkim /* 363238405Sjkim * Send address of word we want to read. 364238405Sjkim */ 365238405Sjkim sis_eeprom_putbyte(sc, addr); 366238405Sjkim 367238405Sjkim /* 368238405Sjkim * Start reading bits from EEPROM. 369238405Sjkim */ 370238405Sjkim for (i = 0x8000; i; i >>= 1) { 371238405Sjkim SIO_SET(SIS_EECTL_CLK); 372238405Sjkim sis_delay(sc); 373238405Sjkim if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECTL_DOUT) 374238405Sjkim word |= i; 375238405Sjkim sis_delay(sc); 376238405Sjkim SIO_CLR(SIS_EECTL_CLK); 377238405Sjkim sis_delay(sc); 378238405Sjkim } 379238405Sjkim 380238405Sjkim /* Turn off EEPROM access mode. */ 381238405Sjkim sis_eeprom_idle(sc); 382238405Sjkim 383238405Sjkim *dest = word; 384238405Sjkim 385238405Sjkim return; 386238405Sjkim} 387238405Sjkim 388238405Sjkim/* 389238405Sjkim * Read a sequence of words from the EEPROM. 390238405Sjkim */ 391238405Sjkimstatic void sis_read_eeprom(sc, dest, off, cnt, swap) 392238405Sjkim struct sis_softc *sc; 393238405Sjkim caddr_t dest; 394238405Sjkim int off; 395238405Sjkim int cnt; 396238405Sjkim int swap; 397238405Sjkim{ 398238405Sjkim int i; 399238405Sjkim u_int16_t word = 0, *ptr; 400238405Sjkim 401238405Sjkim for (i = 0; i < cnt; i++) { 402238405Sjkim sis_eeprom_getword(sc, off + i, &word); 403238405Sjkim ptr = (u_int16_t *)(dest + (i * 2)); 404238405Sjkim if (swap) 405238405Sjkim *ptr = ntohs(word); 406238405Sjkim else 407238405Sjkim *ptr = word; 408238405Sjkim } 409238405Sjkim 410238405Sjkim return; 411238405Sjkim} 412238405Sjkim 413238405Sjkim#ifdef __i386__ 414238405Sjkimstatic device_t sis_find_bridge(dev) 415238405Sjkim device_t dev; 416238405Sjkim{ 417238405Sjkim devclass_t pci_devclass; 418238405Sjkim device_t *pci_devices; 419238405Sjkim int pci_count = 0; 420238405Sjkim device_t *pci_children; 421238405Sjkim int pci_childcount = 0; 422238405Sjkim device_t *busp, *childp; 423238405Sjkim device_t child = NULL; 424238405Sjkim int i, j; 425238405Sjkim 426238405Sjkim if ((pci_devclass = devclass_find("pci")) == NULL) 427238405Sjkim return(NULL); 428238405Sjkim 429238405Sjkim devclass_get_devices(pci_devclass, &pci_devices, &pci_count); 430238405Sjkim 431238405Sjkim for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) { 432238405Sjkim pci_childcount = 0; 433238405Sjkim device_get_children(*busp, &pci_children, &pci_childcount); 434238405Sjkim for (j = 0, childp = pci_children; 435238405Sjkim j < pci_childcount; j++, childp++) { 436238405Sjkim if (pci_get_vendor(*childp) == SIS_VENDORID && 437238405Sjkim pci_get_device(*childp) == 0x0008) { 438238405Sjkim child = *childp; 439238405Sjkim goto done; 440238405Sjkim } 441238405Sjkim } 442238405Sjkim } 443238405Sjkim 444238405Sjkimdone: 445238405Sjkim free(pci_devices, M_TEMP); 446238405Sjkim free(pci_children, M_TEMP); 447238405Sjkim return(child); 448238405Sjkim} 449238405Sjkim 450238405Sjkimstatic void sis_read_cmos(sc, dev, dest, off, cnt) 451238405Sjkim struct sis_softc *sc; 452238405Sjkim device_t dev; 453238405Sjkim caddr_t dest; 454238405Sjkim int off; 455238405Sjkim int cnt; 456238405Sjkim{ 457238405Sjkim device_t bridge; 458238405Sjkim u_int8_t reg; 459238405Sjkim int i; 460238405Sjkim bus_space_tag_t btag; 461238405Sjkim 462238405Sjkim bridge = sis_find_bridge(dev); 463238405Sjkim if (bridge == NULL) 464238405Sjkim return; 465238405Sjkim reg = pci_read_config(bridge, 0x48, 1); 466238405Sjkim pci_write_config(bridge, 0x48, reg|0x40, 1); 467238405Sjkim 468238405Sjkim /* XXX */ 469238405Sjkim btag = I386_BUS_SPACE_IO; 470238405Sjkim 471238405Sjkim for (i = 0; i < cnt; i++) { 472238405Sjkim bus_space_write_1(btag, 0x0, 0x70, i + off); 473238405Sjkim *(dest + i) = bus_space_read_1(btag, 0x0, 0x71); 474238405Sjkim } 475238405Sjkim 476238405Sjkim pci_write_config(bridge, 0x48, reg & ~0x40, 1); 477238405Sjkim return; 478238405Sjkim} 479238405Sjkim 480238405Sjkimstatic void sis_read_mac(sc, dev, dest) 481238405Sjkim struct sis_softc *sc; 482238405Sjkim device_t dev; 483238405Sjkim caddr_t dest; 484238405Sjkim{ 485238405Sjkim u_int32_t filtsave, csrsave; 486238405Sjkim 487238405Sjkim filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); 488238405Sjkim csrsave = CSR_READ_4(sc, SIS_CSR); 489238405Sjkim 490238405Sjkim CSR_WRITE_4(sc, SIS_CSR, SIS_CSR_RELOAD | filtsave); 491238405Sjkim CSR_WRITE_4(sc, SIS_CSR, 0); 492238405Sjkim 493238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE); 494238405Sjkim 495238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 496238405Sjkim ((u_int16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA); 497238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1); 498238405Sjkim ((u_int16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA); 499238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 500238405Sjkim ((u_int16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA); 501238405Sjkim 502238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); 503238405Sjkim CSR_WRITE_4(sc, SIS_CSR, csrsave); 504238405Sjkim return; 505238405Sjkim} 506238405Sjkim#endif 507238405Sjkim 508238405Sjkimstatic int sis_miibus_readreg(dev, phy, reg) 509238405Sjkim device_t dev; 510238405Sjkim int phy, reg; 511238405Sjkim{ 512238405Sjkim struct sis_softc *sc; 513238405Sjkim int i, val = 0; 514238405Sjkim 515238405Sjkim sc = device_get_softc(dev); 516238405Sjkim 517238405Sjkim if (sc->sis_type == SIS_TYPE_83815) { 518238405Sjkim if (phy != 0) 519238405Sjkim return(0); 520238405Sjkim /* 521238405Sjkim * The NatSemi chip can take a while after 522238405Sjkim * a reset to come ready, during which the BMSR 523238405Sjkim * returns a value of 0. This is *never* supposed 524238405Sjkim * to happen: some of the BMSR bits are meant to 525238405Sjkim * be hardwired in the on position, and this can 526238405Sjkim * confuse the miibus code a bit during the probe 527238405Sjkim * and attach phase. So we make an effort to check 528238405Sjkim * for this condition and wait for it to clear. 529238405Sjkim */ 530238405Sjkim if (!CSR_READ_4(sc, NS_BMSR)) 531238405Sjkim DELAY(1000); 532238405Sjkim val = CSR_READ_4(sc, NS_BMCR + (reg * 4)); 533238405Sjkim return(val); 534238405Sjkim } 535238405Sjkim 536238405Sjkim if (sc->sis_type == SIS_TYPE_900 && 537238405Sjkim sc->sis_rev < SIS_REV_635 && phy != 0) 538238405Sjkim return(0); 539238405Sjkim 540238405Sjkim CSR_WRITE_4(sc, SIS_PHYCTL, (phy << 11) | (reg << 6) | SIS_PHYOP_READ); 541238405Sjkim SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS); 542238405Sjkim 543238405Sjkim for (i = 0; i < SIS_TIMEOUT; i++) { 544238405Sjkim if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS)) 545238405Sjkim break; 546238405Sjkim } 547238405Sjkim 548238405Sjkim if (i == SIS_TIMEOUT) { 549238405Sjkim printf("sis%d: PHY failed to come ready\n", sc->sis_unit); 550238405Sjkim return(0); 551238405Sjkim } 552238405Sjkim 553238405Sjkim val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF; 554238405Sjkim 555238405Sjkim if (val == 0xFFFF) 556238405Sjkim return(0); 557238405Sjkim 558238405Sjkim return(val); 559238405Sjkim} 560238405Sjkim 561238405Sjkimstatic int sis_miibus_writereg(dev, phy, reg, data) 562238405Sjkim device_t dev; 563238405Sjkim int phy, reg, data; 564238405Sjkim{ 565238405Sjkim struct sis_softc *sc; 566238405Sjkim int i; 567238405Sjkim 568238405Sjkim sc = device_get_softc(dev); 569238405Sjkim 570238405Sjkim if (sc->sis_type == SIS_TYPE_83815) { 571238405Sjkim if (phy != 0) 572238405Sjkim return(0); 573238405Sjkim CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data); 574238405Sjkim return(0); 575238405Sjkim } 576238405Sjkim 577238405Sjkim if (sc->sis_type == SIS_TYPE_900 && phy != 0) 578238405Sjkim return(0); 579238405Sjkim 580238405Sjkim CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) | 581238405Sjkim (reg << 6) | SIS_PHYOP_WRITE); 582238405Sjkim SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS); 583238405Sjkim 584238405Sjkim for (i = 0; i < SIS_TIMEOUT; i++) { 585238405Sjkim if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS)) 586238405Sjkim break; 587238405Sjkim } 588238405Sjkim 589238405Sjkim if (i == SIS_TIMEOUT) 590238405Sjkim printf("sis%d: PHY failed to come ready\n", sc->sis_unit); 591238405Sjkim 592238405Sjkim return(0); 593238405Sjkim} 594238405Sjkim 595238405Sjkimstatic void sis_miibus_statchg(dev) 596238405Sjkim device_t dev; 597238405Sjkim{ 598238405Sjkim struct sis_softc *sc; 599238405Sjkim 600238405Sjkim sc = device_get_softc(dev); 601238405Sjkim sis_init(sc); 602238405Sjkim 603238405Sjkim return; 604238405Sjkim} 605238405Sjkim 606238405Sjkimstatic u_int32_t sis_crc(sc, addr) 607238405Sjkim struct sis_softc *sc; 608238405Sjkim caddr_t addr; 609238405Sjkim{ 610238405Sjkim u_int32_t crc, carry; 611238405Sjkim int i, j; 612238405Sjkim u_int8_t c; 613238405Sjkim 614238405Sjkim /* Compute CRC for the address value. */ 615238405Sjkim crc = 0xFFFFFFFF; /* initial value */ 616238405Sjkim 617238405Sjkim for (i = 0; i < 6; i++) { 618238405Sjkim c = *(addr + i); 619238405Sjkim for (j = 0; j < 8; j++) { 620238405Sjkim carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01); 621238405Sjkim crc <<= 1; 622238405Sjkim c >>= 1; 623238405Sjkim if (carry) 624238405Sjkim crc = (crc ^ 0x04c11db6) | carry; 625238405Sjkim } 626238405Sjkim } 627238405Sjkim 628238405Sjkim /* 629238405Sjkim * return the filter bit position 630238405Sjkim * 631238405Sjkim * The NatSemi chip has a 512-bit filter, which is 632238405Sjkim * different than the SiS, so we special-case it. 633238405Sjkim */ 634238405Sjkim if (sc->sis_type == SIS_TYPE_83815) 635238405Sjkim return((crc >> 23) & 0x1FF); 636238405Sjkim 637238405Sjkim return((crc >> 25) & 0x0000007F); 638238405Sjkim} 639238405Sjkim 640238405Sjkimstatic void sis_setmulti_ns(sc) 641238405Sjkim struct sis_softc *sc; 642238405Sjkim{ 643238405Sjkim struct ifnet *ifp; 644238405Sjkim struct ifmultiaddr *ifma; 645238405Sjkim u_int32_t h = 0, i, filtsave; 646238405Sjkim int bit, index; 647238405Sjkim 648238405Sjkim ifp = &sc->arpcom.ac_if; 649238405Sjkim 650238405Sjkim if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 651238405Sjkim SIS_CLRBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH); 652238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); 653238405Sjkim return; 654238405Sjkim } 655238405Sjkim 656238405Sjkim /* 657238405Sjkim * We have to explicitly enable the multicast hash table 658238405Sjkim * on the NatSemi chip if we want to use it, which we do. 659238405Sjkim */ 660238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH); 661238405Sjkim SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); 662238405Sjkim 663238405Sjkim filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); 664238405Sjkim 665238405Sjkim /* first, zot all the existing hash bits */ 666238405Sjkim for (i = 0; i < 32; i++) { 667238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + (i*2)); 668238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0); 669238405Sjkim } 670238405Sjkim 671238405Sjkim TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 672238405Sjkim if (ifma->ifma_addr->sa_family != AF_LINK) 673238405Sjkim continue; 674238405Sjkim h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 675238405Sjkim index = h >> 3; 676238405Sjkim bit = h & 0x1F; 677238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index); 678238405Sjkim if (bit > 0xF) 679238405Sjkim bit -= 0x10; 680238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit)); 681238405Sjkim } 682238405Sjkim 683238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); 684238405Sjkim 685238405Sjkim return; 686238405Sjkim} 687238405Sjkim 688238405Sjkimstatic void sis_setmulti_sis(sc) 689238405Sjkim struct sis_softc *sc; 690238405Sjkim{ 691238405Sjkim struct ifnet *ifp; 692238405Sjkim struct ifmultiaddr *ifma; 693238405Sjkim u_int32_t h = 0, i, filtsave; 694238405Sjkim 695238405Sjkim ifp = &sc->arpcom.ac_if; 696238405Sjkim 697238405Sjkim if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 698238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); 699238405Sjkim return; 700238405Sjkim } 701238405Sjkim 702238405Sjkim SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI); 703238405Sjkim 704238405Sjkim filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL); 705238405Sjkim 706238405Sjkim /* first, zot all the existing hash bits */ 707238405Sjkim for (i = 0; i < 8; i++) { 708238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + ((i * 16) >> 4)) << 16); 709238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0); 710238405Sjkim } 711238405Sjkim 712238405Sjkim /* now program new ones */ 713238405Sjkim TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 714238405Sjkim if (ifma->ifma_addr->sa_family != AF_LINK) 715238405Sjkim continue; 716238405Sjkim h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 717238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + (h >> 4)) << 16); 718238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << (h & 0xF))); 719238405Sjkim } 720238405Sjkim 721238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave); 722238405Sjkim 723238405Sjkim return; 724238405Sjkim} 725238405Sjkim 726238405Sjkimstatic void sis_reset(sc) 727238405Sjkim struct sis_softc *sc; 728238405Sjkim{ 729238405Sjkim register int i; 730238405Sjkim 731238405Sjkim SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RESET); 732238405Sjkim 733238405Sjkim for (i = 0; i < SIS_TIMEOUT; i++) { 734238405Sjkim if (!(CSR_READ_4(sc, SIS_CSR) & SIS_CSR_RESET)) 735238405Sjkim break; 736238405Sjkim } 737238405Sjkim 738238405Sjkim if (i == SIS_TIMEOUT) 739238405Sjkim printf("sis%d: reset never completed\n", sc->sis_unit); 740238405Sjkim 741238405Sjkim /* Wait a little while for the chip to get its brains in order. */ 742238405Sjkim DELAY(1000); 743238405Sjkim 744238405Sjkim /* 745238405Sjkim * If this is a NetSemi chip, make sure to clear 746238405Sjkim * PME mode. 747238405Sjkim */ 748238405Sjkim if (sc->sis_type == SIS_TYPE_83815) { 749238405Sjkim CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS); 750238405Sjkim CSR_WRITE_4(sc, NS_CLKRUN, 0); 751238405Sjkim } 752238405Sjkim 753238405Sjkim return; 754238405Sjkim} 755238405Sjkim 756238405Sjkim/* 757238405Sjkim * Probe for an SiS chip. Check the PCI vendor and device 758238405Sjkim * IDs against our list and return a device name if we find a match. 759238405Sjkim */ 760238405Sjkimstatic int sis_probe(dev) 761238405Sjkim device_t dev; 762238405Sjkim{ 763238405Sjkim struct sis_type *t; 764238405Sjkim 765238405Sjkim t = sis_devs; 766238405Sjkim 767238405Sjkim while(t->sis_name != NULL) { 768238405Sjkim if ((pci_get_vendor(dev) == t->sis_vid) && 769238405Sjkim (pci_get_device(dev) == t->sis_did)) { 770238405Sjkim device_set_desc(dev, t->sis_name); 771238405Sjkim return(0); 772238405Sjkim } 773238405Sjkim t++; 774238405Sjkim } 775238405Sjkim 776238405Sjkim return(ENXIO); 777238405Sjkim} 778238405Sjkim 779238405Sjkim/* 780238405Sjkim * Attach the interface. Allocate softc structures, do ifmedia 781238405Sjkim * setup and ethernet/BPF attach. 782238405Sjkim */ 783238405Sjkimstatic int sis_attach(dev) 784238405Sjkim device_t dev; 785238405Sjkim{ 786238405Sjkim u_char eaddr[ETHER_ADDR_LEN]; 787238405Sjkim u_int32_t command; 788238405Sjkim struct sis_softc *sc; 789238405Sjkim struct ifnet *ifp; 790238405Sjkim int unit, error = 0, rid; 791238405Sjkim 792238405Sjkim sc = device_get_softc(dev); 793238405Sjkim unit = device_get_unit(dev); 794238405Sjkim bzero(sc, sizeof(struct sis_softc)); 795238405Sjkim 796238405Sjkim mtx_init(&sc->sis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 797238405Sjkim MTX_DEF | MTX_RECURSE); 798238405Sjkim SIS_LOCK(sc); 799238405Sjkim 800238405Sjkim if (pci_get_device(dev) == SIS_DEVICEID_900) 801238405Sjkim sc->sis_type = SIS_TYPE_900; 802238405Sjkim if (pci_get_device(dev) == SIS_DEVICEID_7016) 803238405Sjkim sc->sis_type = SIS_TYPE_7016; 804238405Sjkim if (pci_get_vendor(dev) == NS_VENDORID) 805238405Sjkim sc->sis_type = SIS_TYPE_83815; 806238405Sjkim 807238405Sjkim sc->sis_rev = pci_read_config(dev, PCIR_REVID, 1); 808238405Sjkim 809238405Sjkim /* 810238405Sjkim * Handle power management nonsense. 811238405Sjkim */ 812238405Sjkim if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 813238405Sjkim u_int32_t iobase, membase, irq; 814238405Sjkim 815238405Sjkim /* Save important PCI config data. */ 816238405Sjkim iobase = pci_read_config(dev, SIS_PCI_LOIO, 4); 817238405Sjkim membase = pci_read_config(dev, SIS_PCI_LOMEM, 4); 818238405Sjkim irq = pci_read_config(dev, SIS_PCI_INTLINE, 4); 819238405Sjkim 820238405Sjkim /* Reset the power state. */ 821238405Sjkim printf("sis%d: chip is in D%d power mode " 822238405Sjkim "-- setting to D0\n", unit, 823238405Sjkim pci_get_powerstate(dev)); 824238405Sjkim pci_set_powerstate(dev, PCI_POWERSTATE_D0); 825238405Sjkim 826238405Sjkim /* Restore PCI config data. */ 827238405Sjkim pci_write_config(dev, SIS_PCI_LOIO, iobase, 4); 828238405Sjkim pci_write_config(dev, SIS_PCI_LOMEM, membase, 4); 829238405Sjkim pci_write_config(dev, SIS_PCI_INTLINE, irq, 4); 830238405Sjkim } 831238405Sjkim 832238405Sjkim /* 833238405Sjkim * Map control/status registers. 834238405Sjkim */ 835238405Sjkim pci_enable_busmaster(dev); 836238405Sjkim pci_enable_io(dev, SYS_RES_IOPORT); 837238405Sjkim pci_enable_io(dev, SYS_RES_MEMORY); 838238405Sjkim command = pci_read_config(dev, PCIR_COMMAND, 4); 839238405Sjkim 840238405Sjkim#ifdef SIS_USEIOSPACE 841238405Sjkim if (!(command & PCIM_CMD_PORTEN)) { 842238405Sjkim printf("sis%d: failed to enable I/O ports!\n", unit); 843238405Sjkim error = ENXIO;; 844238405Sjkim goto fail; 845238405Sjkim } 846238405Sjkim#else 847238405Sjkim if (!(command & PCIM_CMD_MEMEN)) { 848238405Sjkim printf("sis%d: failed to enable memory mapping!\n", unit); 849238405Sjkim error = ENXIO;; 850238405Sjkim goto fail; 851238405Sjkim } 852238405Sjkim#endif 853238405Sjkim 854238405Sjkim rid = SIS_RID; 855238405Sjkim sc->sis_res = bus_alloc_resource(dev, SIS_RES, &rid, 856238405Sjkim 0, ~0, 1, RF_ACTIVE); 857238405Sjkim 858238405Sjkim if (sc->sis_res == NULL) { 859238405Sjkim printf("sis%d: couldn't map ports/memory\n", unit); 860238405Sjkim error = ENXIO; 861238405Sjkim goto fail; 862238405Sjkim } 863238405Sjkim 864238405Sjkim sc->sis_btag = rman_get_bustag(sc->sis_res); 865238405Sjkim sc->sis_bhandle = rman_get_bushandle(sc->sis_res); 866238405Sjkim 867238405Sjkim /* Allocate interrupt */ 868238405Sjkim rid = 0; 869238405Sjkim sc->sis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 870238405Sjkim RF_SHAREABLE | RF_ACTIVE); 871238405Sjkim 872238405Sjkim if (sc->sis_irq == NULL) { 873238405Sjkim printf("sis%d: couldn't map interrupt\n", unit); 874238405Sjkim bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 875238405Sjkim error = ENXIO; 876238405Sjkim goto fail; 877238405Sjkim } 878238405Sjkim 879238405Sjkim error = bus_setup_intr(dev, sc->sis_irq, INTR_TYPE_NET, 880238405Sjkim sis_intr, sc, &sc->sis_intrhand); 881238405Sjkim 882238405Sjkim if (error) { 883238405Sjkim bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 884238405Sjkim bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 885238405Sjkim printf("sis%d: couldn't set up irq\n", unit); 886238405Sjkim goto fail; 887238405Sjkim } 888238405Sjkim 889238405Sjkim /* Reset the adapter. */ 890238405Sjkim sis_reset(sc); 891238405Sjkim 892238405Sjkim /* 893238405Sjkim * Get station address from the EEPROM. 894238405Sjkim */ 895238405Sjkim switch (pci_get_vendor(dev)) { 896238405Sjkim case NS_VENDORID: 897238405Sjkim /* 898238405Sjkim * Reading the MAC address out of the EEPROM on 899238405Sjkim * the NatSemi chip takes a bit more work than 900238405Sjkim * you'd expect. The address spans 4 16-bit words, 901238405Sjkim * with the first word containing only a single bit. 902238405Sjkim * You have to shift everything over one bit to 903238405Sjkim * get it aligned properly. Also, the bits are 904238405Sjkim * stored backwards (the LSB is really the MSB, 905238405Sjkim * and so on) so you have to reverse them in order 906238405Sjkim * to get the MAC address into the form we want. 907238405Sjkim * Why? Who the hell knows. 908238405Sjkim */ 909238405Sjkim { 910238405Sjkim u_int16_t tmp[4]; 911238405Sjkim 912238405Sjkim sis_read_eeprom(sc, (caddr_t)&tmp, 913238405Sjkim NS_EE_NODEADDR, 4, 0); 914238405Sjkim 915238405Sjkim /* Shift everything over one bit. */ 916238405Sjkim tmp[3] = tmp[3] >> 1; 917238405Sjkim tmp[3] |= tmp[2] << 15; 918238405Sjkim tmp[2] = tmp[2] >> 1; 919238405Sjkim tmp[2] |= tmp[1] << 15; 920238405Sjkim tmp[1] = tmp[1] >> 1; 921238405Sjkim tmp[1] |= tmp[0] << 15; 922238405Sjkim 923238405Sjkim /* Now reverse all the bits. */ 924238405Sjkim tmp[3] = sis_reverse(tmp[3]); 925238405Sjkim tmp[2] = sis_reverse(tmp[2]); 926238405Sjkim tmp[1] = sis_reverse(tmp[1]); 927238405Sjkim 928238405Sjkim bcopy((char *)&tmp[1], eaddr, ETHER_ADDR_LEN); 929238405Sjkim } 930238405Sjkim break; 931238405Sjkim case SIS_VENDORID: 932238405Sjkim default: 933238405Sjkim#ifdef __i386__ 934238405Sjkim /* 935238405Sjkim * If this is a SiS 630E chipset with an embedded 936238405Sjkim * SiS 900 controller, we have to read the MAC address 937238405Sjkim * from the APC CMOS RAM. Our method for doing this 938238405Sjkim * is very ugly since we have to reach out and grab 939238405Sjkim * ahold of hardware for which we cannot properly 940238405Sjkim * allocate resources. This code is only compiled on 941238405Sjkim * the i386 architecture since the SiS 630E chipset 942238405Sjkim * is for x86 motherboards only. Note that there are 943238405Sjkim * a lot of magic numbers in this hack. These are 944238405Sjkim * taken from SiS's Linux driver. I'd like to replace 945238405Sjkim * them with proper symbolic definitions, but that 946238405Sjkim * requires some datasheets that I don't have access 947238405Sjkim * to at the moment. 948238405Sjkim */ 949238405Sjkim if (sc->sis_rev == SIS_REV_630S || 950238405Sjkim sc->sis_rev == SIS_REV_630E || 951238405Sjkim sc->sis_rev == SIS_REV_630EA1) 952238405Sjkim sis_read_cmos(sc, dev, (caddr_t)&eaddr, 0x9, 6); 953238405Sjkim 954238405Sjkim else if (sc->sis_rev == SIS_REV_635 || 955238405Sjkim sc->sis_rev == SIS_REV_630ET) 956238405Sjkim sis_read_mac(sc, dev, (caddr_t)&eaddr); 957238405Sjkim else 958238405Sjkim#endif 959238405Sjkim sis_read_eeprom(sc, (caddr_t)&eaddr, 960238405Sjkim SIS_EE_NODEADDR, 3, 0); 961238405Sjkim break; 962238405Sjkim } 963238405Sjkim 964238405Sjkim /* 965238405Sjkim * A SiS chip was detected. Inform the world. 966238405Sjkim */ 967238405Sjkim printf("sis%d: Ethernet address: %6D\n", unit, eaddr, ":"); 968238405Sjkim 969238405Sjkim sc->sis_unit = unit; 970238405Sjkim callout_handle_init(&sc->sis_stat_ch); 971238405Sjkim bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 972238405Sjkim 973238405Sjkim /* 974238405Sjkim * Allocate the parent bus DMA tag appropriate for PCI. 975238405Sjkim */ 976238405Sjkim#define SIS_NSEG_NEW 32 977238405Sjkim error = bus_dma_tag_create(NULL, /* parent */ 978238405Sjkim 1, 0, /* alignment, boundary */ 979238405Sjkim BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 980238405Sjkim BUS_SPACE_MAXADDR, /* highaddr */ 981238405Sjkim NULL, NULL, /* filter, filterarg */ 982238405Sjkim MAXBSIZE, SIS_NSEG_NEW, /* maxsize, nsegments */ 983238405Sjkim BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 984238405Sjkim BUS_DMA_ALLOCNOW, /* flags */ 985238405Sjkim &sc->sis_parent_tag); 986238405Sjkim 987238405Sjkim /* 988238405Sjkim * Now allocate a tag for the DMA descriptor lists. 989238405Sjkim * All of our lists are allocated as a contiguous block 990238405Sjkim * of memory. 991238405Sjkim */ 992238405Sjkim error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ 993238405Sjkim 1, 0, /* alignment, boundary */ 994238405Sjkim BUS_SPACE_MAXADDR, /* lowaddr */ 995238405Sjkim BUS_SPACE_MAXADDR, /* highaddr */ 996238405Sjkim NULL, NULL, /* filter, filterarg */ 997238405Sjkim SIS_RX_LIST_SZ, 1, /* maxsize,nsegments */ 998238405Sjkim BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 999238405Sjkim 0, /* flags */ 1000238405Sjkim &sc->sis_ldata.sis_rx_tag); 1001238405Sjkim 1002238405Sjkim error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ 1003238405Sjkim 1, 0, /* alignment, boundary */ 1004238405Sjkim BUS_SPACE_MAXADDR, /* lowaddr */ 1005238405Sjkim BUS_SPACE_MAXADDR, /* highaddr */ 1006238405Sjkim NULL, NULL, /* filter, filterarg */ 1007238405Sjkim SIS_TX_LIST_SZ, 1, /* maxsize,nsegments */ 1008238405Sjkim BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 1009238405Sjkim 0, /* flags */ 1010238405Sjkim &sc->sis_ldata.sis_tx_tag); 1011238405Sjkim 1012238405Sjkim error = bus_dma_tag_create(sc->sis_parent_tag, /* parent */ 1013238405Sjkim 1, 0, /* alignment, boundary */ 1014238405Sjkim BUS_SPACE_MAXADDR, /* lowaddr */ 1015238405Sjkim BUS_SPACE_MAXADDR, /* highaddr */ 1016238405Sjkim NULL, NULL, /* filter, filterarg */ 1017238405Sjkim SIS_TX_LIST_SZ, 1, /* maxsize,nsegments */ 1018238405Sjkim BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 1019238405Sjkim 0, /* flags */ 1020238405Sjkim &sc->sis_tag); 1021238405Sjkim 1022238405Sjkim /* 1023238405Sjkim * Now allocate a chunk of DMA-able memory based on the 1024238405Sjkim * tag we just created. 1025238405Sjkim */ 1026238405Sjkim error = bus_dmamem_alloc(sc->sis_ldata.sis_tx_tag, 1027238405Sjkim (void **)&sc->sis_ldata.sis_tx_list, BUS_DMA_NOWAIT, 1028238405Sjkim &sc->sis_ldata.sis_tx_dmamap); 1029238405Sjkim 1030238405Sjkim if (error) { 1031238405Sjkim printf("sis%d: no memory for list buffers!\n", unit); 1032238405Sjkim bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); 1033238405Sjkim bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 1034238405Sjkim bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 1035238405Sjkim bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); 1036238405Sjkim bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); 1037238405Sjkim error = ENXIO; 1038238405Sjkim goto fail; 1039238405Sjkim } 1040238405Sjkim 1041238405Sjkim error = bus_dmamem_alloc(sc->sis_ldata.sis_rx_tag, 1042238405Sjkim (void **)&sc->sis_ldata.sis_rx_list, BUS_DMA_NOWAIT, 1043238405Sjkim &sc->sis_ldata.sis_rx_dmamap); 1044238405Sjkim 1045238405Sjkim if (error) { 1046238405Sjkim printf("sis%d: no memory for list buffers!\n", unit); 1047238405Sjkim bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); 1048238405Sjkim bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 1049238405Sjkim bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 1050238405Sjkim bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 1051238405Sjkim sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); 1052238405Sjkim bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); 1053238405Sjkim bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); 1054238405Sjkim error = ENXIO; 1055238405Sjkim goto fail; 1056238405Sjkim } 1057238405Sjkim 1058238405Sjkim 1059238405Sjkim bzero(sc->sis_ldata.sis_tx_list, SIS_TX_LIST_SZ); 1060238405Sjkim bzero(sc->sis_ldata.sis_rx_list, SIS_RX_LIST_SZ); 1061238405Sjkim 1062238405Sjkim /* 1063238405Sjkim * Obtain the physical addresses of the RX and TX 1064238405Sjkim * rings which we'll need later in the init routine. 1065238405Sjkim */ 1066238405Sjkim bus_dmamap_load(sc->sis_ldata.sis_tx_tag, 1067238405Sjkim sc->sis_ldata.sis_tx_dmamap, &(sc->sis_ldata.sis_tx_list[0]), 1068238405Sjkim sizeof(struct sis_desc), sis_dma_map_ring, 1069238405Sjkim &sc->sis_cdata.sis_tx_paddr, 0); 1070238405Sjkim bus_dmamap_load(sc->sis_ldata.sis_rx_tag, 1071238405Sjkim sc->sis_ldata.sis_rx_dmamap, &(sc->sis_ldata.sis_rx_list[0]), 1072238405Sjkim sizeof(struct sis_desc), sis_dma_map_ring, 1073238405Sjkim &sc->sis_cdata.sis_rx_paddr, 0); 1074238405Sjkim 1075238405Sjkim ifp = &sc->arpcom.ac_if; 1076238405Sjkim ifp->if_softc = sc; 1077238405Sjkim ifp->if_unit = unit; 1078238405Sjkim ifp->if_name = "sis"; 1079238405Sjkim ifp->if_mtu = ETHERMTU; 1080238405Sjkim ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1081238405Sjkim ifp->if_ioctl = sis_ioctl; 1082238405Sjkim ifp->if_output = ether_output; 1083238405Sjkim ifp->if_start = sis_start; 1084238405Sjkim ifp->if_watchdog = sis_watchdog; 1085238405Sjkim ifp->if_init = sis_init; 1086238405Sjkim ifp->if_baudrate = 10000000; 1087238405Sjkim ifp->if_snd.ifq_maxlen = SIS_TX_LIST_CNT - 1; 1088238405Sjkim 1089238405Sjkim /* 1090238405Sjkim * Do MII setup. 1091238405Sjkim */ 1092238405Sjkim if (mii_phy_probe(dev, &sc->sis_miibus, 1093238405Sjkim sis_ifmedia_upd, sis_ifmedia_sts)) { 1094238405Sjkim printf("sis%d: MII without any PHY!\n", sc->sis_unit); 1095238405Sjkim bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); 1096238405Sjkim bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 1097238405Sjkim bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 1098238405Sjkim bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 1099238405Sjkim sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap); 1100238405Sjkim bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 1101238405Sjkim sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); 1102238405Sjkim bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); 1103238405Sjkim bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); 1104238405Sjkim error = ENXIO; 1105238405Sjkim goto fail; 1106238405Sjkim } 1107238405Sjkim 1108238405Sjkim /* 1109238405Sjkim * Call MI attach routine. 1110238405Sjkim */ 1111238405Sjkim ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 1112238405Sjkim 1113238405Sjkim /* 1114238405Sjkim * Tell the upper layer(s) we support long frames. 1115238405Sjkim */ 1116238405Sjkim ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 1117238405Sjkim 1118238405Sjkim callout_handle_init(&sc->sis_stat_ch); 1119238405Sjkim SIS_UNLOCK(sc); 1120238405Sjkim return(0); 1121238405Sjkim 1122238405Sjkimfail: 1123238405Sjkim SIS_UNLOCK(sc); 1124238405Sjkim mtx_destroy(&sc->sis_mtx); 1125238405Sjkim return(error); 1126238405Sjkim} 1127238405Sjkim 1128238405Sjkimstatic int sis_detach(dev) 1129238405Sjkim device_t dev; 1130238405Sjkim{ 1131238405Sjkim struct sis_softc *sc; 1132238405Sjkim struct ifnet *ifp; 1133238405Sjkim 1134238405Sjkim 1135238405Sjkim sc = device_get_softc(dev); 1136238405Sjkim SIS_LOCK(sc); 1137238405Sjkim ifp = &sc->arpcom.ac_if; 1138238405Sjkim 1139238405Sjkim sis_reset(sc); 1140238405Sjkim sis_stop(sc); 1141238405Sjkim ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 1142238405Sjkim 1143238405Sjkim bus_generic_detach(dev); 1144238405Sjkim device_delete_child(dev, sc->sis_miibus); 1145238405Sjkim 1146238405Sjkim bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand); 1147238405Sjkim bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq); 1148238405Sjkim bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res); 1149238405Sjkim 1150238405Sjkim bus_dmamap_unload(sc->sis_ldata.sis_rx_tag, 1151238405Sjkim sc->sis_ldata.sis_rx_dmamap); 1152238405Sjkim bus_dmamap_unload(sc->sis_ldata.sis_tx_tag, 1153238405Sjkim sc->sis_ldata.sis_tx_dmamap); 1154238405Sjkim bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 1155238405Sjkim sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap); 1156238405Sjkim bus_dmamem_free(sc->sis_ldata.sis_rx_tag, 1157238405Sjkim sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap); 1158238405Sjkim bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag); 1159238405Sjkim bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag); 1160238405Sjkim bus_dma_tag_destroy(sc->sis_parent_tag); 1161238405Sjkim 1162238405Sjkim SIS_UNLOCK(sc); 1163238405Sjkim mtx_destroy(&sc->sis_mtx); 1164238405Sjkim 1165238405Sjkim return(0); 1166238405Sjkim} 1167238405Sjkim 1168238405Sjkim/* 1169238405Sjkim * Initialize the transmit descriptors. 1170238405Sjkim */ 1171238405Sjkimstatic int sis_list_tx_init(sc) 1172238405Sjkim struct sis_softc *sc; 1173238405Sjkim{ 1174238405Sjkim struct sis_list_data *ld; 1175238405Sjkim struct sis_ring_data *cd; 1176238405Sjkim int i, nexti; 1177238405Sjkim 1178238405Sjkim cd = &sc->sis_cdata; 1179238405Sjkim ld = &sc->sis_ldata; 1180238405Sjkim 1181238405Sjkim for (i = 0; i < SIS_TX_LIST_CNT; i++) { 1182238405Sjkim nexti = (i == (SIS_TX_LIST_CNT - 1)) ? 0 : i+1; 1183238405Sjkim ld->sis_tx_list[i].sis_nextdesc = 1184238405Sjkim &ld->sis_tx_list[nexti]; 1185238405Sjkim bus_dmamap_load(sc->sis_ldata.sis_tx_tag, 1186238405Sjkim sc->sis_ldata.sis_tx_dmamap, 1187238405Sjkim &ld->sis_tx_list[nexti], sizeof(struct sis_desc), 1188238405Sjkim sis_dma_map_desc_next, &ld->sis_tx_list[i], 0); 1189238405Sjkim ld->sis_tx_list[i].sis_mbuf = NULL; 1190238405Sjkim ld->sis_tx_list[i].sis_ptr = 0; 1191238405Sjkim ld->sis_tx_list[i].sis_ctl = 0; 1192238405Sjkim } 1193238405Sjkim 1194238405Sjkim cd->sis_tx_prod = cd->sis_tx_cons = cd->sis_tx_cnt = 0; 1195238405Sjkim 1196238405Sjkim bus_dmamap_sync(sc->sis_ldata.sis_tx_tag, 1197238405Sjkim sc->sis_ldata.sis_rx_dmamap, BUS_DMASYNC_PREWRITE); 1198238405Sjkim 1199238405Sjkim return(0); 1200238405Sjkim} 1201238405Sjkim 1202238405Sjkim/* 1203238405Sjkim * Initialize the RX descriptors and allocate mbufs for them. Note that 1204238405Sjkim * we arrange the descriptors in a closed ring, so that the last descriptor 1205238405Sjkim * points back to the first. 1206238405Sjkim */ 1207238405Sjkimstatic int sis_list_rx_init(sc) 1208238405Sjkim struct sis_softc *sc; 1209238405Sjkim{ 1210238405Sjkim struct sis_list_data *ld; 1211238405Sjkim struct sis_ring_data *cd; 1212238405Sjkim int i,nexti; 1213238405Sjkim 1214238405Sjkim ld = &sc->sis_ldata; 1215238405Sjkim cd = &sc->sis_cdata; 1216238405Sjkim 1217238405Sjkim for (i = 0; i < SIS_RX_LIST_CNT; i++) { 1218238405Sjkim if (sis_newbuf(sc, &ld->sis_rx_list[i], NULL) == ENOBUFS) 1219238405Sjkim return(ENOBUFS); 1220238405Sjkim nexti = (i == (SIS_RX_LIST_CNT - 1)) ? 0 : i+1; 1221238405Sjkim ld->sis_rx_list[i].sis_nextdesc = 1222238405Sjkim &ld->sis_rx_list[nexti]; 1223238405Sjkim bus_dmamap_load(sc->sis_ldata.sis_rx_tag, 1224238405Sjkim sc->sis_ldata.sis_rx_dmamap, 1225238405Sjkim &ld->sis_rx_list[nexti], 1226238405Sjkim sizeof(struct sis_desc), sis_dma_map_desc_next, 1227238405Sjkim &ld->sis_rx_list[i], 0); 1228238405Sjkim } 1229238405Sjkim 1230238405Sjkim bus_dmamap_sync(sc->sis_ldata.sis_rx_tag, 1231238405Sjkim sc->sis_ldata.sis_rx_dmamap, BUS_DMASYNC_PREWRITE); 1232238405Sjkim 1233238405Sjkim cd->sis_rx_prod = 0; 1234238405Sjkim 1235238405Sjkim return(0); 1236238405Sjkim} 1237238405Sjkim 1238238405Sjkim/* 1239238405Sjkim * Initialize an RX descriptor and attach an MBUF cluster. 1240238405Sjkim */ 1241238405Sjkimstatic int sis_newbuf(sc, c, m) 1242238405Sjkim struct sis_softc *sc; 1243238405Sjkim struct sis_desc *c; 1244238405Sjkim struct mbuf *m; 1245238405Sjkim{ 1246238405Sjkim 1247238405Sjkim if (c == NULL) 1248238405Sjkim return(EINVAL); 1249238405Sjkim 1250238405Sjkim if (m == NULL) { 1251238405Sjkim m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1252238405Sjkim if (m == NULL) 1253238405Sjkim return(ENOBUFS); 1254238405Sjkim } else 1255238405Sjkim m->m_data = m->m_ext.ext_buf; 1256238405Sjkim 1257238405Sjkim c->sis_mbuf = m; 1258238405Sjkim c->sis_ctl = SIS_RXLEN; 1259238405Sjkim 1260238405Sjkim bus_dmamap_create(sc->sis_tag, 0, &c->sis_map); 1261238405Sjkim bus_dmamap_load(sc->sis_tag, c->sis_map, 1262238405Sjkim mtod(m, void *), MCLBYTES, 1263238405Sjkim sis_dma_map_desc_ptr, c, 0); 1264238405Sjkim bus_dmamap_sync(sc->sis_tag, c->sis_map, BUS_DMASYNC_PREWRITE); 1265238405Sjkim 1266238405Sjkim return(0); 1267238405Sjkim} 1268238405Sjkim 1269238405Sjkim/* 1270238405Sjkim * A frame has been uploaded: pass the resulting mbuf chain up to 1271238405Sjkim * the higher level protocols. 1272238405Sjkim */ 1273238405Sjkimstatic void sis_rxeof(sc) 1274238405Sjkim struct sis_softc *sc; 1275238405Sjkim{ 1276238405Sjkim struct mbuf *m; 1277238405Sjkim struct ifnet *ifp; 1278238405Sjkim struct sis_desc *cur_rx; 1279238405Sjkim int i, total_len = 0; 1280238405Sjkim u_int32_t rxstat; 1281238405Sjkim 1282238405Sjkim ifp = &sc->arpcom.ac_if; 1283238405Sjkim i = sc->sis_cdata.sis_rx_prod; 1284238405Sjkim 1285238405Sjkim while(SIS_OWNDESC(&sc->sis_ldata.sis_rx_list[i])) { 1286238405Sjkim 1287238405Sjkim#ifdef DEVICE_POLLING 1288238405Sjkim if (ifp->if_ipending & IFF_POLLING) { 1289238405Sjkim if (sc->rxcycles <= 0) 1290238405Sjkim break; 1291238405Sjkim sc->rxcycles--; 1292238405Sjkim } 1293238405Sjkim#endif /* DEVICE_POLLING */ 1294238405Sjkim cur_rx = &sc->sis_ldata.sis_rx_list[i]; 1295238405Sjkim rxstat = cur_rx->sis_rxstat; 1296238405Sjkim bus_dmamap_sync(sc->sis_tag, 1297238405Sjkim cur_rx->sis_map, BUS_DMASYNC_POSTWRITE); 1298238405Sjkim bus_dmamap_unload(sc->sis_tag, cur_rx->sis_map); 1299238405Sjkim bus_dmamap_destroy(sc->sis_tag, cur_rx->sis_map); 1300238405Sjkim m = cur_rx->sis_mbuf; 1301238405Sjkim cur_rx->sis_mbuf = NULL; 1302238405Sjkim total_len = SIS_RXBYTES(cur_rx); 1303238405Sjkim SIS_INC(i, SIS_RX_LIST_CNT); 1304238405Sjkim 1305238405Sjkim /* 1306238405Sjkim * If an error occurs, update stats, clear the 1307238405Sjkim * status word and leave the mbuf cluster in place: 1308238405Sjkim * it should simply get re-used next time this descriptor 1309238405Sjkim * comes up in the ring. 1310238405Sjkim */ 1311238405Sjkim if (!(rxstat & SIS_CMDSTS_PKT_OK)) { 1312238405Sjkim ifp->if_ierrors++; 1313238405Sjkim if (rxstat & SIS_RXSTAT_COLL) 1314238405Sjkim ifp->if_collisions++; 1315238405Sjkim sis_newbuf(sc, cur_rx, m); 1316238405Sjkim continue; 1317238405Sjkim } 1318238405Sjkim 1319238405Sjkim /* No errors; receive the packet. */ 1320238405Sjkim#ifdef __i386__ 1321238405Sjkim /* 1322238405Sjkim * On the x86 we do not have alignment problems, so try to 1323238405Sjkim * allocate a new buffer for the receive ring, and pass up 1324238405Sjkim * the one where the packet is already, saving the expensive 1325238405Sjkim * copy done in m_devget(). 1326238405Sjkim * If we are on an architecture with alignment problems, or 1327238405Sjkim * if the allocation fails, then use m_devget and leave the 1328238405Sjkim * existing buffer in the receive ring. 1329238405Sjkim */ 1330238405Sjkim if (sis_newbuf(sc, cur_rx, NULL) == 0) 1331238405Sjkim m->m_pkthdr.len = m->m_len = total_len; 1332238405Sjkim else 1333238405Sjkim#endif 1334238405Sjkim { 1335238405Sjkim struct mbuf *m0; 1336238405Sjkim m0 = m_devget(mtod(m, char *), total_len, 1337238405Sjkim ETHER_ALIGN, ifp, NULL); 1338238405Sjkim sis_newbuf(sc, cur_rx, m); 1339238405Sjkim if (m0 == NULL) { 1340238405Sjkim ifp->if_ierrors++; 1341238405Sjkim continue; 1342238405Sjkim } 1343238405Sjkim m = m0; 1344238405Sjkim } 1345238405Sjkim 1346238405Sjkim ifp->if_ipackets++; 1347238405Sjkim ether_input(ifp, NULL, m); 1348238405Sjkim } 1349238405Sjkim 1350238405Sjkim sc->sis_cdata.sis_rx_prod = i; 1351238405Sjkim 1352238405Sjkim return; 1353238405Sjkim} 1354238405Sjkim 1355238405Sjkimvoid sis_rxeoc(sc) 1356238405Sjkim struct sis_softc *sc; 1357238405Sjkim{ 1358238405Sjkim sis_rxeof(sc); 1359238405Sjkim sis_init(sc); 1360238405Sjkim return; 1361238405Sjkim} 1362238405Sjkim 1363238405Sjkim/* 1364238405Sjkim * A frame was downloaded to the chip. It's safe for us to clean up 1365238405Sjkim * the list buffers. 1366238405Sjkim */ 1367238405Sjkim 1368238405Sjkimstatic void sis_txeof(sc) 1369238405Sjkim struct sis_softc *sc; 1370238405Sjkim{ 1371238405Sjkim struct ifnet *ifp; 1372238405Sjkim u_int32_t idx; 1373238405Sjkim 1374238405Sjkim ifp = &sc->arpcom.ac_if; 1375238405Sjkim 1376238405Sjkim /* 1377238405Sjkim * Go through our tx list and free mbufs for those 1378238405Sjkim * frames that have been transmitted. 1379238405Sjkim */ 1380238405Sjkim for (idx = sc->sis_cdata.sis_tx_cons; sc->sis_cdata.sis_tx_cnt > 0; 1381238405Sjkim sc->sis_cdata.sis_tx_cnt--, SIS_INC(idx, SIS_TX_LIST_CNT) ) { 1382238405Sjkim struct sis_desc *cur_tx = &sc->sis_ldata.sis_tx_list[idx]; 1383238405Sjkim 1384238405Sjkim if (SIS_OWNDESC(cur_tx)) 1385238405Sjkim break; 1386238405Sjkim 1387238405Sjkim if (cur_tx->sis_ctl & SIS_CMDSTS_MORE) 1388238405Sjkim continue; 1389238405Sjkim 1390238405Sjkim if (!(cur_tx->sis_ctl & SIS_CMDSTS_PKT_OK)) { 1391238405Sjkim ifp->if_oerrors++; 1392238405Sjkim if (cur_tx->sis_txstat & SIS_TXSTAT_EXCESSCOLLS) 1393238405Sjkim ifp->if_collisions++; 1394238405Sjkim if (cur_tx->sis_txstat & SIS_TXSTAT_OUTOFWINCOLL) 1395238405Sjkim ifp->if_collisions++; 1396238405Sjkim } 1397238405Sjkim 1398238405Sjkim ifp->if_collisions += 1399238405Sjkim (cur_tx->sis_txstat & SIS_TXSTAT_COLLCNT) >> 16; 1400238405Sjkim 1401238405Sjkim ifp->if_opackets++; 1402238405Sjkim if (cur_tx->sis_mbuf != NULL) { 1403238405Sjkim m_freem(cur_tx->sis_mbuf); 1404238405Sjkim cur_tx->sis_mbuf = NULL; 1405238405Sjkim bus_dmamap_unload(sc->sis_tag, cur_tx->sis_map); 1406238405Sjkim bus_dmamap_destroy(sc->sis_tag, cur_tx->sis_map); 1407238405Sjkim } 1408238405Sjkim } 1409238405Sjkim 1410238405Sjkim if (idx != sc->sis_cdata.sis_tx_cons) { 1411238405Sjkim /* we freed up some buffers */ 1412238405Sjkim sc->sis_cdata.sis_tx_cons = idx; 1413238405Sjkim ifp->if_flags &= ~IFF_OACTIVE; 1414238405Sjkim } 1415238405Sjkim 1416238405Sjkim ifp->if_timer = (sc->sis_cdata.sis_tx_cnt == 0) ? 0 : 5; 1417238405Sjkim 1418238405Sjkim return; 1419238405Sjkim} 1420238405Sjkim 1421238405Sjkimstatic void sis_tick(xsc) 1422238405Sjkim void *xsc; 1423238405Sjkim{ 1424238405Sjkim struct sis_softc *sc; 1425238405Sjkim struct mii_data *mii; 1426238405Sjkim struct ifnet *ifp; 1427238405Sjkim 1428238405Sjkim sc = xsc; 1429238405Sjkim SIS_LOCK(sc); 1430238405Sjkim ifp = &sc->arpcom.ac_if; 1431238405Sjkim 1432238405Sjkim mii = device_get_softc(sc->sis_miibus); 1433238405Sjkim mii_tick(mii); 1434238405Sjkim 1435238405Sjkim if (!sc->sis_link && mii->mii_media_status & IFM_ACTIVE && 1436238405Sjkim IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { 1437238405Sjkim sc->sis_link++; 1438238405Sjkim if (ifp->if_snd.ifq_head != NULL) 1439238405Sjkim sis_start(ifp); 1440238405Sjkim } 1441238405Sjkim 1442238405Sjkim sc->sis_stat_ch = timeout(sis_tick, sc, hz); 1443238405Sjkim 1444238405Sjkim SIS_UNLOCK(sc); 1445238405Sjkim 1446238405Sjkim return; 1447238405Sjkim} 1448238405Sjkim 1449238405Sjkim#ifdef DEVICE_POLLING 1450238405Sjkimstatic poll_handler_t sis_poll; 1451238405Sjkim 1452238405Sjkimstatic void 1453238405Sjkimsis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) 1454238405Sjkim{ 1455238405Sjkim struct sis_softc *sc = ifp->if_softc; 1456238405Sjkim 1457238405Sjkim SIS_LOCK(sc); 1458238405Sjkim if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */ 1459238405Sjkim CSR_WRITE_4(sc, SIS_IER, 1); 1460238405Sjkim goto done; 1461238405Sjkim } 1462238405Sjkim 1463238405Sjkim /* 1464238405Sjkim * On the sis, reading the status register also clears it. 1465238405Sjkim * So before returning to intr mode we must make sure that all 1466238405Sjkim * possible pending sources of interrupts have been served. 1467238405Sjkim * In practice this means run to completion the *eof routines, 1468238405Sjkim * and then call the interrupt routine 1469238405Sjkim */ 1470238405Sjkim sc->rxcycles = count; 1471238405Sjkim sis_rxeof(sc); 1472238405Sjkim sis_txeof(sc); 1473238405Sjkim if (ifp->if_snd.ifq_head != NULL) 1474238405Sjkim sis_start(ifp); 1475238405Sjkim 1476238405Sjkim if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) { 1477238405Sjkim u_int32_t status; 1478238405Sjkim 1479238405Sjkim /* Reading the ISR register clears all interrupts. */ 1480238405Sjkim status = CSR_READ_4(sc, SIS_ISR); 1481238405Sjkim 1482238405Sjkim if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW)) 1483238405Sjkim sis_rxeoc(sc); 1484238405Sjkim 1485238405Sjkim if (status & (SIS_ISR_RX_IDLE)) 1486238405Sjkim SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 1487238405Sjkim 1488238405Sjkim if (status & SIS_ISR_SYSERR) { 1489238405Sjkim sis_reset(sc); 1490238405Sjkim sis_init(sc); 1491238405Sjkim } 1492238405Sjkim } 1493238405Sjkimdone: 1494238405Sjkim SIS_UNLOCK(sc); 1495238405Sjkim return; 1496238405Sjkim} 1497238405Sjkim#endif /* DEVICE_POLLING */ 1498238405Sjkim 1499238405Sjkimstatic void sis_intr(arg) 1500238405Sjkim void *arg; 1501238405Sjkim{ 1502238405Sjkim struct sis_softc *sc; 1503238405Sjkim struct ifnet *ifp; 1504238405Sjkim u_int32_t status; 1505238405Sjkim 1506238405Sjkim sc = arg; 1507238405Sjkim ifp = &sc->arpcom.ac_if; 1508238405Sjkim 1509238405Sjkim SIS_LOCK(sc); 1510238405Sjkim#ifdef DEVICE_POLLING 1511238405Sjkim if (ifp->if_ipending & IFF_POLLING) 1512238405Sjkim goto done; 1513238405Sjkim if (ether_poll_register(sis_poll, ifp)) { /* ok, disable interrupts */ 1514238405Sjkim CSR_WRITE_4(sc, SIS_IER, 0); 1515238405Sjkim goto done; 1516238405Sjkim } 1517238405Sjkim#endif /* DEVICE_POLLING */ 1518238405Sjkim 1519238405Sjkim /* Supress unwanted interrupts */ 1520238405Sjkim if (!(ifp->if_flags & IFF_UP)) { 1521238405Sjkim sis_stop(sc); 1522238405Sjkim goto done; 1523238405Sjkim } 1524238405Sjkim 1525238405Sjkim /* Disable interrupts. */ 1526238405Sjkim CSR_WRITE_4(sc, SIS_IER, 0); 1527238405Sjkim 1528238405Sjkim for (;;) { 1529238405Sjkim /* Reading the ISR register clears all interrupts. */ 1530238405Sjkim status = CSR_READ_4(sc, SIS_ISR); 1531238405Sjkim 1532238405Sjkim if ((status & SIS_INTRS) == 0) 1533238405Sjkim break; 1534238405Sjkim 1535238405Sjkim if (status & 1536238405Sjkim (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR | 1537238405Sjkim SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) ) 1538238405Sjkim sis_txeof(sc); 1539238405Sjkim 1540238405Sjkim if (status & (SIS_ISR_RX_DESC_OK|SIS_ISR_RX_OK|SIS_ISR_RX_IDLE)) 1541238405Sjkim sis_rxeof(sc); 1542238405Sjkim 1543238405Sjkim if (status & (SIS_ISR_RX_ERR | SIS_ISR_RX_OFLOW)) 1544238405Sjkim sis_rxeoc(sc); 1545238405Sjkim 1546238405Sjkim if (status & (SIS_ISR_RX_IDLE)) 1547238405Sjkim SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 1548238405Sjkim 1549238405Sjkim if (status & SIS_ISR_SYSERR) { 1550238405Sjkim sis_reset(sc); 1551238405Sjkim sis_init(sc); 1552238405Sjkim } 1553238405Sjkim } 1554238405Sjkim 1555238405Sjkim /* Re-enable interrupts. */ 1556238405Sjkim CSR_WRITE_4(sc, SIS_IER, 1); 1557238405Sjkim 1558238405Sjkim if (ifp->if_snd.ifq_head != NULL) 1559238405Sjkim sis_start(ifp); 1560238405Sjkimdone: 1561238405Sjkim SIS_UNLOCK(sc); 1562238405Sjkim 1563238405Sjkim return; 1564238405Sjkim} 1565238405Sjkim 1566238405Sjkim/* 1567238405Sjkim * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 1568238405Sjkim * pointers to the fragment pointers. 1569238405Sjkim */ 1570238405Sjkimstatic int sis_encap(sc, m_head, txidx) 1571238405Sjkim struct sis_softc *sc; 1572238405Sjkim struct mbuf *m_head; 1573238405Sjkim u_int32_t *txidx; 1574238405Sjkim{ 1575238405Sjkim struct sis_desc *f = NULL; 1576238405Sjkim struct mbuf *m; 1577238405Sjkim int frag, cur, cnt = 0; 1578238405Sjkim 1579238405Sjkim /* 1580238405Sjkim * Start packing the mbufs in this chain into 1581238405Sjkim * the fragment pointers. Stop when we run out 1582238405Sjkim * of fragments or hit the end of the mbuf chain. 1583238405Sjkim */ 1584238405Sjkim m = m_head; 1585238405Sjkim cur = frag = *txidx; 1586238405Sjkim 1587238405Sjkim for (m = m_head; m != NULL; m = m->m_next) { 1588238405Sjkim if (m->m_len != 0) { 1589238405Sjkim if ((SIS_TX_LIST_CNT - 1590238405Sjkim (sc->sis_cdata.sis_tx_cnt + cnt)) < 2) 1591238405Sjkim return(ENOBUFS); 1592238405Sjkim f = &sc->sis_ldata.sis_tx_list[frag]; 1593238405Sjkim f->sis_ctl = SIS_CMDSTS_MORE | m->m_len; 1594238405Sjkim bus_dmamap_create(sc->sis_tag, 0, &f->sis_map); 1595238405Sjkim bus_dmamap_load(sc->sis_tag, f->sis_map, 1596238405Sjkim mtod(m, void *), m->m_len, 1597238405Sjkim sis_dma_map_desc_ptr, f, 0); 1598238405Sjkim bus_dmamap_sync(sc->sis_tag, 1599238405Sjkim f->sis_map, BUS_DMASYNC_PREREAD); 1600238405Sjkim if (cnt != 0) 1601238405Sjkim f->sis_ctl |= SIS_CMDSTS_OWN; 1602238405Sjkim cur = frag; 1603238405Sjkim SIS_INC(frag, SIS_TX_LIST_CNT); 1604238405Sjkim cnt++; 1605238405Sjkim } 1606238405Sjkim } 1607238405Sjkim 1608238405Sjkim if (m != NULL) 1609238405Sjkim return(ENOBUFS); 1610238405Sjkim 1611238405Sjkim sc->sis_ldata.sis_tx_list[cur].sis_mbuf = m_head; 1612238405Sjkim sc->sis_ldata.sis_tx_list[cur].sis_ctl &= ~SIS_CMDSTS_MORE; 1613238405Sjkim sc->sis_ldata.sis_tx_list[*txidx].sis_ctl |= SIS_CMDSTS_OWN; 1614238405Sjkim sc->sis_cdata.sis_tx_cnt += cnt; 1615238405Sjkim *txidx = frag; 1616238405Sjkim 1617238405Sjkim return(0); 1618238405Sjkim} 1619238405Sjkim 1620238405Sjkim/* 1621238405Sjkim * Main transmit routine. To avoid having to do mbuf copies, we put pointers 1622238405Sjkim * to the mbuf data regions directly in the transmit lists. We also save a 1623238405Sjkim * copy of the pointers since the transmit list fragment pointers are 1624238405Sjkim * physical addresses. 1625238405Sjkim */ 1626238405Sjkim 1627238405Sjkimstatic void sis_start(ifp) 1628238405Sjkim struct ifnet *ifp; 1629238405Sjkim{ 1630238405Sjkim struct sis_softc *sc; 1631238405Sjkim struct mbuf *m_head = NULL; 1632238405Sjkim u_int32_t idx; 1633238405Sjkim 1634238405Sjkim sc = ifp->if_softc; 1635238405Sjkim SIS_LOCK(sc); 1636238405Sjkim 1637238405Sjkim if (!sc->sis_link) { 1638238405Sjkim SIS_UNLOCK(sc); 1639238405Sjkim return; 1640238405Sjkim } 1641238405Sjkim 1642238405Sjkim idx = sc->sis_cdata.sis_tx_prod; 1643238405Sjkim 1644238405Sjkim if (ifp->if_flags & IFF_OACTIVE) { 1645238405Sjkim SIS_UNLOCK(sc); 1646238405Sjkim return; 1647238405Sjkim } 1648238405Sjkim 1649238405Sjkim while(sc->sis_ldata.sis_tx_list[idx].sis_mbuf == NULL) { 1650238405Sjkim IF_DEQUEUE(&ifp->if_snd, m_head); 1651238405Sjkim if (m_head == NULL) 1652238405Sjkim break; 1653238405Sjkim 1654238405Sjkim if (sis_encap(sc, m_head, &idx)) { 1655238405Sjkim IF_PREPEND(&ifp->if_snd, m_head); 1656238405Sjkim ifp->if_flags |= IFF_OACTIVE; 1657238405Sjkim break; 1658238405Sjkim } 1659238405Sjkim 1660238405Sjkim /* 1661238405Sjkim * If there's a BPF listener, bounce a copy of this frame 1662238405Sjkim * to him. 1663238405Sjkim */ 1664238405Sjkim if (ifp->if_bpf) 1665238405Sjkim bpf_mtap(ifp, m_head); 1666238405Sjkim 1667238405Sjkim } 1668238405Sjkim 1669238405Sjkim /* Transmit */ 1670238405Sjkim sc->sis_cdata.sis_tx_prod = idx; 1671238405Sjkim SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE); 1672238405Sjkim 1673238405Sjkim /* 1674238405Sjkim * Set a timeout in case the chip goes out to lunch. 1675238405Sjkim */ 1676238405Sjkim ifp->if_timer = 5; 1677238405Sjkim 1678238405Sjkim SIS_UNLOCK(sc); 1679238405Sjkim 1680238405Sjkim return; 1681238405Sjkim} 1682238405Sjkim 1683238405Sjkimstatic void sis_init(xsc) 1684238405Sjkim void *xsc; 1685238405Sjkim{ 1686238405Sjkim struct sis_softc *sc = xsc; 1687238405Sjkim struct ifnet *ifp = &sc->arpcom.ac_if; 1688238405Sjkim struct mii_data *mii; 1689238405Sjkim 1690238405Sjkim SIS_LOCK(sc); 1691238405Sjkim 1692238405Sjkim /* 1693238405Sjkim * Cancel pending I/O and free all RX/TX buffers. 1694238405Sjkim */ 1695238405Sjkim sis_stop(sc); 1696238405Sjkim 1697238405Sjkim mii = device_get_softc(sc->sis_miibus); 1698238405Sjkim 1699238405Sjkim /* Set MAC address */ 1700238405Sjkim if (sc->sis_type == SIS_TYPE_83815) { 1701238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0); 1702238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_DATA, 1703238405Sjkim ((u_int16_t *)sc->arpcom.ac_enaddr)[0]); 1704238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1); 1705238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_DATA, 1706238405Sjkim ((u_int16_t *)sc->arpcom.ac_enaddr)[1]); 1707238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2); 1708238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_DATA, 1709238405Sjkim ((u_int16_t *)sc->arpcom.ac_enaddr)[2]); 1710238405Sjkim } else { 1711238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0); 1712238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_DATA, 1713238405Sjkim ((u_int16_t *)sc->arpcom.ac_enaddr)[0]); 1714238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1); 1715238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_DATA, 1716238405Sjkim ((u_int16_t *)sc->arpcom.ac_enaddr)[1]); 1717238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2); 1718238405Sjkim CSR_WRITE_4(sc, SIS_RXFILT_DATA, 1719238405Sjkim ((u_int16_t *)sc->arpcom.ac_enaddr)[2]); 1720238405Sjkim } 1721238405Sjkim 1722238405Sjkim /* Init circular RX list. */ 1723238405Sjkim if (sis_list_rx_init(sc) == ENOBUFS) { 1724238405Sjkim printf("sis%d: initialization failed: no " 1725238405Sjkim "memory for rx buffers\n", sc->sis_unit); 1726238405Sjkim sis_stop(sc); 1727238405Sjkim SIS_UNLOCK(sc); 1728238405Sjkim return; 1729238405Sjkim } 1730238405Sjkim 1731238405Sjkim /* 1732238405Sjkim * Init tx descriptors. 1733238405Sjkim */ 1734238405Sjkim sis_list_tx_init(sc); 1735238405Sjkim 1736238405Sjkim /* 1737238405Sjkim * For the NatSemi chip, we have to explicitly enable the 1738238405Sjkim * reception of ARP frames, as well as turn on the 'perfect 1739238405Sjkim * match' filter where we store the station address, otherwise 1740238405Sjkim * we won't receive unicasts meant for this host. 1741238405Sjkim */ 1742238405Sjkim if (sc->sis_type == SIS_TYPE_83815) { 1743238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_ARP); 1744238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT); 1745238405Sjkim } 1746238405Sjkim 1747238405Sjkim /* If we want promiscuous mode, set the allframes bit. */ 1748238405Sjkim if (ifp->if_flags & IFF_PROMISC) { 1749238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS); 1750238405Sjkim } else { 1751238405Sjkim SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS); 1752238405Sjkim } 1753238405Sjkim 1754238405Sjkim /* 1755238405Sjkim * Set the capture broadcast bit to capture broadcast frames. 1756238405Sjkim */ 1757238405Sjkim if (ifp->if_flags & IFF_BROADCAST) { 1758238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD); 1759238405Sjkim } else { 1760238405Sjkim SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD); 1761238405Sjkim } 1762238405Sjkim 1763238405Sjkim /* 1764238405Sjkim * Load the multicast filter. 1765238405Sjkim */ 1766238405Sjkim if (sc->sis_type == SIS_TYPE_83815) 1767238405Sjkim sis_setmulti_ns(sc); 1768238405Sjkim else 1769238405Sjkim sis_setmulti_sis(sc); 1770238405Sjkim 1771238405Sjkim /* Turn the receive filter on */ 1772238405Sjkim SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE); 1773238405Sjkim 1774238405Sjkim /* 1775238405Sjkim * Load the address of the RX and TX lists. 1776238405Sjkim */ 1777238405Sjkim CSR_WRITE_4(sc, SIS_RX_LISTPTR, sc->sis_cdata.sis_rx_paddr); 1778238405Sjkim CSR_WRITE_4(sc, SIS_TX_LISTPTR, sc->sis_cdata.sis_tx_paddr); 1779238405Sjkim 1780238405Sjkim /* Set RX configuration */ 1781238405Sjkim CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG); 1782238405Sjkim 1783238405Sjkim /* Accept Long Packets for VLAN support */ 1784238405Sjkim SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER); 1785238405Sjkim 1786238405Sjkim /* Set TX configuration */ 1787238405Sjkim if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { 1788238405Sjkim CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10); 1789238405Sjkim } else { 1790238405Sjkim CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100); 1791238405Sjkim } 1792238405Sjkim 1793238405Sjkim /* Set full/half duplex mode. */ 1794238405Sjkim if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { 1795238405Sjkim SIS_SETBIT(sc, SIS_TX_CFG, 1796238405Sjkim (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR)); 1797238405Sjkim SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); 1798238405Sjkim } else { 1799238405Sjkim SIS_CLRBIT(sc, SIS_TX_CFG, 1800238405Sjkim (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR)); 1801238405Sjkim SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS); 1802238405Sjkim } 1803238405Sjkim 1804238405Sjkim /* 1805238405Sjkim * Enable interrupts. 1806238405Sjkim */ 1807238405Sjkim CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS); 1808238405Sjkim#ifdef DEVICE_POLLING 1809238405Sjkim /* 1810238405Sjkim * ... only enable interrupts if we are not polling, make sure 1811238405Sjkim * they are off otherwise. 1812238405Sjkim */ 1813238405Sjkim if (ifp->if_ipending & IFF_POLLING) 1814238405Sjkim CSR_WRITE_4(sc, SIS_IER, 0); 1815238405Sjkim else 1816238405Sjkim#endif /* DEVICE_POLLING */ 1817238405Sjkim CSR_WRITE_4(sc, SIS_IER, 1); 1818238405Sjkim 1819238405Sjkim /* Enable receiver and transmitter. */ 1820238405Sjkim SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE); 1821238405Sjkim SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE); 1822238405Sjkim 1823238405Sjkim#ifdef notdef 1824238405Sjkim mii_mediachg(mii); 1825238405Sjkim#endif 1826238405Sjkim 1827238405Sjkim /* 1828238405Sjkim * Page 75 of the DP83815 manual recommends the 1829238405Sjkim * following register settings "for optimum 1830238405Sjkim * performance." Note however that at least three 1831238405Sjkim * of the registers are listed as "reserved" in 1832238405Sjkim * the register map, so who knows what they do. 1833238405Sjkim */ 1834238405Sjkim if (sc->sis_type == SIS_TYPE_83815) { 1835238405Sjkim CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001); 1836238405Sjkim CSR_WRITE_4(sc, NS_PHY_CR, 0x189C); 1837238405Sjkim CSR_WRITE_4(sc, NS_PHY_TDATA, 0x0000); 1838238405Sjkim CSR_WRITE_4(sc, NS_PHY_DSPCFG, 0x5040); 1839238405Sjkim CSR_WRITE_4(sc, NS_PHY_SDCFG, 0x008C); 1840238405Sjkim } 1841238405Sjkim 1842238405Sjkim ifp->if_flags |= IFF_RUNNING; 1843238405Sjkim ifp->if_flags &= ~IFF_OACTIVE; 1844238405Sjkim 1845238405Sjkim sc->sis_stat_ch = timeout(sis_tick, sc, hz); 1846238405Sjkim 1847238405Sjkim SIS_UNLOCK(sc); 1848238405Sjkim 1849238405Sjkim return; 1850238405Sjkim} 1851238405Sjkim 1852238405Sjkim/* 1853238405Sjkim * Set media options. 1854238405Sjkim */ 1855238405Sjkimstatic int sis_ifmedia_upd(ifp) 1856238405Sjkim struct ifnet *ifp; 1857238405Sjkim{ 1858238405Sjkim struct sis_softc *sc; 1859238405Sjkim struct mii_data *mii; 1860238405Sjkim 1861238405Sjkim sc = ifp->if_softc; 1862238405Sjkim 1863238405Sjkim mii = device_get_softc(sc->sis_miibus); 1864238405Sjkim sc->sis_link = 0; 1865238405Sjkim if (mii->mii_instance) { 1866238405Sjkim struct mii_softc *miisc; 1867238405Sjkim LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1868238405Sjkim mii_phy_reset(miisc); 1869238405Sjkim } 1870238405Sjkim mii_mediachg(mii); 1871238405Sjkim 1872238405Sjkim return(0); 1873238405Sjkim} 1874238405Sjkim 1875238405Sjkim/* 1876238405Sjkim * Report current media status. 1877238405Sjkim */ 1878238405Sjkimstatic void sis_ifmedia_sts(ifp, ifmr) 1879238405Sjkim struct ifnet *ifp; 1880238405Sjkim struct ifmediareq *ifmr; 1881238405Sjkim{ 1882238405Sjkim struct sis_softc *sc; 1883238405Sjkim struct mii_data *mii; 1884238405Sjkim 1885238405Sjkim sc = ifp->if_softc; 1886238405Sjkim 1887238405Sjkim mii = device_get_softc(sc->sis_miibus); 1888238405Sjkim mii_pollstat(mii); 1889238405Sjkim ifmr->ifm_active = mii->mii_media_active; 1890238405Sjkim ifmr->ifm_status = mii->mii_media_status; 1891238405Sjkim 1892238405Sjkim return; 1893238405Sjkim} 1894238405Sjkim 1895238405Sjkimstatic int sis_ioctl(ifp, command, data) 1896238405Sjkim struct ifnet *ifp; 1897238405Sjkim u_long command; 1898238405Sjkim caddr_t data; 1899238405Sjkim{ 1900238405Sjkim struct sis_softc *sc = ifp->if_softc; 1901238405Sjkim struct ifreq *ifr = (struct ifreq *) data; 1902238405Sjkim struct mii_data *mii; 1903238405Sjkim int error = 0; 1904238405Sjkim 1905238405Sjkim switch(command) { 1906238405Sjkim case SIOCSIFADDR: 1907238405Sjkim case SIOCGIFADDR: 1908238405Sjkim case SIOCSIFMTU: 1909238405Sjkim error = ether_ioctl(ifp, command, data); 1910238405Sjkim break; 1911238405Sjkim case SIOCSIFFLAGS: 1912238405Sjkim if (ifp->if_flags & IFF_UP) { 1913238405Sjkim sis_init(sc); 1914238405Sjkim } else { 1915238405Sjkim if (ifp->if_flags & IFF_RUNNING) 1916238405Sjkim sis_stop(sc); 1917238405Sjkim } 1918238405Sjkim error = 0; 1919238405Sjkim break; 1920238405Sjkim case SIOCADDMULTI: 1921238405Sjkim case SIOCDELMULTI: 1922238405Sjkim SIS_LOCK(sc); 1923238405Sjkim if (sc->sis_type == SIS_TYPE_83815) 1924238405Sjkim sis_setmulti_ns(sc); 1925238405Sjkim else 1926238405Sjkim sis_setmulti_sis(sc); 1927238405Sjkim SIS_UNLOCK(sc); 1928238405Sjkim error = 0; 1929238405Sjkim break; 1930238405Sjkim case SIOCGIFMEDIA: 1931238405Sjkim case SIOCSIFMEDIA: 1932238405Sjkim mii = device_get_softc(sc->sis_miibus); 1933238405Sjkim SIS_LOCK(sc); 1934238405Sjkim error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1935238405Sjkim SIS_UNLOCK(sc); 1936238405Sjkim break; 1937238405Sjkim default: 1938238405Sjkim error = EINVAL; 1939238405Sjkim break; 1940238405Sjkim } 1941238405Sjkim 1942238405Sjkim return(error); 1943238405Sjkim} 1944238405Sjkim 1945238405Sjkimstatic void sis_watchdog(ifp) 1946238405Sjkim struct ifnet *ifp; 1947238405Sjkim{ 1948238405Sjkim struct sis_softc *sc; 1949238405Sjkim 1950238405Sjkim sc = ifp->if_softc; 1951238405Sjkim 1952238405Sjkim SIS_LOCK(sc); 1953238405Sjkim 1954238405Sjkim ifp->if_oerrors++; 1955238405Sjkim printf("sis%d: watchdog timeout\n", sc->sis_unit); 1956238405Sjkim 1957238405Sjkim sis_stop(sc); 1958238405Sjkim sis_reset(sc); 1959238405Sjkim sis_init(sc); 1960238405Sjkim 1961238405Sjkim if (ifp->if_snd.ifq_head != NULL) 1962238405Sjkim sis_start(ifp); 1963238405Sjkim 1964238405Sjkim SIS_UNLOCK(sc); 1965238405Sjkim 1966238405Sjkim return; 1967238405Sjkim} 1968238405Sjkim 1969238405Sjkim/* 1970238405Sjkim * Stop the adapter and free any mbufs allocated to the 1971238405Sjkim * RX and TX lists. 1972238405Sjkim */ 1973238405Sjkimstatic void sis_stop(sc) 1974238405Sjkim struct sis_softc *sc; 1975238405Sjkim{ 1976238405Sjkim register int i; 1977238405Sjkim struct ifnet *ifp; 1978238405Sjkim 1979238405Sjkim SIS_LOCK(sc); 1980238405Sjkim ifp = &sc->arpcom.ac_if; 1981238405Sjkim ifp->if_timer = 0; 1982238405Sjkim 1983238405Sjkim untimeout(sis_tick, sc, sc->sis_stat_ch); 1984238405Sjkim 1985238405Sjkim ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 1986238405Sjkim#ifdef DEVICE_POLLING 1987238405Sjkim ether_poll_deregister(ifp); 1988238405Sjkim#endif 1989238405Sjkim CSR_WRITE_4(sc, SIS_IER, 0); 1990238405Sjkim CSR_WRITE_4(sc, SIS_IMR, 0); 1991238405Sjkim SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE); 1992238405Sjkim DELAY(1000); 1993238405Sjkim CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0); 1994238405Sjkim CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0); 1995238405Sjkim 1996238405Sjkim sc->sis_link = 0; 1997238405Sjkim 1998238405Sjkim /* 1999238405Sjkim * Free data in the RX lists. 2000238405Sjkim */ 2001238405Sjkim for (i = 0; i < SIS_RX_LIST_CNT; i++) { 2002238405Sjkim if (sc->sis_ldata.sis_rx_list[i].sis_mbuf != NULL) { 2003238405Sjkim bus_dmamap_unload(sc->sis_tag, 2004238405Sjkim sc->sis_ldata.sis_rx_list[i].sis_map); 2005238405Sjkim bus_dmamap_destroy(sc->sis_tag, 2006238405Sjkim sc->sis_ldata.sis_rx_list[i].sis_map); 2007238405Sjkim m_freem(sc->sis_ldata.sis_rx_list[i].sis_mbuf); 2008238405Sjkim sc->sis_ldata.sis_rx_list[i].sis_mbuf = NULL; 2009238405Sjkim } 2010238405Sjkim } 2011238405Sjkim bzero(sc->sis_ldata.sis_rx_list, 2012238405Sjkim sizeof(sc->sis_ldata.sis_rx_list)); 2013238405Sjkim 2014238405Sjkim /* 2015238405Sjkim * Free the TX list buffers. 2016238405Sjkim */ 2017238405Sjkim for (i = 0; i < SIS_TX_LIST_CNT; i++) { 2018238405Sjkim if (sc->sis_ldata.sis_tx_list[i].sis_mbuf != NULL) { 2019238405Sjkim bus_dmamap_unload(sc->sis_tag, 2020238405Sjkim sc->sis_ldata.sis_tx_list[i].sis_map); 2021238405Sjkim bus_dmamap_destroy(sc->sis_tag, 2022238405Sjkim sc->sis_ldata.sis_tx_list[i].sis_map); 2023238405Sjkim m_freem(sc->sis_ldata.sis_tx_list[i].sis_mbuf); 2024238405Sjkim sc->sis_ldata.sis_tx_list[i].sis_mbuf = NULL; 2025238405Sjkim } 2026238405Sjkim } 2027238405Sjkim 2028238405Sjkim bzero(sc->sis_ldata.sis_tx_list, 2029238405Sjkim sizeof(sc->sis_ldata.sis_tx_list)); 2030238405Sjkim 2031238405Sjkim SIS_UNLOCK(sc); 2032238405Sjkim 2033238405Sjkim return; 2034238405Sjkim} 2035238405Sjkim 2036238405Sjkim/* 2037238405Sjkim * Stop all chip I/O so that the kernel's probe routines don't 2038238405Sjkim * get confused by errant DMAs when rebooting. 2039238405Sjkim */ 2040238405Sjkimstatic void sis_shutdown(dev) 2041238405Sjkim device_t dev; 2042238405Sjkim{ 2043238405Sjkim struct sis_softc *sc; 2044238405Sjkim 2045238405Sjkim sc = device_get_softc(dev); 2046238405Sjkim SIS_LOCK(sc); 2047238405Sjkim sis_reset(sc); 2048238405Sjkim sis_stop(sc); 2049238405Sjkim SIS_UNLOCK(sc); 2050238405Sjkim 2051238405Sjkim return; 2052238405Sjkim} 2053238405Sjkim