oce_if.c revision 231879
1231437Sluigi/*- 2231437Sluigi * Copyright (C) 2012 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 231879 2012-02-17 13:55:17Z luigi $ */ 40231437Sluigi 41231511Sbz#include "opt_inet6.h" 42231511Sbz#include "opt_inet.h" 43231511Sbz 44231437Sluigi#include "oce_if.h" 45231437Sluigi 46231437Sluigi 47231437Sluigi/* Driver entry points prototypes */ 48231437Sluigistatic int oce_probe(device_t dev); 49231437Sluigistatic int oce_attach(device_t dev); 50231437Sluigistatic int oce_detach(device_t dev); 51231437Sluigistatic int oce_shutdown(device_t dev); 52231437Sluigistatic int oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 53231437Sluigistatic void oce_init(void *xsc); 54231437Sluigistatic int oce_multiq_start(struct ifnet *ifp, struct mbuf *m); 55231437Sluigistatic void oce_multiq_flush(struct ifnet *ifp); 56231437Sluigi 57231437Sluigi/* Driver interrupt routines protypes */ 58231437Sluigistatic void oce_intr(void *arg, int pending); 59231437Sluigistatic int oce_setup_intr(POCE_SOFTC sc); 60231437Sluigistatic int oce_fast_isr(void *arg); 61231437Sluigistatic int oce_alloc_intr(POCE_SOFTC sc, int vector, 62231437Sluigi void (*isr) (void *arg, int pending)); 63231437Sluigi 64231437Sluigi/* Media callbacks prototypes */ 65231437Sluigistatic void oce_media_status(struct ifnet *ifp, struct ifmediareq *req); 66231437Sluigistatic int oce_media_change(struct ifnet *ifp); 67231437Sluigi 68231437Sluigi/* Transmit routines prototypes */ 69231437Sluigistatic int oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index); 70231437Sluigistatic void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq); 71231437Sluigistatic void oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, 72231437Sluigi uint32_t status); 73231437Sluigistatic int oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, 74231437Sluigi struct oce_wq *wq); 75231437Sluigi 76231437Sluigi/* Receive routines prototypes */ 77231437Sluigistatic void oce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); 78231437Sluigistatic int oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 79231437Sluigistatic int oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 80231437Sluigistatic void oce_rx(struct oce_rq *rq, uint32_t rqe_idx, 81231437Sluigi struct oce_nic_rx_cqe *cqe); 82231437Sluigi 83231437Sluigi/* Helper function prototypes in this file */ 84231437Sluigistatic int oce_attach_ifp(POCE_SOFTC sc); 85231437Sluigistatic void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 86231437Sluigistatic void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 87231437Sluigistatic int oce_vid_config(POCE_SOFTC sc); 88231437Sluigistatic void oce_mac_addr_set(POCE_SOFTC sc); 89231437Sluigistatic int oce_handle_passthrough(struct ifnet *ifp, caddr_t data); 90231437Sluigistatic void oce_local_timer(void *arg); 91231437Sluigistatic void oce_if_deactivate(POCE_SOFTC sc); 92231437Sluigistatic void oce_if_activate(POCE_SOFTC sc); 93231437Sluigistatic void setup_max_queues_want(POCE_SOFTC sc); 94231437Sluigistatic void update_queues_got(POCE_SOFTC sc); 95231879Sluigistatic void process_link_state(POCE_SOFTC sc, 96231879Sluigi struct oce_async_cqe_link_state *acqe); 97231437Sluigi 98231879Sluigi 99231879Sluigi/* IP specific */ 100231879Sluigi#if defined(INET6) || defined(INET) 101231879Sluigistatic int oce_init_lro(POCE_SOFTC sc); 102231879Sluigistatic void oce_rx_flush_lro(struct oce_rq *rq); 103231879Sluigistatic struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp); 104231879Sluigi#endif 105231879Sluigi 106231437Sluigistatic device_method_t oce_dispatch[] = { 107231437Sluigi DEVMETHOD(device_probe, oce_probe), 108231437Sluigi DEVMETHOD(device_attach, oce_attach), 109231437Sluigi DEVMETHOD(device_detach, oce_detach), 110231437Sluigi DEVMETHOD(device_shutdown, oce_shutdown), 111231437Sluigi {0, 0} 112231437Sluigi}; 113231437Sluigi 114231437Sluigistatic driver_t oce_driver = { 115231437Sluigi "oce", 116231437Sluigi oce_dispatch, 117231437Sluigi sizeof(OCE_SOFTC) 118231437Sluigi}; 119231437Sluigistatic devclass_t oce_devclass; 120231437Sluigi 121231437Sluigi 122231437SluigiDRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0); 123231437SluigiMODULE_DEPEND(oce, pci, 1, 1, 1); 124231437SluigiMODULE_DEPEND(oce, ether, 1, 1, 1); 125231437SluigiMODULE_VERSION(oce, 1); 126231437Sluigi 127231437Sluigi 128231437Sluigi/* global vars */ 129231437Sluigiconst char component_revision[32] = {"///" COMPONENT_REVISION "///"}; 130231437Sluigi 131231437Sluigi/* Module capabilites and parameters */ 132231437Sluigiuint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED; 133231437Sluigiuint32_t oce_enable_rss = OCE_MODCAP_RSS; 134231437Sluigi 135231437Sluigi 136231437SluigiTUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled); 137231437SluigiTUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss); 138231437Sluigi 139231437Sluigi 140231437Sluigi/* Supported devices table */ 141231437Sluigistatic uint32_t supportedDevices[] = { 142231437Sluigi (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2, 143231437Sluigi (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3, 144231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3, 145231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201, 146231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF, 147231437Sluigi}; 148231437Sluigi 149231437Sluigi 150231437Sluigi 151231437Sluigi 152231437Sluigi/***************************************************************************** 153231437Sluigi * Driver entry points functions * 154231437Sluigi *****************************************************************************/ 155231437Sluigi 156231437Sluigistatic int 157231437Sluigioce_probe(device_t dev) 158231437Sluigi{ 159231879Sluigi uint16_t vendor = 0; 160231879Sluigi uint16_t device = 0; 161231879Sluigi int i = 0; 162231879Sluigi char str[256] = {0}; 163231437Sluigi POCE_SOFTC sc; 164231437Sluigi 165231437Sluigi sc = device_get_softc(dev); 166231437Sluigi bzero(sc, sizeof(OCE_SOFTC)); 167231437Sluigi sc->dev = dev; 168231437Sluigi 169231437Sluigi vendor = pci_get_vendor(dev); 170231437Sluigi device = pci_get_device(dev); 171231437Sluigi 172231879Sluigi for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) { 173231437Sluigi if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) { 174231437Sluigi if (device == (supportedDevices[i] & 0xffff)) { 175231879Sluigi sprintf(str, "%s:%s", "Emulex CNA NIC function", 176231437Sluigi component_revision); 177231437Sluigi device_set_desc_copy(dev, str); 178231437Sluigi 179231437Sluigi switch (device) { 180231437Sluigi case PCI_PRODUCT_BE2: 181231437Sluigi sc->flags |= OCE_FLAGS_BE2; 182231437Sluigi break; 183231437Sluigi case PCI_PRODUCT_BE3: 184231437Sluigi sc->flags |= OCE_FLAGS_BE3; 185231437Sluigi break; 186231437Sluigi case PCI_PRODUCT_XE201: 187231437Sluigi case PCI_PRODUCT_XE201_VF: 188231437Sluigi sc->flags |= OCE_FLAGS_XE201; 189231437Sluigi break; 190231437Sluigi default: 191231437Sluigi return ENXIO; 192231437Sluigi } 193231437Sluigi return BUS_PROBE_DEFAULT; 194231437Sluigi } 195231437Sluigi } 196231437Sluigi } 197231437Sluigi 198231437Sluigi return ENXIO; 199231437Sluigi} 200231437Sluigi 201231437Sluigi 202231437Sluigistatic int 203231437Sluigioce_attach(device_t dev) 204231437Sluigi{ 205231437Sluigi POCE_SOFTC sc; 206231437Sluigi int rc = 0; 207231437Sluigi 208231437Sluigi sc = device_get_softc(dev); 209231437Sluigi 210231437Sluigi rc = oce_hw_pci_alloc(sc); 211231437Sluigi if (rc) 212231437Sluigi return rc; 213231437Sluigi 214231437Sluigi sc->rss_enable = oce_enable_rss; 215231437Sluigi sc->tx_ring_size = OCE_TX_RING_SIZE; 216231437Sluigi sc->rx_ring_size = OCE_RX_RING_SIZE; 217231437Sluigi sc->rq_frag_size = OCE_RQ_BUF_SIZE; 218231437Sluigi sc->flow_control = OCE_DEFAULT_FLOW_CONTROL; 219231437Sluigi sc->promisc = OCE_DEFAULT_PROMISCUOUS; 220231437Sluigi 221231437Sluigi LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock"); 222231437Sluigi LOCK_CREATE(&sc->dev_lock, "Device_lock"); 223231437Sluigi 224231437Sluigi /* initialise the hardware */ 225231437Sluigi rc = oce_hw_init(sc); 226231437Sluigi if (rc) 227231437Sluigi goto pci_res_free; 228231437Sluigi 229231437Sluigi setup_max_queues_want(sc); 230231437Sluigi 231231437Sluigi rc = oce_setup_intr(sc); 232231437Sluigi if (rc) 233231437Sluigi goto mbox_free; 234231437Sluigi 235231437Sluigi rc = oce_queue_init_all(sc); 236231437Sluigi if (rc) 237231437Sluigi goto intr_free; 238231437Sluigi 239231437Sluigi rc = oce_attach_ifp(sc); 240231437Sluigi if (rc) 241231437Sluigi goto queues_free; 242231437Sluigi 243231511Sbz#if defined(INET6) || defined(INET) 244231437Sluigi rc = oce_init_lro(sc); 245231437Sluigi if (rc) 246231879Sluigi goto ifp_free; 247231511Sbz#endif 248231437Sluigi 249231437Sluigi rc = oce_hw_start(sc); 250231437Sluigi if (rc) 251231437Sluigi goto lro_free;; 252231437Sluigi 253231437Sluigi sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 254231437Sluigi oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST); 255231437Sluigi sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 256231437Sluigi oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST); 257231437Sluigi 258231437Sluigi rc = oce_stats_init(sc); 259231437Sluigi if (rc) 260231437Sluigi goto vlan_free; 261231437Sluigi 262231437Sluigi oce_add_sysctls(sc); 263231437Sluigi 264231437Sluigi callout_init(&sc->timer, CALLOUT_MPSAFE); 265231437Sluigi rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc); 266231437Sluigi if (rc) 267231437Sluigi goto stats_free; 268231879Sluigi#ifdef DEV_NETMAP 269231879Sluigi#endif /* DEV_NETMAP */ 270231437Sluigi 271231437Sluigi return 0; 272231437Sluigi 273231437Sluigistats_free: 274231437Sluigi callout_drain(&sc->timer); 275231437Sluigi oce_stats_free(sc); 276231437Sluigivlan_free: 277231437Sluigi if (sc->vlan_attach) 278231437Sluigi EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 279231437Sluigi if (sc->vlan_detach) 280231437Sluigi EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 281231437Sluigi oce_hw_intr_disable(sc); 282231437Sluigilro_free: 283231511Sbz#if defined(INET6) || defined(INET) 284231437Sluigi oce_free_lro(sc); 285231437Sluigiifp_free: 286231511Sbz#endif 287231437Sluigi ether_ifdetach(sc->ifp); 288231437Sluigi if_free(sc->ifp); 289231437Sluigiqueues_free: 290231437Sluigi oce_queue_release_all(sc); 291231437Sluigiintr_free: 292231437Sluigi oce_intr_free(sc); 293231437Sluigimbox_free: 294231437Sluigi oce_dma_free(sc, &sc->bsmbx); 295231437Sluigipci_res_free: 296231437Sluigi oce_hw_pci_free(sc); 297231437Sluigi LOCK_DESTROY(&sc->dev_lock); 298231437Sluigi LOCK_DESTROY(&sc->bmbx_lock); 299231437Sluigi return rc; 300231437Sluigi 301231437Sluigi} 302231437Sluigi 303231437Sluigi 304231437Sluigistatic int 305231437Sluigioce_detach(device_t dev) 306231437Sluigi{ 307231437Sluigi POCE_SOFTC sc = device_get_softc(dev); 308231437Sluigi 309231437Sluigi LOCK(&sc->dev_lock); 310231437Sluigi oce_if_deactivate(sc); 311231437Sluigi UNLOCK(&sc->dev_lock); 312231437Sluigi 313231437Sluigi callout_drain(&sc->timer); 314231437Sluigi 315231437Sluigi if (sc->vlan_attach != NULL) 316231437Sluigi EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 317231437Sluigi if (sc->vlan_detach != NULL) 318231437Sluigi EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 319231437Sluigi 320231437Sluigi ether_ifdetach(sc->ifp); 321231437Sluigi 322231437Sluigi if_free(sc->ifp); 323231437Sluigi 324231437Sluigi oce_hw_shutdown(sc); 325231437Sluigi 326231437Sluigi bus_generic_detach(dev); 327231437Sluigi 328231437Sluigi return 0; 329231437Sluigi} 330231437Sluigi 331231437Sluigi 332231437Sluigistatic int 333231437Sluigioce_shutdown(device_t dev) 334231437Sluigi{ 335231437Sluigi int rc; 336231437Sluigi 337231437Sluigi rc = oce_detach(dev); 338231437Sluigi 339231437Sluigi return rc; 340231437Sluigi} 341231437Sluigi 342231437Sluigi 343231437Sluigistatic int 344231437Sluigioce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 345231437Sluigi{ 346231437Sluigi struct ifreq *ifr = (struct ifreq *)data; 347231437Sluigi POCE_SOFTC sc = ifp->if_softc; 348231437Sluigi int rc = 0; 349231437Sluigi uint32_t u; 350231437Sluigi 351231437Sluigi switch (command) { 352231437Sluigi 353231437Sluigi case SIOCGIFMEDIA: 354231437Sluigi rc = ifmedia_ioctl(ifp, ifr, &sc->media, command); 355231437Sluigi break; 356231437Sluigi 357231437Sluigi case SIOCSIFMTU: 358231437Sluigi if (ifr->ifr_mtu > OCE_MAX_MTU) 359231437Sluigi rc = EINVAL; 360231437Sluigi else 361231437Sluigi ifp->if_mtu = ifr->ifr_mtu; 362231437Sluigi break; 363231437Sluigi 364231437Sluigi case SIOCSIFFLAGS: 365231437Sluigi if (ifp->if_flags & IFF_UP) { 366231437Sluigi if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 367231437Sluigi sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 368231437Sluigi oce_init(sc); 369231437Sluigi } 370231437Sluigi device_printf(sc->dev, "Interface Up\n"); 371231437Sluigi } else { 372231437Sluigi LOCK(&sc->dev_lock); 373231437Sluigi 374231437Sluigi sc->ifp->if_drv_flags &= 375231437Sluigi ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 376231437Sluigi oce_if_deactivate(sc); 377231437Sluigi 378231437Sluigi UNLOCK(&sc->dev_lock); 379231437Sluigi 380231437Sluigi device_printf(sc->dev, "Interface Down\n"); 381231437Sluigi } 382231437Sluigi 383231437Sluigi if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) { 384231437Sluigi sc->promisc = TRUE; 385231437Sluigi oce_rxf_set_promiscuous(sc, sc->promisc); 386231437Sluigi } else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) { 387231437Sluigi sc->promisc = FALSE; 388231437Sluigi oce_rxf_set_promiscuous(sc, sc->promisc); 389231437Sluigi } 390231437Sluigi 391231437Sluigi break; 392231437Sluigi 393231437Sluigi case SIOCADDMULTI: 394231437Sluigi case SIOCDELMULTI: 395231437Sluigi rc = oce_hw_update_multicast(sc); 396231437Sluigi if (rc) 397231437Sluigi device_printf(sc->dev, 398231437Sluigi "Update multicast address failed\n"); 399231437Sluigi break; 400231437Sluigi 401231437Sluigi case SIOCSIFCAP: 402231437Sluigi u = ifr->ifr_reqcap ^ ifp->if_capenable; 403231437Sluigi 404231437Sluigi if (u & IFCAP_TXCSUM) { 405231437Sluigi ifp->if_capenable ^= IFCAP_TXCSUM; 406231437Sluigi ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 407231437Sluigi 408231437Sluigi if (IFCAP_TSO & ifp->if_capenable && 409231437Sluigi !(IFCAP_TXCSUM & ifp->if_capenable)) { 410231437Sluigi ifp->if_capenable &= ~IFCAP_TSO; 411231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 412231437Sluigi if_printf(ifp, 413231437Sluigi "TSO disabled due to -txcsum.\n"); 414231437Sluigi } 415231437Sluigi } 416231437Sluigi 417231437Sluigi if (u & IFCAP_RXCSUM) 418231437Sluigi ifp->if_capenable ^= IFCAP_RXCSUM; 419231437Sluigi 420231437Sluigi if (u & IFCAP_TSO4) { 421231437Sluigi ifp->if_capenable ^= IFCAP_TSO4; 422231437Sluigi 423231437Sluigi if (IFCAP_TSO & ifp->if_capenable) { 424231437Sluigi if (IFCAP_TXCSUM & ifp->if_capenable) 425231437Sluigi ifp->if_hwassist |= CSUM_TSO; 426231437Sluigi else { 427231437Sluigi ifp->if_capenable &= ~IFCAP_TSO; 428231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 429231437Sluigi if_printf(ifp, 430231437Sluigi "Enable txcsum first.\n"); 431231437Sluigi rc = EAGAIN; 432231437Sluigi } 433231437Sluigi } else 434231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 435231437Sluigi } 436231437Sluigi 437231437Sluigi if (u & IFCAP_VLAN_HWTAGGING) 438231437Sluigi ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 439231437Sluigi 440231437Sluigi if (u & IFCAP_VLAN_HWFILTER) { 441231437Sluigi ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 442231437Sluigi oce_vid_config(sc); 443231437Sluigi } 444231511Sbz#if defined(INET6) || defined(INET) 445231437Sluigi if (u & IFCAP_LRO) 446231437Sluigi ifp->if_capenable ^= IFCAP_LRO; 447231511Sbz#endif 448231437Sluigi 449231437Sluigi break; 450231437Sluigi 451231437Sluigi case SIOCGPRIVATE_0: 452231437Sluigi rc = oce_handle_passthrough(ifp, data); 453231437Sluigi break; 454231437Sluigi default: 455231437Sluigi rc = ether_ioctl(ifp, command, data); 456231437Sluigi break; 457231437Sluigi } 458231437Sluigi 459231437Sluigi return rc; 460231437Sluigi} 461231437Sluigi 462231437Sluigi 463231437Sluigistatic void 464231437Sluigioce_init(void *arg) 465231437Sluigi{ 466231437Sluigi POCE_SOFTC sc = arg; 467231437Sluigi 468231437Sluigi LOCK(&sc->dev_lock); 469231437Sluigi 470231437Sluigi if (sc->ifp->if_flags & IFF_UP) { 471231437Sluigi oce_if_deactivate(sc); 472231437Sluigi oce_if_activate(sc); 473231437Sluigi } 474231437Sluigi 475231437Sluigi UNLOCK(&sc->dev_lock); 476231437Sluigi 477231437Sluigi} 478231437Sluigi 479231437Sluigi 480231437Sluigistatic int 481231437Sluigioce_multiq_start(struct ifnet *ifp, struct mbuf *m) 482231437Sluigi{ 483231437Sluigi POCE_SOFTC sc = ifp->if_softc; 484231437Sluigi struct oce_wq *wq = NULL; 485231437Sluigi int queue_index = 0; 486231437Sluigi int status = 0; 487231437Sluigi 488231437Sluigi if ((m->m_flags & M_FLOWID) != 0) 489231437Sluigi queue_index = m->m_pkthdr.flowid % sc->nwqs; 490231437Sluigi 491231437Sluigi wq = sc->wq[queue_index]; 492231437Sluigi 493231437Sluigi if (TRY_LOCK(&wq->tx_lock)) { 494231437Sluigi status = oce_multiq_transmit(ifp, m, wq); 495231437Sluigi UNLOCK(&wq->tx_lock); 496231437Sluigi } else { 497231437Sluigi status = drbr_enqueue(ifp, wq->br, m); 498231437Sluigi } 499231437Sluigi return status; 500231437Sluigi 501231437Sluigi} 502231437Sluigi 503231437Sluigi 504231437Sluigistatic void 505231437Sluigioce_multiq_flush(struct ifnet *ifp) 506231437Sluigi{ 507231437Sluigi POCE_SOFTC sc = ifp->if_softc; 508231437Sluigi struct mbuf *m; 509231437Sluigi int i = 0; 510231437Sluigi 511231437Sluigi for (i = 0; i < sc->nwqs; i++) { 512231437Sluigi while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) 513231437Sluigi m_freem(m); 514231437Sluigi } 515231437Sluigi if_qflush(ifp); 516231437Sluigi} 517231437Sluigi 518231437Sluigi 519231437Sluigi 520231437Sluigi/***************************************************************************** 521231437Sluigi * Driver interrupt routines functions * 522231437Sluigi *****************************************************************************/ 523231437Sluigi 524231437Sluigistatic void 525231437Sluigioce_intr(void *arg, int pending) 526231437Sluigi{ 527231437Sluigi 528231437Sluigi POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 529231437Sluigi POCE_SOFTC sc = ii->sc; 530231437Sluigi struct oce_eq *eq = ii->eq; 531231437Sluigi struct oce_eqe *eqe; 532231437Sluigi struct oce_cq *cq = NULL; 533231437Sluigi int i, num_eqes = 0; 534231437Sluigi 535231437Sluigi 536231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 537231437Sluigi BUS_DMASYNC_POSTWRITE); 538231437Sluigi do { 539231437Sluigi eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 540231437Sluigi if (eqe->evnt == 0) 541231437Sluigi break; 542231437Sluigi eqe->evnt = 0; 543231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 544231437Sluigi BUS_DMASYNC_POSTWRITE); 545231437Sluigi RING_GET(eq->ring, 1); 546231437Sluigi num_eqes++; 547231437Sluigi 548231437Sluigi } while (TRUE); 549231437Sluigi 550231437Sluigi if (!num_eqes) 551231437Sluigi goto eq_arm; /* Spurious */ 552231437Sluigi 553231437Sluigi /* Clear EQ entries, but dont arm */ 554231437Sluigi oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE); 555231437Sluigi 556231437Sluigi /* Process TX, RX and MCC. But dont arm CQ*/ 557231437Sluigi for (i = 0; i < eq->cq_valid; i++) { 558231437Sluigi cq = eq->cq[i]; 559231437Sluigi (*cq->cq_handler)(cq->cb_arg); 560231437Sluigi } 561231437Sluigi 562231437Sluigi /* Arm all cqs connected to this EQ */ 563231437Sluigi for (i = 0; i < eq->cq_valid; i++) { 564231437Sluigi cq = eq->cq[i]; 565231437Sluigi oce_arm_cq(sc, cq->cq_id, 0, TRUE); 566231437Sluigi } 567231437Sluigi 568231437Sluigieq_arm: 569231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 570231437Sluigi return; 571231437Sluigi} 572231437Sluigi 573231437Sluigi 574231437Sluigistatic int 575231437Sluigioce_setup_intr(POCE_SOFTC sc) 576231437Sluigi{ 577231437Sluigi int rc = 0, use_intx = 0; 578231437Sluigi int vector = 0, req_vectors = 0; 579231437Sluigi 580231437Sluigi if (sc->rss_enable) 581231437Sluigi req_vectors = MAX((sc->nrqs - 1), sc->nwqs); 582231437Sluigi else 583231437Sluigi req_vectors = 1; 584231437Sluigi 585231437Sluigi if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) { 586231437Sluigi sc->intr_count = req_vectors; 587231437Sluigi rc = pci_alloc_msix(sc->dev, &sc->intr_count); 588231437Sluigi if (rc != 0) { 589231437Sluigi use_intx = 1; 590231437Sluigi pci_release_msi(sc->dev); 591231437Sluigi } else 592231437Sluigi sc->flags |= OCE_FLAGS_USING_MSIX; 593231437Sluigi } else 594231437Sluigi use_intx = 1; 595231437Sluigi 596231437Sluigi if (use_intx) 597231437Sluigi sc->intr_count = 1; 598231437Sluigi 599231437Sluigi /* Scale number of queues based on intr we got */ 600231437Sluigi update_queues_got(sc); 601231437Sluigi 602231437Sluigi if (use_intx) { 603231437Sluigi device_printf(sc->dev, "Using legacy interrupt\n"); 604231437Sluigi rc = oce_alloc_intr(sc, vector, oce_intr); 605231437Sluigi if (rc) 606231437Sluigi goto error; 607231437Sluigi } else { 608231437Sluigi for (; vector < sc->intr_count; vector++) { 609231437Sluigi rc = oce_alloc_intr(sc, vector, oce_intr); 610231437Sluigi if (rc) 611231437Sluigi goto error; 612231437Sluigi } 613231437Sluigi } 614231437Sluigi 615231437Sluigi return 0; 616231437Sluigierror: 617231437Sluigi oce_intr_free(sc); 618231437Sluigi return rc; 619231437Sluigi} 620231437Sluigi 621231437Sluigi 622231437Sluigistatic int 623231437Sluigioce_fast_isr(void *arg) 624231437Sluigi{ 625231437Sluigi POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 626231437Sluigi POCE_SOFTC sc = ii->sc; 627231437Sluigi 628231437Sluigi if (ii->eq == NULL) 629231437Sluigi return FILTER_STRAY; 630231437Sluigi 631231437Sluigi oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE); 632231437Sluigi 633231437Sluigi taskqueue_enqueue_fast(ii->tq, &ii->task); 634231437Sluigi 635231437Sluigi return FILTER_HANDLED; 636231437Sluigi} 637231437Sluigi 638231437Sluigi 639231437Sluigistatic int 640231437Sluigioce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) 641231437Sluigi{ 642231437Sluigi POCE_INTR_INFO ii = &sc->intrs[vector]; 643231437Sluigi int rc = 0, rr; 644231437Sluigi 645231437Sluigi if (vector >= OCE_MAX_EQ) 646231437Sluigi return (EINVAL); 647231437Sluigi 648231437Sluigi /* Set the resource id for the interrupt. 649231437Sluigi * MSIx is vector + 1 for the resource id, 650231437Sluigi * INTx is 0 for the resource id. 651231437Sluigi */ 652231437Sluigi if (sc->flags & OCE_FLAGS_USING_MSIX) 653231437Sluigi rr = vector + 1; 654231437Sluigi else 655231437Sluigi rr = 0; 656231437Sluigi ii->intr_res = bus_alloc_resource_any(sc->dev, 657231437Sluigi SYS_RES_IRQ, 658231437Sluigi &rr, RF_ACTIVE|RF_SHAREABLE); 659231437Sluigi ii->irq_rr = rr; 660231437Sluigi if (ii->intr_res == NULL) { 661231437Sluigi device_printf(sc->dev, 662231437Sluigi "Could not allocate interrupt\n"); 663231437Sluigi rc = ENXIO; 664231437Sluigi return rc; 665231437Sluigi } 666231437Sluigi 667231437Sluigi TASK_INIT(&ii->task, 0, isr, ii); 668231437Sluigi ii->vector = vector; 669231437Sluigi sprintf(ii->task_name, "oce_task[%d]", ii->vector); 670231437Sluigi ii->tq = taskqueue_create_fast(ii->task_name, 671231437Sluigi M_NOWAIT, 672231437Sluigi taskqueue_thread_enqueue, 673231437Sluigi &ii->tq); 674231437Sluigi taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq", 675231437Sluigi device_get_nameunit(sc->dev)); 676231437Sluigi 677231437Sluigi ii->sc = sc; 678231437Sluigi rc = bus_setup_intr(sc->dev, 679231437Sluigi ii->intr_res, 680231437Sluigi INTR_TYPE_NET, 681231437Sluigi oce_fast_isr, NULL, ii, &ii->tag); 682231437Sluigi return rc; 683231437Sluigi 684231437Sluigi} 685231437Sluigi 686231437Sluigi 687231437Sluigivoid 688231437Sluigioce_intr_free(POCE_SOFTC sc) 689231437Sluigi{ 690231437Sluigi int i = 0; 691231437Sluigi 692231437Sluigi for (i = 0; i < sc->intr_count; i++) { 693231437Sluigi 694231437Sluigi if (sc->intrs[i].tag != NULL) 695231437Sluigi bus_teardown_intr(sc->dev, sc->intrs[i].intr_res, 696231437Sluigi sc->intrs[i].tag); 697231437Sluigi if (sc->intrs[i].tq != NULL) 698231437Sluigi taskqueue_free(sc->intrs[i].tq); 699231437Sluigi 700231437Sluigi if (sc->intrs[i].intr_res != NULL) 701231437Sluigi bus_release_resource(sc->dev, SYS_RES_IRQ, 702231437Sluigi sc->intrs[i].irq_rr, 703231437Sluigi sc->intrs[i].intr_res); 704231437Sluigi sc->intrs[i].tag = NULL; 705231437Sluigi sc->intrs[i].intr_res = NULL; 706231437Sluigi } 707231437Sluigi 708231437Sluigi if (sc->flags & OCE_FLAGS_USING_MSIX) 709231437Sluigi pci_release_msi(sc->dev); 710231437Sluigi 711231437Sluigi} 712231437Sluigi 713231437Sluigi 714231437Sluigi 715231437Sluigi/****************************************************************************** 716231437Sluigi* Media callbacks functions * 717231437Sluigi******************************************************************************/ 718231437Sluigi 719231437Sluigistatic void 720231437Sluigioce_media_status(struct ifnet *ifp, struct ifmediareq *req) 721231437Sluigi{ 722231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc; 723231437Sluigi 724231437Sluigi 725231437Sluigi req->ifm_status = IFM_AVALID; 726231437Sluigi req->ifm_active = IFM_ETHER; 727231437Sluigi 728231437Sluigi if (sc->link_status == 1) 729231437Sluigi req->ifm_status |= IFM_ACTIVE; 730231437Sluigi else 731231437Sluigi return; 732231437Sluigi 733231437Sluigi switch (sc->link_speed) { 734231437Sluigi case 1: /* 10 Mbps */ 735231437Sluigi req->ifm_active |= IFM_10_T | IFM_FDX; 736231437Sluigi sc->speed = 10; 737231437Sluigi break; 738231437Sluigi case 2: /* 100 Mbps */ 739231437Sluigi req->ifm_active |= IFM_100_TX | IFM_FDX; 740231437Sluigi sc->speed = 100; 741231437Sluigi break; 742231437Sluigi case 3: /* 1 Gbps */ 743231437Sluigi req->ifm_active |= IFM_1000_T | IFM_FDX; 744231437Sluigi sc->speed = 1000; 745231437Sluigi break; 746231437Sluigi case 4: /* 10 Gbps */ 747231437Sluigi req->ifm_active |= IFM_10G_SR | IFM_FDX; 748231437Sluigi sc->speed = 10000; 749231437Sluigi break; 750231437Sluigi } 751231437Sluigi 752231437Sluigi return; 753231437Sluigi} 754231437Sluigi 755231437Sluigi 756231437Sluigiint 757231437Sluigioce_media_change(struct ifnet *ifp) 758231437Sluigi{ 759231437Sluigi return 0; 760231437Sluigi} 761231437Sluigi 762231437Sluigi 763231437Sluigi 764231437Sluigi 765231437Sluigi/***************************************************************************** 766231437Sluigi * Transmit routines functions * 767231437Sluigi *****************************************************************************/ 768231437Sluigi 769231437Sluigistatic int 770231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 771231437Sluigi{ 772231437Sluigi int rc = 0, i, retry_cnt = 0; 773231437Sluigi bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 774231437Sluigi struct mbuf *m, *m_temp; 775231437Sluigi struct oce_wq *wq = sc->wq[wq_index]; 776231437Sluigi struct oce_packet_desc *pd; 777231437Sluigi uint32_t out; 778231437Sluigi struct oce_nic_hdr_wqe *nichdr; 779231437Sluigi struct oce_nic_frag_wqe *nicfrag; 780231437Sluigi int num_wqes; 781231437Sluigi uint32_t reg_value; 782231437Sluigi 783231437Sluigi m = *mpp; 784231437Sluigi if (!m) 785231437Sluigi return EINVAL; 786231437Sluigi 787231437Sluigi if (!(m->m_flags & M_PKTHDR)) { 788231437Sluigi rc = ENXIO; 789231437Sluigi goto free_ret; 790231437Sluigi } 791231437Sluigi 792231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 793231879Sluigi /* consolidate packet buffers for TSO/LSO segment offload */ 794231511Sbz#if defined(INET6) || defined(INET) 795231879Sluigi m = oce_tso_setup(sc, mpp); 796231511Sbz#else 797231511Sbz m = NULL; 798231511Sbz#endif 799231437Sluigi if (m == NULL) { 800231437Sluigi rc = ENXIO; 801231437Sluigi goto free_ret; 802231437Sluigi } 803231437Sluigi } 804231437Sluigi 805231437Sluigi out = wq->packets_out + 1; 806231437Sluigi if (out == OCE_WQ_PACKET_ARRAY_SIZE) 807231437Sluigi out = 0; 808231437Sluigi if (out == wq->packets_in) 809231437Sluigi return EBUSY; 810231437Sluigi 811231437Sluigi pd = &wq->pckts[wq->packets_out]; 812231437Sluigiretry: 813231437Sluigi rc = bus_dmamap_load_mbuf_sg(wq->tag, 814231437Sluigi pd->map, 815231437Sluigi m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 816231437Sluigi if (rc == 0) { 817231437Sluigi num_wqes = pd->nsegs + 1; 818231437Sluigi if (IS_BE(sc)) { 819231437Sluigi /*Dummy required only for BE3.*/ 820231437Sluigi if (num_wqes & 1) 821231437Sluigi num_wqes++; 822231437Sluigi } 823231437Sluigi if (num_wqes >= RING_NUM_FREE(wq->ring)) { 824231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 825231437Sluigi return EBUSY; 826231437Sluigi } 827231437Sluigi 828231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 829231437Sluigi pd->mbuf = m; 830231437Sluigi wq->packets_out = out; 831231437Sluigi 832231437Sluigi nichdr = 833231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 834231437Sluigi nichdr->u0.dw[0] = 0; 835231437Sluigi nichdr->u0.dw[1] = 0; 836231437Sluigi nichdr->u0.dw[2] = 0; 837231437Sluigi nichdr->u0.dw[3] = 0; 838231437Sluigi 839231437Sluigi nichdr->u0.s.complete = 1; 840231437Sluigi nichdr->u0.s.event = 1; 841231437Sluigi nichdr->u0.s.crc = 1; 842231437Sluigi nichdr->u0.s.forward = 0; 843231437Sluigi nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 844231437Sluigi nichdr->u0.s.udpcs = 845231437Sluigi (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 846231437Sluigi nichdr->u0.s.tcpcs = 847231437Sluigi (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 848231437Sluigi nichdr->u0.s.num_wqe = num_wqes; 849231437Sluigi nichdr->u0.s.total_length = m->m_pkthdr.len; 850231437Sluigi if (m->m_flags & M_VLANTAG) { 851231437Sluigi nichdr->u0.s.vlan = 1; /*Vlan present*/ 852231437Sluigi nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 853231437Sluigi } 854231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 855231437Sluigi if (m->m_pkthdr.tso_segsz) { 856231437Sluigi nichdr->u0.s.lso = 1; 857231437Sluigi nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 858231437Sluigi } 859231437Sluigi if (!IS_BE(sc)) 860231437Sluigi nichdr->u0.s.ipcs = 1; 861231437Sluigi } 862231437Sluigi 863231437Sluigi RING_PUT(wq->ring, 1); 864231437Sluigi wq->ring->num_used++; 865231437Sluigi 866231437Sluigi for (i = 0; i < pd->nsegs; i++) { 867231437Sluigi nicfrag = 868231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 869231437Sluigi struct oce_nic_frag_wqe); 870231437Sluigi nicfrag->u0.s.rsvd0 = 0; 871231437Sluigi nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 872231437Sluigi nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 873231437Sluigi nicfrag->u0.s.frag_len = segs[i].ds_len; 874231437Sluigi pd->wqe_idx = wq->ring->pidx; 875231437Sluigi RING_PUT(wq->ring, 1); 876231437Sluigi wq->ring->num_used++; 877231437Sluigi } 878231437Sluigi if (num_wqes > (pd->nsegs + 1)) { 879231437Sluigi nicfrag = 880231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 881231437Sluigi struct oce_nic_frag_wqe); 882231437Sluigi nicfrag->u0.dw[0] = 0; 883231437Sluigi nicfrag->u0.dw[1] = 0; 884231437Sluigi nicfrag->u0.dw[2] = 0; 885231437Sluigi nicfrag->u0.dw[3] = 0; 886231437Sluigi pd->wqe_idx = wq->ring->pidx; 887231437Sluigi RING_PUT(wq->ring, 1); 888231437Sluigi wq->ring->num_used++; 889231437Sluigi pd->nsegs++; 890231437Sluigi } 891231437Sluigi 892231437Sluigi sc->ifp->if_opackets++; 893231437Sluigi wq->tx_stats.tx_reqs++; 894231437Sluigi wq->tx_stats.tx_wrbs += num_wqes; 895231437Sluigi wq->tx_stats.tx_bytes += m->m_pkthdr.len; 896231437Sluigi wq->tx_stats.tx_pkts++; 897231437Sluigi 898231437Sluigi bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 899231437Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 900231437Sluigi reg_value = (num_wqes << 16) | wq->wq_id; 901231437Sluigi OCE_WRITE_REG32(sc, db, PD_TXULP_DB, reg_value); 902231437Sluigi 903231437Sluigi } else if (rc == EFBIG) { 904231437Sluigi if (retry_cnt == 0) { 905231437Sluigi m_temp = m_defrag(m, M_DONTWAIT); 906231437Sluigi if (m_temp == NULL) 907231437Sluigi goto free_ret; 908231437Sluigi m = m_temp; 909231437Sluigi *mpp = m_temp; 910231437Sluigi retry_cnt = retry_cnt + 1; 911231437Sluigi goto retry; 912231437Sluigi } else 913231437Sluigi goto free_ret; 914231437Sluigi } else if (rc == ENOMEM) 915231437Sluigi return rc; 916231437Sluigi else 917231437Sluigi goto free_ret; 918231437Sluigi 919231437Sluigi return 0; 920231437Sluigi 921231437Sluigifree_ret: 922231437Sluigi m_freem(*mpp); 923231437Sluigi *mpp = NULL; 924231437Sluigi return rc; 925231437Sluigi} 926231437Sluigi 927231437Sluigi 928231437Sluigistatic void 929231437Sluigioce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status) 930231437Sluigi{ 931231437Sluigi uint32_t in; 932231437Sluigi struct oce_packet_desc *pd; 933231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 934231437Sluigi struct mbuf *m; 935231437Sluigi 936231437Sluigi if (wq->packets_out == wq->packets_in) 937231437Sluigi device_printf(sc->dev, "WQ transmit descriptor missing\n"); 938231437Sluigi 939231437Sluigi in = wq->packets_in + 1; 940231437Sluigi if (in == OCE_WQ_PACKET_ARRAY_SIZE) 941231437Sluigi in = 0; 942231437Sluigi 943231437Sluigi pd = &wq->pckts[wq->packets_in]; 944231437Sluigi wq->packets_in = in; 945231437Sluigi wq->ring->num_used -= (pd->nsegs + 1); 946231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 947231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 948231437Sluigi 949231437Sluigi m = pd->mbuf; 950231437Sluigi m_freem(m); 951231437Sluigi pd->mbuf = NULL; 952231437Sluigi 953231437Sluigi if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 954231437Sluigi if (wq->ring->num_used < (wq->ring->num_items / 2)) { 955231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 956231437Sluigi oce_tx_restart(sc, wq); 957231437Sluigi } 958231437Sluigi } 959231437Sluigi} 960231437Sluigi 961231437Sluigi 962231437Sluigistatic void 963231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 964231437Sluigi{ 965231437Sluigi 966231437Sluigi if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 967231437Sluigi return; 968231437Sluigi 969231437Sluigi#if __FreeBSD_version >= 800000 970231437Sluigi if (!drbr_empty(sc->ifp, wq->br)) 971231437Sluigi#else 972231437Sluigi if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 973231437Sluigi#endif 974231437Sluigi taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask); 975231437Sluigi 976231437Sluigi} 977231437Sluigi 978231879Sluigi 979231511Sbz#if defined(INET6) || defined(INET) 980231437Sluigistatic struct mbuf * 981231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp) 982231437Sluigi{ 983231437Sluigi struct mbuf *m; 984231511Sbz#ifdef INET 985231437Sluigi struct ip *ip; 986231511Sbz#endif 987231511Sbz#ifdef INET6 988231437Sluigi struct ip6_hdr *ip6; 989231511Sbz#endif 990231437Sluigi struct ether_vlan_header *eh; 991231437Sluigi struct tcphdr *th; 992231437Sluigi uint16_t etype; 993231879Sluigi int total_len = 0, ehdrlen = 0; 994231437Sluigi 995231437Sluigi m = *mpp; 996231437Sluigi 997231437Sluigi if (M_WRITABLE(m) == 0) { 998231437Sluigi m = m_dup(*mpp, M_DONTWAIT); 999231437Sluigi if (!m) 1000231437Sluigi return NULL; 1001231437Sluigi m_freem(*mpp); 1002231437Sluigi *mpp = m; 1003231437Sluigi } 1004231437Sluigi 1005231437Sluigi eh = mtod(m, struct ether_vlan_header *); 1006231437Sluigi if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 1007231437Sluigi etype = ntohs(eh->evl_proto); 1008231437Sluigi ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1009231437Sluigi } else { 1010231437Sluigi etype = ntohs(eh->evl_encap_proto); 1011231437Sluigi ehdrlen = ETHER_HDR_LEN; 1012231437Sluigi } 1013231437Sluigi 1014231437Sluigi switch (etype) { 1015231511Sbz#ifdef INET 1016231437Sluigi case ETHERTYPE_IP: 1017231437Sluigi ip = (struct ip *)(m->m_data + ehdrlen); 1018231437Sluigi if (ip->ip_p != IPPROTO_TCP) 1019231437Sluigi return NULL; 1020231437Sluigi th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 1021231437Sluigi 1022231437Sluigi total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 1023231437Sluigi break; 1024231511Sbz#endif 1025231511Sbz#ifdef INET6 1026231437Sluigi case ETHERTYPE_IPV6: 1027231437Sluigi ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 1028231437Sluigi if (ip6->ip6_nxt != IPPROTO_TCP) 1029231437Sluigi return NULL; 1030231437Sluigi th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 1031231437Sluigi 1032231437Sluigi total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 1033231437Sluigi break; 1034231511Sbz#endif 1035231437Sluigi default: 1036231437Sluigi return NULL; 1037231437Sluigi } 1038231437Sluigi 1039231437Sluigi m = m_pullup(m, total_len); 1040231437Sluigi if (!m) 1041231437Sluigi return NULL; 1042231437Sluigi *mpp = m; 1043231437Sluigi return m; 1044231437Sluigi 1045231437Sluigi} 1046231511Sbz#endif /* INET6 || INET */ 1047231437Sluigi 1048231437Sluigivoid 1049231437Sluigioce_tx_task(void *arg, int npending) 1050231437Sluigi{ 1051231437Sluigi struct oce_wq *wq = arg; 1052231437Sluigi POCE_SOFTC sc = wq->parent; 1053231437Sluigi struct ifnet *ifp = sc->ifp; 1054231437Sluigi int rc = 0; 1055231437Sluigi 1056231437Sluigi#if __FreeBSD_version >= 800000 1057231437Sluigi if (TRY_LOCK(&wq->tx_lock)) { 1058231437Sluigi rc = oce_multiq_transmit(ifp, NULL, wq); 1059231437Sluigi if (rc) { 1060231437Sluigi device_printf(sc->dev, 1061231437Sluigi "TX[%d] restart failed\n", wq->queue_index); 1062231437Sluigi } 1063231437Sluigi UNLOCK(&wq->tx_lock); 1064231437Sluigi } 1065231437Sluigi#else 1066231437Sluigi oce_start(ifp); 1067231437Sluigi#endif 1068231437Sluigi 1069231437Sluigi} 1070231437Sluigi 1071231437Sluigi 1072231437Sluigivoid 1073231437Sluigioce_start(struct ifnet *ifp) 1074231437Sluigi{ 1075231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1076231437Sluigi struct mbuf *m; 1077231437Sluigi int rc = 0; 1078231879Sluigi int def_q = 0; /* Defualt tx queue is 0*/ 1079231437Sluigi 1080231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1081231437Sluigi IFF_DRV_RUNNING) 1082231437Sluigi return; 1083231437Sluigi 1084231437Sluigi do { 1085231437Sluigi IF_DEQUEUE(&sc->ifp->if_snd, m); 1086231437Sluigi if (m == NULL) 1087231437Sluigi break; 1088231879Sluigi 1089231879Sluigi LOCK(&sc->wq[def_q]->tx_lock); 1090231879Sluigi rc = oce_tx(sc, &m, def_q); 1091231879Sluigi UNLOCK(&sc->wq[def_q]->tx_lock); 1092231437Sluigi if (rc) { 1093231437Sluigi if (m != NULL) { 1094231879Sluigi sc->wq[def_q]->tx_stats.tx_stops ++; 1095231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1096231437Sluigi IFQ_DRV_PREPEND(&ifp->if_snd, m); 1097231437Sluigi m = NULL; 1098231437Sluigi } 1099231437Sluigi break; 1100231437Sluigi } 1101231437Sluigi if (m != NULL) 1102231437Sluigi ETHER_BPF_MTAP(ifp, m); 1103231437Sluigi 1104231879Sluigi } while (TRUE); 1105231437Sluigi 1106231437Sluigi return; 1107231437Sluigi} 1108231437Sluigi 1109231437Sluigi 1110231437Sluigi/* Handle the Completion Queue for transmit */ 1111231437Sluigiuint16_t 1112231437Sluigioce_wq_handler(void *arg) 1113231437Sluigi{ 1114231437Sluigi struct oce_wq *wq = (struct oce_wq *)arg; 1115231437Sluigi POCE_SOFTC sc = wq->parent; 1116231437Sluigi struct oce_cq *cq = wq->cq; 1117231437Sluigi struct oce_nic_tx_cqe *cqe; 1118231437Sluigi int num_cqes = 0; 1119231437Sluigi 1120231437Sluigi LOCK(&wq->tx_lock); 1121231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1122231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1123231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1124231437Sluigi while (cqe->u0.dw[3]) { 1125231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 1126231437Sluigi 1127231437Sluigi wq->ring->cidx = cqe->u0.s.wqe_index + 1; 1128231437Sluigi if (wq->ring->cidx >= wq->ring->num_items) 1129231437Sluigi wq->ring->cidx -= wq->ring->num_items; 1130231437Sluigi 1131231437Sluigi oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status); 1132231437Sluigi wq->tx_stats.tx_compl++; 1133231437Sluigi cqe->u0.dw[3] = 0; 1134231437Sluigi RING_GET(cq->ring, 1); 1135231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1136231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1137231437Sluigi cqe = 1138231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1139231437Sluigi num_cqes++; 1140231437Sluigi } 1141231437Sluigi 1142231437Sluigi if (num_cqes) 1143231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1144231437Sluigi UNLOCK(&wq->tx_lock); 1145231437Sluigi 1146231437Sluigi return 0; 1147231437Sluigi} 1148231437Sluigi 1149231437Sluigi 1150231437Sluigistatic int 1151231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 1152231437Sluigi{ 1153231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1154231437Sluigi int status = 0, queue_index = 0; 1155231437Sluigi struct mbuf *next = NULL; 1156231437Sluigi struct buf_ring *br = NULL; 1157231437Sluigi 1158231437Sluigi br = wq->br; 1159231437Sluigi queue_index = wq->queue_index; 1160231437Sluigi 1161231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1162231437Sluigi IFF_DRV_RUNNING) { 1163231437Sluigi if (m != NULL) 1164231437Sluigi status = drbr_enqueue(ifp, br, m); 1165231437Sluigi return status; 1166231437Sluigi } 1167231437Sluigi 1168231437Sluigi if (m == NULL) 1169231437Sluigi next = drbr_dequeue(ifp, br); 1170231437Sluigi else if (drbr_needs_enqueue(ifp, br)) { 1171231437Sluigi if ((status = drbr_enqueue(ifp, br, m)) != 0) 1172231437Sluigi return status; 1173231437Sluigi next = drbr_dequeue(ifp, br); 1174231437Sluigi } else 1175231437Sluigi next = m; 1176231437Sluigi 1177231437Sluigi while (next != NULL) { 1178231437Sluigi if (oce_tx(sc, &next, queue_index)) { 1179231437Sluigi if (next != NULL) { 1180231437Sluigi wq->tx_stats.tx_stops ++; 1181231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1182231437Sluigi status = drbr_enqueue(ifp, br, next); 1183231437Sluigi } 1184231437Sluigi break; 1185231437Sluigi } 1186231437Sluigi drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags); 1187231437Sluigi ETHER_BPF_MTAP(ifp, next); 1188231437Sluigi next = drbr_dequeue(ifp, br); 1189231437Sluigi } 1190231437Sluigi 1191231437Sluigi return status; 1192231437Sluigi} 1193231437Sluigi 1194231437Sluigi 1195231437Sluigi 1196231437Sluigi 1197231437Sluigi/***************************************************************************** 1198231437Sluigi * Receive routines functions * 1199231437Sluigi *****************************************************************************/ 1200231437Sluigi 1201231437Sluigistatic void 1202231437Sluigioce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe) 1203231437Sluigi{ 1204231437Sluigi uint32_t out; 1205231437Sluigi struct oce_packet_desc *pd; 1206231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1207231437Sluigi int i, len, frag_len; 1208231437Sluigi struct mbuf *m = NULL, *tail = NULL; 1209231437Sluigi uint16_t vtag; 1210231437Sluigi 1211231437Sluigi len = cqe->u0.s.pkt_size; 1212231437Sluigi if (!len) { 1213231437Sluigi /*partial DMA workaround for Lancer*/ 1214231437Sluigi oce_discard_rx_comp(rq, cqe); 1215231437Sluigi goto exit; 1216231437Sluigi } 1217231437Sluigi 1218231879Sluigi /* Get vlan_tag value */ 1219231879Sluigi if(IS_BE(sc)) 1220231879Sluigi vtag = BSWAP_16(cqe->u0.s.vlan_tag); 1221231879Sluigi else 1222231879Sluigi vtag = cqe->u0.s.vlan_tag; 1223231879Sluigi 1224231879Sluigi 1225231437Sluigi for (i = 0; i < cqe->u0.s.num_fragments; i++) { 1226231437Sluigi 1227231437Sluigi if (rq->packets_out == rq->packets_in) { 1228231437Sluigi device_printf(sc->dev, 1229231437Sluigi "RQ transmit descriptor missing\n"); 1230231437Sluigi } 1231231437Sluigi out = rq->packets_out + 1; 1232231437Sluigi if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1233231437Sluigi out = 0; 1234231437Sluigi pd = &rq->pckts[rq->packets_out]; 1235231437Sluigi rq->packets_out = out; 1236231437Sluigi 1237231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1238231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1239231437Sluigi rq->pending--; 1240231437Sluigi 1241231437Sluigi frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 1242231437Sluigi pd->mbuf->m_len = frag_len; 1243231437Sluigi 1244231437Sluigi if (tail != NULL) { 1245231437Sluigi /* additional fragments */ 1246231437Sluigi pd->mbuf->m_flags &= ~M_PKTHDR; 1247231437Sluigi tail->m_next = pd->mbuf; 1248231437Sluigi tail = pd->mbuf; 1249231437Sluigi } else { 1250231437Sluigi /* first fragment, fill out much of the packet header */ 1251231437Sluigi pd->mbuf->m_pkthdr.len = len; 1252231437Sluigi pd->mbuf->m_pkthdr.csum_flags = 0; 1253231437Sluigi if (IF_CSUM_ENABLED(sc)) { 1254231437Sluigi if (cqe->u0.s.l4_cksum_pass) { 1255231437Sluigi pd->mbuf->m_pkthdr.csum_flags |= 1256231437Sluigi (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1257231437Sluigi pd->mbuf->m_pkthdr.csum_data = 0xffff; 1258231437Sluigi } 1259231437Sluigi if (cqe->u0.s.ip_cksum_pass) { 1260231879Sluigi if (!cqe->u0.s.ip_ver) { /* IPV4 */ 1261231437Sluigi pd->mbuf->m_pkthdr.csum_flags |= 1262231437Sluigi (CSUM_IP_CHECKED|CSUM_IP_VALID); 1263231437Sluigi } 1264231437Sluigi } 1265231437Sluigi } 1266231437Sluigi m = tail = pd->mbuf; 1267231437Sluigi } 1268231437Sluigi pd->mbuf = NULL; 1269231437Sluigi len -= frag_len; 1270231437Sluigi } 1271231437Sluigi 1272231437Sluigi if (m) { 1273231437Sluigi if (!oce_cqe_portid_valid(sc, cqe)) { 1274231437Sluigi m_freem(m); 1275231437Sluigi goto exit; 1276231437Sluigi } 1277231437Sluigi 1278231437Sluigi m->m_pkthdr.rcvif = sc->ifp; 1279231437Sluigi#if __FreeBSD_version >= 800000 1280231437Sluigi m->m_pkthdr.flowid = rq->queue_index; 1281231437Sluigi m->m_flags |= M_FLOWID; 1282231437Sluigi#endif 1283231879Sluigi /* This deternies if vlan tag is Valid */ 1284231437Sluigi if (oce_cqe_vtp_valid(sc, cqe)) { 1285231437Sluigi if (sc->function_mode & FNM_FLEX10_MODE) { 1286231879Sluigi /* FLEX10. If QnQ is not set, neglect VLAN */ 1287231437Sluigi if (cqe->u0.s.qnq) { 1288231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1289231437Sluigi m->m_flags |= M_VLANTAG; 1290231437Sluigi } 1291231879Sluigi } else if (sc->pvid != (vtag & VLAN_VID_MASK)) { 1292231879Sluigi /* In UMC mode generally pvid will be striped by 1293231879Sluigi hw. But in some cases we have seen it comes 1294231879Sluigi with pvid. So if pvid == vlan, neglect vlan. 1295231879Sluigi */ 1296231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1297231437Sluigi m->m_flags |= M_VLANTAG; 1298231437Sluigi } 1299231437Sluigi } 1300231437Sluigi 1301231437Sluigi sc->ifp->if_ipackets++; 1302231511Sbz#if defined(INET6) || defined(INET) 1303231437Sluigi /* Try to queue to LRO */ 1304231437Sluigi if (IF_LRO_ENABLED(sc) && 1305231437Sluigi !(m->m_flags & M_VLANTAG) && 1306231437Sluigi (cqe->u0.s.ip_cksum_pass) && 1307231437Sluigi (cqe->u0.s.l4_cksum_pass) && 1308231437Sluigi (!cqe->u0.s.ip_ver) && 1309231437Sluigi (rq->lro.lro_cnt != 0)) { 1310231437Sluigi 1311231437Sluigi if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 1312231437Sluigi rq->lro_pkts_queued ++; 1313231437Sluigi goto post_done; 1314231437Sluigi } 1315231437Sluigi /* If LRO posting fails then try to post to STACK */ 1316231437Sluigi } 1317231511Sbz#endif 1318231437Sluigi 1319231437Sluigi (*sc->ifp->if_input) (sc->ifp, m); 1320231511Sbz#if defined(INET6) || defined(INET) 1321231437Sluigipost_done: 1322231511Sbz#endif 1323231437Sluigi /* Update rx stats per queue */ 1324231437Sluigi rq->rx_stats.rx_pkts++; 1325231437Sluigi rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 1326231437Sluigi rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 1327231437Sluigi if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 1328231437Sluigi rq->rx_stats.rx_mcast_pkts++; 1329231437Sluigi if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 1330231437Sluigi rq->rx_stats.rx_ucast_pkts++; 1331231437Sluigi } 1332231437Sluigiexit: 1333231437Sluigi return; 1334231437Sluigi} 1335231437Sluigi 1336231437Sluigi 1337231437Sluigistatic void 1338231437Sluigioce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1339231437Sluigi{ 1340231437Sluigi uint32_t out, i = 0; 1341231437Sluigi struct oce_packet_desc *pd; 1342231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1343231437Sluigi int num_frags = cqe->u0.s.num_fragments; 1344231437Sluigi 1345231437Sluigi if (IS_XE201(sc) && cqe->u0.s.error) { 1346231437Sluigi /* Lancer A0 workaround 1347231437Sluigi * num_frags will be 1 more than actual in case of error 1348231437Sluigi */ 1349231437Sluigi if (num_frags) 1350231437Sluigi num_frags -= 1; 1351231437Sluigi } 1352231437Sluigi for (i = 0; i < num_frags; i++) { 1353231437Sluigi if (rq->packets_out == rq->packets_in) { 1354231437Sluigi device_printf(sc->dev, 1355231437Sluigi "RQ transmit descriptor missing\n"); 1356231437Sluigi } 1357231437Sluigi out = rq->packets_out + 1; 1358231437Sluigi if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1359231437Sluigi out = 0; 1360231437Sluigi pd = &rq->pckts[rq->packets_out]; 1361231437Sluigi rq->packets_out = out; 1362231437Sluigi 1363231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1364231437Sluigi bus_dmamap_unload(rq->tag, pd->map); 1365231437Sluigi rq->pending--; 1366231437Sluigi m_freem(pd->mbuf); 1367231437Sluigi } 1368231437Sluigi 1369231437Sluigi} 1370231437Sluigi 1371231437Sluigi 1372231437Sluigistatic int 1373231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1374231437Sluigi{ 1375231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1376231437Sluigi int vtp = 0; 1377231437Sluigi 1378231437Sluigi if (sc->be3_native) { 1379231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1380231437Sluigi vtp = cqe_v1->u0.s.vlan_tag_present; 1381231879Sluigi } else 1382231437Sluigi vtp = cqe->u0.s.vlan_tag_present; 1383231437Sluigi 1384231437Sluigi return vtp; 1385231437Sluigi 1386231437Sluigi} 1387231437Sluigi 1388231437Sluigi 1389231437Sluigistatic int 1390231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1391231437Sluigi{ 1392231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1393231437Sluigi int port_id = 0; 1394231437Sluigi 1395231437Sluigi if (sc->be3_native && IS_BE(sc)) { 1396231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1397231437Sluigi port_id = cqe_v1->u0.s.port; 1398231437Sluigi if (sc->port_id != port_id) 1399231437Sluigi return 0; 1400231437Sluigi } else 1401231437Sluigi ;/* For BE3 legacy and Lancer this is dummy */ 1402231437Sluigi 1403231437Sluigi return 1; 1404231437Sluigi 1405231437Sluigi} 1406231437Sluigi 1407231511Sbz#if defined(INET6) || defined(INET) 1408231437Sluigistatic void 1409231437Sluigioce_rx_flush_lro(struct oce_rq *rq) 1410231437Sluigi{ 1411231437Sluigi struct lro_ctrl *lro = &rq->lro; 1412231437Sluigi struct lro_entry *queued; 1413231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1414231437Sluigi 1415231437Sluigi if (!IF_LRO_ENABLED(sc)) 1416231437Sluigi return; 1417231437Sluigi 1418231437Sluigi while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { 1419231437Sluigi SLIST_REMOVE_HEAD(&lro->lro_active, next); 1420231437Sluigi tcp_lro_flush(lro, queued); 1421231437Sluigi } 1422231437Sluigi rq->lro_pkts_queued = 0; 1423231437Sluigi 1424231437Sluigi return; 1425231437Sluigi} 1426231437Sluigi 1427231437Sluigi 1428231437Sluigistatic int 1429231437Sluigioce_init_lro(POCE_SOFTC sc) 1430231437Sluigi{ 1431231437Sluigi struct lro_ctrl *lro = NULL; 1432231437Sluigi int i = 0, rc = 0; 1433231437Sluigi 1434231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1435231437Sluigi lro = &sc->rq[i]->lro; 1436231437Sluigi rc = tcp_lro_init(lro); 1437231437Sluigi if (rc != 0) { 1438231437Sluigi device_printf(sc->dev, "LRO init failed\n"); 1439231437Sluigi return rc; 1440231437Sluigi } 1441231437Sluigi lro->ifp = sc->ifp; 1442231437Sluigi } 1443231437Sluigi 1444231437Sluigi return rc; 1445231437Sluigi} 1446231437Sluigi 1447231879Sluigi 1448231437Sluigivoid 1449231437Sluigioce_free_lro(POCE_SOFTC sc) 1450231437Sluigi{ 1451231437Sluigi struct lro_ctrl *lro = NULL; 1452231437Sluigi int i = 0; 1453231437Sluigi 1454231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1455231437Sluigi lro = &sc->rq[i]->lro; 1456231437Sluigi if (lro) 1457231437Sluigi tcp_lro_free(lro); 1458231437Sluigi } 1459231437Sluigi} 1460231879Sluigi#endif /* INET6 || INET */ 1461231437Sluigi 1462231437Sluigiint 1463231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count) 1464231437Sluigi{ 1465231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1466231437Sluigi int i, in, rc; 1467231437Sluigi struct oce_packet_desc *pd; 1468231437Sluigi bus_dma_segment_t segs[6]; 1469231437Sluigi int nsegs, added = 0; 1470231437Sluigi struct oce_nic_rqe *rqe; 1471231437Sluigi pd_rxulp_db_t rxdb_reg; 1472231437Sluigi 1473231437Sluigi 1474231437Sluigi for (i = 0; i < count; i++) { 1475231437Sluigi in = rq->packets_in + 1; 1476231437Sluigi if (in == OCE_RQ_PACKET_ARRAY_SIZE) 1477231437Sluigi in = 0; 1478231437Sluigi if (in == rq->packets_out) 1479231437Sluigi break; /* no more room */ 1480231437Sluigi 1481231437Sluigi pd = &rq->pckts[rq->packets_in]; 1482231437Sluigi pd->mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1483231437Sluigi if (pd->mbuf == NULL) 1484231437Sluigi break; 1485231437Sluigi 1486231437Sluigi pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES; 1487231437Sluigi rc = bus_dmamap_load_mbuf_sg(rq->tag, 1488231437Sluigi pd->map, 1489231437Sluigi pd->mbuf, 1490231437Sluigi segs, &nsegs, BUS_DMA_NOWAIT); 1491231437Sluigi if (rc) { 1492231437Sluigi m_free(pd->mbuf); 1493231437Sluigi break; 1494231437Sluigi } 1495231437Sluigi 1496231437Sluigi if (nsegs != 1) { 1497231437Sluigi i--; 1498231437Sluigi continue; 1499231437Sluigi } 1500231437Sluigi 1501231437Sluigi rq->packets_in = in; 1502231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 1503231437Sluigi 1504231437Sluigi rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 1505231437Sluigi rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 1506231437Sluigi rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 1507231437Sluigi DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 1508231437Sluigi RING_PUT(rq->ring, 1); 1509231437Sluigi added++; 1510231437Sluigi rq->pending++; 1511231437Sluigi } 1512231437Sluigi if (added != 0) { 1513231437Sluigi for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) { 1514231437Sluigi DELAY(1); 1515231437Sluigi rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS; 1516231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1517231437Sluigi OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1518231437Sluigi added -= OCE_MAX_RQ_POSTS; 1519231437Sluigi } 1520231437Sluigi if (added > 0) { 1521231437Sluigi DELAY(1); 1522231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1523231437Sluigi rxdb_reg.bits.num_posted = added; 1524231437Sluigi OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1525231437Sluigi } 1526231437Sluigi } 1527231437Sluigi 1528231437Sluigi return 0; 1529231437Sluigi} 1530231437Sluigi 1531231437Sluigi 1532231437Sluigi/* Handle the Completion Queue for receive */ 1533231437Sluigiuint16_t 1534231437Sluigioce_rq_handler(void *arg) 1535231437Sluigi{ 1536231437Sluigi struct oce_rq *rq = (struct oce_rq *)arg; 1537231437Sluigi struct oce_cq *cq = rq->cq; 1538231437Sluigi POCE_SOFTC sc = rq->parent; 1539231437Sluigi struct oce_nic_rx_cqe *cqe; 1540231437Sluigi int num_cqes = 0, rq_buffers_used = 0; 1541231437Sluigi 1542231437Sluigi 1543231437Sluigi LOCK(&rq->rx_lock); 1544231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1545231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1546231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1547231437Sluigi while (cqe->u0.dw[2]) { 1548231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 1549231437Sluigi 1550231437Sluigi RING_GET(rq->ring, 1); 1551231437Sluigi if (cqe->u0.s.error == 0) { 1552231437Sluigi oce_rx(rq, cqe->u0.s.frag_index, cqe); 1553231437Sluigi } else { 1554231437Sluigi rq->rx_stats.rxcp_err++; 1555231437Sluigi sc->ifp->if_ierrors++; 1556231437Sluigi if (IS_XE201(sc)) 1557231437Sluigi /* Lancer A0 no buffer workaround */ 1558231437Sluigi oce_discard_rx_comp(rq, cqe); 1559231437Sluigi else 1560231437Sluigi /* Post L3/L4 errors to stack.*/ 1561231437Sluigi oce_rx(rq, cqe->u0.s.frag_index, cqe); 1562231437Sluigi 1563231437Sluigi } 1564231437Sluigi rq->rx_stats.rx_compl++; 1565231437Sluigi cqe->u0.dw[2] = 0; 1566231437Sluigi 1567231511Sbz#if defined(INET6) || defined(INET) 1568231437Sluigi if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 1569231437Sluigi oce_rx_flush_lro(rq); 1570231437Sluigi } 1571231511Sbz#endif 1572231437Sluigi 1573231437Sluigi RING_GET(cq->ring, 1); 1574231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1575231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1576231437Sluigi cqe = 1577231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1578231437Sluigi num_cqes++; 1579231437Sluigi if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 1580231437Sluigi break; 1581231437Sluigi } 1582231879Sluigi 1583231511Sbz#if defined(INET6) || defined(INET) 1584231437Sluigi if (IF_LRO_ENABLED(sc)) 1585231437Sluigi oce_rx_flush_lro(rq); 1586231511Sbz#endif 1587231437Sluigi 1588231437Sluigi if (num_cqes) { 1589231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1590231437Sluigi rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending; 1591231437Sluigi if (rq_buffers_used > 1) 1592231437Sluigi oce_alloc_rx_bufs(rq, (rq_buffers_used - 1)); 1593231437Sluigi } 1594231437Sluigi 1595231437Sluigi UNLOCK(&rq->rx_lock); 1596231437Sluigi 1597231437Sluigi return 0; 1598231437Sluigi 1599231437Sluigi} 1600231437Sluigi 1601231437Sluigi 1602231437Sluigi 1603231437Sluigi 1604231437Sluigi/***************************************************************************** 1605231437Sluigi * Helper function prototypes in this file * 1606231437Sluigi *****************************************************************************/ 1607231437Sluigi 1608231437Sluigistatic int 1609231437Sluigioce_attach_ifp(POCE_SOFTC sc) 1610231437Sluigi{ 1611231437Sluigi 1612231437Sluigi sc->ifp = if_alloc(IFT_ETHER); 1613231437Sluigi if (!sc->ifp) 1614231437Sluigi return ENOMEM; 1615231437Sluigi 1616231437Sluigi ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 1617231437Sluigi ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1618231437Sluigi ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 1619231437Sluigi 1620231437Sluigi sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 1621231437Sluigi sc->ifp->if_ioctl = oce_ioctl; 1622231437Sluigi sc->ifp->if_start = oce_start; 1623231437Sluigi sc->ifp->if_init = oce_init; 1624231437Sluigi sc->ifp->if_mtu = ETHERMTU; 1625231437Sluigi sc->ifp->if_softc = sc; 1626231437Sluigi#if __FreeBSD_version >= 800000 1627231437Sluigi sc->ifp->if_transmit = oce_multiq_start; 1628231437Sluigi sc->ifp->if_qflush = oce_multiq_flush; 1629231437Sluigi#endif 1630231437Sluigi 1631231437Sluigi if_initname(sc->ifp, 1632231437Sluigi device_get_name(sc->dev), device_get_unit(sc->dev)); 1633231437Sluigi 1634231437Sluigi sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 1635231437Sluigi IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 1636231437Sluigi IFQ_SET_READY(&sc->ifp->if_snd); 1637231437Sluigi 1638231437Sluigi sc->ifp->if_hwassist = OCE_IF_HWASSIST; 1639231437Sluigi sc->ifp->if_hwassist |= CSUM_TSO; 1640231437Sluigi sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 1641231437Sluigi 1642231437Sluigi sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 1643231437Sluigi sc->ifp->if_capabilities |= IFCAP_HWCSUM; 1644231437Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 1645231879Sluigi 1646231511Sbz#if defined(INET6) || defined(INET) 1647231511Sbz sc->ifp->if_capabilities |= IFCAP_TSO; 1648231437Sluigi sc->ifp->if_capabilities |= IFCAP_LRO; 1649231879Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 1650231511Sbz#endif 1651231437Sluigi 1652231437Sluigi sc->ifp->if_capenable = sc->ifp->if_capabilities; 1653231509Sbz sc->ifp->if_baudrate = IF_Gbps(10UL); 1654231437Sluigi 1655231437Sluigi ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 1656231437Sluigi 1657231437Sluigi return 0; 1658231437Sluigi} 1659231437Sluigi 1660231437Sluigi 1661231437Sluigistatic void 1662231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1663231437Sluigi{ 1664231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1665231437Sluigi 1666231437Sluigi if (ifp->if_softc != arg) 1667231437Sluigi return; 1668231437Sluigi if ((vtag == 0) || (vtag > 4095)) 1669231437Sluigi return; 1670231437Sluigi 1671231437Sluigi sc->vlan_tag[vtag] = 1; 1672231437Sluigi sc->vlans_added++; 1673231437Sluigi oce_vid_config(sc); 1674231437Sluigi} 1675231437Sluigi 1676231437Sluigi 1677231437Sluigistatic void 1678231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1679231437Sluigi{ 1680231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1681231437Sluigi 1682231437Sluigi if (ifp->if_softc != arg) 1683231437Sluigi return; 1684231437Sluigi if ((vtag == 0) || (vtag > 4095)) 1685231437Sluigi return; 1686231437Sluigi 1687231437Sluigi sc->vlan_tag[vtag] = 0; 1688231437Sluigi sc->vlans_added--; 1689231437Sluigi oce_vid_config(sc); 1690231437Sluigi} 1691231437Sluigi 1692231437Sluigi 1693231437Sluigi/* 1694231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures 1695231437Sluigi * more, place the card in vlan promiscuous mode. 1696231437Sluigi */ 1697231437Sluigistatic int 1698231437Sluigioce_vid_config(POCE_SOFTC sc) 1699231437Sluigi{ 1700231437Sluigi struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 1701231437Sluigi uint16_t ntags = 0, i; 1702231437Sluigi int status = 0; 1703231437Sluigi 1704231437Sluigi if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 1705231437Sluigi (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 1706231437Sluigi for (i = 0; i < MAX_VLANS; i++) { 1707231437Sluigi if (sc->vlan_tag[i]) { 1708231437Sluigi vtags[ntags].vtag = i; 1709231437Sluigi ntags++; 1710231437Sluigi } 1711231437Sluigi } 1712231437Sluigi if (ntags) 1713231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1714231437Sluigi vtags, ntags, 1, 0); 1715231437Sluigi } else 1716231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1717231437Sluigi NULL, 0, 1, 1); 1718231437Sluigi return status; 1719231437Sluigi} 1720231437Sluigi 1721231437Sluigi 1722231437Sluigistatic void 1723231437Sluigioce_mac_addr_set(POCE_SOFTC sc) 1724231437Sluigi{ 1725231437Sluigi uint32_t old_pmac_id = sc->pmac_id; 1726231437Sluigi int status = 0; 1727231437Sluigi 1728231437Sluigi 1729231437Sluigi status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1730231437Sluigi sc->macaddr.size_of_struct); 1731231437Sluigi if (!status) 1732231437Sluigi return; 1733231437Sluigi 1734231437Sluigi status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 1735231437Sluigi sc->if_id, &sc->pmac_id); 1736231437Sluigi if (!status) { 1737231437Sluigi status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 1738231437Sluigi bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1739231437Sluigi sc->macaddr.size_of_struct); 1740231437Sluigi } 1741231437Sluigi if (status) 1742231437Sluigi device_printf(sc->dev, "Failed update macaddress\n"); 1743231437Sluigi 1744231437Sluigi} 1745231437Sluigi 1746231437Sluigi 1747231437Sluigistatic int 1748231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data) 1749231437Sluigi{ 1750231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1751231437Sluigi struct ifreq *ifr = (struct ifreq *)data; 1752231437Sluigi int rc = ENXIO; 1753231437Sluigi char cookie[32] = {0}; 1754231437Sluigi void *priv_data = (void *)ifr->ifr_data; 1755231437Sluigi void *ioctl_ptr; 1756231437Sluigi uint32_t req_size; 1757231437Sluigi struct mbx_hdr req; 1758231437Sluigi OCE_DMA_MEM dma_mem; 1759231437Sluigi 1760231437Sluigi 1761231437Sluigi if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 1762231437Sluigi return EFAULT; 1763231437Sluigi 1764231437Sluigi if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 1765231437Sluigi return EINVAL; 1766231437Sluigi 1767231437Sluigi ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 1768231437Sluigi if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 1769231437Sluigi return EFAULT; 1770231437Sluigi 1771231437Sluigi req_size = le32toh(req.u0.req.request_length); 1772231437Sluigi if (req_size > 65536) 1773231437Sluigi return EINVAL; 1774231437Sluigi 1775231437Sluigi req_size += sizeof(struct mbx_hdr); 1776231437Sluigi rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 1777231437Sluigi if (rc) 1778231437Sluigi return ENOMEM; 1779231437Sluigi 1780231437Sluigi if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 1781231437Sluigi rc = EFAULT; 1782231437Sluigi goto dma_free; 1783231437Sluigi } 1784231437Sluigi 1785231437Sluigi rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 1786231437Sluigi if (rc) { 1787231437Sluigi rc = EIO; 1788231437Sluigi goto dma_free; 1789231437Sluigi } 1790231437Sluigi 1791231437Sluigi if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 1792231437Sluigi rc = EFAULT; 1793231437Sluigi 1794231437Sluigidma_free: 1795231437Sluigi oce_dma_free(sc, &dma_mem); 1796231437Sluigi return rc; 1797231437Sluigi 1798231437Sluigi} 1799231437Sluigi 1800231437Sluigi 1801231437Sluigistatic void 1802231437Sluigioce_local_timer(void *arg) 1803231437Sluigi{ 1804231437Sluigi POCE_SOFTC sc = arg; 1805231437Sluigi int i = 0; 1806231437Sluigi 1807231437Sluigi oce_refresh_nic_stats(sc); 1808231437Sluigi oce_refresh_queue_stats(sc); 1809231437Sluigi oce_mac_addr_set(sc); 1810231437Sluigi 1811231437Sluigi /* TX Watch Dog*/ 1812231437Sluigi for (i = 0; i < sc->nwqs; i++) 1813231437Sluigi oce_tx_restart(sc, sc->wq[i]); 1814231437Sluigi 1815231437Sluigi callout_reset(&sc->timer, hz, oce_local_timer, sc); 1816231437Sluigi} 1817231437Sluigi 1818231437Sluigi 1819231437Sluigistatic void 1820231437Sluigioce_if_deactivate(POCE_SOFTC sc) 1821231437Sluigi{ 1822231437Sluigi int i, mtime = 0; 1823231437Sluigi int wait_req = 0; 1824231437Sluigi struct oce_rq *rq; 1825231437Sluigi struct oce_wq *wq; 1826231437Sluigi struct oce_eq *eq; 1827231437Sluigi 1828231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1829231437Sluigi 1830231437Sluigi /*Wait for max of 400ms for TX completions to be done */ 1831231437Sluigi while (mtime < 400) { 1832231437Sluigi wait_req = 0; 1833231437Sluigi for_all_wq_queues(sc, wq, i) { 1834231437Sluigi if (wq->ring->num_used) { 1835231437Sluigi wait_req = 1; 1836231437Sluigi DELAY(1); 1837231437Sluigi break; 1838231437Sluigi } 1839231437Sluigi } 1840231437Sluigi mtime += 1; 1841231437Sluigi if (!wait_req) 1842231437Sluigi break; 1843231437Sluigi } 1844231437Sluigi 1845231437Sluigi /* Stop intrs and finish any bottom halves pending */ 1846231437Sluigi oce_hw_intr_disable(sc); 1847231437Sluigi 1848231437Sluigi for (i = 0; i < sc->intr_count; i++) { 1849231437Sluigi if (sc->intrs[i].tq != NULL) { 1850231437Sluigi taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 1851231437Sluigi } 1852231437Sluigi } 1853231437Sluigi 1854231437Sluigi /* Delete RX queue in card with flush param */ 1855231437Sluigi oce_stop_rx(sc); 1856231437Sluigi 1857231437Sluigi /* Invalidate any pending cq and eq entries*/ 1858231437Sluigi for_all_evnt_queues(sc, eq, i) 1859231437Sluigi oce_drain_eq(eq); 1860231437Sluigi for_all_rq_queues(sc, rq, i) 1861231437Sluigi oce_drain_rq_cq(rq); 1862231437Sluigi for_all_wq_queues(sc, wq, i) 1863231437Sluigi oce_drain_wq_cq(wq); 1864231437Sluigi 1865231437Sluigi /* But still we need to get MCC aync events. 1866231437Sluigi So enable intrs and also arm first EQ 1867231437Sluigi */ 1868231437Sluigi oce_hw_intr_enable(sc); 1869231437Sluigi oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 1870231437Sluigi 1871231437Sluigi DELAY(10); 1872231437Sluigi} 1873231437Sluigi 1874231437Sluigi 1875231437Sluigistatic void 1876231437Sluigioce_if_activate(POCE_SOFTC sc) 1877231437Sluigi{ 1878231437Sluigi struct oce_eq *eq; 1879231437Sluigi struct oce_rq *rq; 1880231437Sluigi struct oce_wq *wq; 1881231437Sluigi int i, rc = 0; 1882231437Sluigi 1883231437Sluigi sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 1884231437Sluigi 1885231437Sluigi oce_hw_intr_disable(sc); 1886231437Sluigi 1887231437Sluigi oce_start_rx(sc); 1888231437Sluigi 1889231437Sluigi for_all_rq_queues(sc, rq, i) { 1890231437Sluigi rc = oce_start_rq(rq); 1891231437Sluigi if (rc) 1892231437Sluigi device_printf(sc->dev, "Unable to start RX\n"); 1893231437Sluigi } 1894231437Sluigi 1895231437Sluigi for_all_wq_queues(sc, wq, i) { 1896231437Sluigi rc = oce_start_wq(wq); 1897231437Sluigi if (rc) 1898231437Sluigi device_printf(sc->dev, "Unable to start TX\n"); 1899231437Sluigi } 1900231437Sluigi 1901231437Sluigi 1902231437Sluigi for_all_evnt_queues(sc, eq, i) 1903231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 1904231437Sluigi 1905231437Sluigi oce_hw_intr_enable(sc); 1906231437Sluigi 1907231437Sluigi} 1908231437Sluigi 1909231879Sluigistatic void 1910231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe) 1911231879Sluigi{ 1912231879Sluigi /* Update Link status */ 1913231879Sluigi if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 1914231879Sluigi ASYNC_EVENT_LINK_UP) { 1915231879Sluigi sc->link_status = ASYNC_EVENT_LINK_UP; 1916231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_UP); 1917231879Sluigi } else { 1918231879Sluigi sc->link_status = ASYNC_EVENT_LINK_DOWN; 1919231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_DOWN); 1920231879Sluigi } 1921231879Sluigi 1922231879Sluigi /* Update speed */ 1923231879Sluigi sc->link_speed = acqe->u0.s.speed; 1924231879Sluigi sc->qos_link_speed = (uint32_t) acqe->u0.s.qos_link_speed * 10; 1925231879Sluigi 1926231879Sluigi} 1927231879Sluigi 1928231879Sluigi 1929231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */ 1930231437Sluigiuint16_t 1931231437Sluigioce_mq_handler(void *arg) 1932231437Sluigi{ 1933231437Sluigi struct oce_mq *mq = (struct oce_mq *)arg; 1934231437Sluigi POCE_SOFTC sc = mq->parent; 1935231437Sluigi struct oce_cq *cq = mq->cq; 1936231879Sluigi int num_cqes = 0, evt_type = 0, optype = 0; 1937231437Sluigi struct oce_mq_cqe *cqe; 1938231437Sluigi struct oce_async_cqe_link_state *acqe; 1939231879Sluigi struct oce_async_event_grp5_pvid_state *gcqe; 1940231437Sluigi 1941231879Sluigi 1942231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1943231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1944231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 1945231879Sluigi 1946231437Sluigi while (cqe->u0.dw[3]) { 1947231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 1948231437Sluigi if (cqe->u0.s.async_event) { 1949231879Sluigi evt_type = cqe->u0.s.event_type; 1950231879Sluigi optype = cqe->u0.s.async_type; 1951231879Sluigi if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) { 1952231879Sluigi /* Link status evt */ 1953231879Sluigi acqe = (struct oce_async_cqe_link_state *)cqe; 1954231879Sluigi process_link_state(sc, acqe); 1955231879Sluigi } else if ((evt_type == ASYNC_EVENT_GRP5) && 1956231879Sluigi (optype == ASYNC_EVENT_PVID_STATE)) { 1957231879Sluigi /* GRP5 PVID */ 1958231879Sluigi gcqe = 1959231879Sluigi (struct oce_async_event_grp5_pvid_state *)cqe; 1960231879Sluigi if (gcqe->enabled) 1961231879Sluigi sc->pvid = gcqe->tag & VLAN_VID_MASK; 1962231879Sluigi else 1963231879Sluigi sc->pvid = 0; 1964231879Sluigi 1965231437Sluigi } 1966231437Sluigi } 1967231437Sluigi cqe->u0.dw[3] = 0; 1968231437Sluigi RING_GET(cq->ring, 1); 1969231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1970231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1971231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 1972231437Sluigi num_cqes++; 1973231437Sluigi } 1974231437Sluigi 1975231437Sluigi if (num_cqes) 1976231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1977231437Sluigi 1978231437Sluigi return 0; 1979231437Sluigi} 1980231437Sluigi 1981231437Sluigi 1982231437Sluigistatic void 1983231437Sluigisetup_max_queues_want(POCE_SOFTC sc) 1984231437Sluigi{ 1985231437Sluigi int max_rss = 0; 1986231437Sluigi 1987231437Sluigi /* Check if it is FLEX machine. Is so dont use RSS */ 1988231437Sluigi if ((sc->function_mode & FNM_FLEX10_MODE) || 1989231879Sluigi (sc->function_mode & FNM_UMC_MODE) || 1990231879Sluigi (sc->function_mode & FNM_VNIC_MODE) || 1991231879Sluigi (!sc->rss_enable) || 1992231879Sluigi (sc->flags & OCE_FLAGS_BE2)) { 1993231437Sluigi sc->nrqs = 1; 1994231437Sluigi sc->nwqs = 1; 1995231437Sluigi sc->rss_enable = 0; 1996231437Sluigi } else { 1997231437Sluigi /* For multiq, our deisgn is to have TX rings equal to 1998231437Sluigi RSS rings. So that we can pair up one RSS ring and TX 1999231437Sluigi to a single intr, which improves CPU cache efficiency. 2000231437Sluigi */ 2001231437Sluigi if (IS_BE(sc) && (!sc->be3_native)) 2002231437Sluigi max_rss = OCE_LEGACY_MODE_RSS; 2003231437Sluigi else 2004231437Sluigi max_rss = OCE_MAX_RSS; 2005231437Sluigi 2006231437Sluigi sc->nrqs = MIN(OCE_NCPUS, max_rss) + 1; /* 1 for def RX */ 2007231437Sluigi sc->nwqs = MIN(OCE_NCPUS, max_rss); 2008231437Sluigi } 2009231437Sluigi 2010231437Sluigi} 2011231437Sluigi 2012231437Sluigi 2013231437Sluigistatic void 2014231437Sluigiupdate_queues_got(POCE_SOFTC sc) 2015231437Sluigi{ 2016231437Sluigi if (sc->rss_enable) { 2017231437Sluigi sc->nrqs = sc->intr_count + 1; 2018231437Sluigi sc->nwqs = sc->intr_count; 2019231437Sluigi } else { 2020231437Sluigi sc->nrqs = 1; 2021231437Sluigi sc->nwqs = 1; 2022231437Sluigi } 2023231437Sluigi} 2024231437Sluigi 2025