if_sge.c revision 207071
1206625Syongari/*- 2206625Syongari * Copyright (c) 2008-2010 Nikolay Denev <ndenev@gmail.com> 3206625Syongari * Copyright (c) 2007-2008 Alexander Pohoyda <alexander.pohoyda@gmx.net> 4206625Syongari * Copyright (c) 1997, 1998, 1999 5206625Syongari * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 6206625Syongari * 7206625Syongari * Redistribution and use in source and binary forms, with or without 8206625Syongari * modification, are permitted provided that the following conditions 9206625Syongari * are met: 10206625Syongari * 1. Redistributions of source code must retain the above copyright 11206625Syongari * notice, this list of conditions and the following disclaimer. 12206625Syongari * 2. Redistributions in binary form must reproduce the above copyright 13206625Syongari * notice, this list of conditions and the following disclaimer in the 14206625Syongari * documentation and/or other materials provided with the distribution. 15206625Syongari * 3. All advertising materials mentioning features or use of this software 16206625Syongari * must display the following acknowledgement: 17206625Syongari * This product includes software developed by Bill Paul. 18206625Syongari * 4. Neither the name of the author nor the names of any co-contributors 19206625Syongari * may be used to endorse or promote products derived from this software 20206625Syongari * without specific prior written permission. 21206625Syongari * 22206625Syongari * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' 23206625Syongari * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24206625Syongari * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25206625Syongari * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AUTHORS OR 26206625Syongari * THE VOICES IN THEIR HEADS BE LIABLE FOR ANY DIRECT, INDIRECT, 27206625Syongari * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28206625Syongari * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29206625Syongari * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30206625Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31206625Syongari * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32206625Syongari * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 33206625Syongari * OF THE POSSIBILITY OF SUCH DAMAGE. 34206625Syongari */ 35206625Syongari 36206625Syongari#include <sys/cdefs.h> 37206625Syongari__FBSDID("$FreeBSD: head/sys/dev/sge/if_sge.c 207071 2010-04-22 20:25:07Z yongari $"); 38206625Syongari 39206625Syongari/* 40206625Syongari * SiS 190/191 PCI Ethernet NIC driver. 41206625Syongari * 42206625Syongari * Adapted to SiS 190 NIC by Alexander Pohoyda based on the original 43206625Syongari * SiS 900 driver by Bill Paul, using SiS 190/191 Solaris driver by 44206625Syongari * Masayuki Murayama and SiS 190/191 GNU/Linux driver by K.M. Liu 45206625Syongari * <kmliu@sis.com>. Thanks to Pyun YongHyeon <pyunyh@gmail.com> for 46206625Syongari * review and very useful comments. 47206625Syongari * 48206625Syongari * Adapted to SiS 191 NIC by Nikolay Denev with further ideas from the 49206625Syongari * Linux and Solaris drivers. 50206625Syongari */ 51206625Syongari 52206625Syongari#include <sys/param.h> 53206625Syongari#include <sys/systm.h> 54206625Syongari#include <sys/bus.h> 55206625Syongari#include <sys/endian.h> 56206625Syongari#include <sys/kernel.h> 57206625Syongari#include <sys/lock.h> 58206625Syongari#include <sys/malloc.h> 59206625Syongari#include <sys/mbuf.h> 60206625Syongari#include <sys/module.h> 61206625Syongari#include <sys/mutex.h> 62206625Syongari#include <sys/rman.h> 63206625Syongari#include <sys/socket.h> 64206625Syongari#include <sys/sockio.h> 65206625Syongari 66206625Syongari#include <net/bpf.h> 67206625Syongari#include <net/if.h> 68206625Syongari#include <net/if_arp.h> 69206625Syongari#include <net/ethernet.h> 70206625Syongari#include <net/if_dl.h> 71206625Syongari#include <net/if_media.h> 72206625Syongari#include <net/if_types.h> 73206625Syongari#include <net/if_vlan_var.h> 74206625Syongari 75206625Syongari#include <machine/bus.h> 76206625Syongari#include <machine/resource.h> 77206625Syongari 78206625Syongari#include <dev/mii/mii.h> 79206625Syongari#include <dev/mii/miivar.h> 80206625Syongari 81206625Syongari#include <dev/pci/pcireg.h> 82206625Syongari#include <dev/pci/pcivar.h> 83206625Syongari 84206672Syongari#include <dev/sge/if_sgereg.h> 85206625Syongari 86206625SyongariMODULE_DEPEND(sge, pci, 1, 1, 1); 87206625SyongariMODULE_DEPEND(sge, ether, 1, 1, 1); 88206625SyongariMODULE_DEPEND(sge, miibus, 1, 1, 1); 89206625Syongari 90206625Syongari/* "device miibus0" required. See GENERIC if you get errors here. */ 91206625Syongari#include "miibus_if.h" 92206625Syongari 93206625Syongari/* 94206625Syongari * Various supported device vendors/types and their names. 95206625Syongari */ 96206625Syongaristatic struct sge_type sge_devs[] = { 97206625Syongari { SIS_VENDORID, SIS_DEVICEID_190, "SiS190 Fast Ethernet" }, 98206625Syongari { SIS_VENDORID, SIS_DEVICEID_191, "SiS191 Fast/Gigabit Ethernet" }, 99206625Syongari { 0, 0, NULL } 100206625Syongari}; 101206625Syongari 102206625Syongaristatic int sge_probe(device_t); 103206625Syongaristatic int sge_attach(device_t); 104206625Syongaristatic int sge_detach(device_t); 105206625Syongaristatic int sge_shutdown(device_t); 106206625Syongaristatic int sge_suspend(device_t); 107206625Syongaristatic int sge_resume(device_t); 108206625Syongari 109206625Syongaristatic int sge_miibus_readreg(device_t, int, int); 110206625Syongaristatic int sge_miibus_writereg(device_t, int, int, int); 111206625Syongaristatic void sge_miibus_statchg(device_t); 112206625Syongari 113206625Syongaristatic int sge_newbuf(struct sge_softc *, int); 114206625Syongaristatic int sge_encap(struct sge_softc *, struct mbuf **); 115206625Syongari#ifndef __NO_STRICT_ALIGNMENT 116206625Syongaristatic __inline void 117206625Syongari sge_fixup_rx(struct mbuf *); 118206625Syongari#endif 119206625Syongaristatic __inline void 120206625Syongari sge_discard_rxbuf(struct sge_softc *, int); 121206625Syongaristatic void sge_rxeof(struct sge_softc *); 122206625Syongaristatic void sge_txeof(struct sge_softc *); 123206625Syongaristatic void sge_intr(void *); 124206625Syongaristatic void sge_tick(void *); 125206625Syongaristatic void sge_start(struct ifnet *); 126206625Syongaristatic void sge_start_locked(struct ifnet *); 127206625Syongaristatic int sge_ioctl(struct ifnet *, u_long, caddr_t); 128206625Syongaristatic void sge_init(void *); 129206625Syongaristatic void sge_init_locked(struct sge_softc *); 130206625Syongaristatic void sge_stop(struct sge_softc *); 131206625Syongaristatic void sge_watchdog(struct sge_softc *); 132206625Syongaristatic int sge_ifmedia_upd(struct ifnet *); 133206625Syongaristatic void sge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 134206625Syongari 135206625Syongaristatic int sge_get_mac_addr_apc(struct sge_softc *, uint8_t *); 136206625Syongaristatic int sge_get_mac_addr_eeprom(struct sge_softc *, uint8_t *); 137206625Syongaristatic uint16_t sge_read_eeprom(struct sge_softc *, int); 138206625Syongari 139206625Syongaristatic void sge_rxfilter(struct sge_softc *); 140206625Syongaristatic void sge_reset(struct sge_softc *); 141206625Syongaristatic int sge_list_rx_init(struct sge_softc *); 142206625Syongaristatic int sge_list_rx_free(struct sge_softc *); 143206625Syongaristatic int sge_list_tx_init(struct sge_softc *); 144206625Syongaristatic int sge_list_tx_free(struct sge_softc *); 145206625Syongari 146206625Syongaristatic int sge_dma_alloc(struct sge_softc *); 147206625Syongaristatic void sge_dma_free(struct sge_softc *); 148206625Syongaristatic void sge_dma_map_addr(void *, bus_dma_segment_t *, int, int); 149206625Syongari 150206625Syongaristatic device_method_t sge_methods[] = { 151206625Syongari /* Device interface */ 152206625Syongari DEVMETHOD(device_probe, sge_probe), 153206625Syongari DEVMETHOD(device_attach, sge_attach), 154206625Syongari DEVMETHOD(device_detach, sge_detach), 155206625Syongari DEVMETHOD(device_suspend, sge_suspend), 156206625Syongari DEVMETHOD(device_resume, sge_resume), 157206625Syongari DEVMETHOD(device_shutdown, sge_shutdown), 158206625Syongari 159206625Syongari /* Bus interface */ 160206625Syongari DEVMETHOD(bus_print_child, bus_generic_print_child), 161206625Syongari DEVMETHOD(bus_driver_added, bus_generic_driver_added), 162206625Syongari 163206625Syongari /* MII interface */ 164206625Syongari DEVMETHOD(miibus_readreg, sge_miibus_readreg), 165206625Syongari DEVMETHOD(miibus_writereg, sge_miibus_writereg), 166206625Syongari DEVMETHOD(miibus_statchg, sge_miibus_statchg), 167206625Syongari 168206625Syongari KOBJMETHOD_END 169206625Syongari}; 170206625Syongari 171206625Syongaristatic driver_t sge_driver = { 172206625Syongari "sge", sge_methods, sizeof(struct sge_softc) 173206625Syongari}; 174206625Syongari 175206625Syongaristatic devclass_t sge_devclass; 176206625Syongari 177206625SyongariDRIVER_MODULE(sge, pci, sge_driver, sge_devclass, 0, 0); 178206625SyongariDRIVER_MODULE(miibus, sge, miibus_driver, miibus_devclass, 0, 0); 179206625Syongari 180206625Syongari/* 181206625Syongari * Register space access macros. 182206625Syongari */ 183206625Syongari#define CSR_WRITE_4(sc, reg, val) bus_write_4(sc->sge_res, reg, val) 184206625Syongari#define CSR_WRITE_2(sc, reg, val) bus_write_2(sc->sge_res, reg, val) 185206625Syongari#define CSR_WRITE_1(cs, reg, val) bus_write_1(sc->sge_res, reg, val) 186206625Syongari 187206625Syongari#define CSR_READ_4(sc, reg) bus_read_4(sc->sge_res, reg) 188206625Syongari#define CSR_READ_2(sc, reg) bus_read_2(sc->sge_res, reg) 189206625Syongari#define CSR_READ_1(sc, reg) bus_read_1(sc->sge_res, reg) 190206625Syongari 191206625Syongari/* Define to show Tx/Rx error status. */ 192206625Syongari#undef SGE_SHOW_ERRORS 193206625Syongari 194206625Syongari#define SGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP) 195206625Syongari 196206625Syongaristatic void 197206625Syongarisge_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) 198206625Syongari{ 199206625Syongari bus_addr_t *p; 200206625Syongari 201206625Syongari if (error != 0) 202206625Syongari return; 203206625Syongari KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); 204206625Syongari p = arg; 205206625Syongari *p = segs->ds_addr; 206206625Syongari} 207206625Syongari 208206625Syongari/* 209206625Syongari * Read a sequence of words from the EEPROM. 210206625Syongari */ 211206625Syongaristatic uint16_t 212206625Syongarisge_read_eeprom(struct sge_softc *sc, int offset) 213206625Syongari{ 214206625Syongari uint32_t val; 215206625Syongari int i; 216206625Syongari 217206625Syongari KASSERT(offset <= EI_OFFSET, ("EEPROM offset too big")); 218206625Syongari CSR_WRITE_4(sc, ROMInterface, 219206625Syongari EI_REQ | EI_OP_RD | (offset << EI_OFFSET_SHIFT)); 220206625Syongari DELAY(500); 221206625Syongari for (i = 0; i < SGE_TIMEOUT; i++) { 222206625Syongari val = CSR_READ_4(sc, ROMInterface); 223206625Syongari if ((val & EI_REQ) == 0) 224206625Syongari break; 225206625Syongari DELAY(100); 226206625Syongari } 227206625Syongari if (i == SGE_TIMEOUT) { 228206625Syongari device_printf(sc->sge_dev, 229206625Syongari "EEPROM read timeout : 0x%08x\n", val); 230206625Syongari return (0xffff); 231206625Syongari } 232206625Syongari 233206625Syongari return ((val & EI_DATA) >> EI_DATA_SHIFT); 234206625Syongari} 235206625Syongari 236206625Syongaristatic int 237206625Syongarisge_get_mac_addr_eeprom(struct sge_softc *sc, uint8_t *dest) 238206625Syongari{ 239206625Syongari uint16_t val; 240206625Syongari int i; 241206625Syongari 242206625Syongari val = sge_read_eeprom(sc, EEPROMSignature); 243206625Syongari if (val == 0xffff || val == 0) { 244206625Syongari device_printf(sc->sge_dev, 245206625Syongari "invalid EEPROM signature : 0x%04x\n", val); 246206625Syongari return (EINVAL); 247206625Syongari } 248206625Syongari 249206625Syongari for (i = 0; i < ETHER_ADDR_LEN; i += 2) { 250206625Syongari val = sge_read_eeprom(sc, EEPROMMACAddr + i / 2); 251206625Syongari dest[i + 0] = (uint8_t)val; 252206625Syongari dest[i + 1] = (uint8_t)(val >> 8); 253206625Syongari } 254206625Syongari 255206625Syongari if ((sge_read_eeprom(sc, EEPROMInfo) & 0x80) != 0) 256206625Syongari sc->sge_flags |= SGE_FLAG_RGMII; 257206625Syongari return (0); 258206625Syongari} 259206625Syongari 260206625Syongari/* 261206625Syongari * For SiS96x, APC CMOS RAM is used to store ethernet address. 262206625Syongari * APC CMOS RAM is accessed through ISA bridge. 263206625Syongari */ 264206625Syongaristatic int 265206625Syongarisge_get_mac_addr_apc(struct sge_softc *sc, uint8_t *dest) 266206625Syongari{ 267206625Syongari#if defined(__amd64__) || defined(__i386__) 268206625Syongari devclass_t pci; 269206625Syongari device_t bus, dev = NULL; 270206625Syongari device_t *kids; 271206625Syongari struct apc_tbl { 272206625Syongari uint16_t vid; 273206625Syongari uint16_t did; 274206625Syongari } *tp, apc_tbls[] = { 275206625Syongari { SIS_VENDORID, 0x0965 }, 276206625Syongari { SIS_VENDORID, 0x0966 }, 277206625Syongari { SIS_VENDORID, 0x0968 } 278206625Syongari }; 279206625Syongari uint8_t reg; 280206625Syongari int busnum, cnt, i, j, numkids; 281206625Syongari 282206625Syongari cnt = sizeof(apc_tbls) / sizeof(apc_tbls[0]); 283206625Syongari pci = devclass_find("pci"); 284206625Syongari for (busnum = 0; busnum < devclass_get_maxunit(pci); busnum++) { 285206625Syongari bus = devclass_get_device(pci, busnum); 286206625Syongari if (!bus) 287206625Syongari continue; 288206625Syongari if (device_get_children(bus, &kids, &numkids) != 0) 289206625Syongari continue; 290206625Syongari for (i = 0; i < numkids; i++) { 291206625Syongari dev = kids[i]; 292206625Syongari if (pci_get_class(dev) == PCIC_BRIDGE && 293206625Syongari pci_get_subclass(dev) == PCIS_BRIDGE_ISA) { 294206625Syongari tp = apc_tbls; 295206625Syongari for (j = 0; j < cnt; j++) { 296206625Syongari if (pci_get_vendor(dev) == tp->vid && 297206625Syongari pci_get_device(dev) == tp->did) { 298206625Syongari free(kids, M_TEMP); 299206625Syongari goto apc_found; 300206625Syongari } 301206625Syongari tp++; 302206625Syongari } 303206625Syongari } 304206625Syongari } 305206625Syongari free(kids, M_TEMP); 306206625Syongari } 307206625Syongari device_printf(sc->sge_dev, "couldn't find PCI-ISA bridge\n"); 308206625Syongari return (EINVAL); 309206625Syongariapc_found: 310206625Syongari /* Enable port 0x78 and 0x79 to access APC registers. */ 311206625Syongari reg = pci_read_config(dev, 0x48, 1); 312206625Syongari pci_write_config(dev, 0x48, reg & ~0x02, 1); 313206625Syongari DELAY(50); 314206625Syongari pci_read_config(dev, 0x48, 1); 315206625Syongari /* Read stored ethernet address. */ 316206625Syongari for (i = 0; i < ETHER_ADDR_LEN; i++) { 317206625Syongari outb(0x78, 0x09 + i); 318206625Syongari dest[i] = inb(0x79); 319206625Syongari } 320206625Syongari outb(0x78, 0x12); 321206625Syongari if ((inb(0x79) & 0x80) != 0) 322206625Syongari sc->sge_flags |= SGE_FLAG_RGMII; 323206625Syongari /* Restore access to APC registers. */ 324206625Syongari pci_write_config(dev, 0x48, reg, 1); 325206625Syongari 326206625Syongari return (0); 327206625Syongari#else 328206625Syongari return (EINVAL); 329206625Syongari#endif 330206625Syongari} 331206625Syongari 332206625Syongaristatic int 333206625Syongarisge_miibus_readreg(device_t dev, int phy, int reg) 334206625Syongari{ 335206625Syongari struct sge_softc *sc; 336206625Syongari uint32_t val; 337206625Syongari int i; 338206625Syongari 339206625Syongari sc = device_get_softc(dev); 340206625Syongari CSR_WRITE_4(sc, GMIIControl, (phy << GMI_PHY_SHIFT) | 341206625Syongari (reg << GMI_REG_SHIFT) | GMI_OP_RD | GMI_REQ); 342206625Syongari DELAY(10); 343206625Syongari for (i = 0; i < SGE_TIMEOUT; i++) { 344206625Syongari val = CSR_READ_4(sc, GMIIControl); 345206625Syongari if ((val & GMI_REQ) == 0) 346206625Syongari break; 347206625Syongari DELAY(10); 348206625Syongari } 349206625Syongari if (i == SGE_TIMEOUT) { 350206625Syongari device_printf(sc->sge_dev, "PHY read timeout : %d\n", reg); 351206625Syongari return (0); 352206625Syongari } 353206625Syongari return ((val & GMI_DATA) >> GMI_DATA_SHIFT); 354206625Syongari} 355206625Syongari 356206625Syongaristatic int 357206625Syongarisge_miibus_writereg(device_t dev, int phy, int reg, int data) 358206625Syongari{ 359206625Syongari struct sge_softc *sc; 360206625Syongari uint32_t val; 361206625Syongari int i; 362206625Syongari 363206625Syongari sc = device_get_softc(dev); 364206625Syongari CSR_WRITE_4(sc, GMIIControl, (phy << GMI_PHY_SHIFT) | 365206625Syongari (reg << GMI_REG_SHIFT) | (data << GMI_DATA_SHIFT) | 366206625Syongari GMI_OP_WR | GMI_REQ); 367206625Syongari DELAY(10); 368206625Syongari for (i = 0; i < SGE_TIMEOUT; i++) { 369206625Syongari val = CSR_READ_4(sc, GMIIControl); 370206625Syongari if ((val & GMI_REQ) == 0) 371206625Syongari break; 372206625Syongari DELAY(10); 373206625Syongari } 374206625Syongari if (i == SGE_TIMEOUT) 375206625Syongari device_printf(sc->sge_dev, "PHY write timeout : %d\n", reg); 376206625Syongari return (0); 377206625Syongari} 378206625Syongari 379206625Syongaristatic void 380206625Syongarisge_miibus_statchg(device_t dev) 381206625Syongari{ 382206625Syongari struct sge_softc *sc; 383206625Syongari struct mii_data *mii; 384206625Syongari struct ifnet *ifp; 385206625Syongari uint32_t ctl, speed; 386206625Syongari 387206625Syongari sc = device_get_softc(dev); 388206625Syongari mii = device_get_softc(sc->sge_miibus); 389206625Syongari ifp = sc->sge_ifp; 390206625Syongari if (mii == NULL || ifp == NULL || 391206625Syongari (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 392206625Syongari return; 393206625Syongari speed = 0; 394206625Syongari sc->sge_flags &= ~SGE_FLAG_LINK; 395206625Syongari if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == 396206625Syongari (IFM_ACTIVE | IFM_AVALID)) { 397206625Syongari switch (IFM_SUBTYPE(mii->mii_media_active)) { 398206625Syongari case IFM_10_T: 399206625Syongari sc->sge_flags |= SGE_FLAG_LINK; 400206625Syongari speed = SC_SPEED_10; 401206625Syongari break; 402206625Syongari case IFM_100_TX: 403206625Syongari sc->sge_flags |= SGE_FLAG_LINK; 404206625Syongari speed = SC_SPEED_100; 405206625Syongari break; 406206625Syongari case IFM_1000_T: 407206625Syongari if ((sc->sge_flags & SGE_FLAG_FASTETHER) == 0) { 408206625Syongari sc->sge_flags |= SGE_FLAG_LINK; 409206625Syongari speed = SC_SPEED_1000; 410206625Syongari } 411206625Syongari break; 412206625Syongari default: 413206625Syongari break; 414206625Syongari } 415206625Syongari } 416206625Syongari if ((sc->sge_flags & SGE_FLAG_LINK) == 0) 417206625Syongari return; 418206625Syongari /* Reprogram MAC to resolved speed/duplex/flow-control parameters. */ 419206625Syongari ctl = CSR_READ_4(sc, StationControl); 420206625Syongari ctl &= ~(0x0f000000 | SC_FDX | SC_SPEED_MASK); 421206625Syongari if (speed == SC_SPEED_1000) { 422206625Syongari ctl |= 0x07000000; 423206625Syongari sc->sge_flags |= SGE_FLAG_SPEED_1000; 424206625Syongari } else { 425206625Syongari ctl |= 0x04000000; 426206625Syongari sc->sge_flags &= ~SGE_FLAG_SPEED_1000; 427206625Syongari } 428206625Syongari#ifdef notyet 429206625Syongari if ((sc->sge_flags & SGE_FLAG_GMII) != 0) 430206625Syongari ctl |= 0x03000000; 431206625Syongari#endif 432206625Syongari ctl |= speed; 433206625Syongari if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { 434206625Syongari ctl |= SC_FDX; 435206625Syongari sc->sge_flags |= SGE_FLAG_FDX; 436206625Syongari } else 437206625Syongari sc->sge_flags &= ~SGE_FLAG_FDX; 438206625Syongari CSR_WRITE_4(sc, StationControl, ctl); 439206625Syongari if ((sc->sge_flags & SGE_FLAG_RGMII) != 0) { 440206625Syongari CSR_WRITE_4(sc, RGMIIDelay, 0x0441); 441206625Syongari CSR_WRITE_4(sc, RGMIIDelay, 0x0440); 442206625Syongari } 443206625Syongari} 444206625Syongari 445206625Syongaristatic void 446206625Syongarisge_rxfilter(struct sge_softc *sc) 447206625Syongari{ 448206625Syongari struct ifnet *ifp; 449206625Syongari struct ifmultiaddr *ifma; 450206625Syongari uint32_t crc, hashes[2]; 451206625Syongari uint16_t rxfilt; 452206625Syongari 453206625Syongari SGE_LOCK_ASSERT(sc); 454206625Syongari 455206625Syongari ifp = sc->sge_ifp; 456206625Syongari hashes[0] = hashes[1] = 0; 457206625Syongari rxfilt = AcceptMyPhys; 458206625Syongari if ((ifp->if_flags & IFF_BROADCAST) != 0) 459206625Syongari rxfilt |= AcceptBroadcast; 460206625Syongari if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { 461206625Syongari if ((ifp->if_flags & IFF_PROMISC) != 0) 462206625Syongari rxfilt |= AcceptAllPhys; 463206625Syongari rxfilt |= AcceptMulticast; 464206625Syongari hashes[0] = 0xFFFFFFFF; 465206625Syongari hashes[1] = 0xFFFFFFFF; 466206625Syongari goto done; 467206625Syongari } 468206625Syongari rxfilt |= AcceptMulticast; 469206625Syongari /* Now program new ones. */ 470206625Syongari if_maddr_rlock(ifp); 471206625Syongari TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 472206625Syongari if (ifma->ifma_addr->sa_family != AF_LINK) 473206625Syongari continue; 474206625Syongari crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) 475206625Syongari ifma->ifma_addr), ETHER_ADDR_LEN); 476206625Syongari hashes[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); 477206625Syongari } 478206625Syongari if_maddr_runlock(ifp); 479206625Syongaridone: 480206625Syongari CSR_WRITE_2(sc, RxMacControl, rxfilt | 0x02); 481206625Syongari CSR_WRITE_4(sc, RxHashTable, hashes[0]); 482206625Syongari CSR_WRITE_4(sc, RxHashTable2, hashes[1]); 483206625Syongari} 484206625Syongari 485206625Syongaristatic void 486206625Syongarisge_reset(struct sge_softc *sc) 487206625Syongari{ 488206625Syongari 489206625Syongari CSR_WRITE_4(sc, IntrMask, 0); 490206625Syongari CSR_WRITE_4(sc, IntrStatus, 0xffffffff); 491206625Syongari 492206625Syongari /* Soft reset. */ 493206625Syongari CSR_WRITE_4(sc, IntrControl, 0x8000); 494206625Syongari CSR_READ_4(sc, IntrControl); 495206625Syongari DELAY(100); 496206625Syongari CSR_WRITE_4(sc, IntrControl, 0); 497206625Syongari /* Stop MAC. */ 498206625Syongari CSR_WRITE_4(sc, TX_CTL, 0x1a00); 499206625Syongari CSR_WRITE_4(sc, RX_CTL, 0x1a00); 500206625Syongari 501206625Syongari CSR_WRITE_4(sc, IntrMask, 0); 502206625Syongari CSR_WRITE_4(sc, IntrStatus, 0xffffffff); 503206625Syongari 504206625Syongari CSR_WRITE_4(sc, GMIIControl, 0); 505206625Syongari} 506206625Syongari 507206625Syongari/* 508206625Syongari * Probe for an SiS chip. Check the PCI vendor and device 509206625Syongari * IDs against our list and return a device name if we find a match. 510206625Syongari */ 511206625Syongaristatic int 512206625Syongarisge_probe(device_t dev) 513206625Syongari{ 514206625Syongari struct sge_type *t; 515206625Syongari 516206625Syongari t = sge_devs; 517206625Syongari while (t->sge_name != NULL) { 518206625Syongari if ((pci_get_vendor(dev) == t->sge_vid) && 519206625Syongari (pci_get_device(dev) == t->sge_did)) { 520206625Syongari device_set_desc(dev, t->sge_name); 521206625Syongari return (BUS_PROBE_DEFAULT); 522206625Syongari } 523206625Syongari t++; 524206625Syongari } 525206625Syongari 526206625Syongari return (ENXIO); 527206625Syongari} 528206625Syongari 529206625Syongari/* 530206625Syongari * Attach the interface. Allocate softc structures, do ifmedia 531206625Syongari * setup and ethernet/BPF attach. 532206625Syongari */ 533206625Syongaristatic int 534206625Syongarisge_attach(device_t dev) 535206625Syongari{ 536206625Syongari struct sge_softc *sc; 537206625Syongari struct ifnet *ifp; 538206625Syongari uint8_t eaddr[ETHER_ADDR_LEN]; 539206625Syongari int error = 0, rid; 540206625Syongari 541206625Syongari sc = device_get_softc(dev); 542206625Syongari sc->sge_dev = dev; 543206625Syongari 544206625Syongari mtx_init(&sc->sge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 545206625Syongari MTX_DEF); 546206625Syongari callout_init_mtx(&sc->sge_stat_ch, &sc->sge_mtx, 0); 547206625Syongari 548206625Syongari /* 549206625Syongari * Map control/status registers. 550206625Syongari */ 551206625Syongari pci_enable_busmaster(dev); 552206625Syongari 553206625Syongari /* Allocate resources. */ 554206625Syongari sc->sge_res_id = PCIR_BAR(0); 555206625Syongari sc->sge_res_type = SYS_RES_MEMORY; 556206625Syongari sc->sge_res = bus_alloc_resource_any(dev, sc->sge_res_type, 557206625Syongari &sc->sge_res_id, RF_ACTIVE); 558206625Syongari if (sc->sge_res == NULL) { 559206625Syongari device_printf(dev, "couldn't allocate resource\n"); 560206625Syongari error = ENXIO; 561206625Syongari goto fail; 562206625Syongari } 563206625Syongari 564206625Syongari rid = 0; 565206625Syongari sc->sge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 566206625Syongari RF_SHAREABLE | RF_ACTIVE); 567206625Syongari if (sc->sge_irq == NULL) { 568206625Syongari device_printf(dev, "couldn't allocate IRQ resources\n"); 569206625Syongari error = ENXIO; 570206625Syongari goto fail; 571206625Syongari } 572206625Syongari sc->sge_rev = pci_get_revid(dev); 573206625Syongari if (pci_get_device(dev) == SIS_DEVICEID_190) 574206625Syongari sc->sge_flags |= SGE_FLAG_FASTETHER; 575206625Syongari /* Reset the adapter. */ 576206625Syongari sge_reset(sc); 577206625Syongari 578206625Syongari /* Get MAC address from the EEPROM. */ 579206625Syongari if ((pci_read_config(dev, 0x73, 1) & 0x01) != 0) 580206625Syongari sge_get_mac_addr_apc(sc, eaddr); 581206625Syongari else 582206625Syongari sge_get_mac_addr_eeprom(sc, eaddr); 583206625Syongari 584206625Syongari if ((error = sge_dma_alloc(sc)) != 0) 585206625Syongari goto fail; 586206625Syongari 587206625Syongari ifp = sc->sge_ifp = if_alloc(IFT_ETHER); 588206625Syongari if (ifp == NULL) { 589206625Syongari device_printf(dev, "cannot allocate ifnet structure.\n"); 590206625Syongari error = ENOSPC; 591206625Syongari goto fail; 592206625Syongari } 593206625Syongari ifp->if_softc = sc; 594206625Syongari if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 595206625Syongari ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 596206625Syongari ifp->if_ioctl = sge_ioctl; 597206625Syongari ifp->if_start = sge_start; 598206625Syongari ifp->if_init = sge_init; 599206625Syongari ifp->if_snd.ifq_drv_maxlen = SGE_TX_RING_CNT - 1; 600206625Syongari IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 601206625Syongari IFQ_SET_READY(&ifp->if_snd); 602206625Syongari ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_RXCSUM; 603206625Syongari ifp->if_hwassist = SGE_CSUM_FEATURES; 604206625Syongari ifp->if_capenable = ifp->if_capabilities; 605206625Syongari /* 606206625Syongari * Do MII setup. 607206625Syongari */ 608206625Syongari if (mii_phy_probe(dev, &sc->sge_miibus, sge_ifmedia_upd, 609206625Syongari sge_ifmedia_sts)) { 610206625Syongari device_printf(dev, "no PHY found!\n"); 611206625Syongari error = ENXIO; 612206625Syongari goto fail; 613206625Syongari } 614206625Syongari 615206625Syongari /* 616206625Syongari * Call MI attach routine. 617206625Syongari */ 618206625Syongari ether_ifattach(ifp, eaddr); 619206625Syongari 620206625Syongari /* VLAN setup. */ 621206625Syongari ifp->if_capabilities |= IFCAP_VLAN_MTU; 622206625Syongari ifp->if_capenable = ifp->if_capabilities; 623206625Syongari /* Tell the upper layer(s) we support long frames. */ 624206625Syongari ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 625206625Syongari 626206625Syongari /* Hook interrupt last to avoid having to lock softc */ 627206625Syongari error = bus_setup_intr(dev, sc->sge_irq, INTR_TYPE_NET | INTR_MPSAFE, 628206625Syongari NULL, sge_intr, sc, &sc->sge_intrhand); 629206625Syongari if (error) { 630206625Syongari device_printf(dev, "couldn't set up irq\n"); 631206625Syongari ether_ifdetach(ifp); 632206625Syongari goto fail; 633206625Syongari } 634206625Syongari 635206625Syongarifail: 636206625Syongari if (error) 637206625Syongari sge_detach(dev); 638206625Syongari 639206625Syongari return (error); 640206625Syongari} 641206625Syongari 642206625Syongari/* 643206625Syongari * Shutdown hardware and free up resources. This can be called any 644206625Syongari * time after the mutex has been initialized. It is called in both 645206625Syongari * the error case in attach and the normal detach case so it needs 646206625Syongari * to be careful about only freeing resources that have actually been 647206625Syongari * allocated. 648206625Syongari */ 649206625Syongaristatic int 650206625Syongarisge_detach(device_t dev) 651206625Syongari{ 652206625Syongari struct sge_softc *sc; 653206625Syongari struct ifnet *ifp; 654206625Syongari 655206625Syongari sc = device_get_softc(dev); 656206625Syongari ifp = sc->sge_ifp; 657206625Syongari /* These should only be active if attach succeeded. */ 658206625Syongari if (device_is_attached(dev)) { 659206625Syongari ether_ifdetach(ifp); 660206625Syongari SGE_LOCK(sc); 661206625Syongari sge_stop(sc); 662206625Syongari SGE_UNLOCK(sc); 663206625Syongari callout_drain(&sc->sge_stat_ch); 664206625Syongari } 665206625Syongari if (sc->sge_miibus) 666206625Syongari device_delete_child(dev, sc->sge_miibus); 667206625Syongari bus_generic_detach(dev); 668206625Syongari 669206625Syongari if (sc->sge_intrhand) 670206625Syongari bus_teardown_intr(dev, sc->sge_irq, sc->sge_intrhand); 671206625Syongari if (sc->sge_irq) 672206625Syongari bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sge_irq); 673206625Syongari if (sc->sge_res) 674206625Syongari bus_release_resource(dev, sc->sge_res_type, sc->sge_res_id, 675206625Syongari sc->sge_res); 676206625Syongari if (ifp) 677206625Syongari if_free(ifp); 678206625Syongari sge_dma_free(sc); 679206625Syongari mtx_destroy(&sc->sge_mtx); 680206625Syongari 681206625Syongari return (0); 682206625Syongari} 683206625Syongari 684206625Syongari/* 685206625Syongari * Stop all chip I/O so that the kernel's probe routines don't 686206625Syongari * get confused by errant DMAs when rebooting. 687206625Syongari */ 688206625Syongaristatic int 689206625Syongarisge_shutdown(device_t dev) 690206625Syongari{ 691206625Syongari struct sge_softc *sc; 692206625Syongari 693206625Syongari sc = device_get_softc(dev); 694206625Syongari SGE_LOCK(sc); 695206625Syongari sge_stop(sc); 696206625Syongari SGE_UNLOCK(sc); 697206625Syongari return (0); 698206625Syongari} 699206625Syongari 700206625Syongaristatic int 701206625Syongarisge_suspend(device_t dev) 702206625Syongari{ 703206625Syongari struct sge_softc *sc; 704206625Syongari struct ifnet *ifp; 705206625Syongari 706206625Syongari sc = device_get_softc(dev); 707206625Syongari SGE_LOCK(sc); 708206625Syongari ifp = sc->sge_ifp; 709206625Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 710206625Syongari sge_stop(sc); 711206625Syongari SGE_UNLOCK(sc); 712206625Syongari return (0); 713206625Syongari} 714206625Syongari 715206625Syongaristatic int 716206625Syongarisge_resume(device_t dev) 717206625Syongari{ 718206625Syongari struct sge_softc *sc; 719206625Syongari struct ifnet *ifp; 720206625Syongari 721206625Syongari sc = device_get_softc(dev); 722206625Syongari SGE_LOCK(sc); 723206625Syongari ifp = sc->sge_ifp; 724206625Syongari if ((ifp->if_flags & IFF_UP) != 0) 725206625Syongari sge_init_locked(sc); 726206625Syongari SGE_UNLOCK(sc); 727206625Syongari return (0); 728206625Syongari} 729206625Syongari 730206625Syongaristatic int 731206625Syongarisge_dma_alloc(struct sge_softc *sc) 732206625Syongari{ 733206625Syongari struct sge_chain_data *cd; 734206625Syongari struct sge_list_data *ld; 735206625Syongari int error, i; 736206625Syongari 737206625Syongari cd = &sc->sge_cdata; 738206625Syongari ld = &sc->sge_ldata; 739206625Syongari error = bus_dma_tag_create(bus_get_dma_tag(sc->sge_dev), 740206625Syongari 1, 0, /* alignment, boundary */ 741206625Syongari BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 742206625Syongari BUS_SPACE_MAXADDR, /* highaddr */ 743206625Syongari NULL, NULL, /* filter, filterarg */ 744206625Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 745206625Syongari 1, /* nsegments */ 746206625Syongari BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 747206625Syongari 0, /* flags */ 748206625Syongari NULL, /* lockfunc */ 749206625Syongari NULL, /* lockarg */ 750206625Syongari &cd->sge_tag); 751206625Syongari if (error != 0) { 752206625Syongari device_printf(sc->sge_dev, 753206625Syongari "could not create parent DMA tag.\n"); 754206625Syongari goto fail; 755206625Syongari } 756206625Syongari 757206625Syongari /* RX descriptor ring */ 758206625Syongari error = bus_dma_tag_create(cd->sge_tag, 759206625Syongari SGE_DESC_ALIGN, 0, /* alignment, boundary */ 760206625Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 761206625Syongari BUS_SPACE_MAXADDR, /* highaddr */ 762206625Syongari NULL, NULL, /* filter, filterarg */ 763206625Syongari SGE_RX_RING_SZ, 1, /* maxsize,nsegments */ 764206625Syongari SGE_RX_RING_SZ, /* maxsegsize */ 765206625Syongari 0, /* flags */ 766206625Syongari NULL, /* lockfunc */ 767206625Syongari NULL, /* lockarg */ 768206625Syongari &cd->sge_rx_tag); 769206625Syongari if (error != 0) { 770206625Syongari device_printf(sc->sge_dev, 771206625Syongari "could not create Rx ring DMA tag.\n"); 772206625Syongari goto fail; 773206625Syongari } 774206625Syongari /* Allocate DMA'able memory and load DMA map for RX ring. */ 775206625Syongari error = bus_dmamem_alloc(cd->sge_rx_tag, (void **)&ld->sge_rx_ring, 776206625Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 777206625Syongari &cd->sge_rx_dmamap); 778206625Syongari if (error != 0) { 779206625Syongari device_printf(sc->sge_dev, 780206625Syongari "could not allocate DMA'able memory for Rx ring.\n"); 781206625Syongari goto fail; 782206625Syongari } 783206625Syongari error = bus_dmamap_load(cd->sge_rx_tag, cd->sge_rx_dmamap, 784206625Syongari ld->sge_rx_ring, SGE_RX_RING_SZ, sge_dma_map_addr, 785206625Syongari &ld->sge_rx_paddr, BUS_DMA_NOWAIT); 786206625Syongari if (error != 0) { 787206625Syongari device_printf(sc->sge_dev, 788206625Syongari "could not load DMA'able memory for Rx ring.\n"); 789206625Syongari } 790206625Syongari 791206625Syongari /* TX descriptor ring */ 792206625Syongari error = bus_dma_tag_create(cd->sge_tag, 793206625Syongari SGE_DESC_ALIGN, 0, /* alignment, boundary */ 794206625Syongari BUS_SPACE_MAXADDR, /* lowaddr */ 795206625Syongari BUS_SPACE_MAXADDR, /* highaddr */ 796206625Syongari NULL, NULL, /* filter, filterarg */ 797206625Syongari SGE_TX_RING_SZ, 1, /* maxsize,nsegments */ 798206625Syongari SGE_TX_RING_SZ, /* maxsegsize */ 799206625Syongari 0, /* flags */ 800206625Syongari NULL, /* lockfunc */ 801206625Syongari NULL, /* lockarg */ 802206625Syongari &cd->sge_tx_tag); 803206625Syongari if (error != 0) { 804206625Syongari device_printf(sc->sge_dev, 805206625Syongari "could not create Rx ring DMA tag.\n"); 806206625Syongari goto fail; 807206625Syongari } 808206625Syongari /* Allocate DMA'able memory and load DMA map for TX ring. */ 809206625Syongari error = bus_dmamem_alloc(cd->sge_tx_tag, (void **)&ld->sge_tx_ring, 810206625Syongari BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, 811206625Syongari &cd->sge_tx_dmamap); 812206625Syongari if (error != 0) { 813206625Syongari device_printf(sc->sge_dev, 814206625Syongari "could not allocate DMA'able memory for Tx ring.\n"); 815206625Syongari goto fail; 816206625Syongari } 817206625Syongari error = bus_dmamap_load(cd->sge_tx_tag, cd->sge_tx_dmamap, 818206625Syongari ld->sge_tx_ring, SGE_TX_RING_SZ, sge_dma_map_addr, 819206625Syongari &ld->sge_tx_paddr, BUS_DMA_NOWAIT); 820206625Syongari if (error != 0) { 821206625Syongari device_printf(sc->sge_dev, 822206625Syongari "could not load DMA'able memory for Rx ring.\n"); 823206625Syongari goto fail; 824206625Syongari } 825206625Syongari 826206625Syongari /* Create DMA tag for Tx buffers. */ 827206625Syongari error = bus_dma_tag_create(cd->sge_tag, 1, 0, BUS_SPACE_MAXADDR, 828206625Syongari BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES * SGE_MAXTXSEGS, 829206625Syongari SGE_MAXTXSEGS, MCLBYTES, 0, NULL, NULL, &cd->sge_txmbuf_tag); 830206625Syongari if (error != 0) { 831206625Syongari device_printf(sc->sge_dev, 832206625Syongari "could not create Tx mbuf DMA tag.\n"); 833206625Syongari goto fail; 834206625Syongari } 835206625Syongari 836206625Syongari /* Create DMA tag for Rx buffers. */ 837206625Syongari error = bus_dma_tag_create(cd->sge_tag, SGE_RX_BUF_ALIGN, 0, 838206625Syongari BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, 839206625Syongari MCLBYTES, 0, NULL, NULL, &cd->sge_rxmbuf_tag); 840206625Syongari if (error != 0) { 841206625Syongari device_printf(sc->sge_dev, 842206625Syongari "could not create Rx mbuf DMA tag.\n"); 843206625Syongari goto fail; 844206625Syongari } 845206625Syongari 846206625Syongari /* Create DMA maps for Tx buffers. */ 847206625Syongari for (i = 0; i < SGE_TX_RING_CNT; i++) { 848206625Syongari error = bus_dmamap_create(cd->sge_txmbuf_tag, 0, 849206625Syongari &cd->sge_tx_map[i]); 850206625Syongari if (error != 0) { 851206625Syongari device_printf(sc->sge_dev, 852206625Syongari "could not create Tx DMA map.\n"); 853206625Syongari goto fail; 854206625Syongari } 855206625Syongari } 856206625Syongari /* Create spare DMA map for Rx buffer. */ 857206625Syongari error = bus_dmamap_create(cd->sge_rxmbuf_tag, 0, &cd->sge_rx_spare_map); 858206625Syongari if (error != 0) { 859206625Syongari device_printf(sc->sge_dev, 860206625Syongari "could not create spare Rx DMA map.\n"); 861206625Syongari goto fail; 862206625Syongari } 863206625Syongari /* Create DMA maps for Rx buffers. */ 864206625Syongari for (i = 0; i < SGE_RX_RING_CNT; i++) { 865206625Syongari error = bus_dmamap_create(cd->sge_rxmbuf_tag, 0, 866206625Syongari &cd->sge_rx_map[i]); 867206625Syongari if (error) { 868206625Syongari device_printf(sc->sge_dev, 869206625Syongari "could not create Rx DMA map.\n"); 870206625Syongari goto fail; 871206625Syongari } 872206625Syongari } 873206625Syongarifail: 874206625Syongari return (error); 875206625Syongari} 876206625Syongari 877206625Syongaristatic void 878206625Syongarisge_dma_free(struct sge_softc *sc) 879206625Syongari{ 880206625Syongari struct sge_chain_data *cd; 881206625Syongari struct sge_list_data *ld; 882206625Syongari int i; 883206625Syongari 884206625Syongari cd = &sc->sge_cdata; 885206625Syongari ld = &sc->sge_ldata; 886206625Syongari /* Rx ring. */ 887206625Syongari if (cd->sge_rx_tag != NULL) { 888206625Syongari if (cd->sge_rx_dmamap != NULL) 889206625Syongari bus_dmamap_unload(cd->sge_rx_tag, cd->sge_rx_dmamap); 890206625Syongari if (cd->sge_rx_dmamap != NULL && ld->sge_rx_ring != NULL) 891206625Syongari bus_dmamem_free(cd->sge_rx_tag, ld->sge_rx_ring, 892206625Syongari cd->sge_rx_dmamap); 893206625Syongari ld->sge_rx_ring = NULL; 894206625Syongari cd->sge_rx_dmamap = NULL; 895206625Syongari bus_dma_tag_destroy(cd->sge_rx_tag); 896206625Syongari cd->sge_rx_tag = NULL; 897206625Syongari } 898206625Syongari /* Tx ring. */ 899206625Syongari if (cd->sge_tx_tag != NULL) { 900206625Syongari if (cd->sge_tx_dmamap != NULL) 901206625Syongari bus_dmamap_unload(cd->sge_tx_tag, cd->sge_tx_dmamap); 902206625Syongari if (cd->sge_tx_dmamap != NULL && ld->sge_tx_ring != NULL) 903206625Syongari bus_dmamem_free(cd->sge_tx_tag, ld->sge_tx_ring, 904206625Syongari cd->sge_tx_dmamap); 905206625Syongari ld->sge_tx_ring = NULL; 906206625Syongari cd->sge_tx_dmamap = NULL; 907206625Syongari bus_dma_tag_destroy(cd->sge_tx_tag); 908206625Syongari cd->sge_tx_tag = NULL; 909206625Syongari } 910206625Syongari /* Rx buffers. */ 911206625Syongari if (cd->sge_rxmbuf_tag != NULL) { 912206625Syongari for (i = 0; i < SGE_RX_RING_CNT; i++) { 913206625Syongari if (cd->sge_rx_map[i] != NULL) { 914206625Syongari bus_dmamap_destroy(cd->sge_rxmbuf_tag, 915206625Syongari cd->sge_rx_map[i]); 916206625Syongari cd->sge_rx_map[i] = NULL; 917206625Syongari } 918206625Syongari } 919206625Syongari if (cd->sge_rx_spare_map != NULL) { 920206625Syongari bus_dmamap_destroy(cd->sge_rxmbuf_tag, 921206625Syongari cd->sge_rx_spare_map); 922206625Syongari cd->sge_rx_spare_map = NULL; 923206625Syongari } 924206625Syongari bus_dma_tag_destroy(cd->sge_rxmbuf_tag); 925206625Syongari cd->sge_rxmbuf_tag = NULL; 926206625Syongari } 927206625Syongari /* Tx buffers. */ 928206625Syongari if (cd->sge_txmbuf_tag != NULL) { 929206625Syongari for (i = 0; i < SGE_TX_RING_CNT; i++) { 930206625Syongari if (cd->sge_tx_map[i] != NULL) { 931206625Syongari bus_dmamap_destroy(cd->sge_txmbuf_tag, 932206625Syongari cd->sge_tx_map[i]); 933206625Syongari cd->sge_tx_map[i] = NULL; 934206625Syongari } 935206625Syongari } 936206625Syongari bus_dma_tag_destroy(cd->sge_txmbuf_tag); 937206625Syongari cd->sge_txmbuf_tag = NULL; 938206625Syongari } 939206625Syongari if (cd->sge_tag != NULL) 940206625Syongari bus_dma_tag_destroy(cd->sge_tag); 941206625Syongari cd->sge_tag = NULL; 942206625Syongari} 943206625Syongari 944206625Syongari/* 945206625Syongari * Initialize the TX descriptors. 946206625Syongari */ 947206625Syongaristatic int 948206625Syongarisge_list_tx_init(struct sge_softc *sc) 949206625Syongari{ 950206625Syongari struct sge_list_data *ld; 951206625Syongari struct sge_chain_data *cd; 952206625Syongari 953206625Syongari SGE_LOCK_ASSERT(sc); 954206625Syongari ld = &sc->sge_ldata; 955206625Syongari cd = &sc->sge_cdata; 956206625Syongari bzero(ld->sge_tx_ring, SGE_TX_RING_SZ); 957206625Syongari ld->sge_tx_ring[SGE_TX_RING_CNT - 1].sge_flags = htole32(RING_END); 958206625Syongari bus_dmamap_sync(cd->sge_tx_tag, cd->sge_tx_dmamap, 959206625Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 960206625Syongari cd->sge_tx_prod = 0; 961206625Syongari cd->sge_tx_cons = 0; 962206625Syongari cd->sge_tx_cnt = 0; 963206625Syongari return (0); 964206625Syongari} 965206625Syongari 966206625Syongaristatic int 967206625Syongarisge_list_tx_free(struct sge_softc *sc) 968206625Syongari{ 969206625Syongari struct sge_chain_data *cd; 970206625Syongari int i; 971206625Syongari 972206625Syongari SGE_LOCK_ASSERT(sc); 973206625Syongari cd = &sc->sge_cdata; 974206625Syongari for (i = 0; i < SGE_TX_RING_CNT; i++) { 975206625Syongari if (cd->sge_tx_mbuf[i] != NULL) { 976206625Syongari bus_dmamap_sync(cd->sge_txmbuf_tag, 977206625Syongari cd->sge_tx_map[i], BUS_DMASYNC_POSTWRITE); 978206625Syongari bus_dmamap_unload(cd->sge_txmbuf_tag, 979206625Syongari cd->sge_tx_map[i]); 980206625Syongari m_free(cd->sge_tx_mbuf[i]); 981206625Syongari cd->sge_tx_mbuf[i] = NULL; 982206625Syongari } 983206625Syongari } 984206625Syongari 985206625Syongari return (0); 986206625Syongari} 987206625Syongari 988206625Syongari/* 989206625Syongari * Initialize the RX descriptors and allocate mbufs for them. Note that 990206625Syongari * we arrange the descriptors in a closed ring, so that the last descriptor 991206625Syongari * has RING_END flag set. 992206625Syongari */ 993206625Syongaristatic int 994206625Syongarisge_list_rx_init(struct sge_softc *sc) 995206625Syongari{ 996206625Syongari struct sge_chain_data *cd; 997206625Syongari int i; 998206625Syongari 999206625Syongari SGE_LOCK_ASSERT(sc); 1000206625Syongari cd = &sc->sge_cdata; 1001206625Syongari cd->sge_rx_cons = 0; 1002206625Syongari bzero(sc->sge_ldata.sge_rx_ring, SGE_RX_RING_SZ); 1003206625Syongari for (i = 0; i < SGE_RX_RING_CNT; i++) { 1004206625Syongari if (sge_newbuf(sc, i) != 0) 1005206625Syongari return (ENOBUFS); 1006206625Syongari } 1007206625Syongari bus_dmamap_sync(cd->sge_rx_tag, cd->sge_rx_dmamap, 1008206625Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1009206625Syongari return (0); 1010206625Syongari} 1011206625Syongari 1012206625Syongaristatic int 1013206625Syongarisge_list_rx_free(struct sge_softc *sc) 1014206625Syongari{ 1015206625Syongari struct sge_chain_data *cd; 1016206625Syongari int i; 1017206625Syongari 1018206625Syongari SGE_LOCK_ASSERT(sc); 1019206625Syongari cd = &sc->sge_cdata; 1020206625Syongari for (i = 0; i < SGE_RX_RING_CNT; i++) { 1021206625Syongari if (cd->sge_rx_mbuf[i] != NULL) { 1022206625Syongari bus_dmamap_sync(cd->sge_rxmbuf_tag, cd->sge_rx_map[i], 1023206625Syongari BUS_DMASYNC_POSTREAD); 1024206625Syongari bus_dmamap_unload(cd->sge_rxmbuf_tag, 1025206625Syongari cd->sge_rx_map[i]); 1026206625Syongari m_free(cd->sge_rx_mbuf[i]); 1027206625Syongari cd->sge_rx_mbuf[i] = NULL; 1028206625Syongari } 1029206625Syongari } 1030206625Syongari return (0); 1031206625Syongari} 1032206625Syongari 1033206625Syongari/* 1034206625Syongari * Initialize an RX descriptor and attach an MBUF cluster. 1035206625Syongari */ 1036206625Syongaristatic int 1037206625Syongarisge_newbuf(struct sge_softc *sc, int prod) 1038206625Syongari{ 1039206625Syongari struct mbuf *m; 1040206625Syongari struct sge_desc *desc; 1041206625Syongari struct sge_chain_data *cd; 1042206625Syongari bus_dma_segment_t segs[1]; 1043206625Syongari bus_dmamap_t map; 1044206625Syongari int error, nsegs; 1045206625Syongari 1046206625Syongari SGE_LOCK_ASSERT(sc); 1047206625Syongari 1048206625Syongari cd = &sc->sge_cdata; 1049206625Syongari m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1050206625Syongari if (m == NULL) 1051206625Syongari return (ENOBUFS); 1052206625Syongari m->m_len = m->m_pkthdr.len = MCLBYTES; 1053206625Syongari m_adj(m, SGE_RX_BUF_ALIGN); 1054206625Syongari error = bus_dmamap_load_mbuf_sg(cd->sge_rxmbuf_tag, 1055206625Syongari cd->sge_rx_spare_map, m, segs, &nsegs, 0); 1056206625Syongari if (error != 0) { 1057206625Syongari m_freem(m); 1058206625Syongari return (error); 1059206625Syongari } 1060206625Syongari KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); 1061206625Syongari if (cd->sge_rx_mbuf[prod] != NULL) { 1062206625Syongari bus_dmamap_sync(cd->sge_rxmbuf_tag, cd->sge_rx_map[prod], 1063206625Syongari BUS_DMASYNC_POSTREAD); 1064206625Syongari bus_dmamap_unload(cd->sge_rxmbuf_tag, cd->sge_rx_map[prod]); 1065206625Syongari } 1066206625Syongari map = cd->sge_rx_map[prod]; 1067206625Syongari cd->sge_rx_map[prod] = cd->sge_rx_spare_map; 1068206625Syongari cd->sge_rx_spare_map = map; 1069206625Syongari bus_dmamap_sync(cd->sge_rxmbuf_tag, cd->sge_rx_map[prod], 1070206625Syongari BUS_DMASYNC_PREREAD); 1071206625Syongari cd->sge_rx_mbuf[prod] = m; 1072206625Syongari 1073206625Syongari desc = &sc->sge_ldata.sge_rx_ring[prod]; 1074206625Syongari desc->sge_sts_size = 0; 1075206625Syongari desc->sge_ptr = htole32(SGE_ADDR_LO(segs[0].ds_addr)); 1076206625Syongari desc->sge_flags = htole32(segs[0].ds_len); 1077206625Syongari if (prod == SGE_RX_RING_CNT - 1) 1078206625Syongari desc->sge_flags |= htole32(RING_END); 1079206625Syongari desc->sge_cmdsts = htole32(RDC_OWN | RDC_INTR | RDC_IP_CSUM | 1080206625Syongari RDC_TCP_CSUM | RDC_UDP_CSUM); 1081206625Syongari return (0); 1082206625Syongari} 1083206625Syongari 1084206625Syongari#ifndef __NO_STRICT_ALIGNMENT 1085206625Syongaristatic __inline void 1086206625Syongarisge_fixup_rx(struct mbuf *m) 1087206625Syongari{ 1088206625Syongari int i; 1089206625Syongari uint16_t *src, *dst; 1090206625Syongari 1091206625Syongari src = mtod(m, uint16_t *); 1092206625Syongari dst = src - 3; 1093206625Syongari 1094206625Syongari for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) 1095206625Syongari *dst++ = *src++; 1096206625Syongari 1097206625Syongari m->m_data -= (SGE_RX_BUF_ALIGN - ETHER_ALIGN); 1098206625Syongari} 1099206625Syongari#endif 1100206625Syongari 1101206625Syongaristatic __inline void 1102206625Syongarisge_discard_rxbuf(struct sge_softc *sc, int index) 1103206625Syongari{ 1104206625Syongari struct sge_desc *desc; 1105206625Syongari 1106206625Syongari desc = &sc->sge_ldata.sge_rx_ring[index]; 1107206625Syongari desc->sge_sts_size = 0; 1108206625Syongari desc->sge_flags = htole32(MCLBYTES - SGE_RX_BUF_ALIGN); 1109206625Syongari if (index == SGE_RX_RING_CNT - 1) 1110206625Syongari desc->sge_flags |= htole32(RING_END); 1111206625Syongari desc->sge_cmdsts = htole32(RDC_OWN | RDC_INTR | RDC_IP_CSUM | 1112206625Syongari RDC_TCP_CSUM | RDC_UDP_CSUM); 1113206625Syongari} 1114206625Syongari 1115206625Syongari/* 1116206625Syongari * A frame has been uploaded: pass the resulting mbuf chain up to 1117206625Syongari * the higher level protocols. 1118206625Syongari */ 1119206625Syongaristatic void 1120206625Syongarisge_rxeof(struct sge_softc *sc) 1121206625Syongari{ 1122206625Syongari struct ifnet *ifp; 1123206625Syongari struct mbuf *m; 1124206625Syongari struct sge_chain_data *cd; 1125206625Syongari struct sge_desc *cur_rx; 1126206625Syongari uint32_t rxinfo, rxstat; 1127206625Syongari int cons, prog; 1128206625Syongari 1129206625Syongari SGE_LOCK_ASSERT(sc); 1130206625Syongari 1131206625Syongari ifp = sc->sge_ifp; 1132206625Syongari cd = &sc->sge_cdata; 1133206625Syongari 1134206625Syongari bus_dmamap_sync(cd->sge_rx_tag, cd->sge_rx_dmamap, 1135206625Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1136206625Syongari cons = cd->sge_rx_cons; 1137206625Syongari for (prog = 0; prog < SGE_RX_RING_CNT; prog++, 1138206625Syongari SGE_INC(cons, SGE_RX_RING_CNT)) { 1139206625Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1140206625Syongari break; 1141206625Syongari cur_rx = &sc->sge_ldata.sge_rx_ring[cons]; 1142206625Syongari rxinfo = le32toh(cur_rx->sge_cmdsts); 1143206625Syongari if ((rxinfo & RDC_OWN) != 0) 1144206625Syongari break; 1145206625Syongari rxstat = le32toh(cur_rx->sge_sts_size); 1146206625Syongari if (SGE_RX_ERROR(rxstat) != 0 || SGE_RX_NSEGS(rxstat) != 1) { 1147206625Syongari /* XXX We don't support multi-segment frames yet. */ 1148206625Syongari#ifdef SGE_SHOW_ERRORS 1149206625Syongari device_printf(sc->sge_dev, "Rx error : 0x%b\n", rxstat, 1150206625Syongari RX_ERR_BITS); 1151206625Syongari#endif 1152206625Syongari sge_discard_rxbuf(sc, cons); 1153206625Syongari ifp->if_ierrors++; 1154206625Syongari continue; 1155206625Syongari } 1156206625Syongari m = cd->sge_rx_mbuf[cons]; 1157206625Syongari if (sge_newbuf(sc, cons) != 0) { 1158206625Syongari sge_discard_rxbuf(sc, cons); 1159206625Syongari ifp->if_iqdrops++; 1160206625Syongari continue; 1161206625Syongari } 1162206625Syongari if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { 1163206625Syongari if ((rxinfo & RDC_IP_CSUM) != 0 && 1164206625Syongari (rxinfo & RDC_IP_CSUM_OK) != 0) 1165206625Syongari m->m_pkthdr.csum_flags |= 1166206625Syongari CSUM_IP_CHECKED | CSUM_IP_VALID; 1167206625Syongari if (((rxinfo & RDC_TCP_CSUM) != 0 && 1168206625Syongari (rxinfo & RDC_TCP_CSUM_OK) != 0) || 1169206625Syongari ((rxinfo & RDC_UDP_CSUM) != 0 && 1170206625Syongari (rxinfo & RDC_UDP_CSUM_OK) != 0)) { 1171206625Syongari m->m_pkthdr.csum_flags |= 1172206625Syongari CSUM_DATA_VALID | CSUM_PSEUDO_HDR; 1173206625Syongari m->m_pkthdr.csum_data = 0xffff; 1174206625Syongari } 1175206625Syongari } 1176206625Syongari /* 1177206625Syongari * TODO : VLAN hardware tag stripping. 1178206625Syongari */ 1179206625Syongari m->m_pkthdr.len = m->m_len = 1180206625Syongari SGE_RX_BYTES(rxstat) - ETHER_CRC_LEN; 1181206625Syongari#ifndef __NO_STRICT_ALIGNMENT 1182206625Syongari sge_fixup_rx(m); 1183206625Syongari#endif 1184206625Syongari m->m_pkthdr.rcvif = ifp; 1185206625Syongari ifp->if_ipackets++; 1186206625Syongari SGE_UNLOCK(sc); 1187206625Syongari (*ifp->if_input)(ifp, m); 1188206625Syongari SGE_LOCK(sc); 1189206625Syongari } 1190206625Syongari 1191206625Syongari if (prog > 0) { 1192206625Syongari bus_dmamap_sync(cd->sge_rx_tag, cd->sge_rx_dmamap, 1193206625Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1194206625Syongari cd->sge_rx_cons = cons; 1195206625Syongari } 1196206625Syongari} 1197206625Syongari 1198206625Syongari/* 1199206625Syongari * A frame was downloaded to the chip. It's safe for us to clean up 1200206625Syongari * the list buffers. 1201206625Syongari */ 1202206625Syongaristatic void 1203206625Syongarisge_txeof(struct sge_softc *sc) 1204206625Syongari{ 1205206625Syongari struct ifnet *ifp; 1206206625Syongari struct sge_list_data *ld; 1207206625Syongari struct sge_chain_data *cd; 1208206625Syongari uint32_t txstat; 1209206625Syongari int cons, prod; 1210206625Syongari 1211206625Syongari SGE_LOCK_ASSERT(sc); 1212206625Syongari 1213206625Syongari ifp = sc->sge_ifp; 1214206625Syongari ld = &sc->sge_ldata; 1215206625Syongari cd = &sc->sge_cdata; 1216206625Syongari 1217206625Syongari if (cd->sge_tx_cnt == 0) 1218206625Syongari return; 1219206625Syongari bus_dmamap_sync(cd->sge_tx_tag, cd->sge_tx_dmamap, 1220206625Syongari BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1221206625Syongari cons = cd->sge_tx_cons; 1222206625Syongari prod = cd->sge_tx_prod; 1223206625Syongari for (; cons != prod; SGE_INC(cons, SGE_TX_RING_CNT)) { 1224206625Syongari txstat = le32toh(ld->sge_tx_ring[cons].sge_cmdsts); 1225206625Syongari if ((txstat & TDC_OWN) != 0) 1226206625Syongari break; 1227206625Syongari cd->sge_tx_cnt--; 1228206625Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1229206625Syongari if (cd->sge_tx_mbuf[cons] != NULL) { 1230206625Syongari bus_dmamap_sync(cd->sge_txmbuf_tag, 1231206625Syongari cd->sge_tx_map[cons], BUS_DMASYNC_POSTWRITE); 1232206625Syongari bus_dmamap_unload(cd->sge_txmbuf_tag, 1233206625Syongari cd->sge_tx_map[cons]); 1234206625Syongari m_freem(cd->sge_tx_mbuf[cons]); 1235206625Syongari cd->sge_tx_mbuf[cons] = NULL; 1236206625Syongari if (SGE_TX_ERROR(txstat) != 0) { 1237206625Syongari#ifdef SGE_SHOW_ERRORS 1238206625Syongari device_printf(sc->sge_dev, "Tx error : 0x%b\n", 1239206625Syongari txstat, TX_ERR_BITS); 1240206625Syongari#endif 1241206625Syongari ifp->if_oerrors++; 1242206625Syongari } else { 1243206625Syongari#ifdef notyet 1244206625Syongari ifp->if_collisions += (txstat & 0xFFFF) - 1; 1245206625Syongari#endif 1246206625Syongari ifp->if_opackets++; 1247206625Syongari } 1248206625Syongari } 1249206625Syongari 1250206625Syongari } 1251206625Syongari cd->sge_tx_cons = cons; 1252206625Syongari if (cd->sge_tx_cnt == 0) 1253206625Syongari sc->sge_timer = 0; 1254206625Syongari} 1255206625Syongari 1256206625Syongaristatic void 1257206625Syongarisge_tick(void *arg) 1258206625Syongari{ 1259206625Syongari struct sge_softc *sc; 1260206625Syongari struct mii_data *mii; 1261206625Syongari struct ifnet *ifp; 1262206625Syongari 1263206625Syongari sc = arg; 1264206625Syongari SGE_LOCK_ASSERT(sc); 1265206625Syongari 1266206625Syongari ifp = sc->sge_ifp; 1267206625Syongari mii = device_get_softc(sc->sge_miibus); 1268206625Syongari mii_tick(mii); 1269206625Syongari if ((sc->sge_flags & SGE_FLAG_LINK) == 0) { 1270206625Syongari sge_miibus_statchg(sc->sge_dev); 1271206625Syongari if ((sc->sge_flags & SGE_FLAG_LINK) != 0 && 1272206625Syongari !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1273206625Syongari sge_start_locked(ifp); 1274206625Syongari } 1275206625Syongari /* 1276206625Syongari * Reclaim transmitted frames here as we do not request 1277206625Syongari * Tx completion interrupt for every queued frames to 1278206625Syongari * reduce excessive interrupts. 1279206625Syongari */ 1280206625Syongari sge_txeof(sc); 1281206625Syongari sge_watchdog(sc); 1282206625Syongari callout_reset(&sc->sge_stat_ch, hz, sge_tick, sc); 1283206625Syongari} 1284206625Syongari 1285206625Syongaristatic void 1286206625Syongarisge_intr(void *arg) 1287206625Syongari{ 1288206625Syongari struct sge_softc *sc; 1289206625Syongari struct ifnet *ifp; 1290206625Syongari uint32_t status; 1291206625Syongari 1292206625Syongari sc = arg; 1293206625Syongari SGE_LOCK(sc); 1294206625Syongari ifp = sc->sge_ifp; 1295206625Syongari 1296206625Syongari status = CSR_READ_4(sc, IntrStatus); 1297206625Syongari if (status == 0xFFFFFFFF || (status & SGE_INTRS) == 0) { 1298206625Syongari /* Not ours. */ 1299206625Syongari SGE_UNLOCK(sc); 1300206625Syongari return; 1301206625Syongari } 1302206625Syongari /* Acknowledge interrupts. */ 1303206625Syongari CSR_WRITE_4(sc, IntrStatus, status); 1304206625Syongari /* Disable further interrupts. */ 1305206625Syongari CSR_WRITE_4(sc, IntrMask, 0); 1306206625Syongari /* 1307206625Syongari * It seems the controller supports some kind of interrupt 1308206625Syongari * moderation mechanism but we still don't know how to 1309206625Syongari * enable that. To reduce number of generated interrupts 1310206625Syongari * under load we check pending interrupts in a loop. This 1311206625Syongari * will increase number of register access and is not correct 1312206625Syongari * way to handle interrupt moderation but there seems to be 1313206625Syongari * no other way at this time. 1314206625Syongari */ 1315206625Syongari for (;;) { 1316206625Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 1317206625Syongari break; 1318206625Syongari if ((status & (INTR_RX_DONE | INTR_RX_IDLE)) != 0) { 1319206625Syongari sge_rxeof(sc); 1320206625Syongari /* Wakeup Rx MAC. */ 1321206625Syongari if ((status & INTR_RX_IDLE) != 0) 1322206625Syongari CSR_WRITE_4(sc, RX_CTL, 1323206625Syongari 0x1a00 | 0x000c | RX_CTL_POLL | RX_CTL_ENB); 1324206625Syongari } 1325206625Syongari if ((status & (INTR_TX_DONE | INTR_TX_IDLE)) != 0) 1326206625Syongari sge_txeof(sc); 1327206625Syongari status = CSR_READ_4(sc, IntrStatus); 1328206625Syongari if ((status & SGE_INTRS) == 0) 1329206625Syongari break; 1330206625Syongari /* Acknowledge interrupts. */ 1331206625Syongari CSR_WRITE_4(sc, IntrStatus, status); 1332206625Syongari } 1333206625Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 1334206625Syongari /* Re-enable interrupts */ 1335206625Syongari CSR_WRITE_4(sc, IntrMask, SGE_INTRS); 1336206625Syongari if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1337206625Syongari sge_start_locked(ifp); 1338206625Syongari } 1339206625Syongari SGE_UNLOCK(sc); 1340206625Syongari} 1341206625Syongari 1342206625Syongari/* 1343206625Syongari * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data 1344206625Syongari * pointers to the fragment pointers. 1345206625Syongari */ 1346206625Syongaristatic int 1347206625Syongarisge_encap(struct sge_softc *sc, struct mbuf **m_head) 1348206625Syongari{ 1349206625Syongari struct mbuf *m; 1350206625Syongari struct sge_desc *desc; 1351206625Syongari bus_dma_segment_t txsegs[SGE_MAXTXSEGS]; 1352206625Syongari bus_dmamap_t map; 1353206625Syongari uint32_t cflags; 1354206625Syongari int error, nsegs, prod; 1355206625Syongari 1356206625Syongari SGE_LOCK_ASSERT(sc); 1357206625Syongari 1358206625Syongari prod = sc->sge_cdata.sge_tx_prod; 1359206625Syongari map = sc->sge_cdata.sge_tx_map[prod]; 1360206625Syongari /* 1361206625Syongari * Reading Windows inf file indicates SiS controller supports 1362206625Syongari * TSO, VLAN hardware tag insertion/stripping, interrupt 1363206625Syongari * moderation and Tx/Rx checksum offloading. Unfortunately 1364206625Syongari * vendor didn't release these information so we're guessing 1365206625Syongari * descriptor usage with trial and errors. 1366206625Syongari * 1367206625Syongari * Controller seems to support multi-fragmented buffers but 1368206625Syongari * don't know how to enable that feature so limit number of 1369206625Syongari * fragmented Tx buffers to single buffer until we understand 1370206625Syongari * the controller internals. 1371206625Syongari * I assume the controller can pad zero bytes if frame length 1372206625Syongari * is less than 60 bytes and I also think the controller has 1373206625Syongari * no Tx buffer alignment limitation. - Need testing! 1374206625Syongari */ 1375206625Syongari if ((*m_head)->m_next != NULL) { 1376206625Syongari m = m_defrag(*m_head, M_DONTWAIT); 1377206625Syongari if (m == NULL) { 1378206625Syongari m_freem(*m_head); 1379206625Syongari *m_head = NULL; 1380206625Syongari return (ENOBUFS); 1381206625Syongari } 1382206625Syongari *m_head = m; 1383206625Syongari } 1384206625Syongari error = bus_dmamap_load_mbuf_sg(sc->sge_cdata.sge_tx_tag, map, 1385206625Syongari *m_head, txsegs, &nsegs, 0); 1386206625Syongari if (error != 0) { 1387206625Syongari m_freem(*m_head); 1388206625Syongari *m_head = NULL; 1389206625Syongari return (error); 1390206625Syongari } 1391206625Syongari /* Check descriptor overrun. */ 1392206625Syongari if (sc->sge_cdata.sge_tx_cnt + nsegs >= SGE_TX_RING_CNT) { 1393206625Syongari bus_dmamap_unload(sc->sge_cdata.sge_tx_tag, map); 1394206625Syongari return (ENOBUFS); 1395206625Syongari } 1396206625Syongari bus_dmamap_sync(sc->sge_cdata.sge_tx_tag, map, BUS_DMASYNC_PREWRITE); 1397206625Syongari 1398206625Syongari cflags = 0; 1399206625Syongari if ((*m_head)->m_pkthdr.csum_flags & CSUM_IP) 1400206625Syongari cflags |= TDC_IP_CSUM; 1401206625Syongari if ((*m_head)->m_pkthdr.csum_flags & CSUM_TCP) 1402206625Syongari cflags |= TDC_TCP_CSUM; 1403206625Syongari if ((*m_head)->m_pkthdr.csum_flags & CSUM_UDP) 1404206625Syongari cflags |= TDC_UDP_CSUM; 1405206625Syongari desc = &sc->sge_ldata.sge_tx_ring[prod]; 1406206625Syongari desc->sge_sts_size = htole32((*m_head)->m_pkthdr.len); 1407206625Syongari desc->sge_ptr = htole32(SGE_ADDR_LO(txsegs[0].ds_addr)); 1408206625Syongari desc->sge_flags = htole32(txsegs[0].ds_len); 1409206625Syongari if (prod == SGE_TX_RING_CNT - 1) 1410206625Syongari desc->sge_flags |= htole32(RING_END); 1411206625Syongari desc->sge_cmdsts = htole32(TDC_DEF | TDC_CRC | TDC_PAD | cflags); 1412206625Syongari#if 1 1413206625Syongari if ((sc->sge_flags & SGE_FLAG_SPEED_1000) != 0) 1414206625Syongari desc->sge_cmdsts |= htole32(TDC_BST); 1415206625Syongari#else 1416206625Syongari if ((sc->sge_flags & SGE_FLAG_FDX) == 0) { 1417206625Syongari desc->sge_cmdsts |= htole32(TDC_COL | TDC_CRS | TDC_BKF); 1418206625Syongari if ((sc->sge_flags & SGE_FLAG_SPEED_1000) != 0) 1419206625Syongari desc->sge_cmdsts |= htole32(TDC_EXT | TDC_BST); 1420206625Syongari } 1421206625Syongari#endif 1422206625Syongari /* Request interrupt and give ownership to controller. */ 1423206625Syongari if ((prod % SGE_TX_INTR_FRAMES) == 0) 1424206625Syongari desc->sge_cmdsts |= htole32(TDC_OWN | TDC_INTR); 1425206625Syongari else 1426206625Syongari desc->sge_cmdsts |= htole32(TDC_OWN); 1427206625Syongari sc->sge_cdata.sge_tx_mbuf[prod] = *m_head; 1428206625Syongari sc->sge_cdata.sge_tx_cnt++; 1429206625Syongari SGE_INC(sc->sge_cdata.sge_tx_prod, SGE_TX_RING_CNT); 1430206625Syongari return (0); 1431206625Syongari} 1432206625Syongari 1433206625Syongaristatic void 1434206625Syongarisge_start(struct ifnet *ifp) 1435206625Syongari{ 1436206625Syongari struct sge_softc *sc; 1437206625Syongari 1438206625Syongari sc = ifp->if_softc; 1439206625Syongari SGE_LOCK(sc); 1440206625Syongari sge_start_locked(ifp); 1441206625Syongari SGE_UNLOCK(sc); 1442206625Syongari} 1443206625Syongari 1444206625Syongaristatic void 1445206625Syongarisge_start_locked(struct ifnet *ifp) 1446206625Syongari{ 1447206625Syongari struct sge_softc *sc; 1448206625Syongari struct mbuf *m_head; 1449206625Syongari int queued = 0; 1450206625Syongari 1451206625Syongari sc = ifp->if_softc; 1452206625Syongari SGE_LOCK_ASSERT(sc); 1453206625Syongari 1454206625Syongari if ((sc->sge_flags & SGE_FLAG_LINK) == 0 || 1455206625Syongari (ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1456206625Syongari IFF_DRV_RUNNING) 1457206625Syongari return; 1458206625Syongari 1459206625Syongari for (queued = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) { 1460206625Syongari if (sc->sge_cdata.sge_tx_cnt == SGE_TX_RING_CNT - 1) { 1461206625Syongari ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1462206625Syongari break; 1463206625Syongari } 1464206625Syongari IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); 1465206625Syongari if (m_head == NULL) 1466206625Syongari break; 1467206625Syongari if (sge_encap(sc, &m_head)) { 1468206625Syongari IFQ_DRV_PREPEND(&ifp->if_snd, m_head); 1469206625Syongari ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1470206625Syongari break; 1471206625Syongari } 1472206625Syongari queued++; 1473206625Syongari /* 1474206625Syongari * If there's a BPF listener, bounce a copy of this frame 1475206625Syongari * to him. 1476206625Syongari */ 1477206625Syongari BPF_MTAP(ifp, m_head); 1478206625Syongari } 1479206625Syongari 1480206625Syongari if (queued > 0) { 1481206625Syongari bus_dmamap_sync(sc->sge_cdata.sge_tx_tag, 1482206625Syongari sc->sge_cdata.sge_tx_dmamap, 1483206625Syongari BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1484206625Syongari CSR_WRITE_4(sc, TX_CTL, 0x1a00 | TX_CTL_ENB | TX_CTL_POLL); 1485206625Syongari sc->sge_timer = 5; 1486206625Syongari } 1487206625Syongari} 1488206625Syongari 1489206625Syongaristatic void 1490206625Syongarisge_init(void *arg) 1491206625Syongari{ 1492206625Syongari struct sge_softc *sc; 1493206625Syongari 1494206625Syongari sc = arg; 1495206625Syongari SGE_LOCK(sc); 1496206625Syongari sge_init_locked(sc); 1497206625Syongari SGE_UNLOCK(sc); 1498206625Syongari} 1499206625Syongari 1500206625Syongaristatic void 1501206625Syongarisge_init_locked(struct sge_softc *sc) 1502206625Syongari{ 1503206625Syongari struct ifnet *ifp; 1504206625Syongari struct mii_data *mii; 1505206625Syongari int i; 1506206625Syongari 1507206625Syongari SGE_LOCK_ASSERT(sc); 1508206625Syongari ifp = sc->sge_ifp; 1509206625Syongari mii = device_get_softc(sc->sge_miibus); 1510206625Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1511206625Syongari return; 1512206625Syongari /* 1513206625Syongari * Cancel pending I/O and free all RX/TX buffers. 1514206625Syongari */ 1515206625Syongari sge_stop(sc); 1516206625Syongari sge_reset(sc); 1517206625Syongari 1518206625Syongari /* Init circular RX list. */ 1519206625Syongari if (sge_list_rx_init(sc) == ENOBUFS) { 1520206625Syongari device_printf(sc->sge_dev, "no memory for Rx buffers\n"); 1521206625Syongari sge_stop(sc); 1522206625Syongari return; 1523206625Syongari } 1524206625Syongari /* Init TX descriptors. */ 1525206625Syongari sge_list_tx_init(sc); 1526206625Syongari /* 1527206625Syongari * Load the address of the RX and TX lists. 1528206625Syongari */ 1529206625Syongari CSR_WRITE_4(sc, TX_DESC, SGE_ADDR_LO(sc->sge_ldata.sge_tx_paddr)); 1530206625Syongari CSR_WRITE_4(sc, RX_DESC, SGE_ADDR_LO(sc->sge_ldata.sge_rx_paddr)); 1531206625Syongari 1532206625Syongari CSR_WRITE_4(sc, TxMacControl, 0x60); 1533206625Syongari CSR_WRITE_4(sc, 0x6c, 0); 1534206625Syongari CSR_WRITE_4(sc, RxWakeOnLan, 0); 1535206625Syongari CSR_WRITE_4(sc, RxWakeOnLanData, 0); 1536206625Syongari /* Allow receiving VLAN frames. */ 1537206625Syongari CSR_WRITE_2(sc, RxMPSControl, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN); 1538206625Syongari 1539206625Syongari for (i = 0; i < ETHER_ADDR_LEN; i++) 1540206625Syongari CSR_WRITE_1(sc, RxMacAddr + i, IF_LLADDR(ifp)[i]); 1541206625Syongari sge_rxfilter(sc); 1542206625Syongari 1543206625Syongari /* Initialize default speed/duplex information. */ 1544206625Syongari if ((sc->sge_flags & SGE_FLAG_FASTETHER) == 0) 1545206625Syongari sc->sge_flags |= SGE_FLAG_SPEED_1000; 1546206625Syongari sc->sge_flags |= SGE_FLAG_FDX; 1547206625Syongari if ((sc->sge_flags & SGE_FLAG_RGMII) != 0) 1548206625Syongari CSR_WRITE_4(sc, StationControl, 0x04008001); 1549206625Syongari else 1550206625Syongari CSR_WRITE_4(sc, StationControl, 0x04000001); 1551206625Syongari /* 1552206625Syongari * XXX Try to mitigate interrupts. 1553206625Syongari */ 1554207071Syongari CSR_WRITE_4(sc, IntrControl, 0x08880000); 1555207071Syongari#ifdef notyet 1556206625Syongari if (sc->sge_intrcontrol != 0) 1557206625Syongari CSR_WRITE_4(sc, IntrControl, sc->sge_intrcontrol); 1558206625Syongari if (sc->sge_intrtimer != 0) 1559206625Syongari CSR_WRITE_4(sc, IntrTimer, sc->sge_intrtimer); 1560207071Syongari#endif 1561206625Syongari 1562206625Syongari /* 1563206625Syongari * Clear and enable interrupts. 1564206625Syongari */ 1565206625Syongari CSR_WRITE_4(sc, IntrStatus, 0xFFFFFFFF); 1566206625Syongari CSR_WRITE_4(sc, IntrMask, SGE_INTRS); 1567206625Syongari 1568206625Syongari /* Enable receiver and transmitter. */ 1569206625Syongari CSR_WRITE_4(sc, TX_CTL, 0x1a00 | TX_CTL_ENB); 1570206625Syongari CSR_WRITE_4(sc, RX_CTL, 0x1a00 | 0x000c | RX_CTL_POLL | RX_CTL_ENB); 1571206625Syongari 1572206625Syongari ifp->if_drv_flags |= IFF_DRV_RUNNING; 1573206625Syongari ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1574206625Syongari 1575206625Syongari sc->sge_flags &= ~SGE_FLAG_LINK; 1576206625Syongari mii_mediachg(mii); 1577206625Syongari callout_reset(&sc->sge_stat_ch, hz, sge_tick, sc); 1578206625Syongari} 1579206625Syongari 1580206625Syongari/* 1581206625Syongari * Set media options. 1582206625Syongari */ 1583206625Syongaristatic int 1584206625Syongarisge_ifmedia_upd(struct ifnet *ifp) 1585206625Syongari{ 1586206625Syongari struct sge_softc *sc; 1587206625Syongari struct mii_data *mii; 1588206625Syongari int error; 1589206625Syongari 1590206625Syongari sc = ifp->if_softc; 1591206625Syongari SGE_LOCK(sc); 1592206625Syongari mii = device_get_softc(sc->sge_miibus); 1593206625Syongari sc->sge_flags &= ~SGE_FLAG_LINK; 1594206625Syongari if (mii->mii_instance) { 1595206625Syongari struct mii_softc *miisc; 1596206625Syongari LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 1597206625Syongari mii_phy_reset(miisc); 1598206625Syongari } 1599206625Syongari error = mii_mediachg(mii); 1600206625Syongari SGE_UNLOCK(sc); 1601206625Syongari 1602206625Syongari return (error); 1603206625Syongari} 1604206625Syongari 1605206625Syongari/* 1606206625Syongari * Report current media status. 1607206625Syongari */ 1608206625Syongaristatic void 1609206625Syongarisge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 1610206625Syongari{ 1611206625Syongari struct sge_softc *sc; 1612206625Syongari struct mii_data *mii; 1613206625Syongari 1614206625Syongari sc = ifp->if_softc; 1615206625Syongari SGE_LOCK(sc); 1616206625Syongari mii = device_get_softc(sc->sge_miibus); 1617206625Syongari if ((ifp->if_flags & IFF_UP) == 0) { 1618206625Syongari SGE_UNLOCK(sc); 1619206625Syongari return; 1620206625Syongari } 1621206625Syongari mii_pollstat(mii); 1622206625Syongari SGE_UNLOCK(sc); 1623206625Syongari ifmr->ifm_active = mii->mii_media_active; 1624206625Syongari ifmr->ifm_status = mii->mii_media_status; 1625206625Syongari} 1626206625Syongari 1627206625Syongaristatic int 1628206625Syongarisge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1629206625Syongari{ 1630206625Syongari struct sge_softc *sc; 1631206625Syongari struct ifreq *ifr; 1632206625Syongari struct mii_data *mii; 1633206625Syongari int error = 0, mask; 1634206625Syongari 1635206625Syongari sc = ifp->if_softc; 1636206625Syongari ifr = (struct ifreq *)data; 1637206625Syongari 1638206625Syongari switch(command) { 1639206625Syongari case SIOCSIFFLAGS: 1640206625Syongari SGE_LOCK(sc); 1641206625Syongari if ((ifp->if_flags & IFF_UP) != 0) { 1642206625Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && 1643206625Syongari ((ifp->if_flags ^ sc->sge_if_flags) & 1644206625Syongari (IFF_PROMISC | IFF_ALLMULTI)) != 0) 1645206625Syongari sge_rxfilter(sc); 1646206625Syongari else 1647206625Syongari sge_init_locked(sc); 1648206625Syongari } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1649206625Syongari sge_stop(sc); 1650206625Syongari sc->sge_if_flags = ifp->if_flags; 1651206625Syongari SGE_UNLOCK(sc); 1652206625Syongari break; 1653206625Syongari case SIOCSIFCAP: 1654206625Syongari SGE_LOCK(sc); 1655206625Syongari mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1656206625Syongari if ((mask & IFCAP_TXCSUM) != 0 && 1657206625Syongari (ifp->if_capabilities & IFCAP_TXCSUM) != 0) { 1658206625Syongari ifp->if_capenable ^= IFCAP_TXCSUM; 1659206625Syongari if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) 1660206625Syongari ifp->if_hwassist |= SGE_CSUM_FEATURES; 1661206625Syongari else 1662206625Syongari ifp->if_hwassist &= ~SGE_CSUM_FEATURES; 1663206625Syongari } 1664206625Syongari if ((mask & IFCAP_RXCSUM) != 0 && 1665206625Syongari (ifp->if_capabilities & IFCAP_RXCSUM) != 0) 1666206625Syongari ifp->if_capenable ^= IFCAP_RXCSUM; 1667206625Syongari SGE_UNLOCK(sc); 1668206625Syongari break; 1669206625Syongari case SIOCADDMULTI: 1670206625Syongari case SIOCDELMULTI: 1671206625Syongari SGE_LOCK(sc); 1672206625Syongari if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 1673206625Syongari sge_rxfilter(sc); 1674206625Syongari SGE_UNLOCK(sc); 1675206625Syongari break; 1676206625Syongari case SIOCGIFMEDIA: 1677206625Syongari case SIOCSIFMEDIA: 1678206625Syongari mii = device_get_softc(sc->sge_miibus); 1679206625Syongari error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); 1680206625Syongari break; 1681206625Syongari default: 1682206625Syongari error = ether_ioctl(ifp, command, data); 1683206625Syongari break; 1684206625Syongari } 1685206625Syongari 1686206625Syongari return (error); 1687206625Syongari} 1688206625Syongari 1689206625Syongaristatic void 1690206625Syongarisge_watchdog(struct sge_softc *sc) 1691206625Syongari{ 1692206625Syongari struct ifnet *ifp; 1693206625Syongari 1694206625Syongari SGE_LOCK_ASSERT(sc); 1695206625Syongari if (sc->sge_timer == 0 || --sc->sge_timer > 0) 1696206625Syongari return; 1697206625Syongari 1698206625Syongari ifp = sc->sge_ifp; 1699206625Syongari if ((sc->sge_flags & SGE_FLAG_LINK) == 0) { 1700206625Syongari if (1 || bootverbose) 1701206625Syongari device_printf(sc->sge_dev, 1702206625Syongari "watchdog timeout (lost link)\n"); 1703206625Syongari ifp->if_oerrors++; 1704206625Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1705206625Syongari sge_init_locked(sc); 1706206625Syongari return; 1707206625Syongari } 1708206625Syongari device_printf(sc->sge_dev, "watchdog timeout\n"); 1709206625Syongari ifp->if_oerrors++; 1710206625Syongari 1711206625Syongari ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1712206625Syongari sge_init_locked(sc); 1713206625Syongari if (!IFQ_DRV_IS_EMPTY(&sc->sge_ifp->if_snd)) 1714206625Syongari sge_start_locked(ifp); 1715206625Syongari} 1716206625Syongari 1717206625Syongari/* 1718206625Syongari * Stop the adapter and free any mbufs allocated to the 1719206625Syongari * RX and TX lists. 1720206625Syongari */ 1721206625Syongaristatic void 1722206625Syongarisge_stop(struct sge_softc *sc) 1723206625Syongari{ 1724206625Syongari struct ifnet *ifp; 1725206625Syongari 1726206625Syongari ifp = sc->sge_ifp; 1727206625Syongari 1728206625Syongari SGE_LOCK_ASSERT(sc); 1729206625Syongari 1730206625Syongari sc->sge_timer = 0; 1731206625Syongari callout_stop(&sc->sge_stat_ch); 1732206625Syongari ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1733206625Syongari 1734206625Syongari CSR_WRITE_4(sc, IntrMask, 0); 1735206625Syongari CSR_READ_4(sc, IntrMask); 1736206625Syongari CSR_WRITE_4(sc, IntrStatus, 0xffffffff); 1737206625Syongari /* Stop TX/RX MAC. */ 1738206625Syongari CSR_WRITE_4(sc, TX_CTL, 0x1a00); 1739206625Syongari CSR_WRITE_4(sc, RX_CTL, 0x1a00); 1740206625Syongari /* XXX Can we assume active DMA cycles gone? */ 1741206625Syongari DELAY(2000); 1742206625Syongari CSR_WRITE_4(sc, IntrMask, 0); 1743206625Syongari CSR_WRITE_4(sc, IntrStatus, 0xffffffff); 1744206625Syongari 1745206625Syongari sc->sge_flags &= ~SGE_FLAG_LINK; 1746206625Syongari sge_list_rx_free(sc); 1747206625Syongari sge_list_tx_free(sc); 1748206625Syongari} 1749