1231437Sluigi/*- 2252869Sdelphij * Copyright (C) 2013 Emulex 3231437Sluigi * All rights reserved. 4231437Sluigi * 5231437Sluigi * Redistribution and use in source and binary forms, with or without 6231437Sluigi * modification, are permitted provided that the following conditions are met: 7231437Sluigi * 8231437Sluigi * 1. Redistributions of source code must retain the above copyright notice, 9231437Sluigi * this list of conditions and the following disclaimer. 10231437Sluigi * 11231437Sluigi * 2. Redistributions in binary form must reproduce the above copyright 12231437Sluigi * notice, this list of conditions and the following disclaimer in the 13231437Sluigi * documentation and/or other materials provided with the distribution. 14231437Sluigi * 15231437Sluigi * 3. Neither the name of the Emulex Corporation nor the names of its 16231437Sluigi * contributors may be used to endorse or promote products derived from 17231437Sluigi * this software without specific prior written permission. 18231437Sluigi * 19231437Sluigi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20231437Sluigi * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21231437Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22231437Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23231437Sluigi * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24231437Sluigi * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25231437Sluigi * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26231437Sluigi * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27231437Sluigi * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28231437Sluigi * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29231437Sluigi * POSSIBILITY OF SUCH DAMAGE. 30231437Sluigi * 31231437Sluigi * Contact Information: 32231437Sluigi * freebsd-drivers@emulex.com 33231437Sluigi * 34231437Sluigi * Emulex 35231437Sluigi * 3333 Susan Street 36231437Sluigi * Costa Mesa, CA 92626 37231437Sluigi */ 38231437Sluigi 39231437Sluigi/* $FreeBSD$ */ 40231437Sluigi 41231511Sbz#include "opt_inet6.h" 42231511Sbz#include "opt_inet.h" 43231511Sbz 44231437Sluigi#include "oce_if.h" 45231437Sluigi 46257187Sdelphij/* UE Status Low CSR */ 47257187Sdelphijstatic char *ue_status_low_desc[] = { 48257187Sdelphij "CEV", 49257187Sdelphij "CTX", 50257187Sdelphij "DBUF", 51257187Sdelphij "ERX", 52257187Sdelphij "Host", 53257187Sdelphij "MPU", 54257187Sdelphij "NDMA", 55257187Sdelphij "PTC ", 56257187Sdelphij "RDMA ", 57257187Sdelphij "RXF ", 58257187Sdelphij "RXIPS ", 59257187Sdelphij "RXULP0 ", 60257187Sdelphij "RXULP1 ", 61257187Sdelphij "RXULP2 ", 62257187Sdelphij "TIM ", 63257187Sdelphij "TPOST ", 64257187Sdelphij "TPRE ", 65257187Sdelphij "TXIPS ", 66257187Sdelphij "TXULP0 ", 67257187Sdelphij "TXULP1 ", 68257187Sdelphij "UC ", 69257187Sdelphij "WDMA ", 70257187Sdelphij "TXULP2 ", 71257187Sdelphij "HOST1 ", 72257187Sdelphij "P0_OB_LINK ", 73257187Sdelphij "P1_OB_LINK ", 74257187Sdelphij "HOST_GPIO ", 75257187Sdelphij "MBOX ", 76257187Sdelphij "AXGMAC0", 77257187Sdelphij "AXGMAC1", 78257187Sdelphij "JTAG", 79257187Sdelphij "MPU_INTPEND" 80257187Sdelphij}; 81231437Sluigi 82257187Sdelphij/* UE Status High CSR */ 83257187Sdelphijstatic char *ue_status_hi_desc[] = { 84257187Sdelphij "LPCMEMHOST", 85257187Sdelphij "MGMT_MAC", 86257187Sdelphij "PCS0ONLINE", 87257187Sdelphij "MPU_IRAM", 88257187Sdelphij "PCS1ONLINE", 89257187Sdelphij "PCTL0", 90257187Sdelphij "PCTL1", 91257187Sdelphij "PMEM", 92257187Sdelphij "RR", 93257187Sdelphij "TXPB", 94257187Sdelphij "RXPP", 95257187Sdelphij "XAUI", 96257187Sdelphij "TXP", 97257187Sdelphij "ARM", 98257187Sdelphij "IPC", 99257187Sdelphij "HOST2", 100257187Sdelphij "HOST3", 101257187Sdelphij "HOST4", 102257187Sdelphij "HOST5", 103257187Sdelphij "HOST6", 104257187Sdelphij "HOST7", 105257187Sdelphij "HOST8", 106257187Sdelphij "HOST9", 107257187Sdelphij "NETC", 108257187Sdelphij "Unknown", 109257187Sdelphij "Unknown", 110257187Sdelphij "Unknown", 111257187Sdelphij "Unknown", 112257187Sdelphij "Unknown", 113257187Sdelphij "Unknown", 114257187Sdelphij "Unknown", 115257187Sdelphij "Unknown" 116257187Sdelphij}; 117257187Sdelphij 118257187Sdelphij 119231437Sluigi/* Driver entry points prototypes */ 120231437Sluigistatic int oce_probe(device_t dev); 121231437Sluigistatic int oce_attach(device_t dev); 122231437Sluigistatic int oce_detach(device_t dev); 123231437Sluigistatic int oce_shutdown(device_t dev); 124231437Sluigistatic int oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 125231437Sluigistatic void oce_init(void *xsc); 126231437Sluigistatic int oce_multiq_start(struct ifnet *ifp, struct mbuf *m); 127231437Sluigistatic void oce_multiq_flush(struct ifnet *ifp); 128231437Sluigi 129231437Sluigi/* Driver interrupt routines protypes */ 130231437Sluigistatic void oce_intr(void *arg, int pending); 131231437Sluigistatic int oce_setup_intr(POCE_SOFTC sc); 132231437Sluigistatic int oce_fast_isr(void *arg); 133231437Sluigistatic int oce_alloc_intr(POCE_SOFTC sc, int vector, 134231437Sluigi void (*isr) (void *arg, int pending)); 135231437Sluigi 136231437Sluigi/* Media callbacks prototypes */ 137231437Sluigistatic void oce_media_status(struct ifnet *ifp, struct ifmediareq *req); 138231437Sluigistatic int oce_media_change(struct ifnet *ifp); 139231437Sluigi 140231437Sluigi/* Transmit routines prototypes */ 141231437Sluigistatic int oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index); 142231437Sluigistatic void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq); 143231437Sluigistatic void oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, 144231437Sluigi uint32_t status); 145231437Sluigistatic int oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, 146231437Sluigi struct oce_wq *wq); 147231437Sluigi 148231437Sluigi/* Receive routines prototypes */ 149231437Sluigistatic void oce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); 150231437Sluigistatic int oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 151231437Sluigistatic int oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 152231437Sluigistatic void oce_rx(struct oce_rq *rq, uint32_t rqe_idx, 153231437Sluigi struct oce_nic_rx_cqe *cqe); 154231437Sluigi 155231437Sluigi/* Helper function prototypes in this file */ 156231437Sluigistatic int oce_attach_ifp(POCE_SOFTC sc); 157231437Sluigistatic void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 158231437Sluigistatic void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 159231437Sluigistatic int oce_vid_config(POCE_SOFTC sc); 160231437Sluigistatic void oce_mac_addr_set(POCE_SOFTC sc); 161231437Sluigistatic int oce_handle_passthrough(struct ifnet *ifp, caddr_t data); 162231437Sluigistatic void oce_local_timer(void *arg); 163231437Sluigistatic void oce_if_deactivate(POCE_SOFTC sc); 164231437Sluigistatic void oce_if_activate(POCE_SOFTC sc); 165231437Sluigistatic void setup_max_queues_want(POCE_SOFTC sc); 166231437Sluigistatic void update_queues_got(POCE_SOFTC sc); 167231879Sluigistatic void process_link_state(POCE_SOFTC sc, 168231879Sluigi struct oce_async_cqe_link_state *acqe); 169247880Sdelphijstatic int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m); 170252869Sdelphijstatic void oce_get_config(POCE_SOFTC sc); 171247880Sdelphijstatic struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete); 172231437Sluigi 173231879Sluigi/* IP specific */ 174231879Sluigi#if defined(INET6) || defined(INET) 175231879Sluigistatic int oce_init_lro(POCE_SOFTC sc); 176231879Sluigistatic void oce_rx_flush_lro(struct oce_rq *rq); 177231879Sluigistatic struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp); 178231879Sluigi#endif 179231879Sluigi 180231437Sluigistatic device_method_t oce_dispatch[] = { 181231437Sluigi DEVMETHOD(device_probe, oce_probe), 182231437Sluigi DEVMETHOD(device_attach, oce_attach), 183231437Sluigi DEVMETHOD(device_detach, oce_detach), 184231437Sluigi DEVMETHOD(device_shutdown, oce_shutdown), 185246128Ssbz 186246128Ssbz DEVMETHOD_END 187231437Sluigi}; 188231437Sluigi 189231437Sluigistatic driver_t oce_driver = { 190231437Sluigi "oce", 191231437Sluigi oce_dispatch, 192231437Sluigi sizeof(OCE_SOFTC) 193231437Sluigi}; 194231437Sluigistatic devclass_t oce_devclass; 195231437Sluigi 196231437Sluigi 197231437SluigiDRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0); 198231437SluigiMODULE_DEPEND(oce, pci, 1, 1, 1); 199231437SluigiMODULE_DEPEND(oce, ether, 1, 1, 1); 200231437SluigiMODULE_VERSION(oce, 1); 201231437Sluigi 202231437Sluigi 203231437Sluigi/* global vars */ 204231437Sluigiconst char component_revision[32] = {"///" COMPONENT_REVISION "///"}; 205231437Sluigi 206231437Sluigi/* Module capabilites and parameters */ 207231437Sluigiuint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED; 208231437Sluigiuint32_t oce_enable_rss = OCE_MODCAP_RSS; 209231437Sluigi 210231437Sluigi 211231437SluigiTUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled); 212231437SluigiTUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss); 213231437Sluigi 214231437Sluigi 215231437Sluigi/* Supported devices table */ 216231437Sluigistatic uint32_t supportedDevices[] = { 217231437Sluigi (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2, 218231437Sluigi (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3, 219231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3, 220231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201, 221231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF, 222252869Sdelphij (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH 223231437Sluigi}; 224231437Sluigi 225231437Sluigi 226231437Sluigi 227231437Sluigi 228231437Sluigi/***************************************************************************** 229231437Sluigi * Driver entry points functions * 230231437Sluigi *****************************************************************************/ 231231437Sluigi 232231437Sluigistatic int 233231437Sluigioce_probe(device_t dev) 234231437Sluigi{ 235231879Sluigi uint16_t vendor = 0; 236231879Sluigi uint16_t device = 0; 237231879Sluigi int i = 0; 238231879Sluigi char str[256] = {0}; 239231437Sluigi POCE_SOFTC sc; 240231437Sluigi 241231437Sluigi sc = device_get_softc(dev); 242231437Sluigi bzero(sc, sizeof(OCE_SOFTC)); 243231437Sluigi sc->dev = dev; 244231437Sluigi 245231437Sluigi vendor = pci_get_vendor(dev); 246231437Sluigi device = pci_get_device(dev); 247231437Sluigi 248231879Sluigi for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) { 249231437Sluigi if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) { 250231437Sluigi if (device == (supportedDevices[i] & 0xffff)) { 251231879Sluigi sprintf(str, "%s:%s", "Emulex CNA NIC function", 252231437Sluigi component_revision); 253231437Sluigi device_set_desc_copy(dev, str); 254231437Sluigi 255231437Sluigi switch (device) { 256231437Sluigi case PCI_PRODUCT_BE2: 257231437Sluigi sc->flags |= OCE_FLAGS_BE2; 258231437Sluigi break; 259231437Sluigi case PCI_PRODUCT_BE3: 260231437Sluigi sc->flags |= OCE_FLAGS_BE3; 261231437Sluigi break; 262231437Sluigi case PCI_PRODUCT_XE201: 263231437Sluigi case PCI_PRODUCT_XE201_VF: 264231437Sluigi sc->flags |= OCE_FLAGS_XE201; 265231437Sluigi break; 266252869Sdelphij case PCI_PRODUCT_SH: 267252869Sdelphij sc->flags |= OCE_FLAGS_SH; 268252869Sdelphij break; 269231437Sluigi default: 270231437Sluigi return ENXIO; 271231437Sluigi } 272231437Sluigi return BUS_PROBE_DEFAULT; 273231437Sluigi } 274231437Sluigi } 275231437Sluigi } 276231437Sluigi 277231437Sluigi return ENXIO; 278231437Sluigi} 279231437Sluigi 280231437Sluigi 281231437Sluigistatic int 282231437Sluigioce_attach(device_t dev) 283231437Sluigi{ 284231437Sluigi POCE_SOFTC sc; 285231437Sluigi int rc = 0; 286231437Sluigi 287231437Sluigi sc = device_get_softc(dev); 288231437Sluigi 289231437Sluigi rc = oce_hw_pci_alloc(sc); 290231437Sluigi if (rc) 291231437Sluigi return rc; 292231437Sluigi 293231437Sluigi sc->tx_ring_size = OCE_TX_RING_SIZE; 294231437Sluigi sc->rx_ring_size = OCE_RX_RING_SIZE; 295231437Sluigi sc->rq_frag_size = OCE_RQ_BUF_SIZE; 296231437Sluigi sc->flow_control = OCE_DEFAULT_FLOW_CONTROL; 297231437Sluigi sc->promisc = OCE_DEFAULT_PROMISCUOUS; 298231437Sluigi 299231437Sluigi LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock"); 300231437Sluigi LOCK_CREATE(&sc->dev_lock, "Device_lock"); 301231437Sluigi 302231437Sluigi /* initialise the hardware */ 303231437Sluigi rc = oce_hw_init(sc); 304231437Sluigi if (rc) 305231437Sluigi goto pci_res_free; 306231437Sluigi 307252869Sdelphij oce_get_config(sc); 308252869Sdelphij 309231437Sluigi setup_max_queues_want(sc); 310231437Sluigi 311231437Sluigi rc = oce_setup_intr(sc); 312231437Sluigi if (rc) 313231437Sluigi goto mbox_free; 314231437Sluigi 315231437Sluigi rc = oce_queue_init_all(sc); 316231437Sluigi if (rc) 317231437Sluigi goto intr_free; 318231437Sluigi 319231437Sluigi rc = oce_attach_ifp(sc); 320231437Sluigi if (rc) 321231437Sluigi goto queues_free; 322231437Sluigi 323231511Sbz#if defined(INET6) || defined(INET) 324231437Sluigi rc = oce_init_lro(sc); 325231437Sluigi if (rc) 326231879Sluigi goto ifp_free; 327231511Sbz#endif 328231437Sluigi 329231437Sluigi rc = oce_hw_start(sc); 330231437Sluigi if (rc) 331241844Seadler goto lro_free; 332231437Sluigi 333231437Sluigi sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 334231437Sluigi oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST); 335231437Sluigi sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 336231437Sluigi oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST); 337231437Sluigi 338231437Sluigi rc = oce_stats_init(sc); 339231437Sluigi if (rc) 340231437Sluigi goto vlan_free; 341231437Sluigi 342231437Sluigi oce_add_sysctls(sc); 343231437Sluigi 344231437Sluigi callout_init(&sc->timer, CALLOUT_MPSAFE); 345231437Sluigi rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc); 346231437Sluigi if (rc) 347231437Sluigi goto stats_free; 348231437Sluigi 349231437Sluigi return 0; 350231437Sluigi 351231437Sluigistats_free: 352231437Sluigi callout_drain(&sc->timer); 353231437Sluigi oce_stats_free(sc); 354231437Sluigivlan_free: 355231437Sluigi if (sc->vlan_attach) 356231437Sluigi EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 357231437Sluigi if (sc->vlan_detach) 358231437Sluigi EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 359231437Sluigi oce_hw_intr_disable(sc); 360231437Sluigilro_free: 361231511Sbz#if defined(INET6) || defined(INET) 362231437Sluigi oce_free_lro(sc); 363231437Sluigiifp_free: 364231511Sbz#endif 365231437Sluigi ether_ifdetach(sc->ifp); 366231437Sluigi if_free(sc->ifp); 367231437Sluigiqueues_free: 368231437Sluigi oce_queue_release_all(sc); 369231437Sluigiintr_free: 370231437Sluigi oce_intr_free(sc); 371231437Sluigimbox_free: 372231437Sluigi oce_dma_free(sc, &sc->bsmbx); 373231437Sluigipci_res_free: 374231437Sluigi oce_hw_pci_free(sc); 375231437Sluigi LOCK_DESTROY(&sc->dev_lock); 376231437Sluigi LOCK_DESTROY(&sc->bmbx_lock); 377231437Sluigi return rc; 378231437Sluigi 379231437Sluigi} 380231437Sluigi 381231437Sluigi 382231437Sluigistatic int 383231437Sluigioce_detach(device_t dev) 384231437Sluigi{ 385231437Sluigi POCE_SOFTC sc = device_get_softc(dev); 386231437Sluigi 387231437Sluigi LOCK(&sc->dev_lock); 388231437Sluigi oce_if_deactivate(sc); 389231437Sluigi UNLOCK(&sc->dev_lock); 390231437Sluigi 391231437Sluigi callout_drain(&sc->timer); 392231437Sluigi 393231437Sluigi if (sc->vlan_attach != NULL) 394231437Sluigi EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 395231437Sluigi if (sc->vlan_detach != NULL) 396231437Sluigi EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 397231437Sluigi 398231437Sluigi ether_ifdetach(sc->ifp); 399231437Sluigi 400231437Sluigi if_free(sc->ifp); 401231437Sluigi 402231437Sluigi oce_hw_shutdown(sc); 403231437Sluigi 404231437Sluigi bus_generic_detach(dev); 405231437Sluigi 406231437Sluigi return 0; 407231437Sluigi} 408231437Sluigi 409231437Sluigi 410231437Sluigistatic int 411231437Sluigioce_shutdown(device_t dev) 412231437Sluigi{ 413231437Sluigi int rc; 414231437Sluigi 415231437Sluigi rc = oce_detach(dev); 416231437Sluigi 417231437Sluigi return rc; 418231437Sluigi} 419231437Sluigi 420231437Sluigi 421231437Sluigistatic int 422231437Sluigioce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 423231437Sluigi{ 424231437Sluigi struct ifreq *ifr = (struct ifreq *)data; 425231437Sluigi POCE_SOFTC sc = ifp->if_softc; 426231437Sluigi int rc = 0; 427231437Sluigi uint32_t u; 428231437Sluigi 429231437Sluigi switch (command) { 430231437Sluigi 431231437Sluigi case SIOCGIFMEDIA: 432231437Sluigi rc = ifmedia_ioctl(ifp, ifr, &sc->media, command); 433231437Sluigi break; 434231437Sluigi 435231437Sluigi case SIOCSIFMTU: 436231437Sluigi if (ifr->ifr_mtu > OCE_MAX_MTU) 437231437Sluigi rc = EINVAL; 438231437Sluigi else 439231437Sluigi ifp->if_mtu = ifr->ifr_mtu; 440231437Sluigi break; 441231437Sluigi 442231437Sluigi case SIOCSIFFLAGS: 443231437Sluigi if (ifp->if_flags & IFF_UP) { 444231437Sluigi if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 445231437Sluigi sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 446231437Sluigi oce_init(sc); 447231437Sluigi } 448231437Sluigi device_printf(sc->dev, "Interface Up\n"); 449231437Sluigi } else { 450231437Sluigi LOCK(&sc->dev_lock); 451231437Sluigi 452231437Sluigi sc->ifp->if_drv_flags &= 453231437Sluigi ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 454231437Sluigi oce_if_deactivate(sc); 455231437Sluigi 456231437Sluigi UNLOCK(&sc->dev_lock); 457231437Sluigi 458231437Sluigi device_printf(sc->dev, "Interface Down\n"); 459231437Sluigi } 460231437Sluigi 461231437Sluigi if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) { 462257187Sdelphij if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1)))) 463257187Sdelphij sc->promisc = TRUE; 464231437Sluigi } else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) { 465257187Sdelphij if (!oce_rxf_set_promiscuous(sc, 0)) 466257187Sdelphij sc->promisc = FALSE; 467231437Sluigi } 468231437Sluigi 469231437Sluigi break; 470231437Sluigi 471231437Sluigi case SIOCADDMULTI: 472231437Sluigi case SIOCDELMULTI: 473231437Sluigi rc = oce_hw_update_multicast(sc); 474231437Sluigi if (rc) 475231437Sluigi device_printf(sc->dev, 476231437Sluigi "Update multicast address failed\n"); 477231437Sluigi break; 478231437Sluigi 479231437Sluigi case SIOCSIFCAP: 480231437Sluigi u = ifr->ifr_reqcap ^ ifp->if_capenable; 481231437Sluigi 482231437Sluigi if (u & IFCAP_TXCSUM) { 483231437Sluigi ifp->if_capenable ^= IFCAP_TXCSUM; 484231437Sluigi ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 485231437Sluigi 486231437Sluigi if (IFCAP_TSO & ifp->if_capenable && 487231437Sluigi !(IFCAP_TXCSUM & ifp->if_capenable)) { 488231437Sluigi ifp->if_capenable &= ~IFCAP_TSO; 489231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 490231437Sluigi if_printf(ifp, 491231437Sluigi "TSO disabled due to -txcsum.\n"); 492231437Sluigi } 493231437Sluigi } 494231437Sluigi 495231437Sluigi if (u & IFCAP_RXCSUM) 496231437Sluigi ifp->if_capenable ^= IFCAP_RXCSUM; 497231437Sluigi 498231437Sluigi if (u & IFCAP_TSO4) { 499231437Sluigi ifp->if_capenable ^= IFCAP_TSO4; 500231437Sluigi 501231437Sluigi if (IFCAP_TSO & ifp->if_capenable) { 502231437Sluigi if (IFCAP_TXCSUM & ifp->if_capenable) 503231437Sluigi ifp->if_hwassist |= CSUM_TSO; 504231437Sluigi else { 505231437Sluigi ifp->if_capenable &= ~IFCAP_TSO; 506231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 507231437Sluigi if_printf(ifp, 508231437Sluigi "Enable txcsum first.\n"); 509231437Sluigi rc = EAGAIN; 510231437Sluigi } 511231437Sluigi } else 512231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 513231437Sluigi } 514231437Sluigi 515231437Sluigi if (u & IFCAP_VLAN_HWTAGGING) 516231437Sluigi ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 517231437Sluigi 518231437Sluigi if (u & IFCAP_VLAN_HWFILTER) { 519231437Sluigi ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 520231437Sluigi oce_vid_config(sc); 521231437Sluigi } 522231511Sbz#if defined(INET6) || defined(INET) 523231437Sluigi if (u & IFCAP_LRO) 524231437Sluigi ifp->if_capenable ^= IFCAP_LRO; 525231511Sbz#endif 526231437Sluigi 527231437Sluigi break; 528231437Sluigi 529231437Sluigi case SIOCGPRIVATE_0: 530231437Sluigi rc = oce_handle_passthrough(ifp, data); 531231437Sluigi break; 532231437Sluigi default: 533231437Sluigi rc = ether_ioctl(ifp, command, data); 534231437Sluigi break; 535231437Sluigi } 536231437Sluigi 537231437Sluigi return rc; 538231437Sluigi} 539231437Sluigi 540231437Sluigi 541231437Sluigistatic void 542231437Sluigioce_init(void *arg) 543231437Sluigi{ 544231437Sluigi POCE_SOFTC sc = arg; 545231437Sluigi 546231437Sluigi LOCK(&sc->dev_lock); 547231437Sluigi 548231437Sluigi if (sc->ifp->if_flags & IFF_UP) { 549231437Sluigi oce_if_deactivate(sc); 550231437Sluigi oce_if_activate(sc); 551231437Sluigi } 552231437Sluigi 553231437Sluigi UNLOCK(&sc->dev_lock); 554231437Sluigi 555231437Sluigi} 556231437Sluigi 557231437Sluigi 558231437Sluigistatic int 559231437Sluigioce_multiq_start(struct ifnet *ifp, struct mbuf *m) 560231437Sluigi{ 561231437Sluigi POCE_SOFTC sc = ifp->if_softc; 562231437Sluigi struct oce_wq *wq = NULL; 563231437Sluigi int queue_index = 0; 564231437Sluigi int status = 0; 565247880Sdelphij 566252869Sdelphij if (!sc->link_status) 567252869Sdelphij return ENXIO; 568252869Sdelphij 569231437Sluigi if ((m->m_flags & M_FLOWID) != 0) 570231437Sluigi queue_index = m->m_pkthdr.flowid % sc->nwqs; 571252869Sdelphij 572231437Sluigi wq = sc->wq[queue_index]; 573231437Sluigi 574252869Sdelphij LOCK(&wq->tx_lock); 575252869Sdelphij status = oce_multiq_transmit(ifp, m, wq); 576252869Sdelphij UNLOCK(&wq->tx_lock); 577252869Sdelphij 578231437Sluigi return status; 579231437Sluigi 580231437Sluigi} 581231437Sluigi 582231437Sluigi 583231437Sluigistatic void 584231437Sluigioce_multiq_flush(struct ifnet *ifp) 585231437Sluigi{ 586231437Sluigi POCE_SOFTC sc = ifp->if_softc; 587231437Sluigi struct mbuf *m; 588231437Sluigi int i = 0; 589231437Sluigi 590231437Sluigi for (i = 0; i < sc->nwqs; i++) { 591231437Sluigi while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) 592231437Sluigi m_freem(m); 593231437Sluigi } 594231437Sluigi if_qflush(ifp); 595231437Sluigi} 596231437Sluigi 597231437Sluigi 598231437Sluigi 599231437Sluigi/***************************************************************************** 600231437Sluigi * Driver interrupt routines functions * 601231437Sluigi *****************************************************************************/ 602231437Sluigi 603231437Sluigistatic void 604231437Sluigioce_intr(void *arg, int pending) 605231437Sluigi{ 606231437Sluigi 607231437Sluigi POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 608231437Sluigi POCE_SOFTC sc = ii->sc; 609231437Sluigi struct oce_eq *eq = ii->eq; 610231437Sluigi struct oce_eqe *eqe; 611231437Sluigi struct oce_cq *cq = NULL; 612231437Sluigi int i, num_eqes = 0; 613231437Sluigi 614231437Sluigi 615231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 616231437Sluigi BUS_DMASYNC_POSTWRITE); 617231437Sluigi do { 618231437Sluigi eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 619231437Sluigi if (eqe->evnt == 0) 620231437Sluigi break; 621231437Sluigi eqe->evnt = 0; 622231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 623231437Sluigi BUS_DMASYNC_POSTWRITE); 624231437Sluigi RING_GET(eq->ring, 1); 625231437Sluigi num_eqes++; 626231437Sluigi 627231437Sluigi } while (TRUE); 628231437Sluigi 629231437Sluigi if (!num_eqes) 630231437Sluigi goto eq_arm; /* Spurious */ 631231437Sluigi 632231437Sluigi /* Clear EQ entries, but dont arm */ 633231437Sluigi oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE); 634231437Sluigi 635231437Sluigi /* Process TX, RX and MCC. But dont arm CQ*/ 636231437Sluigi for (i = 0; i < eq->cq_valid; i++) { 637231437Sluigi cq = eq->cq[i]; 638231437Sluigi (*cq->cq_handler)(cq->cb_arg); 639231437Sluigi } 640231437Sluigi 641231437Sluigi /* Arm all cqs connected to this EQ */ 642231437Sluigi for (i = 0; i < eq->cq_valid; i++) { 643231437Sluigi cq = eq->cq[i]; 644231437Sluigi oce_arm_cq(sc, cq->cq_id, 0, TRUE); 645231437Sluigi } 646231437Sluigi 647231437Sluigieq_arm: 648231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 649247880Sdelphij 650231437Sluigi return; 651231437Sluigi} 652231437Sluigi 653231437Sluigi 654231437Sluigistatic int 655231437Sluigioce_setup_intr(POCE_SOFTC sc) 656231437Sluigi{ 657231437Sluigi int rc = 0, use_intx = 0; 658231437Sluigi int vector = 0, req_vectors = 0; 659231437Sluigi 660252869Sdelphij if (is_rss_enabled(sc)) 661231437Sluigi req_vectors = MAX((sc->nrqs - 1), sc->nwqs); 662231437Sluigi else 663231437Sluigi req_vectors = 1; 664231437Sluigi 665231437Sluigi if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) { 666231437Sluigi sc->intr_count = req_vectors; 667231437Sluigi rc = pci_alloc_msix(sc->dev, &sc->intr_count); 668231437Sluigi if (rc != 0) { 669231437Sluigi use_intx = 1; 670231437Sluigi pci_release_msi(sc->dev); 671231437Sluigi } else 672231437Sluigi sc->flags |= OCE_FLAGS_USING_MSIX; 673231437Sluigi } else 674231437Sluigi use_intx = 1; 675231437Sluigi 676231437Sluigi if (use_intx) 677231437Sluigi sc->intr_count = 1; 678231437Sluigi 679231437Sluigi /* Scale number of queues based on intr we got */ 680231437Sluigi update_queues_got(sc); 681231437Sluigi 682231437Sluigi if (use_intx) { 683231437Sluigi device_printf(sc->dev, "Using legacy interrupt\n"); 684231437Sluigi rc = oce_alloc_intr(sc, vector, oce_intr); 685231437Sluigi if (rc) 686231437Sluigi goto error; 687231437Sluigi } else { 688231437Sluigi for (; vector < sc->intr_count; vector++) { 689231437Sluigi rc = oce_alloc_intr(sc, vector, oce_intr); 690231437Sluigi if (rc) 691231437Sluigi goto error; 692231437Sluigi } 693231437Sluigi } 694231437Sluigi 695231437Sluigi return 0; 696231437Sluigierror: 697231437Sluigi oce_intr_free(sc); 698231437Sluigi return rc; 699231437Sluigi} 700231437Sluigi 701231437Sluigi 702231437Sluigistatic int 703231437Sluigioce_fast_isr(void *arg) 704231437Sluigi{ 705231437Sluigi POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 706231437Sluigi POCE_SOFTC sc = ii->sc; 707231437Sluigi 708231437Sluigi if (ii->eq == NULL) 709231437Sluigi return FILTER_STRAY; 710231437Sluigi 711231437Sluigi oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE); 712231437Sluigi 713231437Sluigi taskqueue_enqueue_fast(ii->tq, &ii->task); 714231437Sluigi 715247880Sdelphij ii->eq->intr++; 716247880Sdelphij 717231437Sluigi return FILTER_HANDLED; 718231437Sluigi} 719231437Sluigi 720231437Sluigi 721231437Sluigistatic int 722231437Sluigioce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) 723231437Sluigi{ 724231437Sluigi POCE_INTR_INFO ii = &sc->intrs[vector]; 725231437Sluigi int rc = 0, rr; 726231437Sluigi 727231437Sluigi if (vector >= OCE_MAX_EQ) 728231437Sluigi return (EINVAL); 729231437Sluigi 730231437Sluigi /* Set the resource id for the interrupt. 731231437Sluigi * MSIx is vector + 1 for the resource id, 732231437Sluigi * INTx is 0 for the resource id. 733231437Sluigi */ 734231437Sluigi if (sc->flags & OCE_FLAGS_USING_MSIX) 735231437Sluigi rr = vector + 1; 736231437Sluigi else 737231437Sluigi rr = 0; 738231437Sluigi ii->intr_res = bus_alloc_resource_any(sc->dev, 739231437Sluigi SYS_RES_IRQ, 740231437Sluigi &rr, RF_ACTIVE|RF_SHAREABLE); 741231437Sluigi ii->irq_rr = rr; 742231437Sluigi if (ii->intr_res == NULL) { 743231437Sluigi device_printf(sc->dev, 744231437Sluigi "Could not allocate interrupt\n"); 745231437Sluigi rc = ENXIO; 746231437Sluigi return rc; 747231437Sluigi } 748231437Sluigi 749231437Sluigi TASK_INIT(&ii->task, 0, isr, ii); 750231437Sluigi ii->vector = vector; 751231437Sluigi sprintf(ii->task_name, "oce_task[%d]", ii->vector); 752231437Sluigi ii->tq = taskqueue_create_fast(ii->task_name, 753231437Sluigi M_NOWAIT, 754231437Sluigi taskqueue_thread_enqueue, 755231437Sluigi &ii->tq); 756231437Sluigi taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq", 757231437Sluigi device_get_nameunit(sc->dev)); 758231437Sluigi 759231437Sluigi ii->sc = sc; 760231437Sluigi rc = bus_setup_intr(sc->dev, 761231437Sluigi ii->intr_res, 762231437Sluigi INTR_TYPE_NET, 763231437Sluigi oce_fast_isr, NULL, ii, &ii->tag); 764231437Sluigi return rc; 765231437Sluigi 766231437Sluigi} 767231437Sluigi 768231437Sluigi 769231437Sluigivoid 770231437Sluigioce_intr_free(POCE_SOFTC sc) 771231437Sluigi{ 772231437Sluigi int i = 0; 773231437Sluigi 774231437Sluigi for (i = 0; i < sc->intr_count; i++) { 775231437Sluigi 776231437Sluigi if (sc->intrs[i].tag != NULL) 777231437Sluigi bus_teardown_intr(sc->dev, sc->intrs[i].intr_res, 778231437Sluigi sc->intrs[i].tag); 779231437Sluigi if (sc->intrs[i].tq != NULL) 780231437Sluigi taskqueue_free(sc->intrs[i].tq); 781231437Sluigi 782231437Sluigi if (sc->intrs[i].intr_res != NULL) 783231437Sluigi bus_release_resource(sc->dev, SYS_RES_IRQ, 784231437Sluigi sc->intrs[i].irq_rr, 785231437Sluigi sc->intrs[i].intr_res); 786231437Sluigi sc->intrs[i].tag = NULL; 787231437Sluigi sc->intrs[i].intr_res = NULL; 788231437Sluigi } 789231437Sluigi 790231437Sluigi if (sc->flags & OCE_FLAGS_USING_MSIX) 791231437Sluigi pci_release_msi(sc->dev); 792231437Sluigi 793231437Sluigi} 794231437Sluigi 795231437Sluigi 796231437Sluigi 797231437Sluigi/****************************************************************************** 798231437Sluigi* Media callbacks functions * 799231437Sluigi******************************************************************************/ 800231437Sluigi 801231437Sluigistatic void 802231437Sluigioce_media_status(struct ifnet *ifp, struct ifmediareq *req) 803231437Sluigi{ 804231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc; 805231437Sluigi 806231437Sluigi 807231437Sluigi req->ifm_status = IFM_AVALID; 808231437Sluigi req->ifm_active = IFM_ETHER; 809231437Sluigi 810231437Sluigi if (sc->link_status == 1) 811231437Sluigi req->ifm_status |= IFM_ACTIVE; 812231437Sluigi else 813231437Sluigi return; 814231437Sluigi 815231437Sluigi switch (sc->link_speed) { 816231437Sluigi case 1: /* 10 Mbps */ 817231437Sluigi req->ifm_active |= IFM_10_T | IFM_FDX; 818231437Sluigi sc->speed = 10; 819231437Sluigi break; 820231437Sluigi case 2: /* 100 Mbps */ 821231437Sluigi req->ifm_active |= IFM_100_TX | IFM_FDX; 822231437Sluigi sc->speed = 100; 823231437Sluigi break; 824231437Sluigi case 3: /* 1 Gbps */ 825231437Sluigi req->ifm_active |= IFM_1000_T | IFM_FDX; 826231437Sluigi sc->speed = 1000; 827231437Sluigi break; 828231437Sluigi case 4: /* 10 Gbps */ 829231437Sluigi req->ifm_active |= IFM_10G_SR | IFM_FDX; 830231437Sluigi sc->speed = 10000; 831231437Sluigi break; 832259050Sdelphij case 7: /* 40 Gbps */ 833259050Sdelphij req->ifm_active |= IFM_40G_SR4 | IFM_FDX; 834259050Sdelphij sc->speed = 40000; 835259050Sdelphij break; 836231437Sluigi } 837231437Sluigi 838231437Sluigi return; 839231437Sluigi} 840231437Sluigi 841231437Sluigi 842231437Sluigiint 843231437Sluigioce_media_change(struct ifnet *ifp) 844231437Sluigi{ 845231437Sluigi return 0; 846231437Sluigi} 847231437Sluigi 848231437Sluigi 849231437Sluigi 850231437Sluigi 851231437Sluigi/***************************************************************************** 852231437Sluigi * Transmit routines functions * 853231437Sluigi *****************************************************************************/ 854231437Sluigi 855231437Sluigistatic int 856231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 857231437Sluigi{ 858231437Sluigi int rc = 0, i, retry_cnt = 0; 859231437Sluigi bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 860231437Sluigi struct mbuf *m, *m_temp; 861231437Sluigi struct oce_wq *wq = sc->wq[wq_index]; 862231437Sluigi struct oce_packet_desc *pd; 863231437Sluigi struct oce_nic_hdr_wqe *nichdr; 864231437Sluigi struct oce_nic_frag_wqe *nicfrag; 865231437Sluigi int num_wqes; 866231437Sluigi uint32_t reg_value; 867247880Sdelphij boolean_t complete = TRUE; 868231437Sluigi 869231437Sluigi m = *mpp; 870231437Sluigi if (!m) 871231437Sluigi return EINVAL; 872231437Sluigi 873231437Sluigi if (!(m->m_flags & M_PKTHDR)) { 874231437Sluigi rc = ENXIO; 875231437Sluigi goto free_ret; 876231437Sluigi } 877231437Sluigi 878247880Sdelphij if(oce_tx_asic_stall_verify(sc, m)) { 879247880Sdelphij m = oce_insert_vlan_tag(sc, m, &complete); 880247880Sdelphij if(!m) { 881247880Sdelphij device_printf(sc->dev, "Insertion unsuccessful\n"); 882247880Sdelphij return 0; 883247880Sdelphij } 884247880Sdelphij 885247880Sdelphij } 886247880Sdelphij 887231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 888231879Sluigi /* consolidate packet buffers for TSO/LSO segment offload */ 889231511Sbz#if defined(INET6) || defined(INET) 890231879Sluigi m = oce_tso_setup(sc, mpp); 891231511Sbz#else 892231511Sbz m = NULL; 893231511Sbz#endif 894231437Sluigi if (m == NULL) { 895231437Sluigi rc = ENXIO; 896231437Sluigi goto free_ret; 897231437Sluigi } 898231437Sluigi } 899231437Sluigi 900252869Sdelphij pd = &wq->pckts[wq->pkt_desc_head]; 901231437Sluigiretry: 902231437Sluigi rc = bus_dmamap_load_mbuf_sg(wq->tag, 903231437Sluigi pd->map, 904231437Sluigi m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 905231437Sluigi if (rc == 0) { 906231437Sluigi num_wqes = pd->nsegs + 1; 907252869Sdelphij if (IS_BE(sc) || IS_SH(sc)) { 908231437Sluigi /*Dummy required only for BE3.*/ 909231437Sluigi if (num_wqes & 1) 910231437Sluigi num_wqes++; 911231437Sluigi } 912231437Sluigi if (num_wqes >= RING_NUM_FREE(wq->ring)) { 913231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 914231437Sluigi return EBUSY; 915231437Sluigi } 916252869Sdelphij atomic_store_rel_int(&wq->pkt_desc_head, 917252869Sdelphij (wq->pkt_desc_head + 1) % \ 918252869Sdelphij OCE_WQ_PACKET_ARRAY_SIZE); 919231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 920231437Sluigi pd->mbuf = m; 921231437Sluigi 922231437Sluigi nichdr = 923231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 924231437Sluigi nichdr->u0.dw[0] = 0; 925231437Sluigi nichdr->u0.dw[1] = 0; 926231437Sluigi nichdr->u0.dw[2] = 0; 927231437Sluigi nichdr->u0.dw[3] = 0; 928231437Sluigi 929247880Sdelphij nichdr->u0.s.complete = complete; 930231437Sluigi nichdr->u0.s.event = 1; 931231437Sluigi nichdr->u0.s.crc = 1; 932231437Sluigi nichdr->u0.s.forward = 0; 933231437Sluigi nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 934231437Sluigi nichdr->u0.s.udpcs = 935247880Sdelphij (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 936231437Sluigi nichdr->u0.s.tcpcs = 937247880Sdelphij (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 938231437Sluigi nichdr->u0.s.num_wqe = num_wqes; 939231437Sluigi nichdr->u0.s.total_length = m->m_pkthdr.len; 940257187Sdelphij 941231437Sluigi if (m->m_flags & M_VLANTAG) { 942231437Sluigi nichdr->u0.s.vlan = 1; /*Vlan present*/ 943231437Sluigi nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 944231437Sluigi } 945257187Sdelphij 946231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 947231437Sluigi if (m->m_pkthdr.tso_segsz) { 948231437Sluigi nichdr->u0.s.lso = 1; 949231437Sluigi nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 950231437Sluigi } 951252869Sdelphij if (!IS_BE(sc) || !IS_SH(sc)) 952231437Sluigi nichdr->u0.s.ipcs = 1; 953231437Sluigi } 954231437Sluigi 955231437Sluigi RING_PUT(wq->ring, 1); 956252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 957231437Sluigi 958231437Sluigi for (i = 0; i < pd->nsegs; i++) { 959231437Sluigi nicfrag = 960231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 961231437Sluigi struct oce_nic_frag_wqe); 962231437Sluigi nicfrag->u0.s.rsvd0 = 0; 963231437Sluigi nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 964231437Sluigi nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 965231437Sluigi nicfrag->u0.s.frag_len = segs[i].ds_len; 966231437Sluigi pd->wqe_idx = wq->ring->pidx; 967231437Sluigi RING_PUT(wq->ring, 1); 968252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 969231437Sluigi } 970231437Sluigi if (num_wqes > (pd->nsegs + 1)) { 971231437Sluigi nicfrag = 972231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 973231437Sluigi struct oce_nic_frag_wqe); 974231437Sluigi nicfrag->u0.dw[0] = 0; 975231437Sluigi nicfrag->u0.dw[1] = 0; 976231437Sluigi nicfrag->u0.dw[2] = 0; 977231437Sluigi nicfrag->u0.dw[3] = 0; 978231437Sluigi pd->wqe_idx = wq->ring->pidx; 979231437Sluigi RING_PUT(wq->ring, 1); 980252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 981231437Sluigi pd->nsegs++; 982231437Sluigi } 983231437Sluigi 984231437Sluigi sc->ifp->if_opackets++; 985231437Sluigi wq->tx_stats.tx_reqs++; 986231437Sluigi wq->tx_stats.tx_wrbs += num_wqes; 987231437Sluigi wq->tx_stats.tx_bytes += m->m_pkthdr.len; 988231437Sluigi wq->tx_stats.tx_pkts++; 989247880Sdelphij 990231437Sluigi bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 991231437Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 992231437Sluigi reg_value = (num_wqes << 16) | wq->wq_id; 993252869Sdelphij OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value); 994231437Sluigi 995231437Sluigi } else if (rc == EFBIG) { 996231437Sluigi if (retry_cnt == 0) { 997243857Sglebius m_temp = m_defrag(m, M_NOWAIT); 998231437Sluigi if (m_temp == NULL) 999231437Sluigi goto free_ret; 1000231437Sluigi m = m_temp; 1001231437Sluigi *mpp = m_temp; 1002231437Sluigi retry_cnt = retry_cnt + 1; 1003231437Sluigi goto retry; 1004231437Sluigi } else 1005231437Sluigi goto free_ret; 1006231437Sluigi } else if (rc == ENOMEM) 1007231437Sluigi return rc; 1008231437Sluigi else 1009231437Sluigi goto free_ret; 1010252869Sdelphij 1011231437Sluigi return 0; 1012231437Sluigi 1013231437Sluigifree_ret: 1014231437Sluigi m_freem(*mpp); 1015231437Sluigi *mpp = NULL; 1016231437Sluigi return rc; 1017231437Sluigi} 1018231437Sluigi 1019231437Sluigi 1020231437Sluigistatic void 1021231437Sluigioce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status) 1022231437Sluigi{ 1023231437Sluigi struct oce_packet_desc *pd; 1024231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 1025231437Sluigi struct mbuf *m; 1026231437Sluigi 1027252869Sdelphij pd = &wq->pckts[wq->pkt_desc_tail]; 1028252869Sdelphij atomic_store_rel_int(&wq->pkt_desc_tail, 1029252869Sdelphij (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE); 1030252869Sdelphij atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1); 1031231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1032231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 1033231437Sluigi 1034231437Sluigi m = pd->mbuf; 1035231437Sluigi m_freem(m); 1036231437Sluigi pd->mbuf = NULL; 1037231437Sluigi 1038252869Sdelphij 1039231437Sluigi if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1040231437Sluigi if (wq->ring->num_used < (wq->ring->num_items / 2)) { 1041231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 1042231437Sluigi oce_tx_restart(sc, wq); 1043231437Sluigi } 1044231437Sluigi } 1045231437Sluigi} 1046231437Sluigi 1047231437Sluigi 1048231437Sluigistatic void 1049231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 1050231437Sluigi{ 1051231437Sluigi 1052231437Sluigi if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 1053231437Sluigi return; 1054231437Sluigi 1055231437Sluigi#if __FreeBSD_version >= 800000 1056231437Sluigi if (!drbr_empty(sc->ifp, wq->br)) 1057231437Sluigi#else 1058231437Sluigi if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 1059231437Sluigi#endif 1060231437Sluigi taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask); 1061231437Sluigi 1062231437Sluigi} 1063231437Sluigi 1064231879Sluigi 1065231511Sbz#if defined(INET6) || defined(INET) 1066231437Sluigistatic struct mbuf * 1067231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp) 1068231437Sluigi{ 1069231437Sluigi struct mbuf *m; 1070231511Sbz#ifdef INET 1071231437Sluigi struct ip *ip; 1072231511Sbz#endif 1073231511Sbz#ifdef INET6 1074231437Sluigi struct ip6_hdr *ip6; 1075231511Sbz#endif 1076231437Sluigi struct ether_vlan_header *eh; 1077231437Sluigi struct tcphdr *th; 1078231437Sluigi uint16_t etype; 1079231879Sluigi int total_len = 0, ehdrlen = 0; 1080231437Sluigi 1081231437Sluigi m = *mpp; 1082231437Sluigi 1083231437Sluigi if (M_WRITABLE(m) == 0) { 1084243857Sglebius m = m_dup(*mpp, M_NOWAIT); 1085231437Sluigi if (!m) 1086231437Sluigi return NULL; 1087231437Sluigi m_freem(*mpp); 1088231437Sluigi *mpp = m; 1089231437Sluigi } 1090231437Sluigi 1091231437Sluigi eh = mtod(m, struct ether_vlan_header *); 1092231437Sluigi if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 1093231437Sluigi etype = ntohs(eh->evl_proto); 1094231437Sluigi ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1095231437Sluigi } else { 1096231437Sluigi etype = ntohs(eh->evl_encap_proto); 1097231437Sluigi ehdrlen = ETHER_HDR_LEN; 1098231437Sluigi } 1099231437Sluigi 1100231437Sluigi switch (etype) { 1101231511Sbz#ifdef INET 1102231437Sluigi case ETHERTYPE_IP: 1103231437Sluigi ip = (struct ip *)(m->m_data + ehdrlen); 1104231437Sluigi if (ip->ip_p != IPPROTO_TCP) 1105231437Sluigi return NULL; 1106231437Sluigi th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 1107231437Sluigi 1108231437Sluigi total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 1109231437Sluigi break; 1110231511Sbz#endif 1111231511Sbz#ifdef INET6 1112231437Sluigi case ETHERTYPE_IPV6: 1113231437Sluigi ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 1114231437Sluigi if (ip6->ip6_nxt != IPPROTO_TCP) 1115231437Sluigi return NULL; 1116231437Sluigi th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 1117231437Sluigi 1118231437Sluigi total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 1119231437Sluigi break; 1120231511Sbz#endif 1121231437Sluigi default: 1122231437Sluigi return NULL; 1123231437Sluigi } 1124231437Sluigi 1125231437Sluigi m = m_pullup(m, total_len); 1126231437Sluigi if (!m) 1127231437Sluigi return NULL; 1128231437Sluigi *mpp = m; 1129231437Sluigi return m; 1130231437Sluigi 1131231437Sluigi} 1132231511Sbz#endif /* INET6 || INET */ 1133231437Sluigi 1134231437Sluigivoid 1135231437Sluigioce_tx_task(void *arg, int npending) 1136231437Sluigi{ 1137231437Sluigi struct oce_wq *wq = arg; 1138231437Sluigi POCE_SOFTC sc = wq->parent; 1139231437Sluigi struct ifnet *ifp = sc->ifp; 1140231437Sluigi int rc = 0; 1141252869Sdelphij 1142231437Sluigi#if __FreeBSD_version >= 800000 1143252869Sdelphij LOCK(&wq->tx_lock); 1144252869Sdelphij rc = oce_multiq_transmit(ifp, NULL, wq); 1145252869Sdelphij if (rc) { 1146252869Sdelphij device_printf(sc->dev, 1147252869Sdelphij "TX[%d] restart failed\n", wq->queue_index); 1148231437Sluigi } 1149252869Sdelphij UNLOCK(&wq->tx_lock); 1150231437Sluigi#else 1151231437Sluigi oce_start(ifp); 1152231437Sluigi#endif 1153231437Sluigi 1154231437Sluigi} 1155231437Sluigi 1156231437Sluigi 1157231437Sluigivoid 1158231437Sluigioce_start(struct ifnet *ifp) 1159231437Sluigi{ 1160231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1161231437Sluigi struct mbuf *m; 1162231437Sluigi int rc = 0; 1163231879Sluigi int def_q = 0; /* Defualt tx queue is 0*/ 1164231437Sluigi 1165231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1166231437Sluigi IFF_DRV_RUNNING) 1167231437Sluigi return; 1168247880Sdelphij 1169247880Sdelphij if (!sc->link_status) 1170247880Sdelphij return; 1171231437Sluigi 1172231437Sluigi do { 1173231437Sluigi IF_DEQUEUE(&sc->ifp->if_snd, m); 1174231437Sluigi if (m == NULL) 1175231437Sluigi break; 1176231879Sluigi 1177231879Sluigi LOCK(&sc->wq[def_q]->tx_lock); 1178231879Sluigi rc = oce_tx(sc, &m, def_q); 1179231879Sluigi UNLOCK(&sc->wq[def_q]->tx_lock); 1180231437Sluigi if (rc) { 1181231437Sluigi if (m != NULL) { 1182231879Sluigi sc->wq[def_q]->tx_stats.tx_stops ++; 1183231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1184231437Sluigi IFQ_DRV_PREPEND(&ifp->if_snd, m); 1185231437Sluigi m = NULL; 1186231437Sluigi } 1187231437Sluigi break; 1188231437Sluigi } 1189231437Sluigi if (m != NULL) 1190231437Sluigi ETHER_BPF_MTAP(ifp, m); 1191231437Sluigi 1192231879Sluigi } while (TRUE); 1193231437Sluigi 1194231437Sluigi return; 1195231437Sluigi} 1196231437Sluigi 1197231437Sluigi 1198231437Sluigi/* Handle the Completion Queue for transmit */ 1199231437Sluigiuint16_t 1200231437Sluigioce_wq_handler(void *arg) 1201231437Sluigi{ 1202231437Sluigi struct oce_wq *wq = (struct oce_wq *)arg; 1203231437Sluigi POCE_SOFTC sc = wq->parent; 1204231437Sluigi struct oce_cq *cq = wq->cq; 1205231437Sluigi struct oce_nic_tx_cqe *cqe; 1206231437Sluigi int num_cqes = 0; 1207231437Sluigi 1208231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1209231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1210231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1211231437Sluigi while (cqe->u0.dw[3]) { 1212231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 1213231437Sluigi 1214231437Sluigi wq->ring->cidx = cqe->u0.s.wqe_index + 1; 1215231437Sluigi if (wq->ring->cidx >= wq->ring->num_items) 1216231437Sluigi wq->ring->cidx -= wq->ring->num_items; 1217231437Sluigi 1218231437Sluigi oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status); 1219231437Sluigi wq->tx_stats.tx_compl++; 1220231437Sluigi cqe->u0.dw[3] = 0; 1221231437Sluigi RING_GET(cq->ring, 1); 1222231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1223231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1224231437Sluigi cqe = 1225231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1226231437Sluigi num_cqes++; 1227231437Sluigi } 1228231437Sluigi 1229231437Sluigi if (num_cqes) 1230231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1231231437Sluigi 1232231437Sluigi return 0; 1233231437Sluigi} 1234231437Sluigi 1235231437Sluigi 1236257187Sdelphij#if __FreeBSD_version >= 1000000 1237257187Sdelphijstatic __inline void 1238257187Sdelphijdrbr_stats_update(struct ifnet *ifp, int len, int mflags) 1239257187Sdelphij{ 1240257187Sdelphij#ifndef NO_SLOW_STATS 1241257187Sdelphij ifp->if_obytes += len; 1242257187Sdelphij if (mflags & M_MCAST) 1243257187Sdelphij ifp->if_omcasts++; 1244257187Sdelphij#endif 1245257187Sdelphij} 1246257187Sdelphij#endif 1247257187Sdelphij 1248231437Sluigistatic int 1249231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 1250231437Sluigi{ 1251231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1252231437Sluigi int status = 0, queue_index = 0; 1253231437Sluigi struct mbuf *next = NULL; 1254231437Sluigi struct buf_ring *br = NULL; 1255231437Sluigi 1256231437Sluigi br = wq->br; 1257231437Sluigi queue_index = wq->queue_index; 1258231437Sluigi 1259231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1260231437Sluigi IFF_DRV_RUNNING) { 1261231437Sluigi if (m != NULL) 1262231437Sluigi status = drbr_enqueue(ifp, br, m); 1263231437Sluigi return status; 1264231437Sluigi } 1265231437Sluigi 1266257187Sdelphij if (m != NULL) { 1267231437Sluigi if ((status = drbr_enqueue(ifp, br, m)) != 0) 1268231437Sluigi return status; 1269246482Srrs } 1270246482Srrs while ((next = drbr_peek(ifp, br)) != NULL) { 1271231437Sluigi if (oce_tx(sc, &next, queue_index)) { 1272246482Srrs if (next == NULL) { 1273246482Srrs drbr_advance(ifp, br); 1274246482Srrs } else { 1275246482Srrs drbr_putback(ifp, br, next); 1276231437Sluigi wq->tx_stats.tx_stops ++; 1277231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1278231437Sluigi status = drbr_enqueue(ifp, br, next); 1279231437Sluigi } 1280231437Sluigi break; 1281231437Sluigi } 1282246482Srrs drbr_advance(ifp, br); 1283241037Sglebius ifp->if_obytes += next->m_pkthdr.len; 1284241037Sglebius if (next->m_flags & M_MCAST) 1285241037Sglebius ifp->if_omcasts++; 1286231437Sluigi ETHER_BPF_MTAP(ifp, next); 1287231437Sluigi } 1288231437Sluigi 1289231437Sluigi return status; 1290231437Sluigi} 1291231437Sluigi 1292231437Sluigi 1293231437Sluigi 1294231437Sluigi 1295231437Sluigi/***************************************************************************** 1296231437Sluigi * Receive routines functions * 1297231437Sluigi *****************************************************************************/ 1298231437Sluigi 1299231437Sluigistatic void 1300231437Sluigioce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe) 1301231437Sluigi{ 1302231437Sluigi uint32_t out; 1303231437Sluigi struct oce_packet_desc *pd; 1304231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1305231437Sluigi int i, len, frag_len; 1306231437Sluigi struct mbuf *m = NULL, *tail = NULL; 1307231437Sluigi uint16_t vtag; 1308231437Sluigi 1309231437Sluigi len = cqe->u0.s.pkt_size; 1310231437Sluigi if (!len) { 1311231437Sluigi /*partial DMA workaround for Lancer*/ 1312231437Sluigi oce_discard_rx_comp(rq, cqe); 1313231437Sluigi goto exit; 1314231437Sluigi } 1315231437Sluigi 1316231879Sluigi /* Get vlan_tag value */ 1317252869Sdelphij if(IS_BE(sc) || IS_SH(sc)) 1318231879Sluigi vtag = BSWAP_16(cqe->u0.s.vlan_tag); 1319231879Sluigi else 1320231879Sluigi vtag = cqe->u0.s.vlan_tag; 1321231879Sluigi 1322231879Sluigi 1323231437Sluigi for (i = 0; i < cqe->u0.s.num_fragments; i++) { 1324231437Sluigi 1325231437Sluigi if (rq->packets_out == rq->packets_in) { 1326231437Sluigi device_printf(sc->dev, 1327231437Sluigi "RQ transmit descriptor missing\n"); 1328231437Sluigi } 1329231437Sluigi out = rq->packets_out + 1; 1330231437Sluigi if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1331231437Sluigi out = 0; 1332231437Sluigi pd = &rq->pckts[rq->packets_out]; 1333231437Sluigi rq->packets_out = out; 1334231437Sluigi 1335231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1336231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1337231437Sluigi rq->pending--; 1338231437Sluigi 1339231437Sluigi frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 1340231437Sluigi pd->mbuf->m_len = frag_len; 1341231437Sluigi 1342231437Sluigi if (tail != NULL) { 1343231437Sluigi /* additional fragments */ 1344231437Sluigi pd->mbuf->m_flags &= ~M_PKTHDR; 1345231437Sluigi tail->m_next = pd->mbuf; 1346231437Sluigi tail = pd->mbuf; 1347231437Sluigi } else { 1348231437Sluigi /* first fragment, fill out much of the packet header */ 1349231437Sluigi pd->mbuf->m_pkthdr.len = len; 1350231437Sluigi pd->mbuf->m_pkthdr.csum_flags = 0; 1351231437Sluigi if (IF_CSUM_ENABLED(sc)) { 1352231437Sluigi if (cqe->u0.s.l4_cksum_pass) { 1353231437Sluigi pd->mbuf->m_pkthdr.csum_flags |= 1354231437Sluigi (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1355231437Sluigi pd->mbuf->m_pkthdr.csum_data = 0xffff; 1356231437Sluigi } 1357231437Sluigi if (cqe->u0.s.ip_cksum_pass) { 1358231879Sluigi if (!cqe->u0.s.ip_ver) { /* IPV4 */ 1359231437Sluigi pd->mbuf->m_pkthdr.csum_flags |= 1360231437Sluigi (CSUM_IP_CHECKED|CSUM_IP_VALID); 1361231437Sluigi } 1362231437Sluigi } 1363231437Sluigi } 1364231437Sluigi m = tail = pd->mbuf; 1365231437Sluigi } 1366231437Sluigi pd->mbuf = NULL; 1367231437Sluigi len -= frag_len; 1368231437Sluigi } 1369231437Sluigi 1370231437Sluigi if (m) { 1371231437Sluigi if (!oce_cqe_portid_valid(sc, cqe)) { 1372231437Sluigi m_freem(m); 1373231437Sluigi goto exit; 1374231437Sluigi } 1375231437Sluigi 1376231437Sluigi m->m_pkthdr.rcvif = sc->ifp; 1377231437Sluigi#if __FreeBSD_version >= 800000 1378252869Sdelphij if (rq->queue_index) 1379252869Sdelphij m->m_pkthdr.flowid = (rq->queue_index - 1); 1380252869Sdelphij else 1381252869Sdelphij m->m_pkthdr.flowid = rq->queue_index; 1382231437Sluigi m->m_flags |= M_FLOWID; 1383231437Sluigi#endif 1384231879Sluigi /* This deternies if vlan tag is Valid */ 1385231437Sluigi if (oce_cqe_vtp_valid(sc, cqe)) { 1386231437Sluigi if (sc->function_mode & FNM_FLEX10_MODE) { 1387231879Sluigi /* FLEX10. If QnQ is not set, neglect VLAN */ 1388231437Sluigi if (cqe->u0.s.qnq) { 1389231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1390231437Sluigi m->m_flags |= M_VLANTAG; 1391231437Sluigi } 1392231879Sluigi } else if (sc->pvid != (vtag & VLAN_VID_MASK)) { 1393231879Sluigi /* In UMC mode generally pvid will be striped by 1394231879Sluigi hw. But in some cases we have seen it comes 1395231879Sluigi with pvid. So if pvid == vlan, neglect vlan. 1396231879Sluigi */ 1397231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1398231437Sluigi m->m_flags |= M_VLANTAG; 1399231437Sluigi } 1400231437Sluigi } 1401231437Sluigi 1402231437Sluigi sc->ifp->if_ipackets++; 1403231511Sbz#if defined(INET6) || defined(INET) 1404231437Sluigi /* Try to queue to LRO */ 1405231437Sluigi if (IF_LRO_ENABLED(sc) && 1406231437Sluigi (cqe->u0.s.ip_cksum_pass) && 1407231437Sluigi (cqe->u0.s.l4_cksum_pass) && 1408231437Sluigi (!cqe->u0.s.ip_ver) && 1409231437Sluigi (rq->lro.lro_cnt != 0)) { 1410231437Sluigi 1411231437Sluigi if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 1412231437Sluigi rq->lro_pkts_queued ++; 1413231437Sluigi goto post_done; 1414231437Sluigi } 1415231437Sluigi /* If LRO posting fails then try to post to STACK */ 1416231437Sluigi } 1417231511Sbz#endif 1418231437Sluigi 1419231437Sluigi (*sc->ifp->if_input) (sc->ifp, m); 1420231511Sbz#if defined(INET6) || defined(INET) 1421231437Sluigipost_done: 1422231511Sbz#endif 1423231437Sluigi /* Update rx stats per queue */ 1424231437Sluigi rq->rx_stats.rx_pkts++; 1425231437Sluigi rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 1426231437Sluigi rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 1427231437Sluigi if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 1428231437Sluigi rq->rx_stats.rx_mcast_pkts++; 1429231437Sluigi if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 1430231437Sluigi rq->rx_stats.rx_ucast_pkts++; 1431231437Sluigi } 1432231437Sluigiexit: 1433231437Sluigi return; 1434231437Sluigi} 1435231437Sluigi 1436231437Sluigi 1437231437Sluigistatic void 1438231437Sluigioce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1439231437Sluigi{ 1440231437Sluigi uint32_t out, i = 0; 1441231437Sluigi struct oce_packet_desc *pd; 1442231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1443231437Sluigi int num_frags = cqe->u0.s.num_fragments; 1444231437Sluigi 1445231437Sluigi for (i = 0; i < num_frags; i++) { 1446231437Sluigi if (rq->packets_out == rq->packets_in) { 1447231437Sluigi device_printf(sc->dev, 1448231437Sluigi "RQ transmit descriptor missing\n"); 1449231437Sluigi } 1450231437Sluigi out = rq->packets_out + 1; 1451231437Sluigi if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1452231437Sluigi out = 0; 1453231437Sluigi pd = &rq->pckts[rq->packets_out]; 1454231437Sluigi rq->packets_out = out; 1455231437Sluigi 1456231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1457231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1458231437Sluigi rq->pending--; 1459231437Sluigi m_freem(pd->mbuf); 1460231437Sluigi } 1461231437Sluigi 1462231437Sluigi} 1463231437Sluigi 1464231437Sluigi 1465231437Sluigistatic int 1466231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1467231437Sluigi{ 1468231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1469231437Sluigi int vtp = 0; 1470231437Sluigi 1471231437Sluigi if (sc->be3_native) { 1472231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1473231437Sluigi vtp = cqe_v1->u0.s.vlan_tag_present; 1474231879Sluigi } else 1475231437Sluigi vtp = cqe->u0.s.vlan_tag_present; 1476231437Sluigi 1477231437Sluigi return vtp; 1478231437Sluigi 1479231437Sluigi} 1480231437Sluigi 1481231437Sluigi 1482231437Sluigistatic int 1483231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1484231437Sluigi{ 1485231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1486231437Sluigi int port_id = 0; 1487231437Sluigi 1488252869Sdelphij if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) { 1489231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1490231437Sluigi port_id = cqe_v1->u0.s.port; 1491231437Sluigi if (sc->port_id != port_id) 1492231437Sluigi return 0; 1493231437Sluigi } else 1494231437Sluigi ;/* For BE3 legacy and Lancer this is dummy */ 1495231437Sluigi 1496231437Sluigi return 1; 1497231437Sluigi 1498231437Sluigi} 1499231437Sluigi 1500231511Sbz#if defined(INET6) || defined(INET) 1501231437Sluigistatic void 1502231437Sluigioce_rx_flush_lro(struct oce_rq *rq) 1503231437Sluigi{ 1504231437Sluigi struct lro_ctrl *lro = &rq->lro; 1505231437Sluigi struct lro_entry *queued; 1506231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1507231437Sluigi 1508231437Sluigi if (!IF_LRO_ENABLED(sc)) 1509231437Sluigi return; 1510231437Sluigi 1511231437Sluigi while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { 1512231437Sluigi SLIST_REMOVE_HEAD(&lro->lro_active, next); 1513231437Sluigi tcp_lro_flush(lro, queued); 1514231437Sluigi } 1515231437Sluigi rq->lro_pkts_queued = 0; 1516231437Sluigi 1517231437Sluigi return; 1518231437Sluigi} 1519231437Sluigi 1520231437Sluigi 1521231437Sluigistatic int 1522231437Sluigioce_init_lro(POCE_SOFTC sc) 1523231437Sluigi{ 1524231437Sluigi struct lro_ctrl *lro = NULL; 1525231437Sluigi int i = 0, rc = 0; 1526231437Sluigi 1527231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1528231437Sluigi lro = &sc->rq[i]->lro; 1529231437Sluigi rc = tcp_lro_init(lro); 1530231437Sluigi if (rc != 0) { 1531231437Sluigi device_printf(sc->dev, "LRO init failed\n"); 1532231437Sluigi return rc; 1533231437Sluigi } 1534231437Sluigi lro->ifp = sc->ifp; 1535231437Sluigi } 1536231437Sluigi 1537231437Sluigi return rc; 1538231437Sluigi} 1539231437Sluigi 1540231879Sluigi 1541231437Sluigivoid 1542231437Sluigioce_free_lro(POCE_SOFTC sc) 1543231437Sluigi{ 1544231437Sluigi struct lro_ctrl *lro = NULL; 1545231437Sluigi int i = 0; 1546231437Sluigi 1547231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1548231437Sluigi lro = &sc->rq[i]->lro; 1549231437Sluigi if (lro) 1550231437Sluigi tcp_lro_free(lro); 1551231437Sluigi } 1552231437Sluigi} 1553247880Sdelphij#endif 1554231437Sluigi 1555231437Sluigiint 1556231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count) 1557231437Sluigi{ 1558231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1559231437Sluigi int i, in, rc; 1560231437Sluigi struct oce_packet_desc *pd; 1561231437Sluigi bus_dma_segment_t segs[6]; 1562231437Sluigi int nsegs, added = 0; 1563231437Sluigi struct oce_nic_rqe *rqe; 1564231437Sluigi pd_rxulp_db_t rxdb_reg; 1565231437Sluigi 1566247880Sdelphij bzero(&rxdb_reg, sizeof(pd_rxulp_db_t)); 1567231437Sluigi for (i = 0; i < count; i++) { 1568231437Sluigi in = rq->packets_in + 1; 1569231437Sluigi if (in == OCE_RQ_PACKET_ARRAY_SIZE) 1570231437Sluigi in = 0; 1571231437Sluigi if (in == rq->packets_out) 1572231437Sluigi break; /* no more room */ 1573231437Sluigi 1574231437Sluigi pd = &rq->pckts[rq->packets_in]; 1575243857Sglebius pd->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1576231437Sluigi if (pd->mbuf == NULL) 1577231437Sluigi break; 1578231437Sluigi 1579231437Sluigi pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES; 1580231437Sluigi rc = bus_dmamap_load_mbuf_sg(rq->tag, 1581231437Sluigi pd->map, 1582231437Sluigi pd->mbuf, 1583231437Sluigi segs, &nsegs, BUS_DMA_NOWAIT); 1584231437Sluigi if (rc) { 1585231437Sluigi m_free(pd->mbuf); 1586231437Sluigi break; 1587231437Sluigi } 1588231437Sluigi 1589231437Sluigi if (nsegs != 1) { 1590231437Sluigi i--; 1591231437Sluigi continue; 1592231437Sluigi } 1593231437Sluigi 1594231437Sluigi rq->packets_in = in; 1595231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 1596231437Sluigi 1597231437Sluigi rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 1598231437Sluigi rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 1599231437Sluigi rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 1600231437Sluigi DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 1601231437Sluigi RING_PUT(rq->ring, 1); 1602231437Sluigi added++; 1603231437Sluigi rq->pending++; 1604231437Sluigi } 1605231437Sluigi if (added != 0) { 1606231437Sluigi for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) { 1607231437Sluigi rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS; 1608231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1609231437Sluigi OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1610231437Sluigi added -= OCE_MAX_RQ_POSTS; 1611231437Sluigi } 1612231437Sluigi if (added > 0) { 1613231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1614231437Sluigi rxdb_reg.bits.num_posted = added; 1615231437Sluigi OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1616231437Sluigi } 1617231437Sluigi } 1618231437Sluigi 1619231437Sluigi return 0; 1620231437Sluigi} 1621231437Sluigi 1622231437Sluigi 1623231437Sluigi/* Handle the Completion Queue for receive */ 1624231437Sluigiuint16_t 1625231437Sluigioce_rq_handler(void *arg) 1626231437Sluigi{ 1627231437Sluigi struct oce_rq *rq = (struct oce_rq *)arg; 1628231437Sluigi struct oce_cq *cq = rq->cq; 1629231437Sluigi POCE_SOFTC sc = rq->parent; 1630231437Sluigi struct oce_nic_rx_cqe *cqe; 1631231437Sluigi int num_cqes = 0, rq_buffers_used = 0; 1632231437Sluigi 1633231437Sluigi 1634231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1635231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1636231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1637231437Sluigi while (cqe->u0.dw[2]) { 1638231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 1639231437Sluigi 1640231437Sluigi RING_GET(rq->ring, 1); 1641231437Sluigi if (cqe->u0.s.error == 0) { 1642231437Sluigi oce_rx(rq, cqe->u0.s.frag_index, cqe); 1643231437Sluigi } else { 1644231437Sluigi rq->rx_stats.rxcp_err++; 1645231437Sluigi sc->ifp->if_ierrors++; 1646247880Sdelphij /* Post L3/L4 errors to stack.*/ 1647247880Sdelphij oce_rx(rq, cqe->u0.s.frag_index, cqe); 1648231437Sluigi } 1649231437Sluigi rq->rx_stats.rx_compl++; 1650231437Sluigi cqe->u0.dw[2] = 0; 1651231437Sluigi 1652231511Sbz#if defined(INET6) || defined(INET) 1653231437Sluigi if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 1654231437Sluigi oce_rx_flush_lro(rq); 1655231437Sluigi } 1656231511Sbz#endif 1657231437Sluigi 1658231437Sluigi RING_GET(cq->ring, 1); 1659231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1660231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1661231437Sluigi cqe = 1662231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1663231437Sluigi num_cqes++; 1664231437Sluigi if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 1665231437Sluigi break; 1666231437Sluigi } 1667231879Sluigi 1668231511Sbz#if defined(INET6) || defined(INET) 1669231437Sluigi if (IF_LRO_ENABLED(sc)) 1670231437Sluigi oce_rx_flush_lro(rq); 1671231511Sbz#endif 1672231437Sluigi 1673231437Sluigi if (num_cqes) { 1674231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1675231437Sluigi rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending; 1676231437Sluigi if (rq_buffers_used > 1) 1677231437Sluigi oce_alloc_rx_bufs(rq, (rq_buffers_used - 1)); 1678231437Sluigi } 1679231437Sluigi 1680231437Sluigi return 0; 1681231437Sluigi 1682231437Sluigi} 1683231437Sluigi 1684231437Sluigi 1685231437Sluigi 1686231437Sluigi 1687231437Sluigi/***************************************************************************** 1688231437Sluigi * Helper function prototypes in this file * 1689231437Sluigi *****************************************************************************/ 1690231437Sluigi 1691231437Sluigistatic int 1692231437Sluigioce_attach_ifp(POCE_SOFTC sc) 1693231437Sluigi{ 1694231437Sluigi 1695231437Sluigi sc->ifp = if_alloc(IFT_ETHER); 1696231437Sluigi if (!sc->ifp) 1697231437Sluigi return ENOMEM; 1698231437Sluigi 1699231437Sluigi ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 1700231437Sluigi ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1701231437Sluigi ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 1702231437Sluigi 1703231437Sluigi sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 1704231437Sluigi sc->ifp->if_ioctl = oce_ioctl; 1705231437Sluigi sc->ifp->if_start = oce_start; 1706231437Sluigi sc->ifp->if_init = oce_init; 1707231437Sluigi sc->ifp->if_mtu = ETHERMTU; 1708231437Sluigi sc->ifp->if_softc = sc; 1709231437Sluigi#if __FreeBSD_version >= 800000 1710231437Sluigi sc->ifp->if_transmit = oce_multiq_start; 1711231437Sluigi sc->ifp->if_qflush = oce_multiq_flush; 1712231437Sluigi#endif 1713231437Sluigi 1714231437Sluigi if_initname(sc->ifp, 1715231437Sluigi device_get_name(sc->dev), device_get_unit(sc->dev)); 1716231437Sluigi 1717231437Sluigi sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 1718231437Sluigi IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 1719231437Sluigi IFQ_SET_READY(&sc->ifp->if_snd); 1720231437Sluigi 1721231437Sluigi sc->ifp->if_hwassist = OCE_IF_HWASSIST; 1722231437Sluigi sc->ifp->if_hwassist |= CSUM_TSO; 1723231437Sluigi sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 1724231437Sluigi 1725231437Sluigi sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 1726231437Sluigi sc->ifp->if_capabilities |= IFCAP_HWCSUM; 1727231437Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 1728231879Sluigi 1729231511Sbz#if defined(INET6) || defined(INET) 1730231511Sbz sc->ifp->if_capabilities |= IFCAP_TSO; 1731231437Sluigi sc->ifp->if_capabilities |= IFCAP_LRO; 1732231879Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 1733231511Sbz#endif 1734231437Sluigi 1735231437Sluigi sc->ifp->if_capenable = sc->ifp->if_capabilities; 1736241691Sjhb if_initbaudrate(sc->ifp, IF_Gbps(10)); 1737231437Sluigi 1738257187Sdelphij#if __FreeBSD_version >= 1000000 1739257187Sdelphij sc->ifp->if_hw_tsomax = OCE_MAX_TSO_SIZE; 1740257187Sdelphij#endif 1741257187Sdelphij 1742231437Sluigi ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 1743231437Sluigi 1744231437Sluigi return 0; 1745231437Sluigi} 1746231437Sluigi 1747231437Sluigi 1748231437Sluigistatic void 1749231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1750231437Sluigi{ 1751231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1752231437Sluigi 1753231437Sluigi if (ifp->if_softc != arg) 1754231437Sluigi return; 1755231437Sluigi if ((vtag == 0) || (vtag > 4095)) 1756231437Sluigi return; 1757231437Sluigi 1758231437Sluigi sc->vlan_tag[vtag] = 1; 1759231437Sluigi sc->vlans_added++; 1760257187Sdelphij if (sc->vlans_added <= (sc->max_vlans + 1)) 1761257187Sdelphij oce_vid_config(sc); 1762231437Sluigi} 1763231437Sluigi 1764231437Sluigi 1765231437Sluigistatic void 1766231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1767231437Sluigi{ 1768231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1769231437Sluigi 1770231437Sluigi if (ifp->if_softc != arg) 1771231437Sluigi return; 1772231437Sluigi if ((vtag == 0) || (vtag > 4095)) 1773231437Sluigi return; 1774231437Sluigi 1775231437Sluigi sc->vlan_tag[vtag] = 0; 1776231437Sluigi sc->vlans_added--; 1777231437Sluigi oce_vid_config(sc); 1778231437Sluigi} 1779231437Sluigi 1780231437Sluigi 1781231437Sluigi/* 1782231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures 1783231437Sluigi * more, place the card in vlan promiscuous mode. 1784231437Sluigi */ 1785231437Sluigistatic int 1786231437Sluigioce_vid_config(POCE_SOFTC sc) 1787231437Sluigi{ 1788231437Sluigi struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 1789231437Sluigi uint16_t ntags = 0, i; 1790231437Sluigi int status = 0; 1791231437Sluigi 1792231437Sluigi if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 1793231437Sluigi (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 1794231437Sluigi for (i = 0; i < MAX_VLANS; i++) { 1795231437Sluigi if (sc->vlan_tag[i]) { 1796231437Sluigi vtags[ntags].vtag = i; 1797231437Sluigi ntags++; 1798231437Sluigi } 1799231437Sluigi } 1800231437Sluigi if (ntags) 1801231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1802231437Sluigi vtags, ntags, 1, 0); 1803231437Sluigi } else 1804231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1805231437Sluigi NULL, 0, 1, 1); 1806231437Sluigi return status; 1807231437Sluigi} 1808231437Sluigi 1809231437Sluigi 1810231437Sluigistatic void 1811231437Sluigioce_mac_addr_set(POCE_SOFTC sc) 1812231437Sluigi{ 1813231437Sluigi uint32_t old_pmac_id = sc->pmac_id; 1814231437Sluigi int status = 0; 1815231437Sluigi 1816231437Sluigi 1817231437Sluigi status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1818231437Sluigi sc->macaddr.size_of_struct); 1819231437Sluigi if (!status) 1820231437Sluigi return; 1821231437Sluigi 1822231437Sluigi status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 1823231437Sluigi sc->if_id, &sc->pmac_id); 1824231437Sluigi if (!status) { 1825231437Sluigi status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 1826231437Sluigi bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1827231437Sluigi sc->macaddr.size_of_struct); 1828231437Sluigi } 1829231437Sluigi if (status) 1830231437Sluigi device_printf(sc->dev, "Failed update macaddress\n"); 1831231437Sluigi 1832231437Sluigi} 1833231437Sluigi 1834231437Sluigi 1835231437Sluigistatic int 1836231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data) 1837231437Sluigi{ 1838231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1839231437Sluigi struct ifreq *ifr = (struct ifreq *)data; 1840231437Sluigi int rc = ENXIO; 1841231437Sluigi char cookie[32] = {0}; 1842231437Sluigi void *priv_data = (void *)ifr->ifr_data; 1843231437Sluigi void *ioctl_ptr; 1844231437Sluigi uint32_t req_size; 1845231437Sluigi struct mbx_hdr req; 1846231437Sluigi OCE_DMA_MEM dma_mem; 1847247880Sdelphij struct mbx_common_get_cntl_attr *fw_cmd; 1848231437Sluigi 1849231437Sluigi if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 1850231437Sluigi return EFAULT; 1851247880Sdelphij 1852231437Sluigi if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 1853231437Sluigi return EINVAL; 1854247880Sdelphij 1855231437Sluigi ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 1856231437Sluigi if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 1857231437Sluigi return EFAULT; 1858247880Sdelphij 1859231437Sluigi req_size = le32toh(req.u0.req.request_length); 1860231437Sluigi if (req_size > 65536) 1861231437Sluigi return EINVAL; 1862231437Sluigi 1863231437Sluigi req_size += sizeof(struct mbx_hdr); 1864231437Sluigi rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 1865231437Sluigi if (rc) 1866231437Sluigi return ENOMEM; 1867231437Sluigi 1868231437Sluigi if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 1869231437Sluigi rc = EFAULT; 1870231437Sluigi goto dma_free; 1871231437Sluigi } 1872231437Sluigi 1873231437Sluigi rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 1874231437Sluigi if (rc) { 1875231437Sluigi rc = EIO; 1876231437Sluigi goto dma_free; 1877231437Sluigi } 1878231437Sluigi 1879231437Sluigi if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 1880231437Sluigi rc = EFAULT; 1881231437Sluigi 1882247880Sdelphij /* 1883247880Sdelphij firmware is filling all the attributes for this ioctl except 1884247880Sdelphij the driver version..so fill it 1885247880Sdelphij */ 1886247880Sdelphij if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) { 1887247880Sdelphij fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr; 1888247880Sdelphij strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str, 1889247880Sdelphij COMPONENT_REVISION, strlen(COMPONENT_REVISION)); 1890247880Sdelphij } 1891247880Sdelphij 1892231437Sluigidma_free: 1893231437Sluigi oce_dma_free(sc, &dma_mem); 1894231437Sluigi return rc; 1895231437Sluigi 1896231437Sluigi} 1897231437Sluigi 1898247880Sdelphijstatic void 1899247880Sdelphijoce_eqd_set_periodic(POCE_SOFTC sc) 1900247880Sdelphij{ 1901247880Sdelphij struct oce_set_eqd set_eqd[OCE_MAX_EQ]; 1902247880Sdelphij struct oce_aic_obj *aic; 1903247880Sdelphij struct oce_eq *eqo; 1904247880Sdelphij uint64_t now = 0, delta; 1905247880Sdelphij int eqd, i, num = 0; 1906247880Sdelphij uint32_t ips = 0; 1907247880Sdelphij int tps; 1908231437Sluigi 1909247880Sdelphij for (i = 0 ; i < sc->neqs; i++) { 1910247880Sdelphij eqo = sc->eq[i]; 1911247880Sdelphij aic = &sc->aic_obj[i]; 1912247880Sdelphij /* When setting the static eq delay from the user space */ 1913247880Sdelphij if (!aic->enable) { 1914247880Sdelphij eqd = aic->et_eqd; 1915247880Sdelphij goto modify_eqd; 1916247880Sdelphij } 1917247880Sdelphij 1918247880Sdelphij now = ticks; 1919247880Sdelphij 1920247880Sdelphij /* Over flow check */ 1921247880Sdelphij if ((now < aic->ticks) || (eqo->intr < aic->intr_prev)) 1922247880Sdelphij goto done; 1923247880Sdelphij 1924247880Sdelphij delta = now - aic->ticks; 1925247880Sdelphij tps = delta/hz; 1926247880Sdelphij 1927247880Sdelphij /* Interrupt rate based on elapsed ticks */ 1928247880Sdelphij if(tps) 1929247880Sdelphij ips = (uint32_t)(eqo->intr - aic->intr_prev) / tps; 1930247880Sdelphij 1931247880Sdelphij if (ips > INTR_RATE_HWM) 1932247880Sdelphij eqd = aic->cur_eqd + 20; 1933247880Sdelphij else if (ips < INTR_RATE_LWM) 1934247880Sdelphij eqd = aic->cur_eqd / 2; 1935247880Sdelphij else 1936247880Sdelphij goto done; 1937247880Sdelphij 1938247880Sdelphij if (eqd < 10) 1939247880Sdelphij eqd = 0; 1940247880Sdelphij 1941247880Sdelphij /* Make sure that the eq delay is in the known range */ 1942247880Sdelphij eqd = min(eqd, aic->max_eqd); 1943247880Sdelphij eqd = max(eqd, aic->min_eqd); 1944247880Sdelphij 1945247880Sdelphijmodify_eqd: 1946247880Sdelphij if (eqd != aic->cur_eqd) { 1947247880Sdelphij set_eqd[num].delay_multiplier = (eqd * 65)/100; 1948247880Sdelphij set_eqd[num].eq_id = eqo->eq_id; 1949247880Sdelphij aic->cur_eqd = eqd; 1950247880Sdelphij num++; 1951247880Sdelphij } 1952247880Sdelphijdone: 1953247880Sdelphij aic->intr_prev = eqo->intr; 1954247880Sdelphij aic->ticks = now; 1955247880Sdelphij } 1956247880Sdelphij 1957247880Sdelphij /* Is there atleast one eq that needs to be modified? */ 1958247880Sdelphij if(num) 1959247880Sdelphij oce_mbox_eqd_modify_periodic(sc, set_eqd, num); 1960247880Sdelphij} 1961247880Sdelphij 1962257187Sdelphijstatic void oce_detect_hw_error(POCE_SOFTC sc) 1963257187Sdelphij{ 1964257187Sdelphij 1965257187Sdelphij uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0; 1966257187Sdelphij uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; 1967257187Sdelphij uint32_t i; 1968257187Sdelphij 1969257187Sdelphij if (sc->hw_error) 1970257187Sdelphij return; 1971257187Sdelphij 1972257187Sdelphij if (IS_XE201(sc)) { 1973257187Sdelphij sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET); 1974257187Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1975257187Sdelphij sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET); 1976257187Sdelphij sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET); 1977257187Sdelphij } 1978257187Sdelphij } else { 1979257187Sdelphij ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW); 1980257187Sdelphij ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH); 1981257187Sdelphij ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK); 1982257187Sdelphij ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK); 1983257187Sdelphij 1984257187Sdelphij ue_low = (ue_low & ~ue_low_mask); 1985257187Sdelphij ue_high = (ue_high & ~ue_high_mask); 1986257187Sdelphij } 1987257187Sdelphij 1988257187Sdelphij /* On certain platforms BE hardware can indicate spurious UEs. 1989257187Sdelphij * Allow the h/w to stop working completely in case of a real UE. 1990257187Sdelphij * Hence not setting the hw_error for UE detection. 1991257187Sdelphij */ 1992257187Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1993257187Sdelphij sc->hw_error = TRUE; 1994257187Sdelphij device_printf(sc->dev, "Error detected in the card\n"); 1995257187Sdelphij } 1996257187Sdelphij 1997257187Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1998257187Sdelphij device_printf(sc->dev, 1999257187Sdelphij "ERR: sliport status 0x%x\n", sliport_status); 2000257187Sdelphij device_printf(sc->dev, 2001257187Sdelphij "ERR: sliport error1 0x%x\n", sliport_err1); 2002257187Sdelphij device_printf(sc->dev, 2003257187Sdelphij "ERR: sliport error2 0x%x\n", sliport_err2); 2004257187Sdelphij } 2005257187Sdelphij 2006257187Sdelphij if (ue_low) { 2007257187Sdelphij for (i = 0; ue_low; ue_low >>= 1, i++) { 2008257187Sdelphij if (ue_low & 1) 2009257187Sdelphij device_printf(sc->dev, "UE: %s bit set\n", 2010257187Sdelphij ue_status_low_desc[i]); 2011257187Sdelphij } 2012257187Sdelphij } 2013257187Sdelphij 2014257187Sdelphij if (ue_high) { 2015257187Sdelphij for (i = 0; ue_high; ue_high >>= 1, i++) { 2016257187Sdelphij if (ue_high & 1) 2017257187Sdelphij device_printf(sc->dev, "UE: %s bit set\n", 2018257187Sdelphij ue_status_hi_desc[i]); 2019257187Sdelphij } 2020257187Sdelphij } 2021257187Sdelphij 2022257187Sdelphij} 2023257187Sdelphij 2024257187Sdelphij 2025231437Sluigistatic void 2026231437Sluigioce_local_timer(void *arg) 2027231437Sluigi{ 2028231437Sluigi POCE_SOFTC sc = arg; 2029231437Sluigi int i = 0; 2030231437Sluigi 2031257187Sdelphij oce_detect_hw_error(sc); 2032231437Sluigi oce_refresh_nic_stats(sc); 2033231437Sluigi oce_refresh_queue_stats(sc); 2034231437Sluigi oce_mac_addr_set(sc); 2035231437Sluigi 2036231437Sluigi /* TX Watch Dog*/ 2037231437Sluigi for (i = 0; i < sc->nwqs; i++) 2038231437Sluigi oce_tx_restart(sc, sc->wq[i]); 2039231437Sluigi 2040247880Sdelphij /* calculate and set the eq delay for optimal interrupt rate */ 2041252869Sdelphij if (IS_BE(sc) || IS_SH(sc)) 2042247880Sdelphij oce_eqd_set_periodic(sc); 2043247880Sdelphij 2044231437Sluigi callout_reset(&sc->timer, hz, oce_local_timer, sc); 2045231437Sluigi} 2046231437Sluigi 2047231437Sluigi 2048246799Sjpaetzel/* NOTE : This should only be called holding 2049246799Sjpaetzel * DEVICE_LOCK. 2050257187Sdelphij */ 2051231437Sluigistatic void 2052231437Sluigioce_if_deactivate(POCE_SOFTC sc) 2053231437Sluigi{ 2054231437Sluigi int i, mtime = 0; 2055231437Sluigi int wait_req = 0; 2056231437Sluigi struct oce_rq *rq; 2057231437Sluigi struct oce_wq *wq; 2058231437Sluigi struct oce_eq *eq; 2059231437Sluigi 2060231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2061231437Sluigi 2062231437Sluigi /*Wait for max of 400ms for TX completions to be done */ 2063231437Sluigi while (mtime < 400) { 2064231437Sluigi wait_req = 0; 2065231437Sluigi for_all_wq_queues(sc, wq, i) { 2066231437Sluigi if (wq->ring->num_used) { 2067231437Sluigi wait_req = 1; 2068231437Sluigi DELAY(1); 2069231437Sluigi break; 2070231437Sluigi } 2071231437Sluigi } 2072231437Sluigi mtime += 1; 2073231437Sluigi if (!wait_req) 2074231437Sluigi break; 2075231437Sluigi } 2076231437Sluigi 2077231437Sluigi /* Stop intrs and finish any bottom halves pending */ 2078231437Sluigi oce_hw_intr_disable(sc); 2079231437Sluigi 2080247880Sdelphij /* Since taskqueue_drain takes a Gaint Lock, We should not acquire 2081247880Sdelphij any other lock. So unlock device lock and require after 2082247880Sdelphij completing taskqueue_drain. 2083247880Sdelphij */ 2084247880Sdelphij UNLOCK(&sc->dev_lock); 2085231437Sluigi for (i = 0; i < sc->intr_count; i++) { 2086231437Sluigi if (sc->intrs[i].tq != NULL) { 2087231437Sluigi taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 2088231437Sluigi } 2089231437Sluigi } 2090247880Sdelphij LOCK(&sc->dev_lock); 2091231437Sluigi 2092231437Sluigi /* Delete RX queue in card with flush param */ 2093231437Sluigi oce_stop_rx(sc); 2094231437Sluigi 2095231437Sluigi /* Invalidate any pending cq and eq entries*/ 2096231437Sluigi for_all_evnt_queues(sc, eq, i) 2097231437Sluigi oce_drain_eq(eq); 2098231437Sluigi for_all_rq_queues(sc, rq, i) 2099231437Sluigi oce_drain_rq_cq(rq); 2100231437Sluigi for_all_wq_queues(sc, wq, i) 2101231437Sluigi oce_drain_wq_cq(wq); 2102231437Sluigi 2103231437Sluigi /* But still we need to get MCC aync events. 2104231437Sluigi So enable intrs and also arm first EQ 2105247880Sdelphij */ 2106231437Sluigi oce_hw_intr_enable(sc); 2107231437Sluigi oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 2108231437Sluigi 2109231437Sluigi DELAY(10); 2110231437Sluigi} 2111231437Sluigi 2112231437Sluigi 2113231437Sluigistatic void 2114231437Sluigioce_if_activate(POCE_SOFTC sc) 2115231437Sluigi{ 2116231437Sluigi struct oce_eq *eq; 2117231437Sluigi struct oce_rq *rq; 2118231437Sluigi struct oce_wq *wq; 2119231437Sluigi int i, rc = 0; 2120231437Sluigi 2121231437Sluigi sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 2122231437Sluigi 2123231437Sluigi oce_hw_intr_disable(sc); 2124231437Sluigi 2125231437Sluigi oce_start_rx(sc); 2126231437Sluigi 2127231437Sluigi for_all_rq_queues(sc, rq, i) { 2128231437Sluigi rc = oce_start_rq(rq); 2129231437Sluigi if (rc) 2130231437Sluigi device_printf(sc->dev, "Unable to start RX\n"); 2131231437Sluigi } 2132231437Sluigi 2133231437Sluigi for_all_wq_queues(sc, wq, i) { 2134231437Sluigi rc = oce_start_wq(wq); 2135231437Sluigi if (rc) 2136231437Sluigi device_printf(sc->dev, "Unable to start TX\n"); 2137231437Sluigi } 2138231437Sluigi 2139231437Sluigi 2140231437Sluigi for_all_evnt_queues(sc, eq, i) 2141231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 2142231437Sluigi 2143231437Sluigi oce_hw_intr_enable(sc); 2144231437Sluigi 2145231437Sluigi} 2146231437Sluigi 2147231879Sluigistatic void 2148231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe) 2149231879Sluigi{ 2150231879Sluigi /* Update Link status */ 2151231879Sluigi if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 2152231879Sluigi ASYNC_EVENT_LINK_UP) { 2153231879Sluigi sc->link_status = ASYNC_EVENT_LINK_UP; 2154231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_UP); 2155231879Sluigi } else { 2156231879Sluigi sc->link_status = ASYNC_EVENT_LINK_DOWN; 2157231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_DOWN); 2158231879Sluigi } 2159231879Sluigi} 2160231879Sluigi 2161231879Sluigi 2162231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */ 2163231437Sluigiuint16_t 2164231437Sluigioce_mq_handler(void *arg) 2165231437Sluigi{ 2166231437Sluigi struct oce_mq *mq = (struct oce_mq *)arg; 2167231437Sluigi POCE_SOFTC sc = mq->parent; 2168231437Sluigi struct oce_cq *cq = mq->cq; 2169231879Sluigi int num_cqes = 0, evt_type = 0, optype = 0; 2170231437Sluigi struct oce_mq_cqe *cqe; 2171231437Sluigi struct oce_async_cqe_link_state *acqe; 2172231879Sluigi struct oce_async_event_grp5_pvid_state *gcqe; 2173247880Sdelphij struct oce_async_event_qnq *dbgcqe; 2174231437Sluigi 2175231879Sluigi 2176231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2177231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2178231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 2179231879Sluigi 2180231437Sluigi while (cqe->u0.dw[3]) { 2181231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 2182231437Sluigi if (cqe->u0.s.async_event) { 2183231879Sluigi evt_type = cqe->u0.s.event_type; 2184231879Sluigi optype = cqe->u0.s.async_type; 2185231879Sluigi if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) { 2186231879Sluigi /* Link status evt */ 2187231879Sluigi acqe = (struct oce_async_cqe_link_state *)cqe; 2188231879Sluigi process_link_state(sc, acqe); 2189231879Sluigi } else if ((evt_type == ASYNC_EVENT_GRP5) && 2190231879Sluigi (optype == ASYNC_EVENT_PVID_STATE)) { 2191231879Sluigi /* GRP5 PVID */ 2192231879Sluigi gcqe = 2193231879Sluigi (struct oce_async_event_grp5_pvid_state *)cqe; 2194231879Sluigi if (gcqe->enabled) 2195231879Sluigi sc->pvid = gcqe->tag & VLAN_VID_MASK; 2196231879Sluigi else 2197231879Sluigi sc->pvid = 0; 2198231879Sluigi 2199231437Sluigi } 2200247880Sdelphij else if(evt_type == ASYNC_EVENT_CODE_DEBUG && 2201247880Sdelphij optype == ASYNC_EVENT_DEBUG_QNQ) { 2202247880Sdelphij dbgcqe = 2203247880Sdelphij (struct oce_async_event_qnq *)cqe; 2204247880Sdelphij if(dbgcqe->valid) 2205247880Sdelphij sc->qnqid = dbgcqe->vlan_tag; 2206247880Sdelphij sc->qnq_debug_event = TRUE; 2207247880Sdelphij } 2208231437Sluigi } 2209231437Sluigi cqe->u0.dw[3] = 0; 2210231437Sluigi RING_GET(cq->ring, 1); 2211231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2212231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2213231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 2214231437Sluigi num_cqes++; 2215231437Sluigi } 2216231437Sluigi 2217231437Sluigi if (num_cqes) 2218231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 2219231437Sluigi 2220231437Sluigi return 0; 2221231437Sluigi} 2222231437Sluigi 2223231437Sluigi 2224231437Sluigistatic void 2225231437Sluigisetup_max_queues_want(POCE_SOFTC sc) 2226231437Sluigi{ 2227231437Sluigi /* Check if it is FLEX machine. Is so dont use RSS */ 2228231437Sluigi if ((sc->function_mode & FNM_FLEX10_MODE) || 2229231879Sluigi (sc->function_mode & FNM_UMC_MODE) || 2230231879Sluigi (sc->function_mode & FNM_VNIC_MODE) || 2231252869Sdelphij (!is_rss_enabled(sc)) || 2232231879Sluigi (sc->flags & OCE_FLAGS_BE2)) { 2233231437Sluigi sc->nrqs = 1; 2234231437Sluigi sc->nwqs = 1; 2235257187Sdelphij } else { 2236257187Sdelphij sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 2237257187Sdelphij sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs); 2238231437Sluigi } 2239231437Sluigi} 2240231437Sluigi 2241231437Sluigi 2242231437Sluigistatic void 2243231437Sluigiupdate_queues_got(POCE_SOFTC sc) 2244231437Sluigi{ 2245252869Sdelphij if (is_rss_enabled(sc)) { 2246231437Sluigi sc->nrqs = sc->intr_count + 1; 2247231437Sluigi sc->nwqs = sc->intr_count; 2248231437Sluigi } else { 2249231437Sluigi sc->nrqs = 1; 2250231437Sluigi sc->nwqs = 1; 2251231437Sluigi } 2252231437Sluigi} 2253231437Sluigi 2254247880Sdelphijstatic int 2255247880Sdelphijoce_check_ipv6_ext_hdr(struct mbuf *m) 2256247880Sdelphij{ 2257247880Sdelphij struct ether_header *eh = mtod(m, struct ether_header *); 2258247880Sdelphij caddr_t m_datatemp = m->m_data; 2259247880Sdelphij 2260247880Sdelphij if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 2261247880Sdelphij m->m_data += sizeof(struct ether_header); 2262247880Sdelphij struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 2263247880Sdelphij 2264247880Sdelphij if((ip6->ip6_nxt != IPPROTO_TCP) && \ 2265247880Sdelphij (ip6->ip6_nxt != IPPROTO_UDP)){ 2266247880Sdelphij struct ip6_ext *ip6e = NULL; 2267247880Sdelphij m->m_data += sizeof(struct ip6_hdr); 2268247880Sdelphij 2269247880Sdelphij ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *); 2270247880Sdelphij if(ip6e->ip6e_len == 0xff) { 2271247880Sdelphij m->m_data = m_datatemp; 2272247880Sdelphij return TRUE; 2273247880Sdelphij } 2274247880Sdelphij } 2275247880Sdelphij m->m_data = m_datatemp; 2276247880Sdelphij } 2277247880Sdelphij return FALSE; 2278247880Sdelphij} 2279247880Sdelphij 2280247880Sdelphijstatic int 2281247880Sdelphijis_be3_a1(POCE_SOFTC sc) 2282247880Sdelphij{ 2283247880Sdelphij if((sc->flags & OCE_FLAGS_BE3) && ((sc->asic_revision & 0xFF) < 2)) { 2284247880Sdelphij return TRUE; 2285247880Sdelphij } 2286247880Sdelphij return FALSE; 2287247880Sdelphij} 2288247880Sdelphij 2289247880Sdelphijstatic struct mbuf * 2290247880Sdelphijoce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete) 2291247880Sdelphij{ 2292247880Sdelphij uint16_t vlan_tag = 0; 2293247880Sdelphij 2294247880Sdelphij if(!M_WRITABLE(m)) 2295247880Sdelphij return NULL; 2296247880Sdelphij 2297247880Sdelphij /* Embed vlan tag in the packet if it is not part of it */ 2298247880Sdelphij if(m->m_flags & M_VLANTAG) { 2299247880Sdelphij vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 2300247880Sdelphij m->m_flags &= ~M_VLANTAG; 2301247880Sdelphij } 2302247880Sdelphij 2303247880Sdelphij /* if UMC, ignore vlan tag insertion and instead insert pvid */ 2304247880Sdelphij if(sc->pvid) { 2305247880Sdelphij if(!vlan_tag) 2306247880Sdelphij vlan_tag = sc->pvid; 2307247880Sdelphij *complete = FALSE; 2308247880Sdelphij } 2309247880Sdelphij 2310247880Sdelphij if(vlan_tag) { 2311247880Sdelphij m = ether_vlanencap(m, vlan_tag); 2312247880Sdelphij } 2313247880Sdelphij 2314247880Sdelphij if(sc->qnqid) { 2315247880Sdelphij m = ether_vlanencap(m, sc->qnqid); 2316247880Sdelphij *complete = FALSE; 2317247880Sdelphij } 2318247880Sdelphij return m; 2319247880Sdelphij} 2320247880Sdelphij 2321247880Sdelphijstatic int 2322247880Sdelphijoce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m) 2323247880Sdelphij{ 2324247880Sdelphij if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \ 2325247880Sdelphij oce_check_ipv6_ext_hdr(m)) { 2326247880Sdelphij return TRUE; 2327247880Sdelphij } 2328247880Sdelphij return FALSE; 2329247880Sdelphij} 2330252869Sdelphij 2331252869Sdelphijstatic void 2332252869Sdelphijoce_get_config(POCE_SOFTC sc) 2333252869Sdelphij{ 2334252869Sdelphij int rc = 0; 2335252869Sdelphij uint32_t max_rss = 0; 2336252869Sdelphij 2337252869Sdelphij if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native)) 2338252869Sdelphij max_rss = OCE_LEGACY_MODE_RSS; 2339252869Sdelphij else 2340252869Sdelphij max_rss = OCE_MAX_RSS; 2341252869Sdelphij 2342252869Sdelphij if (!IS_BE(sc)) { 2343259050Sdelphij rc = oce_get_profile_config(sc, max_rss); 2344252869Sdelphij if (rc) { 2345252869Sdelphij sc->nwqs = OCE_MAX_WQ; 2346252869Sdelphij sc->nrssqs = max_rss; 2347252869Sdelphij sc->nrqs = sc->nrssqs + 1; 2348252869Sdelphij } 2349252869Sdelphij } 2350259050Sdelphij else { /* For BE3 don't rely on fw for determining the resources */ 2351252869Sdelphij sc->nrssqs = max_rss; 2352252869Sdelphij sc->nrqs = sc->nrssqs + 1; 2353259050Sdelphij sc->nwqs = OCE_MAX_WQ; 2354259050Sdelphij sc->max_vlans = MAX_VLANFILTER_SIZE; 2355252869Sdelphij } 2356252869Sdelphij} 2357