1231437Sluigi/*- 2252869Sdelphij * Copyright (C) 2013 Emulex 3231437Sluigi * All rights reserved. 4231437Sluigi * 5231437Sluigi * Redistribution and use in source and binary forms, with or without 6231437Sluigi * modification, are permitted provided that the following conditions are met: 7231437Sluigi * 8231437Sluigi * 1. Redistributions of source code must retain the above copyright notice, 9231437Sluigi * this list of conditions and the following disclaimer. 10231437Sluigi * 11231437Sluigi * 2. Redistributions in binary form must reproduce the above copyright 12231437Sluigi * notice, this list of conditions and the following disclaimer in the 13231437Sluigi * documentation and/or other materials provided with the distribution. 14231437Sluigi * 15231437Sluigi * 3. Neither the name of the Emulex Corporation nor the names of its 16231437Sluigi * contributors may be used to endorse or promote products derived from 17231437Sluigi * this software without specific prior written permission. 18231437Sluigi * 19231437Sluigi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20231437Sluigi * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21231437Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22231437Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23231437Sluigi * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24231437Sluigi * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25231437Sluigi * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26231437Sluigi * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27231437Sluigi * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28231437Sluigi * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29231437Sluigi * POSSIBILITY OF SUCH DAMAGE. 30231437Sluigi * 31231437Sluigi * Contact Information: 32231437Sluigi * freebsd-drivers@emulex.com 33231437Sluigi * 34231437Sluigi * Emulex 35231437Sluigi * 3333 Susan Street 36231437Sluigi * Costa Mesa, CA 92626 37231437Sluigi */ 38231437Sluigi 39231437Sluigi/* $FreeBSD: stable/11/sys/dev/oce/oce_if.c 369531 2021-03-30 15:05:49Z freqlabs $ */ 40231437Sluigi 41231511Sbz#include "opt_inet6.h" 42231511Sbz#include "opt_inet.h" 43231511Sbz 44231437Sluigi#include "oce_if.h" 45338938Sjpaetzel#include "oce_user.h" 46231437Sluigi 47338938Sjpaetzel#define is_tso_pkt(m) (m->m_pkthdr.csum_flags & CSUM_TSO) 48338938Sjpaetzel 49257007Sdelphij/* UE Status Low CSR */ 50257007Sdelphijstatic char *ue_status_low_desc[] = { 51338938Sjpaetzel "CEV", 52338938Sjpaetzel "CTX", 53338938Sjpaetzel "DBUF", 54338938Sjpaetzel "ERX", 55338938Sjpaetzel "Host", 56338938Sjpaetzel "MPU", 57338938Sjpaetzel "NDMA", 58338938Sjpaetzel "PTC ", 59338938Sjpaetzel "RDMA ", 60338938Sjpaetzel "RXF ", 61338938Sjpaetzel "RXIPS ", 62338938Sjpaetzel "RXULP0 ", 63338938Sjpaetzel "RXULP1 ", 64338938Sjpaetzel "RXULP2 ", 65338938Sjpaetzel "TIM ", 66338938Sjpaetzel "TPOST ", 67338938Sjpaetzel "TPRE ", 68338938Sjpaetzel "TXIPS ", 69338938Sjpaetzel "TXULP0 ", 70338938Sjpaetzel "TXULP1 ", 71338938Sjpaetzel "UC ", 72338938Sjpaetzel "WDMA ", 73338938Sjpaetzel "TXULP2 ", 74338938Sjpaetzel "HOST1 ", 75338938Sjpaetzel "P0_OB_LINK ", 76338938Sjpaetzel "P1_OB_LINK ", 77338938Sjpaetzel "HOST_GPIO ", 78338938Sjpaetzel "MBOX ", 79338938Sjpaetzel "AXGMAC0", 80338938Sjpaetzel "AXGMAC1", 81338938Sjpaetzel "JTAG", 82338938Sjpaetzel "MPU_INTPEND" 83257007Sdelphij}; 84231437Sluigi 85257007Sdelphij/* UE Status High CSR */ 86257007Sdelphijstatic char *ue_status_hi_desc[] = { 87338938Sjpaetzel "LPCMEMHOST", 88338938Sjpaetzel "MGMT_MAC", 89338938Sjpaetzel "PCS0ONLINE", 90338938Sjpaetzel "MPU_IRAM", 91338938Sjpaetzel "PCS1ONLINE", 92338938Sjpaetzel "PCTL0", 93338938Sjpaetzel "PCTL1", 94338938Sjpaetzel "PMEM", 95338938Sjpaetzel "RR", 96338938Sjpaetzel "TXPB", 97338938Sjpaetzel "RXPP", 98338938Sjpaetzel "XAUI", 99338938Sjpaetzel "TXP", 100338938Sjpaetzel "ARM", 101338938Sjpaetzel "IPC", 102338938Sjpaetzel "HOST2", 103338938Sjpaetzel "HOST3", 104338938Sjpaetzel "HOST4", 105338938Sjpaetzel "HOST5", 106338938Sjpaetzel "HOST6", 107338938Sjpaetzel "HOST7", 108338938Sjpaetzel "HOST8", 109338938Sjpaetzel "HOST9", 110338938Sjpaetzel "NETC", 111338938Sjpaetzel "Unknown", 112338938Sjpaetzel "Unknown", 113338938Sjpaetzel "Unknown", 114338938Sjpaetzel "Unknown", 115338938Sjpaetzel "Unknown", 116338938Sjpaetzel "Unknown", 117338938Sjpaetzel "Unknown", 118338938Sjpaetzel "Unknown" 119257007Sdelphij}; 120257007Sdelphij 121338938Sjpaetzelstruct oce_common_cqe_info{ 122338938Sjpaetzel uint8_t vtp:1; 123338938Sjpaetzel uint8_t l4_cksum_pass:1; 124338938Sjpaetzel uint8_t ip_cksum_pass:1; 125338938Sjpaetzel uint8_t ipv6_frame:1; 126338938Sjpaetzel uint8_t qnq:1; 127338938Sjpaetzel uint8_t rsvd:3; 128338938Sjpaetzel uint8_t num_frags; 129338938Sjpaetzel uint16_t pkt_size; 130338938Sjpaetzel uint16_t vtag; 131338938Sjpaetzel}; 132257007Sdelphij 133338938Sjpaetzel 134231437Sluigi/* Driver entry points prototypes */ 135231437Sluigistatic int oce_probe(device_t dev); 136231437Sluigistatic int oce_attach(device_t dev); 137231437Sluigistatic int oce_detach(device_t dev); 138231437Sluigistatic int oce_shutdown(device_t dev); 139231437Sluigistatic int oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 140231437Sluigistatic void oce_init(void *xsc); 141231437Sluigistatic int oce_multiq_start(struct ifnet *ifp, struct mbuf *m); 142231437Sluigistatic void oce_multiq_flush(struct ifnet *ifp); 143231437Sluigi 144231437Sluigi/* Driver interrupt routines protypes */ 145231437Sluigistatic void oce_intr(void *arg, int pending); 146231437Sluigistatic int oce_setup_intr(POCE_SOFTC sc); 147231437Sluigistatic int oce_fast_isr(void *arg); 148231437Sluigistatic int oce_alloc_intr(POCE_SOFTC sc, int vector, 149231437Sluigi void (*isr) (void *arg, int pending)); 150231437Sluigi 151231437Sluigi/* Media callbacks prototypes */ 152231437Sluigistatic void oce_media_status(struct ifnet *ifp, struct ifmediareq *req); 153231437Sluigistatic int oce_media_change(struct ifnet *ifp); 154231437Sluigi 155231437Sluigi/* Transmit routines prototypes */ 156231437Sluigistatic int oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index); 157231437Sluigistatic void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq); 158338938Sjpaetzelstatic void oce_process_tx_completion(struct oce_wq *wq); 159231437Sluigistatic int oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, 160231437Sluigi struct oce_wq *wq); 161231437Sluigi 162231437Sluigi/* Receive routines prototypes */ 163231437Sluigistatic int oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 164231437Sluigistatic int oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 165338938Sjpaetzelstatic void oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); 166338938Sjpaetzelstatic void oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq); 167338938Sjpaetzelstatic uint16_t oce_rq_handler_lro(void *arg); 168338938Sjpaetzelstatic void oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2); 169338938Sjpaetzelstatic void oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2); 170338938Sjpaetzelstatic void oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m); 171231437Sluigi 172231437Sluigi/* Helper function prototypes in this file */ 173231437Sluigistatic int oce_attach_ifp(POCE_SOFTC sc); 174231437Sluigistatic void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 175231437Sluigistatic void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 176231437Sluigistatic int oce_vid_config(POCE_SOFTC sc); 177231437Sluigistatic void oce_mac_addr_set(POCE_SOFTC sc); 178231437Sluigistatic int oce_handle_passthrough(struct ifnet *ifp, caddr_t data); 179231437Sluigistatic void oce_local_timer(void *arg); 180231437Sluigistatic void oce_if_deactivate(POCE_SOFTC sc); 181231437Sluigistatic void oce_if_activate(POCE_SOFTC sc); 182231437Sluigistatic void setup_max_queues_want(POCE_SOFTC sc); 183231437Sluigistatic void update_queues_got(POCE_SOFTC sc); 184231879Sluigistatic void process_link_state(POCE_SOFTC sc, 185231879Sluigi struct oce_async_cqe_link_state *acqe); 186247880Sdelphijstatic int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m); 187252869Sdelphijstatic void oce_get_config(POCE_SOFTC sc); 188247880Sdelphijstatic struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete); 189338938Sjpaetzelstatic void oce_read_env_variables(POCE_SOFTC sc); 190231437Sluigi 191338938Sjpaetzel 192231879Sluigi/* IP specific */ 193231879Sluigi#if defined(INET6) || defined(INET) 194231879Sluigistatic int oce_init_lro(POCE_SOFTC sc); 195231879Sluigistatic struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp); 196231879Sluigi#endif 197231879Sluigi 198231437Sluigistatic device_method_t oce_dispatch[] = { 199231437Sluigi DEVMETHOD(device_probe, oce_probe), 200231437Sluigi DEVMETHOD(device_attach, oce_attach), 201231437Sluigi DEVMETHOD(device_detach, oce_detach), 202231437Sluigi DEVMETHOD(device_shutdown, oce_shutdown), 203246128Ssbz 204246128Ssbz DEVMETHOD_END 205231437Sluigi}; 206231437Sluigi 207231437Sluigistatic driver_t oce_driver = { 208231437Sluigi "oce", 209231437Sluigi oce_dispatch, 210231437Sluigi sizeof(OCE_SOFTC) 211231437Sluigi}; 212231437Sluigistatic devclass_t oce_devclass; 213231437Sluigi 214231437Sluigi 215231437SluigiDRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0); 216231437SluigiMODULE_DEPEND(oce, pci, 1, 1, 1); 217231437SluigiMODULE_DEPEND(oce, ether, 1, 1, 1); 218231437SluigiMODULE_VERSION(oce, 1); 219231437Sluigi 220231437Sluigi 221231437Sluigi/* global vars */ 222231437Sluigiconst char component_revision[32] = {"///" COMPONENT_REVISION "///"}; 223231437Sluigi 224231437Sluigi/* Module capabilites and parameters */ 225231437Sluigiuint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED; 226231437Sluigiuint32_t oce_enable_rss = OCE_MODCAP_RSS; 227338938Sjpaetzeluint32_t oce_rq_buf_size = 2048; 228231437Sluigi 229231437SluigiTUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled); 230231437SluigiTUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss); 231231437Sluigi 232231437Sluigi 233231437Sluigi/* Supported devices table */ 234231437Sluigistatic uint32_t supportedDevices[] = { 235231437Sluigi (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2, 236231437Sluigi (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3, 237231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3, 238231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201, 239231437Sluigi (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF, 240252869Sdelphij (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH 241231437Sluigi}; 242231437Sluigi 243338938SjpaetzelPOCE_SOFTC softc_head = NULL; 244338938SjpaetzelPOCE_SOFTC softc_tail = NULL; 245231437Sluigi 246338938Sjpaetzelstruct oce_rdma_if *oce_rdma_if = NULL; 247231437Sluigi 248231437Sluigi/***************************************************************************** 249231437Sluigi * Driver entry points functions * 250231437Sluigi *****************************************************************************/ 251231437Sluigi 252231437Sluigistatic int 253231437Sluigioce_probe(device_t dev) 254231437Sluigi{ 255231879Sluigi uint16_t vendor = 0; 256231879Sluigi uint16_t device = 0; 257231879Sluigi int i = 0; 258231879Sluigi char str[256] = {0}; 259231437Sluigi POCE_SOFTC sc; 260231437Sluigi 261231437Sluigi sc = device_get_softc(dev); 262231437Sluigi bzero(sc, sizeof(OCE_SOFTC)); 263231437Sluigi sc->dev = dev; 264231437Sluigi 265231437Sluigi vendor = pci_get_vendor(dev); 266231437Sluigi device = pci_get_device(dev); 267231437Sluigi 268231879Sluigi for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) { 269231437Sluigi if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) { 270231437Sluigi if (device == (supportedDevices[i] & 0xffff)) { 271231879Sluigi sprintf(str, "%s:%s", "Emulex CNA NIC function", 272231437Sluigi component_revision); 273231437Sluigi device_set_desc_copy(dev, str); 274231437Sluigi 275231437Sluigi switch (device) { 276231437Sluigi case PCI_PRODUCT_BE2: 277231437Sluigi sc->flags |= OCE_FLAGS_BE2; 278231437Sluigi break; 279231437Sluigi case PCI_PRODUCT_BE3: 280231437Sluigi sc->flags |= OCE_FLAGS_BE3; 281231437Sluigi break; 282231437Sluigi case PCI_PRODUCT_XE201: 283231437Sluigi case PCI_PRODUCT_XE201_VF: 284231437Sluigi sc->flags |= OCE_FLAGS_XE201; 285231437Sluigi break; 286252869Sdelphij case PCI_PRODUCT_SH: 287252869Sdelphij sc->flags |= OCE_FLAGS_SH; 288252869Sdelphij break; 289231437Sluigi default: 290231437Sluigi return ENXIO; 291231437Sluigi } 292231437Sluigi return BUS_PROBE_DEFAULT; 293231437Sluigi } 294231437Sluigi } 295231437Sluigi } 296231437Sluigi 297231437Sluigi return ENXIO; 298231437Sluigi} 299231437Sluigi 300231437Sluigi 301231437Sluigistatic int 302231437Sluigioce_attach(device_t dev) 303231437Sluigi{ 304231437Sluigi POCE_SOFTC sc; 305231437Sluigi int rc = 0; 306231437Sluigi 307231437Sluigi sc = device_get_softc(dev); 308231437Sluigi 309231437Sluigi rc = oce_hw_pci_alloc(sc); 310231437Sluigi if (rc) 311231437Sluigi return rc; 312231437Sluigi 313231437Sluigi sc->tx_ring_size = OCE_TX_RING_SIZE; 314231437Sluigi sc->rx_ring_size = OCE_RX_RING_SIZE; 315338938Sjpaetzel /* receive fragment size should be multiple of 2K */ 316338938Sjpaetzel sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048); 317231437Sluigi sc->flow_control = OCE_DEFAULT_FLOW_CONTROL; 318231437Sluigi sc->promisc = OCE_DEFAULT_PROMISCUOUS; 319231437Sluigi 320231437Sluigi LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock"); 321231437Sluigi LOCK_CREATE(&sc->dev_lock, "Device_lock"); 322231437Sluigi 323231437Sluigi /* initialise the hardware */ 324231437Sluigi rc = oce_hw_init(sc); 325231437Sluigi if (rc) 326231437Sluigi goto pci_res_free; 327231437Sluigi 328338938Sjpaetzel oce_read_env_variables(sc); 329338938Sjpaetzel 330252869Sdelphij oce_get_config(sc); 331252869Sdelphij 332231437Sluigi setup_max_queues_want(sc); 333231437Sluigi 334231437Sluigi rc = oce_setup_intr(sc); 335231437Sluigi if (rc) 336231437Sluigi goto mbox_free; 337231437Sluigi 338231437Sluigi rc = oce_queue_init_all(sc); 339231437Sluigi if (rc) 340231437Sluigi goto intr_free; 341231437Sluigi 342231437Sluigi rc = oce_attach_ifp(sc); 343231437Sluigi if (rc) 344231437Sluigi goto queues_free; 345231437Sluigi 346231511Sbz#if defined(INET6) || defined(INET) 347231437Sluigi rc = oce_init_lro(sc); 348231437Sluigi if (rc) 349231879Sluigi goto ifp_free; 350231511Sbz#endif 351231437Sluigi 352231437Sluigi rc = oce_hw_start(sc); 353231437Sluigi if (rc) 354241844Seadler goto lro_free; 355231437Sluigi 356231437Sluigi sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 357231437Sluigi oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST); 358231437Sluigi sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 359231437Sluigi oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST); 360231437Sluigi 361231437Sluigi rc = oce_stats_init(sc); 362231437Sluigi if (rc) 363231437Sluigi goto vlan_free; 364231437Sluigi 365231437Sluigi oce_add_sysctls(sc); 366231437Sluigi 367338938Sjpaetzel callout_init(&sc->timer, CALLOUT_MPSAFE); 368231437Sluigi rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc); 369231437Sluigi if (rc) 370231437Sluigi goto stats_free; 371231437Sluigi 372338938Sjpaetzel sc->next =NULL; 373338938Sjpaetzel if (softc_tail != NULL) { 374338938Sjpaetzel softc_tail->next = sc; 375338938Sjpaetzel } else { 376338938Sjpaetzel softc_head = sc; 377338938Sjpaetzel } 378338938Sjpaetzel softc_tail = sc; 379338938Sjpaetzel 380231437Sluigi return 0; 381231437Sluigi 382231437Sluigistats_free: 383231437Sluigi callout_drain(&sc->timer); 384231437Sluigi oce_stats_free(sc); 385231437Sluigivlan_free: 386231437Sluigi if (sc->vlan_attach) 387231437Sluigi EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 388231437Sluigi if (sc->vlan_detach) 389231437Sluigi EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 390231437Sluigi oce_hw_intr_disable(sc); 391231437Sluigilro_free: 392231511Sbz#if defined(INET6) || defined(INET) 393231437Sluigi oce_free_lro(sc); 394231437Sluigiifp_free: 395231511Sbz#endif 396231437Sluigi ether_ifdetach(sc->ifp); 397231437Sluigi if_free(sc->ifp); 398231437Sluigiqueues_free: 399231437Sluigi oce_queue_release_all(sc); 400231437Sluigiintr_free: 401231437Sluigi oce_intr_free(sc); 402231437Sluigimbox_free: 403231437Sluigi oce_dma_free(sc, &sc->bsmbx); 404231437Sluigipci_res_free: 405231437Sluigi oce_hw_pci_free(sc); 406231437Sluigi LOCK_DESTROY(&sc->dev_lock); 407231437Sluigi LOCK_DESTROY(&sc->bmbx_lock); 408231437Sluigi return rc; 409231437Sluigi 410231437Sluigi} 411231437Sluigi 412231437Sluigi 413231437Sluigistatic int 414231437Sluigioce_detach(device_t dev) 415231437Sluigi{ 416231437Sluigi POCE_SOFTC sc = device_get_softc(dev); 417338938Sjpaetzel POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL; 418231437Sluigi 419338938Sjpaetzel poce_sc_tmp = softc_head; 420338938Sjpaetzel ppoce_sc_tmp1 = &softc_head; 421338938Sjpaetzel while (poce_sc_tmp != NULL) { 422338938Sjpaetzel if (poce_sc_tmp == sc) { 423338938Sjpaetzel *ppoce_sc_tmp1 = sc->next; 424338938Sjpaetzel if (sc->next == NULL) { 425338938Sjpaetzel softc_tail = poce_sc_tmp2; 426338938Sjpaetzel } 427338938Sjpaetzel break; 428338938Sjpaetzel } 429338938Sjpaetzel poce_sc_tmp2 = poce_sc_tmp; 430338938Sjpaetzel ppoce_sc_tmp1 = &poce_sc_tmp->next; 431338938Sjpaetzel poce_sc_tmp = poce_sc_tmp->next; 432338938Sjpaetzel } 433338938Sjpaetzel 434231437Sluigi LOCK(&sc->dev_lock); 435231437Sluigi oce_if_deactivate(sc); 436231437Sluigi UNLOCK(&sc->dev_lock); 437231437Sluigi 438231437Sluigi callout_drain(&sc->timer); 439231437Sluigi 440231437Sluigi if (sc->vlan_attach != NULL) 441231437Sluigi EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 442231437Sluigi if (sc->vlan_detach != NULL) 443231437Sluigi EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 444231437Sluigi 445231437Sluigi ether_ifdetach(sc->ifp); 446231437Sluigi 447231437Sluigi if_free(sc->ifp); 448231437Sluigi 449231437Sluigi oce_hw_shutdown(sc); 450231437Sluigi 451231437Sluigi bus_generic_detach(dev); 452231437Sluigi 453231437Sluigi return 0; 454231437Sluigi} 455231437Sluigi 456231437Sluigi 457231437Sluigistatic int 458231437Sluigioce_shutdown(device_t dev) 459231437Sluigi{ 460231437Sluigi int rc; 461231437Sluigi 462231437Sluigi rc = oce_detach(dev); 463231437Sluigi 464231437Sluigi return rc; 465231437Sluigi} 466231437Sluigi 467231437Sluigi 468231437Sluigistatic int 469231437Sluigioce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 470231437Sluigi{ 471231437Sluigi struct ifreq *ifr = (struct ifreq *)data; 472231437Sluigi POCE_SOFTC sc = ifp->if_softc; 473343300Sdelphij struct ifi2creq i2c; 474343300Sdelphij uint8_t offset = 0; 475231437Sluigi int rc = 0; 476231437Sluigi uint32_t u; 477231437Sluigi 478231437Sluigi switch (command) { 479231437Sluigi 480231437Sluigi case SIOCGIFMEDIA: 481231437Sluigi rc = ifmedia_ioctl(ifp, ifr, &sc->media, command); 482231437Sluigi break; 483231437Sluigi 484231437Sluigi case SIOCSIFMTU: 485231437Sluigi if (ifr->ifr_mtu > OCE_MAX_MTU) 486231437Sluigi rc = EINVAL; 487231437Sluigi else 488231437Sluigi ifp->if_mtu = ifr->ifr_mtu; 489231437Sluigi break; 490231437Sluigi 491231437Sluigi case SIOCSIFFLAGS: 492231437Sluigi if (ifp->if_flags & IFF_UP) { 493231437Sluigi if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 494231437Sluigi sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 495231437Sluigi oce_init(sc); 496231437Sluigi } 497231437Sluigi device_printf(sc->dev, "Interface Up\n"); 498231437Sluigi } else { 499231437Sluigi LOCK(&sc->dev_lock); 500231437Sluigi 501231437Sluigi sc->ifp->if_drv_flags &= 502231437Sluigi ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 503231437Sluigi oce_if_deactivate(sc); 504231437Sluigi 505231437Sluigi UNLOCK(&sc->dev_lock); 506231437Sluigi 507231437Sluigi device_printf(sc->dev, "Interface Down\n"); 508231437Sluigi } 509231437Sluigi 510231437Sluigi if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) { 511257007Sdelphij if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1)))) 512257007Sdelphij sc->promisc = TRUE; 513231437Sluigi } else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) { 514257007Sdelphij if (!oce_rxf_set_promiscuous(sc, 0)) 515257007Sdelphij sc->promisc = FALSE; 516231437Sluigi } 517231437Sluigi 518231437Sluigi break; 519231437Sluigi 520231437Sluigi case SIOCADDMULTI: 521231437Sluigi case SIOCDELMULTI: 522231437Sluigi rc = oce_hw_update_multicast(sc); 523231437Sluigi if (rc) 524231437Sluigi device_printf(sc->dev, 525231437Sluigi "Update multicast address failed\n"); 526231437Sluigi break; 527231437Sluigi 528231437Sluigi case SIOCSIFCAP: 529231437Sluigi u = ifr->ifr_reqcap ^ ifp->if_capenable; 530231437Sluigi 531231437Sluigi if (u & IFCAP_TXCSUM) { 532231437Sluigi ifp->if_capenable ^= IFCAP_TXCSUM; 533231437Sluigi ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 534231437Sluigi 535231437Sluigi if (IFCAP_TSO & ifp->if_capenable && 536231437Sluigi !(IFCAP_TXCSUM & ifp->if_capenable)) { 537362511Sfreqlabs u &= ~IFCAP_TSO; 538231437Sluigi ifp->if_capenable &= ~IFCAP_TSO; 539231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 540231437Sluigi if_printf(ifp, 541231437Sluigi "TSO disabled due to -txcsum.\n"); 542231437Sluigi } 543231437Sluigi } 544231437Sluigi 545231437Sluigi if (u & IFCAP_RXCSUM) 546231437Sluigi ifp->if_capenable ^= IFCAP_RXCSUM; 547231437Sluigi 548231437Sluigi if (u & IFCAP_TSO4) { 549231437Sluigi ifp->if_capenable ^= IFCAP_TSO4; 550231437Sluigi 551231437Sluigi if (IFCAP_TSO & ifp->if_capenable) { 552231437Sluigi if (IFCAP_TXCSUM & ifp->if_capenable) 553231437Sluigi ifp->if_hwassist |= CSUM_TSO; 554231437Sluigi else { 555231437Sluigi ifp->if_capenable &= ~IFCAP_TSO; 556231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 557231437Sluigi if_printf(ifp, 558231437Sluigi "Enable txcsum first.\n"); 559231437Sluigi rc = EAGAIN; 560231437Sluigi } 561231437Sluigi } else 562231437Sluigi ifp->if_hwassist &= ~CSUM_TSO; 563231437Sluigi } 564231437Sluigi 565231437Sluigi if (u & IFCAP_VLAN_HWTAGGING) 566231437Sluigi ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 567231437Sluigi 568231437Sluigi if (u & IFCAP_VLAN_HWFILTER) { 569231437Sluigi ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 570231437Sluigi oce_vid_config(sc); 571231437Sluigi } 572231511Sbz#if defined(INET6) || defined(INET) 573338938Sjpaetzel if (u & IFCAP_LRO) { 574231437Sluigi ifp->if_capenable ^= IFCAP_LRO; 575338938Sjpaetzel if(sc->enable_hwlro) { 576338938Sjpaetzel if(ifp->if_capenable & IFCAP_LRO) { 577338938Sjpaetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 1); 578338938Sjpaetzel }else { 579338938Sjpaetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 0); 580338938Sjpaetzel } 581338938Sjpaetzel } 582338938Sjpaetzel } 583231511Sbz#endif 584231437Sluigi 585231437Sluigi break; 586231437Sluigi 587343300Sdelphij case SIOCGI2C: 588343300Sdelphij rc = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c)); 589343300Sdelphij if (rc) 590343300Sdelphij break; 591343300Sdelphij 592343300Sdelphij if (i2c.dev_addr != PAGE_NUM_A0 && 593343300Sdelphij i2c.dev_addr != PAGE_NUM_A2) { 594343300Sdelphij rc = EINVAL; 595343300Sdelphij break; 596343300Sdelphij } 597343300Sdelphij 598343300Sdelphij if (i2c.len > sizeof(i2c.data)) { 599343300Sdelphij rc = EINVAL; 600343300Sdelphij break; 601343300Sdelphij } 602343300Sdelphij 603343300Sdelphij rc = oce_mbox_read_transrecv_data(sc, i2c.dev_addr); 604343300Sdelphij if(rc) { 605343300Sdelphij rc = -rc; 606343300Sdelphij break; 607343300Sdelphij } 608343300Sdelphij 609343300Sdelphij if (i2c.dev_addr == PAGE_NUM_A0) 610343300Sdelphij offset = i2c.offset; 611343300Sdelphij else 612343300Sdelphij offset = TRANSCEIVER_A0_SIZE + i2c.offset; 613343300Sdelphij 614343300Sdelphij memcpy(&i2c.data[0], &sfp_vpd_dump_buffer[offset], i2c.len); 615343300Sdelphij 616343300Sdelphij rc = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c)); 617343300Sdelphij break; 618343300Sdelphij 619231437Sluigi case SIOCGPRIVATE_0: 620356090Smarkj rc = priv_check(curthread, PRIV_DRIVER); 621356090Smarkj if (rc != 0) 622356090Smarkj break; 623231437Sluigi rc = oce_handle_passthrough(ifp, data); 624231437Sluigi break; 625231437Sluigi default: 626231437Sluigi rc = ether_ioctl(ifp, command, data); 627231437Sluigi break; 628231437Sluigi } 629231437Sluigi 630231437Sluigi return rc; 631231437Sluigi} 632231437Sluigi 633231437Sluigi 634231437Sluigistatic void 635231437Sluigioce_init(void *arg) 636231437Sluigi{ 637231437Sluigi POCE_SOFTC sc = arg; 638231437Sluigi 639231437Sluigi LOCK(&sc->dev_lock); 640231437Sluigi 641231437Sluigi if (sc->ifp->if_flags & IFF_UP) { 642231437Sluigi oce_if_deactivate(sc); 643231437Sluigi oce_if_activate(sc); 644231437Sluigi } 645231437Sluigi 646231437Sluigi UNLOCK(&sc->dev_lock); 647231437Sluigi 648231437Sluigi} 649231437Sluigi 650231437Sluigi 651231437Sluigistatic int 652231437Sluigioce_multiq_start(struct ifnet *ifp, struct mbuf *m) 653231437Sluigi{ 654231437Sluigi POCE_SOFTC sc = ifp->if_softc; 655231437Sluigi struct oce_wq *wq = NULL; 656231437Sluigi int queue_index = 0; 657231437Sluigi int status = 0; 658247880Sdelphij 659338938Sjpaetzel if (!sc->link_status) 660338938Sjpaetzel return ENXIO; 661338938Sjpaetzel 662275358Shselasky if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 663231437Sluigi queue_index = m->m_pkthdr.flowid % sc->nwqs; 664252869Sdelphij 665231437Sluigi wq = sc->wq[queue_index]; 666231437Sluigi 667252869Sdelphij LOCK(&wq->tx_lock); 668252869Sdelphij status = oce_multiq_transmit(ifp, m, wq); 669252869Sdelphij UNLOCK(&wq->tx_lock); 670252869Sdelphij 671231437Sluigi return status; 672231437Sluigi 673231437Sluigi} 674231437Sluigi 675231437Sluigi 676231437Sluigistatic void 677231437Sluigioce_multiq_flush(struct ifnet *ifp) 678231437Sluigi{ 679231437Sluigi POCE_SOFTC sc = ifp->if_softc; 680231437Sluigi struct mbuf *m; 681231437Sluigi int i = 0; 682231437Sluigi 683231437Sluigi for (i = 0; i < sc->nwqs; i++) { 684231437Sluigi while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) 685231437Sluigi m_freem(m); 686231437Sluigi } 687231437Sluigi if_qflush(ifp); 688231437Sluigi} 689231437Sluigi 690231437Sluigi 691231437Sluigi 692231437Sluigi/***************************************************************************** 693231437Sluigi * Driver interrupt routines functions * 694231437Sluigi *****************************************************************************/ 695231437Sluigi 696231437Sluigistatic void 697231437Sluigioce_intr(void *arg, int pending) 698231437Sluigi{ 699231437Sluigi 700231437Sluigi POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 701231437Sluigi POCE_SOFTC sc = ii->sc; 702231437Sluigi struct oce_eq *eq = ii->eq; 703231437Sluigi struct oce_eqe *eqe; 704231437Sluigi struct oce_cq *cq = NULL; 705231437Sluigi int i, num_eqes = 0; 706231437Sluigi 707231437Sluigi 708231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 709231437Sluigi BUS_DMASYNC_POSTWRITE); 710231437Sluigi do { 711231437Sluigi eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 712231437Sluigi if (eqe->evnt == 0) 713231437Sluigi break; 714231437Sluigi eqe->evnt = 0; 715231437Sluigi bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 716231437Sluigi BUS_DMASYNC_POSTWRITE); 717231437Sluigi RING_GET(eq->ring, 1); 718231437Sluigi num_eqes++; 719231437Sluigi 720231437Sluigi } while (TRUE); 721231437Sluigi 722231437Sluigi if (!num_eqes) 723231437Sluigi goto eq_arm; /* Spurious */ 724231437Sluigi 725231437Sluigi /* Clear EQ entries, but dont arm */ 726231437Sluigi oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE); 727231437Sluigi 728231437Sluigi /* Process TX, RX and MCC. But dont arm CQ*/ 729231437Sluigi for (i = 0; i < eq->cq_valid; i++) { 730231437Sluigi cq = eq->cq[i]; 731231437Sluigi (*cq->cq_handler)(cq->cb_arg); 732231437Sluigi } 733231437Sluigi 734231437Sluigi /* Arm all cqs connected to this EQ */ 735231437Sluigi for (i = 0; i < eq->cq_valid; i++) { 736231437Sluigi cq = eq->cq[i]; 737231437Sluigi oce_arm_cq(sc, cq->cq_id, 0, TRUE); 738231437Sluigi } 739231437Sluigi 740231437Sluigieq_arm: 741231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 742247880Sdelphij 743231437Sluigi return; 744231437Sluigi} 745231437Sluigi 746231437Sluigi 747231437Sluigistatic int 748231437Sluigioce_setup_intr(POCE_SOFTC sc) 749231437Sluigi{ 750231437Sluigi int rc = 0, use_intx = 0; 751231437Sluigi int vector = 0, req_vectors = 0; 752338938Sjpaetzel int tot_req_vectors, tot_vectors; 753231437Sluigi 754252869Sdelphij if (is_rss_enabled(sc)) 755231437Sluigi req_vectors = MAX((sc->nrqs - 1), sc->nwqs); 756231437Sluigi else 757231437Sluigi req_vectors = 1; 758231437Sluigi 759338938Sjpaetzel tot_req_vectors = req_vectors; 760338938Sjpaetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 761338938Sjpaetzel if (req_vectors > 1) { 762338938Sjpaetzel tot_req_vectors += OCE_RDMA_VECTORS; 763338938Sjpaetzel sc->roce_intr_count = OCE_RDMA_VECTORS; 764338938Sjpaetzel } 765338938Sjpaetzel } 766338938Sjpaetzel 767338938Sjpaetzel if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) { 768231437Sluigi sc->intr_count = req_vectors; 769338938Sjpaetzel tot_vectors = tot_req_vectors; 770338938Sjpaetzel rc = pci_alloc_msix(sc->dev, &tot_vectors); 771231437Sluigi if (rc != 0) { 772231437Sluigi use_intx = 1; 773231437Sluigi pci_release_msi(sc->dev); 774338938Sjpaetzel } else { 775338938Sjpaetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 776338938Sjpaetzel if (tot_vectors < tot_req_vectors) { 777338938Sjpaetzel if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) { 778338938Sjpaetzel sc->roce_intr_count = (tot_vectors / 2); 779338938Sjpaetzel } 780338938Sjpaetzel sc->intr_count = tot_vectors - sc->roce_intr_count; 781338938Sjpaetzel } 782338938Sjpaetzel } else { 783338938Sjpaetzel sc->intr_count = tot_vectors; 784338938Sjpaetzel } 785338938Sjpaetzel sc->flags |= OCE_FLAGS_USING_MSIX; 786338938Sjpaetzel } 787231437Sluigi } else 788231437Sluigi use_intx = 1; 789231437Sluigi 790231437Sluigi if (use_intx) 791231437Sluigi sc->intr_count = 1; 792231437Sluigi 793231437Sluigi /* Scale number of queues based on intr we got */ 794231437Sluigi update_queues_got(sc); 795231437Sluigi 796231437Sluigi if (use_intx) { 797231437Sluigi device_printf(sc->dev, "Using legacy interrupt\n"); 798231437Sluigi rc = oce_alloc_intr(sc, vector, oce_intr); 799231437Sluigi if (rc) 800231437Sluigi goto error; 801231437Sluigi } else { 802231437Sluigi for (; vector < sc->intr_count; vector++) { 803231437Sluigi rc = oce_alloc_intr(sc, vector, oce_intr); 804231437Sluigi if (rc) 805231437Sluigi goto error; 806231437Sluigi } 807231437Sluigi } 808231437Sluigi 809231437Sluigi return 0; 810231437Sluigierror: 811231437Sluigi oce_intr_free(sc); 812231437Sluigi return rc; 813231437Sluigi} 814231437Sluigi 815231437Sluigi 816231437Sluigistatic int 817231437Sluigioce_fast_isr(void *arg) 818231437Sluigi{ 819231437Sluigi POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 820231437Sluigi POCE_SOFTC sc = ii->sc; 821231437Sluigi 822231437Sluigi if (ii->eq == NULL) 823231437Sluigi return FILTER_STRAY; 824231437Sluigi 825231437Sluigi oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE); 826231437Sluigi 827296272Sjhb taskqueue_enqueue(ii->tq, &ii->task); 828231437Sluigi 829247880Sdelphij ii->eq->intr++; 830247880Sdelphij 831231437Sluigi return FILTER_HANDLED; 832231437Sluigi} 833231437Sluigi 834231437Sluigi 835231437Sluigistatic int 836231437Sluigioce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) 837231437Sluigi{ 838351143Skevans POCE_INTR_INFO ii; 839231437Sluigi int rc = 0, rr; 840231437Sluigi 841231437Sluigi if (vector >= OCE_MAX_EQ) 842231437Sluigi return (EINVAL); 843231437Sluigi 844351143Skevans ii = &sc->intrs[vector]; 845351143Skevans 846231437Sluigi /* Set the resource id for the interrupt. 847231437Sluigi * MSIx is vector + 1 for the resource id, 848231437Sluigi * INTx is 0 for the resource id. 849231437Sluigi */ 850231437Sluigi if (sc->flags & OCE_FLAGS_USING_MSIX) 851231437Sluigi rr = vector + 1; 852231437Sluigi else 853231437Sluigi rr = 0; 854231437Sluigi ii->intr_res = bus_alloc_resource_any(sc->dev, 855231437Sluigi SYS_RES_IRQ, 856231437Sluigi &rr, RF_ACTIVE|RF_SHAREABLE); 857231437Sluigi ii->irq_rr = rr; 858231437Sluigi if (ii->intr_res == NULL) { 859231437Sluigi device_printf(sc->dev, 860231437Sluigi "Could not allocate interrupt\n"); 861231437Sluigi rc = ENXIO; 862231437Sluigi return rc; 863231437Sluigi } 864231437Sluigi 865231437Sluigi TASK_INIT(&ii->task, 0, isr, ii); 866231437Sluigi ii->vector = vector; 867231437Sluigi sprintf(ii->task_name, "oce_task[%d]", ii->vector); 868231437Sluigi ii->tq = taskqueue_create_fast(ii->task_name, 869231437Sluigi M_NOWAIT, 870231437Sluigi taskqueue_thread_enqueue, 871231437Sluigi &ii->tq); 872231437Sluigi taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq", 873231437Sluigi device_get_nameunit(sc->dev)); 874231437Sluigi 875231437Sluigi ii->sc = sc; 876231437Sluigi rc = bus_setup_intr(sc->dev, 877231437Sluigi ii->intr_res, 878231437Sluigi INTR_TYPE_NET, 879231437Sluigi oce_fast_isr, NULL, ii, &ii->tag); 880231437Sluigi return rc; 881231437Sluigi 882231437Sluigi} 883231437Sluigi 884231437Sluigi 885231437Sluigivoid 886231437Sluigioce_intr_free(POCE_SOFTC sc) 887231437Sluigi{ 888231437Sluigi int i = 0; 889231437Sluigi 890231437Sluigi for (i = 0; i < sc->intr_count; i++) { 891231437Sluigi 892231437Sluigi if (sc->intrs[i].tag != NULL) 893231437Sluigi bus_teardown_intr(sc->dev, sc->intrs[i].intr_res, 894231437Sluigi sc->intrs[i].tag); 895231437Sluigi if (sc->intrs[i].tq != NULL) 896231437Sluigi taskqueue_free(sc->intrs[i].tq); 897231437Sluigi 898231437Sluigi if (sc->intrs[i].intr_res != NULL) 899231437Sluigi bus_release_resource(sc->dev, SYS_RES_IRQ, 900231437Sluigi sc->intrs[i].irq_rr, 901231437Sluigi sc->intrs[i].intr_res); 902231437Sluigi sc->intrs[i].tag = NULL; 903231437Sluigi sc->intrs[i].intr_res = NULL; 904231437Sluigi } 905231437Sluigi 906231437Sluigi if (sc->flags & OCE_FLAGS_USING_MSIX) 907231437Sluigi pci_release_msi(sc->dev); 908231437Sluigi 909231437Sluigi} 910231437Sluigi 911231437Sluigi 912231437Sluigi 913231437Sluigi/****************************************************************************** 914231437Sluigi* Media callbacks functions * 915231437Sluigi******************************************************************************/ 916231437Sluigi 917231437Sluigistatic void 918231437Sluigioce_media_status(struct ifnet *ifp, struct ifmediareq *req) 919231437Sluigi{ 920231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc; 921231437Sluigi 922231437Sluigi 923231437Sluigi req->ifm_status = IFM_AVALID; 924231437Sluigi req->ifm_active = IFM_ETHER; 925231437Sluigi 926231437Sluigi if (sc->link_status == 1) 927231437Sluigi req->ifm_status |= IFM_ACTIVE; 928231437Sluigi else 929231437Sluigi return; 930231437Sluigi 931231437Sluigi switch (sc->link_speed) { 932231437Sluigi case 1: /* 10 Mbps */ 933231437Sluigi req->ifm_active |= IFM_10_T | IFM_FDX; 934231437Sluigi sc->speed = 10; 935231437Sluigi break; 936231437Sluigi case 2: /* 100 Mbps */ 937231437Sluigi req->ifm_active |= IFM_100_TX | IFM_FDX; 938231437Sluigi sc->speed = 100; 939231437Sluigi break; 940231437Sluigi case 3: /* 1 Gbps */ 941231437Sluigi req->ifm_active |= IFM_1000_T | IFM_FDX; 942231437Sluigi sc->speed = 1000; 943231437Sluigi break; 944231437Sluigi case 4: /* 10 Gbps */ 945231437Sluigi req->ifm_active |= IFM_10G_SR | IFM_FDX; 946231437Sluigi sc->speed = 10000; 947231437Sluigi break; 948267839Sdelphij case 5: /* 20 Gbps */ 949267839Sdelphij req->ifm_active |= IFM_10G_SR | IFM_FDX; 950267839Sdelphij sc->speed = 20000; 951267839Sdelphij break; 952267839Sdelphij case 6: /* 25 Gbps */ 953267839Sdelphij req->ifm_active |= IFM_10G_SR | IFM_FDX; 954267839Sdelphij sc->speed = 25000; 955267839Sdelphij break; 956258941Sdelphij case 7: /* 40 Gbps */ 957258941Sdelphij req->ifm_active |= IFM_40G_SR4 | IFM_FDX; 958258941Sdelphij sc->speed = 40000; 959258941Sdelphij break; 960267839Sdelphij default: 961267839Sdelphij sc->speed = 0; 962267839Sdelphij break; 963231437Sluigi } 964231437Sluigi 965231437Sluigi return; 966231437Sluigi} 967231437Sluigi 968231437Sluigi 969231437Sluigiint 970231437Sluigioce_media_change(struct ifnet *ifp) 971231437Sluigi{ 972231437Sluigi return 0; 973231437Sluigi} 974231437Sluigi 975231437Sluigi 976338938Sjpaetzelstatic void oce_is_pkt_dest_bmc(POCE_SOFTC sc, 977338938Sjpaetzel struct mbuf *m, boolean_t *os2bmc, 978338938Sjpaetzel struct mbuf **m_new) 979338938Sjpaetzel{ 980338938Sjpaetzel struct ether_header *eh = NULL; 981231437Sluigi 982338938Sjpaetzel eh = mtod(m, struct ether_header *); 983231437Sluigi 984338938Sjpaetzel if (!is_os2bmc_enabled(sc) || *os2bmc) { 985338938Sjpaetzel *os2bmc = FALSE; 986338938Sjpaetzel goto done; 987338938Sjpaetzel } 988338938Sjpaetzel if (!ETHER_IS_MULTICAST(eh->ether_dhost)) 989338938Sjpaetzel goto done; 990338938Sjpaetzel 991338938Sjpaetzel if (is_mc_allowed_on_bmc(sc, eh) || 992338938Sjpaetzel is_bc_allowed_on_bmc(sc, eh) || 993338938Sjpaetzel is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) { 994338938Sjpaetzel *os2bmc = TRUE; 995338938Sjpaetzel goto done; 996338938Sjpaetzel } 997338938Sjpaetzel 998338938Sjpaetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) { 999338938Sjpaetzel struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1000338938Sjpaetzel uint8_t nexthdr = ip6->ip6_nxt; 1001338938Sjpaetzel if (nexthdr == IPPROTO_ICMPV6) { 1002338938Sjpaetzel struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1); 1003338938Sjpaetzel switch (icmp6->icmp6_type) { 1004338938Sjpaetzel case ND_ROUTER_ADVERT: 1005338938Sjpaetzel *os2bmc = is_ipv6_ra_filt_enabled(sc); 1006338938Sjpaetzel goto done; 1007338938Sjpaetzel case ND_NEIGHBOR_ADVERT: 1008338938Sjpaetzel *os2bmc = is_ipv6_na_filt_enabled(sc); 1009338938Sjpaetzel goto done; 1010338938Sjpaetzel default: 1011338938Sjpaetzel break; 1012338938Sjpaetzel } 1013338938Sjpaetzel } 1014338938Sjpaetzel } 1015338938Sjpaetzel 1016338938Sjpaetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) { 1017338938Sjpaetzel struct ip *ip = mtod(m, struct ip *); 1018338938Sjpaetzel int iphlen = ip->ip_hl << 2; 1019338938Sjpaetzel struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen); 1020338938Sjpaetzel switch (uh->uh_dport) { 1021338938Sjpaetzel case DHCP_CLIENT_PORT: 1022338938Sjpaetzel *os2bmc = is_dhcp_client_filt_enabled(sc); 1023338938Sjpaetzel goto done; 1024338938Sjpaetzel case DHCP_SERVER_PORT: 1025338938Sjpaetzel *os2bmc = is_dhcp_srvr_filt_enabled(sc); 1026338938Sjpaetzel goto done; 1027338938Sjpaetzel case NET_BIOS_PORT1: 1028338938Sjpaetzel case NET_BIOS_PORT2: 1029338938Sjpaetzel *os2bmc = is_nbios_filt_enabled(sc); 1030338938Sjpaetzel goto done; 1031338938Sjpaetzel case DHCPV6_RAS_PORT: 1032338938Sjpaetzel *os2bmc = is_ipv6_ras_filt_enabled(sc); 1033338938Sjpaetzel goto done; 1034338938Sjpaetzel default: 1035338938Sjpaetzel break; 1036338938Sjpaetzel } 1037338938Sjpaetzel } 1038338938Sjpaetzeldone: 1039338938Sjpaetzel if (*os2bmc) { 1040338938Sjpaetzel *m_new = m_dup(m, M_NOWAIT); 1041338938Sjpaetzel if (!*m_new) { 1042338938Sjpaetzel *os2bmc = FALSE; 1043338938Sjpaetzel return; 1044338938Sjpaetzel } 1045338938Sjpaetzel *m_new = oce_insert_vlan_tag(sc, *m_new, NULL); 1046338938Sjpaetzel } 1047338938Sjpaetzel} 1048338938Sjpaetzel 1049338938Sjpaetzel 1050338938Sjpaetzel 1051231437Sluigi/***************************************************************************** 1052231437Sluigi * Transmit routines functions * 1053231437Sluigi *****************************************************************************/ 1054231437Sluigi 1055231437Sluigistatic int 1056231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 1057231437Sluigi{ 1058231437Sluigi int rc = 0, i, retry_cnt = 0; 1059231437Sluigi bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 1060338938Sjpaetzel struct mbuf *m, *m_temp, *m_new = NULL; 1061231437Sluigi struct oce_wq *wq = sc->wq[wq_index]; 1062231437Sluigi struct oce_packet_desc *pd; 1063231437Sluigi struct oce_nic_hdr_wqe *nichdr; 1064231437Sluigi struct oce_nic_frag_wqe *nicfrag; 1065338938Sjpaetzel struct ether_header *eh = NULL; 1066231437Sluigi int num_wqes; 1067231437Sluigi uint32_t reg_value; 1068247880Sdelphij boolean_t complete = TRUE; 1069338938Sjpaetzel boolean_t os2bmc = FALSE; 1070231437Sluigi 1071231437Sluigi m = *mpp; 1072231437Sluigi if (!m) 1073231437Sluigi return EINVAL; 1074231437Sluigi 1075231437Sluigi if (!(m->m_flags & M_PKTHDR)) { 1076231437Sluigi rc = ENXIO; 1077231437Sluigi goto free_ret; 1078231437Sluigi } 1079231437Sluigi 1080338938Sjpaetzel /* Don't allow non-TSO packets longer than MTU */ 1081338938Sjpaetzel if (!is_tso_pkt(m)) { 1082338938Sjpaetzel eh = mtod(m, struct ether_header *); 1083338938Sjpaetzel if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE)) 1084338938Sjpaetzel goto free_ret; 1085338938Sjpaetzel } 1086338938Sjpaetzel 1087247880Sdelphij if(oce_tx_asic_stall_verify(sc, m)) { 1088247880Sdelphij m = oce_insert_vlan_tag(sc, m, &complete); 1089247880Sdelphij if(!m) { 1090247880Sdelphij device_printf(sc->dev, "Insertion unsuccessful\n"); 1091247880Sdelphij return 0; 1092247880Sdelphij } 1093247880Sdelphij 1094247880Sdelphij } 1095247880Sdelphij 1096338938Sjpaetzel /* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less 1097338938Sjpaetzel * may cause a transmit stall on that port. So the work-around is to 1098338938Sjpaetzel * pad short packets (<= 32 bytes) to a 36-byte length. 1099338938Sjpaetzel */ 1100338938Sjpaetzel if(IS_SH(sc) || IS_XE201(sc) ) { 1101338938Sjpaetzel if(m->m_pkthdr.len <= 32) { 1102338938Sjpaetzel char buf[36]; 1103338938Sjpaetzel bzero((void *)buf, 36); 1104338938Sjpaetzel m_append(m, (36 - m->m_pkthdr.len), buf); 1105338938Sjpaetzel } 1106338938Sjpaetzel } 1107338938Sjpaetzel 1108338938Sjpaetzeltx_start: 1109231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 1110231879Sluigi /* consolidate packet buffers for TSO/LSO segment offload */ 1111231511Sbz#if defined(INET6) || defined(INET) 1112231879Sluigi m = oce_tso_setup(sc, mpp); 1113231511Sbz#else 1114231511Sbz m = NULL; 1115231511Sbz#endif 1116231437Sluigi if (m == NULL) { 1117231437Sluigi rc = ENXIO; 1118231437Sluigi goto free_ret; 1119231437Sluigi } 1120231437Sluigi } 1121231437Sluigi 1122338938Sjpaetzel 1123252869Sdelphij pd = &wq->pckts[wq->pkt_desc_head]; 1124338938Sjpaetzel 1125231437Sluigiretry: 1126231437Sluigi rc = bus_dmamap_load_mbuf_sg(wq->tag, 1127231437Sluigi pd->map, 1128231437Sluigi m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 1129231437Sluigi if (rc == 0) { 1130231437Sluigi num_wqes = pd->nsegs + 1; 1131252869Sdelphij if (IS_BE(sc) || IS_SH(sc)) { 1132231437Sluigi /*Dummy required only for BE3.*/ 1133231437Sluigi if (num_wqes & 1) 1134231437Sluigi num_wqes++; 1135231437Sluigi } 1136231437Sluigi if (num_wqes >= RING_NUM_FREE(wq->ring)) { 1137231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 1138231437Sluigi return EBUSY; 1139231437Sluigi } 1140252869Sdelphij atomic_store_rel_int(&wq->pkt_desc_head, 1141252869Sdelphij (wq->pkt_desc_head + 1) % \ 1142252869Sdelphij OCE_WQ_PACKET_ARRAY_SIZE); 1143231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 1144231437Sluigi pd->mbuf = m; 1145231437Sluigi 1146231437Sluigi nichdr = 1147231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 1148231437Sluigi nichdr->u0.dw[0] = 0; 1149231437Sluigi nichdr->u0.dw[1] = 0; 1150231437Sluigi nichdr->u0.dw[2] = 0; 1151231437Sluigi nichdr->u0.dw[3] = 0; 1152231437Sluigi 1153247880Sdelphij nichdr->u0.s.complete = complete; 1154338938Sjpaetzel nichdr->u0.s.mgmt = os2bmc; 1155231437Sluigi nichdr->u0.s.event = 1; 1156231437Sluigi nichdr->u0.s.crc = 1; 1157231437Sluigi nichdr->u0.s.forward = 0; 1158231437Sluigi nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 1159231437Sluigi nichdr->u0.s.udpcs = 1160247880Sdelphij (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 1161231437Sluigi nichdr->u0.s.tcpcs = 1162247880Sdelphij (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 1163231437Sluigi nichdr->u0.s.num_wqe = num_wqes; 1164231437Sluigi nichdr->u0.s.total_length = m->m_pkthdr.len; 1165257007Sdelphij 1166231437Sluigi if (m->m_flags & M_VLANTAG) { 1167231437Sluigi nichdr->u0.s.vlan = 1; /*Vlan present*/ 1168231437Sluigi nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 1169231437Sluigi } 1170257007Sdelphij 1171231437Sluigi if (m->m_pkthdr.csum_flags & CSUM_TSO) { 1172231437Sluigi if (m->m_pkthdr.tso_segsz) { 1173231437Sluigi nichdr->u0.s.lso = 1; 1174231437Sluigi nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 1175231437Sluigi } 1176252869Sdelphij if (!IS_BE(sc) || !IS_SH(sc)) 1177231437Sluigi nichdr->u0.s.ipcs = 1; 1178231437Sluigi } 1179231437Sluigi 1180231437Sluigi RING_PUT(wq->ring, 1); 1181252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 1182231437Sluigi 1183231437Sluigi for (i = 0; i < pd->nsegs; i++) { 1184231437Sluigi nicfrag = 1185231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 1186231437Sluigi struct oce_nic_frag_wqe); 1187231437Sluigi nicfrag->u0.s.rsvd0 = 0; 1188231437Sluigi nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 1189231437Sluigi nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 1190231437Sluigi nicfrag->u0.s.frag_len = segs[i].ds_len; 1191231437Sluigi pd->wqe_idx = wq->ring->pidx; 1192231437Sluigi RING_PUT(wq->ring, 1); 1193252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 1194231437Sluigi } 1195231437Sluigi if (num_wqes > (pd->nsegs + 1)) { 1196231437Sluigi nicfrag = 1197231437Sluigi RING_GET_PRODUCER_ITEM_VA(wq->ring, 1198231437Sluigi struct oce_nic_frag_wqe); 1199231437Sluigi nicfrag->u0.dw[0] = 0; 1200231437Sluigi nicfrag->u0.dw[1] = 0; 1201231437Sluigi nicfrag->u0.dw[2] = 0; 1202231437Sluigi nicfrag->u0.dw[3] = 0; 1203231437Sluigi pd->wqe_idx = wq->ring->pidx; 1204231437Sluigi RING_PUT(wq->ring, 1); 1205252869Sdelphij atomic_add_int(&wq->ring->num_used, 1); 1206231437Sluigi pd->nsegs++; 1207231437Sluigi } 1208231437Sluigi 1209271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1); 1210231437Sluigi wq->tx_stats.tx_reqs++; 1211231437Sluigi wq->tx_stats.tx_wrbs += num_wqes; 1212231437Sluigi wq->tx_stats.tx_bytes += m->m_pkthdr.len; 1213231437Sluigi wq->tx_stats.tx_pkts++; 1214247880Sdelphij 1215231437Sluigi bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 1216231437Sluigi BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1217231437Sluigi reg_value = (num_wqes << 16) | wq->wq_id; 1218338938Sjpaetzel 1219338938Sjpaetzel /* if os2bmc is not enabled or if the pkt is already tagged as 1220338938Sjpaetzel bmc, do nothing 1221338938Sjpaetzel */ 1222338938Sjpaetzel oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new); 1223338938Sjpaetzel 1224252869Sdelphij OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value); 1225231437Sluigi 1226231437Sluigi } else if (rc == EFBIG) { 1227231437Sluigi if (retry_cnt == 0) { 1228243857Sglebius m_temp = m_defrag(m, M_NOWAIT); 1229231437Sluigi if (m_temp == NULL) 1230231437Sluigi goto free_ret; 1231231437Sluigi m = m_temp; 1232231437Sluigi *mpp = m_temp; 1233231437Sluigi retry_cnt = retry_cnt + 1; 1234231437Sluigi goto retry; 1235231437Sluigi } else 1236231437Sluigi goto free_ret; 1237231437Sluigi } else if (rc == ENOMEM) 1238231437Sluigi return rc; 1239231437Sluigi else 1240231437Sluigi goto free_ret; 1241338938Sjpaetzel 1242338938Sjpaetzel if (os2bmc) { 1243338938Sjpaetzel m = m_new; 1244338938Sjpaetzel goto tx_start; 1245338938Sjpaetzel } 1246252869Sdelphij 1247231437Sluigi return 0; 1248231437Sluigi 1249231437Sluigifree_ret: 1250231437Sluigi m_freem(*mpp); 1251231437Sluigi *mpp = NULL; 1252231437Sluigi return rc; 1253231437Sluigi} 1254231437Sluigi 1255231437Sluigi 1256231437Sluigistatic void 1257338938Sjpaetzeloce_process_tx_completion(struct oce_wq *wq) 1258231437Sluigi{ 1259231437Sluigi struct oce_packet_desc *pd; 1260231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 1261231437Sluigi struct mbuf *m; 1262231437Sluigi 1263252869Sdelphij pd = &wq->pckts[wq->pkt_desc_tail]; 1264252869Sdelphij atomic_store_rel_int(&wq->pkt_desc_tail, 1265252869Sdelphij (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE); 1266252869Sdelphij atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1); 1267231437Sluigi bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1268231437Sluigi bus_dmamap_unload(wq->tag, pd->map); 1269231437Sluigi 1270231437Sluigi m = pd->mbuf; 1271231437Sluigi m_freem(m); 1272231437Sluigi pd->mbuf = NULL; 1273231437Sluigi 1274252869Sdelphij 1275231437Sluigi if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 1276231437Sluigi if (wq->ring->num_used < (wq->ring->num_items / 2)) { 1277231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 1278231437Sluigi oce_tx_restart(sc, wq); 1279231437Sluigi } 1280231437Sluigi } 1281231437Sluigi} 1282231437Sluigi 1283231437Sluigi 1284231437Sluigistatic void 1285231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 1286231437Sluigi{ 1287231437Sluigi 1288231437Sluigi if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 1289231437Sluigi return; 1290231437Sluigi 1291231437Sluigi#if __FreeBSD_version >= 800000 1292231437Sluigi if (!drbr_empty(sc->ifp, wq->br)) 1293231437Sluigi#else 1294231437Sluigi if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 1295231437Sluigi#endif 1296296272Sjhb taskqueue_enqueue(taskqueue_swi, &wq->txtask); 1297231437Sluigi 1298231437Sluigi} 1299231437Sluigi 1300231879Sluigi 1301231511Sbz#if defined(INET6) || defined(INET) 1302231437Sluigistatic struct mbuf * 1303231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp) 1304231437Sluigi{ 1305231437Sluigi struct mbuf *m; 1306231511Sbz#ifdef INET 1307231437Sluigi struct ip *ip; 1308231511Sbz#endif 1309231511Sbz#ifdef INET6 1310231437Sluigi struct ip6_hdr *ip6; 1311231511Sbz#endif 1312231437Sluigi struct ether_vlan_header *eh; 1313231437Sluigi struct tcphdr *th; 1314231437Sluigi uint16_t etype; 1315231879Sluigi int total_len = 0, ehdrlen = 0; 1316231437Sluigi 1317231437Sluigi m = *mpp; 1318231437Sluigi 1319231437Sluigi if (M_WRITABLE(m) == 0) { 1320243857Sglebius m = m_dup(*mpp, M_NOWAIT); 1321231437Sluigi if (!m) 1322231437Sluigi return NULL; 1323231437Sluigi m_freem(*mpp); 1324231437Sluigi *mpp = m; 1325231437Sluigi } 1326231437Sluigi 1327231437Sluigi eh = mtod(m, struct ether_vlan_header *); 1328231437Sluigi if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 1329231437Sluigi etype = ntohs(eh->evl_proto); 1330231437Sluigi ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 1331231437Sluigi } else { 1332231437Sluigi etype = ntohs(eh->evl_encap_proto); 1333231437Sluigi ehdrlen = ETHER_HDR_LEN; 1334231437Sluigi } 1335231437Sluigi 1336231437Sluigi switch (etype) { 1337231511Sbz#ifdef INET 1338231437Sluigi case ETHERTYPE_IP: 1339231437Sluigi ip = (struct ip *)(m->m_data + ehdrlen); 1340231437Sluigi if (ip->ip_p != IPPROTO_TCP) 1341231437Sluigi return NULL; 1342231437Sluigi th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 1343231437Sluigi 1344231437Sluigi total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 1345231437Sluigi break; 1346231511Sbz#endif 1347231511Sbz#ifdef INET6 1348231437Sluigi case ETHERTYPE_IPV6: 1349231437Sluigi ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 1350231437Sluigi if (ip6->ip6_nxt != IPPROTO_TCP) 1351231437Sluigi return NULL; 1352231437Sluigi th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 1353231437Sluigi 1354231437Sluigi total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 1355231437Sluigi break; 1356231511Sbz#endif 1357231437Sluigi default: 1358231437Sluigi return NULL; 1359231437Sluigi } 1360231437Sluigi 1361231437Sluigi m = m_pullup(m, total_len); 1362231437Sluigi if (!m) 1363231437Sluigi return NULL; 1364231437Sluigi *mpp = m; 1365231437Sluigi return m; 1366231437Sluigi 1367231437Sluigi} 1368231511Sbz#endif /* INET6 || INET */ 1369231437Sluigi 1370231437Sluigivoid 1371231437Sluigioce_tx_task(void *arg, int npending) 1372231437Sluigi{ 1373231437Sluigi struct oce_wq *wq = arg; 1374231437Sluigi POCE_SOFTC sc = wq->parent; 1375231437Sluigi struct ifnet *ifp = sc->ifp; 1376231437Sluigi int rc = 0; 1377252869Sdelphij 1378231437Sluigi#if __FreeBSD_version >= 800000 1379252869Sdelphij LOCK(&wq->tx_lock); 1380252869Sdelphij rc = oce_multiq_transmit(ifp, NULL, wq); 1381252869Sdelphij if (rc) { 1382252869Sdelphij device_printf(sc->dev, 1383252869Sdelphij "TX[%d] restart failed\n", wq->queue_index); 1384231437Sluigi } 1385252869Sdelphij UNLOCK(&wq->tx_lock); 1386231437Sluigi#else 1387231437Sluigi oce_start(ifp); 1388231437Sluigi#endif 1389231437Sluigi 1390231437Sluigi} 1391231437Sluigi 1392231437Sluigi 1393231437Sluigivoid 1394231437Sluigioce_start(struct ifnet *ifp) 1395231437Sluigi{ 1396231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1397231437Sluigi struct mbuf *m; 1398231437Sluigi int rc = 0; 1399231879Sluigi int def_q = 0; /* Defualt tx queue is 0*/ 1400231437Sluigi 1401231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1402231437Sluigi IFF_DRV_RUNNING) 1403231437Sluigi return; 1404247880Sdelphij 1405247880Sdelphij if (!sc->link_status) 1406247880Sdelphij return; 1407231437Sluigi 1408231437Sluigi do { 1409231437Sluigi IF_DEQUEUE(&sc->ifp->if_snd, m); 1410231437Sluigi if (m == NULL) 1411231437Sluigi break; 1412231879Sluigi 1413231879Sluigi LOCK(&sc->wq[def_q]->tx_lock); 1414231879Sluigi rc = oce_tx(sc, &m, def_q); 1415231879Sluigi UNLOCK(&sc->wq[def_q]->tx_lock); 1416231437Sluigi if (rc) { 1417231437Sluigi if (m != NULL) { 1418231879Sluigi sc->wq[def_q]->tx_stats.tx_stops ++; 1419231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1420231437Sluigi IFQ_DRV_PREPEND(&ifp->if_snd, m); 1421231437Sluigi m = NULL; 1422231437Sluigi } 1423231437Sluigi break; 1424231437Sluigi } 1425231437Sluigi if (m != NULL) 1426231437Sluigi ETHER_BPF_MTAP(ifp, m); 1427231437Sluigi 1428231879Sluigi } while (TRUE); 1429231437Sluigi 1430231437Sluigi return; 1431231437Sluigi} 1432231437Sluigi 1433231437Sluigi 1434231437Sluigi/* Handle the Completion Queue for transmit */ 1435231437Sluigiuint16_t 1436231437Sluigioce_wq_handler(void *arg) 1437231437Sluigi{ 1438231437Sluigi struct oce_wq *wq = (struct oce_wq *)arg; 1439231437Sluigi POCE_SOFTC sc = wq->parent; 1440231437Sluigi struct oce_cq *cq = wq->cq; 1441231437Sluigi struct oce_nic_tx_cqe *cqe; 1442231437Sluigi int num_cqes = 0; 1443231437Sluigi 1444338938Sjpaetzel LOCK(&wq->tx_compl_lock); 1445231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1446231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1447231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1448231437Sluigi while (cqe->u0.dw[3]) { 1449231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 1450231437Sluigi 1451231437Sluigi wq->ring->cidx = cqe->u0.s.wqe_index + 1; 1452231437Sluigi if (wq->ring->cidx >= wq->ring->num_items) 1453231437Sluigi wq->ring->cidx -= wq->ring->num_items; 1454231437Sluigi 1455338938Sjpaetzel oce_process_tx_completion(wq); 1456231437Sluigi wq->tx_stats.tx_compl++; 1457231437Sluigi cqe->u0.dw[3] = 0; 1458231437Sluigi RING_GET(cq->ring, 1); 1459231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 1460231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1461231437Sluigi cqe = 1462231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 1463231437Sluigi num_cqes++; 1464231437Sluigi } 1465231437Sluigi 1466231437Sluigi if (num_cqes) 1467231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 1468338938Sjpaetzel 1469338938Sjpaetzel UNLOCK(&wq->tx_compl_lock); 1470338938Sjpaetzel return num_cqes; 1471231437Sluigi} 1472231437Sluigi 1473231437Sluigi 1474231437Sluigistatic int 1475231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 1476231437Sluigi{ 1477231437Sluigi POCE_SOFTC sc = ifp->if_softc; 1478231437Sluigi int status = 0, queue_index = 0; 1479231437Sluigi struct mbuf *next = NULL; 1480231437Sluigi struct buf_ring *br = NULL; 1481231437Sluigi 1482231437Sluigi br = wq->br; 1483231437Sluigi queue_index = wq->queue_index; 1484231437Sluigi 1485231437Sluigi if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1486231437Sluigi IFF_DRV_RUNNING) { 1487231437Sluigi if (m != NULL) 1488231437Sluigi status = drbr_enqueue(ifp, br, m); 1489231437Sluigi return status; 1490231437Sluigi } 1491231437Sluigi 1492257007Sdelphij if (m != NULL) { 1493231437Sluigi if ((status = drbr_enqueue(ifp, br, m)) != 0) 1494231437Sluigi return status; 1495246482Srrs } 1496246482Srrs while ((next = drbr_peek(ifp, br)) != NULL) { 1497231437Sluigi if (oce_tx(sc, &next, queue_index)) { 1498246482Srrs if (next == NULL) { 1499246482Srrs drbr_advance(ifp, br); 1500246482Srrs } else { 1501246482Srrs drbr_putback(ifp, br, next); 1502231437Sluigi wq->tx_stats.tx_stops ++; 1503231437Sluigi ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1504231437Sluigi } 1505231437Sluigi break; 1506231437Sluigi } 1507246482Srrs drbr_advance(ifp, br); 1508271849Sglebius if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len); 1509241037Sglebius if (next->m_flags & M_MCAST) 1510271849Sglebius if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 1511231437Sluigi ETHER_BPF_MTAP(ifp, next); 1512231437Sluigi } 1513231437Sluigi 1514268156Sluigi return 0; 1515231437Sluigi} 1516231437Sluigi 1517231437Sluigi 1518231437Sluigi 1519231437Sluigi 1520231437Sluigi/***************************************************************************** 1521231437Sluigi * Receive routines functions * 1522231437Sluigi *****************************************************************************/ 1523231437Sluigi 1524231437Sluigistatic void 1525338938Sjpaetzeloce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2) 1526231437Sluigi{ 1527338938Sjpaetzel uint32_t *p; 1528338938Sjpaetzel struct ether_header *eh = NULL; 1529338938Sjpaetzel struct tcphdr *tcp_hdr = NULL; 1530338938Sjpaetzel struct ip *ip4_hdr = NULL; 1531338938Sjpaetzel struct ip6_hdr *ip6 = NULL; 1532338938Sjpaetzel uint32_t payload_len = 0; 1533338938Sjpaetzel 1534338938Sjpaetzel eh = mtod(m, struct ether_header *); 1535338938Sjpaetzel /* correct IP header */ 1536338938Sjpaetzel if(!cqe2->ipv6_frame) { 1537338938Sjpaetzel ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header)); 1538338938Sjpaetzel ip4_hdr->ip_ttl = cqe2->frame_lifespan; 1539338938Sjpaetzel ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header)); 1540338938Sjpaetzel tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip)); 1541338938Sjpaetzel }else { 1542338938Sjpaetzel ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header)); 1543338938Sjpaetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan; 1544338938Sjpaetzel payload_len = cqe2->coalesced_size - sizeof(struct ether_header) 1545338938Sjpaetzel - sizeof(struct ip6_hdr); 1546338938Sjpaetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len); 1547338938Sjpaetzel tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr)); 1548338938Sjpaetzel } 1549338938Sjpaetzel 1550338938Sjpaetzel /* correct tcp header */ 1551338938Sjpaetzel tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num); 1552338938Sjpaetzel if(cqe2->push) { 1553338938Sjpaetzel tcp_hdr->th_flags |= TH_PUSH; 1554338938Sjpaetzel } 1555338938Sjpaetzel tcp_hdr->th_win = htons(cqe2->tcp_window); 1556338938Sjpaetzel tcp_hdr->th_sum = 0xffff; 1557338938Sjpaetzel if(cqe2->ts_opt) { 1558338938Sjpaetzel p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2); 1559338938Sjpaetzel *p = cqe1->tcp_timestamp_val; 1560338938Sjpaetzel *(p+1) = cqe1->tcp_timestamp_ecr; 1561338938Sjpaetzel } 1562338938Sjpaetzel 1563338938Sjpaetzel return; 1564338938Sjpaetzel} 1565338938Sjpaetzel 1566338938Sjpaetzelstatic void 1567338938Sjpaetzeloce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m) 1568338938Sjpaetzel{ 1569231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1570338938Sjpaetzel uint32_t i = 0, frag_len = 0; 1571338938Sjpaetzel uint32_t len = cqe_info->pkt_size; 1572338938Sjpaetzel struct oce_packet_desc *pd; 1573338938Sjpaetzel struct mbuf *tail = NULL; 1574231437Sluigi 1575338938Sjpaetzel for (i = 0; i < cqe_info->num_frags; i++) { 1576338938Sjpaetzel if (rq->ring->cidx == rq->ring->pidx) { 1577338938Sjpaetzel device_printf(sc->dev, 1578338938Sjpaetzel "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n"); 1579338938Sjpaetzel return; 1580338938Sjpaetzel } 1581338938Sjpaetzel pd = &rq->pckts[rq->ring->cidx]; 1582338938Sjpaetzel 1583338938Sjpaetzel bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1584338938Sjpaetzel bus_dmamap_unload(rq->tag, pd->map); 1585338938Sjpaetzel RING_GET(rq->ring, 1); 1586338938Sjpaetzel rq->pending--; 1587338938Sjpaetzel 1588338938Sjpaetzel frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 1589338938Sjpaetzel pd->mbuf->m_len = frag_len; 1590338938Sjpaetzel 1591338938Sjpaetzel if (tail != NULL) { 1592338938Sjpaetzel /* additional fragments */ 1593338938Sjpaetzel pd->mbuf->m_flags &= ~M_PKTHDR; 1594338938Sjpaetzel tail->m_next = pd->mbuf; 1595338938Sjpaetzel if(rq->islro) 1596338938Sjpaetzel tail->m_nextpkt = NULL; 1597338938Sjpaetzel tail = pd->mbuf; 1598338938Sjpaetzel } else { 1599338938Sjpaetzel /* first fragment, fill out much of the packet header */ 1600338938Sjpaetzel pd->mbuf->m_pkthdr.len = len; 1601338938Sjpaetzel if(rq->islro) 1602338938Sjpaetzel pd->mbuf->m_nextpkt = NULL; 1603338938Sjpaetzel pd->mbuf->m_pkthdr.csum_flags = 0; 1604338938Sjpaetzel if (IF_CSUM_ENABLED(sc)) { 1605338938Sjpaetzel if (cqe_info->l4_cksum_pass) { 1606338938Sjpaetzel if(!cqe_info->ipv6_frame) { /* IPV4 */ 1607338938Sjpaetzel pd->mbuf->m_pkthdr.csum_flags |= 1608338938Sjpaetzel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1609338938Sjpaetzel }else { /* IPV6 frame */ 1610338938Sjpaetzel if(rq->islro) { 1611338938Sjpaetzel pd->mbuf->m_pkthdr.csum_flags |= 1612338938Sjpaetzel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1613338938Sjpaetzel } 1614338938Sjpaetzel } 1615338938Sjpaetzel pd->mbuf->m_pkthdr.csum_data = 0xffff; 1616338938Sjpaetzel } 1617338938Sjpaetzel if (cqe_info->ip_cksum_pass) { 1618338938Sjpaetzel pd->mbuf->m_pkthdr.csum_flags |= 1619338938Sjpaetzel (CSUM_IP_CHECKED|CSUM_IP_VALID); 1620338938Sjpaetzel } 1621338938Sjpaetzel } 1622338938Sjpaetzel *m = tail = pd->mbuf; 1623338938Sjpaetzel } 1624338938Sjpaetzel pd->mbuf = NULL; 1625338938Sjpaetzel len -= frag_len; 1626338938Sjpaetzel } 1627338938Sjpaetzel 1628338938Sjpaetzel return; 1629338938Sjpaetzel} 1630338938Sjpaetzel 1631338938Sjpaetzelstatic void 1632338938Sjpaetzeloce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2) 1633338938Sjpaetzel{ 1634338938Sjpaetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1635338938Sjpaetzel struct nic_hwlro_cqe_part1 *cqe1 = NULL; 1636338938Sjpaetzel struct mbuf *m = NULL; 1637338938Sjpaetzel struct oce_common_cqe_info cq_info; 1638338938Sjpaetzel 1639338938Sjpaetzel /* parse cqe */ 1640338938Sjpaetzel if(cqe2 == NULL) { 1641338938Sjpaetzel cq_info.pkt_size = cqe->pkt_size; 1642338938Sjpaetzel cq_info.vtag = cqe->vlan_tag; 1643338938Sjpaetzel cq_info.l4_cksum_pass = cqe->l4_cksum_pass; 1644338938Sjpaetzel cq_info.ip_cksum_pass = cqe->ip_cksum_pass; 1645338938Sjpaetzel cq_info.ipv6_frame = cqe->ipv6_frame; 1646338938Sjpaetzel cq_info.vtp = cqe->vtp; 1647338938Sjpaetzel cq_info.qnq = cqe->qnq; 1648338938Sjpaetzel }else { 1649338938Sjpaetzel cqe1 = (struct nic_hwlro_cqe_part1 *)cqe; 1650338938Sjpaetzel cq_info.pkt_size = cqe2->coalesced_size; 1651338938Sjpaetzel cq_info.vtag = cqe2->vlan_tag; 1652338938Sjpaetzel cq_info.l4_cksum_pass = cqe2->l4_cksum_pass; 1653338938Sjpaetzel cq_info.ip_cksum_pass = cqe2->ip_cksum_pass; 1654338938Sjpaetzel cq_info.ipv6_frame = cqe2->ipv6_frame; 1655338938Sjpaetzel cq_info.vtp = cqe2->vtp; 1656338938Sjpaetzel cq_info.qnq = cqe1->qnq; 1657338938Sjpaetzel } 1658338938Sjpaetzel 1659338938Sjpaetzel cq_info.vtag = BSWAP_16(cq_info.vtag); 1660338938Sjpaetzel 1661338938Sjpaetzel cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size; 1662338938Sjpaetzel if(cq_info.pkt_size % rq->cfg.frag_size) 1663338938Sjpaetzel cq_info.num_frags++; 1664338938Sjpaetzel 1665338938Sjpaetzel oce_rx_mbuf_chain(rq, &cq_info, &m); 1666338938Sjpaetzel 1667338938Sjpaetzel if (m) { 1668338938Sjpaetzel if(cqe2) { 1669338938Sjpaetzel //assert(cqe2->valid != 0); 1670338938Sjpaetzel 1671338938Sjpaetzel //assert(cqe2->cqe_type != 2); 1672338938Sjpaetzel oce_correct_header(m, cqe1, cqe2); 1673338938Sjpaetzel } 1674338938Sjpaetzel 1675338938Sjpaetzel m->m_pkthdr.rcvif = sc->ifp; 1676338938Sjpaetzel#if __FreeBSD_version >= 800000 1677338938Sjpaetzel if (rq->queue_index) 1678338938Sjpaetzel m->m_pkthdr.flowid = (rq->queue_index - 1); 1679338938Sjpaetzel else 1680338938Sjpaetzel m->m_pkthdr.flowid = rq->queue_index; 1681338938Sjpaetzel M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 1682338938Sjpaetzel#endif 1683338938Sjpaetzel /* This deternies if vlan tag is Valid */ 1684338938Sjpaetzel if (cq_info.vtp) { 1685338938Sjpaetzel if (sc->function_mode & FNM_FLEX10_MODE) { 1686338938Sjpaetzel /* FLEX10. If QnQ is not set, neglect VLAN */ 1687338938Sjpaetzel if (cq_info.qnq) { 1688338938Sjpaetzel m->m_pkthdr.ether_vtag = cq_info.vtag; 1689338938Sjpaetzel m->m_flags |= M_VLANTAG; 1690338938Sjpaetzel } 1691338938Sjpaetzel } else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK)) { 1692338938Sjpaetzel /* In UMC mode generally pvid will be striped by 1693338938Sjpaetzel hw. But in some cases we have seen it comes 1694338938Sjpaetzel with pvid. So if pvid == vlan, neglect vlan. 1695338938Sjpaetzel */ 1696338938Sjpaetzel m->m_pkthdr.ether_vtag = cq_info.vtag; 1697338938Sjpaetzel m->m_flags |= M_VLANTAG; 1698338938Sjpaetzel } 1699338938Sjpaetzel } 1700338938Sjpaetzel if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 1701338938Sjpaetzel 1702338938Sjpaetzel (*sc->ifp->if_input) (sc->ifp, m); 1703338938Sjpaetzel 1704338938Sjpaetzel /* Update rx stats per queue */ 1705338938Sjpaetzel rq->rx_stats.rx_pkts++; 1706338938Sjpaetzel rq->rx_stats.rx_bytes += cq_info.pkt_size; 1707338938Sjpaetzel rq->rx_stats.rx_frags += cq_info.num_frags; 1708338938Sjpaetzel rq->rx_stats.rx_ucast_pkts++; 1709338938Sjpaetzel } 1710338938Sjpaetzel return; 1711338938Sjpaetzel} 1712338938Sjpaetzel 1713338938Sjpaetzelstatic void 1714338938Sjpaetzeloce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1715338938Sjpaetzel{ 1716338938Sjpaetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1717338938Sjpaetzel int len; 1718338938Sjpaetzel struct mbuf *m = NULL; 1719338938Sjpaetzel struct oce_common_cqe_info cq_info; 1720338938Sjpaetzel uint16_t vtag = 0; 1721338938Sjpaetzel 1722338938Sjpaetzel /* Is it a flush compl that has no data */ 1723338938Sjpaetzel if(!cqe->u0.s.num_fragments) 1724338938Sjpaetzel goto exit; 1725338938Sjpaetzel 1726231437Sluigi len = cqe->u0.s.pkt_size; 1727231437Sluigi if (!len) { 1728231437Sluigi /*partial DMA workaround for Lancer*/ 1729338938Sjpaetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 1730231437Sluigi goto exit; 1731231437Sluigi } 1732231437Sluigi 1733338938Sjpaetzel if (!oce_cqe_portid_valid(sc, cqe)) { 1734338938Sjpaetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 1735338938Sjpaetzel goto exit; 1736338938Sjpaetzel } 1737338938Sjpaetzel 1738231879Sluigi /* Get vlan_tag value */ 1739252869Sdelphij if(IS_BE(sc) || IS_SH(sc)) 1740231879Sluigi vtag = BSWAP_16(cqe->u0.s.vlan_tag); 1741231879Sluigi else 1742231879Sluigi vtag = cqe->u0.s.vlan_tag; 1743338938Sjpaetzel 1744338938Sjpaetzel cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass; 1745338938Sjpaetzel cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass; 1746338938Sjpaetzel cq_info.ipv6_frame = cqe->u0.s.ip_ver; 1747338938Sjpaetzel cq_info.num_frags = cqe->u0.s.num_fragments; 1748338938Sjpaetzel cq_info.pkt_size = cqe->u0.s.pkt_size; 1749231879Sluigi 1750338938Sjpaetzel oce_rx_mbuf_chain(rq, &cq_info, &m); 1751231879Sluigi 1752231437Sluigi if (m) { 1753231437Sluigi m->m_pkthdr.rcvif = sc->ifp; 1754231437Sluigi#if __FreeBSD_version >= 800000 1755252869Sdelphij if (rq->queue_index) 1756252869Sdelphij m->m_pkthdr.flowid = (rq->queue_index - 1); 1757252869Sdelphij else 1758252869Sdelphij m->m_pkthdr.flowid = rq->queue_index; 1759275358Shselasky M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 1760231437Sluigi#endif 1761231879Sluigi /* This deternies if vlan tag is Valid */ 1762231437Sluigi if (oce_cqe_vtp_valid(sc, cqe)) { 1763231437Sluigi if (sc->function_mode & FNM_FLEX10_MODE) { 1764231879Sluigi /* FLEX10. If QnQ is not set, neglect VLAN */ 1765231437Sluigi if (cqe->u0.s.qnq) { 1766231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1767231437Sluigi m->m_flags |= M_VLANTAG; 1768231437Sluigi } 1769231879Sluigi } else if (sc->pvid != (vtag & VLAN_VID_MASK)) { 1770231879Sluigi /* In UMC mode generally pvid will be striped by 1771231879Sluigi hw. But in some cases we have seen it comes 1772231879Sluigi with pvid. So if pvid == vlan, neglect vlan. 1773231879Sluigi */ 1774231879Sluigi m->m_pkthdr.ether_vtag = vtag; 1775231437Sluigi m->m_flags |= M_VLANTAG; 1776231437Sluigi } 1777231437Sluigi } 1778231437Sluigi 1779271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 1780231511Sbz#if defined(INET6) || defined(INET) 1781231437Sluigi /* Try to queue to LRO */ 1782231437Sluigi if (IF_LRO_ENABLED(sc) && 1783231437Sluigi (cqe->u0.s.ip_cksum_pass) && 1784231437Sluigi (cqe->u0.s.l4_cksum_pass) && 1785231437Sluigi (!cqe->u0.s.ip_ver) && 1786231437Sluigi (rq->lro.lro_cnt != 0)) { 1787231437Sluigi 1788231437Sluigi if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 1789231437Sluigi rq->lro_pkts_queued ++; 1790231437Sluigi goto post_done; 1791231437Sluigi } 1792231437Sluigi /* If LRO posting fails then try to post to STACK */ 1793231437Sluigi } 1794231511Sbz#endif 1795231437Sluigi 1796231437Sluigi (*sc->ifp->if_input) (sc->ifp, m); 1797231511Sbz#if defined(INET6) || defined(INET) 1798231437Sluigipost_done: 1799231511Sbz#endif 1800231437Sluigi /* Update rx stats per queue */ 1801231437Sluigi rq->rx_stats.rx_pkts++; 1802231437Sluigi rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 1803231437Sluigi rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 1804231437Sluigi if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 1805231437Sluigi rq->rx_stats.rx_mcast_pkts++; 1806231437Sluigi if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 1807231437Sluigi rq->rx_stats.rx_ucast_pkts++; 1808231437Sluigi } 1809231437Sluigiexit: 1810231437Sluigi return; 1811231437Sluigi} 1812231437Sluigi 1813231437Sluigi 1814338938Sjpaetzelvoid 1815338938Sjpaetzeloce_discard_rx_comp(struct oce_rq *rq, int num_frags) 1816231437Sluigi{ 1817338938Sjpaetzel uint32_t i = 0; 1818231437Sluigi struct oce_packet_desc *pd; 1819231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1820231437Sluigi 1821231437Sluigi for (i = 0; i < num_frags; i++) { 1822338938Sjpaetzel if (rq->ring->cidx == rq->ring->pidx) { 1823338938Sjpaetzel device_printf(sc->dev, 1824338938Sjpaetzel "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n"); 1825338938Sjpaetzel return; 1826338938Sjpaetzel } 1827338938Sjpaetzel pd = &rq->pckts[rq->ring->cidx]; 1828338938Sjpaetzel bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 1829338938Sjpaetzel bus_dmamap_unload(rq->tag, pd->map); 1830338938Sjpaetzel if (pd->mbuf != NULL) { 1831338938Sjpaetzel m_freem(pd->mbuf); 1832338938Sjpaetzel pd->mbuf = NULL; 1833338938Sjpaetzel } 1834231437Sluigi 1835338938Sjpaetzel RING_GET(rq->ring, 1); 1836338938Sjpaetzel rq->pending--; 1837231437Sluigi } 1838231437Sluigi} 1839231437Sluigi 1840231437Sluigi 1841231437Sluigistatic int 1842231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1843231437Sluigi{ 1844231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1845231437Sluigi int vtp = 0; 1846231437Sluigi 1847231437Sluigi if (sc->be3_native) { 1848231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1849231437Sluigi vtp = cqe_v1->u0.s.vlan_tag_present; 1850231879Sluigi } else 1851231437Sluigi vtp = cqe->u0.s.vlan_tag_present; 1852231437Sluigi 1853231437Sluigi return vtp; 1854231437Sluigi 1855231437Sluigi} 1856231437Sluigi 1857231437Sluigi 1858231437Sluigistatic int 1859231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 1860231437Sluigi{ 1861231437Sluigi struct oce_nic_rx_cqe_v1 *cqe_v1; 1862231437Sluigi int port_id = 0; 1863231437Sluigi 1864252869Sdelphij if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) { 1865231437Sluigi cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 1866231437Sluigi port_id = cqe_v1->u0.s.port; 1867231437Sluigi if (sc->port_id != port_id) 1868231437Sluigi return 0; 1869231437Sluigi } else 1870231437Sluigi ;/* For BE3 legacy and Lancer this is dummy */ 1871231437Sluigi 1872231437Sluigi return 1; 1873231437Sluigi 1874231437Sluigi} 1875231437Sluigi 1876231511Sbz#if defined(INET6) || defined(INET) 1877338938Sjpaetzelvoid 1878231437Sluigioce_rx_flush_lro(struct oce_rq *rq) 1879231437Sluigi{ 1880231437Sluigi struct lro_ctrl *lro = &rq->lro; 1881231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1882231437Sluigi 1883231437Sluigi if (!IF_LRO_ENABLED(sc)) 1884231437Sluigi return; 1885231437Sluigi 1886297482Ssephe tcp_lro_flush_all(lro); 1887231437Sluigi rq->lro_pkts_queued = 0; 1888231437Sluigi 1889231437Sluigi return; 1890231437Sluigi} 1891231437Sluigi 1892231437Sluigi 1893231437Sluigistatic int 1894231437Sluigioce_init_lro(POCE_SOFTC sc) 1895231437Sluigi{ 1896231437Sluigi struct lro_ctrl *lro = NULL; 1897231437Sluigi int i = 0, rc = 0; 1898231437Sluigi 1899231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1900231437Sluigi lro = &sc->rq[i]->lro; 1901231437Sluigi rc = tcp_lro_init(lro); 1902231437Sluigi if (rc != 0) { 1903231437Sluigi device_printf(sc->dev, "LRO init failed\n"); 1904231437Sluigi return rc; 1905231437Sluigi } 1906231437Sluigi lro->ifp = sc->ifp; 1907231437Sluigi } 1908231437Sluigi 1909231437Sluigi return rc; 1910231437Sluigi} 1911231437Sluigi 1912231879Sluigi 1913231437Sluigivoid 1914231437Sluigioce_free_lro(POCE_SOFTC sc) 1915231437Sluigi{ 1916231437Sluigi struct lro_ctrl *lro = NULL; 1917231437Sluigi int i = 0; 1918231437Sluigi 1919231437Sluigi for (i = 0; i < sc->nrqs; i++) { 1920231437Sluigi lro = &sc->rq[i]->lro; 1921231437Sluigi if (lro) 1922231437Sluigi tcp_lro_free(lro); 1923231437Sluigi } 1924231437Sluigi} 1925247880Sdelphij#endif 1926231437Sluigi 1927231437Sluigiint 1928231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count) 1929231437Sluigi{ 1930231437Sluigi POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1931231437Sluigi int i, in, rc; 1932231437Sluigi struct oce_packet_desc *pd; 1933231437Sluigi bus_dma_segment_t segs[6]; 1934231437Sluigi int nsegs, added = 0; 1935231437Sluigi struct oce_nic_rqe *rqe; 1936231437Sluigi pd_rxulp_db_t rxdb_reg; 1937338938Sjpaetzel uint32_t val = 0; 1938338938Sjpaetzel uint32_t oce_max_rq_posts = 64; 1939231437Sluigi 1940247880Sdelphij bzero(&rxdb_reg, sizeof(pd_rxulp_db_t)); 1941231437Sluigi for (i = 0; i < count; i++) { 1942338938Sjpaetzel in = (rq->ring->pidx + 1) % OCE_RQ_PACKET_ARRAY_SIZE; 1943231437Sluigi 1944338938Sjpaetzel pd = &rq->pckts[rq->ring->pidx]; 1945338938Sjpaetzel pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size); 1946338938Sjpaetzel if (pd->mbuf == NULL) { 1947338938Sjpaetzel device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size); 1948231437Sluigi break; 1949338938Sjpaetzel } 1950338938Sjpaetzel pd->mbuf->m_nextpkt = NULL; 1951231437Sluigi 1952338938Sjpaetzel pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size; 1953338938Sjpaetzel 1954231437Sluigi rc = bus_dmamap_load_mbuf_sg(rq->tag, 1955231437Sluigi pd->map, 1956231437Sluigi pd->mbuf, 1957231437Sluigi segs, &nsegs, BUS_DMA_NOWAIT); 1958231437Sluigi if (rc) { 1959231437Sluigi m_free(pd->mbuf); 1960338938Sjpaetzel device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc); 1961231437Sluigi break; 1962231437Sluigi } 1963231437Sluigi 1964231437Sluigi if (nsegs != 1) { 1965231437Sluigi i--; 1966231437Sluigi continue; 1967231437Sluigi } 1968231437Sluigi 1969231437Sluigi bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 1970231437Sluigi 1971231437Sluigi rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 1972231437Sluigi rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 1973231437Sluigi rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 1974231437Sluigi DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 1975231437Sluigi RING_PUT(rq->ring, 1); 1976231437Sluigi added++; 1977231437Sluigi rq->pending++; 1978231437Sluigi } 1979338938Sjpaetzel oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS; 1980231437Sluigi if (added != 0) { 1981338938Sjpaetzel for (i = added / oce_max_rq_posts; i > 0; i--) { 1982338938Sjpaetzel rxdb_reg.bits.num_posted = oce_max_rq_posts; 1983231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1984338938Sjpaetzel if(rq->islro) { 1985338938Sjpaetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK; 1986338938Sjpaetzel val |= oce_max_rq_posts << 16; 1987338938Sjpaetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val); 1988338938Sjpaetzel }else { 1989338938Sjpaetzel OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1990338938Sjpaetzel } 1991338938Sjpaetzel added -= oce_max_rq_posts; 1992231437Sluigi } 1993231437Sluigi if (added > 0) { 1994231437Sluigi rxdb_reg.bits.qid = rq->rq_id; 1995231437Sluigi rxdb_reg.bits.num_posted = added; 1996338938Sjpaetzel if(rq->islro) { 1997338938Sjpaetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK; 1998338938Sjpaetzel val |= added << 16; 1999338938Sjpaetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val); 2000338938Sjpaetzel }else { 2001338938Sjpaetzel OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 2002338938Sjpaetzel } 2003231437Sluigi } 2004231437Sluigi } 2005231437Sluigi 2006231437Sluigi return 0; 2007231437Sluigi} 2008231437Sluigi 2009338938Sjpaetzelstatic void 2010338938Sjpaetzeloce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq) 2011338938Sjpaetzel{ 2012338938Sjpaetzel if (num_cqes) { 2013338938Sjpaetzel oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE); 2014338938Sjpaetzel if(!sc->enable_hwlro) { 2015338938Sjpaetzel if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1) 2016338938Sjpaetzel oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1)); 2017338938Sjpaetzel }else { 2018338938Sjpaetzel if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64) 2019338938Sjpaetzel oce_alloc_rx_bufs(rq, 64); 2020338938Sjpaetzel } 2021338938Sjpaetzel } 2022231437Sluigi 2023338938Sjpaetzel return; 2024338938Sjpaetzel} 2025338938Sjpaetzel 2026338938Sjpaetzeluint16_t 2027338938Sjpaetzeloce_rq_handler_lro(void *arg) 2028338938Sjpaetzel{ 2029338938Sjpaetzel struct oce_rq *rq = (struct oce_rq *)arg; 2030338938Sjpaetzel struct oce_cq *cq = rq->cq; 2031338938Sjpaetzel POCE_SOFTC sc = rq->parent; 2032338938Sjpaetzel struct nic_hwlro_singleton_cqe *cqe; 2033338938Sjpaetzel struct nic_hwlro_cqe_part2 *cqe2; 2034338938Sjpaetzel int num_cqes = 0; 2035338938Sjpaetzel 2036338938Sjpaetzel LOCK(&rq->rx_lock); 2037338938Sjpaetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2038338938Sjpaetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 2039338938Sjpaetzel while (cqe->valid) { 2040338938Sjpaetzel if(cqe->cqe_type == 0) { /* singleton cqe */ 2041338938Sjpaetzel /* we should not get singleton cqe after cqe1 on same rq */ 2042338938Sjpaetzel if(rq->cqe_firstpart != NULL) { 2043338938Sjpaetzel device_printf(sc->dev, "Got singleton cqe after cqe1 \n"); 2044338938Sjpaetzel goto exit_rq_handler_lro; 2045338938Sjpaetzel } 2046338938Sjpaetzel if(cqe->error != 0) { 2047338938Sjpaetzel rq->rx_stats.rxcp_err++; 2048338938Sjpaetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2049338938Sjpaetzel } 2050338938Sjpaetzel oce_rx_lro(rq, cqe, NULL); 2051338938Sjpaetzel rq->rx_stats.rx_compl++; 2052338938Sjpaetzel cqe->valid = 0; 2053338938Sjpaetzel RING_GET(cq->ring, 1); 2054338938Sjpaetzel num_cqes++; 2055338938Sjpaetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2056338938Sjpaetzel break; 2057338938Sjpaetzel }else if(cqe->cqe_type == 0x1) { /* first part */ 2058338938Sjpaetzel /* we should not get cqe1 after cqe1 on same rq */ 2059338938Sjpaetzel if(rq->cqe_firstpart != NULL) { 2060338938Sjpaetzel device_printf(sc->dev, "Got cqe1 after cqe1 \n"); 2061338938Sjpaetzel goto exit_rq_handler_lro; 2062338938Sjpaetzel } 2063338938Sjpaetzel rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe; 2064338938Sjpaetzel RING_GET(cq->ring, 1); 2065338938Sjpaetzel }else if(cqe->cqe_type == 0x2) { /* second part */ 2066338938Sjpaetzel cqe2 = (struct nic_hwlro_cqe_part2 *)cqe; 2067338938Sjpaetzel if(cqe2->error != 0) { 2068338938Sjpaetzel rq->rx_stats.rxcp_err++; 2069338938Sjpaetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2070338938Sjpaetzel } 2071338938Sjpaetzel /* We should not get cqe2 without cqe1 */ 2072338938Sjpaetzel if(rq->cqe_firstpart == NULL) { 2073338938Sjpaetzel device_printf(sc->dev, "Got cqe2 without cqe1 \n"); 2074338938Sjpaetzel goto exit_rq_handler_lro; 2075338938Sjpaetzel } 2076338938Sjpaetzel oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2); 2077338938Sjpaetzel 2078338938Sjpaetzel rq->rx_stats.rx_compl++; 2079338938Sjpaetzel rq->cqe_firstpart->valid = 0; 2080338938Sjpaetzel cqe2->valid = 0; 2081338938Sjpaetzel rq->cqe_firstpart = NULL; 2082338938Sjpaetzel 2083338938Sjpaetzel RING_GET(cq->ring, 1); 2084338938Sjpaetzel num_cqes += 2; 2085338938Sjpaetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2086338938Sjpaetzel break; 2087338938Sjpaetzel } 2088338938Sjpaetzel 2089338938Sjpaetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2090338938Sjpaetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 2091338938Sjpaetzel } 2092338938Sjpaetzel oce_check_rx_bufs(sc, num_cqes, rq); 2093338938Sjpaetzelexit_rq_handler_lro: 2094338938Sjpaetzel UNLOCK(&rq->rx_lock); 2095338938Sjpaetzel return 0; 2096338938Sjpaetzel} 2097338938Sjpaetzel 2098231437Sluigi/* Handle the Completion Queue for receive */ 2099231437Sluigiuint16_t 2100231437Sluigioce_rq_handler(void *arg) 2101231437Sluigi{ 2102231437Sluigi struct oce_rq *rq = (struct oce_rq *)arg; 2103231437Sluigi struct oce_cq *cq = rq->cq; 2104231437Sluigi POCE_SOFTC sc = rq->parent; 2105231437Sluigi struct oce_nic_rx_cqe *cqe; 2106338938Sjpaetzel int num_cqes = 0; 2107231437Sluigi 2108338938Sjpaetzel if(rq->islro) { 2109338938Sjpaetzel oce_rq_handler_lro(arg); 2110338938Sjpaetzel return 0; 2111338938Sjpaetzel } 2112338938Sjpaetzel LOCK(&rq->rx_lock); 2113231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2114231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2115231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 2116231437Sluigi while (cqe->u0.dw[2]) { 2117231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 2118231437Sluigi 2119231437Sluigi if (cqe->u0.s.error == 0) { 2120338938Sjpaetzel oce_rx(rq, cqe); 2121231437Sluigi } else { 2122231437Sluigi rq->rx_stats.rxcp_err++; 2123271849Sglebius if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2124247880Sdelphij /* Post L3/L4 errors to stack.*/ 2125338938Sjpaetzel oce_rx(rq, cqe); 2126231437Sluigi } 2127231437Sluigi rq->rx_stats.rx_compl++; 2128231437Sluigi cqe->u0.dw[2] = 0; 2129231437Sluigi 2130231511Sbz#if defined(INET6) || defined(INET) 2131231437Sluigi if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 2132231437Sluigi oce_rx_flush_lro(rq); 2133231437Sluigi } 2134231511Sbz#endif 2135231437Sluigi 2136231437Sluigi RING_GET(cq->ring, 1); 2137231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2138231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2139231437Sluigi cqe = 2140231437Sluigi RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 2141231437Sluigi num_cqes++; 2142231437Sluigi if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2143231437Sluigi break; 2144231437Sluigi } 2145231879Sluigi 2146231511Sbz#if defined(INET6) || defined(INET) 2147338938Sjpaetzel if (IF_LRO_ENABLED(sc)) 2148338938Sjpaetzel oce_rx_flush_lro(rq); 2149231511Sbz#endif 2150231437Sluigi 2151338938Sjpaetzel oce_check_rx_bufs(sc, num_cqes, rq); 2152338938Sjpaetzel UNLOCK(&rq->rx_lock); 2153231437Sluigi return 0; 2154231437Sluigi 2155231437Sluigi} 2156231437Sluigi 2157231437Sluigi 2158231437Sluigi 2159231437Sluigi 2160231437Sluigi/***************************************************************************** 2161231437Sluigi * Helper function prototypes in this file * 2162231437Sluigi *****************************************************************************/ 2163231437Sluigi 2164231437Sluigistatic int 2165231437Sluigioce_attach_ifp(POCE_SOFTC sc) 2166231437Sluigi{ 2167231437Sluigi 2168231437Sluigi sc->ifp = if_alloc(IFT_ETHER); 2169231437Sluigi if (!sc->ifp) 2170231437Sluigi return ENOMEM; 2171231437Sluigi 2172231437Sluigi ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 2173231437Sluigi ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2174231437Sluigi ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 2175231437Sluigi 2176231437Sluigi sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 2177231437Sluigi sc->ifp->if_ioctl = oce_ioctl; 2178231437Sluigi sc->ifp->if_start = oce_start; 2179231437Sluigi sc->ifp->if_init = oce_init; 2180231437Sluigi sc->ifp->if_mtu = ETHERMTU; 2181231437Sluigi sc->ifp->if_softc = sc; 2182231437Sluigi#if __FreeBSD_version >= 800000 2183231437Sluigi sc->ifp->if_transmit = oce_multiq_start; 2184231437Sluigi sc->ifp->if_qflush = oce_multiq_flush; 2185231437Sluigi#endif 2186231437Sluigi 2187231437Sluigi if_initname(sc->ifp, 2188231437Sluigi device_get_name(sc->dev), device_get_unit(sc->dev)); 2189231437Sluigi 2190231437Sluigi sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 2191231437Sluigi IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 2192231437Sluigi IFQ_SET_READY(&sc->ifp->if_snd); 2193231437Sluigi 2194231437Sluigi sc->ifp->if_hwassist = OCE_IF_HWASSIST; 2195231437Sluigi sc->ifp->if_hwassist |= CSUM_TSO; 2196231437Sluigi sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 2197231437Sluigi 2198231437Sluigi sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 2199231437Sluigi sc->ifp->if_capabilities |= IFCAP_HWCSUM; 2200231437Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 2201231879Sluigi 2202231511Sbz#if defined(INET6) || defined(INET) 2203231511Sbz sc->ifp->if_capabilities |= IFCAP_TSO; 2204231437Sluigi sc->ifp->if_capabilities |= IFCAP_LRO; 2205231879Sluigi sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 2206231511Sbz#endif 2207231437Sluigi 2208231437Sluigi sc->ifp->if_capenable = sc->ifp->if_capabilities; 2209263102Sglebius sc->ifp->if_baudrate = IF_Gbps(10); 2210231437Sluigi 2211257007Sdelphij#if __FreeBSD_version >= 1000000 2212271946Shselasky sc->ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 2213271946Shselasky sc->ifp->if_hw_tsomaxsegcount = OCE_MAX_TX_ELEMENTS; 2214271946Shselasky sc->ifp->if_hw_tsomaxsegsize = 4096; 2215257007Sdelphij#endif 2216257007Sdelphij 2217231437Sluigi ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 2218231437Sluigi 2219231437Sluigi return 0; 2220231437Sluigi} 2221231437Sluigi 2222231437Sluigi 2223231437Sluigistatic void 2224231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 2225231437Sluigi{ 2226231437Sluigi POCE_SOFTC sc = ifp->if_softc; 2227231437Sluigi 2228231437Sluigi if (ifp->if_softc != arg) 2229231437Sluigi return; 2230231437Sluigi if ((vtag == 0) || (vtag > 4095)) 2231231437Sluigi return; 2232231437Sluigi 2233231437Sluigi sc->vlan_tag[vtag] = 1; 2234231437Sluigi sc->vlans_added++; 2235257007Sdelphij if (sc->vlans_added <= (sc->max_vlans + 1)) 2236257007Sdelphij oce_vid_config(sc); 2237231437Sluigi} 2238231437Sluigi 2239231437Sluigi 2240231437Sluigistatic void 2241231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 2242231437Sluigi{ 2243231437Sluigi POCE_SOFTC sc = ifp->if_softc; 2244231437Sluigi 2245231437Sluigi if (ifp->if_softc != arg) 2246231437Sluigi return; 2247231437Sluigi if ((vtag == 0) || (vtag > 4095)) 2248231437Sluigi return; 2249231437Sluigi 2250231437Sluigi sc->vlan_tag[vtag] = 0; 2251231437Sluigi sc->vlans_added--; 2252231437Sluigi oce_vid_config(sc); 2253231437Sluigi} 2254231437Sluigi 2255231437Sluigi 2256231437Sluigi/* 2257231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures 2258231437Sluigi * more, place the card in vlan promiscuous mode. 2259231437Sluigi */ 2260231437Sluigistatic int 2261231437Sluigioce_vid_config(POCE_SOFTC sc) 2262231437Sluigi{ 2263231437Sluigi struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 2264231437Sluigi uint16_t ntags = 0, i; 2265231437Sluigi int status = 0; 2266231437Sluigi 2267231437Sluigi if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 2268231437Sluigi (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 2269231437Sluigi for (i = 0; i < MAX_VLANS; i++) { 2270231437Sluigi if (sc->vlan_tag[i]) { 2271231437Sluigi vtags[ntags].vtag = i; 2272231437Sluigi ntags++; 2273231437Sluigi } 2274231437Sluigi } 2275231437Sluigi if (ntags) 2276231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 2277231437Sluigi vtags, ntags, 1, 0); 2278231437Sluigi } else 2279231437Sluigi status = oce_config_vlan(sc, (uint8_t) sc->if_id, 2280231437Sluigi NULL, 0, 1, 1); 2281231437Sluigi return status; 2282231437Sluigi} 2283231437Sluigi 2284231437Sluigi 2285231437Sluigistatic void 2286231437Sluigioce_mac_addr_set(POCE_SOFTC sc) 2287231437Sluigi{ 2288231437Sluigi uint32_t old_pmac_id = sc->pmac_id; 2289231437Sluigi int status = 0; 2290231437Sluigi 2291231437Sluigi 2292231437Sluigi status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 2293231437Sluigi sc->macaddr.size_of_struct); 2294231437Sluigi if (!status) 2295231437Sluigi return; 2296231437Sluigi 2297231437Sluigi status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 2298231437Sluigi sc->if_id, &sc->pmac_id); 2299231437Sluigi if (!status) { 2300231437Sluigi status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 2301231437Sluigi bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 2302231437Sluigi sc->macaddr.size_of_struct); 2303231437Sluigi } 2304231437Sluigi if (status) 2305231437Sluigi device_printf(sc->dev, "Failed update macaddress\n"); 2306231437Sluigi 2307231437Sluigi} 2308231437Sluigi 2309231437Sluigi 2310231437Sluigistatic int 2311231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data) 2312231437Sluigi{ 2313231437Sluigi POCE_SOFTC sc = ifp->if_softc; 2314231437Sluigi struct ifreq *ifr = (struct ifreq *)data; 2315231437Sluigi int rc = ENXIO; 2316231437Sluigi char cookie[32] = {0}; 2317332288Sbrooks void *priv_data = ifr_data_get_ptr(ifr); 2318231437Sluigi void *ioctl_ptr; 2319231437Sluigi uint32_t req_size; 2320231437Sluigi struct mbx_hdr req; 2321231437Sluigi OCE_DMA_MEM dma_mem; 2322247880Sdelphij struct mbx_common_get_cntl_attr *fw_cmd; 2323231437Sluigi 2324231437Sluigi if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 2325231437Sluigi return EFAULT; 2326247880Sdelphij 2327231437Sluigi if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 2328231437Sluigi return EINVAL; 2329247880Sdelphij 2330231437Sluigi ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 2331231437Sluigi if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 2332231437Sluigi return EFAULT; 2333247880Sdelphij 2334231437Sluigi req_size = le32toh(req.u0.req.request_length); 2335231437Sluigi if (req_size > 65536) 2336231437Sluigi return EINVAL; 2337231437Sluigi 2338231437Sluigi req_size += sizeof(struct mbx_hdr); 2339231437Sluigi rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 2340231437Sluigi if (rc) 2341231437Sluigi return ENOMEM; 2342231437Sluigi 2343231437Sluigi if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 2344231437Sluigi rc = EFAULT; 2345231437Sluigi goto dma_free; 2346231437Sluigi } 2347231437Sluigi 2348231437Sluigi rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 2349231437Sluigi if (rc) { 2350231437Sluigi rc = EIO; 2351231437Sluigi goto dma_free; 2352231437Sluigi } 2353231437Sluigi 2354231437Sluigi if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 2355231437Sluigi rc = EFAULT; 2356231437Sluigi 2357247880Sdelphij /* 2358247880Sdelphij firmware is filling all the attributes for this ioctl except 2359247880Sdelphij the driver version..so fill it 2360247880Sdelphij */ 2361247880Sdelphij if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) { 2362247880Sdelphij fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr; 2363247880Sdelphij strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str, 2364247880Sdelphij COMPONENT_REVISION, strlen(COMPONENT_REVISION)); 2365247880Sdelphij } 2366247880Sdelphij 2367231437Sluigidma_free: 2368231437Sluigi oce_dma_free(sc, &dma_mem); 2369231437Sluigi return rc; 2370231437Sluigi 2371231437Sluigi} 2372231437Sluigi 2373247880Sdelphijstatic void 2374247880Sdelphijoce_eqd_set_periodic(POCE_SOFTC sc) 2375247880Sdelphij{ 2376247880Sdelphij struct oce_set_eqd set_eqd[OCE_MAX_EQ]; 2377247880Sdelphij struct oce_aic_obj *aic; 2378247880Sdelphij struct oce_eq *eqo; 2379247880Sdelphij uint64_t now = 0, delta; 2380247880Sdelphij int eqd, i, num = 0; 2381338938Sjpaetzel uint32_t tx_reqs = 0, rxpkts = 0, pps; 2382338938Sjpaetzel struct oce_wq *wq; 2383338938Sjpaetzel struct oce_rq *rq; 2384231437Sluigi 2385338938Sjpaetzel #define ticks_to_msecs(t) (1000 * (t) / hz) 2386338938Sjpaetzel 2387247880Sdelphij for (i = 0 ; i < sc->neqs; i++) { 2388247880Sdelphij eqo = sc->eq[i]; 2389247880Sdelphij aic = &sc->aic_obj[i]; 2390247880Sdelphij /* When setting the static eq delay from the user space */ 2391247880Sdelphij if (!aic->enable) { 2392338938Sjpaetzel if (aic->ticks) 2393338938Sjpaetzel aic->ticks = 0; 2394247880Sdelphij eqd = aic->et_eqd; 2395247880Sdelphij goto modify_eqd; 2396247880Sdelphij } 2397247880Sdelphij 2398369531Sfreqlabs if (i == 0) { 2399369531Sfreqlabs rq = sc->rq[0]; 2400369531Sfreqlabs rxpkts = rq->rx_stats.rx_pkts; 2401369531Sfreqlabs } else 2402369531Sfreqlabs rxpkts = 0; 2403369531Sfreqlabs if (i + 1 < sc->nrqs) { 2404369531Sfreqlabs rq = sc->rq[i + 1]; 2405369531Sfreqlabs rxpkts += rq->rx_stats.rx_pkts; 2406369531Sfreqlabs } 2407369531Sfreqlabs if (i < sc->nwqs) { 2408369531Sfreqlabs wq = sc->wq[i]; 2409369531Sfreqlabs tx_reqs = wq->tx_stats.tx_reqs; 2410369531Sfreqlabs } else 2411369531Sfreqlabs tx_reqs = 0; 2412247880Sdelphij now = ticks; 2413247880Sdelphij 2414338938Sjpaetzel if (!aic->ticks || now < aic->ticks || 2415338938Sjpaetzel rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) { 2416338938Sjpaetzel aic->prev_rxpkts = rxpkts; 2417338938Sjpaetzel aic->prev_txreqs = tx_reqs; 2418338938Sjpaetzel aic->ticks = now; 2419338938Sjpaetzel continue; 2420338938Sjpaetzel } 2421247880Sdelphij 2422338938Sjpaetzel delta = ticks_to_msecs(now - aic->ticks); 2423247880Sdelphij 2424338938Sjpaetzel pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) + 2425338938Sjpaetzel (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta); 2426338938Sjpaetzel eqd = (pps / 15000) << 2; 2427338938Sjpaetzel if (eqd < 8) 2428247880Sdelphij eqd = 0; 2429247880Sdelphij 2430247880Sdelphij /* Make sure that the eq delay is in the known range */ 2431247880Sdelphij eqd = min(eqd, aic->max_eqd); 2432247880Sdelphij eqd = max(eqd, aic->min_eqd); 2433247880Sdelphij 2434338938Sjpaetzel aic->prev_rxpkts = rxpkts; 2435338938Sjpaetzel aic->prev_txreqs = tx_reqs; 2436338938Sjpaetzel aic->ticks = now; 2437338938Sjpaetzel 2438247880Sdelphijmodify_eqd: 2439247880Sdelphij if (eqd != aic->cur_eqd) { 2440247880Sdelphij set_eqd[num].delay_multiplier = (eqd * 65)/100; 2441247880Sdelphij set_eqd[num].eq_id = eqo->eq_id; 2442247880Sdelphij aic->cur_eqd = eqd; 2443247880Sdelphij num++; 2444247880Sdelphij } 2445247880Sdelphij } 2446247880Sdelphij 2447247880Sdelphij /* Is there atleast one eq that needs to be modified? */ 2448338938Sjpaetzel for(i = 0; i < num; i += 8) { 2449338938Sjpaetzel if((num - i) >=8 ) 2450338938Sjpaetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8); 2451338938Sjpaetzel else 2452338938Sjpaetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i)); 2453338938Sjpaetzel } 2454338938Sjpaetzel 2455247880Sdelphij} 2456247880Sdelphij 2457257007Sdelphijstatic void oce_detect_hw_error(POCE_SOFTC sc) 2458257007Sdelphij{ 2459257007Sdelphij 2460257007Sdelphij uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0; 2461257007Sdelphij uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; 2462257007Sdelphij uint32_t i; 2463257007Sdelphij 2464257007Sdelphij if (sc->hw_error) 2465257007Sdelphij return; 2466257007Sdelphij 2467257007Sdelphij if (IS_XE201(sc)) { 2468257007Sdelphij sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET); 2469257007Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 2470257007Sdelphij sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET); 2471257007Sdelphij sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET); 2472257007Sdelphij } 2473257007Sdelphij } else { 2474257007Sdelphij ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW); 2475257007Sdelphij ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH); 2476257007Sdelphij ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK); 2477257007Sdelphij ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK); 2478257007Sdelphij 2479257007Sdelphij ue_low = (ue_low & ~ue_low_mask); 2480257007Sdelphij ue_high = (ue_high & ~ue_high_mask); 2481257007Sdelphij } 2482257007Sdelphij 2483257007Sdelphij /* On certain platforms BE hardware can indicate spurious UEs. 2484257007Sdelphij * Allow the h/w to stop working completely in case of a real UE. 2485257007Sdelphij * Hence not setting the hw_error for UE detection. 2486257007Sdelphij */ 2487257007Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 2488257007Sdelphij sc->hw_error = TRUE; 2489257007Sdelphij device_printf(sc->dev, "Error detected in the card\n"); 2490257007Sdelphij } 2491257007Sdelphij 2492257007Sdelphij if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 2493257007Sdelphij device_printf(sc->dev, 2494257007Sdelphij "ERR: sliport status 0x%x\n", sliport_status); 2495257007Sdelphij device_printf(sc->dev, 2496257007Sdelphij "ERR: sliport error1 0x%x\n", sliport_err1); 2497257007Sdelphij device_printf(sc->dev, 2498257007Sdelphij "ERR: sliport error2 0x%x\n", sliport_err2); 2499257007Sdelphij } 2500257007Sdelphij 2501257007Sdelphij if (ue_low) { 2502257007Sdelphij for (i = 0; ue_low; ue_low >>= 1, i++) { 2503257007Sdelphij if (ue_low & 1) 2504257007Sdelphij device_printf(sc->dev, "UE: %s bit set\n", 2505257007Sdelphij ue_status_low_desc[i]); 2506257007Sdelphij } 2507257007Sdelphij } 2508257007Sdelphij 2509257007Sdelphij if (ue_high) { 2510257007Sdelphij for (i = 0; ue_high; ue_high >>= 1, i++) { 2511257007Sdelphij if (ue_high & 1) 2512257007Sdelphij device_printf(sc->dev, "UE: %s bit set\n", 2513257007Sdelphij ue_status_hi_desc[i]); 2514257007Sdelphij } 2515257007Sdelphij } 2516257007Sdelphij 2517257007Sdelphij} 2518257007Sdelphij 2519257007Sdelphij 2520231437Sluigistatic void 2521231437Sluigioce_local_timer(void *arg) 2522231437Sluigi{ 2523231437Sluigi POCE_SOFTC sc = arg; 2524231437Sluigi int i = 0; 2525231437Sluigi 2526257007Sdelphij oce_detect_hw_error(sc); 2527231437Sluigi oce_refresh_nic_stats(sc); 2528231437Sluigi oce_refresh_queue_stats(sc); 2529231437Sluigi oce_mac_addr_set(sc); 2530231437Sluigi 2531231437Sluigi /* TX Watch Dog*/ 2532231437Sluigi for (i = 0; i < sc->nwqs; i++) 2533231437Sluigi oce_tx_restart(sc, sc->wq[i]); 2534231437Sluigi 2535247880Sdelphij /* calculate and set the eq delay for optimal interrupt rate */ 2536252869Sdelphij if (IS_BE(sc) || IS_SH(sc)) 2537247880Sdelphij oce_eqd_set_periodic(sc); 2538247880Sdelphij 2539231437Sluigi callout_reset(&sc->timer, hz, oce_local_timer, sc); 2540231437Sluigi} 2541231437Sluigi 2542338938Sjpaetzelstatic void 2543338938Sjpaetzeloce_tx_compl_clean(POCE_SOFTC sc) 2544338938Sjpaetzel{ 2545338938Sjpaetzel struct oce_wq *wq; 2546338938Sjpaetzel int i = 0, timeo = 0, num_wqes = 0; 2547338938Sjpaetzel int pending_txqs = sc->nwqs; 2548231437Sluigi 2549338938Sjpaetzel /* Stop polling for compls when HW has been silent for 10ms or 2550338938Sjpaetzel * hw_error or no outstanding completions expected 2551338938Sjpaetzel */ 2552338938Sjpaetzel do { 2553338938Sjpaetzel pending_txqs = sc->nwqs; 2554338938Sjpaetzel 2555338938Sjpaetzel for_all_wq_queues(sc, wq, i) { 2556338938Sjpaetzel num_wqes = oce_wq_handler(wq); 2557338938Sjpaetzel 2558338938Sjpaetzel if(num_wqes) 2559338938Sjpaetzel timeo = 0; 2560338938Sjpaetzel 2561338938Sjpaetzel if(!wq->ring->num_used) 2562338938Sjpaetzel pending_txqs--; 2563338938Sjpaetzel } 2564338938Sjpaetzel 2565338938Sjpaetzel if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error) 2566338938Sjpaetzel break; 2567338938Sjpaetzel 2568338938Sjpaetzel DELAY(1000); 2569338938Sjpaetzel } while (TRUE); 2570338938Sjpaetzel 2571338938Sjpaetzel for_all_wq_queues(sc, wq, i) { 2572338938Sjpaetzel while(wq->ring->num_used) { 2573338938Sjpaetzel LOCK(&wq->tx_compl_lock); 2574338938Sjpaetzel oce_process_tx_completion(wq); 2575338938Sjpaetzel UNLOCK(&wq->tx_compl_lock); 2576338938Sjpaetzel } 2577338938Sjpaetzel } 2578338938Sjpaetzel 2579338938Sjpaetzel} 2580338938Sjpaetzel 2581246799Sjpaetzel/* NOTE : This should only be called holding 2582246799Sjpaetzel * DEVICE_LOCK. 2583257007Sdelphij */ 2584231437Sluigistatic void 2585231437Sluigioce_if_deactivate(POCE_SOFTC sc) 2586231437Sluigi{ 2587338938Sjpaetzel int i; 2588231437Sluigi struct oce_rq *rq; 2589231437Sluigi struct oce_wq *wq; 2590231437Sluigi struct oce_eq *eq; 2591231437Sluigi 2592231437Sluigi sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 2593231437Sluigi 2594338938Sjpaetzel oce_tx_compl_clean(sc); 2595231437Sluigi 2596231437Sluigi /* Stop intrs and finish any bottom halves pending */ 2597231437Sluigi oce_hw_intr_disable(sc); 2598231437Sluigi 2599247880Sdelphij /* Since taskqueue_drain takes a Gaint Lock, We should not acquire 2600247880Sdelphij any other lock. So unlock device lock and require after 2601247880Sdelphij completing taskqueue_drain. 2602247880Sdelphij */ 2603247880Sdelphij UNLOCK(&sc->dev_lock); 2604231437Sluigi for (i = 0; i < sc->intr_count; i++) { 2605231437Sluigi if (sc->intrs[i].tq != NULL) { 2606231437Sluigi taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 2607231437Sluigi } 2608231437Sluigi } 2609247880Sdelphij LOCK(&sc->dev_lock); 2610231437Sluigi 2611231437Sluigi /* Delete RX queue in card with flush param */ 2612231437Sluigi oce_stop_rx(sc); 2613231437Sluigi 2614231437Sluigi /* Invalidate any pending cq and eq entries*/ 2615231437Sluigi for_all_evnt_queues(sc, eq, i) 2616231437Sluigi oce_drain_eq(eq); 2617231437Sluigi for_all_rq_queues(sc, rq, i) 2618231437Sluigi oce_drain_rq_cq(rq); 2619231437Sluigi for_all_wq_queues(sc, wq, i) 2620231437Sluigi oce_drain_wq_cq(wq); 2621231437Sluigi 2622231437Sluigi /* But still we need to get MCC aync events. 2623231437Sluigi So enable intrs and also arm first EQ 2624247880Sdelphij */ 2625231437Sluigi oce_hw_intr_enable(sc); 2626231437Sluigi oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 2627231437Sluigi 2628231437Sluigi DELAY(10); 2629231437Sluigi} 2630231437Sluigi 2631231437Sluigi 2632231437Sluigistatic void 2633231437Sluigioce_if_activate(POCE_SOFTC sc) 2634231437Sluigi{ 2635231437Sluigi struct oce_eq *eq; 2636231437Sluigi struct oce_rq *rq; 2637231437Sluigi struct oce_wq *wq; 2638231437Sluigi int i, rc = 0; 2639231437Sluigi 2640231437Sluigi sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 2641231437Sluigi 2642231437Sluigi oce_hw_intr_disable(sc); 2643231437Sluigi 2644231437Sluigi oce_start_rx(sc); 2645231437Sluigi 2646231437Sluigi for_all_rq_queues(sc, rq, i) { 2647231437Sluigi rc = oce_start_rq(rq); 2648231437Sluigi if (rc) 2649231437Sluigi device_printf(sc->dev, "Unable to start RX\n"); 2650231437Sluigi } 2651231437Sluigi 2652231437Sluigi for_all_wq_queues(sc, wq, i) { 2653231437Sluigi rc = oce_start_wq(wq); 2654231437Sluigi if (rc) 2655231437Sluigi device_printf(sc->dev, "Unable to start TX\n"); 2656231437Sluigi } 2657231437Sluigi 2658231437Sluigi 2659231437Sluigi for_all_evnt_queues(sc, eq, i) 2660231437Sluigi oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 2661231437Sluigi 2662231437Sluigi oce_hw_intr_enable(sc); 2663231437Sluigi 2664231437Sluigi} 2665231437Sluigi 2666231879Sluigistatic void 2667231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe) 2668231879Sluigi{ 2669231879Sluigi /* Update Link status */ 2670231879Sluigi if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 2671231879Sluigi ASYNC_EVENT_LINK_UP) { 2672231879Sluigi sc->link_status = ASYNC_EVENT_LINK_UP; 2673231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_UP); 2674231879Sluigi } else { 2675231879Sluigi sc->link_status = ASYNC_EVENT_LINK_DOWN; 2676231879Sluigi if_link_state_change(sc->ifp, LINK_STATE_DOWN); 2677231879Sluigi } 2678231879Sluigi} 2679231879Sluigi 2680231879Sluigi 2681338938Sjpaetzelstatic void oce_async_grp5_osbmc_process(POCE_SOFTC sc, 2682338938Sjpaetzel struct oce_async_evt_grp5_os2bmc *evt) 2683338938Sjpaetzel{ 2684338938Sjpaetzel DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc)); 2685338938Sjpaetzel if (evt->u.s.mgmt_enable) 2686338938Sjpaetzel sc->flags |= OCE_FLAGS_OS2BMC; 2687338938Sjpaetzel else 2688338938Sjpaetzel return; 2689338938Sjpaetzel 2690338938Sjpaetzel sc->bmc_filt_mask = evt->u.s.arp_filter; 2691338938Sjpaetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1); 2692338938Sjpaetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2); 2693338938Sjpaetzel sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3); 2694338938Sjpaetzel sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4); 2695338938Sjpaetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5); 2696338938Sjpaetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6); 2697338938Sjpaetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7); 2698338938Sjpaetzel sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8); 2699338938Sjpaetzel} 2700338938Sjpaetzel 2701338938Sjpaetzel 2702338938Sjpaetzelstatic void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe) 2703338938Sjpaetzel{ 2704338938Sjpaetzel struct oce_async_event_grp5_pvid_state *gcqe; 2705338938Sjpaetzel struct oce_async_evt_grp5_os2bmc *bmccqe; 2706338938Sjpaetzel 2707338938Sjpaetzel switch (cqe->u0.s.async_type) { 2708338938Sjpaetzel case ASYNC_EVENT_PVID_STATE: 2709338938Sjpaetzel /* GRP5 PVID */ 2710338938Sjpaetzel gcqe = (struct oce_async_event_grp5_pvid_state *)cqe; 2711338938Sjpaetzel if (gcqe->enabled) 2712338938Sjpaetzel sc->pvid = gcqe->tag & VLAN_VID_MASK; 2713338938Sjpaetzel else 2714338938Sjpaetzel sc->pvid = 0; 2715338938Sjpaetzel break; 2716338938Sjpaetzel case ASYNC_EVENT_OS2BMC: 2717338938Sjpaetzel bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe; 2718338938Sjpaetzel oce_async_grp5_osbmc_process(sc, bmccqe); 2719338938Sjpaetzel break; 2720338938Sjpaetzel default: 2721338938Sjpaetzel break; 2722338938Sjpaetzel } 2723338938Sjpaetzel} 2724338938Sjpaetzel 2725231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */ 2726231437Sluigiuint16_t 2727231437Sluigioce_mq_handler(void *arg) 2728231437Sluigi{ 2729231437Sluigi struct oce_mq *mq = (struct oce_mq *)arg; 2730231437Sluigi POCE_SOFTC sc = mq->parent; 2731231437Sluigi struct oce_cq *cq = mq->cq; 2732231879Sluigi int num_cqes = 0, evt_type = 0, optype = 0; 2733231437Sluigi struct oce_mq_cqe *cqe; 2734231437Sluigi struct oce_async_cqe_link_state *acqe; 2735247880Sdelphij struct oce_async_event_qnq *dbgcqe; 2736231437Sluigi 2737231879Sluigi 2738231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2739231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2740231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 2741231879Sluigi 2742231437Sluigi while (cqe->u0.dw[3]) { 2743231437Sluigi DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 2744231437Sluigi if (cqe->u0.s.async_event) { 2745231879Sluigi evt_type = cqe->u0.s.event_type; 2746231879Sluigi optype = cqe->u0.s.async_type; 2747231879Sluigi if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) { 2748231879Sluigi /* Link status evt */ 2749231879Sluigi acqe = (struct oce_async_cqe_link_state *)cqe; 2750231879Sluigi process_link_state(sc, acqe); 2751338938Sjpaetzel } else if (evt_type == ASYNC_EVENT_GRP5) { 2752338938Sjpaetzel oce_process_grp5_events(sc, cqe); 2753338938Sjpaetzel } else if (evt_type == ASYNC_EVENT_CODE_DEBUG && 2754338938Sjpaetzel optype == ASYNC_EVENT_DEBUG_QNQ) { 2755338938Sjpaetzel dbgcqe = (struct oce_async_event_qnq *)cqe; 2756247880Sdelphij if(dbgcqe->valid) 2757247880Sdelphij sc->qnqid = dbgcqe->vlan_tag; 2758247880Sdelphij sc->qnq_debug_event = TRUE; 2759247880Sdelphij } 2760231437Sluigi } 2761231437Sluigi cqe->u0.dw[3] = 0; 2762231437Sluigi RING_GET(cq->ring, 1); 2763231437Sluigi bus_dmamap_sync(cq->ring->dma.tag, 2764231437Sluigi cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2765231437Sluigi cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 2766231437Sluigi num_cqes++; 2767231437Sluigi } 2768231437Sluigi 2769231437Sluigi if (num_cqes) 2770231437Sluigi oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 2771231437Sluigi 2772231437Sluigi return 0; 2773231437Sluigi} 2774231437Sluigi 2775231437Sluigi 2776231437Sluigistatic void 2777231437Sluigisetup_max_queues_want(POCE_SOFTC sc) 2778231437Sluigi{ 2779231437Sluigi /* Check if it is FLEX machine. Is so dont use RSS */ 2780231437Sluigi if ((sc->function_mode & FNM_FLEX10_MODE) || 2781231879Sluigi (sc->function_mode & FNM_UMC_MODE) || 2782231879Sluigi (sc->function_mode & FNM_VNIC_MODE) || 2783252869Sdelphij (!is_rss_enabled(sc)) || 2784267839Sdelphij IS_BE2(sc)) { 2785231437Sluigi sc->nrqs = 1; 2786231437Sluigi sc->nwqs = 1; 2787257007Sdelphij } else { 2788257007Sdelphij sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 2789257007Sdelphij sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs); 2790231437Sluigi } 2791267839Sdelphij 2792267839Sdelphij if (IS_BE2(sc) && is_rss_enabled(sc)) 2793267839Sdelphij sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 2794231437Sluigi} 2795231437Sluigi 2796231437Sluigi 2797231437Sluigistatic void 2798231437Sluigiupdate_queues_got(POCE_SOFTC sc) 2799231437Sluigi{ 2800252869Sdelphij if (is_rss_enabled(sc)) { 2801231437Sluigi sc->nrqs = sc->intr_count + 1; 2802231437Sluigi sc->nwqs = sc->intr_count; 2803231437Sluigi } else { 2804231437Sluigi sc->nrqs = 1; 2805231437Sluigi sc->nwqs = 1; 2806231437Sluigi } 2807267839Sdelphij 2808267839Sdelphij if (IS_BE2(sc)) 2809267839Sdelphij sc->nwqs = 1; 2810231437Sluigi} 2811231437Sluigi 2812247880Sdelphijstatic int 2813247880Sdelphijoce_check_ipv6_ext_hdr(struct mbuf *m) 2814247880Sdelphij{ 2815247880Sdelphij struct ether_header *eh = mtod(m, struct ether_header *); 2816247880Sdelphij caddr_t m_datatemp = m->m_data; 2817247880Sdelphij 2818247880Sdelphij if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 2819247880Sdelphij m->m_data += sizeof(struct ether_header); 2820247880Sdelphij struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 2821247880Sdelphij 2822247880Sdelphij if((ip6->ip6_nxt != IPPROTO_TCP) && \ 2823247880Sdelphij (ip6->ip6_nxt != IPPROTO_UDP)){ 2824247880Sdelphij struct ip6_ext *ip6e = NULL; 2825247880Sdelphij m->m_data += sizeof(struct ip6_hdr); 2826247880Sdelphij 2827247880Sdelphij ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *); 2828247880Sdelphij if(ip6e->ip6e_len == 0xff) { 2829247880Sdelphij m->m_data = m_datatemp; 2830247880Sdelphij return TRUE; 2831247880Sdelphij } 2832247880Sdelphij } 2833247880Sdelphij m->m_data = m_datatemp; 2834247880Sdelphij } 2835247880Sdelphij return FALSE; 2836247880Sdelphij} 2837247880Sdelphij 2838247880Sdelphijstatic int 2839247880Sdelphijis_be3_a1(POCE_SOFTC sc) 2840247880Sdelphij{ 2841247880Sdelphij if((sc->flags & OCE_FLAGS_BE3) && ((sc->asic_revision & 0xFF) < 2)) { 2842247880Sdelphij return TRUE; 2843247880Sdelphij } 2844247880Sdelphij return FALSE; 2845247880Sdelphij} 2846247880Sdelphij 2847247880Sdelphijstatic struct mbuf * 2848247880Sdelphijoce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete) 2849247880Sdelphij{ 2850247880Sdelphij uint16_t vlan_tag = 0; 2851247880Sdelphij 2852247880Sdelphij if(!M_WRITABLE(m)) 2853247880Sdelphij return NULL; 2854247880Sdelphij 2855247880Sdelphij /* Embed vlan tag in the packet if it is not part of it */ 2856247880Sdelphij if(m->m_flags & M_VLANTAG) { 2857247880Sdelphij vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 2858247880Sdelphij m->m_flags &= ~M_VLANTAG; 2859247880Sdelphij } 2860247880Sdelphij 2861247880Sdelphij /* if UMC, ignore vlan tag insertion and instead insert pvid */ 2862247880Sdelphij if(sc->pvid) { 2863247880Sdelphij if(!vlan_tag) 2864247880Sdelphij vlan_tag = sc->pvid; 2865338938Sjpaetzel if (complete) 2866338938Sjpaetzel *complete = FALSE; 2867247880Sdelphij } 2868247880Sdelphij 2869247880Sdelphij if(vlan_tag) { 2870247880Sdelphij m = ether_vlanencap(m, vlan_tag); 2871247880Sdelphij } 2872247880Sdelphij 2873247880Sdelphij if(sc->qnqid) { 2874247880Sdelphij m = ether_vlanencap(m, sc->qnqid); 2875338938Sjpaetzel 2876338938Sjpaetzel if (complete) 2877338938Sjpaetzel *complete = FALSE; 2878247880Sdelphij } 2879247880Sdelphij return m; 2880247880Sdelphij} 2881247880Sdelphij 2882247880Sdelphijstatic int 2883247880Sdelphijoce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m) 2884247880Sdelphij{ 2885247880Sdelphij if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \ 2886247880Sdelphij oce_check_ipv6_ext_hdr(m)) { 2887247880Sdelphij return TRUE; 2888247880Sdelphij } 2889247880Sdelphij return FALSE; 2890247880Sdelphij} 2891252869Sdelphij 2892252869Sdelphijstatic void 2893252869Sdelphijoce_get_config(POCE_SOFTC sc) 2894252869Sdelphij{ 2895252869Sdelphij int rc = 0; 2896252869Sdelphij uint32_t max_rss = 0; 2897252869Sdelphij 2898252869Sdelphij if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native)) 2899252869Sdelphij max_rss = OCE_LEGACY_MODE_RSS; 2900252869Sdelphij else 2901252869Sdelphij max_rss = OCE_MAX_RSS; 2902252869Sdelphij 2903252869Sdelphij if (!IS_BE(sc)) { 2904258941Sdelphij rc = oce_get_profile_config(sc, max_rss); 2905252869Sdelphij if (rc) { 2906252869Sdelphij sc->nwqs = OCE_MAX_WQ; 2907252869Sdelphij sc->nrssqs = max_rss; 2908252869Sdelphij sc->nrqs = sc->nrssqs + 1; 2909252869Sdelphij } 2910252869Sdelphij } 2911258941Sdelphij else { /* For BE3 don't rely on fw for determining the resources */ 2912252869Sdelphij sc->nrssqs = max_rss; 2913252869Sdelphij sc->nrqs = sc->nrssqs + 1; 2914258941Sdelphij sc->nwqs = OCE_MAX_WQ; 2915258941Sdelphij sc->max_vlans = MAX_VLANFILTER_SIZE; 2916252869Sdelphij } 2917252869Sdelphij} 2918338938Sjpaetzel 2919338938Sjpaetzelstatic void 2920338938Sjpaetzeloce_rdma_close(void) 2921338938Sjpaetzel{ 2922338938Sjpaetzel if (oce_rdma_if != NULL) { 2923338938Sjpaetzel oce_rdma_if = NULL; 2924338938Sjpaetzel } 2925338938Sjpaetzel} 2926338938Sjpaetzel 2927338938Sjpaetzelstatic void 2928338938Sjpaetzeloce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr) 2929338938Sjpaetzel{ 2930338938Sjpaetzel memcpy(macaddr, sc->macaddr.mac_addr, 6); 2931338938Sjpaetzel} 2932338938Sjpaetzel 2933338938Sjpaetzelint 2934338938Sjpaetzeloce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if) 2935338938Sjpaetzel{ 2936338938Sjpaetzel POCE_SOFTC sc; 2937338938Sjpaetzel struct oce_dev_info di; 2938338938Sjpaetzel int i; 2939338938Sjpaetzel 2940338938Sjpaetzel if ((rdma_info == NULL) || (rdma_if == NULL)) { 2941338938Sjpaetzel return -EINVAL; 2942338938Sjpaetzel } 2943338938Sjpaetzel 2944338938Sjpaetzel if ((rdma_info->size != OCE_RDMA_INFO_SIZE) || 2945338938Sjpaetzel (rdma_if->size != OCE_RDMA_IF_SIZE)) { 2946338938Sjpaetzel return -ENXIO; 2947338938Sjpaetzel } 2948338938Sjpaetzel 2949338938Sjpaetzel rdma_info->close = oce_rdma_close; 2950338938Sjpaetzel rdma_info->mbox_post = oce_mbox_post; 2951338938Sjpaetzel rdma_info->common_req_hdr_init = mbx_common_req_hdr_init; 2952338938Sjpaetzel rdma_info->get_mac_addr = oce_get_mac_addr; 2953338938Sjpaetzel 2954338938Sjpaetzel oce_rdma_if = rdma_if; 2955338938Sjpaetzel 2956338938Sjpaetzel sc = softc_head; 2957338938Sjpaetzel while (sc != NULL) { 2958338938Sjpaetzel if (oce_rdma_if->announce != NULL) { 2959338938Sjpaetzel memset(&di, 0, sizeof(di)); 2960338938Sjpaetzel di.dev = sc->dev; 2961338938Sjpaetzel di.softc = sc; 2962338938Sjpaetzel di.ifp = sc->ifp; 2963338938Sjpaetzel di.db_bhandle = sc->db_bhandle; 2964338938Sjpaetzel di.db_btag = sc->db_btag; 2965338938Sjpaetzel di.db_page_size = 4096; 2966338938Sjpaetzel if (sc->flags & OCE_FLAGS_USING_MSIX) { 2967338938Sjpaetzel di.intr_mode = OCE_INTERRUPT_MODE_MSIX; 2968338938Sjpaetzel } else if (sc->flags & OCE_FLAGS_USING_MSI) { 2969338938Sjpaetzel di.intr_mode = OCE_INTERRUPT_MODE_MSI; 2970338938Sjpaetzel } else { 2971338938Sjpaetzel di.intr_mode = OCE_INTERRUPT_MODE_INTX; 2972338938Sjpaetzel } 2973338938Sjpaetzel di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk 2974338938Sjpaetzel if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) { 2975338938Sjpaetzel di.msix.num_vectors = sc->intr_count + sc->roce_intr_count; 2976338938Sjpaetzel di.msix.start_vector = sc->intr_count; 2977338938Sjpaetzel for (i=0; i<di.msix.num_vectors; i++) { 2978338938Sjpaetzel di.msix.vector_list[i] = sc->intrs[i].vector; 2979338938Sjpaetzel } 2980338938Sjpaetzel } else { 2981338938Sjpaetzel } 2982338938Sjpaetzel memcpy(di.mac_addr, sc->macaddr.mac_addr, 6); 2983338938Sjpaetzel di.vendor_id = pci_get_vendor(sc->dev); 2984338938Sjpaetzel di.dev_id = pci_get_device(sc->dev); 2985338938Sjpaetzel 2986338938Sjpaetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 2987338938Sjpaetzel di.flags |= OCE_RDMA_INFO_RDMA_SUPPORTED; 2988338938Sjpaetzel } 2989338938Sjpaetzel 2990338938Sjpaetzel rdma_if->announce(&di); 2991338938Sjpaetzel sc = sc->next; 2992338938Sjpaetzel } 2993338938Sjpaetzel } 2994338938Sjpaetzel 2995338938Sjpaetzel return 0; 2996338938Sjpaetzel} 2997338938Sjpaetzel 2998338938Sjpaetzelstatic void 2999338938Sjpaetzeloce_read_env_variables( POCE_SOFTC sc ) 3000338938Sjpaetzel{ 3001338938Sjpaetzel char *value = NULL; 3002338938Sjpaetzel int rc = 0; 3003338938Sjpaetzel 3004338938Sjpaetzel /* read if user wants to enable hwlro or swlro */ 3005338938Sjpaetzel //value = getenv("oce_enable_hwlro"); 3006338938Sjpaetzel if(value && IS_SH(sc)) { 3007338938Sjpaetzel sc->enable_hwlro = strtol(value, NULL, 10); 3008338938Sjpaetzel if(sc->enable_hwlro) { 3009338938Sjpaetzel rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL); 3010338938Sjpaetzel if(rc) { 3011338938Sjpaetzel device_printf(sc->dev, "no hardware lro support\n"); 3012338938Sjpaetzel device_printf(sc->dev, "software lro enabled\n"); 3013338938Sjpaetzel sc->enable_hwlro = 0; 3014338938Sjpaetzel }else { 3015338938Sjpaetzel device_printf(sc->dev, "hardware lro enabled\n"); 3016338938Sjpaetzel oce_max_rsp_handled = 32; 3017338938Sjpaetzel } 3018338938Sjpaetzel }else { 3019338938Sjpaetzel device_printf(sc->dev, "software lro enabled\n"); 3020338938Sjpaetzel } 3021338938Sjpaetzel }else { 3022338938Sjpaetzel sc->enable_hwlro = 0; 3023338938Sjpaetzel } 3024338938Sjpaetzel 3025338938Sjpaetzel /* read mbuf size */ 3026338938Sjpaetzel //value = getenv("oce_rq_buf_size"); 3027338938Sjpaetzel if(value && IS_SH(sc)) { 3028338938Sjpaetzel oce_rq_buf_size = strtol(value, NULL, 10); 3029338938Sjpaetzel switch(oce_rq_buf_size) { 3030338938Sjpaetzel case 2048: 3031338938Sjpaetzel case 4096: 3032338938Sjpaetzel case 9216: 3033338938Sjpaetzel case 16384: 3034338938Sjpaetzel break; 3035338938Sjpaetzel 3036338938Sjpaetzel default: 3037338938Sjpaetzel device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n"); 3038338938Sjpaetzel oce_rq_buf_size = 2048; 3039338938Sjpaetzel } 3040338938Sjpaetzel } 3041338938Sjpaetzel 3042338938Sjpaetzel return; 3043338938Sjpaetzel} 3044