1227569Sphilip/*- 2227569Sphilip * Copyright (c) 2010-2011 Solarflare Communications, Inc. 3227569Sphilip * All rights reserved. 4227569Sphilip * 5227569Sphilip * This software was developed in part by Philip Paeps under contract for 6227569Sphilip * Solarflare Communications, Inc. 7227569Sphilip * 8227569Sphilip * Redistribution and use in source and binary forms, with or without 9227569Sphilip * modification, are permitted provided that the following conditions 10227569Sphilip * are met: 11227569Sphilip * 1. Redistributions of source code must retain the above copyright 12227569Sphilip * notice, this list of conditions and the following disclaimer. 13227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright 14227569Sphilip * notice, this list of conditions and the following disclaimer in the 15227569Sphilip * documentation and/or other materials provided with the distribution. 16227569Sphilip * 17227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20227569Sphilip * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27227569Sphilip * SUCH DAMAGE. 28227569Sphilip */ 29227569Sphilip 30227569Sphilip#include <sys/cdefs.h> 31227569Sphilip__FBSDID("$FreeBSD$"); 32227569Sphilip 33227569Sphilip#include <sys/param.h> 34227569Sphilip#include <sys/kernel.h> 35227569Sphilip#include <sys/bus.h> 36227569Sphilip#include <sys/rman.h> 37227569Sphilip#include <sys/lock.h> 38227569Sphilip#include <sys/module.h> 39227569Sphilip#include <sys/mutex.h> 40227569Sphilip#include <sys/smp.h> 41227569Sphilip#include <sys/socket.h> 42227569Sphilip#include <sys/taskqueue.h> 43227569Sphilip#include <sys/sockio.h> 44227569Sphilip#include <sys/sysctl.h> 45227569Sphilip 46227569Sphilip#include <dev/pci/pcireg.h> 47227569Sphilip#include <dev/pci/pcivar.h> 48227569Sphilip 49227569Sphilip#include <net/ethernet.h> 50227569Sphilip#include <net/if.h> 51227569Sphilip#include <net/if_media.h> 52227569Sphilip#include <net/if_types.h> 53227569Sphilip 54227569Sphilip#include "common/efx.h" 55227569Sphilip 56227569Sphilip#include "sfxge.h" 57227569Sphilip#include "sfxge_rx.h" 58227569Sphilip 59227569Sphilip#define SFXGE_CAP (IFCAP_VLAN_MTU | \ 60227569Sphilip IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | \ 61227569Sphilip IFCAP_JUMBO_MTU | IFCAP_LRO | \ 62227569Sphilip IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE) 63227569Sphilip#define SFXGE_CAP_ENABLE SFXGE_CAP 64227569Sphilip#define SFXGE_CAP_FIXED (IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | \ 65227569Sphilip IFCAP_JUMBO_MTU | IFCAP_LINKSTATE) 66227569Sphilip 67227569SphilipMALLOC_DEFINE(M_SFXGE, "sfxge", "Solarflare 10GigE driver"); 68227569Sphilip 69227569Sphilipstatic void 70227569Sphilipsfxge_reset(void *arg, int npending); 71227569Sphilip 72227569Sphilipstatic int 73227569Sphilipsfxge_start(struct sfxge_softc *sc) 74227569Sphilip{ 75227569Sphilip int rc; 76227569Sphilip 77227569Sphilip sx_assert(&sc->softc_lock, LA_XLOCKED); 78227569Sphilip 79227569Sphilip if (sc->init_state == SFXGE_STARTED) 80227569Sphilip return 0; 81227569Sphilip 82227569Sphilip if (sc->init_state != SFXGE_REGISTERED) { 83227569Sphilip rc = EINVAL; 84227569Sphilip goto fail; 85227569Sphilip } 86227569Sphilip 87227569Sphilip if ((rc = efx_nic_init(sc->enp)) != 0) 88227569Sphilip goto fail; 89227569Sphilip 90227569Sphilip /* Start processing interrupts. */ 91227569Sphilip if ((rc = sfxge_intr_start(sc)) != 0) 92227569Sphilip goto fail2; 93227569Sphilip 94227569Sphilip /* Start processing events. */ 95227569Sphilip if ((rc = sfxge_ev_start(sc)) != 0) 96227569Sphilip goto fail3; 97227569Sphilip 98227569Sphilip /* Start the receiver side. */ 99227569Sphilip if ((rc = sfxge_rx_start(sc)) != 0) 100227569Sphilip goto fail4; 101227569Sphilip 102227569Sphilip /* Start the transmitter side. */ 103227569Sphilip if ((rc = sfxge_tx_start(sc)) != 0) 104227569Sphilip goto fail5; 105227569Sphilip 106227569Sphilip /* Fire up the port. */ 107227569Sphilip if ((rc = sfxge_port_start(sc)) != 0) 108227569Sphilip goto fail6; 109227569Sphilip 110227569Sphilip sc->init_state = SFXGE_STARTED; 111227569Sphilip 112227569Sphilip /* Tell the stack we're running. */ 113227569Sphilip sc->ifnet->if_drv_flags |= IFF_DRV_RUNNING; 114227569Sphilip sc->ifnet->if_drv_flags &= ~IFF_DRV_OACTIVE; 115227569Sphilip 116227569Sphilip return (0); 117227569Sphilip 118227569Sphilipfail6: 119227569Sphilip sfxge_tx_stop(sc); 120227569Sphilip 121227569Sphilipfail5: 122227569Sphilip sfxge_rx_stop(sc); 123227569Sphilip 124227569Sphilipfail4: 125227569Sphilip sfxge_ev_stop(sc); 126227569Sphilip 127227569Sphilipfail3: 128227569Sphilip sfxge_intr_stop(sc); 129227569Sphilip 130227569Sphilipfail2: 131227569Sphilip efx_nic_fini(sc->enp); 132227569Sphilip 133227569Sphilipfail: 134227569Sphilip device_printf(sc->dev, "sfxge_start: %d\n", rc); 135227569Sphilip 136227569Sphilip return (rc); 137227569Sphilip} 138227569Sphilip 139227569Sphilipstatic void 140227569Sphilipsfxge_if_init(void *arg) 141227569Sphilip{ 142227569Sphilip struct sfxge_softc *sc; 143227569Sphilip 144227569Sphilip sc = (struct sfxge_softc *)arg; 145227569Sphilip 146227569Sphilip sx_xlock(&sc->softc_lock); 147227569Sphilip (void)sfxge_start(sc); 148227569Sphilip sx_xunlock(&sc->softc_lock); 149227569Sphilip} 150227569Sphilip 151227569Sphilipstatic void 152227569Sphilipsfxge_stop(struct sfxge_softc *sc) 153227569Sphilip{ 154227569Sphilip sx_assert(&sc->softc_lock, LA_XLOCKED); 155227569Sphilip 156227569Sphilip if (sc->init_state != SFXGE_STARTED) 157227569Sphilip return; 158227569Sphilip 159227569Sphilip sc->init_state = SFXGE_REGISTERED; 160227569Sphilip 161227569Sphilip /* Stop the port. */ 162227569Sphilip sfxge_port_stop(sc); 163227569Sphilip 164227569Sphilip /* Stop the transmitter. */ 165227569Sphilip sfxge_tx_stop(sc); 166227569Sphilip 167227569Sphilip /* Stop the receiver. */ 168227569Sphilip sfxge_rx_stop(sc); 169227569Sphilip 170227569Sphilip /* Stop processing events. */ 171227569Sphilip sfxge_ev_stop(sc); 172227569Sphilip 173227569Sphilip /* Stop processing interrupts. */ 174227569Sphilip sfxge_intr_stop(sc); 175227569Sphilip 176227569Sphilip efx_nic_fini(sc->enp); 177227569Sphilip 178227569Sphilip sc->ifnet->if_drv_flags &= ~IFF_DRV_RUNNING; 179227569Sphilip} 180227569Sphilip 181227569Sphilipstatic int 182227569Sphilipsfxge_if_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 183227569Sphilip{ 184227569Sphilip struct sfxge_softc *sc; 185227569Sphilip struct ifreq *ifr; 186227569Sphilip int error; 187227569Sphilip 188227569Sphilip ifr = (struct ifreq *)data; 189227569Sphilip sc = ifp->if_softc; 190227569Sphilip error = 0; 191227569Sphilip 192227569Sphilip switch (command) { 193227569Sphilip case SIOCSIFFLAGS: 194227569Sphilip sx_xlock(&sc->softc_lock); 195227569Sphilip if (ifp->if_flags & IFF_UP) { 196227569Sphilip if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 197227569Sphilip if ((ifp->if_flags ^ sc->if_flags) & 198227569Sphilip (IFF_PROMISC | IFF_ALLMULTI)) { 199227569Sphilip sfxge_mac_filter_set(sc); 200227569Sphilip } 201227569Sphilip } else 202227569Sphilip sfxge_start(sc); 203227569Sphilip } else 204227569Sphilip if (ifp->if_drv_flags & IFF_DRV_RUNNING) 205227569Sphilip sfxge_stop(sc); 206227569Sphilip sc->if_flags = ifp->if_flags; 207227569Sphilip sx_xunlock(&sc->softc_lock); 208227569Sphilip break; 209227569Sphilip case SIOCSIFMTU: 210227569Sphilip if (ifr->ifr_mtu == ifp->if_mtu) { 211227569Sphilip /* Nothing to do */ 212227569Sphilip error = 0; 213227569Sphilip } else if (ifr->ifr_mtu > SFXGE_MAX_MTU) { 214227569Sphilip error = EINVAL; 215227569Sphilip } else if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 216227569Sphilip ifp->if_mtu = ifr->ifr_mtu; 217227569Sphilip error = 0; 218227569Sphilip } else { 219227569Sphilip /* Restart required */ 220227569Sphilip sx_xlock(&sc->softc_lock); 221227569Sphilip sfxge_stop(sc); 222227569Sphilip ifp->if_mtu = ifr->ifr_mtu; 223227569Sphilip error = sfxge_start(sc); 224227569Sphilip sx_xunlock(&sc->softc_lock); 225227569Sphilip if (error) { 226227569Sphilip ifp->if_flags &= ~IFF_UP; 227227569Sphilip ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 228227569Sphilip if_down(ifp); 229227569Sphilip } 230227569Sphilip } 231227569Sphilip break; 232227569Sphilip case SIOCADDMULTI: 233227569Sphilip case SIOCDELMULTI: 234227569Sphilip if (ifp->if_drv_flags & IFF_DRV_RUNNING) 235227569Sphilip sfxge_mac_filter_set(sc); 236227569Sphilip break; 237227569Sphilip case SIOCSIFCAP: 238227569Sphilip sx_xlock(&sc->softc_lock); 239227569Sphilip 240227569Sphilip /* 241227569Sphilip * The networking core already rejects attempts to 242227569Sphilip * enable capabilities we don't have. We still have 243227569Sphilip * to reject attempts to disable capabilities that we 244227569Sphilip * can't (yet) disable. 245227569Sphilip */ 246227569Sphilip if (~ifr->ifr_reqcap & SFXGE_CAP_FIXED) { 247227569Sphilip error = EINVAL; 248227569Sphilip sx_xunlock(&sc->softc_lock); 249227569Sphilip break; 250227569Sphilip } 251227569Sphilip 252227569Sphilip ifp->if_capenable = ifr->ifr_reqcap; 253227569Sphilip if (ifp->if_capenable & IFCAP_TXCSUM) 254227569Sphilip ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 255227569Sphilip else 256227569Sphilip ifp->if_hwassist &= ~(CSUM_IP | CSUM_TCP | CSUM_UDP); 257227569Sphilip if (ifp->if_capenable & IFCAP_TSO) 258227569Sphilip ifp->if_hwassist |= CSUM_TSO; 259227569Sphilip else 260227569Sphilip ifp->if_hwassist &= ~CSUM_TSO; 261227569Sphilip 262227569Sphilip sx_xunlock(&sc->softc_lock); 263227569Sphilip break; 264227569Sphilip case SIOCSIFMEDIA: 265227569Sphilip case SIOCGIFMEDIA: 266227569Sphilip error = ifmedia_ioctl(ifp, ifr, &sc->media, command); 267227569Sphilip break; 268227569Sphilip default: 269227569Sphilip error = ether_ioctl(ifp, command, data); 270227569Sphilip } 271227569Sphilip 272227569Sphilip return (error); 273227569Sphilip} 274227569Sphilip 275227569Sphilipstatic void 276227569Sphilipsfxge_ifnet_fini(struct ifnet *ifp) 277227569Sphilip{ 278227569Sphilip struct sfxge_softc *sc = ifp->if_softc; 279227569Sphilip 280227569Sphilip sx_xlock(&sc->softc_lock); 281227569Sphilip sfxge_stop(sc); 282227569Sphilip sx_xunlock(&sc->softc_lock); 283227569Sphilip 284227569Sphilip ifmedia_removeall(&sc->media); 285227569Sphilip ether_ifdetach(ifp); 286227569Sphilip if_free(ifp); 287227569Sphilip} 288227569Sphilip 289227569Sphilipstatic int 290227569Sphilipsfxge_ifnet_init(struct ifnet *ifp, struct sfxge_softc *sc) 291227569Sphilip{ 292227569Sphilip const efx_nic_cfg_t *encp = efx_nic_cfg_get(sc->enp); 293227569Sphilip device_t dev; 294227569Sphilip int rc; 295227569Sphilip 296227569Sphilip dev = sc->dev; 297227569Sphilip sc->ifnet = ifp; 298227569Sphilip 299227569Sphilip if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 300227569Sphilip ifp->if_init = sfxge_if_init; 301227569Sphilip ifp->if_softc = sc; 302227569Sphilip ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 303227569Sphilip ifp->if_ioctl = sfxge_if_ioctl; 304227569Sphilip 305227569Sphilip ifp->if_capabilities = SFXGE_CAP; 306227569Sphilip ifp->if_capenable = SFXGE_CAP_ENABLE; 307227569Sphilip ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO; 308227569Sphilip 309227569Sphilip ether_ifattach(ifp, encp->enc_mac_addr); 310227569Sphilip 311227569Sphilip#ifdef SFXGE_HAVE_MQ 312227569Sphilip ifp->if_transmit = sfxge_if_transmit; 313227569Sphilip ifp->if_qflush = sfxge_if_qflush; 314227569Sphilip#else 315227569Sphilip ifp->if_start = sfxge_if_start; 316227569Sphilip IFQ_SET_MAXLEN(&ifp->if_snd, SFXGE_NDESCS - 1); 317227569Sphilip ifp->if_snd.ifq_drv_maxlen = SFXGE_NDESCS - 1; 318227569Sphilip IFQ_SET_READY(&ifp->if_snd); 319227569Sphilip 320227569Sphilip mtx_init(&sc->tx_lock, "txq", NULL, MTX_DEF); 321227569Sphilip#endif 322227569Sphilip 323227569Sphilip if ((rc = sfxge_port_ifmedia_init(sc)) != 0) 324227569Sphilip goto fail; 325227569Sphilip 326227569Sphilip return 0; 327227569Sphilip 328227569Sphilipfail: 329227569Sphilip ether_ifdetach(sc->ifnet); 330227569Sphilip return rc; 331227569Sphilip} 332227569Sphilip 333227569Sphilipvoid 334227569Sphilipsfxge_sram_buf_tbl_alloc(struct sfxge_softc *sc, size_t n, uint32_t *idp) 335227569Sphilip{ 336227569Sphilip KASSERT(sc->buffer_table_next + n <= 337227569Sphilip efx_nic_cfg_get(sc->enp)->enc_buftbl_limit, 338227569Sphilip ("buffer table full")); 339227569Sphilip 340227569Sphilip *idp = sc->buffer_table_next; 341227569Sphilip sc->buffer_table_next += n; 342227569Sphilip} 343227569Sphilip 344227569Sphilipstatic int 345227569Sphilipsfxge_bar_init(struct sfxge_softc *sc) 346227569Sphilip{ 347227569Sphilip efsys_bar_t *esbp = &sc->bar; 348227569Sphilip 349227569Sphilip esbp->esb_rid = PCIR_BAR(EFX_MEM_BAR); 350227569Sphilip if ((esbp->esb_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 351227569Sphilip &esbp->esb_rid, RF_ACTIVE)) == NULL) { 352227569Sphilip device_printf(sc->dev, "Cannot allocate BAR region %d\n", 353227569Sphilip EFX_MEM_BAR); 354227569Sphilip return (ENXIO); 355227569Sphilip } 356227569Sphilip esbp->esb_tag = rman_get_bustag(esbp->esb_res); 357227569Sphilip esbp->esb_handle = rman_get_bushandle(esbp->esb_res); 358227569Sphilip mtx_init(&esbp->esb_lock, "sfxge_efsys_bar", NULL, MTX_DEF); 359227569Sphilip 360227569Sphilip return (0); 361227569Sphilip} 362227569Sphilip 363227569Sphilipstatic void 364227569Sphilipsfxge_bar_fini(struct sfxge_softc *sc) 365227569Sphilip{ 366227569Sphilip efsys_bar_t *esbp = &sc->bar; 367227569Sphilip 368227569Sphilip bus_release_resource(sc->dev, SYS_RES_MEMORY, esbp->esb_rid, 369227569Sphilip esbp->esb_res); 370227569Sphilip mtx_destroy(&esbp->esb_lock); 371227569Sphilip} 372227569Sphilip 373227569Sphilipstatic int 374227569Sphilipsfxge_create(struct sfxge_softc *sc) 375227569Sphilip{ 376227569Sphilip device_t dev; 377227569Sphilip efx_nic_t *enp; 378227569Sphilip int error; 379227569Sphilip 380227569Sphilip dev = sc->dev; 381227569Sphilip 382227569Sphilip sx_init(&sc->softc_lock, "sfxge_softc"); 383227569Sphilip 384227569Sphilip sc->stats_node = SYSCTL_ADD_NODE( 385227569Sphilip device_get_sysctl_ctx(dev), 386227569Sphilip SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 387227569Sphilip OID_AUTO, "stats", CTLFLAG_RD, NULL, "Statistics"); 388227569Sphilip if (!sc->stats_node) { 389227569Sphilip error = ENOMEM; 390227569Sphilip goto fail; 391227569Sphilip } 392227569Sphilip 393227569Sphilip TASK_INIT(&sc->task_reset, 0, sfxge_reset, sc); 394227569Sphilip 395227569Sphilip (void) pci_enable_busmaster(dev); 396227569Sphilip 397227569Sphilip /* Initialize DMA mappings. */ 398227569Sphilip if ((error = sfxge_dma_init(sc)) != 0) 399227569Sphilip goto fail; 400227569Sphilip 401227569Sphilip /* Map the device registers. */ 402227569Sphilip if ((error = sfxge_bar_init(sc)) != 0) 403227569Sphilip goto fail; 404227569Sphilip 405227569Sphilip error = efx_family(pci_get_vendor(dev), pci_get_device(dev), 406227569Sphilip &sc->family); 407227569Sphilip KASSERT(error == 0, ("Family should be filtered by sfxge_probe()")); 408227569Sphilip 409227569Sphilip /* Create the common code nic object. */ 410227569Sphilip mtx_init(&sc->enp_lock, "sfxge_nic", NULL, MTX_DEF); 411227569Sphilip if ((error = efx_nic_create(sc->family, (efsys_identifier_t *)sc, 412227569Sphilip &sc->bar, &sc->enp_lock, &enp)) != 0) 413227569Sphilip goto fail3; 414227569Sphilip sc->enp = enp; 415227569Sphilip 416227569Sphilip /* Initialize MCDI to talk to the microcontroller. */ 417227569Sphilip if ((error = sfxge_mcdi_init(sc)) != 0) 418227569Sphilip goto fail4; 419227569Sphilip 420227569Sphilip /* Probe the NIC and build the configuration data area. */ 421227569Sphilip if ((error = efx_nic_probe(enp)) != 0) 422227569Sphilip goto fail5; 423227569Sphilip 424227569Sphilip /* Initialize the NVRAM. */ 425227569Sphilip if ((error = efx_nvram_init(enp)) != 0) 426227569Sphilip goto fail6; 427227569Sphilip 428227569Sphilip /* Initialize the VPD. */ 429227569Sphilip if ((error = efx_vpd_init(enp)) != 0) 430227569Sphilip goto fail7; 431227569Sphilip 432227569Sphilip /* Reset the NIC. */ 433227569Sphilip if ((error = efx_nic_reset(enp)) != 0) 434227569Sphilip goto fail8; 435227569Sphilip 436227569Sphilip /* Initialize buffer table allocation. */ 437227569Sphilip sc->buffer_table_next = 0; 438227569Sphilip 439227569Sphilip /* Set up interrupts. */ 440227569Sphilip if ((error = sfxge_intr_init(sc)) != 0) 441227569Sphilip goto fail8; 442227569Sphilip 443227569Sphilip /* Initialize event processing state. */ 444227569Sphilip if ((error = sfxge_ev_init(sc)) != 0) 445227569Sphilip goto fail11; 446227569Sphilip 447227569Sphilip /* Initialize receive state. */ 448227569Sphilip if ((error = sfxge_rx_init(sc)) != 0) 449227569Sphilip goto fail12; 450227569Sphilip 451227569Sphilip /* Initialize transmit state. */ 452227569Sphilip if ((error = sfxge_tx_init(sc)) != 0) 453227569Sphilip goto fail13; 454227569Sphilip 455227569Sphilip /* Initialize port state. */ 456227569Sphilip if ((error = sfxge_port_init(sc)) != 0) 457227569Sphilip goto fail14; 458227569Sphilip 459227569Sphilip sc->init_state = SFXGE_INITIALIZED; 460227569Sphilip 461227569Sphilip return (0); 462227569Sphilip 463227569Sphilipfail14: 464227569Sphilip sfxge_tx_fini(sc); 465227569Sphilip 466227569Sphilipfail13: 467227569Sphilip sfxge_rx_fini(sc); 468227569Sphilip 469227569Sphilipfail12: 470227569Sphilip sfxge_ev_fini(sc); 471227569Sphilip 472227569Sphilipfail11: 473227569Sphilip sfxge_intr_fini(sc); 474227569Sphilip 475227569Sphilipfail8: 476227569Sphilip efx_vpd_fini(enp); 477227569Sphilip 478227569Sphilipfail7: 479227569Sphilip efx_nvram_fini(enp); 480227569Sphilip 481227569Sphilipfail6: 482227569Sphilip efx_nic_unprobe(enp); 483227569Sphilip 484227569Sphilipfail5: 485227569Sphilip sfxge_mcdi_fini(sc); 486227569Sphilip 487227569Sphilipfail4: 488227569Sphilip sc->enp = NULL; 489227569Sphilip efx_nic_destroy(enp); 490227569Sphilip mtx_destroy(&sc->enp_lock); 491227569Sphilip 492227569Sphilipfail3: 493227569Sphilip sfxge_bar_fini(sc); 494227569Sphilip (void) pci_disable_busmaster(sc->dev); 495227569Sphilip 496227569Sphilipfail: 497227569Sphilip sc->dev = NULL; 498227569Sphilip sx_destroy(&sc->softc_lock); 499227569Sphilip return (error); 500227569Sphilip} 501227569Sphilip 502227569Sphilipstatic void 503227569Sphilipsfxge_destroy(struct sfxge_softc *sc) 504227569Sphilip{ 505227569Sphilip efx_nic_t *enp; 506227569Sphilip 507227569Sphilip /* Clean up port state. */ 508227569Sphilip sfxge_port_fini(sc); 509227569Sphilip 510227569Sphilip /* Clean up transmit state. */ 511227569Sphilip sfxge_tx_fini(sc); 512227569Sphilip 513227569Sphilip /* Clean up receive state. */ 514227569Sphilip sfxge_rx_fini(sc); 515227569Sphilip 516227569Sphilip /* Clean up event processing state. */ 517227569Sphilip sfxge_ev_fini(sc); 518227569Sphilip 519227569Sphilip /* Clean up interrupts. */ 520227569Sphilip sfxge_intr_fini(sc); 521227569Sphilip 522227569Sphilip /* Tear down common code subsystems. */ 523227569Sphilip efx_nic_reset(sc->enp); 524227569Sphilip efx_vpd_fini(sc->enp); 525227569Sphilip efx_nvram_fini(sc->enp); 526227569Sphilip efx_nic_unprobe(sc->enp); 527227569Sphilip 528227569Sphilip /* Tear down MCDI. */ 529227569Sphilip sfxge_mcdi_fini(sc); 530227569Sphilip 531227569Sphilip /* Destroy common code context. */ 532227569Sphilip enp = sc->enp; 533227569Sphilip sc->enp = NULL; 534227569Sphilip efx_nic_destroy(enp); 535227569Sphilip 536227569Sphilip /* Free DMA memory. */ 537227569Sphilip sfxge_dma_fini(sc); 538227569Sphilip 539227569Sphilip /* Free mapped BARs. */ 540227569Sphilip sfxge_bar_fini(sc); 541227569Sphilip 542227569Sphilip (void) pci_disable_busmaster(sc->dev); 543227569Sphilip 544227569Sphilip taskqueue_drain(taskqueue_thread, &sc->task_reset); 545227569Sphilip 546227569Sphilip /* Destroy the softc lock. */ 547227569Sphilip sx_destroy(&sc->softc_lock); 548227569Sphilip} 549227569Sphilip 550227569Sphilipstatic int 551227569Sphilipsfxge_vpd_handler(SYSCTL_HANDLER_ARGS) 552227569Sphilip{ 553227569Sphilip struct sfxge_softc *sc = arg1; 554227569Sphilip efx_vpd_value_t value; 555227569Sphilip int rc; 556227569Sphilip 557227569Sphilip value.evv_tag = arg2 >> 16; 558227569Sphilip value.evv_keyword = arg2 & 0xffff; 559227569Sphilip if ((rc = efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value)) 560227569Sphilip != 0) 561227569Sphilip return rc; 562227569Sphilip 563227569Sphilip return SYSCTL_OUT(req, value.evv_value, value.evv_length); 564227569Sphilip} 565227569Sphilip 566227569Sphilipstatic void 567227569Sphilipsfxge_vpd_try_add(struct sfxge_softc *sc, struct sysctl_oid_list *list, 568227569Sphilip efx_vpd_tag_t tag, const char *keyword) 569227569Sphilip{ 570227569Sphilip struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); 571227569Sphilip efx_vpd_value_t value; 572227569Sphilip 573227569Sphilip /* Check whether VPD tag/keyword is present */ 574227569Sphilip value.evv_tag = tag; 575227569Sphilip value.evv_keyword = EFX_VPD_KEYWORD(keyword[0], keyword[1]); 576227569Sphilip if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) != 0) 577227569Sphilip return; 578227569Sphilip 579227569Sphilip SYSCTL_ADD_PROC( 580227569Sphilip ctx, list, OID_AUTO, keyword, CTLTYPE_STRING|CTLFLAG_RD, 581227569Sphilip sc, tag << 16 | EFX_VPD_KEYWORD(keyword[0], keyword[1]), 582227569Sphilip sfxge_vpd_handler, "A", ""); 583227569Sphilip} 584227569Sphilip 585227569Sphilipstatic int 586227569Sphilipsfxge_vpd_init(struct sfxge_softc *sc) 587227569Sphilip{ 588227569Sphilip struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); 589227569Sphilip struct sysctl_oid *vpd_node; 590227569Sphilip struct sysctl_oid_list *vpd_list; 591227569Sphilip char keyword[3]; 592227569Sphilip efx_vpd_value_t value; 593227569Sphilip int rc; 594227569Sphilip 595227569Sphilip if ((rc = efx_vpd_size(sc->enp, &sc->vpd_size)) != 0) 596227569Sphilip goto fail; 597227569Sphilip sc->vpd_data = malloc(sc->vpd_size, M_SFXGE, M_WAITOK); 598227569Sphilip if ((rc = efx_vpd_read(sc->enp, sc->vpd_data, sc->vpd_size)) != 0) 599227569Sphilip goto fail2; 600227569Sphilip 601227569Sphilip /* Copy ID (product name) into device description, and log it. */ 602227569Sphilip value.evv_tag = EFX_VPD_ID; 603227569Sphilip if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) == 0) { 604227569Sphilip value.evv_value[value.evv_length] = 0; 605227569Sphilip device_set_desc_copy(sc->dev, value.evv_value); 606227569Sphilip device_printf(sc->dev, "%s\n", value.evv_value); 607227569Sphilip } 608227569Sphilip 609227569Sphilip vpd_node = SYSCTL_ADD_NODE( 610227569Sphilip ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 611227569Sphilip OID_AUTO, "vpd", CTLFLAG_RD, NULL, "Vital Product Data"); 612227569Sphilip vpd_list = SYSCTL_CHILDREN(vpd_node); 613227569Sphilip 614227569Sphilip /* Add sysctls for all expected and any vendor-defined keywords. */ 615227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "PN"); 616227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "EC"); 617227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "SN"); 618227569Sphilip keyword[0] = 'V'; 619227569Sphilip keyword[2] = 0; 620227569Sphilip for (keyword[1] = '0'; keyword[1] <= '9'; keyword[1]++) 621227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword); 622227569Sphilip for (keyword[1] = 'A'; keyword[1] <= 'Z'; keyword[1]++) 623227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword); 624227569Sphilip 625227569Sphilip return 0; 626227569Sphilip 627227569Sphilipfail2: 628227569Sphilip free(sc->vpd_data, M_SFXGE); 629227569Sphilipfail: 630227569Sphilip return rc; 631227569Sphilip} 632227569Sphilip 633227569Sphilipstatic void 634227569Sphilipsfxge_vpd_fini(struct sfxge_softc *sc) 635227569Sphilip{ 636227569Sphilip free(sc->vpd_data, M_SFXGE); 637227569Sphilip} 638227569Sphilip 639227569Sphilipstatic void 640227569Sphilipsfxge_reset(void *arg, int npending) 641227569Sphilip{ 642227569Sphilip struct sfxge_softc *sc; 643227569Sphilip int rc; 644227569Sphilip 645227569Sphilip (void)npending; 646227569Sphilip 647227569Sphilip sc = (struct sfxge_softc *)arg; 648227569Sphilip 649227569Sphilip sx_xlock(&sc->softc_lock); 650227569Sphilip 651227569Sphilip if (sc->init_state != SFXGE_STARTED) 652227569Sphilip goto done; 653227569Sphilip 654227569Sphilip sfxge_stop(sc); 655227569Sphilip efx_nic_reset(sc->enp); 656227569Sphilip if ((rc = sfxge_start(sc)) != 0) 657227569Sphilip device_printf(sc->dev, 658227569Sphilip "reset failed (%d); interface is now stopped\n", 659227569Sphilip rc); 660227569Sphilip 661227569Sphilipdone: 662227569Sphilip sx_xunlock(&sc->softc_lock); 663227569Sphilip} 664227569Sphilip 665227569Sphilipvoid 666227569Sphilipsfxge_schedule_reset(struct sfxge_softc *sc) 667227569Sphilip{ 668227569Sphilip taskqueue_enqueue(taskqueue_thread, &sc->task_reset); 669227569Sphilip} 670227569Sphilip 671227569Sphilipstatic int 672227569Sphilipsfxge_attach(device_t dev) 673227569Sphilip{ 674227569Sphilip struct sfxge_softc *sc; 675227569Sphilip struct ifnet *ifp; 676227569Sphilip int error; 677227569Sphilip 678227569Sphilip sc = device_get_softc(dev); 679227569Sphilip sc->dev = dev; 680227569Sphilip 681227569Sphilip /* Allocate ifnet. */ 682227569Sphilip ifp = if_alloc(IFT_ETHER); 683227569Sphilip if (ifp == NULL) { 684227569Sphilip device_printf(dev, "Couldn't allocate ifnet\n"); 685227569Sphilip error = ENOMEM; 686227569Sphilip goto fail; 687227569Sphilip } 688227569Sphilip sc->ifnet = ifp; 689227569Sphilip 690227569Sphilip /* Initialize hardware. */ 691227569Sphilip if ((error = sfxge_create(sc)) != 0) 692227569Sphilip goto fail2; 693227569Sphilip 694227569Sphilip /* Create the ifnet for the port. */ 695227569Sphilip if ((error = sfxge_ifnet_init(ifp, sc)) != 0) 696227569Sphilip goto fail3; 697227569Sphilip 698227569Sphilip if ((error = sfxge_vpd_init(sc)) != 0) 699227569Sphilip goto fail4; 700227569Sphilip 701227569Sphilip sc->init_state = SFXGE_REGISTERED; 702227569Sphilip 703227569Sphilip return (0); 704227569Sphilip 705227569Sphilipfail4: 706227569Sphilip sfxge_ifnet_fini(ifp); 707227569Sphilipfail3: 708227569Sphilip sfxge_destroy(sc); 709227569Sphilip 710227569Sphilipfail2: 711227569Sphilip if_free(sc->ifnet); 712227569Sphilip 713227569Sphilipfail: 714227569Sphilip return (error); 715227569Sphilip} 716227569Sphilip 717227569Sphilipstatic int 718227569Sphilipsfxge_detach(device_t dev) 719227569Sphilip{ 720227569Sphilip struct sfxge_softc *sc; 721227569Sphilip 722227569Sphilip sc = device_get_softc(dev); 723227569Sphilip 724227569Sphilip sfxge_vpd_fini(sc); 725227569Sphilip 726227569Sphilip /* Destroy the ifnet. */ 727227569Sphilip sfxge_ifnet_fini(sc->ifnet); 728227569Sphilip 729227569Sphilip /* Tear down hardware. */ 730227569Sphilip sfxge_destroy(sc); 731227569Sphilip 732227569Sphilip return (0); 733227569Sphilip} 734227569Sphilip 735227569Sphilipstatic int 736227569Sphilipsfxge_probe(device_t dev) 737227569Sphilip{ 738227569Sphilip uint16_t pci_vendor_id; 739227569Sphilip uint16_t pci_device_id; 740227569Sphilip efx_family_t family; 741227569Sphilip int rc; 742227569Sphilip 743227569Sphilip pci_vendor_id = pci_get_vendor(dev); 744227569Sphilip pci_device_id = pci_get_device(dev); 745227569Sphilip 746227569Sphilip rc = efx_family(pci_vendor_id, pci_device_id, &family); 747227569Sphilip if (rc) 748227569Sphilip return ENXIO; 749227569Sphilip 750227569Sphilip KASSERT(family == EFX_FAMILY_SIENA, ("impossible controller family")); 751227569Sphilip device_set_desc(dev, "Solarflare SFC9000 family"); 752227569Sphilip return 0; 753227569Sphilip} 754227569Sphilip 755227569Sphilipstatic device_method_t sfxge_methods[] = { 756227569Sphilip DEVMETHOD(device_probe, sfxge_probe), 757227569Sphilip DEVMETHOD(device_attach, sfxge_attach), 758227569Sphilip DEVMETHOD(device_detach, sfxge_detach), 759227569Sphilip 760227843Smarius DEVMETHOD_END 761227569Sphilip}; 762227569Sphilip 763227569Sphilipstatic devclass_t sfxge_devclass; 764227569Sphilip 765227569Sphilipstatic driver_t sfxge_driver = { 766227569Sphilip "sfxge", 767227569Sphilip sfxge_methods, 768227569Sphilip sizeof(struct sfxge_softc) 769227569Sphilip}; 770227569Sphilip 771227569SphilipDRIVER_MODULE(sfxge, pci, sfxge_driver, sfxge_devclass, 0, 0); 772