1*2f345d8eSLuigi Rizzo /*- 2*2f345d8eSLuigi Rizzo * Copyright (C) 2012 Emulex 3*2f345d8eSLuigi Rizzo * All rights reserved. 4*2f345d8eSLuigi Rizzo * 5*2f345d8eSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 6*2f345d8eSLuigi Rizzo * modification, are permitted provided that the following conditions are met: 7*2f345d8eSLuigi Rizzo * 8*2f345d8eSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright notice, 9*2f345d8eSLuigi Rizzo * this list of conditions and the following disclaimer. 10*2f345d8eSLuigi Rizzo * 11*2f345d8eSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 12*2f345d8eSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 13*2f345d8eSLuigi Rizzo * documentation and/or other materials provided with the distribution. 14*2f345d8eSLuigi Rizzo * 15*2f345d8eSLuigi Rizzo * 3. Neither the name of the Emulex Corporation nor the names of its 16*2f345d8eSLuigi Rizzo * contributors may be used to endorse or promote products derived from 17*2f345d8eSLuigi Rizzo * this software without specific prior written permission. 18*2f345d8eSLuigi Rizzo * 19*2f345d8eSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20*2f345d8eSLuigi Rizzo * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*2f345d8eSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*2f345d8eSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23*2f345d8eSLuigi Rizzo * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24*2f345d8eSLuigi Rizzo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25*2f345d8eSLuigi Rizzo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26*2f345d8eSLuigi Rizzo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27*2f345d8eSLuigi Rizzo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28*2f345d8eSLuigi Rizzo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29*2f345d8eSLuigi Rizzo * POSSIBILITY OF SUCH DAMAGE. 30*2f345d8eSLuigi Rizzo * 31*2f345d8eSLuigi Rizzo * Contact Information: 32*2f345d8eSLuigi Rizzo * freebsd-drivers@emulex.com 33*2f345d8eSLuigi Rizzo * 34*2f345d8eSLuigi Rizzo * Emulex 35*2f345d8eSLuigi Rizzo * 3333 Susan Street 36*2f345d8eSLuigi Rizzo * Costa Mesa, CA 92626 37*2f345d8eSLuigi Rizzo */ 38*2f345d8eSLuigi Rizzo 39*2f345d8eSLuigi Rizzo 40*2f345d8eSLuigi Rizzo /* $FreeBSD$ */ 41*2f345d8eSLuigi Rizzo 42*2f345d8eSLuigi Rizzo #include "oce_if.h" 43*2f345d8eSLuigi Rizzo 44*2f345d8eSLuigi Rizzo 45*2f345d8eSLuigi Rizzo /* Driver entry points prototypes */ 46*2f345d8eSLuigi Rizzo static int oce_probe(device_t dev); 47*2f345d8eSLuigi Rizzo static int oce_attach(device_t dev); 48*2f345d8eSLuigi Rizzo static int oce_detach(device_t dev); 49*2f345d8eSLuigi Rizzo static int oce_shutdown(device_t dev); 50*2f345d8eSLuigi Rizzo static int oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 51*2f345d8eSLuigi Rizzo static void oce_init(void *xsc); 52*2f345d8eSLuigi Rizzo static int oce_multiq_start(struct ifnet *ifp, struct mbuf *m); 53*2f345d8eSLuigi Rizzo static void oce_multiq_flush(struct ifnet *ifp); 54*2f345d8eSLuigi Rizzo 55*2f345d8eSLuigi Rizzo /* Driver interrupt routines protypes */ 56*2f345d8eSLuigi Rizzo static void oce_intr(void *arg, int pending); 57*2f345d8eSLuigi Rizzo static int oce_setup_intr(POCE_SOFTC sc); 58*2f345d8eSLuigi Rizzo static int oce_fast_isr(void *arg); 59*2f345d8eSLuigi Rizzo static int oce_alloc_intr(POCE_SOFTC sc, int vector, 60*2f345d8eSLuigi Rizzo void (*isr) (void *arg, int pending)); 61*2f345d8eSLuigi Rizzo 62*2f345d8eSLuigi Rizzo /* Media callbacks prototypes */ 63*2f345d8eSLuigi Rizzo static void oce_media_status(struct ifnet *ifp, struct ifmediareq *req); 64*2f345d8eSLuigi Rizzo static int oce_media_change(struct ifnet *ifp); 65*2f345d8eSLuigi Rizzo 66*2f345d8eSLuigi Rizzo /* Transmit routines prototypes */ 67*2f345d8eSLuigi Rizzo static int oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index); 68*2f345d8eSLuigi Rizzo static void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq); 69*2f345d8eSLuigi Rizzo static void oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, 70*2f345d8eSLuigi Rizzo uint32_t status); 71*2f345d8eSLuigi Rizzo static struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp, 72*2f345d8eSLuigi Rizzo uint16_t *mss); 73*2f345d8eSLuigi Rizzo static int oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, 74*2f345d8eSLuigi Rizzo struct oce_wq *wq); 75*2f345d8eSLuigi Rizzo 76*2f345d8eSLuigi Rizzo /* Receive routines prototypes */ 77*2f345d8eSLuigi Rizzo static void oce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); 78*2f345d8eSLuigi Rizzo static int oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 79*2f345d8eSLuigi Rizzo static int oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 80*2f345d8eSLuigi Rizzo static void oce_rx_flush_lro(struct oce_rq *rq); 81*2f345d8eSLuigi Rizzo static void oce_rx(struct oce_rq *rq, uint32_t rqe_idx, 82*2f345d8eSLuigi Rizzo struct oce_nic_rx_cqe *cqe); 83*2f345d8eSLuigi Rizzo 84*2f345d8eSLuigi Rizzo /* Helper function prototypes in this file */ 85*2f345d8eSLuigi Rizzo static int oce_attach_ifp(POCE_SOFTC sc); 86*2f345d8eSLuigi Rizzo static void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 87*2f345d8eSLuigi Rizzo static void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 88*2f345d8eSLuigi Rizzo static int oce_vid_config(POCE_SOFTC sc); 89*2f345d8eSLuigi Rizzo static void oce_mac_addr_set(POCE_SOFTC sc); 90*2f345d8eSLuigi Rizzo static int oce_handle_passthrough(struct ifnet *ifp, caddr_t data); 91*2f345d8eSLuigi Rizzo static void oce_local_timer(void *arg); 92*2f345d8eSLuigi Rizzo static int oce_init_lro(POCE_SOFTC sc); 93*2f345d8eSLuigi Rizzo static void oce_if_deactivate(POCE_SOFTC sc); 94*2f345d8eSLuigi Rizzo static void oce_if_activate(POCE_SOFTC sc); 95*2f345d8eSLuigi Rizzo static void setup_max_queues_want(POCE_SOFTC sc); 96*2f345d8eSLuigi Rizzo static void update_queues_got(POCE_SOFTC sc); 97*2f345d8eSLuigi Rizzo 98*2f345d8eSLuigi Rizzo static device_method_t oce_dispatch[] = { 99*2f345d8eSLuigi Rizzo DEVMETHOD(device_probe, oce_probe), 100*2f345d8eSLuigi Rizzo DEVMETHOD(device_attach, oce_attach), 101*2f345d8eSLuigi Rizzo DEVMETHOD(device_detach, oce_detach), 102*2f345d8eSLuigi Rizzo DEVMETHOD(device_shutdown, oce_shutdown), 103*2f345d8eSLuigi Rizzo {0, 0} 104*2f345d8eSLuigi Rizzo }; 105*2f345d8eSLuigi Rizzo 106*2f345d8eSLuigi Rizzo static driver_t oce_driver = { 107*2f345d8eSLuigi Rizzo "oce", 108*2f345d8eSLuigi Rizzo oce_dispatch, 109*2f345d8eSLuigi Rizzo sizeof(OCE_SOFTC) 110*2f345d8eSLuigi Rizzo }; 111*2f345d8eSLuigi Rizzo static devclass_t oce_devclass; 112*2f345d8eSLuigi Rizzo 113*2f345d8eSLuigi Rizzo 114*2f345d8eSLuigi Rizzo DRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0); 115*2f345d8eSLuigi Rizzo MODULE_DEPEND(oce, pci, 1, 1, 1); 116*2f345d8eSLuigi Rizzo MODULE_DEPEND(oce, ether, 1, 1, 1); 117*2f345d8eSLuigi Rizzo MODULE_VERSION(oce, 1); 118*2f345d8eSLuigi Rizzo 119*2f345d8eSLuigi Rizzo 120*2f345d8eSLuigi Rizzo /* global vars */ 121*2f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"}; 122*2f345d8eSLuigi Rizzo 123*2f345d8eSLuigi Rizzo /* Module capabilites and parameters */ 124*2f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED; 125*2f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS; 126*2f345d8eSLuigi Rizzo 127*2f345d8eSLuigi Rizzo 128*2f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled); 129*2f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss); 130*2f345d8eSLuigi Rizzo 131*2f345d8eSLuigi Rizzo 132*2f345d8eSLuigi Rizzo /* Supported devices table */ 133*2f345d8eSLuigi Rizzo static uint32_t supportedDevices[] = { 134*2f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2, 135*2f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3, 136*2f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3, 137*2f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201, 138*2f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF, 139*2f345d8eSLuigi Rizzo }; 140*2f345d8eSLuigi Rizzo 141*2f345d8eSLuigi Rizzo 142*2f345d8eSLuigi Rizzo 143*2f345d8eSLuigi Rizzo 144*2f345d8eSLuigi Rizzo /***************************************************************************** 145*2f345d8eSLuigi Rizzo * Driver entry points functions * 146*2f345d8eSLuigi Rizzo *****************************************************************************/ 147*2f345d8eSLuigi Rizzo 148*2f345d8eSLuigi Rizzo static int 149*2f345d8eSLuigi Rizzo oce_probe(device_t dev) 150*2f345d8eSLuigi Rizzo { 151*2f345d8eSLuigi Rizzo uint16_t vendor; 152*2f345d8eSLuigi Rizzo uint16_t device; 153*2f345d8eSLuigi Rizzo int i; 154*2f345d8eSLuigi Rizzo char str[80]; 155*2f345d8eSLuigi Rizzo POCE_SOFTC sc; 156*2f345d8eSLuigi Rizzo 157*2f345d8eSLuigi Rizzo sc = device_get_softc(dev); 158*2f345d8eSLuigi Rizzo bzero(sc, sizeof(OCE_SOFTC)); 159*2f345d8eSLuigi Rizzo sc->dev = dev; 160*2f345d8eSLuigi Rizzo 161*2f345d8eSLuigi Rizzo vendor = pci_get_vendor(dev); 162*2f345d8eSLuigi Rizzo device = pci_get_device(dev); 163*2f345d8eSLuigi Rizzo 164*2f345d8eSLuigi Rizzo for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint16_t)); i++) { 165*2f345d8eSLuigi Rizzo if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) { 166*2f345d8eSLuigi Rizzo if (device == (supportedDevices[i] & 0xffff)) { 167*2f345d8eSLuigi Rizzo sprintf(str, "%s:%s", 168*2f345d8eSLuigi Rizzo "Emulex CNA NIC function", 169*2f345d8eSLuigi Rizzo component_revision); 170*2f345d8eSLuigi Rizzo device_set_desc_copy(dev, str); 171*2f345d8eSLuigi Rizzo 172*2f345d8eSLuigi Rizzo switch (device) { 173*2f345d8eSLuigi Rizzo case PCI_PRODUCT_BE2: 174*2f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE2; 175*2f345d8eSLuigi Rizzo break; 176*2f345d8eSLuigi Rizzo case PCI_PRODUCT_BE3: 177*2f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE3; 178*2f345d8eSLuigi Rizzo break; 179*2f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201: 180*2f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201_VF: 181*2f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_XE201; 182*2f345d8eSLuigi Rizzo break; 183*2f345d8eSLuigi Rizzo default: 184*2f345d8eSLuigi Rizzo return ENXIO; 185*2f345d8eSLuigi Rizzo } 186*2f345d8eSLuigi Rizzo return BUS_PROBE_DEFAULT; 187*2f345d8eSLuigi Rizzo } 188*2f345d8eSLuigi Rizzo } 189*2f345d8eSLuigi Rizzo } 190*2f345d8eSLuigi Rizzo 191*2f345d8eSLuigi Rizzo return ENXIO; 192*2f345d8eSLuigi Rizzo } 193*2f345d8eSLuigi Rizzo 194*2f345d8eSLuigi Rizzo 195*2f345d8eSLuigi Rizzo static int 196*2f345d8eSLuigi Rizzo oce_attach(device_t dev) 197*2f345d8eSLuigi Rizzo { 198*2f345d8eSLuigi Rizzo POCE_SOFTC sc; 199*2f345d8eSLuigi Rizzo int rc = 0; 200*2f345d8eSLuigi Rizzo 201*2f345d8eSLuigi Rizzo sc = device_get_softc(dev); 202*2f345d8eSLuigi Rizzo 203*2f345d8eSLuigi Rizzo rc = oce_hw_pci_alloc(sc); 204*2f345d8eSLuigi Rizzo if (rc) 205*2f345d8eSLuigi Rizzo return rc; 206*2f345d8eSLuigi Rizzo 207*2f345d8eSLuigi Rizzo sc->rss_enable = oce_enable_rss; 208*2f345d8eSLuigi Rizzo sc->tx_ring_size = OCE_TX_RING_SIZE; 209*2f345d8eSLuigi Rizzo sc->rx_ring_size = OCE_RX_RING_SIZE; 210*2f345d8eSLuigi Rizzo sc->rq_frag_size = OCE_RQ_BUF_SIZE; 211*2f345d8eSLuigi Rizzo sc->flow_control = OCE_DEFAULT_FLOW_CONTROL; 212*2f345d8eSLuigi Rizzo sc->promisc = OCE_DEFAULT_PROMISCUOUS; 213*2f345d8eSLuigi Rizzo 214*2f345d8eSLuigi Rizzo LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock"); 215*2f345d8eSLuigi Rizzo LOCK_CREATE(&sc->dev_lock, "Device_lock"); 216*2f345d8eSLuigi Rizzo 217*2f345d8eSLuigi Rizzo /* initialise the hardware */ 218*2f345d8eSLuigi Rizzo rc = oce_hw_init(sc); 219*2f345d8eSLuigi Rizzo if (rc) 220*2f345d8eSLuigi Rizzo goto pci_res_free; 221*2f345d8eSLuigi Rizzo 222*2f345d8eSLuigi Rizzo 223*2f345d8eSLuigi Rizzo setup_max_queues_want(sc); 224*2f345d8eSLuigi Rizzo 225*2f345d8eSLuigi Rizzo 226*2f345d8eSLuigi Rizzo rc = oce_setup_intr(sc); 227*2f345d8eSLuigi Rizzo if (rc) 228*2f345d8eSLuigi Rizzo goto mbox_free; 229*2f345d8eSLuigi Rizzo 230*2f345d8eSLuigi Rizzo 231*2f345d8eSLuigi Rizzo rc = oce_queue_init_all(sc); 232*2f345d8eSLuigi Rizzo if (rc) 233*2f345d8eSLuigi Rizzo goto intr_free; 234*2f345d8eSLuigi Rizzo 235*2f345d8eSLuigi Rizzo 236*2f345d8eSLuigi Rizzo rc = oce_attach_ifp(sc); 237*2f345d8eSLuigi Rizzo if (rc) 238*2f345d8eSLuigi Rizzo goto queues_free; 239*2f345d8eSLuigi Rizzo 240*2f345d8eSLuigi Rizzo 241*2f345d8eSLuigi Rizzo rc = oce_init_lro(sc); 242*2f345d8eSLuigi Rizzo if (rc) 243*2f345d8eSLuigi Rizzo goto ifp_free; 244*2f345d8eSLuigi Rizzo 245*2f345d8eSLuigi Rizzo 246*2f345d8eSLuigi Rizzo rc = oce_hw_start(sc); 247*2f345d8eSLuigi Rizzo if (rc) 248*2f345d8eSLuigi Rizzo goto lro_free;; 249*2f345d8eSLuigi Rizzo 250*2f345d8eSLuigi Rizzo 251*2f345d8eSLuigi Rizzo sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 252*2f345d8eSLuigi Rizzo oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST); 253*2f345d8eSLuigi Rizzo sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 254*2f345d8eSLuigi Rizzo oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST); 255*2f345d8eSLuigi Rizzo 256*2f345d8eSLuigi Rizzo rc = oce_stats_init(sc); 257*2f345d8eSLuigi Rizzo if (rc) 258*2f345d8eSLuigi Rizzo goto vlan_free; 259*2f345d8eSLuigi Rizzo 260*2f345d8eSLuigi Rizzo oce_add_sysctls(sc); 261*2f345d8eSLuigi Rizzo 262*2f345d8eSLuigi Rizzo 263*2f345d8eSLuigi Rizzo callout_init(&sc->timer, CALLOUT_MPSAFE); 264*2f345d8eSLuigi Rizzo rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc); 265*2f345d8eSLuigi Rizzo if (rc) 266*2f345d8eSLuigi Rizzo goto stats_free; 267*2f345d8eSLuigi Rizzo 268*2f345d8eSLuigi Rizzo return 0; 269*2f345d8eSLuigi Rizzo 270*2f345d8eSLuigi Rizzo stats_free: 271*2f345d8eSLuigi Rizzo callout_drain(&sc->timer); 272*2f345d8eSLuigi Rizzo oce_stats_free(sc); 273*2f345d8eSLuigi Rizzo vlan_free: 274*2f345d8eSLuigi Rizzo if (sc->vlan_attach) 275*2f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 276*2f345d8eSLuigi Rizzo if (sc->vlan_detach) 277*2f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 278*2f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 279*2f345d8eSLuigi Rizzo lro_free: 280*2f345d8eSLuigi Rizzo oce_free_lro(sc); 281*2f345d8eSLuigi Rizzo ifp_free: 282*2f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp); 283*2f345d8eSLuigi Rizzo if_free(sc->ifp); 284*2f345d8eSLuigi Rizzo queues_free: 285*2f345d8eSLuigi Rizzo oce_queue_release_all(sc); 286*2f345d8eSLuigi Rizzo intr_free: 287*2f345d8eSLuigi Rizzo oce_intr_free(sc); 288*2f345d8eSLuigi Rizzo mbox_free: 289*2f345d8eSLuigi Rizzo oce_dma_free(sc, &sc->bsmbx); 290*2f345d8eSLuigi Rizzo pci_res_free: 291*2f345d8eSLuigi Rizzo oce_hw_pci_free(sc); 292*2f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->dev_lock); 293*2f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->bmbx_lock); 294*2f345d8eSLuigi Rizzo return rc; 295*2f345d8eSLuigi Rizzo 296*2f345d8eSLuigi Rizzo } 297*2f345d8eSLuigi Rizzo 298*2f345d8eSLuigi Rizzo 299*2f345d8eSLuigi Rizzo static int 300*2f345d8eSLuigi Rizzo oce_detach(device_t dev) 301*2f345d8eSLuigi Rizzo { 302*2f345d8eSLuigi Rizzo POCE_SOFTC sc = device_get_softc(dev); 303*2f345d8eSLuigi Rizzo 304*2f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 305*2f345d8eSLuigi Rizzo 306*2f345d8eSLuigi Rizzo oce_if_deactivate(sc); 307*2f345d8eSLuigi Rizzo 308*2f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 309*2f345d8eSLuigi Rizzo 310*2f345d8eSLuigi Rizzo callout_drain(&sc->timer); 311*2f345d8eSLuigi Rizzo 312*2f345d8eSLuigi Rizzo if (sc->vlan_attach != NULL) 313*2f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 314*2f345d8eSLuigi Rizzo if (sc->vlan_detach != NULL) 315*2f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 316*2f345d8eSLuigi Rizzo 317*2f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp); 318*2f345d8eSLuigi Rizzo 319*2f345d8eSLuigi Rizzo if_free(sc->ifp); 320*2f345d8eSLuigi Rizzo 321*2f345d8eSLuigi Rizzo oce_hw_shutdown(sc); 322*2f345d8eSLuigi Rizzo 323*2f345d8eSLuigi Rizzo bus_generic_detach(dev); 324*2f345d8eSLuigi Rizzo 325*2f345d8eSLuigi Rizzo return 0; 326*2f345d8eSLuigi Rizzo } 327*2f345d8eSLuigi Rizzo 328*2f345d8eSLuigi Rizzo 329*2f345d8eSLuigi Rizzo static int 330*2f345d8eSLuigi Rizzo oce_shutdown(device_t dev) 331*2f345d8eSLuigi Rizzo { 332*2f345d8eSLuigi Rizzo int rc; 333*2f345d8eSLuigi Rizzo 334*2f345d8eSLuigi Rizzo rc = oce_detach(dev); 335*2f345d8eSLuigi Rizzo 336*2f345d8eSLuigi Rizzo return rc; 337*2f345d8eSLuigi Rizzo } 338*2f345d8eSLuigi Rizzo 339*2f345d8eSLuigi Rizzo 340*2f345d8eSLuigi Rizzo static int 341*2f345d8eSLuigi Rizzo oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 342*2f345d8eSLuigi Rizzo { 343*2f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data; 344*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 345*2f345d8eSLuigi Rizzo int rc = 0; 346*2f345d8eSLuigi Rizzo uint32_t u; 347*2f345d8eSLuigi Rizzo 348*2f345d8eSLuigi Rizzo switch (command) { 349*2f345d8eSLuigi Rizzo case SIOCGIFPSRCADDR_IN6: 350*2f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 351*2f345d8eSLuigi Rizzo break; 352*2f345d8eSLuigi Rizzo 353*2f345d8eSLuigi Rizzo case SIOCGIFPSRCADDR: 354*2f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 355*2f345d8eSLuigi Rizzo break; 356*2f345d8eSLuigi Rizzo 357*2f345d8eSLuigi Rizzo case SIOCGIFSTATUS: 358*2f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 359*2f345d8eSLuigi Rizzo break; 360*2f345d8eSLuigi Rizzo 361*2f345d8eSLuigi Rizzo case SIOCGIFMEDIA: 362*2f345d8eSLuigi Rizzo rc = ifmedia_ioctl(ifp, ifr, &sc->media, command); 363*2f345d8eSLuigi Rizzo break; 364*2f345d8eSLuigi Rizzo 365*2f345d8eSLuigi Rizzo case SIOCSIFMEDIA: 366*2f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 367*2f345d8eSLuigi Rizzo break; 368*2f345d8eSLuigi Rizzo 369*2f345d8eSLuigi Rizzo case SIOCGIFGENERIC: 370*2f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 371*2f345d8eSLuigi Rizzo break; 372*2f345d8eSLuigi Rizzo 373*2f345d8eSLuigi Rizzo case SIOCGETMIFCNT_IN6: 374*2f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 375*2f345d8eSLuigi Rizzo break; 376*2f345d8eSLuigi Rizzo 377*2f345d8eSLuigi Rizzo case SIOCSIFMTU: 378*2f345d8eSLuigi Rizzo if (ifr->ifr_mtu > OCE_MAX_MTU) 379*2f345d8eSLuigi Rizzo rc = EINVAL; 380*2f345d8eSLuigi Rizzo else 381*2f345d8eSLuigi Rizzo ifp->if_mtu = ifr->ifr_mtu; 382*2f345d8eSLuigi Rizzo break; 383*2f345d8eSLuigi Rizzo 384*2f345d8eSLuigi Rizzo case SIOCSIFFLAGS: 385*2f345d8eSLuigi Rizzo if (ifp->if_flags & IFF_UP) { 386*2f345d8eSLuigi Rizzo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 387*2f345d8eSLuigi Rizzo sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 388*2f345d8eSLuigi Rizzo oce_init(sc); 389*2f345d8eSLuigi Rizzo } 390*2f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Up\n"); 391*2f345d8eSLuigi Rizzo } else { 392*2f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 393*2f345d8eSLuigi Rizzo 394*2f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= 395*2f345d8eSLuigi Rizzo ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 396*2f345d8eSLuigi Rizzo oce_if_deactivate(sc); 397*2f345d8eSLuigi Rizzo 398*2f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 399*2f345d8eSLuigi Rizzo 400*2f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Down\n"); 401*2f345d8eSLuigi Rizzo } 402*2f345d8eSLuigi Rizzo 403*2f345d8eSLuigi Rizzo if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) { 404*2f345d8eSLuigi Rizzo sc->promisc = TRUE; 405*2f345d8eSLuigi Rizzo oce_rxf_set_promiscuous(sc, sc->promisc); 406*2f345d8eSLuigi Rizzo } else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) { 407*2f345d8eSLuigi Rizzo sc->promisc = FALSE; 408*2f345d8eSLuigi Rizzo oce_rxf_set_promiscuous(sc, sc->promisc); 409*2f345d8eSLuigi Rizzo } 410*2f345d8eSLuigi Rizzo 411*2f345d8eSLuigi Rizzo break; 412*2f345d8eSLuigi Rizzo 413*2f345d8eSLuigi Rizzo case SIOCADDMULTI: 414*2f345d8eSLuigi Rizzo case SIOCDELMULTI: 415*2f345d8eSLuigi Rizzo rc = oce_hw_update_multicast(sc); 416*2f345d8eSLuigi Rizzo if (rc) 417*2f345d8eSLuigi Rizzo device_printf(sc->dev, 418*2f345d8eSLuigi Rizzo "Update multicast address failed\n"); 419*2f345d8eSLuigi Rizzo break; 420*2f345d8eSLuigi Rizzo 421*2f345d8eSLuigi Rizzo case SIOCSIFCAP: 422*2f345d8eSLuigi Rizzo u = ifr->ifr_reqcap ^ ifp->if_capenable; 423*2f345d8eSLuigi Rizzo 424*2f345d8eSLuigi Rizzo if (u & IFCAP_TXCSUM) { 425*2f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_TXCSUM; 426*2f345d8eSLuigi Rizzo ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 427*2f345d8eSLuigi Rizzo 428*2f345d8eSLuigi Rizzo if (IFCAP_TSO & ifp->if_capenable && 429*2f345d8eSLuigi Rizzo !(IFCAP_TXCSUM & ifp->if_capenable)) { 430*2f345d8eSLuigi Rizzo ifp->if_capenable &= ~IFCAP_TSO; 431*2f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 432*2f345d8eSLuigi Rizzo if_printf(ifp, 433*2f345d8eSLuigi Rizzo "TSO disabled due to -txcsum.\n"); 434*2f345d8eSLuigi Rizzo } 435*2f345d8eSLuigi Rizzo } 436*2f345d8eSLuigi Rizzo 437*2f345d8eSLuigi Rizzo if (u & IFCAP_RXCSUM) 438*2f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_RXCSUM; 439*2f345d8eSLuigi Rizzo 440*2f345d8eSLuigi Rizzo if (u & IFCAP_TSO4) { 441*2f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_TSO4; 442*2f345d8eSLuigi Rizzo 443*2f345d8eSLuigi Rizzo if (IFCAP_TSO & ifp->if_capenable) { 444*2f345d8eSLuigi Rizzo if (IFCAP_TXCSUM & ifp->if_capenable) 445*2f345d8eSLuigi Rizzo ifp->if_hwassist |= CSUM_TSO; 446*2f345d8eSLuigi Rizzo else { 447*2f345d8eSLuigi Rizzo ifp->if_capenable &= ~IFCAP_TSO; 448*2f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 449*2f345d8eSLuigi Rizzo if_printf(ifp, 450*2f345d8eSLuigi Rizzo "Enable txcsum first.\n"); 451*2f345d8eSLuigi Rizzo rc = EAGAIN; 452*2f345d8eSLuigi Rizzo } 453*2f345d8eSLuigi Rizzo } else 454*2f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 455*2f345d8eSLuigi Rizzo } 456*2f345d8eSLuigi Rizzo 457*2f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWTAGGING) 458*2f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 459*2f345d8eSLuigi Rizzo 460*2f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWFILTER) { 461*2f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 462*2f345d8eSLuigi Rizzo oce_vid_config(sc); 463*2f345d8eSLuigi Rizzo } 464*2f345d8eSLuigi Rizzo 465*2f345d8eSLuigi Rizzo if (u & IFCAP_LRO) 466*2f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_LRO; 467*2f345d8eSLuigi Rizzo 468*2f345d8eSLuigi Rizzo break; 469*2f345d8eSLuigi Rizzo 470*2f345d8eSLuigi Rizzo case SIOCGPRIVATE_0: 471*2f345d8eSLuigi Rizzo rc = oce_handle_passthrough(ifp, data); 472*2f345d8eSLuigi Rizzo break; 473*2f345d8eSLuigi Rizzo default: 474*2f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 475*2f345d8eSLuigi Rizzo break; 476*2f345d8eSLuigi Rizzo } 477*2f345d8eSLuigi Rizzo 478*2f345d8eSLuigi Rizzo return rc; 479*2f345d8eSLuigi Rizzo } 480*2f345d8eSLuigi Rizzo 481*2f345d8eSLuigi Rizzo 482*2f345d8eSLuigi Rizzo static void 483*2f345d8eSLuigi Rizzo oce_init(void *arg) 484*2f345d8eSLuigi Rizzo { 485*2f345d8eSLuigi Rizzo POCE_SOFTC sc = arg; 486*2f345d8eSLuigi Rizzo 487*2f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 488*2f345d8eSLuigi Rizzo 489*2f345d8eSLuigi Rizzo if (sc->ifp->if_flags & IFF_UP) { 490*2f345d8eSLuigi Rizzo oce_if_deactivate(sc); 491*2f345d8eSLuigi Rizzo oce_if_activate(sc); 492*2f345d8eSLuigi Rizzo } 493*2f345d8eSLuigi Rizzo 494*2f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 495*2f345d8eSLuigi Rizzo 496*2f345d8eSLuigi Rizzo } 497*2f345d8eSLuigi Rizzo 498*2f345d8eSLuigi Rizzo 499*2f345d8eSLuigi Rizzo static int 500*2f345d8eSLuigi Rizzo oce_multiq_start(struct ifnet *ifp, struct mbuf *m) 501*2f345d8eSLuigi Rizzo { 502*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 503*2f345d8eSLuigi Rizzo struct oce_wq *wq = NULL; 504*2f345d8eSLuigi Rizzo int queue_index = 0; 505*2f345d8eSLuigi Rizzo int status = 0; 506*2f345d8eSLuigi Rizzo 507*2f345d8eSLuigi Rizzo if ((m->m_flags & M_FLOWID) != 0) 508*2f345d8eSLuigi Rizzo queue_index = m->m_pkthdr.flowid % sc->nwqs; 509*2f345d8eSLuigi Rizzo 510*2f345d8eSLuigi Rizzo wq = sc->wq[queue_index]; 511*2f345d8eSLuigi Rizzo 512*2f345d8eSLuigi Rizzo if (TRY_LOCK(&wq->tx_lock)) { 513*2f345d8eSLuigi Rizzo status = oce_multiq_transmit(ifp, m, wq); 514*2f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 515*2f345d8eSLuigi Rizzo } else { 516*2f345d8eSLuigi Rizzo status = drbr_enqueue(ifp, wq->br, m); 517*2f345d8eSLuigi Rizzo } 518*2f345d8eSLuigi Rizzo return status; 519*2f345d8eSLuigi Rizzo 520*2f345d8eSLuigi Rizzo } 521*2f345d8eSLuigi Rizzo 522*2f345d8eSLuigi Rizzo 523*2f345d8eSLuigi Rizzo static void 524*2f345d8eSLuigi Rizzo oce_multiq_flush(struct ifnet *ifp) 525*2f345d8eSLuigi Rizzo { 526*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 527*2f345d8eSLuigi Rizzo struct mbuf *m; 528*2f345d8eSLuigi Rizzo int i = 0; 529*2f345d8eSLuigi Rizzo 530*2f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) { 531*2f345d8eSLuigi Rizzo while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) 532*2f345d8eSLuigi Rizzo m_freem(m); 533*2f345d8eSLuigi Rizzo } 534*2f345d8eSLuigi Rizzo if_qflush(ifp); 535*2f345d8eSLuigi Rizzo } 536*2f345d8eSLuigi Rizzo 537*2f345d8eSLuigi Rizzo 538*2f345d8eSLuigi Rizzo 539*2f345d8eSLuigi Rizzo /***************************************************************************** 540*2f345d8eSLuigi Rizzo * Driver interrupt routines functions * 541*2f345d8eSLuigi Rizzo *****************************************************************************/ 542*2f345d8eSLuigi Rizzo 543*2f345d8eSLuigi Rizzo static void 544*2f345d8eSLuigi Rizzo oce_intr(void *arg, int pending) 545*2f345d8eSLuigi Rizzo { 546*2f345d8eSLuigi Rizzo 547*2f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 548*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc; 549*2f345d8eSLuigi Rizzo struct oce_eq *eq = ii->eq; 550*2f345d8eSLuigi Rizzo struct oce_eqe *eqe; 551*2f345d8eSLuigi Rizzo struct oce_cq *cq = NULL; 552*2f345d8eSLuigi Rizzo int i, num_eqes = 0; 553*2f345d8eSLuigi Rizzo 554*2f345d8eSLuigi Rizzo 555*2f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 556*2f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 557*2f345d8eSLuigi Rizzo do { 558*2f345d8eSLuigi Rizzo eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 559*2f345d8eSLuigi Rizzo if (eqe->evnt == 0) 560*2f345d8eSLuigi Rizzo break; 561*2f345d8eSLuigi Rizzo eqe->evnt = 0; 562*2f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 563*2f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 564*2f345d8eSLuigi Rizzo RING_GET(eq->ring, 1); 565*2f345d8eSLuigi Rizzo num_eqes++; 566*2f345d8eSLuigi Rizzo 567*2f345d8eSLuigi Rizzo } while (TRUE); 568*2f345d8eSLuigi Rizzo 569*2f345d8eSLuigi Rizzo if (!num_eqes) 570*2f345d8eSLuigi Rizzo goto eq_arm; /* Spurious */ 571*2f345d8eSLuigi Rizzo 572*2f345d8eSLuigi Rizzo /* Clear EQ entries, but dont arm */ 573*2f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE); 574*2f345d8eSLuigi Rizzo 575*2f345d8eSLuigi Rizzo /* Process TX, RX and MCC. But dont arm CQ*/ 576*2f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) { 577*2f345d8eSLuigi Rizzo cq = eq->cq[i]; 578*2f345d8eSLuigi Rizzo (*cq->cq_handler)(cq->cb_arg); 579*2f345d8eSLuigi Rizzo } 580*2f345d8eSLuigi Rizzo 581*2f345d8eSLuigi Rizzo /* Arm all cqs connected to this EQ */ 582*2f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) { 583*2f345d8eSLuigi Rizzo cq = eq->cq[i]; 584*2f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, 0, TRUE); 585*2f345d8eSLuigi Rizzo } 586*2f345d8eSLuigi Rizzo 587*2f345d8eSLuigi Rizzo eq_arm: 588*2f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 589*2f345d8eSLuigi Rizzo return; 590*2f345d8eSLuigi Rizzo } 591*2f345d8eSLuigi Rizzo 592*2f345d8eSLuigi Rizzo 593*2f345d8eSLuigi Rizzo static int 594*2f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc) 595*2f345d8eSLuigi Rizzo { 596*2f345d8eSLuigi Rizzo int rc = 0, use_intx = 0; 597*2f345d8eSLuigi Rizzo int vector = 0, req_vectors = 0; 598*2f345d8eSLuigi Rizzo 599*2f345d8eSLuigi Rizzo if (sc->rss_enable) 600*2f345d8eSLuigi Rizzo req_vectors = MAX((sc->nrqs - 1), sc->nwqs); 601*2f345d8eSLuigi Rizzo else 602*2f345d8eSLuigi Rizzo req_vectors = 1; 603*2f345d8eSLuigi Rizzo 604*2f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) { 605*2f345d8eSLuigi Rizzo sc->intr_count = req_vectors; 606*2f345d8eSLuigi Rizzo rc = pci_alloc_msix(sc->dev, &sc->intr_count); 607*2f345d8eSLuigi Rizzo if (rc != 0) { 608*2f345d8eSLuigi Rizzo use_intx = 1; 609*2f345d8eSLuigi Rizzo pci_release_msi(sc->dev); 610*2f345d8eSLuigi Rizzo } else 611*2f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_USING_MSIX; 612*2f345d8eSLuigi Rizzo } else 613*2f345d8eSLuigi Rizzo use_intx = 1; 614*2f345d8eSLuigi Rizzo 615*2f345d8eSLuigi Rizzo if (use_intx) 616*2f345d8eSLuigi Rizzo sc->intr_count = 1; 617*2f345d8eSLuigi Rizzo 618*2f345d8eSLuigi Rizzo /* Scale number of queues based on intr we got */ 619*2f345d8eSLuigi Rizzo update_queues_got(sc); 620*2f345d8eSLuigi Rizzo 621*2f345d8eSLuigi Rizzo if (use_intx) { 622*2f345d8eSLuigi Rizzo device_printf(sc->dev, "Using legacy interrupt\n"); 623*2f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr); 624*2f345d8eSLuigi Rizzo if (rc) 625*2f345d8eSLuigi Rizzo goto error; 626*2f345d8eSLuigi Rizzo } else { 627*2f345d8eSLuigi Rizzo for (; vector < sc->intr_count; vector++) { 628*2f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr); 629*2f345d8eSLuigi Rizzo if (rc) 630*2f345d8eSLuigi Rizzo goto error; 631*2f345d8eSLuigi Rizzo } 632*2f345d8eSLuigi Rizzo } 633*2f345d8eSLuigi Rizzo 634*2f345d8eSLuigi Rizzo return 0; 635*2f345d8eSLuigi Rizzo error: 636*2f345d8eSLuigi Rizzo oce_intr_free(sc); 637*2f345d8eSLuigi Rizzo return rc; 638*2f345d8eSLuigi Rizzo } 639*2f345d8eSLuigi Rizzo 640*2f345d8eSLuigi Rizzo 641*2f345d8eSLuigi Rizzo static int 642*2f345d8eSLuigi Rizzo oce_fast_isr(void *arg) 643*2f345d8eSLuigi Rizzo { 644*2f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 645*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc; 646*2f345d8eSLuigi Rizzo 647*2f345d8eSLuigi Rizzo if (ii->eq == NULL) 648*2f345d8eSLuigi Rizzo return FILTER_STRAY; 649*2f345d8eSLuigi Rizzo 650*2f345d8eSLuigi Rizzo oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE); 651*2f345d8eSLuigi Rizzo 652*2f345d8eSLuigi Rizzo taskqueue_enqueue_fast(ii->tq, &ii->task); 653*2f345d8eSLuigi Rizzo 654*2f345d8eSLuigi Rizzo return FILTER_HANDLED; 655*2f345d8eSLuigi Rizzo } 656*2f345d8eSLuigi Rizzo 657*2f345d8eSLuigi Rizzo 658*2f345d8eSLuigi Rizzo static int 659*2f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) 660*2f345d8eSLuigi Rizzo { 661*2f345d8eSLuigi Rizzo POCE_INTR_INFO ii = &sc->intrs[vector]; 662*2f345d8eSLuigi Rizzo int rc = 0, rr; 663*2f345d8eSLuigi Rizzo 664*2f345d8eSLuigi Rizzo if (vector >= OCE_MAX_EQ) 665*2f345d8eSLuigi Rizzo return (EINVAL); 666*2f345d8eSLuigi Rizzo 667*2f345d8eSLuigi Rizzo /* Set the resource id for the interrupt. 668*2f345d8eSLuigi Rizzo * MSIx is vector + 1 for the resource id, 669*2f345d8eSLuigi Rizzo * INTx is 0 for the resource id. 670*2f345d8eSLuigi Rizzo */ 671*2f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX) 672*2f345d8eSLuigi Rizzo rr = vector + 1; 673*2f345d8eSLuigi Rizzo else 674*2f345d8eSLuigi Rizzo rr = 0; 675*2f345d8eSLuigi Rizzo ii->intr_res = bus_alloc_resource_any(sc->dev, 676*2f345d8eSLuigi Rizzo SYS_RES_IRQ, 677*2f345d8eSLuigi Rizzo &rr, RF_ACTIVE|RF_SHAREABLE); 678*2f345d8eSLuigi Rizzo ii->irq_rr = rr; 679*2f345d8eSLuigi Rizzo if (ii->intr_res == NULL) { 680*2f345d8eSLuigi Rizzo device_printf(sc->dev, 681*2f345d8eSLuigi Rizzo "Could not allocate interrupt\n"); 682*2f345d8eSLuigi Rizzo rc = ENXIO; 683*2f345d8eSLuigi Rizzo return rc; 684*2f345d8eSLuigi Rizzo } 685*2f345d8eSLuigi Rizzo 686*2f345d8eSLuigi Rizzo TASK_INIT(&ii->task, 0, isr, ii); 687*2f345d8eSLuigi Rizzo ii->vector = vector; 688*2f345d8eSLuigi Rizzo sprintf(ii->task_name, "oce_task[%d]", ii->vector); 689*2f345d8eSLuigi Rizzo ii->tq = taskqueue_create_fast(ii->task_name, 690*2f345d8eSLuigi Rizzo M_NOWAIT, 691*2f345d8eSLuigi Rizzo taskqueue_thread_enqueue, 692*2f345d8eSLuigi Rizzo &ii->tq); 693*2f345d8eSLuigi Rizzo taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq", 694*2f345d8eSLuigi Rizzo device_get_nameunit(sc->dev)); 695*2f345d8eSLuigi Rizzo 696*2f345d8eSLuigi Rizzo ii->sc = sc; 697*2f345d8eSLuigi Rizzo rc = bus_setup_intr(sc->dev, 698*2f345d8eSLuigi Rizzo ii->intr_res, 699*2f345d8eSLuigi Rizzo INTR_TYPE_NET, 700*2f345d8eSLuigi Rizzo oce_fast_isr, NULL, ii, &ii->tag); 701*2f345d8eSLuigi Rizzo return rc; 702*2f345d8eSLuigi Rizzo 703*2f345d8eSLuigi Rizzo } 704*2f345d8eSLuigi Rizzo 705*2f345d8eSLuigi Rizzo 706*2f345d8eSLuigi Rizzo void 707*2f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc) 708*2f345d8eSLuigi Rizzo { 709*2f345d8eSLuigi Rizzo int i = 0; 710*2f345d8eSLuigi Rizzo 711*2f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) { 712*2f345d8eSLuigi Rizzo 713*2f345d8eSLuigi Rizzo if (sc->intrs[i].tag != NULL) 714*2f345d8eSLuigi Rizzo bus_teardown_intr(sc->dev, sc->intrs[i].intr_res, 715*2f345d8eSLuigi Rizzo sc->intrs[i].tag); 716*2f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) 717*2f345d8eSLuigi Rizzo taskqueue_free(sc->intrs[i].tq); 718*2f345d8eSLuigi Rizzo 719*2f345d8eSLuigi Rizzo if (sc->intrs[i].intr_res != NULL) 720*2f345d8eSLuigi Rizzo bus_release_resource(sc->dev, SYS_RES_IRQ, 721*2f345d8eSLuigi Rizzo sc->intrs[i].irq_rr, 722*2f345d8eSLuigi Rizzo sc->intrs[i].intr_res); 723*2f345d8eSLuigi Rizzo sc->intrs[i].tag = NULL; 724*2f345d8eSLuigi Rizzo sc->intrs[i].intr_res = NULL; 725*2f345d8eSLuigi Rizzo } 726*2f345d8eSLuigi Rizzo 727*2f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX) 728*2f345d8eSLuigi Rizzo pci_release_msi(sc->dev); 729*2f345d8eSLuigi Rizzo 730*2f345d8eSLuigi Rizzo } 731*2f345d8eSLuigi Rizzo 732*2f345d8eSLuigi Rizzo 733*2f345d8eSLuigi Rizzo 734*2f345d8eSLuigi Rizzo /****************************************************************************** 735*2f345d8eSLuigi Rizzo * Media callbacks functions * 736*2f345d8eSLuigi Rizzo ******************************************************************************/ 737*2f345d8eSLuigi Rizzo 738*2f345d8eSLuigi Rizzo static void 739*2f345d8eSLuigi Rizzo oce_media_status(struct ifnet *ifp, struct ifmediareq *req) 740*2f345d8eSLuigi Rizzo { 741*2f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc; 742*2f345d8eSLuigi Rizzo 743*2f345d8eSLuigi Rizzo 744*2f345d8eSLuigi Rizzo req->ifm_status = IFM_AVALID; 745*2f345d8eSLuigi Rizzo req->ifm_active = IFM_ETHER; 746*2f345d8eSLuigi Rizzo 747*2f345d8eSLuigi Rizzo if (sc->link_status == 1) 748*2f345d8eSLuigi Rizzo req->ifm_status |= IFM_ACTIVE; 749*2f345d8eSLuigi Rizzo else 750*2f345d8eSLuigi Rizzo return; 751*2f345d8eSLuigi Rizzo 752*2f345d8eSLuigi Rizzo switch (sc->link_speed) { 753*2f345d8eSLuigi Rizzo case 1: /* 10 Mbps */ 754*2f345d8eSLuigi Rizzo req->ifm_active |= IFM_10_T | IFM_FDX; 755*2f345d8eSLuigi Rizzo sc->speed = 10; 756*2f345d8eSLuigi Rizzo break; 757*2f345d8eSLuigi Rizzo case 2: /* 100 Mbps */ 758*2f345d8eSLuigi Rizzo req->ifm_active |= IFM_100_TX | IFM_FDX; 759*2f345d8eSLuigi Rizzo sc->speed = 100; 760*2f345d8eSLuigi Rizzo break; 761*2f345d8eSLuigi Rizzo case 3: /* 1 Gbps */ 762*2f345d8eSLuigi Rizzo req->ifm_active |= IFM_1000_T | IFM_FDX; 763*2f345d8eSLuigi Rizzo sc->speed = 1000; 764*2f345d8eSLuigi Rizzo break; 765*2f345d8eSLuigi Rizzo case 4: /* 10 Gbps */ 766*2f345d8eSLuigi Rizzo req->ifm_active |= IFM_10G_SR | IFM_FDX; 767*2f345d8eSLuigi Rizzo sc->speed = 10000; 768*2f345d8eSLuigi Rizzo break; 769*2f345d8eSLuigi Rizzo } 770*2f345d8eSLuigi Rizzo 771*2f345d8eSLuigi Rizzo return; 772*2f345d8eSLuigi Rizzo } 773*2f345d8eSLuigi Rizzo 774*2f345d8eSLuigi Rizzo 775*2f345d8eSLuigi Rizzo int 776*2f345d8eSLuigi Rizzo oce_media_change(struct ifnet *ifp) 777*2f345d8eSLuigi Rizzo { 778*2f345d8eSLuigi Rizzo return 0; 779*2f345d8eSLuigi Rizzo } 780*2f345d8eSLuigi Rizzo 781*2f345d8eSLuigi Rizzo 782*2f345d8eSLuigi Rizzo 783*2f345d8eSLuigi Rizzo 784*2f345d8eSLuigi Rizzo /***************************************************************************** 785*2f345d8eSLuigi Rizzo * Transmit routines functions * 786*2f345d8eSLuigi Rizzo *****************************************************************************/ 787*2f345d8eSLuigi Rizzo 788*2f345d8eSLuigi Rizzo static int 789*2f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 790*2f345d8eSLuigi Rizzo { 791*2f345d8eSLuigi Rizzo int rc = 0, i, retry_cnt = 0; 792*2f345d8eSLuigi Rizzo bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 793*2f345d8eSLuigi Rizzo struct mbuf *m, *m_temp; 794*2f345d8eSLuigi Rizzo struct oce_wq *wq = sc->wq[wq_index]; 795*2f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 796*2f345d8eSLuigi Rizzo uint32_t out; 797*2f345d8eSLuigi Rizzo struct oce_nic_hdr_wqe *nichdr; 798*2f345d8eSLuigi Rizzo struct oce_nic_frag_wqe *nicfrag; 799*2f345d8eSLuigi Rizzo int num_wqes; 800*2f345d8eSLuigi Rizzo uint32_t reg_value; 801*2f345d8eSLuigi Rizzo uint16_t mss = 0; 802*2f345d8eSLuigi Rizzo 803*2f345d8eSLuigi Rizzo m = *mpp; 804*2f345d8eSLuigi Rizzo if (!m) 805*2f345d8eSLuigi Rizzo return EINVAL; 806*2f345d8eSLuigi Rizzo 807*2f345d8eSLuigi Rizzo if (!(m->m_flags & M_PKTHDR)) { 808*2f345d8eSLuigi Rizzo rc = ENXIO; 809*2f345d8eSLuigi Rizzo goto free_ret; 810*2f345d8eSLuigi Rizzo } 811*2f345d8eSLuigi Rizzo 812*2f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) { 813*2f345d8eSLuigi Rizzo /* consolidate packet buffers for TSO/LSO segment offload */ 814*2f345d8eSLuigi Rizzo m = oce_tso_setup(sc, mpp, &mss); 815*2f345d8eSLuigi Rizzo if (m == NULL) { 816*2f345d8eSLuigi Rizzo rc = ENXIO; 817*2f345d8eSLuigi Rizzo goto free_ret; 818*2f345d8eSLuigi Rizzo } 819*2f345d8eSLuigi Rizzo } 820*2f345d8eSLuigi Rizzo 821*2f345d8eSLuigi Rizzo out = wq->packets_out + 1; 822*2f345d8eSLuigi Rizzo if (out == OCE_WQ_PACKET_ARRAY_SIZE) 823*2f345d8eSLuigi Rizzo out = 0; 824*2f345d8eSLuigi Rizzo if (out == wq->packets_in) 825*2f345d8eSLuigi Rizzo return EBUSY; 826*2f345d8eSLuigi Rizzo 827*2f345d8eSLuigi Rizzo pd = &wq->pckts[wq->packets_out]; 828*2f345d8eSLuigi Rizzo retry: 829*2f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(wq->tag, 830*2f345d8eSLuigi Rizzo pd->map, 831*2f345d8eSLuigi Rizzo m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 832*2f345d8eSLuigi Rizzo if (rc == 0) { 833*2f345d8eSLuigi Rizzo num_wqes = pd->nsegs + 1; 834*2f345d8eSLuigi Rizzo if (IS_BE(sc)) { 835*2f345d8eSLuigi Rizzo /*Dummy required only for BE3.*/ 836*2f345d8eSLuigi Rizzo if (num_wqes & 1) 837*2f345d8eSLuigi Rizzo num_wqes++; 838*2f345d8eSLuigi Rizzo } 839*2f345d8eSLuigi Rizzo if (num_wqes >= RING_NUM_FREE(wq->ring)) { 840*2f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map); 841*2f345d8eSLuigi Rizzo return EBUSY; 842*2f345d8eSLuigi Rizzo } 843*2f345d8eSLuigi Rizzo 844*2f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 845*2f345d8eSLuigi Rizzo pd->mbuf = m; 846*2f345d8eSLuigi Rizzo wq->packets_out = out; 847*2f345d8eSLuigi Rizzo 848*2f345d8eSLuigi Rizzo nichdr = 849*2f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 850*2f345d8eSLuigi Rizzo nichdr->u0.dw[0] = 0; 851*2f345d8eSLuigi Rizzo nichdr->u0.dw[1] = 0; 852*2f345d8eSLuigi Rizzo nichdr->u0.dw[2] = 0; 853*2f345d8eSLuigi Rizzo nichdr->u0.dw[3] = 0; 854*2f345d8eSLuigi Rizzo 855*2f345d8eSLuigi Rizzo nichdr->u0.s.complete = 1; 856*2f345d8eSLuigi Rizzo nichdr->u0.s.event = 1; 857*2f345d8eSLuigi Rizzo nichdr->u0.s.crc = 1; 858*2f345d8eSLuigi Rizzo nichdr->u0.s.forward = 0; 859*2f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 860*2f345d8eSLuigi Rizzo nichdr->u0.s.udpcs = 861*2f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 862*2f345d8eSLuigi Rizzo nichdr->u0.s.tcpcs = 863*2f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 864*2f345d8eSLuigi Rizzo nichdr->u0.s.num_wqe = num_wqes; 865*2f345d8eSLuigi Rizzo nichdr->u0.s.total_length = m->m_pkthdr.len; 866*2f345d8eSLuigi Rizzo if (m->m_flags & M_VLANTAG) { 867*2f345d8eSLuigi Rizzo nichdr->u0.s.vlan = 1; /*Vlan present*/ 868*2f345d8eSLuigi Rizzo nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 869*2f345d8eSLuigi Rizzo } 870*2f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) { 871*2f345d8eSLuigi Rizzo if (m->m_pkthdr.tso_segsz) { 872*2f345d8eSLuigi Rizzo nichdr->u0.s.lso = 1; 873*2f345d8eSLuigi Rizzo nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 874*2f345d8eSLuigi Rizzo } 875*2f345d8eSLuigi Rizzo if (!IS_BE(sc)) 876*2f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = 1; 877*2f345d8eSLuigi Rizzo } 878*2f345d8eSLuigi Rizzo 879*2f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 880*2f345d8eSLuigi Rizzo wq->ring->num_used++; 881*2f345d8eSLuigi Rizzo 882*2f345d8eSLuigi Rizzo for (i = 0; i < pd->nsegs; i++) { 883*2f345d8eSLuigi Rizzo nicfrag = 884*2f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, 885*2f345d8eSLuigi Rizzo struct oce_nic_frag_wqe); 886*2f345d8eSLuigi Rizzo nicfrag->u0.s.rsvd0 = 0; 887*2f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 888*2f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 889*2f345d8eSLuigi Rizzo nicfrag->u0.s.frag_len = segs[i].ds_len; 890*2f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx; 891*2f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 892*2f345d8eSLuigi Rizzo wq->ring->num_used++; 893*2f345d8eSLuigi Rizzo } 894*2f345d8eSLuigi Rizzo if (num_wqes > (pd->nsegs + 1)) { 895*2f345d8eSLuigi Rizzo nicfrag = 896*2f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, 897*2f345d8eSLuigi Rizzo struct oce_nic_frag_wqe); 898*2f345d8eSLuigi Rizzo nicfrag->u0.dw[0] = 0; 899*2f345d8eSLuigi Rizzo nicfrag->u0.dw[1] = 0; 900*2f345d8eSLuigi Rizzo nicfrag->u0.dw[2] = 0; 901*2f345d8eSLuigi Rizzo nicfrag->u0.dw[3] = 0; 902*2f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx; 903*2f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 904*2f345d8eSLuigi Rizzo wq->ring->num_used++; 905*2f345d8eSLuigi Rizzo pd->nsegs++; 906*2f345d8eSLuigi Rizzo } 907*2f345d8eSLuigi Rizzo 908*2f345d8eSLuigi Rizzo sc->ifp->if_opackets++; 909*2f345d8eSLuigi Rizzo wq->tx_stats.tx_reqs++; 910*2f345d8eSLuigi Rizzo wq->tx_stats.tx_wrbs += num_wqes; 911*2f345d8eSLuigi Rizzo wq->tx_stats.tx_bytes += m->m_pkthdr.len; 912*2f345d8eSLuigi Rizzo wq->tx_stats.tx_pkts++; 913*2f345d8eSLuigi Rizzo 914*2f345d8eSLuigi Rizzo bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 915*2f345d8eSLuigi Rizzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 916*2f345d8eSLuigi Rizzo reg_value = (num_wqes << 16) | wq->wq_id; 917*2f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_TXULP_DB, reg_value); 918*2f345d8eSLuigi Rizzo 919*2f345d8eSLuigi Rizzo } else if (rc == EFBIG) { 920*2f345d8eSLuigi Rizzo if (retry_cnt == 0) { 921*2f345d8eSLuigi Rizzo m_temp = m_defrag(m, M_DONTWAIT); 922*2f345d8eSLuigi Rizzo if (m_temp == NULL) 923*2f345d8eSLuigi Rizzo goto free_ret; 924*2f345d8eSLuigi Rizzo m = m_temp; 925*2f345d8eSLuigi Rizzo *mpp = m_temp; 926*2f345d8eSLuigi Rizzo retry_cnt = retry_cnt + 1; 927*2f345d8eSLuigi Rizzo goto retry; 928*2f345d8eSLuigi Rizzo } else 929*2f345d8eSLuigi Rizzo goto free_ret; 930*2f345d8eSLuigi Rizzo } else if (rc == ENOMEM) 931*2f345d8eSLuigi Rizzo return rc; 932*2f345d8eSLuigi Rizzo else 933*2f345d8eSLuigi Rizzo goto free_ret; 934*2f345d8eSLuigi Rizzo 935*2f345d8eSLuigi Rizzo return 0; 936*2f345d8eSLuigi Rizzo 937*2f345d8eSLuigi Rizzo free_ret: 938*2f345d8eSLuigi Rizzo m_freem(*mpp); 939*2f345d8eSLuigi Rizzo *mpp = NULL; 940*2f345d8eSLuigi Rizzo return rc; 941*2f345d8eSLuigi Rizzo } 942*2f345d8eSLuigi Rizzo 943*2f345d8eSLuigi Rizzo 944*2f345d8eSLuigi Rizzo static void 945*2f345d8eSLuigi Rizzo oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status) 946*2f345d8eSLuigi Rizzo { 947*2f345d8eSLuigi Rizzo uint32_t in; 948*2f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 949*2f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 950*2f345d8eSLuigi Rizzo struct mbuf *m; 951*2f345d8eSLuigi Rizzo 952*2f345d8eSLuigi Rizzo if (wq->packets_out == wq->packets_in) 953*2f345d8eSLuigi Rizzo device_printf(sc->dev, "WQ transmit descriptor missing\n"); 954*2f345d8eSLuigi Rizzo 955*2f345d8eSLuigi Rizzo in = wq->packets_in + 1; 956*2f345d8eSLuigi Rizzo if (in == OCE_WQ_PACKET_ARRAY_SIZE) 957*2f345d8eSLuigi Rizzo in = 0; 958*2f345d8eSLuigi Rizzo 959*2f345d8eSLuigi Rizzo pd = &wq->pckts[wq->packets_in]; 960*2f345d8eSLuigi Rizzo wq->packets_in = in; 961*2f345d8eSLuigi Rizzo wq->ring->num_used -= (pd->nsegs + 1); 962*2f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 963*2f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map); 964*2f345d8eSLuigi Rizzo 965*2f345d8eSLuigi Rizzo m = pd->mbuf; 966*2f345d8eSLuigi Rizzo m_freem(m); 967*2f345d8eSLuigi Rizzo pd->mbuf = NULL; 968*2f345d8eSLuigi Rizzo 969*2f345d8eSLuigi Rizzo if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 970*2f345d8eSLuigi Rizzo if (wq->ring->num_used < (wq->ring->num_items / 2)) { 971*2f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 972*2f345d8eSLuigi Rizzo oce_tx_restart(sc, wq); 973*2f345d8eSLuigi Rizzo } 974*2f345d8eSLuigi Rizzo } 975*2f345d8eSLuigi Rizzo } 976*2f345d8eSLuigi Rizzo 977*2f345d8eSLuigi Rizzo 978*2f345d8eSLuigi Rizzo static void 979*2f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 980*2f345d8eSLuigi Rizzo { 981*2f345d8eSLuigi Rizzo 982*2f345d8eSLuigi Rizzo if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 983*2f345d8eSLuigi Rizzo return; 984*2f345d8eSLuigi Rizzo 985*2f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 986*2f345d8eSLuigi Rizzo if (!drbr_empty(sc->ifp, wq->br)) 987*2f345d8eSLuigi Rizzo #else 988*2f345d8eSLuigi Rizzo if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 989*2f345d8eSLuigi Rizzo #endif 990*2f345d8eSLuigi Rizzo taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask); 991*2f345d8eSLuigi Rizzo 992*2f345d8eSLuigi Rizzo } 993*2f345d8eSLuigi Rizzo 994*2f345d8eSLuigi Rizzo 995*2f345d8eSLuigi Rizzo static struct mbuf * 996*2f345d8eSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp, uint16_t *mss) 997*2f345d8eSLuigi Rizzo { 998*2f345d8eSLuigi Rizzo struct mbuf *m; 999*2f345d8eSLuigi Rizzo struct ip *ip; 1000*2f345d8eSLuigi Rizzo struct ip6_hdr *ip6; 1001*2f345d8eSLuigi Rizzo struct ether_vlan_header *eh; 1002*2f345d8eSLuigi Rizzo struct tcphdr *th; 1003*2f345d8eSLuigi Rizzo uint16_t etype; 1004*2f345d8eSLuigi Rizzo int total_len = 0, ehdrlen = 0; 1005*2f345d8eSLuigi Rizzo 1006*2f345d8eSLuigi Rizzo m = *mpp; 1007*2f345d8eSLuigi Rizzo *mss = m->m_pkthdr.tso_segsz; 1008*2f345d8eSLuigi Rizzo 1009*2f345d8eSLuigi Rizzo if (M_WRITABLE(m) == 0) { 1010*2f345d8eSLuigi Rizzo m = m_dup(*mpp, M_DONTWAIT); 1011*2f345d8eSLuigi Rizzo if (!m) 1012*2f345d8eSLuigi Rizzo return NULL; 1013*2f345d8eSLuigi Rizzo m_freem(*mpp); 1014*2f345d8eSLuigi Rizzo *mpp = m; 1015*2f345d8eSLuigi Rizzo } 1016*2f345d8eSLuigi Rizzo 1017*2f345d8eSLuigi Rizzo eh = mtod(m, struct ether_vlan_header *); 1018*2f345d8eSLuigi Rizzo if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 1019*2f345d8eSLuigi Rizzo etype = ntohs(eh->evl_proto); 1020*2f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1021*2f345d8eSLuigi Rizzo } else { 1022*2f345d8eSLuigi Rizzo etype = ntohs(eh->evl_encap_proto); 1023*2f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN; 1024*2f345d8eSLuigi Rizzo } 1025*2f345d8eSLuigi Rizzo 1026*2f345d8eSLuigi Rizzo 1027*2f345d8eSLuigi Rizzo switch (etype) { 1028*2f345d8eSLuigi Rizzo case ETHERTYPE_IP: 1029*2f345d8eSLuigi Rizzo ip = (struct ip *)(m->m_data + ehdrlen); 1030*2f345d8eSLuigi Rizzo if (ip->ip_p != IPPROTO_TCP) 1031*2f345d8eSLuigi Rizzo return NULL; 1032*2f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 1033*2f345d8eSLuigi Rizzo 1034*2f345d8eSLuigi Rizzo total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 1035*2f345d8eSLuigi Rizzo break; 1036*2f345d8eSLuigi Rizzo case ETHERTYPE_IPV6: 1037*2f345d8eSLuigi Rizzo ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 1038*2f345d8eSLuigi Rizzo if (ip6->ip6_nxt != IPPROTO_TCP) 1039*2f345d8eSLuigi Rizzo return NULL; 1040*2f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 1041*2f345d8eSLuigi Rizzo 1042*2f345d8eSLuigi Rizzo total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 1043*2f345d8eSLuigi Rizzo break; 1044*2f345d8eSLuigi Rizzo default: 1045*2f345d8eSLuigi Rizzo return NULL; 1046*2f345d8eSLuigi Rizzo } 1047*2f345d8eSLuigi Rizzo 1048*2f345d8eSLuigi Rizzo m = m_pullup(m, total_len); 1049*2f345d8eSLuigi Rizzo if (!m) 1050*2f345d8eSLuigi Rizzo return NULL; 1051*2f345d8eSLuigi Rizzo *mpp = m; 1052*2f345d8eSLuigi Rizzo return m; 1053*2f345d8eSLuigi Rizzo 1054*2f345d8eSLuigi Rizzo } 1055*2f345d8eSLuigi Rizzo 1056*2f345d8eSLuigi Rizzo 1057*2f345d8eSLuigi Rizzo void 1058*2f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending) 1059*2f345d8eSLuigi Rizzo { 1060*2f345d8eSLuigi Rizzo struct oce_wq *wq = arg; 1061*2f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 1062*2f345d8eSLuigi Rizzo struct ifnet *ifp = sc->ifp; 1063*2f345d8eSLuigi Rizzo int rc = 0; 1064*2f345d8eSLuigi Rizzo 1065*2f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1066*2f345d8eSLuigi Rizzo if (TRY_LOCK(&wq->tx_lock)) { 1067*2f345d8eSLuigi Rizzo rc = oce_multiq_transmit(ifp, NULL, wq); 1068*2f345d8eSLuigi Rizzo if (rc) { 1069*2f345d8eSLuigi Rizzo device_printf(sc->dev, 1070*2f345d8eSLuigi Rizzo "TX[%d] restart failed\n", wq->queue_index); 1071*2f345d8eSLuigi Rizzo } 1072*2f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 1073*2f345d8eSLuigi Rizzo } 1074*2f345d8eSLuigi Rizzo #else 1075*2f345d8eSLuigi Rizzo oce_start(ifp); 1076*2f345d8eSLuigi Rizzo #endif 1077*2f345d8eSLuigi Rizzo 1078*2f345d8eSLuigi Rizzo } 1079*2f345d8eSLuigi Rizzo 1080*2f345d8eSLuigi Rizzo 1081*2f345d8eSLuigi Rizzo void 1082*2f345d8eSLuigi Rizzo oce_start(struct ifnet *ifp) 1083*2f345d8eSLuigi Rizzo { 1084*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 1085*2f345d8eSLuigi Rizzo struct mbuf *m; 1086*2f345d8eSLuigi Rizzo int rc = 0; 1087*2f345d8eSLuigi Rizzo 1088*2f345d8eSLuigi Rizzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1089*2f345d8eSLuigi Rizzo IFF_DRV_RUNNING) 1090*2f345d8eSLuigi Rizzo return; 1091*2f345d8eSLuigi Rizzo 1092*2f345d8eSLuigi Rizzo do { 1093*2f345d8eSLuigi Rizzo IF_DEQUEUE(&sc->ifp->if_snd, m); 1094*2f345d8eSLuigi Rizzo if (m == NULL) 1095*2f345d8eSLuigi Rizzo break; 1096*2f345d8eSLuigi Rizzo /* oce_start always uses default TX queue 0 */ 1097*2f345d8eSLuigi Rizzo LOCK(&sc->wq[0]->tx_lock); 1098*2f345d8eSLuigi Rizzo rc = oce_tx(sc, &m, 0); 1099*2f345d8eSLuigi Rizzo UNLOCK(&sc->wq[0]->tx_lock); 1100*2f345d8eSLuigi Rizzo if (rc) { 1101*2f345d8eSLuigi Rizzo if (m != NULL) { 1102*2f345d8eSLuigi Rizzo sc->wq[0]->tx_stats.tx_stops ++; 1103*2f345d8eSLuigi Rizzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1104*2f345d8eSLuigi Rizzo IFQ_DRV_PREPEND(&ifp->if_snd, m); 1105*2f345d8eSLuigi Rizzo m = NULL; 1106*2f345d8eSLuigi Rizzo } 1107*2f345d8eSLuigi Rizzo break; 1108*2f345d8eSLuigi Rizzo } 1109*2f345d8eSLuigi Rizzo if (m != NULL) 1110*2f345d8eSLuigi Rizzo ETHER_BPF_MTAP(ifp, m); 1111*2f345d8eSLuigi Rizzo 1112*2f345d8eSLuigi Rizzo } while (1); 1113*2f345d8eSLuigi Rizzo 1114*2f345d8eSLuigi Rizzo return; 1115*2f345d8eSLuigi Rizzo } 1116*2f345d8eSLuigi Rizzo 1117*2f345d8eSLuigi Rizzo 1118*2f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */ 1119*2f345d8eSLuigi Rizzo uint16_t 1120*2f345d8eSLuigi Rizzo oce_wq_handler(void *arg) 1121*2f345d8eSLuigi Rizzo { 1122*2f345d8eSLuigi Rizzo struct oce_wq *wq = (struct oce_wq *)arg; 1123*2f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 1124*2f345d8eSLuigi Rizzo struct oce_cq *cq = wq->cq; 1125*2f345d8eSLuigi Rizzo struct oce_nic_tx_cqe *cqe; 1126*2f345d8eSLuigi Rizzo int num_cqes = 0; 1127*2f345d8eSLuigi Rizzo 1128*2f345d8eSLuigi Rizzo LOCK(&wq->tx_lock); 1129*2f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 1130*2f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1131*2f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1132*2f345d8eSLuigi Rizzo while (cqe->u0.dw[3]) { 1133*2f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 1134*2f345d8eSLuigi Rizzo 1135*2f345d8eSLuigi Rizzo wq->ring->cidx = cqe->u0.s.wqe_index + 1; 1136*2f345d8eSLuigi Rizzo if (wq->ring->cidx >= wq->ring->num_items) 1137*2f345d8eSLuigi Rizzo wq->ring->cidx -= wq->ring->num_items; 1138*2f345d8eSLuigi Rizzo 1139*2f345d8eSLuigi Rizzo oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status); 1140*2f345d8eSLuigi Rizzo wq->tx_stats.tx_compl++; 1141*2f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 1142*2f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 1143*2f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 1144*2f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1145*2f345d8eSLuigi Rizzo cqe = 1146*2f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1147*2f345d8eSLuigi Rizzo num_cqes++; 1148*2f345d8eSLuigi Rizzo } 1149*2f345d8eSLuigi Rizzo 1150*2f345d8eSLuigi Rizzo if (num_cqes) 1151*2f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1152*2f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 1153*2f345d8eSLuigi Rizzo 1154*2f345d8eSLuigi Rizzo return 0; 1155*2f345d8eSLuigi Rizzo } 1156*2f345d8eSLuigi Rizzo 1157*2f345d8eSLuigi Rizzo 1158*2f345d8eSLuigi Rizzo static int 1159*2f345d8eSLuigi Rizzo oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 1160*2f345d8eSLuigi Rizzo { 1161*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 1162*2f345d8eSLuigi Rizzo int status = 0, queue_index = 0; 1163*2f345d8eSLuigi Rizzo struct mbuf *next = NULL; 1164*2f345d8eSLuigi Rizzo struct buf_ring *br = NULL; 1165*2f345d8eSLuigi Rizzo 1166*2f345d8eSLuigi Rizzo br = wq->br; 1167*2f345d8eSLuigi Rizzo queue_index = wq->queue_index; 1168*2f345d8eSLuigi Rizzo 1169*2f345d8eSLuigi Rizzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1170*2f345d8eSLuigi Rizzo IFF_DRV_RUNNING) { 1171*2f345d8eSLuigi Rizzo if (m != NULL) 1172*2f345d8eSLuigi Rizzo status = drbr_enqueue(ifp, br, m); 1173*2f345d8eSLuigi Rizzo return status; 1174*2f345d8eSLuigi Rizzo } 1175*2f345d8eSLuigi Rizzo 1176*2f345d8eSLuigi Rizzo if (m == NULL) 1177*2f345d8eSLuigi Rizzo next = drbr_dequeue(ifp, br); 1178*2f345d8eSLuigi Rizzo else if (drbr_needs_enqueue(ifp, br)) { 1179*2f345d8eSLuigi Rizzo if ((status = drbr_enqueue(ifp, br, m)) != 0) 1180*2f345d8eSLuigi Rizzo return status; 1181*2f345d8eSLuigi Rizzo next = drbr_dequeue(ifp, br); 1182*2f345d8eSLuigi Rizzo } else 1183*2f345d8eSLuigi Rizzo next = m; 1184*2f345d8eSLuigi Rizzo 1185*2f345d8eSLuigi Rizzo while (next != NULL) { 1186*2f345d8eSLuigi Rizzo if (oce_tx(sc, &next, queue_index)) { 1187*2f345d8eSLuigi Rizzo if (next != NULL) { 1188*2f345d8eSLuigi Rizzo wq->tx_stats.tx_stops ++; 1189*2f345d8eSLuigi Rizzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1190*2f345d8eSLuigi Rizzo status = drbr_enqueue(ifp, br, next); 1191*2f345d8eSLuigi Rizzo } 1192*2f345d8eSLuigi Rizzo break; 1193*2f345d8eSLuigi Rizzo } 1194*2f345d8eSLuigi Rizzo drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags); 1195*2f345d8eSLuigi Rizzo ETHER_BPF_MTAP(ifp, next); 1196*2f345d8eSLuigi Rizzo next = drbr_dequeue(ifp, br); 1197*2f345d8eSLuigi Rizzo } 1198*2f345d8eSLuigi Rizzo 1199*2f345d8eSLuigi Rizzo return status; 1200*2f345d8eSLuigi Rizzo } 1201*2f345d8eSLuigi Rizzo 1202*2f345d8eSLuigi Rizzo 1203*2f345d8eSLuigi Rizzo 1204*2f345d8eSLuigi Rizzo 1205*2f345d8eSLuigi Rizzo /***************************************************************************** 1206*2f345d8eSLuigi Rizzo * Receive routines functions * 1207*2f345d8eSLuigi Rizzo *****************************************************************************/ 1208*2f345d8eSLuigi Rizzo 1209*2f345d8eSLuigi Rizzo static void 1210*2f345d8eSLuigi Rizzo oce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe) 1211*2f345d8eSLuigi Rizzo { 1212*2f345d8eSLuigi Rizzo uint32_t out; 1213*2f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 1214*2f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1215*2f345d8eSLuigi Rizzo int i, len, frag_len; 1216*2f345d8eSLuigi Rizzo struct mbuf *m = NULL, *tail = NULL; 1217*2f345d8eSLuigi Rizzo uint16_t vtag; 1218*2f345d8eSLuigi Rizzo 1219*2f345d8eSLuigi Rizzo len = cqe->u0.s.pkt_size; 1220*2f345d8eSLuigi Rizzo vtag = cqe->u0.s.vlan_tag; 1221*2f345d8eSLuigi Rizzo if (!len) { 1222*2f345d8eSLuigi Rizzo /*partial DMA workaround for Lancer*/ 1223*2f345d8eSLuigi Rizzo oce_discard_rx_comp(rq, cqe); 1224*2f345d8eSLuigi Rizzo goto exit; 1225*2f345d8eSLuigi Rizzo } 1226*2f345d8eSLuigi Rizzo 1227*2f345d8eSLuigi Rizzo for (i = 0; i < cqe->u0.s.num_fragments; i++) { 1228*2f345d8eSLuigi Rizzo 1229*2f345d8eSLuigi Rizzo if (rq->packets_out == rq->packets_in) { 1230*2f345d8eSLuigi Rizzo device_printf(sc->dev, 1231*2f345d8eSLuigi Rizzo "RQ transmit descriptor missing\n"); 1232*2f345d8eSLuigi Rizzo } 1233*2f345d8eSLuigi Rizzo out = rq->packets_out + 1; 1234*2f345d8eSLuigi Rizzo if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1235*2f345d8eSLuigi Rizzo out = 0; 1236*2f345d8eSLuigi Rizzo pd = &rq->pckts[rq->packets_out]; 1237*2f345d8eSLuigi Rizzo rq->packets_out = out; 1238*2f345d8eSLuigi Rizzo 1239*2f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1240*2f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, pd->map); 1241*2f345d8eSLuigi Rizzo rq->pending--; 1242*2f345d8eSLuigi Rizzo 1243*2f345d8eSLuigi Rizzo frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 1244*2f345d8eSLuigi Rizzo pd->mbuf->m_len = frag_len; 1245*2f345d8eSLuigi Rizzo 1246*2f345d8eSLuigi Rizzo if (tail != NULL) { 1247*2f345d8eSLuigi Rizzo /* additional fragments */ 1248*2f345d8eSLuigi Rizzo pd->mbuf->m_flags &= ~M_PKTHDR; 1249*2f345d8eSLuigi Rizzo tail->m_next = pd->mbuf; 1250*2f345d8eSLuigi Rizzo tail = pd->mbuf; 1251*2f345d8eSLuigi Rizzo } else { 1252*2f345d8eSLuigi Rizzo /* first fragment, fill out much of the packet header */ 1253*2f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.len = len; 1254*2f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.csum_flags = 0; 1255*2f345d8eSLuigi Rizzo if (IF_CSUM_ENABLED(sc)) { 1256*2f345d8eSLuigi Rizzo if (cqe->u0.s.l4_cksum_pass) { 1257*2f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.csum_flags |= 1258*2f345d8eSLuigi Rizzo (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1259*2f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.csum_data = 0xffff; 1260*2f345d8eSLuigi Rizzo } 1261*2f345d8eSLuigi Rizzo if (cqe->u0.s.ip_cksum_pass) { 1262*2f345d8eSLuigi Rizzo if (!cqe->u0.s.ip_ver) { //IPV4 1263*2f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.csum_flags |= 1264*2f345d8eSLuigi Rizzo (CSUM_IP_CHECKED|CSUM_IP_VALID); 1265*2f345d8eSLuigi Rizzo } 1266*2f345d8eSLuigi Rizzo } 1267*2f345d8eSLuigi Rizzo } 1268*2f345d8eSLuigi Rizzo m = tail = pd->mbuf; 1269*2f345d8eSLuigi Rizzo } 1270*2f345d8eSLuigi Rizzo pd->mbuf = NULL; 1271*2f345d8eSLuigi Rizzo len -= frag_len; 1272*2f345d8eSLuigi Rizzo } 1273*2f345d8eSLuigi Rizzo 1274*2f345d8eSLuigi Rizzo if (m) { 1275*2f345d8eSLuigi Rizzo if (!oce_cqe_portid_valid(sc, cqe)) { 1276*2f345d8eSLuigi Rizzo m_freem(m); 1277*2f345d8eSLuigi Rizzo goto exit; 1278*2f345d8eSLuigi Rizzo } 1279*2f345d8eSLuigi Rizzo 1280*2f345d8eSLuigi Rizzo m->m_pkthdr.rcvif = sc->ifp; 1281*2f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1282*2f345d8eSLuigi Rizzo m->m_pkthdr.flowid = rq->queue_index; 1283*2f345d8eSLuigi Rizzo m->m_flags |= M_FLOWID; 1284*2f345d8eSLuigi Rizzo #endif 1285*2f345d8eSLuigi Rizzo //This deternies if vlan tag is present 1286*2f345d8eSLuigi Rizzo if (oce_cqe_vtp_valid(sc, cqe)) { 1287*2f345d8eSLuigi Rizzo if (sc->function_mode & FNM_FLEX10_MODE) { 1288*2f345d8eSLuigi Rizzo /* FLEX10 */ 1289*2f345d8eSLuigi Rizzo if (cqe->u0.s.qnq) { 1290*2f345d8eSLuigi Rizzo /* If QnQ is not set, neglect VLAN */ 1291*2f345d8eSLuigi Rizzo if (IS_BE(sc)) 1292*2f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = 1293*2f345d8eSLuigi Rizzo BSWAP_16(vtag); 1294*2f345d8eSLuigi Rizzo else 1295*2f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag; 1296*2f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG; 1297*2f345d8eSLuigi Rizzo } 1298*2f345d8eSLuigi Rizzo } else { 1299*2f345d8eSLuigi Rizzo if (IS_BE(sc)) 1300*2f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = BSWAP_16(vtag); 1301*2f345d8eSLuigi Rizzo else 1302*2f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag; 1303*2f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG; 1304*2f345d8eSLuigi Rizzo } 1305*2f345d8eSLuigi Rizzo } 1306*2f345d8eSLuigi Rizzo 1307*2f345d8eSLuigi Rizzo sc->ifp->if_ipackets++; 1308*2f345d8eSLuigi Rizzo /* Try to queue to LRO */ 1309*2f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && 1310*2f345d8eSLuigi Rizzo !(m->m_flags & M_VLANTAG) && 1311*2f345d8eSLuigi Rizzo (cqe->u0.s.ip_cksum_pass) && 1312*2f345d8eSLuigi Rizzo (cqe->u0.s.l4_cksum_pass) && 1313*2f345d8eSLuigi Rizzo (!cqe->u0.s.ip_ver) && 1314*2f345d8eSLuigi Rizzo (rq->lro.lro_cnt != 0)) { 1315*2f345d8eSLuigi Rizzo 1316*2f345d8eSLuigi Rizzo if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 1317*2f345d8eSLuigi Rizzo rq->lro_pkts_queued ++; 1318*2f345d8eSLuigi Rizzo goto post_done; 1319*2f345d8eSLuigi Rizzo } 1320*2f345d8eSLuigi Rizzo /* If LRO posting fails then try to post to STACK */ 1321*2f345d8eSLuigi Rizzo } 1322*2f345d8eSLuigi Rizzo 1323*2f345d8eSLuigi Rizzo (*sc->ifp->if_input) (sc->ifp, m); 1324*2f345d8eSLuigi Rizzo post_done: 1325*2f345d8eSLuigi Rizzo /* Update rx stats per queue */ 1326*2f345d8eSLuigi Rizzo rq->rx_stats.rx_pkts++; 1327*2f345d8eSLuigi Rizzo rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 1328*2f345d8eSLuigi Rizzo rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 1329*2f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 1330*2f345d8eSLuigi Rizzo rq->rx_stats.rx_mcast_pkts++; 1331*2f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 1332*2f345d8eSLuigi Rizzo rq->rx_stats.rx_ucast_pkts++; 1333*2f345d8eSLuigi Rizzo } 1334*2f345d8eSLuigi Rizzo exit: 1335*2f345d8eSLuigi Rizzo return; 1336*2f345d8eSLuigi Rizzo } 1337*2f345d8eSLuigi Rizzo 1338*2f345d8eSLuigi Rizzo 1339*2f345d8eSLuigi Rizzo static void 1340*2f345d8eSLuigi Rizzo oce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1341*2f345d8eSLuigi Rizzo { 1342*2f345d8eSLuigi Rizzo uint32_t out, i = 0; 1343*2f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 1344*2f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1345*2f345d8eSLuigi Rizzo int num_frags = cqe->u0.s.num_fragments; 1346*2f345d8eSLuigi Rizzo 1347*2f345d8eSLuigi Rizzo if (IS_XE201(sc) && cqe->u0.s.error) { 1348*2f345d8eSLuigi Rizzo /* Lancer A0 workaround 1349*2f345d8eSLuigi Rizzo * num_frags will be 1 more than actual in case of error 1350*2f345d8eSLuigi Rizzo */ 1351*2f345d8eSLuigi Rizzo if (num_frags) 1352*2f345d8eSLuigi Rizzo num_frags -= 1; 1353*2f345d8eSLuigi Rizzo } 1354*2f345d8eSLuigi Rizzo for (i = 0; i < num_frags; i++) { 1355*2f345d8eSLuigi Rizzo if (rq->packets_out == rq->packets_in) { 1356*2f345d8eSLuigi Rizzo device_printf(sc->dev, 1357*2f345d8eSLuigi Rizzo "RQ transmit descriptor missing\n"); 1358*2f345d8eSLuigi Rizzo } 1359*2f345d8eSLuigi Rizzo out = rq->packets_out + 1; 1360*2f345d8eSLuigi Rizzo if (out == OCE_RQ_PACKET_ARRAY_SIZE) 1361*2f345d8eSLuigi Rizzo out = 0; 1362*2f345d8eSLuigi Rizzo pd = &rq->pckts[rq->packets_out]; 1363*2f345d8eSLuigi Rizzo rq->packets_out = out; 1364*2f345d8eSLuigi Rizzo 1365*2f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1366*2f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, pd->map); 1367*2f345d8eSLuigi Rizzo rq->pending--; 1368*2f345d8eSLuigi Rizzo m_freem(pd->mbuf); 1369*2f345d8eSLuigi Rizzo } 1370*2f345d8eSLuigi Rizzo 1371*2f345d8eSLuigi Rizzo } 1372*2f345d8eSLuigi Rizzo 1373*2f345d8eSLuigi Rizzo 1374*2f345d8eSLuigi Rizzo static int 1375*2f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1376*2f345d8eSLuigi Rizzo { 1377*2f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1; 1378*2f345d8eSLuigi Rizzo int vtp = 0; 1379*2f345d8eSLuigi Rizzo 1380*2f345d8eSLuigi Rizzo if (sc->be3_native) { 1381*2f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1382*2f345d8eSLuigi Rizzo vtp = cqe_v1->u0.s.vlan_tag_present; 1383*2f345d8eSLuigi Rizzo } else { 1384*2f345d8eSLuigi Rizzo vtp = cqe->u0.s.vlan_tag_present; 1385*2f345d8eSLuigi Rizzo } 1386*2f345d8eSLuigi Rizzo 1387*2f345d8eSLuigi Rizzo return vtp; 1388*2f345d8eSLuigi Rizzo 1389*2f345d8eSLuigi Rizzo } 1390*2f345d8eSLuigi Rizzo 1391*2f345d8eSLuigi Rizzo 1392*2f345d8eSLuigi Rizzo static int 1393*2f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1394*2f345d8eSLuigi Rizzo { 1395*2f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1; 1396*2f345d8eSLuigi Rizzo int port_id = 0; 1397*2f345d8eSLuigi Rizzo 1398*2f345d8eSLuigi Rizzo if (sc->be3_native && IS_BE(sc)) { 1399*2f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1400*2f345d8eSLuigi Rizzo port_id = cqe_v1->u0.s.port; 1401*2f345d8eSLuigi Rizzo if (sc->port_id != port_id) 1402*2f345d8eSLuigi Rizzo return 0; 1403*2f345d8eSLuigi Rizzo } else 1404*2f345d8eSLuigi Rizzo ;/* For BE3 legacy and Lancer this is dummy */ 1405*2f345d8eSLuigi Rizzo 1406*2f345d8eSLuigi Rizzo return 1; 1407*2f345d8eSLuigi Rizzo 1408*2f345d8eSLuigi Rizzo } 1409*2f345d8eSLuigi Rizzo 1410*2f345d8eSLuigi Rizzo 1411*2f345d8eSLuigi Rizzo static void 1412*2f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq) 1413*2f345d8eSLuigi Rizzo { 1414*2f345d8eSLuigi Rizzo struct lro_ctrl *lro = &rq->lro; 1415*2f345d8eSLuigi Rizzo struct lro_entry *queued; 1416*2f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1417*2f345d8eSLuigi Rizzo 1418*2f345d8eSLuigi Rizzo if (!IF_LRO_ENABLED(sc)) 1419*2f345d8eSLuigi Rizzo return; 1420*2f345d8eSLuigi Rizzo 1421*2f345d8eSLuigi Rizzo while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { 1422*2f345d8eSLuigi Rizzo SLIST_REMOVE_HEAD(&lro->lro_active, next); 1423*2f345d8eSLuigi Rizzo tcp_lro_flush(lro, queued); 1424*2f345d8eSLuigi Rizzo } 1425*2f345d8eSLuigi Rizzo rq->lro_pkts_queued = 0; 1426*2f345d8eSLuigi Rizzo 1427*2f345d8eSLuigi Rizzo return; 1428*2f345d8eSLuigi Rizzo } 1429*2f345d8eSLuigi Rizzo 1430*2f345d8eSLuigi Rizzo 1431*2f345d8eSLuigi Rizzo static int 1432*2f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc) 1433*2f345d8eSLuigi Rizzo { 1434*2f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL; 1435*2f345d8eSLuigi Rizzo int i = 0, rc = 0; 1436*2f345d8eSLuigi Rizzo 1437*2f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) { 1438*2f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro; 1439*2f345d8eSLuigi Rizzo rc = tcp_lro_init(lro); 1440*2f345d8eSLuigi Rizzo if (rc != 0) { 1441*2f345d8eSLuigi Rizzo device_printf(sc->dev, "LRO init failed\n"); 1442*2f345d8eSLuigi Rizzo return rc; 1443*2f345d8eSLuigi Rizzo } 1444*2f345d8eSLuigi Rizzo lro->ifp = sc->ifp; 1445*2f345d8eSLuigi Rizzo } 1446*2f345d8eSLuigi Rizzo 1447*2f345d8eSLuigi Rizzo return rc; 1448*2f345d8eSLuigi Rizzo } 1449*2f345d8eSLuigi Rizzo 1450*2f345d8eSLuigi Rizzo 1451*2f345d8eSLuigi Rizzo void 1452*2f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc) 1453*2f345d8eSLuigi Rizzo { 1454*2f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL; 1455*2f345d8eSLuigi Rizzo int i = 0; 1456*2f345d8eSLuigi Rizzo 1457*2f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) { 1458*2f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro; 1459*2f345d8eSLuigi Rizzo if (lro) 1460*2f345d8eSLuigi Rizzo tcp_lro_free(lro); 1461*2f345d8eSLuigi Rizzo } 1462*2f345d8eSLuigi Rizzo } 1463*2f345d8eSLuigi Rizzo 1464*2f345d8eSLuigi Rizzo 1465*2f345d8eSLuigi Rizzo int 1466*2f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count) 1467*2f345d8eSLuigi Rizzo { 1468*2f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1469*2f345d8eSLuigi Rizzo int i, in, rc; 1470*2f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 1471*2f345d8eSLuigi Rizzo bus_dma_segment_t segs[6]; 1472*2f345d8eSLuigi Rizzo int nsegs, added = 0; 1473*2f345d8eSLuigi Rizzo struct oce_nic_rqe *rqe; 1474*2f345d8eSLuigi Rizzo pd_rxulp_db_t rxdb_reg; 1475*2f345d8eSLuigi Rizzo 1476*2f345d8eSLuigi Rizzo 1477*2f345d8eSLuigi Rizzo for (i = 0; i < count; i++) { 1478*2f345d8eSLuigi Rizzo in = rq->packets_in + 1; 1479*2f345d8eSLuigi Rizzo if (in == OCE_RQ_PACKET_ARRAY_SIZE) 1480*2f345d8eSLuigi Rizzo in = 0; 1481*2f345d8eSLuigi Rizzo if (in == rq->packets_out) 1482*2f345d8eSLuigi Rizzo break; /* no more room */ 1483*2f345d8eSLuigi Rizzo 1484*2f345d8eSLuigi Rizzo pd = &rq->pckts[rq->packets_in]; 1485*2f345d8eSLuigi Rizzo pd->mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1486*2f345d8eSLuigi Rizzo if (pd->mbuf == NULL) 1487*2f345d8eSLuigi Rizzo break; 1488*2f345d8eSLuigi Rizzo 1489*2f345d8eSLuigi Rizzo pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES; 1490*2f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(rq->tag, 1491*2f345d8eSLuigi Rizzo pd->map, 1492*2f345d8eSLuigi Rizzo pd->mbuf, 1493*2f345d8eSLuigi Rizzo segs, &nsegs, BUS_DMA_NOWAIT); 1494*2f345d8eSLuigi Rizzo if (rc) { 1495*2f345d8eSLuigi Rizzo m_free(pd->mbuf); 1496*2f345d8eSLuigi Rizzo break; 1497*2f345d8eSLuigi Rizzo } 1498*2f345d8eSLuigi Rizzo 1499*2f345d8eSLuigi Rizzo if (nsegs != 1) { 1500*2f345d8eSLuigi Rizzo i--; 1501*2f345d8eSLuigi Rizzo continue; 1502*2f345d8eSLuigi Rizzo } 1503*2f345d8eSLuigi Rizzo 1504*2f345d8eSLuigi Rizzo rq->packets_in = in; 1505*2f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 1506*2f345d8eSLuigi Rizzo 1507*2f345d8eSLuigi Rizzo rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 1508*2f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 1509*2f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 1510*2f345d8eSLuigi Rizzo DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 1511*2f345d8eSLuigi Rizzo RING_PUT(rq->ring, 1); 1512*2f345d8eSLuigi Rizzo added++; 1513*2f345d8eSLuigi Rizzo rq->pending++; 1514*2f345d8eSLuigi Rizzo } 1515*2f345d8eSLuigi Rizzo if (added != 0) { 1516*2f345d8eSLuigi Rizzo for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) { 1517*2f345d8eSLuigi Rizzo DELAY(1); 1518*2f345d8eSLuigi Rizzo rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS; 1519*2f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id; 1520*2f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1521*2f345d8eSLuigi Rizzo added -= OCE_MAX_RQ_POSTS; 1522*2f345d8eSLuigi Rizzo } 1523*2f345d8eSLuigi Rizzo if (added > 0) { 1524*2f345d8eSLuigi Rizzo DELAY(1); 1525*2f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id; 1526*2f345d8eSLuigi Rizzo rxdb_reg.bits.num_posted = added; 1527*2f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1528*2f345d8eSLuigi Rizzo } 1529*2f345d8eSLuigi Rizzo } 1530*2f345d8eSLuigi Rizzo 1531*2f345d8eSLuigi Rizzo return 0; 1532*2f345d8eSLuigi Rizzo } 1533*2f345d8eSLuigi Rizzo 1534*2f345d8eSLuigi Rizzo 1535*2f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */ 1536*2f345d8eSLuigi Rizzo uint16_t 1537*2f345d8eSLuigi Rizzo oce_rq_handler(void *arg) 1538*2f345d8eSLuigi Rizzo { 1539*2f345d8eSLuigi Rizzo struct oce_rq *rq = (struct oce_rq *)arg; 1540*2f345d8eSLuigi Rizzo struct oce_cq *cq = rq->cq; 1541*2f345d8eSLuigi Rizzo POCE_SOFTC sc = rq->parent; 1542*2f345d8eSLuigi Rizzo struct oce_nic_rx_cqe *cqe; 1543*2f345d8eSLuigi Rizzo int num_cqes = 0, rq_buffers_used = 0; 1544*2f345d8eSLuigi Rizzo 1545*2f345d8eSLuigi Rizzo 1546*2f345d8eSLuigi Rizzo LOCK(&rq->rx_lock); 1547*2f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 1548*2f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1549*2f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1550*2f345d8eSLuigi Rizzo while (cqe->u0.dw[2]) { 1551*2f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 1552*2f345d8eSLuigi Rizzo 1553*2f345d8eSLuigi Rizzo RING_GET(rq->ring, 1); 1554*2f345d8eSLuigi Rizzo if (cqe->u0.s.error == 0) { 1555*2f345d8eSLuigi Rizzo oce_rx(rq, cqe->u0.s.frag_index, cqe); 1556*2f345d8eSLuigi Rizzo } else { 1557*2f345d8eSLuigi Rizzo rq->rx_stats.rxcp_err++; 1558*2f345d8eSLuigi Rizzo sc->ifp->if_ierrors++; 1559*2f345d8eSLuigi Rizzo if (IS_XE201(sc)) 1560*2f345d8eSLuigi Rizzo /* Lancer A0 no buffer workaround */ 1561*2f345d8eSLuigi Rizzo oce_discard_rx_comp(rq, cqe); 1562*2f345d8eSLuigi Rizzo else 1563*2f345d8eSLuigi Rizzo /* Post L3/L4 errors to stack.*/ 1564*2f345d8eSLuigi Rizzo oce_rx(rq, cqe->u0.s.frag_index, cqe); 1565*2f345d8eSLuigi Rizzo 1566*2f345d8eSLuigi Rizzo } 1567*2f345d8eSLuigi Rizzo rq->rx_stats.rx_compl++; 1568*2f345d8eSLuigi Rizzo cqe->u0.dw[2] = 0; 1569*2f345d8eSLuigi Rizzo 1570*2f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 1571*2f345d8eSLuigi Rizzo oce_rx_flush_lro(rq); 1572*2f345d8eSLuigi Rizzo } 1573*2f345d8eSLuigi Rizzo 1574*2f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 1575*2f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 1576*2f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1577*2f345d8eSLuigi Rizzo cqe = 1578*2f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 1579*2f345d8eSLuigi Rizzo num_cqes++; 1580*2f345d8eSLuigi Rizzo if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 1581*2f345d8eSLuigi Rizzo break; 1582*2f345d8eSLuigi Rizzo } 1583*2f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc)) 1584*2f345d8eSLuigi Rizzo oce_rx_flush_lro(rq); 1585*2f345d8eSLuigi Rizzo 1586*2f345d8eSLuigi Rizzo if (num_cqes) { 1587*2f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1588*2f345d8eSLuigi Rizzo rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending; 1589*2f345d8eSLuigi Rizzo if (rq_buffers_used > 1) 1590*2f345d8eSLuigi Rizzo oce_alloc_rx_bufs(rq, (rq_buffers_used - 1)); 1591*2f345d8eSLuigi Rizzo } 1592*2f345d8eSLuigi Rizzo 1593*2f345d8eSLuigi Rizzo UNLOCK(&rq->rx_lock); 1594*2f345d8eSLuigi Rizzo 1595*2f345d8eSLuigi Rizzo return 0; 1596*2f345d8eSLuigi Rizzo 1597*2f345d8eSLuigi Rizzo } 1598*2f345d8eSLuigi Rizzo 1599*2f345d8eSLuigi Rizzo 1600*2f345d8eSLuigi Rizzo 1601*2f345d8eSLuigi Rizzo 1602*2f345d8eSLuigi Rizzo /***************************************************************************** 1603*2f345d8eSLuigi Rizzo * Helper function prototypes in this file * 1604*2f345d8eSLuigi Rizzo *****************************************************************************/ 1605*2f345d8eSLuigi Rizzo 1606*2f345d8eSLuigi Rizzo static int 1607*2f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc) 1608*2f345d8eSLuigi Rizzo { 1609*2f345d8eSLuigi Rizzo 1610*2f345d8eSLuigi Rizzo sc->ifp = if_alloc(IFT_ETHER); 1611*2f345d8eSLuigi Rizzo if (!sc->ifp) 1612*2f345d8eSLuigi Rizzo return ENOMEM; 1613*2f345d8eSLuigi Rizzo 1614*2f345d8eSLuigi Rizzo ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 1615*2f345d8eSLuigi Rizzo ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1616*2f345d8eSLuigi Rizzo ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 1617*2f345d8eSLuigi Rizzo 1618*2f345d8eSLuigi Rizzo sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 1619*2f345d8eSLuigi Rizzo sc->ifp->if_ioctl = oce_ioctl; 1620*2f345d8eSLuigi Rizzo sc->ifp->if_start = oce_start; 1621*2f345d8eSLuigi Rizzo sc->ifp->if_init = oce_init; 1622*2f345d8eSLuigi Rizzo sc->ifp->if_mtu = ETHERMTU; 1623*2f345d8eSLuigi Rizzo sc->ifp->if_softc = sc; 1624*2f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1625*2f345d8eSLuigi Rizzo sc->ifp->if_transmit = oce_multiq_start; 1626*2f345d8eSLuigi Rizzo sc->ifp->if_qflush = oce_multiq_flush; 1627*2f345d8eSLuigi Rizzo #endif 1628*2f345d8eSLuigi Rizzo 1629*2f345d8eSLuigi Rizzo if_initname(sc->ifp, 1630*2f345d8eSLuigi Rizzo device_get_name(sc->dev), device_get_unit(sc->dev)); 1631*2f345d8eSLuigi Rizzo 1632*2f345d8eSLuigi Rizzo sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 1633*2f345d8eSLuigi Rizzo IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 1634*2f345d8eSLuigi Rizzo IFQ_SET_READY(&sc->ifp->if_snd); 1635*2f345d8eSLuigi Rizzo 1636*2f345d8eSLuigi Rizzo sc->ifp->if_hwassist = OCE_IF_HWASSIST; 1637*2f345d8eSLuigi Rizzo sc->ifp->if_hwassist |= CSUM_TSO; 1638*2f345d8eSLuigi Rizzo sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 1639*2f345d8eSLuigi Rizzo 1640*2f345d8eSLuigi Rizzo sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 1641*2f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_TSO; 1642*2f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_HWCSUM; 1643*2f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 1644*2f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_LRO; 1645*2f345d8eSLuigi Rizzo 1646*2f345d8eSLuigi Rizzo sc->ifp->if_capenable = sc->ifp->if_capabilities; 1647*2f345d8eSLuigi Rizzo sc->ifp->if_baudrate = IF_Mbps(10000ULL); 1648*2f345d8eSLuigi Rizzo 1649*2f345d8eSLuigi Rizzo ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 1650*2f345d8eSLuigi Rizzo 1651*2f345d8eSLuigi Rizzo return 0; 1652*2f345d8eSLuigi Rizzo } 1653*2f345d8eSLuigi Rizzo 1654*2f345d8eSLuigi Rizzo 1655*2f345d8eSLuigi Rizzo static void 1656*2f345d8eSLuigi Rizzo oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1657*2f345d8eSLuigi Rizzo { 1658*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 1659*2f345d8eSLuigi Rizzo 1660*2f345d8eSLuigi Rizzo if (ifp->if_softc != arg) 1661*2f345d8eSLuigi Rizzo return; 1662*2f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095)) 1663*2f345d8eSLuigi Rizzo return; 1664*2f345d8eSLuigi Rizzo 1665*2f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 1; 1666*2f345d8eSLuigi Rizzo sc->vlans_added++; 1667*2f345d8eSLuigi Rizzo oce_vid_config(sc); 1668*2f345d8eSLuigi Rizzo } 1669*2f345d8eSLuigi Rizzo 1670*2f345d8eSLuigi Rizzo 1671*2f345d8eSLuigi Rizzo static void 1672*2f345d8eSLuigi Rizzo oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 1673*2f345d8eSLuigi Rizzo { 1674*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 1675*2f345d8eSLuigi Rizzo 1676*2f345d8eSLuigi Rizzo if (ifp->if_softc != arg) 1677*2f345d8eSLuigi Rizzo return; 1678*2f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095)) 1679*2f345d8eSLuigi Rizzo return; 1680*2f345d8eSLuigi Rizzo 1681*2f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 0; 1682*2f345d8eSLuigi Rizzo sc->vlans_added--; 1683*2f345d8eSLuigi Rizzo oce_vid_config(sc); 1684*2f345d8eSLuigi Rizzo } 1685*2f345d8eSLuigi Rizzo 1686*2f345d8eSLuigi Rizzo 1687*2f345d8eSLuigi Rizzo /* 1688*2f345d8eSLuigi Rizzo * A max of 64 vlans can be configured in BE. If the user configures 1689*2f345d8eSLuigi Rizzo * more, place the card in vlan promiscuous mode. 1690*2f345d8eSLuigi Rizzo */ 1691*2f345d8eSLuigi Rizzo static int 1692*2f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc) 1693*2f345d8eSLuigi Rizzo { 1694*2f345d8eSLuigi Rizzo struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 1695*2f345d8eSLuigi Rizzo uint16_t ntags = 0, i; 1696*2f345d8eSLuigi Rizzo int status = 0; 1697*2f345d8eSLuigi Rizzo 1698*2f345d8eSLuigi Rizzo if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 1699*2f345d8eSLuigi Rizzo (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 1700*2f345d8eSLuigi Rizzo for (i = 0; i < MAX_VLANS; i++) { 1701*2f345d8eSLuigi Rizzo if (sc->vlan_tag[i]) { 1702*2f345d8eSLuigi Rizzo vtags[ntags].vtag = i; 1703*2f345d8eSLuigi Rizzo ntags++; 1704*2f345d8eSLuigi Rizzo } 1705*2f345d8eSLuigi Rizzo } 1706*2f345d8eSLuigi Rizzo if (ntags) 1707*2f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1708*2f345d8eSLuigi Rizzo vtags, ntags, 1, 0); 1709*2f345d8eSLuigi Rizzo } else 1710*2f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id, 1711*2f345d8eSLuigi Rizzo NULL, 0, 1, 1); 1712*2f345d8eSLuigi Rizzo return status; 1713*2f345d8eSLuigi Rizzo } 1714*2f345d8eSLuigi Rizzo 1715*2f345d8eSLuigi Rizzo 1716*2f345d8eSLuigi Rizzo static void 1717*2f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc) 1718*2f345d8eSLuigi Rizzo { 1719*2f345d8eSLuigi Rizzo uint32_t old_pmac_id = sc->pmac_id; 1720*2f345d8eSLuigi Rizzo int status = 0; 1721*2f345d8eSLuigi Rizzo 1722*2f345d8eSLuigi Rizzo 1723*2f345d8eSLuigi Rizzo status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1724*2f345d8eSLuigi Rizzo sc->macaddr.size_of_struct); 1725*2f345d8eSLuigi Rizzo if (!status) 1726*2f345d8eSLuigi Rizzo return; 1727*2f345d8eSLuigi Rizzo 1728*2f345d8eSLuigi Rizzo status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 1729*2f345d8eSLuigi Rizzo sc->if_id, &sc->pmac_id); 1730*2f345d8eSLuigi Rizzo if (!status) { 1731*2f345d8eSLuigi Rizzo status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 1732*2f345d8eSLuigi Rizzo bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 1733*2f345d8eSLuigi Rizzo sc->macaddr.size_of_struct); 1734*2f345d8eSLuigi Rizzo } 1735*2f345d8eSLuigi Rizzo if (status) 1736*2f345d8eSLuigi Rizzo device_printf(sc->dev, "Failed update macaddress\n"); 1737*2f345d8eSLuigi Rizzo 1738*2f345d8eSLuigi Rizzo } 1739*2f345d8eSLuigi Rizzo 1740*2f345d8eSLuigi Rizzo 1741*2f345d8eSLuigi Rizzo static int 1742*2f345d8eSLuigi Rizzo oce_handle_passthrough(struct ifnet *ifp, caddr_t data) 1743*2f345d8eSLuigi Rizzo { 1744*2f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 1745*2f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data; 1746*2f345d8eSLuigi Rizzo int rc = ENXIO; 1747*2f345d8eSLuigi Rizzo char cookie[32] = {0}; 1748*2f345d8eSLuigi Rizzo void *priv_data = (void *)ifr->ifr_data; 1749*2f345d8eSLuigi Rizzo void *ioctl_ptr; 1750*2f345d8eSLuigi Rizzo uint32_t req_size; 1751*2f345d8eSLuigi Rizzo struct mbx_hdr req; 1752*2f345d8eSLuigi Rizzo OCE_DMA_MEM dma_mem; 1753*2f345d8eSLuigi Rizzo 1754*2f345d8eSLuigi Rizzo 1755*2f345d8eSLuigi Rizzo if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 1756*2f345d8eSLuigi Rizzo return EFAULT; 1757*2f345d8eSLuigi Rizzo 1758*2f345d8eSLuigi Rizzo if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 1759*2f345d8eSLuigi Rizzo return EINVAL; 1760*2f345d8eSLuigi Rizzo 1761*2f345d8eSLuigi Rizzo ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 1762*2f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 1763*2f345d8eSLuigi Rizzo return EFAULT; 1764*2f345d8eSLuigi Rizzo 1765*2f345d8eSLuigi Rizzo req_size = le32toh(req.u0.req.request_length); 1766*2f345d8eSLuigi Rizzo if (req_size > 65536) 1767*2f345d8eSLuigi Rizzo return EINVAL; 1768*2f345d8eSLuigi Rizzo 1769*2f345d8eSLuigi Rizzo req_size += sizeof(struct mbx_hdr); 1770*2f345d8eSLuigi Rizzo rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 1771*2f345d8eSLuigi Rizzo if (rc) 1772*2f345d8eSLuigi Rizzo return ENOMEM; 1773*2f345d8eSLuigi Rizzo 1774*2f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 1775*2f345d8eSLuigi Rizzo rc = EFAULT; 1776*2f345d8eSLuigi Rizzo goto dma_free; 1777*2f345d8eSLuigi Rizzo } 1778*2f345d8eSLuigi Rizzo 1779*2f345d8eSLuigi Rizzo rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 1780*2f345d8eSLuigi Rizzo if (rc) { 1781*2f345d8eSLuigi Rizzo rc = EIO; 1782*2f345d8eSLuigi Rizzo goto dma_free; 1783*2f345d8eSLuigi Rizzo } 1784*2f345d8eSLuigi Rizzo 1785*2f345d8eSLuigi Rizzo if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 1786*2f345d8eSLuigi Rizzo rc = EFAULT; 1787*2f345d8eSLuigi Rizzo 1788*2f345d8eSLuigi Rizzo dma_free: 1789*2f345d8eSLuigi Rizzo oce_dma_free(sc, &dma_mem); 1790*2f345d8eSLuigi Rizzo return rc; 1791*2f345d8eSLuigi Rizzo 1792*2f345d8eSLuigi Rizzo } 1793*2f345d8eSLuigi Rizzo 1794*2f345d8eSLuigi Rizzo 1795*2f345d8eSLuigi Rizzo static void 1796*2f345d8eSLuigi Rizzo oce_local_timer(void *arg) 1797*2f345d8eSLuigi Rizzo { 1798*2f345d8eSLuigi Rizzo POCE_SOFTC sc = arg; 1799*2f345d8eSLuigi Rizzo int i = 0; 1800*2f345d8eSLuigi Rizzo 1801*2f345d8eSLuigi Rizzo oce_refresh_nic_stats(sc); 1802*2f345d8eSLuigi Rizzo oce_refresh_queue_stats(sc); 1803*2f345d8eSLuigi Rizzo oce_mac_addr_set(sc); 1804*2f345d8eSLuigi Rizzo 1805*2f345d8eSLuigi Rizzo /* TX Watch Dog*/ 1806*2f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) 1807*2f345d8eSLuigi Rizzo oce_tx_restart(sc, sc->wq[i]); 1808*2f345d8eSLuigi Rizzo 1809*2f345d8eSLuigi Rizzo callout_reset(&sc->timer, hz, oce_local_timer, sc); 1810*2f345d8eSLuigi Rizzo } 1811*2f345d8eSLuigi Rizzo 1812*2f345d8eSLuigi Rizzo 1813*2f345d8eSLuigi Rizzo static void 1814*2f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc) 1815*2f345d8eSLuigi Rizzo { 1816*2f345d8eSLuigi Rizzo int i, mtime = 0; 1817*2f345d8eSLuigi Rizzo int wait_req = 0; 1818*2f345d8eSLuigi Rizzo struct oce_rq *rq; 1819*2f345d8eSLuigi Rizzo struct oce_wq *wq; 1820*2f345d8eSLuigi Rizzo struct oce_eq *eq; 1821*2f345d8eSLuigi Rizzo 1822*2f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1823*2f345d8eSLuigi Rizzo 1824*2f345d8eSLuigi Rizzo /*Wait for max of 400ms for TX completions to be done */ 1825*2f345d8eSLuigi Rizzo while (mtime < 400) { 1826*2f345d8eSLuigi Rizzo wait_req = 0; 1827*2f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) { 1828*2f345d8eSLuigi Rizzo if (wq->ring->num_used) { 1829*2f345d8eSLuigi Rizzo wait_req = 1; 1830*2f345d8eSLuigi Rizzo DELAY(1); 1831*2f345d8eSLuigi Rizzo break; 1832*2f345d8eSLuigi Rizzo } 1833*2f345d8eSLuigi Rizzo } 1834*2f345d8eSLuigi Rizzo mtime += 1; 1835*2f345d8eSLuigi Rizzo if (!wait_req) 1836*2f345d8eSLuigi Rizzo break; 1837*2f345d8eSLuigi Rizzo } 1838*2f345d8eSLuigi Rizzo 1839*2f345d8eSLuigi Rizzo /* Stop intrs and finish any bottom halves pending */ 1840*2f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 1841*2f345d8eSLuigi Rizzo 1842*2f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) { 1843*2f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) { 1844*2f345d8eSLuigi Rizzo taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 1845*2f345d8eSLuigi Rizzo } 1846*2f345d8eSLuigi Rizzo } 1847*2f345d8eSLuigi Rizzo 1848*2f345d8eSLuigi Rizzo /* Delete RX queue in card with flush param */ 1849*2f345d8eSLuigi Rizzo oce_stop_rx(sc); 1850*2f345d8eSLuigi Rizzo 1851*2f345d8eSLuigi Rizzo /* Invalidate any pending cq and eq entries*/ 1852*2f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) 1853*2f345d8eSLuigi Rizzo oce_drain_eq(eq); 1854*2f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) 1855*2f345d8eSLuigi Rizzo oce_drain_rq_cq(rq); 1856*2f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) 1857*2f345d8eSLuigi Rizzo oce_drain_wq_cq(wq); 1858*2f345d8eSLuigi Rizzo 1859*2f345d8eSLuigi Rizzo /* But still we need to get MCC aync events. 1860*2f345d8eSLuigi Rizzo So enable intrs and also arm first EQ 1861*2f345d8eSLuigi Rizzo */ 1862*2f345d8eSLuigi Rizzo oce_hw_intr_enable(sc); 1863*2f345d8eSLuigi Rizzo oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 1864*2f345d8eSLuigi Rizzo 1865*2f345d8eSLuigi Rizzo DELAY(10); 1866*2f345d8eSLuigi Rizzo } 1867*2f345d8eSLuigi Rizzo 1868*2f345d8eSLuigi Rizzo 1869*2f345d8eSLuigi Rizzo static void 1870*2f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc) 1871*2f345d8eSLuigi Rizzo { 1872*2f345d8eSLuigi Rizzo struct oce_eq *eq; 1873*2f345d8eSLuigi Rizzo struct oce_rq *rq; 1874*2f345d8eSLuigi Rizzo struct oce_wq *wq; 1875*2f345d8eSLuigi Rizzo int i, rc = 0; 1876*2f345d8eSLuigi Rizzo 1877*2f345d8eSLuigi Rizzo sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 1878*2f345d8eSLuigi Rizzo 1879*2f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 1880*2f345d8eSLuigi Rizzo 1881*2f345d8eSLuigi Rizzo oce_start_rx(sc); 1882*2f345d8eSLuigi Rizzo 1883*2f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 1884*2f345d8eSLuigi Rizzo rc = oce_start_rq(rq); 1885*2f345d8eSLuigi Rizzo if (rc) 1886*2f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start RX\n"); 1887*2f345d8eSLuigi Rizzo } 1888*2f345d8eSLuigi Rizzo 1889*2f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) { 1890*2f345d8eSLuigi Rizzo rc = oce_start_wq(wq); 1891*2f345d8eSLuigi Rizzo if (rc) 1892*2f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start TX\n"); 1893*2f345d8eSLuigi Rizzo } 1894*2f345d8eSLuigi Rizzo 1895*2f345d8eSLuigi Rizzo 1896*2f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) 1897*2f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 1898*2f345d8eSLuigi Rizzo 1899*2f345d8eSLuigi Rizzo oce_hw_intr_enable(sc); 1900*2f345d8eSLuigi Rizzo 1901*2f345d8eSLuigi Rizzo } 1902*2f345d8eSLuigi Rizzo 1903*2f345d8eSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */ 1904*2f345d8eSLuigi Rizzo uint16_t 1905*2f345d8eSLuigi Rizzo oce_mq_handler(void *arg) 1906*2f345d8eSLuigi Rizzo { 1907*2f345d8eSLuigi Rizzo struct oce_mq *mq = (struct oce_mq *)arg; 1908*2f345d8eSLuigi Rizzo POCE_SOFTC sc = mq->parent; 1909*2f345d8eSLuigi Rizzo struct oce_cq *cq = mq->cq; 1910*2f345d8eSLuigi Rizzo int num_cqes = 0; 1911*2f345d8eSLuigi Rizzo struct oce_mq_cqe *cqe; 1912*2f345d8eSLuigi Rizzo struct oce_async_cqe_link_state *acqe; 1913*2f345d8eSLuigi Rizzo 1914*2f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 1915*2f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1916*2f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 1917*2f345d8eSLuigi Rizzo while (cqe->u0.dw[3]) { 1918*2f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 1919*2f345d8eSLuigi Rizzo if (cqe->u0.s.async_event) { 1920*2f345d8eSLuigi Rizzo acqe = (struct oce_async_cqe_link_state *)cqe; 1921*2f345d8eSLuigi Rizzo if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 1922*2f345d8eSLuigi Rizzo ASYNC_EVENT_LINK_UP) { 1923*2f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_UP; 1924*2f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_UP); 1925*2f345d8eSLuigi Rizzo } else { 1926*2f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_DOWN; 1927*2f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_DOWN); 1928*2f345d8eSLuigi Rizzo } 1929*2f345d8eSLuigi Rizzo 1930*2f345d8eSLuigi Rizzo if (acqe->u0.s.event_code == 1931*2f345d8eSLuigi Rizzo ASYNC_EVENT_CODE_LINK_STATE) { 1932*2f345d8eSLuigi Rizzo sc->link_speed = acqe->u0.s.speed; 1933*2f345d8eSLuigi Rizzo sc->qos_link_speed = 1934*2f345d8eSLuigi Rizzo (uint32_t )acqe->u0.s.qos_link_speed * 10; 1935*2f345d8eSLuigi Rizzo } 1936*2f345d8eSLuigi Rizzo } 1937*2f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 1938*2f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 1939*2f345d8eSLuigi Rizzo RING_GET(mq->ring, 1); 1940*2f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 1941*2f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1942*2f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 1943*2f345d8eSLuigi Rizzo num_cqes++; 1944*2f345d8eSLuigi Rizzo } 1945*2f345d8eSLuigi Rizzo 1946*2f345d8eSLuigi Rizzo if (num_cqes) 1947*2f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1948*2f345d8eSLuigi Rizzo 1949*2f345d8eSLuigi Rizzo return 0; 1950*2f345d8eSLuigi Rizzo } 1951*2f345d8eSLuigi Rizzo 1952*2f345d8eSLuigi Rizzo 1953*2f345d8eSLuigi Rizzo static void 1954*2f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc) 1955*2f345d8eSLuigi Rizzo { 1956*2f345d8eSLuigi Rizzo int max_rss = 0; 1957*2f345d8eSLuigi Rizzo 1958*2f345d8eSLuigi Rizzo /* Check if it is FLEX machine. Is so dont use RSS */ 1959*2f345d8eSLuigi Rizzo if ((sc->function_mode & FNM_FLEX10_MODE) || 1960*2f345d8eSLuigi Rizzo (!sc->rss_enable) || 1961*2f345d8eSLuigi Rizzo (sc->flags & OCE_FLAGS_BE2)) { 1962*2f345d8eSLuigi Rizzo sc->nrqs = 1; 1963*2f345d8eSLuigi Rizzo sc->nwqs = 1; 1964*2f345d8eSLuigi Rizzo sc->rss_enable = 0; 1965*2f345d8eSLuigi Rizzo } else { 1966*2f345d8eSLuigi Rizzo /* For multiq, our deisgn is to have TX rings equal to 1967*2f345d8eSLuigi Rizzo RSS rings. So that we can pair up one RSS ring and TX 1968*2f345d8eSLuigi Rizzo to a single intr, which improves CPU cache efficiency. 1969*2f345d8eSLuigi Rizzo */ 1970*2f345d8eSLuigi Rizzo if (IS_BE(sc) && (!sc->be3_native)) 1971*2f345d8eSLuigi Rizzo max_rss = OCE_LEGACY_MODE_RSS; 1972*2f345d8eSLuigi Rizzo else 1973*2f345d8eSLuigi Rizzo max_rss = OCE_MAX_RSS; 1974*2f345d8eSLuigi Rizzo 1975*2f345d8eSLuigi Rizzo sc->nrqs = MIN(OCE_NCPUS, max_rss) + 1; /* 1 for def RX */ 1976*2f345d8eSLuigi Rizzo sc->nwqs = MIN(OCE_NCPUS, max_rss); 1977*2f345d8eSLuigi Rizzo 1978*2f345d8eSLuigi Rizzo /*Hardware issue. Turn off multi TX for be2 */ 1979*2f345d8eSLuigi Rizzo if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2)) 1980*2f345d8eSLuigi Rizzo sc->nwqs = 1; 1981*2f345d8eSLuigi Rizzo 1982*2f345d8eSLuigi Rizzo } 1983*2f345d8eSLuigi Rizzo 1984*2f345d8eSLuigi Rizzo } 1985*2f345d8eSLuigi Rizzo 1986*2f345d8eSLuigi Rizzo 1987*2f345d8eSLuigi Rizzo static void 1988*2f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc) 1989*2f345d8eSLuigi Rizzo { 1990*2f345d8eSLuigi Rizzo if (sc->rss_enable) { 1991*2f345d8eSLuigi Rizzo sc->nrqs = sc->intr_count + 1; 1992*2f345d8eSLuigi Rizzo sc->nwqs = sc->intr_count; 1993*2f345d8eSLuigi Rizzo if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2)) 1994*2f345d8eSLuigi Rizzo sc->nwqs = 1; 1995*2f345d8eSLuigi Rizzo } else { 1996*2f345d8eSLuigi Rizzo sc->nrqs = 1; 1997*2f345d8eSLuigi Rizzo sc->nwqs = 1; 1998*2f345d8eSLuigi Rizzo } 1999*2f345d8eSLuigi Rizzo } 2000*2f345d8eSLuigi Rizzo 2001