oce_if.c revision 268156
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: head/sys/dev/oce/oce_if.c 268156 2014-07-02 12:13:11Z luigi $ */ 40231437Sluigi 41231511Sbz#include "opt_inet6.h" 42231511Sbz#include "opt_inet.h" 43231511Sbz 44231437Sluigi#include "oce_if.h" 45231437Sluigi 46257007Sdelphij/* UE Status Low CSR */ 47257007Sdelphijstatic char *ue_status_low_desc[] = { 48257007Sdelphij "CEV", 49257007Sdelphij "CTX", 50257007Sdelphij "DBUF", 51257007Sdelphij "ERX", 52257007Sdelphij "Host", 53257007Sdelphij "MPU", 54257007Sdelphij "NDMA", 55257007Sdelphij "PTC ", 56257007Sdelphij "RDMA ", 57257007Sdelphij "RXF ", 58257007Sdelphij "RXIPS ", 59257007Sdelphij "RXULP0 ", 60257007Sdelphij "RXULP1 ", 61257007Sdelphij "RXULP2 ", 62257007Sdelphij "TIM ", 63257007Sdelphij "TPOST ", 64257007Sdelphij "TPRE ", 65257007Sdelphij "TXIPS ", 66257007Sdelphij "TXULP0 ", 67257007Sdelphij "TXULP1 ", 68257007Sdelphij "UC ", 69257007Sdelphij "WDMA ", 70257007Sdelphij "TXULP2 ", 71257007Sdelphij "HOST1 ", 72257007Sdelphij "P0_OB_LINK ", 73257007Sdelphij "P1_OB_LINK ", 74257007Sdelphij "HOST_GPIO ", 75257007Sdelphij "MBOX ", 76257007Sdelphij "AXGMAC0", 77257007Sdelphij "AXGMAC1", 78257007Sdelphij "JTAG", 79257007Sdelphij "MPU_INTPEND" 80257007Sdelphij}; 81231437Sluigi 82257007Sdelphij/* UE Status High CSR */ 83257007Sdelphijstatic char *ue_status_hi_desc[] = { 84257007Sdelphij "LPCMEMHOST", 85257007Sdelphij "MGMT_MAC", 86257007Sdelphij "PCS0ONLINE", 87257007Sdelphij "MPU_IRAM", 88257007Sdelphij "PCS1ONLINE", 89257007Sdelphij "PCTL0", 90257007Sdelphij "PCTL1", 91257007Sdelphij "PMEM", 92257007Sdelphij "RR", 93257007Sdelphij "TXPB", 94257007Sdelphij "RXPP", 95257007Sdelphij "XAUI", 96257007Sdelphij "TXP", 97257007Sdelphij "ARM", 98257007Sdelphij "IPC", 99257007Sdelphij "HOST2", 100257007Sdelphij "HOST3", 101257007Sdelphij "HOST4", 102257007Sdelphij "HOST5", 103257007Sdelphij "HOST6", 104257007Sdelphij "HOST7", 105257007Sdelphij "HOST8", 106257007Sdelphij "HOST9", 107257007Sdelphij "NETC", 108257007Sdelphij "Unknown", 109257007Sdelphij "Unknown", 110257007Sdelphij "Unknown", 111257007Sdelphij "Unknown", 112257007Sdelphij "Unknown", 113257007Sdelphij "Unknown", 114257007Sdelphij "Unknown", 115257007Sdelphij "Unknown" 116257007Sdelphij}; 117257007Sdelphij 118257007Sdelphij 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) { 462257007Sdelphij if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1)))) 463257007Sdelphij sc->promisc = TRUE; 464231437Sluigi } else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) { 465257007Sdelphij if (!oce_rxf_set_promiscuous(sc, 0)) 466257007Sdelphij 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 566231437Sluigi if ((m->m_flags & M_FLOWID) != 0) 567231437Sluigi queue_index = m->m_pkthdr.flowid % sc->nwqs; 568252869Sdelphij 569231437Sluigi wq = sc->wq[queue_index]; 570231437Sluigi 571252869Sdelphij LOCK(&wq->tx_lock); 572252869Sdelphij status = oce_multiq_transmit(ifp, m, wq); 573252869Sdelphij UNLOCK(&wq->tx_lock); 574252869Sdelphij 575231437Sluigi return status; 576231437Sluigi 577231437Sluigi} 578231437Sluigi 579231437Sluigi 580231437Sluigistatic void 581231437Sluigioce_multiq_flush(struct ifnet *ifp) 582231437Sluigi{ 583231437Sluigi POCE_SOFTC sc = ifp->if_softc; 584231437Sluigi struct mbuf *m; 585231437Sluigi int i = 0; 586231437Sluigi 587231437Sluigi for (i = 0; i < sc->nwqs; i++) { 588231437Sluigi while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) 589231437Sluigi m_freem(m); 590231437Sluigi } 591231437Sluigi if_qflush(ifp); 592231437Sluigi} 593231437Sluigi 594231437Sluigi 595231437Sluigi 596231437Sluigi/***************************************************************************** 597231437Sluigi * Driver interrupt routines functions * 598231437Sluigi *****************************************************************************/ 599231437Sluigi 600231437Sluigistatic void 601231437Sluigioce_intr(void *arg, int pending) 602231437Sluigi{ 603231437Sluigi 604231437Sluigi POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 605231437Sluigi POCE_SOFTC sc = ii->sc; 606231437Sluigi struct oce_eq *eq = ii->eq; 607231437Sluigi struct oce_eqe *eqe; 608231437Sluigi struct oce_cq *cq = NULL; 609231437Sluigi int i, num_eqes = 0; 610231437Sluigi 611231437Sluigi 612231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 613231437Sluigi BUS_DMASYNC_POSTWRITE); 614231437Sluigi do { 615231437Sluigi eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 616231437Sluigi if (eqe->evnt == 0) 617231437Sluigi break; 618231437Sluigi eqe->evnt = 0; 619231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 620231437Sluigi BUS_DMASYNC_POSTWRITE); 621231437Sluigi RING_GET(eq->ring, 1); 622231437Sluigi num_eqes++; 623231437Sluigi 624231437Sluigi } while (TRUE); 625231437Sluigi 626231437Sluigi if (!num_eqes) 627231437Sluigi goto eq_arm; /* Spurious */ 628231437Sluigi 629231437Sluigi /* Clear EQ entries, but dont arm */ 630231437Sluigi oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE); 631231437Sluigi 632231437Sluigi /* Process TX, RX and MCC. But dont arm CQ*/ 633231437Sluigi for (i = 0; i < eq->cq_valid; i++) { 634231437Sluigi cq = eq->cq[i]; 635231437Sluigi (*cq->cq_handler)(cq->cb_arg); 636231437Sluigi } 637231437Sluigi 638231437Sluigi /* Arm all cqs connected to this EQ */ 639231437Sluigi for (i = 0; i < eq->cq_valid; i++) { 640231437Sluigi cq = eq->cq[i]; 641231437Sluigi oce_arm_cq(sc, cq->cq_id, 0, TRUE); 642231437Sluigi } 643231437Sluigi 644231437Sluigieq_arm: 645231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 646247880Sdelphij 647231437Sluigi return; 648231437Sluigi} 649231437Sluigi 650231437Sluigi 651231437Sluigistatic int 652231437Sluigioce_setup_intr(POCE_SOFTC sc) 653231437Sluigi{ 654231437Sluigi int rc = 0, use_intx = 0; 655231437Sluigi int vector = 0, req_vectors = 0; 656231437Sluigi 657252869Sdelphij if (is_rss_enabled(sc)) 658231437Sluigi req_vectors = MAX((sc->nrqs - 1), sc->nwqs); 659231437Sluigi else 660231437Sluigi req_vectors = 1; 661231437Sluigi 662231437Sluigi if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) { 663231437Sluigi sc->intr_count = req_vectors; 664231437Sluigi rc = pci_alloc_msix(sc->dev, &sc->intr_count); 665231437Sluigi if (rc != 0) { 666231437Sluigi use_intx = 1; 667231437Sluigi pci_release_msi(sc->dev); 668231437Sluigi } else 669231437Sluigi sc->flags |= OCE_FLAGS_USING_MSIX; 670231437Sluigi } else 671231437Sluigi use_intx = 1; 672231437Sluigi 673231437Sluigi if (use_intx) 674231437Sluigi sc->intr_count = 1; 675231437Sluigi 676231437Sluigi /* Scale number of queues based on intr we got */ 677231437Sluigi update_queues_got(sc); 678231437Sluigi 679231437Sluigi if (use_intx) { 680231437Sluigi device_printf(sc->dev, "Using legacy interrupt\n"); 681231437Sluigi rc = oce_alloc_intr(sc, vector, oce_intr); 682231437Sluigi if (rc) 683231437Sluigi goto error; 684231437Sluigi } else { 685231437Sluigi for (; vector < sc->intr_count; vector++) { 686231437Sluigi rc = oce_alloc_intr(sc, vector, oce_intr); 687231437Sluigi if (rc) 688231437Sluigi goto error; 689231437Sluigi } 690231437Sluigi } 691231437Sluigi 692231437Sluigi return 0; 693231437Sluigierror: 694231437Sluigi oce_intr_free(sc); 695231437Sluigi return rc; 696231437Sluigi} 697231437Sluigi 698231437Sluigi 699231437Sluigistatic int 700231437Sluigioce_fast_isr(void *arg) 701231437Sluigi{ 702231437Sluigi POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 703231437Sluigi POCE_SOFTC sc = ii->sc; 704231437Sluigi 705231437Sluigi if (ii->eq == NULL) 706231437Sluigi return FILTER_STRAY; 707231437Sluigi 708231437Sluigi oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE); 709231437Sluigi 710231437Sluigi taskqueue_enqueue_fast(ii->tq, &ii->task); 711231437Sluigi 712247880Sdelphij ii->eq->intr++; 713247880Sdelphij 714231437Sluigi return FILTER_HANDLED; 715231437Sluigi} 716231437Sluigi 717231437Sluigi 718231437Sluigistatic int 719231437Sluigioce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) 720231437Sluigi{ 721231437Sluigi POCE_INTR_INFO ii = &sc->intrs[vector]; 722231437Sluigi int rc = 0, rr; 723231437Sluigi 724231437Sluigi if (vector >= OCE_MAX_EQ) 725231437Sluigi return (EINVAL); 726231437Sluigi 727231437Sluigi /* Set the resource id for the interrupt. 728231437Sluigi * MSIx is vector + 1 for the resource id, 729231437Sluigi * INTx is 0 for the resource id. 730231437Sluigi */ 731231437Sluigi if (sc->flags & OCE_FLAGS_USING_MSIX) 732231437Sluigi rr = vector + 1; 733231437Sluigi else 734231437Sluigi rr = 0; 735231437Sluigi ii->intr_res = bus_alloc_resource_any(sc->dev, 736231437Sluigi SYS_RES_IRQ, 737231437Sluigi &rr, RF_ACTIVE|RF_SHAREABLE); 738231437Sluigi ii->irq_rr = rr; 739231437Sluigi if (ii->intr_res == NULL) { 740231437Sluigi device_printf(sc->dev, 741231437Sluigi "Could not allocate interrupt\n"); 742231437Sluigi rc = ENXIO; 743231437Sluigi return rc; 744231437Sluigi } 745231437Sluigi 746231437Sluigi TASK_INIT(&ii->task, 0, isr, ii); 747231437Sluigi ii->vector = vector; 748231437Sluigi sprintf(ii->task_name, "oce_task[%d]", ii->vector); 749231437Sluigi ii->tq = taskqueue_create_fast(ii->task_name, 750231437Sluigi M_NOWAIT, 751231437Sluigi taskqueue_thread_enqueue, 752231437Sluigi &ii->tq); 753231437Sluigi taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq", 754231437Sluigi device_get_nameunit(sc->dev)); 755231437Sluigi 756231437Sluigi ii->sc = sc; 757231437Sluigi rc = bus_setup_intr(sc->dev, 758231437Sluigi ii->intr_res, 759231437Sluigi INTR_TYPE_NET, 760231437Sluigi oce_fast_isr, NULL, ii, &ii->tag); 761231437Sluigi return rc; 762231437Sluigi 763231437Sluigi} 764231437Sluigi 765231437Sluigi 766231437Sluigivoid 767231437Sluigioce_intr_free(POCE_SOFTC sc) 768231437Sluigi{ 769231437Sluigi int i = 0; 770231437Sluigi 771231437Sluigi for (i = 0; i < sc->intr_count; i++) { 772231437Sluigi 773231437Sluigi if (sc->intrs[i].tag != NULL) 774231437Sluigi bus_teardown_intr(sc->dev, sc->intrs[i].intr_res, 775231437Sluigi sc->intrs[i].tag); 776231437Sluigi if (sc->intrs[i].tq != NULL) 777231437Sluigi taskqueue_free(sc->intrs[i].tq); 778231437Sluigi 779231437Sluigi if (sc->intrs[i].intr_res != NULL) 780231437Sluigi bus_release_resource(sc->dev, SYS_RES_IRQ, 781231437Sluigi sc->intrs[i].irq_rr, 782231437Sluigi sc->intrs[i].intr_res); 783231437Sluigi sc->intrs[i].tag = NULL; 784231437Sluigi sc->intrs[i].intr_res = NULL; 785231437Sluigi } 786231437Sluigi 787231437Sluigi if (sc->flags & OCE_FLAGS_USING_MSIX) 788231437Sluigi pci_release_msi(sc->dev); 789231437Sluigi 790231437Sluigi} 791231437Sluigi 792231437Sluigi 793231437Sluigi 794231437Sluigi/****************************************************************************** 795231437Sluigi* Media callbacks functions * 796231437Sluigi******************************************************************************/ 797231437Sluigi 798231437Sluigistatic void 799231437Sluigioce_media_status(struct ifnet *ifp, struct ifmediareq *req) 800231437Sluigi{ 801231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc; 802231437Sluigi 803231437Sluigi 804231437Sluigi req->ifm_status = IFM_AVALID; 805231437Sluigi req->ifm_active = IFM_ETHER; 806231437Sluigi 807231437Sluigi if (sc->link_status == 1) 808231437Sluigi req->ifm_status |= IFM_ACTIVE; 809231437Sluigi else 810231437Sluigi return; 811231437Sluigi 812231437Sluigi switch (sc->link_speed) { 813231437Sluigi case 1: /* 10 Mbps */ 814231437Sluigi req->ifm_active |= IFM_10_T | IFM_FDX; 815231437Sluigi sc->speed = 10; 816231437Sluigi break; 817231437Sluigi case 2: /* 100 Mbps */ 818231437Sluigi req->ifm_active |= IFM_100_TX | IFM_FDX; 819231437Sluigi sc->speed = 100; 820231437Sluigi break; 821231437Sluigi case 3: /* 1 Gbps */ 822231437Sluigi req->ifm_active |= IFM_1000_T | IFM_FDX; 823231437Sluigi sc->speed = 1000; 824231437Sluigi break; 825231437Sluigi case 4: /* 10 Gbps */ 826231437Sluigi req->ifm_active |= IFM_10G_SR | IFM_FDX; 827231437Sluigi sc->speed = 10000; 828231437Sluigi break; 829267839Sdelphij case 5: /* 20 Gbps */ 830267839Sdelphij req->ifm_active |= IFM_10G_SR | IFM_FDX; 831267839Sdelphij sc->speed = 20000; 832267839Sdelphij break; 833267839Sdelphij case 6: /* 25 Gbps */ 834267839Sdelphij req->ifm_active |= IFM_10G_SR | IFM_FDX; 835267839Sdelphij sc->speed = 25000; 836267839Sdelphij break; 837258941Sdelphij case 7: /* 40 Gbps */ 838258941Sdelphij req->ifm_active |= IFM_40G_SR4 | IFM_FDX; 839258941Sdelphij sc->speed = 40000; 840258941Sdelphij break; 841267839Sdelphij default: 842267839Sdelphij sc->speed = 0; 843267839Sdelphij break; 844231437Sluigi } 845231437Sluigi 846231437Sluigi return; 847231437Sluigi} 848231437Sluigi 849231437Sluigi 850231437Sluigiint 851231437Sluigioce_media_change(struct ifnet *ifp) 852231437Sluigi{ 853231437Sluigi return 0; 854231437Sluigi} 855231437Sluigi 856231437Sluigi 857231437Sluigi 858231437Sluigi 859231437Sluigi/***************************************************************************** 860231437Sluigi * Transmit routines functions * 861231437Sluigi *****************************************************************************/ 862231437Sluigi 863231437Sluigistatic int 864231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 865231437Sluigi{ 866231437Sluigi int rc = 0, i, retry_cnt = 0; 867231437Sluigi bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 868231437Sluigi struct mbuf *m, *m_temp; 869231437Sluigi struct oce_wq *wq = sc->wq[wq_index]; 870231437Sluigi struct oce_packet_desc *pd; 871231437Sluigi struct oce_nic_hdr_wqe *nichdr; 872231437Sluigi struct oce_nic_frag_wqe *nicfrag; 873231437Sluigi int num_wqes; 874231437Sluigi uint32_t reg_value; 875247880Sdelphij boolean_t complete = TRUE; 876231437Sluigi 877231437Sluigi m = *mpp; 878231437Sluigi if (!m) 879231437Sluigi return EINVAL; 880231437Sluigi 881231437Sluigi if (!(m->m_flags & M_PKTHDR)) { 882231437Sluigi rc = ENXIO; 883231437Sluigi goto free_ret; 884231437Sluigi } 885231437Sluigi 886247880Sdelphij if(oce_tx_asic_stall_verify(sc, m)) { 887247880Sdelphij m = oce_insert_vlan_tag(sc, m, &complete); 888247880Sdelphij if(!m) { 889247880Sdelphij device_printf(sc->dev, "Insertion unsuccessful\n"); 890247880Sdelphij return 0; 891247880Sdelphij } 892247880Sdelphij 893247880Sdelphij } 894247880Sdelphij 895231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 896231879Sluigi /* consolidate packet buffers for TSO/LSO segment offload */ 897231511Sbz#if defined(INET6) || defined(INET) 898231879Sluigi m = oce_tso_setup(sc, mpp); 899231511Sbz#else 900231511Sbz m = NULL; 901231511Sbz#endif 902231437Sluigi if (m == NULL) { 903231437Sluigi rc = ENXIO; 904231437Sluigi goto free_ret; 905231437Sluigi } 906231437Sluigi } 907231437Sluigi 908252869Sdelphij pd = &wq->pckts[wq->pkt_desc_head]; 909231437Sluigiretry: 910231437Sluigi rc = bus_dmamap_load_mbuf_sg(wq->tag, 911231437Sluigi pd->map, 912231437Sluigi m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 913231437Sluigi if (rc == 0) { 914231437Sluigi num_wqes = pd->nsegs + 1; 915252869Sdelphij if (IS_BE(sc) || IS_SH(sc)) { 916231437Sluigi /*Dummy required only for BE3.*/ 917231437Sluigi if (num_wqes & 1) 918231437Sluigi num_wqes++; 919231437Sluigi } 920231437Sluigi if (num_wqes >= RING_NUM_FREE(wq->ring)) { 921231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 922231437Sluigi return EBUSY; 923231437Sluigi } 924252869Sdelphij atomic_store_rel_int(&wq->pkt_desc_head, 925252869Sdelphij (wq->pkt_desc_head + 1) % \ 926252869Sdelphij OCE_WQ_PACKET_ARRAY_SIZE); 927231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 928231437Sluigi pd->mbuf = m; 929231437Sluigi 930231437Sluigi nichdr = 931231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 932231437Sluigi nichdr->u0.dw[0] = 0; 933231437Sluigi nichdr->u0.dw[1] = 0; 934231437Sluigi nichdr->u0.dw[2] = 0; 935231437Sluigi nichdr->u0.dw[3] = 0; 936231437Sluigi 937247880Sdelphij nichdr->u0.s.complete = complete; 938231437Sluigi nichdr->u0.s.event = 1; 939231437Sluigi nichdr->u0.s.crc = 1; 940231437Sluigi nichdr->u0.s.forward = 0; 941231437Sluigi nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 942231437Sluigi nichdr->u0.s.udpcs = 943247880Sdelphij (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 944231437Sluigi nichdr->u0.s.tcpcs = 945247880Sdelphij (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 946231437Sluigi nichdr->u0.s.num_wqe = num_wqes; 947231437Sluigi nichdr->u0.s.total_length = m->m_pkthdr.len; 948257007Sdelphij 949231437Sluigi if (m->m_flags & M_VLANTAG) { 950231437Sluigi nichdr->u0.s.vlan = 1; /*Vlan present*/ 951231437Sluigi nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 952231437Sluigi } 953257007Sdelphij 954231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 955231437Sluigi if (m->m_pkthdr.tso_segsz) { 956231437Sluigi nichdr->u0.s.lso = 1; 957231437Sluigi nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 958231437Sluigi } 959252869Sdelphij if (!IS_BE(sc) || !IS_SH(sc)) 960231437Sluigi nichdr->u0.s.ipcs = 1; 961231437Sluigi } 962231437Sluigi 963231437Sluigi RING_PUT(wq->ring, 1); 964252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 965231437Sluigi 966231437Sluigi for (i = 0; i < pd->nsegs; i++) { 967231437Sluigi nicfrag = 968231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 969231437Sluigi struct oce_nic_frag_wqe); 970231437Sluigi nicfrag->u0.s.rsvd0 = 0; 971231437Sluigi nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 972231437Sluigi nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 973231437Sluigi nicfrag->u0.s.frag_len = segs[i].ds_len; 974231437Sluigi pd->wqe_idx = wq->ring->pidx; 975231437Sluigi RING_PUT(wq->ring, 1); 976252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 977231437Sluigi } 978231437Sluigi if (num_wqes > (pd->nsegs + 1)) { 979231437Sluigi nicfrag = 980231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 981231437Sluigi struct oce_nic_frag_wqe); 982231437Sluigi nicfrag->u0.dw[0] = 0; 983231437Sluigi nicfrag->u0.dw[1] = 0; 984231437Sluigi nicfrag->u0.dw[2] = 0; 985231437Sluigi nicfrag->u0.dw[3] = 0; 986231437Sluigi pd->wqe_idx = wq->ring->pidx; 987231437Sluigi RING_PUT(wq->ring, 1); 988252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 989231437Sluigi pd->nsegs++; 990231437Sluigi } 991231437Sluigi 992231437Sluigi sc->ifp->if_opackets++; 993231437Sluigi wq->tx_stats.tx_reqs++; 994231437Sluigi wq->tx_stats.tx_wrbs += num_wqes; 995231437Sluigi wq->tx_stats.tx_bytes += m->m_pkthdr.len; 996231437Sluigi wq->tx_stats.tx_pkts++; 997247880Sdelphij 998231437Sluigi bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 999231437Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1000231437Sluigi reg_value = (num_wqes << 16) | wq->wq_id; 1001252869Sdelphij OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value); 1002231437Sluigi 1003231437Sluigi } else if (rc == EFBIG) { 1004231437Sluigi if (retry_cnt == 0) { 1005243857Sglebius m_temp = m_defrag(m, M_NOWAIT); 1006231437Sluigi if (m_temp == NULL) 1007231437Sluigi goto free_ret; 1008231437Sluigi m = m_temp; 1009231437Sluigi *mpp = m_temp; 1010231437Sluigi retry_cnt = retry_cnt + 1; 1011231437Sluigi goto retry; 1012231437Sluigi } else 1013231437Sluigi goto free_ret; 1014231437Sluigi } else if (rc == ENOMEM) 1015231437Sluigi return rc; 1016231437Sluigi else 1017231437Sluigi goto free_ret; 1018252869Sdelphij 1019231437Sluigi return 0; 1020231437Sluigi 1021231437Sluigifree_ret: 1022231437Sluigi m_freem(*mpp); 1023231437Sluigi *mpp = NULL; 1024231437Sluigi return rc; 1025231437Sluigi} 1026231437Sluigi 1027231437Sluigi 1028231437Sluigistatic void 1029231437Sluigioce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status) 1030231437Sluigi{ 1031231437Sluigi struct oce_packet_desc *pd; 1032231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 1033231437Sluigi struct mbuf *m; 1034231437Sluigi 1035252869Sdelphij pd = &wq->pckts[wq->pkt_desc_tail]; 1036252869Sdelphij atomic_store_rel_int(&wq->pkt_desc_tail, 1037252869Sdelphij (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE); 1038252869Sdelphij atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1); 1039231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1040231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 1041231437Sluigi 1042231437Sluigi m = pd->mbuf; 1043231437Sluigi m_freem(m); 1044231437Sluigi pd->mbuf = NULL; 1045231437Sluigi 1046252869Sdelphij 1047231437Sluigi if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1048231437Sluigi if (wq->ring->num_used < (wq->ring->num_items / 2)) { 1049231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 1050231437Sluigi oce_tx_restart(sc, wq); 1051231437Sluigi } 1052231437Sluigi } 1053231437Sluigi} 1054231437Sluigi 1055231437Sluigi 1056231437Sluigistatic void 1057231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 1058231437Sluigi{ 1059231437Sluigi 1060231437Sluigi if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 1061231437Sluigi return; 1062231437Sluigi 1063231437Sluigi#if __FreeBSD_version >= 800000 1064231437Sluigi if (!drbr_empty(sc->ifp, wq->br)) 1065231437Sluigi#else 1066231437Sluigi if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 1067231437Sluigi#endif 1068231437Sluigi taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask); 1069231437Sluigi 1070231437Sluigi} 1071231437Sluigi 1072231879Sluigi 1073231511Sbz#if defined(INET6) || defined(INET) 1074231437Sluigistatic struct mbuf * 1075231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp) 1076231437Sluigi{ 1077231437Sluigi struct mbuf *m; 1078231511Sbz#ifdef INET 1079231437Sluigi struct ip *ip; 1080231511Sbz#endif 1081231511Sbz#ifdef INET6 1082231437Sluigi struct ip6_hdr *ip6; 1083231511Sbz#endif 1084231437Sluigi struct ether_vlan_header *eh; 1085231437Sluigi struct tcphdr *th; 1086231437Sluigi uint16_t etype; 1087231879Sluigi int total_len = 0, ehdrlen = 0; 1088231437Sluigi 1089231437Sluigi m = *mpp; 1090231437Sluigi 1091231437Sluigi if (M_WRITABLE(m) == 0) { 1092243857Sglebius m = m_dup(*mpp, M_NOWAIT); 1093231437Sluigi if (!m) 1094231437Sluigi return NULL; 1095231437Sluigi m_freem(*mpp); 1096231437Sluigi *mpp = m; 1097231437Sluigi } 1098231437Sluigi 1099231437Sluigi eh = mtod(m, struct ether_vlan_header *); 1100231437Sluigi if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 1101231437Sluigi etype = ntohs(eh->evl_proto); 1102231437Sluigi ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1103231437Sluigi } else { 1104231437Sluigi etype = ntohs(eh->evl_encap_proto); 1105231437Sluigi ehdrlen = ETHER_HDR_LEN; 1106231437Sluigi } 1107231437Sluigi 1108231437Sluigi switch (etype) { 1109231511Sbz#ifdef INET 1110231437Sluigi case ETHERTYPE_IP: 1111231437Sluigi ip = (struct ip *)(m->m_data + ehdrlen); 1112231437Sluigi if (ip->ip_p != IPPROTO_TCP) 1113231437Sluigi return NULL; 1114231437Sluigi th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 1115231437Sluigi 1116231437Sluigi total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 1117231437Sluigi break; 1118231511Sbz#endif 1119231511Sbz#ifdef INET6 1120231437Sluigi case ETHERTYPE_IPV6: 1121231437Sluigi ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 1122231437Sluigi if (ip6->ip6_nxt != IPPROTO_TCP) 1123231437Sluigi return NULL; 1124231437Sluigi th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 1125231437Sluigi 1126231437Sluigi total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 1127231437Sluigi break; 1128231511Sbz#endif 1129231437Sluigi default: 1130231437Sluigi return NULL; 1131231437Sluigi } 1132231437Sluigi 1133231437Sluigi m = m_pullup(m, total_len); 1134231437Sluigi if (!m) 1135231437Sluigi return NULL; 1136231437Sluigi *mpp = m; 1137231437Sluigi return m; 1138231437Sluigi 1139231437Sluigi} 1140231511Sbz#endif /* INET6 || INET */ 1141231437Sluigi 1142231437Sluigivoid 1143231437Sluigioce_tx_task(void *arg, int npending) 1144231437Sluigi{ 1145231437Sluigi struct oce_wq *wq = arg; 1146231437Sluigi POCE_SOFTC sc = wq->parent; 1147231437Sluigi struct ifnet *ifp = sc->ifp; 1148231437Sluigi int rc = 0; 1149252869Sdelphij 1150231437Sluigi#if __FreeBSD_version >= 800000 1151252869Sdelphij LOCK(&wq->tx_lock); 1152252869Sdelphij rc = oce_multiq_transmit(ifp, NULL, wq); 1153252869Sdelphij if (rc) { 1154252869Sdelphij device_printf(sc->dev, 1155252869Sdelphij "TX[%d] restart failed\n", wq->queue_index); 1156231437Sluigi } 1157252869Sdelphij UNLOCK(&wq->tx_lock); 1158231437Sluigi#else 1159231437Sluigi oce_start(ifp); 1160231437Sluigi#endif 1161231437Sluigi 1162231437Sluigi} 1163231437Sluigi 1164231437Sluigi 1165231437Sluigivoid 1166231437Sluigioce_start(struct ifnet *ifp) 1167231437Sluigi{ 1168231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1169231437Sluigi struct mbuf *m; 1170231437Sluigi int rc = 0; 1171231879Sluigi int def_q = 0; /* Defualt tx queue is 0*/ 1172231437Sluigi 1173231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1174231437Sluigi IFF_DRV_RUNNING) 1175231437Sluigi return; 1176247880Sdelphij 1177247880Sdelphij if (!sc->link_status) 1178247880Sdelphij return; 1179231437Sluigi 1180231437Sluigi do { 1181231437Sluigi IF_DEQUEUE(&sc->ifp->if_snd, m); 1182231437Sluigi if (m == NULL) 1183231437Sluigi break; 1184231879Sluigi 1185231879Sluigi LOCK(&sc->wq[def_q]->tx_lock); 1186231879Sluigi rc = oce_tx(sc, &m, def_q); 1187231879Sluigi UNLOCK(&sc->wq[def_q]->tx_lock); 1188231437Sluigi if (rc) { 1189231437Sluigi if (m != NULL) { 1190231879Sluigi sc->wq[def_q]->tx_stats.tx_stops ++; 1191231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1192231437Sluigi IFQ_DRV_PREPEND(&ifp->if_snd, m); 1193231437Sluigi m = NULL; 1194231437Sluigi } 1195231437Sluigi break; 1196231437Sluigi } 1197231437Sluigi if (m != NULL) 1198231437Sluigi ETHER_BPF_MTAP(ifp, m); 1199231437Sluigi 1200231879Sluigi } while (TRUE); 1201231437Sluigi 1202231437Sluigi return; 1203231437Sluigi} 1204231437Sluigi 1205231437Sluigi 1206231437Sluigi/* Handle the Completion Queue for transmit */ 1207231437Sluigiuint16_t 1208231437Sluigioce_wq_handler(void *arg) 1209231437Sluigi{ 1210231437Sluigi struct oce_wq *wq = (struct oce_wq *)arg; 1211231437Sluigi POCE_SOFTC sc = wq->parent; 1212231437Sluigi struct oce_cq *cq = wq->cq; 1213231437Sluigi struct oce_nic_tx_cqe *cqe; 1214231437Sluigi int num_cqes = 0; 1215231437Sluigi 1216231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1217231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1218231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1219231437Sluigi while (cqe->u0.dw[3]) { 1220231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 1221231437Sluigi 1222231437Sluigi wq->ring->cidx = cqe->u0.s.wqe_index + 1; 1223231437Sluigi if (wq->ring->cidx >= wq->ring->num_items) 1224231437Sluigi wq->ring->cidx -= wq->ring->num_items; 1225231437Sluigi 1226231437Sluigi oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status); 1227231437Sluigi wq->tx_stats.tx_compl++; 1228231437Sluigi cqe->u0.dw[3] = 0; 1229231437Sluigi RING_GET(cq->ring, 1); 1230231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1231231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1232231437Sluigi cqe = 1233231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1234231437Sluigi num_cqes++; 1235231437Sluigi } 1236231437Sluigi 1237231437Sluigi if (num_cqes) 1238231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1239231437Sluigi 1240231437Sluigi return 0; 1241231437Sluigi} 1242231437Sluigi 1243231437Sluigi 1244231437Sluigistatic int 1245231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 1246231437Sluigi{ 1247231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1248231437Sluigi int status = 0, queue_index = 0; 1249231437Sluigi struct mbuf *next = NULL; 1250231437Sluigi struct buf_ring *br = NULL; 1251231437Sluigi 1252231437Sluigi br = wq->br; 1253231437Sluigi queue_index = wq->queue_index; 1254231437Sluigi 1255231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1256231437Sluigi IFF_DRV_RUNNING) { 1257231437Sluigi if (m != NULL) 1258231437Sluigi status = drbr_enqueue(ifp, br, m); 1259231437Sluigi return status; 1260231437Sluigi } 1261231437Sluigi 1262257007Sdelphij if (m != NULL) { 1263231437Sluigi if ((status = drbr_enqueue(ifp, br, m)) != 0) 1264231437Sluigi return status; 1265246482Srrs } 1266246482Srrs while ((next = drbr_peek(ifp, br)) != NULL) { 1267231437Sluigi if (oce_tx(sc, &next, queue_index)) { 1268246482Srrs if (next == NULL) { 1269246482Srrs drbr_advance(ifp, br); 1270246482Srrs } else { 1271246482Srrs drbr_putback(ifp, br, next); 1272231437Sluigi wq->tx_stats.tx_stops ++; 1273231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1274231437Sluigi } 1275231437Sluigi break; 1276231437Sluigi } 1277246482Srrs drbr_advance(ifp, br); 1278241037Sglebius ifp->if_obytes += next->m_pkthdr.len; 1279241037Sglebius if (next->m_flags & M_MCAST) 1280241037Sglebius ifp->if_omcasts++; 1281231437Sluigi ETHER_BPF_MTAP(ifp, next); 1282231437Sluigi } 1283231437Sluigi 1284268156Sluigi return 0; 1285231437Sluigi} 1286231437Sluigi 1287231437Sluigi 1288231437Sluigi 1289231437Sluigi 1290231437Sluigi/***************************************************************************** 1291231437Sluigi * Receive routines functions * 1292231437Sluigi *****************************************************************************/ 1293231437Sluigi 1294231437Sluigistatic void 1295231437Sluigioce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe) 1296231437Sluigi{ 1297231437Sluigi uint32_t out; 1298231437Sluigi struct oce_packet_desc *pd; 1299231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1300231437Sluigi int i, len, frag_len; 1301231437Sluigi struct mbuf *m = NULL, *tail = NULL; 1302231437Sluigi uint16_t vtag; 1303231437Sluigi 1304231437Sluigi len = cqe->u0.s.pkt_size; 1305231437Sluigi if (!len) { 1306231437Sluigi /*partial DMA workaround for Lancer*/ 1307231437Sluigi oce_discard_rx_comp(rq, cqe); 1308231437Sluigi goto exit; 1309231437Sluigi } 1310231437Sluigi 1311231879Sluigi /* Get vlan_tag value */ 1312252869Sdelphij if(IS_BE(sc) || IS_SH(sc)) 1313231879Sluigi vtag = BSWAP_16(cqe->u0.s.vlan_tag); 1314231879Sluigi else 1315231879Sluigi vtag = cqe->u0.s.vlan_tag; 1316231879Sluigi 1317231879Sluigi 1318231437Sluigi for (i = 0; i < cqe->u0.s.num_fragments; i++) { 1319231437Sluigi 1320231437Sluigi if (rq->packets_out == rq->packets_in) { 1321231437Sluigi device_printf(sc->dev, 1322231437Sluigi "RQ transmit descriptor missing\n"); 1323231437Sluigi } 1324231437Sluigi out = rq->packets_out + 1; 1325231437Sluigi if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1326231437Sluigi out = 0; 1327231437Sluigi pd = &rq->pckts[rq->packets_out]; 1328231437Sluigi rq->packets_out = out; 1329231437Sluigi 1330231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1331231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1332231437Sluigi rq->pending--; 1333231437Sluigi 1334231437Sluigi frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 1335231437Sluigi pd->mbuf->m_len = frag_len; 1336231437Sluigi 1337231437Sluigi if (tail != NULL) { 1338231437Sluigi /* additional fragments */ 1339231437Sluigi pd->mbuf->m_flags &= ~M_PKTHDR; 1340231437Sluigi tail->m_next = pd->mbuf; 1341231437Sluigi tail = pd->mbuf; 1342231437Sluigi } else { 1343231437Sluigi /* first fragment, fill out much of the packet header */ 1344231437Sluigi pd->mbuf->m_pkthdr.len = len; 1345231437Sluigi pd->mbuf->m_pkthdr.csum_flags = 0; 1346231437Sluigi if (IF_CSUM_ENABLED(sc)) { 1347231437Sluigi if (cqe->u0.s.l4_cksum_pass) { 1348231437Sluigi pd->mbuf->m_pkthdr.csum_flags |= 1349231437Sluigi (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1350231437Sluigi pd->mbuf->m_pkthdr.csum_data = 0xffff; 1351231437Sluigi } 1352231437Sluigi if (cqe->u0.s.ip_cksum_pass) { 1353231879Sluigi if (!cqe->u0.s.ip_ver) { /* IPV4 */ 1354231437Sluigi pd->mbuf->m_pkthdr.csum_flags |= 1355231437Sluigi (CSUM_IP_CHECKED|CSUM_IP_VALID); 1356231437Sluigi } 1357231437Sluigi } 1358231437Sluigi } 1359231437Sluigi m = tail = pd->mbuf; 1360231437Sluigi } 1361231437Sluigi pd->mbuf = NULL; 1362231437Sluigi len -= frag_len; 1363231437Sluigi } 1364231437Sluigi 1365231437Sluigi if (m) { 1366231437Sluigi if (!oce_cqe_portid_valid(sc, cqe)) { 1367231437Sluigi m_freem(m); 1368231437Sluigi goto exit; 1369231437Sluigi } 1370231437Sluigi 1371231437Sluigi m->m_pkthdr.rcvif = sc->ifp; 1372231437Sluigi#if __FreeBSD_version >= 800000 1373252869Sdelphij if (rq->queue_index) 1374252869Sdelphij m->m_pkthdr.flowid = (rq->queue_index - 1); 1375252869Sdelphij else 1376252869Sdelphij m->m_pkthdr.flowid = rq->queue_index; 1377231437Sluigi m->m_flags |= M_FLOWID; 1378231437Sluigi#endif 1379231879Sluigi /* This deternies if vlan tag is Valid */ 1380231437Sluigi if (oce_cqe_vtp_valid(sc, cqe)) { 1381231437Sluigi if (sc->function_mode & FNM_FLEX10_MODE) { 1382231879Sluigi /* FLEX10. If QnQ is not set, neglect VLAN */ 1383231437Sluigi if (cqe->u0.s.qnq) { 1384231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1385231437Sluigi m->m_flags |= M_VLANTAG; 1386231437Sluigi } 1387231879Sluigi } else if (sc->pvid != (vtag & VLAN_VID_MASK)) { 1388231879Sluigi /* In UMC mode generally pvid will be striped by 1389231879Sluigi hw. But in some cases we have seen it comes 1390231879Sluigi with pvid. So if pvid == vlan, neglect vlan. 1391231879Sluigi */ 1392231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1393231437Sluigi m->m_flags |= M_VLANTAG; 1394231437Sluigi } 1395231437Sluigi } 1396231437Sluigi 1397231437Sluigi sc->ifp->if_ipackets++; 1398231511Sbz#if defined(INET6) || defined(INET) 1399231437Sluigi /* Try to queue to LRO */ 1400231437Sluigi if (IF_LRO_ENABLED(sc) && 1401231437Sluigi (cqe->u0.s.ip_cksum_pass) && 1402231437Sluigi (cqe->u0.s.l4_cksum_pass) && 1403231437Sluigi (!cqe->u0.s.ip_ver) && 1404231437Sluigi (rq->lro.lro_cnt != 0)) { 1405231437Sluigi 1406231437Sluigi if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 1407231437Sluigi rq->lro_pkts_queued ++; 1408231437Sluigi goto post_done; 1409231437Sluigi } 1410231437Sluigi /* If LRO posting fails then try to post to STACK */ 1411231437Sluigi } 1412231511Sbz#endif 1413231437Sluigi 1414231437Sluigi (*sc->ifp->if_input) (sc->ifp, m); 1415231511Sbz#if defined(INET6) || defined(INET) 1416231437Sluigipost_done: 1417231511Sbz#endif 1418231437Sluigi /* Update rx stats per queue */ 1419231437Sluigi rq->rx_stats.rx_pkts++; 1420231437Sluigi rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 1421231437Sluigi rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 1422231437Sluigi if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 1423231437Sluigi rq->rx_stats.rx_mcast_pkts++; 1424231437Sluigi if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 1425231437Sluigi rq->rx_stats.rx_ucast_pkts++; 1426231437Sluigi } 1427231437Sluigiexit: 1428231437Sluigi return; 1429231437Sluigi} 1430231437Sluigi 1431231437Sluigi 1432231437Sluigistatic void 1433231437Sluigioce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1434231437Sluigi{ 1435231437Sluigi uint32_t out, i = 0; 1436231437Sluigi struct oce_packet_desc *pd; 1437231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1438231437Sluigi int num_frags = cqe->u0.s.num_fragments; 1439231437Sluigi 1440231437Sluigi for (i = 0; i < num_frags; i++) { 1441231437Sluigi if (rq->packets_out == rq->packets_in) { 1442231437Sluigi device_printf(sc->dev, 1443231437Sluigi "RQ transmit descriptor missing\n"); 1444231437Sluigi } 1445231437Sluigi out = rq->packets_out + 1; 1446231437Sluigi if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1447231437Sluigi out = 0; 1448231437Sluigi pd = &rq->pckts[rq->packets_out]; 1449231437Sluigi rq->packets_out = out; 1450231437Sluigi 1451231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1452231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1453231437Sluigi rq->pending--; 1454231437Sluigi m_freem(pd->mbuf); 1455231437Sluigi } 1456231437Sluigi 1457231437Sluigi} 1458231437Sluigi 1459231437Sluigi 1460231437Sluigistatic int 1461231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1462231437Sluigi{ 1463231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1464231437Sluigi int vtp = 0; 1465231437Sluigi 1466231437Sluigi if (sc->be3_native) { 1467231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1468231437Sluigi vtp = cqe_v1->u0.s.vlan_tag_present; 1469231879Sluigi } else 1470231437Sluigi vtp = cqe->u0.s.vlan_tag_present; 1471231437Sluigi 1472231437Sluigi return vtp; 1473231437Sluigi 1474231437Sluigi} 1475231437Sluigi 1476231437Sluigi 1477231437Sluigistatic int 1478231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1479231437Sluigi{ 1480231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1481231437Sluigi int port_id = 0; 1482231437Sluigi 1483252869Sdelphij if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) { 1484231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1485231437Sluigi port_id = cqe_v1->u0.s.port; 1486231437Sluigi if (sc->port_id != port_id) 1487231437Sluigi return 0; 1488231437Sluigi } else 1489231437Sluigi ;/* For BE3 legacy and Lancer this is dummy */ 1490231437Sluigi 1491231437Sluigi return 1; 1492231437Sluigi 1493231437Sluigi} 1494231437Sluigi 1495231511Sbz#if defined(INET6) || defined(INET) 1496231437Sluigistatic void 1497231437Sluigioce_rx_flush_lro(struct oce_rq *rq) 1498231437Sluigi{ 1499231437Sluigi struct lro_ctrl *lro = &rq->lro; 1500231437Sluigi struct lro_entry *queued; 1501231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1502231437Sluigi 1503231437Sluigi if (!IF_LRO_ENABLED(sc)) 1504231437Sluigi return; 1505231437Sluigi 1506231437Sluigi while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { 1507231437Sluigi SLIST_REMOVE_HEAD(&lro->lro_active, next); 1508231437Sluigi tcp_lro_flush(lro, queued); 1509231437Sluigi } 1510231437Sluigi rq->lro_pkts_queued = 0; 1511231437Sluigi 1512231437Sluigi return; 1513231437Sluigi} 1514231437Sluigi 1515231437Sluigi 1516231437Sluigistatic int 1517231437Sluigioce_init_lro(POCE_SOFTC sc) 1518231437Sluigi{ 1519231437Sluigi struct lro_ctrl *lro = NULL; 1520231437Sluigi int i = 0, rc = 0; 1521231437Sluigi 1522231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1523231437Sluigi lro = &sc->rq[i]->lro; 1524231437Sluigi rc = tcp_lro_init(lro); 1525231437Sluigi if (rc != 0) { 1526231437Sluigi device_printf(sc->dev, "LRO init failed\n"); 1527231437Sluigi return rc; 1528231437Sluigi } 1529231437Sluigi lro->ifp = sc->ifp; 1530231437Sluigi } 1531231437Sluigi 1532231437Sluigi return rc; 1533231437Sluigi} 1534231437Sluigi 1535231879Sluigi 1536231437Sluigivoid 1537231437Sluigioce_free_lro(POCE_SOFTC sc) 1538231437Sluigi{ 1539231437Sluigi struct lro_ctrl *lro = NULL; 1540231437Sluigi int i = 0; 1541231437Sluigi 1542231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1543231437Sluigi lro = &sc->rq[i]->lro; 1544231437Sluigi if (lro) 1545231437Sluigi tcp_lro_free(lro); 1546231437Sluigi } 1547231437Sluigi} 1548247880Sdelphij#endif 1549231437Sluigi 1550231437Sluigiint 1551231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count) 1552231437Sluigi{ 1553231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1554231437Sluigi int i, in, rc; 1555231437Sluigi struct oce_packet_desc *pd; 1556231437Sluigi bus_dma_segment_t segs[6]; 1557231437Sluigi int nsegs, added = 0; 1558231437Sluigi struct oce_nic_rqe *rqe; 1559231437Sluigi pd_rxulp_db_t rxdb_reg; 1560231437Sluigi 1561247880Sdelphij bzero(&rxdb_reg, sizeof(pd_rxulp_db_t)); 1562231437Sluigi for (i = 0; i < count; i++) { 1563231437Sluigi in = rq->packets_in + 1; 1564231437Sluigi if (in == OCE_RQ_PACKET_ARRAY_SIZE) 1565231437Sluigi in = 0; 1566231437Sluigi if (in == rq->packets_out) 1567231437Sluigi break; /* no more room */ 1568231437Sluigi 1569231437Sluigi pd = &rq->pckts[rq->packets_in]; 1570243857Sglebius pd->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1571231437Sluigi if (pd->mbuf == NULL) 1572231437Sluigi break; 1573231437Sluigi 1574231437Sluigi pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES; 1575231437Sluigi rc = bus_dmamap_load_mbuf_sg(rq->tag, 1576231437Sluigi pd->map, 1577231437Sluigi pd->mbuf, 1578231437Sluigi segs, &nsegs, BUS_DMA_NOWAIT); 1579231437Sluigi if (rc) { 1580231437Sluigi m_free(pd->mbuf); 1581231437Sluigi break; 1582231437Sluigi } 1583231437Sluigi 1584231437Sluigi if (nsegs != 1) { 1585231437Sluigi i--; 1586231437Sluigi continue; 1587231437Sluigi } 1588231437Sluigi 1589231437Sluigi rq->packets_in = in; 1590231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 1591231437Sluigi 1592231437Sluigi rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 1593231437Sluigi rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 1594231437Sluigi rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 1595231437Sluigi DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 1596231437Sluigi RING_PUT(rq->ring, 1); 1597231437Sluigi added++; 1598231437Sluigi rq->pending++; 1599231437Sluigi } 1600231437Sluigi if (added != 0) { 1601231437Sluigi for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) { 1602231437Sluigi rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS; 1603231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1604231437Sluigi OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1605231437Sluigi added -= OCE_MAX_RQ_POSTS; 1606231437Sluigi } 1607231437Sluigi if (added > 0) { 1608231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1609231437Sluigi rxdb_reg.bits.num_posted = added; 1610231437Sluigi OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1611231437Sluigi } 1612231437Sluigi } 1613231437Sluigi 1614231437Sluigi return 0; 1615231437Sluigi} 1616231437Sluigi 1617231437Sluigi 1618231437Sluigi/* Handle the Completion Queue for receive */ 1619231437Sluigiuint16_t 1620231437Sluigioce_rq_handler(void *arg) 1621231437Sluigi{ 1622231437Sluigi struct oce_rq *rq = (struct oce_rq *)arg; 1623231437Sluigi struct oce_cq *cq = rq->cq; 1624231437Sluigi POCE_SOFTC sc = rq->parent; 1625231437Sluigi struct oce_nic_rx_cqe *cqe; 1626231437Sluigi int num_cqes = 0, rq_buffers_used = 0; 1627231437Sluigi 1628231437Sluigi 1629231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1630231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1631231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1632231437Sluigi while (cqe->u0.dw[2]) { 1633231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 1634231437Sluigi 1635231437Sluigi RING_GET(rq->ring, 1); 1636231437Sluigi if (cqe->u0.s.error == 0) { 1637231437Sluigi oce_rx(rq, cqe->u0.s.frag_index, cqe); 1638231437Sluigi } else { 1639231437Sluigi rq->rx_stats.rxcp_err++; 1640231437Sluigi sc->ifp->if_ierrors++; 1641247880Sdelphij /* Post L3/L4 errors to stack.*/ 1642247880Sdelphij oce_rx(rq, cqe->u0.s.frag_index, cqe); 1643231437Sluigi } 1644231437Sluigi rq->rx_stats.rx_compl++; 1645231437Sluigi cqe->u0.dw[2] = 0; 1646231437Sluigi 1647231511Sbz#if defined(INET6) || defined(INET) 1648231437Sluigi if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 1649231437Sluigi oce_rx_flush_lro(rq); 1650231437Sluigi } 1651231511Sbz#endif 1652231437Sluigi 1653231437Sluigi RING_GET(cq->ring, 1); 1654231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1655231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1656231437Sluigi cqe = 1657231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1658231437Sluigi num_cqes++; 1659231437Sluigi if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 1660231437Sluigi break; 1661231437Sluigi } 1662231879Sluigi 1663231511Sbz#if defined(INET6) || defined(INET) 1664231437Sluigi if (IF_LRO_ENABLED(sc)) 1665231437Sluigi oce_rx_flush_lro(rq); 1666231511Sbz#endif 1667231437Sluigi 1668231437Sluigi if (num_cqes) { 1669231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1670231437Sluigi rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending; 1671231437Sluigi if (rq_buffers_used > 1) 1672231437Sluigi oce_alloc_rx_bufs(rq, (rq_buffers_used - 1)); 1673231437Sluigi } 1674231437Sluigi 1675231437Sluigi return 0; 1676231437Sluigi 1677231437Sluigi} 1678231437Sluigi 1679231437Sluigi 1680231437Sluigi 1681231437Sluigi 1682231437Sluigi/***************************************************************************** 1683231437Sluigi * Helper function prototypes in this file * 1684231437Sluigi *****************************************************************************/ 1685231437Sluigi 1686231437Sluigistatic int 1687231437Sluigioce_attach_ifp(POCE_SOFTC sc) 1688231437Sluigi{ 1689231437Sluigi 1690231437Sluigi sc->ifp = if_alloc(IFT_ETHER); 1691231437Sluigi if (!sc->ifp) 1692231437Sluigi return ENOMEM; 1693231437Sluigi 1694231437Sluigi ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 1695231437Sluigi ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1696231437Sluigi ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 1697231437Sluigi 1698231437Sluigi sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 1699231437Sluigi sc->ifp->if_ioctl = oce_ioctl; 1700231437Sluigi sc->ifp->if_start = oce_start; 1701231437Sluigi sc->ifp->if_init = oce_init; 1702231437Sluigi sc->ifp->if_mtu = ETHERMTU; 1703231437Sluigi sc->ifp->if_softc = sc; 1704231437Sluigi#if __FreeBSD_version >= 800000 1705231437Sluigi sc->ifp->if_transmit = oce_multiq_start; 1706231437Sluigi sc->ifp->if_qflush = oce_multiq_flush; 1707231437Sluigi#endif 1708231437Sluigi 1709231437Sluigi if_initname(sc->ifp, 1710231437Sluigi device_get_name(sc->dev), device_get_unit(sc->dev)); 1711231437Sluigi 1712231437Sluigi sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 1713231437Sluigi IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 1714231437Sluigi IFQ_SET_READY(&sc->ifp->if_snd); 1715231437Sluigi 1716231437Sluigi sc->ifp->if_hwassist = OCE_IF_HWASSIST; 1717231437Sluigi sc->ifp->if_hwassist |= CSUM_TSO; 1718231437Sluigi sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 1719231437Sluigi 1720231437Sluigi sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 1721231437Sluigi sc->ifp->if_capabilities |= IFCAP_HWCSUM; 1722231437Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 1723231879Sluigi 1724231511Sbz#if defined(INET6) || defined(INET) 1725231511Sbz sc->ifp->if_capabilities |= IFCAP_TSO; 1726231437Sluigi sc->ifp->if_capabilities |= IFCAP_LRO; 1727231879Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 1728231511Sbz#endif 1729231437Sluigi 1730231437Sluigi sc->ifp->if_capenable = sc->ifp->if_capabilities; 1731263102Sglebius sc->ifp->if_baudrate = IF_Gbps(10); 1732231437Sluigi 1733257007Sdelphij#if __FreeBSD_version >= 1000000 1734257007Sdelphij sc->ifp->if_hw_tsomax = OCE_MAX_TSO_SIZE; 1735257007Sdelphij#endif 1736257007Sdelphij 1737231437Sluigi ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 1738231437Sluigi 1739231437Sluigi return 0; 1740231437Sluigi} 1741231437Sluigi 1742231437Sluigi 1743231437Sluigistatic void 1744231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1745231437Sluigi{ 1746231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1747231437Sluigi 1748231437Sluigi if (ifp->if_softc != arg) 1749231437Sluigi return; 1750231437Sluigi if ((vtag == 0) || (vtag > 4095)) 1751231437Sluigi return; 1752231437Sluigi 1753231437Sluigi sc->vlan_tag[vtag] = 1; 1754231437Sluigi sc->vlans_added++; 1755257007Sdelphij if (sc->vlans_added <= (sc->max_vlans + 1)) 1756257007Sdelphij oce_vid_config(sc); 1757231437Sluigi} 1758231437Sluigi 1759231437Sluigi 1760231437Sluigistatic void 1761231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1762231437Sluigi{ 1763231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1764231437Sluigi 1765231437Sluigi if (ifp->if_softc != arg) 1766231437Sluigi return; 1767231437Sluigi if ((vtag == 0) || (vtag > 4095)) 1768231437Sluigi return; 1769231437Sluigi 1770231437Sluigi sc->vlan_tag[vtag] = 0; 1771231437Sluigi sc->vlans_added--; 1772231437Sluigi oce_vid_config(sc); 1773231437Sluigi} 1774231437Sluigi 1775231437Sluigi 1776231437Sluigi/* 1777231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures 1778231437Sluigi * more, place the card in vlan promiscuous mode. 1779231437Sluigi */ 1780231437Sluigistatic int 1781231437Sluigioce_vid_config(POCE_SOFTC sc) 1782231437Sluigi{ 1783231437Sluigi struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 1784231437Sluigi uint16_t ntags = 0, i; 1785231437Sluigi int status = 0; 1786231437Sluigi 1787231437Sluigi if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 1788231437Sluigi (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 1789231437Sluigi for (i = 0; i < MAX_VLANS; i++) { 1790231437Sluigi if (sc->vlan_tag[i]) { 1791231437Sluigi vtags[ntags].vtag = i; 1792231437Sluigi ntags++; 1793231437Sluigi } 1794231437Sluigi } 1795231437Sluigi if (ntags) 1796231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1797231437Sluigi vtags, ntags, 1, 0); 1798231437Sluigi } else 1799231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1800231437Sluigi NULL, 0, 1, 1); 1801231437Sluigi return status; 1802231437Sluigi} 1803231437Sluigi 1804231437Sluigi 1805231437Sluigistatic void 1806231437Sluigioce_mac_addr_set(POCE_SOFTC sc) 1807231437Sluigi{ 1808231437Sluigi uint32_t old_pmac_id = sc->pmac_id; 1809231437Sluigi int status = 0; 1810231437Sluigi 1811231437Sluigi 1812231437Sluigi status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1813231437Sluigi sc->macaddr.size_of_struct); 1814231437Sluigi if (!status) 1815231437Sluigi return; 1816231437Sluigi 1817231437Sluigi status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 1818231437Sluigi sc->if_id, &sc->pmac_id); 1819231437Sluigi if (!status) { 1820231437Sluigi status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 1821231437Sluigi bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1822231437Sluigi sc->macaddr.size_of_struct); 1823231437Sluigi } 1824231437Sluigi if (status) 1825231437Sluigi device_printf(sc->dev, "Failed update macaddress\n"); 1826231437Sluigi 1827231437Sluigi} 1828231437Sluigi 1829231437Sluigi 1830231437Sluigistatic int 1831231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data) 1832231437Sluigi{ 1833231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1834231437Sluigi struct ifreq *ifr = (struct ifreq *)data; 1835231437Sluigi int rc = ENXIO; 1836231437Sluigi char cookie[32] = {0}; 1837231437Sluigi void *priv_data = (void *)ifr->ifr_data; 1838231437Sluigi void *ioctl_ptr; 1839231437Sluigi uint32_t req_size; 1840231437Sluigi struct mbx_hdr req; 1841231437Sluigi OCE_DMA_MEM dma_mem; 1842247880Sdelphij struct mbx_common_get_cntl_attr *fw_cmd; 1843231437Sluigi 1844231437Sluigi if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 1845231437Sluigi return EFAULT; 1846247880Sdelphij 1847231437Sluigi if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 1848231437Sluigi return EINVAL; 1849247880Sdelphij 1850231437Sluigi ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 1851231437Sluigi if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 1852231437Sluigi return EFAULT; 1853247880Sdelphij 1854231437Sluigi req_size = le32toh(req.u0.req.request_length); 1855231437Sluigi if (req_size > 65536) 1856231437Sluigi return EINVAL; 1857231437Sluigi 1858231437Sluigi req_size += sizeof(struct mbx_hdr); 1859231437Sluigi rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 1860231437Sluigi if (rc) 1861231437Sluigi return ENOMEM; 1862231437Sluigi 1863231437Sluigi if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 1864231437Sluigi rc = EFAULT; 1865231437Sluigi goto dma_free; 1866231437Sluigi } 1867231437Sluigi 1868231437Sluigi rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 1869231437Sluigi if (rc) { 1870231437Sluigi rc = EIO; 1871231437Sluigi goto dma_free; 1872231437Sluigi } 1873231437Sluigi 1874231437Sluigi if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 1875231437Sluigi rc = EFAULT; 1876231437Sluigi 1877247880Sdelphij /* 1878247880Sdelphij firmware is filling all the attributes for this ioctl except 1879247880Sdelphij the driver version..so fill it 1880247880Sdelphij */ 1881247880Sdelphij if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) { 1882247880Sdelphij fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr; 1883247880Sdelphij strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str, 1884247880Sdelphij COMPONENT_REVISION, strlen(COMPONENT_REVISION)); 1885247880Sdelphij } 1886247880Sdelphij 1887231437Sluigidma_free: 1888231437Sluigi oce_dma_free(sc, &dma_mem); 1889231437Sluigi return rc; 1890231437Sluigi 1891231437Sluigi} 1892231437Sluigi 1893247880Sdelphijstatic void 1894247880Sdelphijoce_eqd_set_periodic(POCE_SOFTC sc) 1895247880Sdelphij{ 1896247880Sdelphij struct oce_set_eqd set_eqd[OCE_MAX_EQ]; 1897247880Sdelphij struct oce_aic_obj *aic; 1898247880Sdelphij struct oce_eq *eqo; 1899247880Sdelphij uint64_t now = 0, delta; 1900247880Sdelphij int eqd, i, num = 0; 1901247880Sdelphij uint32_t ips = 0; 1902247880Sdelphij int tps; 1903231437Sluigi 1904247880Sdelphij for (i = 0 ; i < sc->neqs; i++) { 1905247880Sdelphij eqo = sc->eq[i]; 1906247880Sdelphij aic = &sc->aic_obj[i]; 1907247880Sdelphij /* When setting the static eq delay from the user space */ 1908247880Sdelphij if (!aic->enable) { 1909247880Sdelphij eqd = aic->et_eqd; 1910247880Sdelphij goto modify_eqd; 1911247880Sdelphij } 1912247880Sdelphij 1913247880Sdelphij now = ticks; 1914247880Sdelphij 1915247880Sdelphij /* Over flow check */ 1916247880Sdelphij if ((now < aic->ticks) || (eqo->intr < aic->intr_prev)) 1917247880Sdelphij goto done; 1918247880Sdelphij 1919247880Sdelphij delta = now - aic->ticks; 1920247880Sdelphij tps = delta/hz; 1921247880Sdelphij 1922247880Sdelphij /* Interrupt rate based on elapsed ticks */ 1923247880Sdelphij if(tps) 1924247880Sdelphij ips = (uint32_t)(eqo->intr - aic->intr_prev) / tps; 1925247880Sdelphij 1926247880Sdelphij if (ips > INTR_RATE_HWM) 1927247880Sdelphij eqd = aic->cur_eqd + 20; 1928247880Sdelphij else if (ips < INTR_RATE_LWM) 1929247880Sdelphij eqd = aic->cur_eqd / 2; 1930247880Sdelphij else 1931247880Sdelphij goto done; 1932247880Sdelphij 1933247880Sdelphij if (eqd < 10) 1934247880Sdelphij eqd = 0; 1935247880Sdelphij 1936247880Sdelphij /* Make sure that the eq delay is in the known range */ 1937247880Sdelphij eqd = min(eqd, aic->max_eqd); 1938247880Sdelphij eqd = max(eqd, aic->min_eqd); 1939247880Sdelphij 1940247880Sdelphijmodify_eqd: 1941247880Sdelphij if (eqd != aic->cur_eqd) { 1942247880Sdelphij set_eqd[num].delay_multiplier = (eqd * 65)/100; 1943247880Sdelphij set_eqd[num].eq_id = eqo->eq_id; 1944247880Sdelphij aic->cur_eqd = eqd; 1945247880Sdelphij num++; 1946247880Sdelphij } 1947247880Sdelphijdone: 1948247880Sdelphij aic->intr_prev = eqo->intr; 1949247880Sdelphij aic->ticks = now; 1950247880Sdelphij } 1951247880Sdelphij 1952247880Sdelphij /* Is there atleast one eq that needs to be modified? */ 1953247880Sdelphij if(num) 1954247880Sdelphij oce_mbox_eqd_modify_periodic(sc, set_eqd, num); 1955247880Sdelphij} 1956247880Sdelphij 1957257007Sdelphijstatic void oce_detect_hw_error(POCE_SOFTC sc) 1958257007Sdelphij{ 1959257007Sdelphij 1960257007Sdelphij uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0; 1961257007Sdelphij uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; 1962257007Sdelphij uint32_t i; 1963257007Sdelphij 1964257007Sdelphij if (sc->hw_error) 1965257007Sdelphij return; 1966257007Sdelphij 1967257007Sdelphij if (IS_XE201(sc)) { 1968257007Sdelphij sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET); 1969257007Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1970257007Sdelphij sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET); 1971257007Sdelphij sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET); 1972257007Sdelphij } 1973257007Sdelphij } else { 1974257007Sdelphij ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW); 1975257007Sdelphij ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH); 1976257007Sdelphij ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK); 1977257007Sdelphij ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK); 1978257007Sdelphij 1979257007Sdelphij ue_low = (ue_low & ~ue_low_mask); 1980257007Sdelphij ue_high = (ue_high & ~ue_high_mask); 1981257007Sdelphij } 1982257007Sdelphij 1983257007Sdelphij /* On certain platforms BE hardware can indicate spurious UEs. 1984257007Sdelphij * Allow the h/w to stop working completely in case of a real UE. 1985257007Sdelphij * Hence not setting the hw_error for UE detection. 1986257007Sdelphij */ 1987257007Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1988257007Sdelphij sc->hw_error = TRUE; 1989257007Sdelphij device_printf(sc->dev, "Error detected in the card\n"); 1990257007Sdelphij } 1991257007Sdelphij 1992257007Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1993257007Sdelphij device_printf(sc->dev, 1994257007Sdelphij "ERR: sliport status 0x%x\n", sliport_status); 1995257007Sdelphij device_printf(sc->dev, 1996257007Sdelphij "ERR: sliport error1 0x%x\n", sliport_err1); 1997257007Sdelphij device_printf(sc->dev, 1998257007Sdelphij "ERR: sliport error2 0x%x\n", sliport_err2); 1999257007Sdelphij } 2000257007Sdelphij 2001257007Sdelphij if (ue_low) { 2002257007Sdelphij for (i = 0; ue_low; ue_low >>= 1, i++) { 2003257007Sdelphij if (ue_low & 1) 2004257007Sdelphij device_printf(sc->dev, "UE: %s bit set\n", 2005257007Sdelphij ue_status_low_desc[i]); 2006257007Sdelphij } 2007257007Sdelphij } 2008257007Sdelphij 2009257007Sdelphij if (ue_high) { 2010257007Sdelphij for (i = 0; ue_high; ue_high >>= 1, i++) { 2011257007Sdelphij if (ue_high & 1) 2012257007Sdelphij device_printf(sc->dev, "UE: %s bit set\n", 2013257007Sdelphij ue_status_hi_desc[i]); 2014257007Sdelphij } 2015257007Sdelphij } 2016257007Sdelphij 2017257007Sdelphij} 2018257007Sdelphij 2019257007Sdelphij 2020231437Sluigistatic void 2021231437Sluigioce_local_timer(void *arg) 2022231437Sluigi{ 2023231437Sluigi POCE_SOFTC sc = arg; 2024231437Sluigi int i = 0; 2025231437Sluigi 2026257007Sdelphij oce_detect_hw_error(sc); 2027231437Sluigi oce_refresh_nic_stats(sc); 2028231437Sluigi oce_refresh_queue_stats(sc); 2029231437Sluigi oce_mac_addr_set(sc); 2030231437Sluigi 2031231437Sluigi /* TX Watch Dog*/ 2032231437Sluigi for (i = 0; i < sc->nwqs; i++) 2033231437Sluigi oce_tx_restart(sc, sc->wq[i]); 2034231437Sluigi 2035247880Sdelphij /* calculate and set the eq delay for optimal interrupt rate */ 2036252869Sdelphij if (IS_BE(sc) || IS_SH(sc)) 2037247880Sdelphij oce_eqd_set_periodic(sc); 2038247880Sdelphij 2039231437Sluigi callout_reset(&sc->timer, hz, oce_local_timer, sc); 2040231437Sluigi} 2041231437Sluigi 2042231437Sluigi 2043246799Sjpaetzel/* NOTE : This should only be called holding 2044246799Sjpaetzel * DEVICE_LOCK. 2045257007Sdelphij */ 2046231437Sluigistatic void 2047231437Sluigioce_if_deactivate(POCE_SOFTC sc) 2048231437Sluigi{ 2049231437Sluigi int i, mtime = 0; 2050231437Sluigi int wait_req = 0; 2051231437Sluigi struct oce_rq *rq; 2052231437Sluigi struct oce_wq *wq; 2053231437Sluigi struct oce_eq *eq; 2054231437Sluigi 2055231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2056231437Sluigi 2057231437Sluigi /*Wait for max of 400ms for TX completions to be done */ 2058231437Sluigi while (mtime < 400) { 2059231437Sluigi wait_req = 0; 2060231437Sluigi for_all_wq_queues(sc, wq, i) { 2061231437Sluigi if (wq->ring->num_used) { 2062231437Sluigi wait_req = 1; 2063231437Sluigi DELAY(1); 2064231437Sluigi break; 2065231437Sluigi } 2066231437Sluigi } 2067231437Sluigi mtime += 1; 2068231437Sluigi if (!wait_req) 2069231437Sluigi break; 2070231437Sluigi } 2071231437Sluigi 2072231437Sluigi /* Stop intrs and finish any bottom halves pending */ 2073231437Sluigi oce_hw_intr_disable(sc); 2074231437Sluigi 2075247880Sdelphij /* Since taskqueue_drain takes a Gaint Lock, We should not acquire 2076247880Sdelphij any other lock. So unlock device lock and require after 2077247880Sdelphij completing taskqueue_drain. 2078247880Sdelphij */ 2079247880Sdelphij UNLOCK(&sc->dev_lock); 2080231437Sluigi for (i = 0; i < sc->intr_count; i++) { 2081231437Sluigi if (sc->intrs[i].tq != NULL) { 2082231437Sluigi taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 2083231437Sluigi } 2084231437Sluigi } 2085247880Sdelphij LOCK(&sc->dev_lock); 2086231437Sluigi 2087231437Sluigi /* Delete RX queue in card with flush param */ 2088231437Sluigi oce_stop_rx(sc); 2089231437Sluigi 2090231437Sluigi /* Invalidate any pending cq and eq entries*/ 2091231437Sluigi for_all_evnt_queues(sc, eq, i) 2092231437Sluigi oce_drain_eq(eq); 2093231437Sluigi for_all_rq_queues(sc, rq, i) 2094231437Sluigi oce_drain_rq_cq(rq); 2095231437Sluigi for_all_wq_queues(sc, wq, i) 2096231437Sluigi oce_drain_wq_cq(wq); 2097231437Sluigi 2098231437Sluigi /* But still we need to get MCC aync events. 2099231437Sluigi So enable intrs and also arm first EQ 2100247880Sdelphij */ 2101231437Sluigi oce_hw_intr_enable(sc); 2102231437Sluigi oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 2103231437Sluigi 2104231437Sluigi DELAY(10); 2105231437Sluigi} 2106231437Sluigi 2107231437Sluigi 2108231437Sluigistatic void 2109231437Sluigioce_if_activate(POCE_SOFTC sc) 2110231437Sluigi{ 2111231437Sluigi struct oce_eq *eq; 2112231437Sluigi struct oce_rq *rq; 2113231437Sluigi struct oce_wq *wq; 2114231437Sluigi int i, rc = 0; 2115231437Sluigi 2116231437Sluigi sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 2117231437Sluigi 2118231437Sluigi oce_hw_intr_disable(sc); 2119231437Sluigi 2120231437Sluigi oce_start_rx(sc); 2121231437Sluigi 2122231437Sluigi for_all_rq_queues(sc, rq, i) { 2123231437Sluigi rc = oce_start_rq(rq); 2124231437Sluigi if (rc) 2125231437Sluigi device_printf(sc->dev, "Unable to start RX\n"); 2126231437Sluigi } 2127231437Sluigi 2128231437Sluigi for_all_wq_queues(sc, wq, i) { 2129231437Sluigi rc = oce_start_wq(wq); 2130231437Sluigi if (rc) 2131231437Sluigi device_printf(sc->dev, "Unable to start TX\n"); 2132231437Sluigi } 2133231437Sluigi 2134231437Sluigi 2135231437Sluigi for_all_evnt_queues(sc, eq, i) 2136231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 2137231437Sluigi 2138231437Sluigi oce_hw_intr_enable(sc); 2139231437Sluigi 2140231437Sluigi} 2141231437Sluigi 2142231879Sluigistatic void 2143231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe) 2144231879Sluigi{ 2145231879Sluigi /* Update Link status */ 2146231879Sluigi if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 2147231879Sluigi ASYNC_EVENT_LINK_UP) { 2148231879Sluigi sc->link_status = ASYNC_EVENT_LINK_UP; 2149231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_UP); 2150231879Sluigi } else { 2151231879Sluigi sc->link_status = ASYNC_EVENT_LINK_DOWN; 2152231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_DOWN); 2153231879Sluigi } 2154231879Sluigi} 2155231879Sluigi 2156231879Sluigi 2157231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */ 2158231437Sluigiuint16_t 2159231437Sluigioce_mq_handler(void *arg) 2160231437Sluigi{ 2161231437Sluigi struct oce_mq *mq = (struct oce_mq *)arg; 2162231437Sluigi POCE_SOFTC sc = mq->parent; 2163231437Sluigi struct oce_cq *cq = mq->cq; 2164231879Sluigi int num_cqes = 0, evt_type = 0, optype = 0; 2165231437Sluigi struct oce_mq_cqe *cqe; 2166231437Sluigi struct oce_async_cqe_link_state *acqe; 2167231879Sluigi struct oce_async_event_grp5_pvid_state *gcqe; 2168247880Sdelphij struct oce_async_event_qnq *dbgcqe; 2169231437Sluigi 2170231879Sluigi 2171231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2172231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2173231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 2174231879Sluigi 2175231437Sluigi while (cqe->u0.dw[3]) { 2176231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 2177231437Sluigi if (cqe->u0.s.async_event) { 2178231879Sluigi evt_type = cqe->u0.s.event_type; 2179231879Sluigi optype = cqe->u0.s.async_type; 2180231879Sluigi if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) { 2181231879Sluigi /* Link status evt */ 2182231879Sluigi acqe = (struct oce_async_cqe_link_state *)cqe; 2183231879Sluigi process_link_state(sc, acqe); 2184231879Sluigi } else if ((evt_type == ASYNC_EVENT_GRP5) && 2185231879Sluigi (optype == ASYNC_EVENT_PVID_STATE)) { 2186231879Sluigi /* GRP5 PVID */ 2187231879Sluigi gcqe = 2188231879Sluigi (struct oce_async_event_grp5_pvid_state *)cqe; 2189231879Sluigi if (gcqe->enabled) 2190231879Sluigi sc->pvid = gcqe->tag & VLAN_VID_MASK; 2191231879Sluigi else 2192231879Sluigi sc->pvid = 0; 2193231879Sluigi 2194231437Sluigi } 2195247880Sdelphij else if(evt_type == ASYNC_EVENT_CODE_DEBUG && 2196247880Sdelphij optype == ASYNC_EVENT_DEBUG_QNQ) { 2197247880Sdelphij dbgcqe = 2198247880Sdelphij (struct oce_async_event_qnq *)cqe; 2199247880Sdelphij if(dbgcqe->valid) 2200247880Sdelphij sc->qnqid = dbgcqe->vlan_tag; 2201247880Sdelphij sc->qnq_debug_event = TRUE; 2202247880Sdelphij } 2203231437Sluigi } 2204231437Sluigi cqe->u0.dw[3] = 0; 2205231437Sluigi RING_GET(cq->ring, 1); 2206231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2207231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2208231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 2209231437Sluigi num_cqes++; 2210231437Sluigi } 2211231437Sluigi 2212231437Sluigi if (num_cqes) 2213231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 2214231437Sluigi 2215231437Sluigi return 0; 2216231437Sluigi} 2217231437Sluigi 2218231437Sluigi 2219231437Sluigistatic void 2220231437Sluigisetup_max_queues_want(POCE_SOFTC sc) 2221231437Sluigi{ 2222231437Sluigi /* Check if it is FLEX machine. Is so dont use RSS */ 2223231437Sluigi if ((sc->function_mode & FNM_FLEX10_MODE) || 2224231879Sluigi (sc->function_mode & FNM_UMC_MODE) || 2225231879Sluigi (sc->function_mode & FNM_VNIC_MODE) || 2226252869Sdelphij (!is_rss_enabled(sc)) || 2227267839Sdelphij IS_BE2(sc)) { 2228231437Sluigi sc->nrqs = 1; 2229231437Sluigi sc->nwqs = 1; 2230257007Sdelphij } else { 2231257007Sdelphij sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 2232257007Sdelphij sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs); 2233231437Sluigi } 2234267839Sdelphij 2235267839Sdelphij if (IS_BE2(sc) && is_rss_enabled(sc)) 2236267839Sdelphij sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 2237231437Sluigi} 2238231437Sluigi 2239231437Sluigi 2240231437Sluigistatic void 2241231437Sluigiupdate_queues_got(POCE_SOFTC sc) 2242231437Sluigi{ 2243252869Sdelphij if (is_rss_enabled(sc)) { 2244231437Sluigi sc->nrqs = sc->intr_count + 1; 2245231437Sluigi sc->nwqs = sc->intr_count; 2246231437Sluigi } else { 2247231437Sluigi sc->nrqs = 1; 2248231437Sluigi sc->nwqs = 1; 2249231437Sluigi } 2250267839Sdelphij 2251267839Sdelphij if (IS_BE2(sc)) 2252267839Sdelphij sc->nwqs = 1; 2253231437Sluigi} 2254231437Sluigi 2255247880Sdelphijstatic int 2256247880Sdelphijoce_check_ipv6_ext_hdr(struct mbuf *m) 2257247880Sdelphij{ 2258247880Sdelphij struct ether_header *eh = mtod(m, struct ether_header *); 2259247880Sdelphij caddr_t m_datatemp = m->m_data; 2260247880Sdelphij 2261247880Sdelphij if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 2262247880Sdelphij m->m_data += sizeof(struct ether_header); 2263247880Sdelphij struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 2264247880Sdelphij 2265247880Sdelphij if((ip6->ip6_nxt != IPPROTO_TCP) && \ 2266247880Sdelphij (ip6->ip6_nxt != IPPROTO_UDP)){ 2267247880Sdelphij struct ip6_ext *ip6e = NULL; 2268247880Sdelphij m->m_data += sizeof(struct ip6_hdr); 2269247880Sdelphij 2270247880Sdelphij ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *); 2271247880Sdelphij if(ip6e->ip6e_len == 0xff) { 2272247880Sdelphij m->m_data = m_datatemp; 2273247880Sdelphij return TRUE; 2274247880Sdelphij } 2275247880Sdelphij } 2276247880Sdelphij m->m_data = m_datatemp; 2277247880Sdelphij } 2278247880Sdelphij return FALSE; 2279247880Sdelphij} 2280247880Sdelphij 2281247880Sdelphijstatic int 2282247880Sdelphijis_be3_a1(POCE_SOFTC sc) 2283247880Sdelphij{ 2284247880Sdelphij if((sc->flags & OCE_FLAGS_BE3) && ((sc->asic_revision & 0xFF) < 2)) { 2285247880Sdelphij return TRUE; 2286247880Sdelphij } 2287247880Sdelphij return FALSE; 2288247880Sdelphij} 2289247880Sdelphij 2290247880Sdelphijstatic struct mbuf * 2291247880Sdelphijoce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete) 2292247880Sdelphij{ 2293247880Sdelphij uint16_t vlan_tag = 0; 2294247880Sdelphij 2295247880Sdelphij if(!M_WRITABLE(m)) 2296247880Sdelphij return NULL; 2297247880Sdelphij 2298247880Sdelphij /* Embed vlan tag in the packet if it is not part of it */ 2299247880Sdelphij if(m->m_flags & M_VLANTAG) { 2300247880Sdelphij vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 2301247880Sdelphij m->m_flags &= ~M_VLANTAG; 2302247880Sdelphij } 2303247880Sdelphij 2304247880Sdelphij /* if UMC, ignore vlan tag insertion and instead insert pvid */ 2305247880Sdelphij if(sc->pvid) { 2306247880Sdelphij if(!vlan_tag) 2307247880Sdelphij vlan_tag = sc->pvid; 2308247880Sdelphij *complete = FALSE; 2309247880Sdelphij } 2310247880Sdelphij 2311247880Sdelphij if(vlan_tag) { 2312247880Sdelphij m = ether_vlanencap(m, vlan_tag); 2313247880Sdelphij } 2314247880Sdelphij 2315247880Sdelphij if(sc->qnqid) { 2316247880Sdelphij m = ether_vlanencap(m, sc->qnqid); 2317247880Sdelphij *complete = FALSE; 2318247880Sdelphij } 2319247880Sdelphij return m; 2320247880Sdelphij} 2321247880Sdelphij 2322247880Sdelphijstatic int 2323247880Sdelphijoce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m) 2324247880Sdelphij{ 2325247880Sdelphij if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \ 2326247880Sdelphij oce_check_ipv6_ext_hdr(m)) { 2327247880Sdelphij return TRUE; 2328247880Sdelphij } 2329247880Sdelphij return FALSE; 2330247880Sdelphij} 2331252869Sdelphij 2332252869Sdelphijstatic void 2333252869Sdelphijoce_get_config(POCE_SOFTC sc) 2334252869Sdelphij{ 2335252869Sdelphij int rc = 0; 2336252869Sdelphij uint32_t max_rss = 0; 2337252869Sdelphij 2338252869Sdelphij if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native)) 2339252869Sdelphij max_rss = OCE_LEGACY_MODE_RSS; 2340252869Sdelphij else 2341252869Sdelphij max_rss = OCE_MAX_RSS; 2342252869Sdelphij 2343252869Sdelphij if (!IS_BE(sc)) { 2344258941Sdelphij rc = oce_get_profile_config(sc, max_rss); 2345252869Sdelphij if (rc) { 2346252869Sdelphij sc->nwqs = OCE_MAX_WQ; 2347252869Sdelphij sc->nrssqs = max_rss; 2348252869Sdelphij sc->nrqs = sc->nrssqs + 1; 2349252869Sdelphij } 2350252869Sdelphij } 2351258941Sdelphij else { /* For BE3 don't rely on fw for determining the resources */ 2352252869Sdelphij sc->nrssqs = max_rss; 2353252869Sdelphij sc->nrqs = sc->nrssqs + 1; 2354258941Sdelphij sc->nwqs = OCE_MAX_WQ; 2355258941Sdelphij sc->max_vlans = MAX_VLANFILTER_SIZE; 2356252869Sdelphij } 2357252869Sdelphij} 2358