oce_if.c revision 268046
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: stable/10/sys/dev/oce/oce_if.c 268046 2014-06-30 16:23:31Z delphij $ */ 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; 832268046Sdelphij case 5: /* 20 Gbps */ 833268046Sdelphij req->ifm_active |= IFM_10G_SR | IFM_FDX; 834268046Sdelphij sc->speed = 20000; 835268046Sdelphij break; 836268046Sdelphij case 6: /* 25 Gbps */ 837268046Sdelphij req->ifm_active |= IFM_10G_SR | IFM_FDX; 838268046Sdelphij sc->speed = 25000; 839268046Sdelphij break; 840259050Sdelphij case 7: /* 40 Gbps */ 841259050Sdelphij req->ifm_active |= IFM_40G_SR4 | IFM_FDX; 842259050Sdelphij sc->speed = 40000; 843259050Sdelphij break; 844268046Sdelphij default: 845268046Sdelphij sc->speed = 0; 846268046Sdelphij break; 847231437Sluigi } 848231437Sluigi 849231437Sluigi return; 850231437Sluigi} 851231437Sluigi 852231437Sluigi 853231437Sluigiint 854231437Sluigioce_media_change(struct ifnet *ifp) 855231437Sluigi{ 856231437Sluigi return 0; 857231437Sluigi} 858231437Sluigi 859231437Sluigi 860231437Sluigi 861231437Sluigi 862231437Sluigi/***************************************************************************** 863231437Sluigi * Transmit routines functions * 864231437Sluigi *****************************************************************************/ 865231437Sluigi 866231437Sluigistatic int 867231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 868231437Sluigi{ 869231437Sluigi int rc = 0, i, retry_cnt = 0; 870231437Sluigi bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 871231437Sluigi struct mbuf *m, *m_temp; 872231437Sluigi struct oce_wq *wq = sc->wq[wq_index]; 873231437Sluigi struct oce_packet_desc *pd; 874231437Sluigi struct oce_nic_hdr_wqe *nichdr; 875231437Sluigi struct oce_nic_frag_wqe *nicfrag; 876231437Sluigi int num_wqes; 877231437Sluigi uint32_t reg_value; 878247880Sdelphij boolean_t complete = TRUE; 879231437Sluigi 880231437Sluigi m = *mpp; 881231437Sluigi if (!m) 882231437Sluigi return EINVAL; 883231437Sluigi 884231437Sluigi if (!(m->m_flags & M_PKTHDR)) { 885231437Sluigi rc = ENXIO; 886231437Sluigi goto free_ret; 887231437Sluigi } 888231437Sluigi 889247880Sdelphij if(oce_tx_asic_stall_verify(sc, m)) { 890247880Sdelphij m = oce_insert_vlan_tag(sc, m, &complete); 891247880Sdelphij if(!m) { 892247880Sdelphij device_printf(sc->dev, "Insertion unsuccessful\n"); 893247880Sdelphij return 0; 894247880Sdelphij } 895247880Sdelphij 896247880Sdelphij } 897247880Sdelphij 898231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 899231879Sluigi /* consolidate packet buffers for TSO/LSO segment offload */ 900231511Sbz#if defined(INET6) || defined(INET) 901231879Sluigi m = oce_tso_setup(sc, mpp); 902231511Sbz#else 903231511Sbz m = NULL; 904231511Sbz#endif 905231437Sluigi if (m == NULL) { 906231437Sluigi rc = ENXIO; 907231437Sluigi goto free_ret; 908231437Sluigi } 909231437Sluigi } 910231437Sluigi 911252869Sdelphij pd = &wq->pckts[wq->pkt_desc_head]; 912231437Sluigiretry: 913231437Sluigi rc = bus_dmamap_load_mbuf_sg(wq->tag, 914231437Sluigi pd->map, 915231437Sluigi m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 916231437Sluigi if (rc == 0) { 917231437Sluigi num_wqes = pd->nsegs + 1; 918252869Sdelphij if (IS_BE(sc) || IS_SH(sc)) { 919231437Sluigi /*Dummy required only for BE3.*/ 920231437Sluigi if (num_wqes & 1) 921231437Sluigi num_wqes++; 922231437Sluigi } 923231437Sluigi if (num_wqes >= RING_NUM_FREE(wq->ring)) { 924231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 925231437Sluigi return EBUSY; 926231437Sluigi } 927252869Sdelphij atomic_store_rel_int(&wq->pkt_desc_head, 928252869Sdelphij (wq->pkt_desc_head + 1) % \ 929252869Sdelphij OCE_WQ_PACKET_ARRAY_SIZE); 930231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 931231437Sluigi pd->mbuf = m; 932231437Sluigi 933231437Sluigi nichdr = 934231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 935231437Sluigi nichdr->u0.dw[0] = 0; 936231437Sluigi nichdr->u0.dw[1] = 0; 937231437Sluigi nichdr->u0.dw[2] = 0; 938231437Sluigi nichdr->u0.dw[3] = 0; 939231437Sluigi 940247880Sdelphij nichdr->u0.s.complete = complete; 941231437Sluigi nichdr->u0.s.event = 1; 942231437Sluigi nichdr->u0.s.crc = 1; 943231437Sluigi nichdr->u0.s.forward = 0; 944231437Sluigi nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 945231437Sluigi nichdr->u0.s.udpcs = 946247880Sdelphij (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 947231437Sluigi nichdr->u0.s.tcpcs = 948247880Sdelphij (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 949231437Sluigi nichdr->u0.s.num_wqe = num_wqes; 950231437Sluigi nichdr->u0.s.total_length = m->m_pkthdr.len; 951257187Sdelphij 952231437Sluigi if (m->m_flags & M_VLANTAG) { 953231437Sluigi nichdr->u0.s.vlan = 1; /*Vlan present*/ 954231437Sluigi nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 955231437Sluigi } 956257187Sdelphij 957231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 958231437Sluigi if (m->m_pkthdr.tso_segsz) { 959231437Sluigi nichdr->u0.s.lso = 1; 960231437Sluigi nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 961231437Sluigi } 962252869Sdelphij if (!IS_BE(sc) || !IS_SH(sc)) 963231437Sluigi nichdr->u0.s.ipcs = 1; 964231437Sluigi } 965231437Sluigi 966231437Sluigi RING_PUT(wq->ring, 1); 967252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 968231437Sluigi 969231437Sluigi for (i = 0; i < pd->nsegs; i++) { 970231437Sluigi nicfrag = 971231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 972231437Sluigi struct oce_nic_frag_wqe); 973231437Sluigi nicfrag->u0.s.rsvd0 = 0; 974231437Sluigi nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 975231437Sluigi nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 976231437Sluigi nicfrag->u0.s.frag_len = segs[i].ds_len; 977231437Sluigi pd->wqe_idx = wq->ring->pidx; 978231437Sluigi RING_PUT(wq->ring, 1); 979252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 980231437Sluigi } 981231437Sluigi if (num_wqes > (pd->nsegs + 1)) { 982231437Sluigi nicfrag = 983231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 984231437Sluigi struct oce_nic_frag_wqe); 985231437Sluigi nicfrag->u0.dw[0] = 0; 986231437Sluigi nicfrag->u0.dw[1] = 0; 987231437Sluigi nicfrag->u0.dw[2] = 0; 988231437Sluigi nicfrag->u0.dw[3] = 0; 989231437Sluigi pd->wqe_idx = wq->ring->pidx; 990231437Sluigi RING_PUT(wq->ring, 1); 991252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 992231437Sluigi pd->nsegs++; 993231437Sluigi } 994231437Sluigi 995231437Sluigi sc->ifp->if_opackets++; 996231437Sluigi wq->tx_stats.tx_reqs++; 997231437Sluigi wq->tx_stats.tx_wrbs += num_wqes; 998231437Sluigi wq->tx_stats.tx_bytes += m->m_pkthdr.len; 999231437Sluigi wq->tx_stats.tx_pkts++; 1000247880Sdelphij 1001231437Sluigi bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 1002231437Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1003231437Sluigi reg_value = (num_wqes << 16) | wq->wq_id; 1004252869Sdelphij OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value); 1005231437Sluigi 1006231437Sluigi } else if (rc == EFBIG) { 1007231437Sluigi if (retry_cnt == 0) { 1008243857Sglebius m_temp = m_defrag(m, M_NOWAIT); 1009231437Sluigi if (m_temp == NULL) 1010231437Sluigi goto free_ret; 1011231437Sluigi m = m_temp; 1012231437Sluigi *mpp = m_temp; 1013231437Sluigi retry_cnt = retry_cnt + 1; 1014231437Sluigi goto retry; 1015231437Sluigi } else 1016231437Sluigi goto free_ret; 1017231437Sluigi } else if (rc == ENOMEM) 1018231437Sluigi return rc; 1019231437Sluigi else 1020231437Sluigi goto free_ret; 1021252869Sdelphij 1022231437Sluigi return 0; 1023231437Sluigi 1024231437Sluigifree_ret: 1025231437Sluigi m_freem(*mpp); 1026231437Sluigi *mpp = NULL; 1027231437Sluigi return rc; 1028231437Sluigi} 1029231437Sluigi 1030231437Sluigi 1031231437Sluigistatic void 1032231437Sluigioce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status) 1033231437Sluigi{ 1034231437Sluigi struct oce_packet_desc *pd; 1035231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 1036231437Sluigi struct mbuf *m; 1037231437Sluigi 1038252869Sdelphij pd = &wq->pckts[wq->pkt_desc_tail]; 1039252869Sdelphij atomic_store_rel_int(&wq->pkt_desc_tail, 1040252869Sdelphij (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE); 1041252869Sdelphij atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1); 1042231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1043231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 1044231437Sluigi 1045231437Sluigi m = pd->mbuf; 1046231437Sluigi m_freem(m); 1047231437Sluigi pd->mbuf = NULL; 1048231437Sluigi 1049252869Sdelphij 1050231437Sluigi if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1051231437Sluigi if (wq->ring->num_used < (wq->ring->num_items / 2)) { 1052231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 1053231437Sluigi oce_tx_restart(sc, wq); 1054231437Sluigi } 1055231437Sluigi } 1056231437Sluigi} 1057231437Sluigi 1058231437Sluigi 1059231437Sluigistatic void 1060231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 1061231437Sluigi{ 1062231437Sluigi 1063231437Sluigi if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 1064231437Sluigi return; 1065231437Sluigi 1066231437Sluigi#if __FreeBSD_version >= 800000 1067231437Sluigi if (!drbr_empty(sc->ifp, wq->br)) 1068231437Sluigi#else 1069231437Sluigi if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 1070231437Sluigi#endif 1071231437Sluigi taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask); 1072231437Sluigi 1073231437Sluigi} 1074231437Sluigi 1075231879Sluigi 1076231511Sbz#if defined(INET6) || defined(INET) 1077231437Sluigistatic struct mbuf * 1078231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp) 1079231437Sluigi{ 1080231437Sluigi struct mbuf *m; 1081231511Sbz#ifdef INET 1082231437Sluigi struct ip *ip; 1083231511Sbz#endif 1084231511Sbz#ifdef INET6 1085231437Sluigi struct ip6_hdr *ip6; 1086231511Sbz#endif 1087231437Sluigi struct ether_vlan_header *eh; 1088231437Sluigi struct tcphdr *th; 1089231437Sluigi uint16_t etype; 1090231879Sluigi int total_len = 0, ehdrlen = 0; 1091231437Sluigi 1092231437Sluigi m = *mpp; 1093231437Sluigi 1094231437Sluigi if (M_WRITABLE(m) == 0) { 1095243857Sglebius m = m_dup(*mpp, M_NOWAIT); 1096231437Sluigi if (!m) 1097231437Sluigi return NULL; 1098231437Sluigi m_freem(*mpp); 1099231437Sluigi *mpp = m; 1100231437Sluigi } 1101231437Sluigi 1102231437Sluigi eh = mtod(m, struct ether_vlan_header *); 1103231437Sluigi if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 1104231437Sluigi etype = ntohs(eh->evl_proto); 1105231437Sluigi ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1106231437Sluigi } else { 1107231437Sluigi etype = ntohs(eh->evl_encap_proto); 1108231437Sluigi ehdrlen = ETHER_HDR_LEN; 1109231437Sluigi } 1110231437Sluigi 1111231437Sluigi switch (etype) { 1112231511Sbz#ifdef INET 1113231437Sluigi case ETHERTYPE_IP: 1114231437Sluigi ip = (struct ip *)(m->m_data + ehdrlen); 1115231437Sluigi if (ip->ip_p != IPPROTO_TCP) 1116231437Sluigi return NULL; 1117231437Sluigi th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 1118231437Sluigi 1119231437Sluigi total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 1120231437Sluigi break; 1121231511Sbz#endif 1122231511Sbz#ifdef INET6 1123231437Sluigi case ETHERTYPE_IPV6: 1124231437Sluigi ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 1125231437Sluigi if (ip6->ip6_nxt != IPPROTO_TCP) 1126231437Sluigi return NULL; 1127231437Sluigi th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 1128231437Sluigi 1129231437Sluigi total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 1130231437Sluigi break; 1131231511Sbz#endif 1132231437Sluigi default: 1133231437Sluigi return NULL; 1134231437Sluigi } 1135231437Sluigi 1136231437Sluigi m = m_pullup(m, total_len); 1137231437Sluigi if (!m) 1138231437Sluigi return NULL; 1139231437Sluigi *mpp = m; 1140231437Sluigi return m; 1141231437Sluigi 1142231437Sluigi} 1143231511Sbz#endif /* INET6 || INET */ 1144231437Sluigi 1145231437Sluigivoid 1146231437Sluigioce_tx_task(void *arg, int npending) 1147231437Sluigi{ 1148231437Sluigi struct oce_wq *wq = arg; 1149231437Sluigi POCE_SOFTC sc = wq->parent; 1150231437Sluigi struct ifnet *ifp = sc->ifp; 1151231437Sluigi int rc = 0; 1152252869Sdelphij 1153231437Sluigi#if __FreeBSD_version >= 800000 1154252869Sdelphij LOCK(&wq->tx_lock); 1155252869Sdelphij rc = oce_multiq_transmit(ifp, NULL, wq); 1156252869Sdelphij if (rc) { 1157252869Sdelphij device_printf(sc->dev, 1158252869Sdelphij "TX[%d] restart failed\n", wq->queue_index); 1159231437Sluigi } 1160252869Sdelphij UNLOCK(&wq->tx_lock); 1161231437Sluigi#else 1162231437Sluigi oce_start(ifp); 1163231437Sluigi#endif 1164231437Sluigi 1165231437Sluigi} 1166231437Sluigi 1167231437Sluigi 1168231437Sluigivoid 1169231437Sluigioce_start(struct ifnet *ifp) 1170231437Sluigi{ 1171231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1172231437Sluigi struct mbuf *m; 1173231437Sluigi int rc = 0; 1174231879Sluigi int def_q = 0; /* Defualt tx queue is 0*/ 1175231437Sluigi 1176231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1177231437Sluigi IFF_DRV_RUNNING) 1178231437Sluigi return; 1179247880Sdelphij 1180247880Sdelphij if (!sc->link_status) 1181247880Sdelphij return; 1182231437Sluigi 1183231437Sluigi do { 1184231437Sluigi IF_DEQUEUE(&sc->ifp->if_snd, m); 1185231437Sluigi if (m == NULL) 1186231437Sluigi break; 1187231879Sluigi 1188231879Sluigi LOCK(&sc->wq[def_q]->tx_lock); 1189231879Sluigi rc = oce_tx(sc, &m, def_q); 1190231879Sluigi UNLOCK(&sc->wq[def_q]->tx_lock); 1191231437Sluigi if (rc) { 1192231437Sluigi if (m != NULL) { 1193231879Sluigi sc->wq[def_q]->tx_stats.tx_stops ++; 1194231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1195231437Sluigi IFQ_DRV_PREPEND(&ifp->if_snd, m); 1196231437Sluigi m = NULL; 1197231437Sluigi } 1198231437Sluigi break; 1199231437Sluigi } 1200231437Sluigi if (m != NULL) 1201231437Sluigi ETHER_BPF_MTAP(ifp, m); 1202231437Sluigi 1203231879Sluigi } while (TRUE); 1204231437Sluigi 1205231437Sluigi return; 1206231437Sluigi} 1207231437Sluigi 1208231437Sluigi 1209231437Sluigi/* Handle the Completion Queue for transmit */ 1210231437Sluigiuint16_t 1211231437Sluigioce_wq_handler(void *arg) 1212231437Sluigi{ 1213231437Sluigi struct oce_wq *wq = (struct oce_wq *)arg; 1214231437Sluigi POCE_SOFTC sc = wq->parent; 1215231437Sluigi struct oce_cq *cq = wq->cq; 1216231437Sluigi struct oce_nic_tx_cqe *cqe; 1217231437Sluigi int num_cqes = 0; 1218231437Sluigi 1219231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1220231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1221231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1222231437Sluigi while (cqe->u0.dw[3]) { 1223231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 1224231437Sluigi 1225231437Sluigi wq->ring->cidx = cqe->u0.s.wqe_index + 1; 1226231437Sluigi if (wq->ring->cidx >= wq->ring->num_items) 1227231437Sluigi wq->ring->cidx -= wq->ring->num_items; 1228231437Sluigi 1229231437Sluigi oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status); 1230231437Sluigi wq->tx_stats.tx_compl++; 1231231437Sluigi cqe->u0.dw[3] = 0; 1232231437Sluigi RING_GET(cq->ring, 1); 1233231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1234231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1235231437Sluigi cqe = 1236231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1237231437Sluigi num_cqes++; 1238231437Sluigi } 1239231437Sluigi 1240231437Sluigi if (num_cqes) 1241231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1242231437Sluigi 1243231437Sluigi return 0; 1244231437Sluigi} 1245231437Sluigi 1246231437Sluigi 1247231437Sluigistatic int 1248231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 1249231437Sluigi{ 1250231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1251231437Sluigi int status = 0, queue_index = 0; 1252231437Sluigi struct mbuf *next = NULL; 1253231437Sluigi struct buf_ring *br = NULL; 1254231437Sluigi 1255231437Sluigi br = wq->br; 1256231437Sluigi queue_index = wq->queue_index; 1257231437Sluigi 1258231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1259231437Sluigi IFF_DRV_RUNNING) { 1260231437Sluigi if (m != NULL) 1261231437Sluigi status = drbr_enqueue(ifp, br, m); 1262231437Sluigi return status; 1263231437Sluigi } 1264231437Sluigi 1265257187Sdelphij if (m != NULL) { 1266231437Sluigi if ((status = drbr_enqueue(ifp, br, m)) != 0) 1267231437Sluigi return status; 1268246482Srrs } 1269246482Srrs while ((next = drbr_peek(ifp, br)) != NULL) { 1270231437Sluigi if (oce_tx(sc, &next, queue_index)) { 1271246482Srrs if (next == NULL) { 1272246482Srrs drbr_advance(ifp, br); 1273246482Srrs } else { 1274246482Srrs drbr_putback(ifp, br, next); 1275231437Sluigi wq->tx_stats.tx_stops ++; 1276231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1277231437Sluigi status = drbr_enqueue(ifp, br, next); 1278231437Sluigi } 1279231437Sluigi break; 1280231437Sluigi } 1281246482Srrs drbr_advance(ifp, br); 1282241037Sglebius ifp->if_obytes += next->m_pkthdr.len; 1283241037Sglebius if (next->m_flags & M_MCAST) 1284241037Sglebius ifp->if_omcasts++; 1285231437Sluigi ETHER_BPF_MTAP(ifp, next); 1286231437Sluigi } 1287231437Sluigi 1288231437Sluigi return status; 1289231437Sluigi} 1290231437Sluigi 1291231437Sluigi 1292231437Sluigi 1293231437Sluigi 1294231437Sluigi/***************************************************************************** 1295231437Sluigi * Receive routines functions * 1296231437Sluigi *****************************************************************************/ 1297231437Sluigi 1298231437Sluigistatic void 1299231437Sluigioce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe) 1300231437Sluigi{ 1301231437Sluigi uint32_t out; 1302231437Sluigi struct oce_packet_desc *pd; 1303231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1304231437Sluigi int i, len, frag_len; 1305231437Sluigi struct mbuf *m = NULL, *tail = NULL; 1306231437Sluigi uint16_t vtag; 1307231437Sluigi 1308231437Sluigi len = cqe->u0.s.pkt_size; 1309231437Sluigi if (!len) { 1310231437Sluigi /*partial DMA workaround for Lancer*/ 1311231437Sluigi oce_discard_rx_comp(rq, cqe); 1312231437Sluigi goto exit; 1313231437Sluigi } 1314231437Sluigi 1315231879Sluigi /* Get vlan_tag value */ 1316252869Sdelphij if(IS_BE(sc) || IS_SH(sc)) 1317231879Sluigi vtag = BSWAP_16(cqe->u0.s.vlan_tag); 1318231879Sluigi else 1319231879Sluigi vtag = cqe->u0.s.vlan_tag; 1320231879Sluigi 1321231879Sluigi 1322231437Sluigi for (i = 0; i < cqe->u0.s.num_fragments; i++) { 1323231437Sluigi 1324231437Sluigi if (rq->packets_out == rq->packets_in) { 1325231437Sluigi device_printf(sc->dev, 1326231437Sluigi "RQ transmit descriptor missing\n"); 1327231437Sluigi } 1328231437Sluigi out = rq->packets_out + 1; 1329231437Sluigi if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1330231437Sluigi out = 0; 1331231437Sluigi pd = &rq->pckts[rq->packets_out]; 1332231437Sluigi rq->packets_out = out; 1333231437Sluigi 1334231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1335231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1336231437Sluigi rq->pending--; 1337231437Sluigi 1338231437Sluigi frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 1339231437Sluigi pd->mbuf->m_len = frag_len; 1340231437Sluigi 1341231437Sluigi if (tail != NULL) { 1342231437Sluigi /* additional fragments */ 1343231437Sluigi pd->mbuf->m_flags &= ~M_PKTHDR; 1344231437Sluigi tail->m_next = pd->mbuf; 1345231437Sluigi tail = pd->mbuf; 1346231437Sluigi } else { 1347231437Sluigi /* first fragment, fill out much of the packet header */ 1348231437Sluigi pd->mbuf->m_pkthdr.len = len; 1349231437Sluigi pd->mbuf->m_pkthdr.csum_flags = 0; 1350231437Sluigi if (IF_CSUM_ENABLED(sc)) { 1351231437Sluigi if (cqe->u0.s.l4_cksum_pass) { 1352231437Sluigi pd->mbuf->m_pkthdr.csum_flags |= 1353231437Sluigi (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1354231437Sluigi pd->mbuf->m_pkthdr.csum_data = 0xffff; 1355231437Sluigi } 1356231437Sluigi if (cqe->u0.s.ip_cksum_pass) { 1357231879Sluigi if (!cqe->u0.s.ip_ver) { /* IPV4 */ 1358231437Sluigi pd->mbuf->m_pkthdr.csum_flags |= 1359231437Sluigi (CSUM_IP_CHECKED|CSUM_IP_VALID); 1360231437Sluigi } 1361231437Sluigi } 1362231437Sluigi } 1363231437Sluigi m = tail = pd->mbuf; 1364231437Sluigi } 1365231437Sluigi pd->mbuf = NULL; 1366231437Sluigi len -= frag_len; 1367231437Sluigi } 1368231437Sluigi 1369231437Sluigi if (m) { 1370231437Sluigi if (!oce_cqe_portid_valid(sc, cqe)) { 1371231437Sluigi m_freem(m); 1372231437Sluigi goto exit; 1373231437Sluigi } 1374231437Sluigi 1375231437Sluigi m->m_pkthdr.rcvif = sc->ifp; 1376231437Sluigi#if __FreeBSD_version >= 800000 1377252869Sdelphij if (rq->queue_index) 1378252869Sdelphij m->m_pkthdr.flowid = (rq->queue_index - 1); 1379252869Sdelphij else 1380252869Sdelphij m->m_pkthdr.flowid = rq->queue_index; 1381231437Sluigi m->m_flags |= M_FLOWID; 1382231437Sluigi#endif 1383231879Sluigi /* This deternies if vlan tag is Valid */ 1384231437Sluigi if (oce_cqe_vtp_valid(sc, cqe)) { 1385231437Sluigi if (sc->function_mode & FNM_FLEX10_MODE) { 1386231879Sluigi /* FLEX10. If QnQ is not set, neglect VLAN */ 1387231437Sluigi if (cqe->u0.s.qnq) { 1388231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1389231437Sluigi m->m_flags |= M_VLANTAG; 1390231437Sluigi } 1391231879Sluigi } else if (sc->pvid != (vtag & VLAN_VID_MASK)) { 1392231879Sluigi /* In UMC mode generally pvid will be striped by 1393231879Sluigi hw. But in some cases we have seen it comes 1394231879Sluigi with pvid. So if pvid == vlan, neglect vlan. 1395231879Sluigi */ 1396231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1397231437Sluigi m->m_flags |= M_VLANTAG; 1398231437Sluigi } 1399231437Sluigi } 1400231437Sluigi 1401231437Sluigi sc->ifp->if_ipackets++; 1402231511Sbz#if defined(INET6) || defined(INET) 1403231437Sluigi /* Try to queue to LRO */ 1404231437Sluigi if (IF_LRO_ENABLED(sc) && 1405231437Sluigi (cqe->u0.s.ip_cksum_pass) && 1406231437Sluigi (cqe->u0.s.l4_cksum_pass) && 1407231437Sluigi (!cqe->u0.s.ip_ver) && 1408231437Sluigi (rq->lro.lro_cnt != 0)) { 1409231437Sluigi 1410231437Sluigi if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 1411231437Sluigi rq->lro_pkts_queued ++; 1412231437Sluigi goto post_done; 1413231437Sluigi } 1414231437Sluigi /* If LRO posting fails then try to post to STACK */ 1415231437Sluigi } 1416231511Sbz#endif 1417231437Sluigi 1418231437Sluigi (*sc->ifp->if_input) (sc->ifp, m); 1419231511Sbz#if defined(INET6) || defined(INET) 1420231437Sluigipost_done: 1421231511Sbz#endif 1422231437Sluigi /* Update rx stats per queue */ 1423231437Sluigi rq->rx_stats.rx_pkts++; 1424231437Sluigi rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 1425231437Sluigi rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 1426231437Sluigi if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 1427231437Sluigi rq->rx_stats.rx_mcast_pkts++; 1428231437Sluigi if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 1429231437Sluigi rq->rx_stats.rx_ucast_pkts++; 1430231437Sluigi } 1431231437Sluigiexit: 1432231437Sluigi return; 1433231437Sluigi} 1434231437Sluigi 1435231437Sluigi 1436231437Sluigistatic void 1437231437Sluigioce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1438231437Sluigi{ 1439231437Sluigi uint32_t out, i = 0; 1440231437Sluigi struct oce_packet_desc *pd; 1441231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1442231437Sluigi int num_frags = cqe->u0.s.num_fragments; 1443231437Sluigi 1444231437Sluigi for (i = 0; i < num_frags; i++) { 1445231437Sluigi if (rq->packets_out == rq->packets_in) { 1446231437Sluigi device_printf(sc->dev, 1447231437Sluigi "RQ transmit descriptor missing\n"); 1448231437Sluigi } 1449231437Sluigi out = rq->packets_out + 1; 1450231437Sluigi if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1451231437Sluigi out = 0; 1452231437Sluigi pd = &rq->pckts[rq->packets_out]; 1453231437Sluigi rq->packets_out = out; 1454231437Sluigi 1455231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1456231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1457231437Sluigi rq->pending--; 1458231437Sluigi m_freem(pd->mbuf); 1459231437Sluigi } 1460231437Sluigi 1461231437Sluigi} 1462231437Sluigi 1463231437Sluigi 1464231437Sluigistatic int 1465231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1466231437Sluigi{ 1467231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1468231437Sluigi int vtp = 0; 1469231437Sluigi 1470231437Sluigi if (sc->be3_native) { 1471231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1472231437Sluigi vtp = cqe_v1->u0.s.vlan_tag_present; 1473231879Sluigi } else 1474231437Sluigi vtp = cqe->u0.s.vlan_tag_present; 1475231437Sluigi 1476231437Sluigi return vtp; 1477231437Sluigi 1478231437Sluigi} 1479231437Sluigi 1480231437Sluigi 1481231437Sluigistatic int 1482231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1483231437Sluigi{ 1484231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1485231437Sluigi int port_id = 0; 1486231437Sluigi 1487252869Sdelphij if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) { 1488231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1489231437Sluigi port_id = cqe_v1->u0.s.port; 1490231437Sluigi if (sc->port_id != port_id) 1491231437Sluigi return 0; 1492231437Sluigi } else 1493231437Sluigi ;/* For BE3 legacy and Lancer this is dummy */ 1494231437Sluigi 1495231437Sluigi return 1; 1496231437Sluigi 1497231437Sluigi} 1498231437Sluigi 1499231511Sbz#if defined(INET6) || defined(INET) 1500231437Sluigistatic void 1501231437Sluigioce_rx_flush_lro(struct oce_rq *rq) 1502231437Sluigi{ 1503231437Sluigi struct lro_ctrl *lro = &rq->lro; 1504231437Sluigi struct lro_entry *queued; 1505231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1506231437Sluigi 1507231437Sluigi if (!IF_LRO_ENABLED(sc)) 1508231437Sluigi return; 1509231437Sluigi 1510231437Sluigi while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { 1511231437Sluigi SLIST_REMOVE_HEAD(&lro->lro_active, next); 1512231437Sluigi tcp_lro_flush(lro, queued); 1513231437Sluigi } 1514231437Sluigi rq->lro_pkts_queued = 0; 1515231437Sluigi 1516231437Sluigi return; 1517231437Sluigi} 1518231437Sluigi 1519231437Sluigi 1520231437Sluigistatic int 1521231437Sluigioce_init_lro(POCE_SOFTC sc) 1522231437Sluigi{ 1523231437Sluigi struct lro_ctrl *lro = NULL; 1524231437Sluigi int i = 0, rc = 0; 1525231437Sluigi 1526231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1527231437Sluigi lro = &sc->rq[i]->lro; 1528231437Sluigi rc = tcp_lro_init(lro); 1529231437Sluigi if (rc != 0) { 1530231437Sluigi device_printf(sc->dev, "LRO init failed\n"); 1531231437Sluigi return rc; 1532231437Sluigi } 1533231437Sluigi lro->ifp = sc->ifp; 1534231437Sluigi } 1535231437Sluigi 1536231437Sluigi return rc; 1537231437Sluigi} 1538231437Sluigi 1539231879Sluigi 1540231437Sluigivoid 1541231437Sluigioce_free_lro(POCE_SOFTC sc) 1542231437Sluigi{ 1543231437Sluigi struct lro_ctrl *lro = NULL; 1544231437Sluigi int i = 0; 1545231437Sluigi 1546231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1547231437Sluigi lro = &sc->rq[i]->lro; 1548231437Sluigi if (lro) 1549231437Sluigi tcp_lro_free(lro); 1550231437Sluigi } 1551231437Sluigi} 1552247880Sdelphij#endif 1553231437Sluigi 1554231437Sluigiint 1555231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count) 1556231437Sluigi{ 1557231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1558231437Sluigi int i, in, rc; 1559231437Sluigi struct oce_packet_desc *pd; 1560231437Sluigi bus_dma_segment_t segs[6]; 1561231437Sluigi int nsegs, added = 0; 1562231437Sluigi struct oce_nic_rqe *rqe; 1563231437Sluigi pd_rxulp_db_t rxdb_reg; 1564231437Sluigi 1565247880Sdelphij bzero(&rxdb_reg, sizeof(pd_rxulp_db_t)); 1566231437Sluigi for (i = 0; i < count; i++) { 1567231437Sluigi in = rq->packets_in + 1; 1568231437Sluigi if (in == OCE_RQ_PACKET_ARRAY_SIZE) 1569231437Sluigi in = 0; 1570231437Sluigi if (in == rq->packets_out) 1571231437Sluigi break; /* no more room */ 1572231437Sluigi 1573231437Sluigi pd = &rq->pckts[rq->packets_in]; 1574243857Sglebius pd->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1575231437Sluigi if (pd->mbuf == NULL) 1576231437Sluigi break; 1577231437Sluigi 1578231437Sluigi pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES; 1579231437Sluigi rc = bus_dmamap_load_mbuf_sg(rq->tag, 1580231437Sluigi pd->map, 1581231437Sluigi pd->mbuf, 1582231437Sluigi segs, &nsegs, BUS_DMA_NOWAIT); 1583231437Sluigi if (rc) { 1584231437Sluigi m_free(pd->mbuf); 1585231437Sluigi break; 1586231437Sluigi } 1587231437Sluigi 1588231437Sluigi if (nsegs != 1) { 1589231437Sluigi i--; 1590231437Sluigi continue; 1591231437Sluigi } 1592231437Sluigi 1593231437Sluigi rq->packets_in = in; 1594231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 1595231437Sluigi 1596231437Sluigi rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 1597231437Sluigi rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 1598231437Sluigi rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 1599231437Sluigi DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 1600231437Sluigi RING_PUT(rq->ring, 1); 1601231437Sluigi added++; 1602231437Sluigi rq->pending++; 1603231437Sluigi } 1604231437Sluigi if (added != 0) { 1605231437Sluigi for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) { 1606231437Sluigi rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS; 1607231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1608231437Sluigi OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1609231437Sluigi added -= OCE_MAX_RQ_POSTS; 1610231437Sluigi } 1611231437Sluigi if (added > 0) { 1612231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1613231437Sluigi rxdb_reg.bits.num_posted = added; 1614231437Sluigi OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1615231437Sluigi } 1616231437Sluigi } 1617231437Sluigi 1618231437Sluigi return 0; 1619231437Sluigi} 1620231437Sluigi 1621231437Sluigi 1622231437Sluigi/* Handle the Completion Queue for receive */ 1623231437Sluigiuint16_t 1624231437Sluigioce_rq_handler(void *arg) 1625231437Sluigi{ 1626231437Sluigi struct oce_rq *rq = (struct oce_rq *)arg; 1627231437Sluigi struct oce_cq *cq = rq->cq; 1628231437Sluigi POCE_SOFTC sc = rq->parent; 1629231437Sluigi struct oce_nic_rx_cqe *cqe; 1630231437Sluigi int num_cqes = 0, rq_buffers_used = 0; 1631231437Sluigi 1632231437Sluigi 1633231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1634231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1635231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1636231437Sluigi while (cqe->u0.dw[2]) { 1637231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 1638231437Sluigi 1639231437Sluigi RING_GET(rq->ring, 1); 1640231437Sluigi if (cqe->u0.s.error == 0) { 1641231437Sluigi oce_rx(rq, cqe->u0.s.frag_index, cqe); 1642231437Sluigi } else { 1643231437Sluigi rq->rx_stats.rxcp_err++; 1644231437Sluigi sc->ifp->if_ierrors++; 1645247880Sdelphij /* Post L3/L4 errors to stack.*/ 1646247880Sdelphij oce_rx(rq, cqe->u0.s.frag_index, cqe); 1647231437Sluigi } 1648231437Sluigi rq->rx_stats.rx_compl++; 1649231437Sluigi cqe->u0.dw[2] = 0; 1650231437Sluigi 1651231511Sbz#if defined(INET6) || defined(INET) 1652231437Sluigi if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 1653231437Sluigi oce_rx_flush_lro(rq); 1654231437Sluigi } 1655231511Sbz#endif 1656231437Sluigi 1657231437Sluigi RING_GET(cq->ring, 1); 1658231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1659231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1660231437Sluigi cqe = 1661231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1662231437Sluigi num_cqes++; 1663231437Sluigi if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 1664231437Sluigi break; 1665231437Sluigi } 1666231879Sluigi 1667231511Sbz#if defined(INET6) || defined(INET) 1668231437Sluigi if (IF_LRO_ENABLED(sc)) 1669231437Sluigi oce_rx_flush_lro(rq); 1670231511Sbz#endif 1671231437Sluigi 1672231437Sluigi if (num_cqes) { 1673231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1674231437Sluigi rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending; 1675231437Sluigi if (rq_buffers_used > 1) 1676231437Sluigi oce_alloc_rx_bufs(rq, (rq_buffers_used - 1)); 1677231437Sluigi } 1678231437Sluigi 1679231437Sluigi return 0; 1680231437Sluigi 1681231437Sluigi} 1682231437Sluigi 1683231437Sluigi 1684231437Sluigi 1685231437Sluigi 1686231437Sluigi/***************************************************************************** 1687231437Sluigi * Helper function prototypes in this file * 1688231437Sluigi *****************************************************************************/ 1689231437Sluigi 1690231437Sluigistatic int 1691231437Sluigioce_attach_ifp(POCE_SOFTC sc) 1692231437Sluigi{ 1693231437Sluigi 1694231437Sluigi sc->ifp = if_alloc(IFT_ETHER); 1695231437Sluigi if (!sc->ifp) 1696231437Sluigi return ENOMEM; 1697231437Sluigi 1698231437Sluigi ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 1699231437Sluigi ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1700231437Sluigi ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 1701231437Sluigi 1702231437Sluigi sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 1703231437Sluigi sc->ifp->if_ioctl = oce_ioctl; 1704231437Sluigi sc->ifp->if_start = oce_start; 1705231437Sluigi sc->ifp->if_init = oce_init; 1706231437Sluigi sc->ifp->if_mtu = ETHERMTU; 1707231437Sluigi sc->ifp->if_softc = sc; 1708231437Sluigi#if __FreeBSD_version >= 800000 1709231437Sluigi sc->ifp->if_transmit = oce_multiq_start; 1710231437Sluigi sc->ifp->if_qflush = oce_multiq_flush; 1711231437Sluigi#endif 1712231437Sluigi 1713231437Sluigi if_initname(sc->ifp, 1714231437Sluigi device_get_name(sc->dev), device_get_unit(sc->dev)); 1715231437Sluigi 1716231437Sluigi sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 1717231437Sluigi IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 1718231437Sluigi IFQ_SET_READY(&sc->ifp->if_snd); 1719231437Sluigi 1720231437Sluigi sc->ifp->if_hwassist = OCE_IF_HWASSIST; 1721231437Sluigi sc->ifp->if_hwassist |= CSUM_TSO; 1722231437Sluigi sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 1723231437Sluigi 1724231437Sluigi sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 1725231437Sluigi sc->ifp->if_capabilities |= IFCAP_HWCSUM; 1726231437Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 1727231879Sluigi 1728231511Sbz#if defined(INET6) || defined(INET) 1729231511Sbz sc->ifp->if_capabilities |= IFCAP_TSO; 1730231437Sluigi sc->ifp->if_capabilities |= IFCAP_LRO; 1731231879Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 1732231511Sbz#endif 1733231437Sluigi 1734231437Sluigi sc->ifp->if_capenable = sc->ifp->if_capabilities; 1735241691Sjhb if_initbaudrate(sc->ifp, IF_Gbps(10)); 1736231437Sluigi 1737257187Sdelphij#if __FreeBSD_version >= 1000000 1738257187Sdelphij sc->ifp->if_hw_tsomax = OCE_MAX_TSO_SIZE; 1739257187Sdelphij#endif 1740257187Sdelphij 1741231437Sluigi ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 1742231437Sluigi 1743231437Sluigi return 0; 1744231437Sluigi} 1745231437Sluigi 1746231437Sluigi 1747231437Sluigistatic void 1748231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1749231437Sluigi{ 1750231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1751231437Sluigi 1752231437Sluigi if (ifp->if_softc != arg) 1753231437Sluigi return; 1754231437Sluigi if ((vtag == 0) || (vtag > 4095)) 1755231437Sluigi return; 1756231437Sluigi 1757231437Sluigi sc->vlan_tag[vtag] = 1; 1758231437Sluigi sc->vlans_added++; 1759257187Sdelphij if (sc->vlans_added <= (sc->max_vlans + 1)) 1760257187Sdelphij oce_vid_config(sc); 1761231437Sluigi} 1762231437Sluigi 1763231437Sluigi 1764231437Sluigistatic void 1765231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1766231437Sluigi{ 1767231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1768231437Sluigi 1769231437Sluigi if (ifp->if_softc != arg) 1770231437Sluigi return; 1771231437Sluigi if ((vtag == 0) || (vtag > 4095)) 1772231437Sluigi return; 1773231437Sluigi 1774231437Sluigi sc->vlan_tag[vtag] = 0; 1775231437Sluigi sc->vlans_added--; 1776231437Sluigi oce_vid_config(sc); 1777231437Sluigi} 1778231437Sluigi 1779231437Sluigi 1780231437Sluigi/* 1781231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures 1782231437Sluigi * more, place the card in vlan promiscuous mode. 1783231437Sluigi */ 1784231437Sluigistatic int 1785231437Sluigioce_vid_config(POCE_SOFTC sc) 1786231437Sluigi{ 1787231437Sluigi struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 1788231437Sluigi uint16_t ntags = 0, i; 1789231437Sluigi int status = 0; 1790231437Sluigi 1791231437Sluigi if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 1792231437Sluigi (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 1793231437Sluigi for (i = 0; i < MAX_VLANS; i++) { 1794231437Sluigi if (sc->vlan_tag[i]) { 1795231437Sluigi vtags[ntags].vtag = i; 1796231437Sluigi ntags++; 1797231437Sluigi } 1798231437Sluigi } 1799231437Sluigi if (ntags) 1800231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1801231437Sluigi vtags, ntags, 1, 0); 1802231437Sluigi } else 1803231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1804231437Sluigi NULL, 0, 1, 1); 1805231437Sluigi return status; 1806231437Sluigi} 1807231437Sluigi 1808231437Sluigi 1809231437Sluigistatic void 1810231437Sluigioce_mac_addr_set(POCE_SOFTC sc) 1811231437Sluigi{ 1812231437Sluigi uint32_t old_pmac_id = sc->pmac_id; 1813231437Sluigi int status = 0; 1814231437Sluigi 1815231437Sluigi 1816231437Sluigi status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1817231437Sluigi sc->macaddr.size_of_struct); 1818231437Sluigi if (!status) 1819231437Sluigi return; 1820231437Sluigi 1821231437Sluigi status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 1822231437Sluigi sc->if_id, &sc->pmac_id); 1823231437Sluigi if (!status) { 1824231437Sluigi status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 1825231437Sluigi bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1826231437Sluigi sc->macaddr.size_of_struct); 1827231437Sluigi } 1828231437Sluigi if (status) 1829231437Sluigi device_printf(sc->dev, "Failed update macaddress\n"); 1830231437Sluigi 1831231437Sluigi} 1832231437Sluigi 1833231437Sluigi 1834231437Sluigistatic int 1835231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data) 1836231437Sluigi{ 1837231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1838231437Sluigi struct ifreq *ifr = (struct ifreq *)data; 1839231437Sluigi int rc = ENXIO; 1840231437Sluigi char cookie[32] = {0}; 1841231437Sluigi void *priv_data = (void *)ifr->ifr_data; 1842231437Sluigi void *ioctl_ptr; 1843231437Sluigi uint32_t req_size; 1844231437Sluigi struct mbx_hdr req; 1845231437Sluigi OCE_DMA_MEM dma_mem; 1846247880Sdelphij struct mbx_common_get_cntl_attr *fw_cmd; 1847231437Sluigi 1848231437Sluigi if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 1849231437Sluigi return EFAULT; 1850247880Sdelphij 1851231437Sluigi if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 1852231437Sluigi return EINVAL; 1853247880Sdelphij 1854231437Sluigi ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 1855231437Sluigi if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 1856231437Sluigi return EFAULT; 1857247880Sdelphij 1858231437Sluigi req_size = le32toh(req.u0.req.request_length); 1859231437Sluigi if (req_size > 65536) 1860231437Sluigi return EINVAL; 1861231437Sluigi 1862231437Sluigi req_size += sizeof(struct mbx_hdr); 1863231437Sluigi rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 1864231437Sluigi if (rc) 1865231437Sluigi return ENOMEM; 1866231437Sluigi 1867231437Sluigi if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 1868231437Sluigi rc = EFAULT; 1869231437Sluigi goto dma_free; 1870231437Sluigi } 1871231437Sluigi 1872231437Sluigi rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 1873231437Sluigi if (rc) { 1874231437Sluigi rc = EIO; 1875231437Sluigi goto dma_free; 1876231437Sluigi } 1877231437Sluigi 1878231437Sluigi if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 1879231437Sluigi rc = EFAULT; 1880231437Sluigi 1881247880Sdelphij /* 1882247880Sdelphij firmware is filling all the attributes for this ioctl except 1883247880Sdelphij the driver version..so fill it 1884247880Sdelphij */ 1885247880Sdelphij if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) { 1886247880Sdelphij fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr; 1887247880Sdelphij strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str, 1888247880Sdelphij COMPONENT_REVISION, strlen(COMPONENT_REVISION)); 1889247880Sdelphij } 1890247880Sdelphij 1891231437Sluigidma_free: 1892231437Sluigi oce_dma_free(sc, &dma_mem); 1893231437Sluigi return rc; 1894231437Sluigi 1895231437Sluigi} 1896231437Sluigi 1897247880Sdelphijstatic void 1898247880Sdelphijoce_eqd_set_periodic(POCE_SOFTC sc) 1899247880Sdelphij{ 1900247880Sdelphij struct oce_set_eqd set_eqd[OCE_MAX_EQ]; 1901247880Sdelphij struct oce_aic_obj *aic; 1902247880Sdelphij struct oce_eq *eqo; 1903247880Sdelphij uint64_t now = 0, delta; 1904247880Sdelphij int eqd, i, num = 0; 1905247880Sdelphij uint32_t ips = 0; 1906247880Sdelphij int tps; 1907231437Sluigi 1908247880Sdelphij for (i = 0 ; i < sc->neqs; i++) { 1909247880Sdelphij eqo = sc->eq[i]; 1910247880Sdelphij aic = &sc->aic_obj[i]; 1911247880Sdelphij /* When setting the static eq delay from the user space */ 1912247880Sdelphij if (!aic->enable) { 1913247880Sdelphij eqd = aic->et_eqd; 1914247880Sdelphij goto modify_eqd; 1915247880Sdelphij } 1916247880Sdelphij 1917247880Sdelphij now = ticks; 1918247880Sdelphij 1919247880Sdelphij /* Over flow check */ 1920247880Sdelphij if ((now < aic->ticks) || (eqo->intr < aic->intr_prev)) 1921247880Sdelphij goto done; 1922247880Sdelphij 1923247880Sdelphij delta = now - aic->ticks; 1924247880Sdelphij tps = delta/hz; 1925247880Sdelphij 1926247880Sdelphij /* Interrupt rate based on elapsed ticks */ 1927247880Sdelphij if(tps) 1928247880Sdelphij ips = (uint32_t)(eqo->intr - aic->intr_prev) / tps; 1929247880Sdelphij 1930247880Sdelphij if (ips > INTR_RATE_HWM) 1931247880Sdelphij eqd = aic->cur_eqd + 20; 1932247880Sdelphij else if (ips < INTR_RATE_LWM) 1933247880Sdelphij eqd = aic->cur_eqd / 2; 1934247880Sdelphij else 1935247880Sdelphij goto done; 1936247880Sdelphij 1937247880Sdelphij if (eqd < 10) 1938247880Sdelphij eqd = 0; 1939247880Sdelphij 1940247880Sdelphij /* Make sure that the eq delay is in the known range */ 1941247880Sdelphij eqd = min(eqd, aic->max_eqd); 1942247880Sdelphij eqd = max(eqd, aic->min_eqd); 1943247880Sdelphij 1944247880Sdelphijmodify_eqd: 1945247880Sdelphij if (eqd != aic->cur_eqd) { 1946247880Sdelphij set_eqd[num].delay_multiplier = (eqd * 65)/100; 1947247880Sdelphij set_eqd[num].eq_id = eqo->eq_id; 1948247880Sdelphij aic->cur_eqd = eqd; 1949247880Sdelphij num++; 1950247880Sdelphij } 1951247880Sdelphijdone: 1952247880Sdelphij aic->intr_prev = eqo->intr; 1953247880Sdelphij aic->ticks = now; 1954247880Sdelphij } 1955247880Sdelphij 1956247880Sdelphij /* Is there atleast one eq that needs to be modified? */ 1957247880Sdelphij if(num) 1958247880Sdelphij oce_mbox_eqd_modify_periodic(sc, set_eqd, num); 1959247880Sdelphij} 1960247880Sdelphij 1961257187Sdelphijstatic void oce_detect_hw_error(POCE_SOFTC sc) 1962257187Sdelphij{ 1963257187Sdelphij 1964257187Sdelphij uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0; 1965257187Sdelphij uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; 1966257187Sdelphij uint32_t i; 1967257187Sdelphij 1968257187Sdelphij if (sc->hw_error) 1969257187Sdelphij return; 1970257187Sdelphij 1971257187Sdelphij if (IS_XE201(sc)) { 1972257187Sdelphij sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET); 1973257187Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1974257187Sdelphij sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET); 1975257187Sdelphij sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET); 1976257187Sdelphij } 1977257187Sdelphij } else { 1978257187Sdelphij ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW); 1979257187Sdelphij ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH); 1980257187Sdelphij ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK); 1981257187Sdelphij ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK); 1982257187Sdelphij 1983257187Sdelphij ue_low = (ue_low & ~ue_low_mask); 1984257187Sdelphij ue_high = (ue_high & ~ue_high_mask); 1985257187Sdelphij } 1986257187Sdelphij 1987257187Sdelphij /* On certain platforms BE hardware can indicate spurious UEs. 1988257187Sdelphij * Allow the h/w to stop working completely in case of a real UE. 1989257187Sdelphij * Hence not setting the hw_error for UE detection. 1990257187Sdelphij */ 1991257187Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1992257187Sdelphij sc->hw_error = TRUE; 1993257187Sdelphij device_printf(sc->dev, "Error detected in the card\n"); 1994257187Sdelphij } 1995257187Sdelphij 1996257187Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 1997257187Sdelphij device_printf(sc->dev, 1998257187Sdelphij "ERR: sliport status 0x%x\n", sliport_status); 1999257187Sdelphij device_printf(sc->dev, 2000257187Sdelphij "ERR: sliport error1 0x%x\n", sliport_err1); 2001257187Sdelphij device_printf(sc->dev, 2002257187Sdelphij "ERR: sliport error2 0x%x\n", sliport_err2); 2003257187Sdelphij } 2004257187Sdelphij 2005257187Sdelphij if (ue_low) { 2006257187Sdelphij for (i = 0; ue_low; ue_low >>= 1, i++) { 2007257187Sdelphij if (ue_low & 1) 2008257187Sdelphij device_printf(sc->dev, "UE: %s bit set\n", 2009257187Sdelphij ue_status_low_desc[i]); 2010257187Sdelphij } 2011257187Sdelphij } 2012257187Sdelphij 2013257187Sdelphij if (ue_high) { 2014257187Sdelphij for (i = 0; ue_high; ue_high >>= 1, i++) { 2015257187Sdelphij if (ue_high & 1) 2016257187Sdelphij device_printf(sc->dev, "UE: %s bit set\n", 2017257187Sdelphij ue_status_hi_desc[i]); 2018257187Sdelphij } 2019257187Sdelphij } 2020257187Sdelphij 2021257187Sdelphij} 2022257187Sdelphij 2023257187Sdelphij 2024231437Sluigistatic void 2025231437Sluigioce_local_timer(void *arg) 2026231437Sluigi{ 2027231437Sluigi POCE_SOFTC sc = arg; 2028231437Sluigi int i = 0; 2029231437Sluigi 2030257187Sdelphij oce_detect_hw_error(sc); 2031231437Sluigi oce_refresh_nic_stats(sc); 2032231437Sluigi oce_refresh_queue_stats(sc); 2033231437Sluigi oce_mac_addr_set(sc); 2034231437Sluigi 2035231437Sluigi /* TX Watch Dog*/ 2036231437Sluigi for (i = 0; i < sc->nwqs; i++) 2037231437Sluigi oce_tx_restart(sc, sc->wq[i]); 2038231437Sluigi 2039247880Sdelphij /* calculate and set the eq delay for optimal interrupt rate */ 2040252869Sdelphij if (IS_BE(sc) || IS_SH(sc)) 2041247880Sdelphij oce_eqd_set_periodic(sc); 2042247880Sdelphij 2043231437Sluigi callout_reset(&sc->timer, hz, oce_local_timer, sc); 2044231437Sluigi} 2045231437Sluigi 2046231437Sluigi 2047246799Sjpaetzel/* NOTE : This should only be called holding 2048246799Sjpaetzel * DEVICE_LOCK. 2049257187Sdelphij */ 2050231437Sluigistatic void 2051231437Sluigioce_if_deactivate(POCE_SOFTC sc) 2052231437Sluigi{ 2053231437Sluigi int i, mtime = 0; 2054231437Sluigi int wait_req = 0; 2055231437Sluigi struct oce_rq *rq; 2056231437Sluigi struct oce_wq *wq; 2057231437Sluigi struct oce_eq *eq; 2058231437Sluigi 2059231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2060231437Sluigi 2061231437Sluigi /*Wait for max of 400ms for TX completions to be done */ 2062231437Sluigi while (mtime < 400) { 2063231437Sluigi wait_req = 0; 2064231437Sluigi for_all_wq_queues(sc, wq, i) { 2065231437Sluigi if (wq->ring->num_used) { 2066231437Sluigi wait_req = 1; 2067231437Sluigi DELAY(1); 2068231437Sluigi break; 2069231437Sluigi } 2070231437Sluigi } 2071231437Sluigi mtime += 1; 2072231437Sluigi if (!wait_req) 2073231437Sluigi break; 2074231437Sluigi } 2075231437Sluigi 2076231437Sluigi /* Stop intrs and finish any bottom halves pending */ 2077231437Sluigi oce_hw_intr_disable(sc); 2078231437Sluigi 2079247880Sdelphij /* Since taskqueue_drain takes a Gaint Lock, We should not acquire 2080247880Sdelphij any other lock. So unlock device lock and require after 2081247880Sdelphij completing taskqueue_drain. 2082247880Sdelphij */ 2083247880Sdelphij UNLOCK(&sc->dev_lock); 2084231437Sluigi for (i = 0; i < sc->intr_count; i++) { 2085231437Sluigi if (sc->intrs[i].tq != NULL) { 2086231437Sluigi taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 2087231437Sluigi } 2088231437Sluigi } 2089247880Sdelphij LOCK(&sc->dev_lock); 2090231437Sluigi 2091231437Sluigi /* Delete RX queue in card with flush param */ 2092231437Sluigi oce_stop_rx(sc); 2093231437Sluigi 2094231437Sluigi /* Invalidate any pending cq and eq entries*/ 2095231437Sluigi for_all_evnt_queues(sc, eq, i) 2096231437Sluigi oce_drain_eq(eq); 2097231437Sluigi for_all_rq_queues(sc, rq, i) 2098231437Sluigi oce_drain_rq_cq(rq); 2099231437Sluigi for_all_wq_queues(sc, wq, i) 2100231437Sluigi oce_drain_wq_cq(wq); 2101231437Sluigi 2102231437Sluigi /* But still we need to get MCC aync events. 2103231437Sluigi So enable intrs and also arm first EQ 2104247880Sdelphij */ 2105231437Sluigi oce_hw_intr_enable(sc); 2106231437Sluigi oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 2107231437Sluigi 2108231437Sluigi DELAY(10); 2109231437Sluigi} 2110231437Sluigi 2111231437Sluigi 2112231437Sluigistatic void 2113231437Sluigioce_if_activate(POCE_SOFTC sc) 2114231437Sluigi{ 2115231437Sluigi struct oce_eq *eq; 2116231437Sluigi struct oce_rq *rq; 2117231437Sluigi struct oce_wq *wq; 2118231437Sluigi int i, rc = 0; 2119231437Sluigi 2120231437Sluigi sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 2121231437Sluigi 2122231437Sluigi oce_hw_intr_disable(sc); 2123231437Sluigi 2124231437Sluigi oce_start_rx(sc); 2125231437Sluigi 2126231437Sluigi for_all_rq_queues(sc, rq, i) { 2127231437Sluigi rc = oce_start_rq(rq); 2128231437Sluigi if (rc) 2129231437Sluigi device_printf(sc->dev, "Unable to start RX\n"); 2130231437Sluigi } 2131231437Sluigi 2132231437Sluigi for_all_wq_queues(sc, wq, i) { 2133231437Sluigi rc = oce_start_wq(wq); 2134231437Sluigi if (rc) 2135231437Sluigi device_printf(sc->dev, "Unable to start TX\n"); 2136231437Sluigi } 2137231437Sluigi 2138231437Sluigi 2139231437Sluigi for_all_evnt_queues(sc, eq, i) 2140231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 2141231437Sluigi 2142231437Sluigi oce_hw_intr_enable(sc); 2143231437Sluigi 2144231437Sluigi} 2145231437Sluigi 2146231879Sluigistatic void 2147231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe) 2148231879Sluigi{ 2149231879Sluigi /* Update Link status */ 2150231879Sluigi if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 2151231879Sluigi ASYNC_EVENT_LINK_UP) { 2152231879Sluigi sc->link_status = ASYNC_EVENT_LINK_UP; 2153231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_UP); 2154231879Sluigi } else { 2155231879Sluigi sc->link_status = ASYNC_EVENT_LINK_DOWN; 2156231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_DOWN); 2157231879Sluigi } 2158231879Sluigi} 2159231879Sluigi 2160231879Sluigi 2161231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */ 2162231437Sluigiuint16_t 2163231437Sluigioce_mq_handler(void *arg) 2164231437Sluigi{ 2165231437Sluigi struct oce_mq *mq = (struct oce_mq *)arg; 2166231437Sluigi POCE_SOFTC sc = mq->parent; 2167231437Sluigi struct oce_cq *cq = mq->cq; 2168231879Sluigi int num_cqes = 0, evt_type = 0, optype = 0; 2169231437Sluigi struct oce_mq_cqe *cqe; 2170231437Sluigi struct oce_async_cqe_link_state *acqe; 2171231879Sluigi struct oce_async_event_grp5_pvid_state *gcqe; 2172247880Sdelphij struct oce_async_event_qnq *dbgcqe; 2173231437Sluigi 2174231879Sluigi 2175231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2176231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2177231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 2178231879Sluigi 2179231437Sluigi while (cqe->u0.dw[3]) { 2180231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 2181231437Sluigi if (cqe->u0.s.async_event) { 2182231879Sluigi evt_type = cqe->u0.s.event_type; 2183231879Sluigi optype = cqe->u0.s.async_type; 2184231879Sluigi if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) { 2185231879Sluigi /* Link status evt */ 2186231879Sluigi acqe = (struct oce_async_cqe_link_state *)cqe; 2187231879Sluigi process_link_state(sc, acqe); 2188231879Sluigi } else if ((evt_type == ASYNC_EVENT_GRP5) && 2189231879Sluigi (optype == ASYNC_EVENT_PVID_STATE)) { 2190231879Sluigi /* GRP5 PVID */ 2191231879Sluigi gcqe = 2192231879Sluigi (struct oce_async_event_grp5_pvid_state *)cqe; 2193231879Sluigi if (gcqe->enabled) 2194231879Sluigi sc->pvid = gcqe->tag & VLAN_VID_MASK; 2195231879Sluigi else 2196231879Sluigi sc->pvid = 0; 2197231879Sluigi 2198231437Sluigi } 2199247880Sdelphij else if(evt_type == ASYNC_EVENT_CODE_DEBUG && 2200247880Sdelphij optype == ASYNC_EVENT_DEBUG_QNQ) { 2201247880Sdelphij dbgcqe = 2202247880Sdelphij (struct oce_async_event_qnq *)cqe; 2203247880Sdelphij if(dbgcqe->valid) 2204247880Sdelphij sc->qnqid = dbgcqe->vlan_tag; 2205247880Sdelphij sc->qnq_debug_event = TRUE; 2206247880Sdelphij } 2207231437Sluigi } 2208231437Sluigi cqe->u0.dw[3] = 0; 2209231437Sluigi RING_GET(cq->ring, 1); 2210231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2211231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2212231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 2213231437Sluigi num_cqes++; 2214231437Sluigi } 2215231437Sluigi 2216231437Sluigi if (num_cqes) 2217231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 2218231437Sluigi 2219231437Sluigi return 0; 2220231437Sluigi} 2221231437Sluigi 2222231437Sluigi 2223231437Sluigistatic void 2224231437Sluigisetup_max_queues_want(POCE_SOFTC sc) 2225231437Sluigi{ 2226231437Sluigi /* Check if it is FLEX machine. Is so dont use RSS */ 2227231437Sluigi if ((sc->function_mode & FNM_FLEX10_MODE) || 2228231879Sluigi (sc->function_mode & FNM_UMC_MODE) || 2229231879Sluigi (sc->function_mode & FNM_VNIC_MODE) || 2230252869Sdelphij (!is_rss_enabled(sc)) || 2231268046Sdelphij IS_BE2(sc)) { 2232231437Sluigi sc->nrqs = 1; 2233231437Sluigi sc->nwqs = 1; 2234257187Sdelphij } else { 2235257187Sdelphij sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 2236257187Sdelphij sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs); 2237231437Sluigi } 2238268046Sdelphij 2239268046Sdelphij if (IS_BE2(sc) && is_rss_enabled(sc)) 2240268046Sdelphij sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 2241231437Sluigi} 2242231437Sluigi 2243231437Sluigi 2244231437Sluigistatic void 2245231437Sluigiupdate_queues_got(POCE_SOFTC sc) 2246231437Sluigi{ 2247252869Sdelphij if (is_rss_enabled(sc)) { 2248231437Sluigi sc->nrqs = sc->intr_count + 1; 2249231437Sluigi sc->nwqs = sc->intr_count; 2250231437Sluigi } else { 2251231437Sluigi sc->nrqs = 1; 2252231437Sluigi sc->nwqs = 1; 2253231437Sluigi } 2254268046Sdelphij 2255268046Sdelphij if (IS_BE2(sc)) 2256268046Sdelphij sc->nwqs = 1; 2257231437Sluigi} 2258231437Sluigi 2259247880Sdelphijstatic int 2260247880Sdelphijoce_check_ipv6_ext_hdr(struct mbuf *m) 2261247880Sdelphij{ 2262247880Sdelphij struct ether_header *eh = mtod(m, struct ether_header *); 2263247880Sdelphij caddr_t m_datatemp = m->m_data; 2264247880Sdelphij 2265247880Sdelphij if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 2266247880Sdelphij m->m_data += sizeof(struct ether_header); 2267247880Sdelphij struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 2268247880Sdelphij 2269247880Sdelphij if((ip6->ip6_nxt != IPPROTO_TCP) && \ 2270247880Sdelphij (ip6->ip6_nxt != IPPROTO_UDP)){ 2271247880Sdelphij struct ip6_ext *ip6e = NULL; 2272247880Sdelphij m->m_data += sizeof(struct ip6_hdr); 2273247880Sdelphij 2274247880Sdelphij ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *); 2275247880Sdelphij if(ip6e->ip6e_len == 0xff) { 2276247880Sdelphij m->m_data = m_datatemp; 2277247880Sdelphij return TRUE; 2278247880Sdelphij } 2279247880Sdelphij } 2280247880Sdelphij m->m_data = m_datatemp; 2281247880Sdelphij } 2282247880Sdelphij return FALSE; 2283247880Sdelphij} 2284247880Sdelphij 2285247880Sdelphijstatic int 2286247880Sdelphijis_be3_a1(POCE_SOFTC sc) 2287247880Sdelphij{ 2288247880Sdelphij if((sc->flags & OCE_FLAGS_BE3) && ((sc->asic_revision & 0xFF) < 2)) { 2289247880Sdelphij return TRUE; 2290247880Sdelphij } 2291247880Sdelphij return FALSE; 2292247880Sdelphij} 2293247880Sdelphij 2294247880Sdelphijstatic struct mbuf * 2295247880Sdelphijoce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete) 2296247880Sdelphij{ 2297247880Sdelphij uint16_t vlan_tag = 0; 2298247880Sdelphij 2299247880Sdelphij if(!M_WRITABLE(m)) 2300247880Sdelphij return NULL; 2301247880Sdelphij 2302247880Sdelphij /* Embed vlan tag in the packet if it is not part of it */ 2303247880Sdelphij if(m->m_flags & M_VLANTAG) { 2304247880Sdelphij vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 2305247880Sdelphij m->m_flags &= ~M_VLANTAG; 2306247880Sdelphij } 2307247880Sdelphij 2308247880Sdelphij /* if UMC, ignore vlan tag insertion and instead insert pvid */ 2309247880Sdelphij if(sc->pvid) { 2310247880Sdelphij if(!vlan_tag) 2311247880Sdelphij vlan_tag = sc->pvid; 2312247880Sdelphij *complete = FALSE; 2313247880Sdelphij } 2314247880Sdelphij 2315247880Sdelphij if(vlan_tag) { 2316247880Sdelphij m = ether_vlanencap(m, vlan_tag); 2317247880Sdelphij } 2318247880Sdelphij 2319247880Sdelphij if(sc->qnqid) { 2320247880Sdelphij m = ether_vlanencap(m, sc->qnqid); 2321247880Sdelphij *complete = FALSE; 2322247880Sdelphij } 2323247880Sdelphij return m; 2324247880Sdelphij} 2325247880Sdelphij 2326247880Sdelphijstatic int 2327247880Sdelphijoce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m) 2328247880Sdelphij{ 2329247880Sdelphij if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \ 2330247880Sdelphij oce_check_ipv6_ext_hdr(m)) { 2331247880Sdelphij return TRUE; 2332247880Sdelphij } 2333247880Sdelphij return FALSE; 2334247880Sdelphij} 2335252869Sdelphij 2336252869Sdelphijstatic void 2337252869Sdelphijoce_get_config(POCE_SOFTC sc) 2338252869Sdelphij{ 2339252869Sdelphij int rc = 0; 2340252869Sdelphij uint32_t max_rss = 0; 2341252869Sdelphij 2342252869Sdelphij if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native)) 2343252869Sdelphij max_rss = OCE_LEGACY_MODE_RSS; 2344252869Sdelphij else 2345252869Sdelphij max_rss = OCE_MAX_RSS; 2346252869Sdelphij 2347252869Sdelphij if (!IS_BE(sc)) { 2348259050Sdelphij rc = oce_get_profile_config(sc, max_rss); 2349252869Sdelphij if (rc) { 2350252869Sdelphij sc->nwqs = OCE_MAX_WQ; 2351252869Sdelphij sc->nrssqs = max_rss; 2352252869Sdelphij sc->nrqs = sc->nrssqs + 1; 2353252869Sdelphij } 2354252869Sdelphij } 2355259050Sdelphij else { /* For BE3 don't rely on fw for determining the resources */ 2356252869Sdelphij sc->nrssqs = max_rss; 2357252869Sdelphij sc->nrqs = sc->nrssqs + 1; 2358259050Sdelphij sc->nwqs = OCE_MAX_WQ; 2359259050Sdelphij sc->max_vlans = MAX_VLANFILTER_SIZE; 2360252869Sdelphij } 2361252869Sdelphij} 2362