sfxge.c revision 283212
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: stable/10/sys/dev/sfxge/sfxge.c 283212 2015-05-21 09:13:47Z arybchik $"); 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> 45280502Sarybchik#include <sys/syslog.h> 46227569Sphilip 47227569Sphilip#include <dev/pci/pcireg.h> 48227569Sphilip#include <dev/pci/pcivar.h> 49227569Sphilip 50227569Sphilip#include <net/ethernet.h> 51227569Sphilip#include <net/if.h> 52227569Sphilip#include <net/if_media.h> 53227569Sphilip#include <net/if_types.h> 54227569Sphilip 55227569Sphilip#include "common/efx.h" 56227569Sphilip 57227569Sphilip#include "sfxge.h" 58227569Sphilip#include "sfxge_rx.h" 59280601Sarybchik#include "sfxge_version.h" 60227569Sphilip 61283204Sarybchik#define SFXGE_CAP (IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM | \ 62283204Sarybchik IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO | \ 63283205Sarybchik IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6 | \ 64227569Sphilip IFCAP_JUMBO_MTU | IFCAP_LRO | \ 65227569Sphilip IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE) 66280501Sarybchik#define SFXGE_CAP_ENABLE SFXGE_CAP 67283209Sarybchik#define SFXGE_CAP_FIXED (IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM | \ 68227569Sphilip IFCAP_JUMBO_MTU | IFCAP_LINKSTATE) 69227569Sphilip 70227569SphilipMALLOC_DEFINE(M_SFXGE, "sfxge", "Solarflare 10GigE driver"); 71227569Sphilip 72280502Sarybchik 73280502SarybchikSYSCTL_NODE(_hw, OID_AUTO, sfxge, CTLFLAG_RD, 0, 74280502Sarybchik "SFXGE driver parameters"); 75280502Sarybchik 76280502Sarybchik#define SFXGE_PARAM_RX_RING SFXGE_PARAM(rx_ring) 77280502Sarybchikstatic int sfxge_rx_ring_entries = SFXGE_NDESCS; 78280502SarybchikTUNABLE_INT(SFXGE_PARAM_RX_RING, &sfxge_rx_ring_entries); 79280502SarybchikSYSCTL_INT(_hw_sfxge, OID_AUTO, rx_ring, CTLFLAG_RDTUN, 80280502Sarybchik &sfxge_rx_ring_entries, 0, 81280502Sarybchik "Maximum number of descriptors in a receive ring"); 82280502Sarybchik 83280502Sarybchik#define SFXGE_PARAM_TX_RING SFXGE_PARAM(tx_ring) 84280502Sarybchikstatic int sfxge_tx_ring_entries = SFXGE_NDESCS; 85280502SarybchikTUNABLE_INT(SFXGE_PARAM_TX_RING, &sfxge_tx_ring_entries); 86280502SarybchikSYSCTL_INT(_hw_sfxge, OID_AUTO, tx_ring, CTLFLAG_RDTUN, 87280502Sarybchik &sfxge_tx_ring_entries, 0, 88280502Sarybchik "Maximum number of descriptors in a transmit ring"); 89280502Sarybchik 90280502Sarybchik 91227569Sphilipstatic void 92227569Sphilipsfxge_reset(void *arg, int npending); 93227569Sphilip 94227569Sphilipstatic int 95227569Sphilipsfxge_start(struct sfxge_softc *sc) 96227569Sphilip{ 97227569Sphilip int rc; 98227569Sphilip 99280522Sarybchik SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc); 100227569Sphilip 101227569Sphilip if (sc->init_state == SFXGE_STARTED) 102280501Sarybchik return (0); 103227569Sphilip 104227569Sphilip if (sc->init_state != SFXGE_REGISTERED) { 105227569Sphilip rc = EINVAL; 106227569Sphilip goto fail; 107227569Sphilip } 108227569Sphilip 109227569Sphilip if ((rc = efx_nic_init(sc->enp)) != 0) 110227569Sphilip goto fail; 111227569Sphilip 112227569Sphilip /* Start processing interrupts. */ 113227569Sphilip if ((rc = sfxge_intr_start(sc)) != 0) 114227569Sphilip goto fail2; 115227569Sphilip 116227569Sphilip /* Start processing events. */ 117227569Sphilip if ((rc = sfxge_ev_start(sc)) != 0) 118227569Sphilip goto fail3; 119227569Sphilip 120227569Sphilip /* Start the receiver side. */ 121227569Sphilip if ((rc = sfxge_rx_start(sc)) != 0) 122227569Sphilip goto fail4; 123227569Sphilip 124227569Sphilip /* Start the transmitter side. */ 125227569Sphilip if ((rc = sfxge_tx_start(sc)) != 0) 126227569Sphilip goto fail5; 127227569Sphilip 128227569Sphilip /* Fire up the port. */ 129227569Sphilip if ((rc = sfxge_port_start(sc)) != 0) 130227569Sphilip goto fail6; 131227569Sphilip 132227569Sphilip sc->init_state = SFXGE_STARTED; 133227569Sphilip 134227569Sphilip /* Tell the stack we're running. */ 135227569Sphilip sc->ifnet->if_drv_flags |= IFF_DRV_RUNNING; 136227569Sphilip sc->ifnet->if_drv_flags &= ~IFF_DRV_OACTIVE; 137227569Sphilip 138227569Sphilip return (0); 139227569Sphilip 140227569Sphilipfail6: 141227569Sphilip sfxge_tx_stop(sc); 142227569Sphilip 143227569Sphilipfail5: 144227569Sphilip sfxge_rx_stop(sc); 145227569Sphilip 146227569Sphilipfail4: 147227569Sphilip sfxge_ev_stop(sc); 148227569Sphilip 149227569Sphilipfail3: 150227569Sphilip sfxge_intr_stop(sc); 151227569Sphilip 152227569Sphilipfail2: 153227569Sphilip efx_nic_fini(sc->enp); 154227569Sphilip 155227569Sphilipfail: 156227569Sphilip device_printf(sc->dev, "sfxge_start: %d\n", rc); 157227569Sphilip 158227569Sphilip return (rc); 159227569Sphilip} 160227569Sphilip 161227569Sphilipstatic void 162227569Sphilipsfxge_if_init(void *arg) 163227569Sphilip{ 164227569Sphilip struct sfxge_softc *sc; 165227569Sphilip 166227569Sphilip sc = (struct sfxge_softc *)arg; 167227569Sphilip 168280522Sarybchik SFXGE_ADAPTER_LOCK(sc); 169227569Sphilip (void)sfxge_start(sc); 170280522Sarybchik SFXGE_ADAPTER_UNLOCK(sc); 171227569Sphilip} 172227569Sphilip 173227569Sphilipstatic void 174227569Sphilipsfxge_stop(struct sfxge_softc *sc) 175227569Sphilip{ 176280522Sarybchik SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc); 177227569Sphilip 178227569Sphilip if (sc->init_state != SFXGE_STARTED) 179227569Sphilip return; 180227569Sphilip 181227569Sphilip sc->init_state = SFXGE_REGISTERED; 182227569Sphilip 183227569Sphilip /* Stop the port. */ 184227569Sphilip sfxge_port_stop(sc); 185227569Sphilip 186227569Sphilip /* Stop the transmitter. */ 187227569Sphilip sfxge_tx_stop(sc); 188227569Sphilip 189227569Sphilip /* Stop the receiver. */ 190227569Sphilip sfxge_rx_stop(sc); 191227569Sphilip 192227569Sphilip /* Stop processing events. */ 193227569Sphilip sfxge_ev_stop(sc); 194227569Sphilip 195227569Sphilip /* Stop processing interrupts. */ 196227569Sphilip sfxge_intr_stop(sc); 197227569Sphilip 198227569Sphilip efx_nic_fini(sc->enp); 199227569Sphilip 200227569Sphilip sc->ifnet->if_drv_flags &= ~IFF_DRV_RUNNING; 201227569Sphilip} 202227569Sphilip 203227569Sphilipstatic int 204227569Sphilipsfxge_if_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 205227569Sphilip{ 206227569Sphilip struct sfxge_softc *sc; 207227569Sphilip struct ifreq *ifr; 208227569Sphilip int error; 209227569Sphilip 210227569Sphilip ifr = (struct ifreq *)data; 211227569Sphilip sc = ifp->if_softc; 212227569Sphilip error = 0; 213227569Sphilip 214227569Sphilip switch (command) { 215227569Sphilip case SIOCSIFFLAGS: 216280522Sarybchik SFXGE_ADAPTER_LOCK(sc); 217227569Sphilip if (ifp->if_flags & IFF_UP) { 218227569Sphilip if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 219227569Sphilip if ((ifp->if_flags ^ sc->if_flags) & 220227569Sphilip (IFF_PROMISC | IFF_ALLMULTI)) { 221227569Sphilip sfxge_mac_filter_set(sc); 222227569Sphilip } 223227569Sphilip } else 224227569Sphilip sfxge_start(sc); 225227569Sphilip } else 226227569Sphilip if (ifp->if_drv_flags & IFF_DRV_RUNNING) 227227569Sphilip sfxge_stop(sc); 228227569Sphilip sc->if_flags = ifp->if_flags; 229280522Sarybchik SFXGE_ADAPTER_UNLOCK(sc); 230227569Sphilip break; 231227569Sphilip case SIOCSIFMTU: 232227569Sphilip if (ifr->ifr_mtu == ifp->if_mtu) { 233227569Sphilip /* Nothing to do */ 234227569Sphilip error = 0; 235227569Sphilip } else if (ifr->ifr_mtu > SFXGE_MAX_MTU) { 236227569Sphilip error = EINVAL; 237227569Sphilip } else if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 238227569Sphilip ifp->if_mtu = ifr->ifr_mtu; 239227569Sphilip error = 0; 240227569Sphilip } else { 241227569Sphilip /* Restart required */ 242280522Sarybchik SFXGE_ADAPTER_LOCK(sc); 243227569Sphilip sfxge_stop(sc); 244227569Sphilip ifp->if_mtu = ifr->ifr_mtu; 245227569Sphilip error = sfxge_start(sc); 246280522Sarybchik SFXGE_ADAPTER_UNLOCK(sc); 247280501Sarybchik if (error != 0) { 248227569Sphilip ifp->if_flags &= ~IFF_UP; 249227569Sphilip ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 250227569Sphilip if_down(ifp); 251227569Sphilip } 252227569Sphilip } 253227569Sphilip break; 254227569Sphilip case SIOCADDMULTI: 255227569Sphilip case SIOCDELMULTI: 256227569Sphilip if (ifp->if_drv_flags & IFF_DRV_RUNNING) 257227569Sphilip sfxge_mac_filter_set(sc); 258227569Sphilip break; 259227569Sphilip case SIOCSIFCAP: 260283212Sarybchik { 261283212Sarybchik int reqcap = ifr->ifr_reqcap; 262283212Sarybchik int capchg_mask; 263283212Sarybchik 264280522Sarybchik SFXGE_ADAPTER_LOCK(sc); 265227569Sphilip 266283212Sarybchik /* Capabilities to be changed in accordance with request */ 267283212Sarybchik capchg_mask = ifp->if_capenable ^ reqcap; 268283212Sarybchik 269227569Sphilip /* 270227569Sphilip * The networking core already rejects attempts to 271227569Sphilip * enable capabilities we don't have. We still have 272227569Sphilip * to reject attempts to disable capabilities that we 273227569Sphilip * can't (yet) disable. 274227569Sphilip */ 275283212Sarybchik KASSERT((reqcap & ~ifp->if_capabilities) == 0, 276283212Sarybchik ("Unsupported capabilities %x requested %x vs %x", 277283212Sarybchik reqcap & ~ifp->if_capabilities, 278283212Sarybchik reqcap , ifp->if_capabilities)); 279283212Sarybchik if (capchg_mask & SFXGE_CAP_FIXED) { 280227569Sphilip error = EINVAL; 281280522Sarybchik SFXGE_ADAPTER_UNLOCK(sc); 282227569Sphilip break; 283227569Sphilip } 284227569Sphilip 285283212Sarybchik if (reqcap & IFCAP_TXCSUM) 286227569Sphilip ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 287227569Sphilip else 288227569Sphilip ifp->if_hwassist &= ~(CSUM_IP | CSUM_TCP | CSUM_UDP); 289283212Sarybchik if (reqcap & IFCAP_TXCSUM_IPV6) 290283205Sarybchik ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 291283205Sarybchik else 292283205Sarybchik ifp->if_hwassist &= ~(CSUM_TCP_IPV6 | CSUM_UDP_IPV6); 293227569Sphilip 294283207Sarybchik /* 295283207Sarybchik * The kernel takes both IFCAP_TSOx and CSUM_TSO into 296283207Sarybchik * account before using TSO. So, we do not touch 297283207Sarybchik * checksum flags when IFCAP_TSOx is modified. 298283207Sarybchik * Note that CSUM_TSO is (CSUM_IP_TSO|CSUM_IP6_TSO), 299283207Sarybchik * but both bits are set in IPv4 and IPv6 mbufs. 300283207Sarybchik */ 301283207Sarybchik 302283212Sarybchik ifp->if_capenable = reqcap; 303283212Sarybchik 304280522Sarybchik SFXGE_ADAPTER_UNLOCK(sc); 305227569Sphilip break; 306283212Sarybchik } 307227569Sphilip case SIOCSIFMEDIA: 308227569Sphilip case SIOCGIFMEDIA: 309227569Sphilip error = ifmedia_ioctl(ifp, ifr, &sc->media, command); 310227569Sphilip break; 311227569Sphilip default: 312227569Sphilip error = ether_ioctl(ifp, command, data); 313227569Sphilip } 314227569Sphilip 315227569Sphilip return (error); 316227569Sphilip} 317227569Sphilip 318227569Sphilipstatic void 319227569Sphilipsfxge_ifnet_fini(struct ifnet *ifp) 320227569Sphilip{ 321227569Sphilip struct sfxge_softc *sc = ifp->if_softc; 322227569Sphilip 323280522Sarybchik SFXGE_ADAPTER_LOCK(sc); 324227569Sphilip sfxge_stop(sc); 325280522Sarybchik SFXGE_ADAPTER_UNLOCK(sc); 326227569Sphilip 327227569Sphilip ifmedia_removeall(&sc->media); 328227569Sphilip ether_ifdetach(ifp); 329227569Sphilip if_free(ifp); 330227569Sphilip} 331227569Sphilip 332280501Sarybchikstatic int 333227569Sphilipsfxge_ifnet_init(struct ifnet *ifp, struct sfxge_softc *sc) 334227569Sphilip{ 335227569Sphilip const efx_nic_cfg_t *encp = efx_nic_cfg_get(sc->enp); 336227569Sphilip device_t dev; 337227569Sphilip int rc; 338227569Sphilip 339227569Sphilip dev = sc->dev; 340227569Sphilip sc->ifnet = ifp; 341227569Sphilip 342227569Sphilip if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 343227569Sphilip ifp->if_init = sfxge_if_init; 344227569Sphilip ifp->if_softc = sc; 345227569Sphilip ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 346227569Sphilip ifp->if_ioctl = sfxge_if_ioctl; 347227569Sphilip 348227569Sphilip ifp->if_capabilities = SFXGE_CAP; 349227569Sphilip ifp->if_capenable = SFXGE_CAP_ENABLE; 350283205Sarybchik ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 351283205Sarybchik CSUM_TCP_IPV6 | CSUM_UDP_IPV6; 352227569Sphilip 353227569Sphilip ether_ifattach(ifp, encp->enc_mac_addr); 354227569Sphilip 355227569Sphilip ifp->if_transmit = sfxge_if_transmit; 356227569Sphilip ifp->if_qflush = sfxge_if_qflush; 357227569Sphilip 358227569Sphilip if ((rc = sfxge_port_ifmedia_init(sc)) != 0) 359227569Sphilip goto fail; 360227569Sphilip 361280501Sarybchik return (0); 362227569Sphilip 363227569Sphilipfail: 364227569Sphilip ether_ifdetach(sc->ifnet); 365280501Sarybchik return (rc); 366227569Sphilip} 367227569Sphilip 368227569Sphilipvoid 369227569Sphilipsfxge_sram_buf_tbl_alloc(struct sfxge_softc *sc, size_t n, uint32_t *idp) 370227569Sphilip{ 371227569Sphilip KASSERT(sc->buffer_table_next + n <= 372227569Sphilip efx_nic_cfg_get(sc->enp)->enc_buftbl_limit, 373227569Sphilip ("buffer table full")); 374227569Sphilip 375227569Sphilip *idp = sc->buffer_table_next; 376227569Sphilip sc->buffer_table_next += n; 377227569Sphilip} 378227569Sphilip 379227569Sphilipstatic int 380227569Sphilipsfxge_bar_init(struct sfxge_softc *sc) 381227569Sphilip{ 382227569Sphilip efsys_bar_t *esbp = &sc->bar; 383227569Sphilip 384280501Sarybchik esbp->esb_rid = PCIR_BAR(EFX_MEM_BAR); 385227569Sphilip if ((esbp->esb_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 386227569Sphilip &esbp->esb_rid, RF_ACTIVE)) == NULL) { 387227569Sphilip device_printf(sc->dev, "Cannot allocate BAR region %d\n", 388227569Sphilip EFX_MEM_BAR); 389227569Sphilip return (ENXIO); 390227569Sphilip } 391227569Sphilip esbp->esb_tag = rman_get_bustag(esbp->esb_res); 392227569Sphilip esbp->esb_handle = rman_get_bushandle(esbp->esb_res); 393227569Sphilip 394280524Sarybchik SFXGE_BAR_LOCK_INIT(esbp, device_get_nameunit(sc->dev)); 395280524Sarybchik 396227569Sphilip return (0); 397227569Sphilip} 398227569Sphilip 399227569Sphilipstatic void 400227569Sphilipsfxge_bar_fini(struct sfxge_softc *sc) 401227569Sphilip{ 402227569Sphilip efsys_bar_t *esbp = &sc->bar; 403227569Sphilip 404227569Sphilip bus_release_resource(sc->dev, SYS_RES_MEMORY, esbp->esb_rid, 405227569Sphilip esbp->esb_res); 406280522Sarybchik SFXGE_BAR_LOCK_DESTROY(esbp); 407227569Sphilip} 408227569Sphilip 409227569Sphilipstatic int 410227569Sphilipsfxge_create(struct sfxge_softc *sc) 411227569Sphilip{ 412227569Sphilip device_t dev; 413227569Sphilip efx_nic_t *enp; 414227569Sphilip int error; 415280518Sarybchik char rss_param_name[sizeof(SFXGE_PARAM(%d.max_rss_channels))]; 416227569Sphilip 417227569Sphilip dev = sc->dev; 418227569Sphilip 419280524Sarybchik SFXGE_ADAPTER_LOCK_INIT(sc, device_get_nameunit(sc->dev)); 420227569Sphilip 421280518Sarybchik sc->max_rss_channels = 0; 422280518Sarybchik snprintf(rss_param_name, sizeof(rss_param_name), 423280518Sarybchik SFXGE_PARAM(%d.max_rss_channels), 424280518Sarybchik (int)device_get_unit(dev)); 425280518Sarybchik TUNABLE_INT_FETCH(rss_param_name, &sc->max_rss_channels); 426280518Sarybchik 427227569Sphilip sc->stats_node = SYSCTL_ADD_NODE( 428227569Sphilip device_get_sysctl_ctx(dev), 429227569Sphilip SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 430227569Sphilip OID_AUTO, "stats", CTLFLAG_RD, NULL, "Statistics"); 431280501Sarybchik if (sc->stats_node == NULL) { 432227569Sphilip error = ENOMEM; 433227569Sphilip goto fail; 434227569Sphilip } 435227569Sphilip 436227569Sphilip TASK_INIT(&sc->task_reset, 0, sfxge_reset, sc); 437227569Sphilip 438227569Sphilip (void) pci_enable_busmaster(dev); 439227569Sphilip 440227569Sphilip /* Initialize DMA mappings. */ 441227569Sphilip if ((error = sfxge_dma_init(sc)) != 0) 442227569Sphilip goto fail; 443227569Sphilip 444227569Sphilip /* Map the device registers. */ 445227569Sphilip if ((error = sfxge_bar_init(sc)) != 0) 446227569Sphilip goto fail; 447227569Sphilip 448227569Sphilip error = efx_family(pci_get_vendor(dev), pci_get_device(dev), 449227569Sphilip &sc->family); 450227569Sphilip KASSERT(error == 0, ("Family should be filtered by sfxge_probe()")); 451227569Sphilip 452227569Sphilip /* Create the common code nic object. */ 453280524Sarybchik SFXGE_EFSYS_LOCK_INIT(&sc->enp_lock, 454280524Sarybchik device_get_nameunit(sc->dev), "nic"); 455227569Sphilip if ((error = efx_nic_create(sc->family, (efsys_identifier_t *)sc, 456227569Sphilip &sc->bar, &sc->enp_lock, &enp)) != 0) 457227569Sphilip goto fail3; 458227569Sphilip sc->enp = enp; 459227569Sphilip 460280502Sarybchik if (!ISP2(sfxge_rx_ring_entries) || 461280502Sarybchik !(sfxge_rx_ring_entries & EFX_RXQ_NDESCS_MASK)) { 462280502Sarybchik log(LOG_ERR, "%s=%d must be power of 2 from %u to %u", 463280502Sarybchik SFXGE_PARAM_RX_RING, sfxge_rx_ring_entries, 464280502Sarybchik EFX_RXQ_MINNDESCS, EFX_RXQ_MAXNDESCS); 465280502Sarybchik error = EINVAL; 466280502Sarybchik goto fail_rx_ring_entries; 467280502Sarybchik } 468280502Sarybchik sc->rxq_entries = sfxge_rx_ring_entries; 469280502Sarybchik 470280502Sarybchik if (!ISP2(sfxge_tx_ring_entries) || 471280502Sarybchik !(sfxge_tx_ring_entries & EFX_TXQ_NDESCS_MASK)) { 472280502Sarybchik log(LOG_ERR, "%s=%d must be power of 2 from %u to %u", 473280502Sarybchik SFXGE_PARAM_TX_RING, sfxge_tx_ring_entries, 474280502Sarybchik EFX_TXQ_MINNDESCS, EFX_TXQ_MAXNDESCS); 475280502Sarybchik error = EINVAL; 476280502Sarybchik goto fail_tx_ring_entries; 477280502Sarybchik } 478280502Sarybchik sc->txq_entries = sfxge_tx_ring_entries; 479280502Sarybchik 480227569Sphilip /* Initialize MCDI to talk to the microcontroller. */ 481227569Sphilip if ((error = sfxge_mcdi_init(sc)) != 0) 482227569Sphilip goto fail4; 483227569Sphilip 484227569Sphilip /* Probe the NIC and build the configuration data area. */ 485227569Sphilip if ((error = efx_nic_probe(enp)) != 0) 486227569Sphilip goto fail5; 487227569Sphilip 488280601Sarybchik SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), 489280601Sarybchik SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 490280601Sarybchik OID_AUTO, "version", CTLFLAG_RD, 491280601Sarybchik SFXGE_VERSION_STRING, 0, 492280601Sarybchik "Driver version"); 493280601Sarybchik 494227569Sphilip /* Initialize the NVRAM. */ 495227569Sphilip if ((error = efx_nvram_init(enp)) != 0) 496227569Sphilip goto fail6; 497227569Sphilip 498227569Sphilip /* Initialize the VPD. */ 499227569Sphilip if ((error = efx_vpd_init(enp)) != 0) 500227569Sphilip goto fail7; 501227569Sphilip 502227569Sphilip /* Reset the NIC. */ 503227569Sphilip if ((error = efx_nic_reset(enp)) != 0) 504227569Sphilip goto fail8; 505227569Sphilip 506227569Sphilip /* Initialize buffer table allocation. */ 507227569Sphilip sc->buffer_table_next = 0; 508227569Sphilip 509227569Sphilip /* Set up interrupts. */ 510227569Sphilip if ((error = sfxge_intr_init(sc)) != 0) 511227569Sphilip goto fail8; 512227569Sphilip 513227569Sphilip /* Initialize event processing state. */ 514227569Sphilip if ((error = sfxge_ev_init(sc)) != 0) 515227569Sphilip goto fail11; 516227569Sphilip 517227569Sphilip /* Initialize receive state. */ 518227569Sphilip if ((error = sfxge_rx_init(sc)) != 0) 519227569Sphilip goto fail12; 520227569Sphilip 521227569Sphilip /* Initialize transmit state. */ 522227569Sphilip if ((error = sfxge_tx_init(sc)) != 0) 523227569Sphilip goto fail13; 524227569Sphilip 525227569Sphilip /* Initialize port state. */ 526227569Sphilip if ((error = sfxge_port_init(sc)) != 0) 527227569Sphilip goto fail14; 528227569Sphilip 529227569Sphilip sc->init_state = SFXGE_INITIALIZED; 530227569Sphilip 531227569Sphilip return (0); 532227569Sphilip 533227569Sphilipfail14: 534227569Sphilip sfxge_tx_fini(sc); 535227569Sphilip 536227569Sphilipfail13: 537227569Sphilip sfxge_rx_fini(sc); 538227569Sphilip 539227569Sphilipfail12: 540227569Sphilip sfxge_ev_fini(sc); 541227569Sphilip 542227569Sphilipfail11: 543227569Sphilip sfxge_intr_fini(sc); 544227569Sphilip 545227569Sphilipfail8: 546227569Sphilip efx_vpd_fini(enp); 547227569Sphilip 548227569Sphilipfail7: 549227569Sphilip efx_nvram_fini(enp); 550227569Sphilip 551227569Sphilipfail6: 552227569Sphilip efx_nic_unprobe(enp); 553227569Sphilip 554227569Sphilipfail5: 555227569Sphilip sfxge_mcdi_fini(sc); 556227569Sphilip 557227569Sphilipfail4: 558280502Sarybchikfail_tx_ring_entries: 559280502Sarybchikfail_rx_ring_entries: 560227569Sphilip sc->enp = NULL; 561227569Sphilip efx_nic_destroy(enp); 562280524Sarybchik SFXGE_EFSYS_LOCK_DESTROY(&sc->enp_lock); 563227569Sphilip 564227569Sphilipfail3: 565227569Sphilip sfxge_bar_fini(sc); 566227569Sphilip (void) pci_disable_busmaster(sc->dev); 567227569Sphilip 568227569Sphilipfail: 569227569Sphilip sc->dev = NULL; 570280522Sarybchik SFXGE_ADAPTER_LOCK_DESTROY(sc); 571227569Sphilip return (error); 572227569Sphilip} 573227569Sphilip 574227569Sphilipstatic void 575227569Sphilipsfxge_destroy(struct sfxge_softc *sc) 576227569Sphilip{ 577227569Sphilip efx_nic_t *enp; 578227569Sphilip 579227569Sphilip /* Clean up port state. */ 580227569Sphilip sfxge_port_fini(sc); 581227569Sphilip 582227569Sphilip /* Clean up transmit state. */ 583227569Sphilip sfxge_tx_fini(sc); 584227569Sphilip 585227569Sphilip /* Clean up receive state. */ 586227569Sphilip sfxge_rx_fini(sc); 587227569Sphilip 588227569Sphilip /* Clean up event processing state. */ 589227569Sphilip sfxge_ev_fini(sc); 590227569Sphilip 591227569Sphilip /* Clean up interrupts. */ 592227569Sphilip sfxge_intr_fini(sc); 593227569Sphilip 594227569Sphilip /* Tear down common code subsystems. */ 595227569Sphilip efx_nic_reset(sc->enp); 596227569Sphilip efx_vpd_fini(sc->enp); 597227569Sphilip efx_nvram_fini(sc->enp); 598227569Sphilip efx_nic_unprobe(sc->enp); 599227569Sphilip 600227569Sphilip /* Tear down MCDI. */ 601227569Sphilip sfxge_mcdi_fini(sc); 602227569Sphilip 603227569Sphilip /* Destroy common code context. */ 604227569Sphilip enp = sc->enp; 605227569Sphilip sc->enp = NULL; 606227569Sphilip efx_nic_destroy(enp); 607227569Sphilip 608227569Sphilip /* Free DMA memory. */ 609227569Sphilip sfxge_dma_fini(sc); 610227569Sphilip 611227569Sphilip /* Free mapped BARs. */ 612227569Sphilip sfxge_bar_fini(sc); 613227569Sphilip 614227569Sphilip (void) pci_disable_busmaster(sc->dev); 615227569Sphilip 616227569Sphilip taskqueue_drain(taskqueue_thread, &sc->task_reset); 617227569Sphilip 618227569Sphilip /* Destroy the softc lock. */ 619280522Sarybchik SFXGE_ADAPTER_LOCK_DESTROY(sc); 620227569Sphilip} 621227569Sphilip 622227569Sphilipstatic int 623227569Sphilipsfxge_vpd_handler(SYSCTL_HANDLER_ARGS) 624227569Sphilip{ 625227569Sphilip struct sfxge_softc *sc = arg1; 626227569Sphilip efx_vpd_value_t value; 627227569Sphilip int rc; 628280501Sarybchik 629227569Sphilip value.evv_tag = arg2 >> 16; 630227569Sphilip value.evv_keyword = arg2 & 0xffff; 631227569Sphilip if ((rc = efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value)) 632227569Sphilip != 0) 633280501Sarybchik return (rc); 634227569Sphilip 635280501Sarybchik return (SYSCTL_OUT(req, value.evv_value, value.evv_length)); 636227569Sphilip} 637227569Sphilip 638227569Sphilipstatic void 639227569Sphilipsfxge_vpd_try_add(struct sfxge_softc *sc, struct sysctl_oid_list *list, 640227569Sphilip efx_vpd_tag_t tag, const char *keyword) 641227569Sphilip{ 642227569Sphilip struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); 643227569Sphilip efx_vpd_value_t value; 644227569Sphilip 645227569Sphilip /* Check whether VPD tag/keyword is present */ 646227569Sphilip value.evv_tag = tag; 647227569Sphilip value.evv_keyword = EFX_VPD_KEYWORD(keyword[0], keyword[1]); 648227569Sphilip if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) != 0) 649227569Sphilip return; 650227569Sphilip 651227569Sphilip SYSCTL_ADD_PROC( 652227569Sphilip ctx, list, OID_AUTO, keyword, CTLTYPE_STRING|CTLFLAG_RD, 653227569Sphilip sc, tag << 16 | EFX_VPD_KEYWORD(keyword[0], keyword[1]), 654227569Sphilip sfxge_vpd_handler, "A", ""); 655227569Sphilip} 656227569Sphilip 657227569Sphilipstatic int 658227569Sphilipsfxge_vpd_init(struct sfxge_softc *sc) 659227569Sphilip{ 660227569Sphilip struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); 661227569Sphilip struct sysctl_oid *vpd_node; 662227569Sphilip struct sysctl_oid_list *vpd_list; 663227569Sphilip char keyword[3]; 664227569Sphilip efx_vpd_value_t value; 665227569Sphilip int rc; 666227569Sphilip 667227569Sphilip if ((rc = efx_vpd_size(sc->enp, &sc->vpd_size)) != 0) 668227569Sphilip goto fail; 669227569Sphilip sc->vpd_data = malloc(sc->vpd_size, M_SFXGE, M_WAITOK); 670227569Sphilip if ((rc = efx_vpd_read(sc->enp, sc->vpd_data, sc->vpd_size)) != 0) 671227569Sphilip goto fail2; 672227569Sphilip 673227569Sphilip /* Copy ID (product name) into device description, and log it. */ 674227569Sphilip value.evv_tag = EFX_VPD_ID; 675227569Sphilip if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) == 0) { 676227569Sphilip value.evv_value[value.evv_length] = 0; 677227569Sphilip device_set_desc_copy(sc->dev, value.evv_value); 678227569Sphilip device_printf(sc->dev, "%s\n", value.evv_value); 679227569Sphilip } 680227569Sphilip 681227569Sphilip vpd_node = SYSCTL_ADD_NODE( 682227569Sphilip ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 683227569Sphilip OID_AUTO, "vpd", CTLFLAG_RD, NULL, "Vital Product Data"); 684227569Sphilip vpd_list = SYSCTL_CHILDREN(vpd_node); 685227569Sphilip 686227569Sphilip /* Add sysctls for all expected and any vendor-defined keywords. */ 687227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "PN"); 688227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "EC"); 689227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "SN"); 690227569Sphilip keyword[0] = 'V'; 691227569Sphilip keyword[2] = 0; 692227569Sphilip for (keyword[1] = '0'; keyword[1] <= '9'; keyword[1]++) 693227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword); 694227569Sphilip for (keyword[1] = 'A'; keyword[1] <= 'Z'; keyword[1]++) 695227569Sphilip sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword); 696227569Sphilip 697280501Sarybchik return (0); 698280501Sarybchik 699227569Sphilipfail2: 700227569Sphilip free(sc->vpd_data, M_SFXGE); 701227569Sphilipfail: 702280501Sarybchik return (rc); 703227569Sphilip} 704227569Sphilip 705227569Sphilipstatic void 706227569Sphilipsfxge_vpd_fini(struct sfxge_softc *sc) 707227569Sphilip{ 708227569Sphilip free(sc->vpd_data, M_SFXGE); 709227569Sphilip} 710227569Sphilip 711227569Sphilipstatic void 712227569Sphilipsfxge_reset(void *arg, int npending) 713227569Sphilip{ 714227569Sphilip struct sfxge_softc *sc; 715227569Sphilip int rc; 716227569Sphilip 717227569Sphilip (void)npending; 718227569Sphilip 719227569Sphilip sc = (struct sfxge_softc *)arg; 720227569Sphilip 721280522Sarybchik SFXGE_ADAPTER_LOCK(sc); 722227569Sphilip 723227569Sphilip if (sc->init_state != SFXGE_STARTED) 724227569Sphilip goto done; 725227569Sphilip 726227569Sphilip sfxge_stop(sc); 727227569Sphilip efx_nic_reset(sc->enp); 728227569Sphilip if ((rc = sfxge_start(sc)) != 0) 729227569Sphilip device_printf(sc->dev, 730227569Sphilip "reset failed (%d); interface is now stopped\n", 731227569Sphilip rc); 732227569Sphilip 733227569Sphilipdone: 734280522Sarybchik SFXGE_ADAPTER_UNLOCK(sc); 735227569Sphilip} 736227569Sphilip 737227569Sphilipvoid 738227569Sphilipsfxge_schedule_reset(struct sfxge_softc *sc) 739227569Sphilip{ 740227569Sphilip taskqueue_enqueue(taskqueue_thread, &sc->task_reset); 741227569Sphilip} 742227569Sphilip 743227569Sphilipstatic int 744227569Sphilipsfxge_attach(device_t dev) 745227569Sphilip{ 746227569Sphilip struct sfxge_softc *sc; 747227569Sphilip struct ifnet *ifp; 748227569Sphilip int error; 749227569Sphilip 750227569Sphilip sc = device_get_softc(dev); 751227569Sphilip sc->dev = dev; 752227569Sphilip 753227569Sphilip /* Allocate ifnet. */ 754227569Sphilip ifp = if_alloc(IFT_ETHER); 755227569Sphilip if (ifp == NULL) { 756227569Sphilip device_printf(dev, "Couldn't allocate ifnet\n"); 757227569Sphilip error = ENOMEM; 758227569Sphilip goto fail; 759227569Sphilip } 760227569Sphilip sc->ifnet = ifp; 761227569Sphilip 762227569Sphilip /* Initialize hardware. */ 763227569Sphilip if ((error = sfxge_create(sc)) != 0) 764227569Sphilip goto fail2; 765227569Sphilip 766227569Sphilip /* Create the ifnet for the port. */ 767227569Sphilip if ((error = sfxge_ifnet_init(ifp, sc)) != 0) 768227569Sphilip goto fail3; 769227569Sphilip 770227569Sphilip if ((error = sfxge_vpd_init(sc)) != 0) 771227569Sphilip goto fail4; 772227569Sphilip 773227569Sphilip sc->init_state = SFXGE_REGISTERED; 774227569Sphilip 775227569Sphilip return (0); 776227569Sphilip 777227569Sphilipfail4: 778227569Sphilip sfxge_ifnet_fini(ifp); 779227569Sphilipfail3: 780227569Sphilip sfxge_destroy(sc); 781227569Sphilip 782227569Sphilipfail2: 783227569Sphilip if_free(sc->ifnet); 784227569Sphilip 785227569Sphilipfail: 786227569Sphilip return (error); 787227569Sphilip} 788227569Sphilip 789227569Sphilipstatic int 790227569Sphilipsfxge_detach(device_t dev) 791227569Sphilip{ 792227569Sphilip struct sfxge_softc *sc; 793227569Sphilip 794227569Sphilip sc = device_get_softc(dev); 795227569Sphilip 796227569Sphilip sfxge_vpd_fini(sc); 797227569Sphilip 798227569Sphilip /* Destroy the ifnet. */ 799227569Sphilip sfxge_ifnet_fini(sc->ifnet); 800227569Sphilip 801227569Sphilip /* Tear down hardware. */ 802227569Sphilip sfxge_destroy(sc); 803227569Sphilip 804227569Sphilip return (0); 805227569Sphilip} 806227569Sphilip 807227569Sphilipstatic int 808227569Sphilipsfxge_probe(device_t dev) 809227569Sphilip{ 810227569Sphilip uint16_t pci_vendor_id; 811227569Sphilip uint16_t pci_device_id; 812227569Sphilip efx_family_t family; 813227569Sphilip int rc; 814227569Sphilip 815227569Sphilip pci_vendor_id = pci_get_vendor(dev); 816227569Sphilip pci_device_id = pci_get_device(dev); 817227569Sphilip 818227569Sphilip rc = efx_family(pci_vendor_id, pci_device_id, &family); 819280501Sarybchik if (rc != 0) 820280501Sarybchik return (ENXIO); 821227569Sphilip 822227569Sphilip KASSERT(family == EFX_FAMILY_SIENA, ("impossible controller family")); 823227569Sphilip device_set_desc(dev, "Solarflare SFC9000 family"); 824280501Sarybchik return (0); 825227569Sphilip} 826227569Sphilip 827227569Sphilipstatic device_method_t sfxge_methods[] = { 828227569Sphilip DEVMETHOD(device_probe, sfxge_probe), 829227569Sphilip DEVMETHOD(device_attach, sfxge_attach), 830227569Sphilip DEVMETHOD(device_detach, sfxge_detach), 831227569Sphilip 832227843Smarius DEVMETHOD_END 833227569Sphilip}; 834227569Sphilip 835227569Sphilipstatic devclass_t sfxge_devclass; 836227569Sphilip 837227569Sphilipstatic driver_t sfxge_driver = { 838227569Sphilip "sfxge", 839227569Sphilip sfxge_methods, 840227569Sphilip sizeof(struct sfxge_softc) 841227569Sphilip}; 842227569Sphilip 843227569SphilipDRIVER_MODULE(sfxge, pci, sfxge_driver, sfxge_devclass, 0, 0); 844