12f345d8eSLuigi Rizzo /*- 27282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 37282444bSPedro F. Giffuni * 4291a1934SXin LI * Copyright (C) 2013 Emulex 52f345d8eSLuigi Rizzo * All rights reserved. 62f345d8eSLuigi Rizzo * 72f345d8eSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 82f345d8eSLuigi Rizzo * modification, are permitted provided that the following conditions are met: 92f345d8eSLuigi Rizzo * 102f345d8eSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright notice, 112f345d8eSLuigi Rizzo * this list of conditions and the following disclaimer. 122f345d8eSLuigi Rizzo * 132f345d8eSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 142f345d8eSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 152f345d8eSLuigi Rizzo * documentation and/or other materials provided with the distribution. 162f345d8eSLuigi Rizzo * 172f345d8eSLuigi Rizzo * 3. Neither the name of the Emulex Corporation nor the names of its 182f345d8eSLuigi Rizzo * contributors may be used to endorse or promote products derived from 192f345d8eSLuigi Rizzo * this software without specific prior written permission. 202f345d8eSLuigi Rizzo * 212f345d8eSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 222f345d8eSLuigi Rizzo * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 232f345d8eSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 242f345d8eSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 252f345d8eSLuigi Rizzo * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 262f345d8eSLuigi Rizzo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 272f345d8eSLuigi Rizzo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 282f345d8eSLuigi Rizzo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 292f345d8eSLuigi Rizzo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 302f345d8eSLuigi Rizzo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 312f345d8eSLuigi Rizzo * POSSIBILITY OF SUCH DAMAGE. 322f345d8eSLuigi Rizzo * 332f345d8eSLuigi Rizzo * Contact Information: 342f345d8eSLuigi Rizzo * freebsd-drivers@emulex.com 352f345d8eSLuigi Rizzo * 362f345d8eSLuigi Rizzo * Emulex 372f345d8eSLuigi Rizzo * 3333 Susan Street 382f345d8eSLuigi Rizzo * Costa Mesa, CA 92626 392f345d8eSLuigi Rizzo */ 402f345d8eSLuigi Rizzo 412f345d8eSLuigi Rizzo /* $FreeBSD$ */ 422f345d8eSLuigi Rizzo 43ad512958SBjoern A. Zeeb #include "opt_inet6.h" 44ad512958SBjoern A. Zeeb #include "opt_inet.h" 45ad512958SBjoern A. Zeeb 462f345d8eSLuigi Rizzo #include "oce_if.h" 47c2625e6eSJosh Paetzel #include "oce_user.h" 48c2625e6eSJosh Paetzel 49c2625e6eSJosh Paetzel #define is_tso_pkt(m) (m->m_pkthdr.csum_flags & CSUM_TSO) 502f345d8eSLuigi Rizzo 515fbb6830SXin LI /* UE Status Low CSR */ 525fbb6830SXin LI static char *ue_status_low_desc[] = { 535fbb6830SXin LI "CEV", 545fbb6830SXin LI "CTX", 555fbb6830SXin LI "DBUF", 565fbb6830SXin LI "ERX", 575fbb6830SXin LI "Host", 585fbb6830SXin LI "MPU", 595fbb6830SXin LI "NDMA", 605fbb6830SXin LI "PTC ", 615fbb6830SXin LI "RDMA ", 625fbb6830SXin LI "RXF ", 635fbb6830SXin LI "RXIPS ", 645fbb6830SXin LI "RXULP0 ", 655fbb6830SXin LI "RXULP1 ", 665fbb6830SXin LI "RXULP2 ", 675fbb6830SXin LI "TIM ", 685fbb6830SXin LI "TPOST ", 695fbb6830SXin LI "TPRE ", 705fbb6830SXin LI "TXIPS ", 715fbb6830SXin LI "TXULP0 ", 725fbb6830SXin LI "TXULP1 ", 735fbb6830SXin LI "UC ", 745fbb6830SXin LI "WDMA ", 755fbb6830SXin LI "TXULP2 ", 765fbb6830SXin LI "HOST1 ", 775fbb6830SXin LI "P0_OB_LINK ", 785fbb6830SXin LI "P1_OB_LINK ", 795fbb6830SXin LI "HOST_GPIO ", 805fbb6830SXin LI "MBOX ", 815fbb6830SXin LI "AXGMAC0", 825fbb6830SXin LI "AXGMAC1", 835fbb6830SXin LI "JTAG", 845fbb6830SXin LI "MPU_INTPEND" 855fbb6830SXin LI }; 865fbb6830SXin LI 875fbb6830SXin LI /* UE Status High CSR */ 885fbb6830SXin LI static char *ue_status_hi_desc[] = { 895fbb6830SXin LI "LPCMEMHOST", 905fbb6830SXin LI "MGMT_MAC", 915fbb6830SXin LI "PCS0ONLINE", 925fbb6830SXin LI "MPU_IRAM", 935fbb6830SXin LI "PCS1ONLINE", 945fbb6830SXin LI "PCTL0", 955fbb6830SXin LI "PCTL1", 965fbb6830SXin LI "PMEM", 975fbb6830SXin LI "RR", 985fbb6830SXin LI "TXPB", 995fbb6830SXin LI "RXPP", 1005fbb6830SXin LI "XAUI", 1015fbb6830SXin LI "TXP", 1025fbb6830SXin LI "ARM", 1035fbb6830SXin LI "IPC", 1045fbb6830SXin LI "HOST2", 1055fbb6830SXin LI "HOST3", 1065fbb6830SXin LI "HOST4", 1075fbb6830SXin LI "HOST5", 1085fbb6830SXin LI "HOST6", 1095fbb6830SXin LI "HOST7", 1105fbb6830SXin LI "HOST8", 1115fbb6830SXin LI "HOST9", 1125fbb6830SXin LI "NETC", 1135fbb6830SXin LI "Unknown", 1145fbb6830SXin LI "Unknown", 1155fbb6830SXin LI "Unknown", 1165fbb6830SXin LI "Unknown", 1175fbb6830SXin LI "Unknown", 1185fbb6830SXin LI "Unknown", 1195fbb6830SXin LI "Unknown", 1205fbb6830SXin LI "Unknown" 1215fbb6830SXin LI }; 1225fbb6830SXin LI 123c2625e6eSJosh Paetzel struct oce_common_cqe_info{ 124c2625e6eSJosh Paetzel uint8_t vtp:1; 125c2625e6eSJosh Paetzel uint8_t l4_cksum_pass:1; 126c2625e6eSJosh Paetzel uint8_t ip_cksum_pass:1; 127c2625e6eSJosh Paetzel uint8_t ipv6_frame:1; 128c2625e6eSJosh Paetzel uint8_t qnq:1; 129c2625e6eSJosh Paetzel uint8_t rsvd:3; 130c2625e6eSJosh Paetzel uint8_t num_frags; 131c2625e6eSJosh Paetzel uint16_t pkt_size; 132c2625e6eSJosh Paetzel uint16_t vtag; 133c2625e6eSJosh Paetzel }; 134c2625e6eSJosh Paetzel 1352f345d8eSLuigi Rizzo 1362f345d8eSLuigi Rizzo /* Driver entry points prototypes */ 1372f345d8eSLuigi Rizzo static int oce_probe(device_t dev); 1382f345d8eSLuigi Rizzo static int oce_attach(device_t dev); 1392f345d8eSLuigi Rizzo static int oce_detach(device_t dev); 1402f345d8eSLuigi Rizzo static int oce_shutdown(device_t dev); 1412f345d8eSLuigi Rizzo static int oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 1422f345d8eSLuigi Rizzo static void oce_init(void *xsc); 1432f345d8eSLuigi Rizzo static int oce_multiq_start(struct ifnet *ifp, struct mbuf *m); 1442f345d8eSLuigi Rizzo static void oce_multiq_flush(struct ifnet *ifp); 1452f345d8eSLuigi Rizzo 1462f345d8eSLuigi Rizzo /* Driver interrupt routines protypes */ 1472f345d8eSLuigi Rizzo static void oce_intr(void *arg, int pending); 1482f345d8eSLuigi Rizzo static int oce_setup_intr(POCE_SOFTC sc); 1492f345d8eSLuigi Rizzo static int oce_fast_isr(void *arg); 1502f345d8eSLuigi Rizzo static int oce_alloc_intr(POCE_SOFTC sc, int vector, 1512f345d8eSLuigi Rizzo void (*isr) (void *arg, int pending)); 1522f345d8eSLuigi Rizzo 1532f345d8eSLuigi Rizzo /* Media callbacks prototypes */ 1542f345d8eSLuigi Rizzo static void oce_media_status(struct ifnet *ifp, struct ifmediareq *req); 1552f345d8eSLuigi Rizzo static int oce_media_change(struct ifnet *ifp); 1562f345d8eSLuigi Rizzo 1572f345d8eSLuigi Rizzo /* Transmit routines prototypes */ 1582f345d8eSLuigi Rizzo static int oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index); 1592f345d8eSLuigi Rizzo static void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq); 160c2625e6eSJosh Paetzel static void oce_process_tx_completion(struct oce_wq *wq); 1612f345d8eSLuigi Rizzo static int oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, 1622f345d8eSLuigi Rizzo struct oce_wq *wq); 1632f345d8eSLuigi Rizzo 1642f345d8eSLuigi Rizzo /* Receive routines prototypes */ 1652f345d8eSLuigi Rizzo static int oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 1662f345d8eSLuigi Rizzo static int oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 167c2625e6eSJosh Paetzel static void oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); 168c2625e6eSJosh Paetzel static void oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq); 169c2625e6eSJosh Paetzel static uint16_t oce_rq_handler_lro(void *arg); 170c2625e6eSJosh Paetzel static void oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2); 171c2625e6eSJosh Paetzel static void oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2); 172c2625e6eSJosh Paetzel static void oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m); 1732f345d8eSLuigi Rizzo 1742f345d8eSLuigi Rizzo /* Helper function prototypes in this file */ 1752f345d8eSLuigi Rizzo static int oce_attach_ifp(POCE_SOFTC sc); 1762f345d8eSLuigi Rizzo static void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 1772f345d8eSLuigi Rizzo static void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 1782f345d8eSLuigi Rizzo static int oce_vid_config(POCE_SOFTC sc); 1792f345d8eSLuigi Rizzo static void oce_mac_addr_set(POCE_SOFTC sc); 1802f345d8eSLuigi Rizzo static int oce_handle_passthrough(struct ifnet *ifp, caddr_t data); 1812f345d8eSLuigi Rizzo static void oce_local_timer(void *arg); 1822f345d8eSLuigi Rizzo static void oce_if_deactivate(POCE_SOFTC sc); 1832f345d8eSLuigi Rizzo static void oce_if_activate(POCE_SOFTC sc); 1842f345d8eSLuigi Rizzo static void setup_max_queues_want(POCE_SOFTC sc); 1852f345d8eSLuigi Rizzo static void update_queues_got(POCE_SOFTC sc); 1869bd3250aSLuigi Rizzo static void process_link_state(POCE_SOFTC sc, 1879bd3250aSLuigi Rizzo struct oce_async_cqe_link_state *acqe); 188cdaba892SXin LI static int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m); 189291a1934SXin LI static void oce_get_config(POCE_SOFTC sc); 190cdaba892SXin LI static struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete); 191c2625e6eSJosh Paetzel static void oce_read_env_variables(POCE_SOFTC sc); 192c2625e6eSJosh Paetzel 1939bd3250aSLuigi Rizzo 1949bd3250aSLuigi Rizzo /* IP specific */ 1959bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET) 1969bd3250aSLuigi Rizzo static int oce_init_lro(POCE_SOFTC sc); 1979bd3250aSLuigi Rizzo static struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp); 1989bd3250aSLuigi Rizzo #endif 1992f345d8eSLuigi Rizzo 2002f345d8eSLuigi Rizzo static device_method_t oce_dispatch[] = { 2012f345d8eSLuigi Rizzo DEVMETHOD(device_probe, oce_probe), 2022f345d8eSLuigi Rizzo DEVMETHOD(device_attach, oce_attach), 2032f345d8eSLuigi Rizzo DEVMETHOD(device_detach, oce_detach), 2042f345d8eSLuigi Rizzo DEVMETHOD(device_shutdown, oce_shutdown), 20561bfd867SSofian Brabez 20661bfd867SSofian Brabez DEVMETHOD_END 2072f345d8eSLuigi Rizzo }; 2082f345d8eSLuigi Rizzo 2092f345d8eSLuigi Rizzo static driver_t oce_driver = { 2102f345d8eSLuigi Rizzo "oce", 2112f345d8eSLuigi Rizzo oce_dispatch, 2122f345d8eSLuigi Rizzo sizeof(OCE_SOFTC) 2132f345d8eSLuigi Rizzo }; 2142f345d8eSLuigi Rizzo static devclass_t oce_devclass; 2152f345d8eSLuigi Rizzo 2162f345d8eSLuigi Rizzo 2172f345d8eSLuigi Rizzo /* global vars */ 2182f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"}; 2192f345d8eSLuigi Rizzo 2202f345d8eSLuigi Rizzo /* Module capabilites and parameters */ 2212f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED; 2222f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS; 223c2625e6eSJosh Paetzel uint32_t oce_rq_buf_size = 2048; 2242f345d8eSLuigi Rizzo 2252f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled); 2262f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss); 2272f345d8eSLuigi Rizzo 2282f345d8eSLuigi Rizzo 2292f345d8eSLuigi Rizzo /* Supported devices table */ 2302f345d8eSLuigi Rizzo static uint32_t supportedDevices[] = { 2312f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2, 2322f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3, 2332f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3, 2342f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201, 2352f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF, 236291a1934SXin LI (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH 2372f345d8eSLuigi Rizzo }; 2382f345d8eSLuigi Rizzo 239*0dc34160SWarner Losh 240*0dc34160SWarner Losh DRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0); 241*0dc34160SWarner Losh MODULE_PNP_INFO("W32:vendor/device", pci, oce, supportedDevices, 242*0dc34160SWarner Losh nitems(supportedDevices)); 243*0dc34160SWarner Losh MODULE_DEPEND(oce, pci, 1, 1, 1); 244*0dc34160SWarner Losh MODULE_DEPEND(oce, ether, 1, 1, 1); 245*0dc34160SWarner Losh MODULE_VERSION(oce, 1); 246*0dc34160SWarner Losh 247*0dc34160SWarner Losh 248c2625e6eSJosh Paetzel POCE_SOFTC softc_head = NULL; 249c2625e6eSJosh Paetzel POCE_SOFTC softc_tail = NULL; 2502f345d8eSLuigi Rizzo 251c2625e6eSJosh Paetzel struct oce_rdma_if *oce_rdma_if = NULL; 2522f345d8eSLuigi Rizzo 2532f345d8eSLuigi Rizzo /***************************************************************************** 2542f345d8eSLuigi Rizzo * Driver entry points functions * 2552f345d8eSLuigi Rizzo *****************************************************************************/ 2562f345d8eSLuigi Rizzo 2572f345d8eSLuigi Rizzo static int 2582f345d8eSLuigi Rizzo oce_probe(device_t dev) 2592f345d8eSLuigi Rizzo { 2609bd3250aSLuigi Rizzo uint16_t vendor = 0; 2619bd3250aSLuigi Rizzo uint16_t device = 0; 2629bd3250aSLuigi Rizzo int i = 0; 2639bd3250aSLuigi Rizzo char str[256] = {0}; 2642f345d8eSLuigi Rizzo POCE_SOFTC sc; 2652f345d8eSLuigi Rizzo 2662f345d8eSLuigi Rizzo sc = device_get_softc(dev); 2672f345d8eSLuigi Rizzo bzero(sc, sizeof(OCE_SOFTC)); 2682f345d8eSLuigi Rizzo sc->dev = dev; 2692f345d8eSLuigi Rizzo 2702f345d8eSLuigi Rizzo vendor = pci_get_vendor(dev); 2712f345d8eSLuigi Rizzo device = pci_get_device(dev); 2722f345d8eSLuigi Rizzo 2739bd3250aSLuigi Rizzo for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) { 2742f345d8eSLuigi Rizzo if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) { 2752f345d8eSLuigi Rizzo if (device == (supportedDevices[i] & 0xffff)) { 2769bd3250aSLuigi Rizzo sprintf(str, "%s:%s", "Emulex CNA NIC function", 2772f345d8eSLuigi Rizzo component_revision); 2782f345d8eSLuigi Rizzo device_set_desc_copy(dev, str); 2792f345d8eSLuigi Rizzo 2802f345d8eSLuigi Rizzo switch (device) { 2812f345d8eSLuigi Rizzo case PCI_PRODUCT_BE2: 2822f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE2; 2832f345d8eSLuigi Rizzo break; 2842f345d8eSLuigi Rizzo case PCI_PRODUCT_BE3: 2852f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE3; 2862f345d8eSLuigi Rizzo break; 2872f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201: 2882f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201_VF: 2892f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_XE201; 2902f345d8eSLuigi Rizzo break; 291291a1934SXin LI case PCI_PRODUCT_SH: 292291a1934SXin LI sc->flags |= OCE_FLAGS_SH; 293291a1934SXin LI break; 2942f345d8eSLuigi Rizzo default: 2952f345d8eSLuigi Rizzo return ENXIO; 2962f345d8eSLuigi Rizzo } 2972f345d8eSLuigi Rizzo return BUS_PROBE_DEFAULT; 2982f345d8eSLuigi Rizzo } 2992f345d8eSLuigi Rizzo } 3002f345d8eSLuigi Rizzo } 3012f345d8eSLuigi Rizzo 3022f345d8eSLuigi Rizzo return ENXIO; 3032f345d8eSLuigi Rizzo } 3042f345d8eSLuigi Rizzo 3052f345d8eSLuigi Rizzo 3062f345d8eSLuigi Rizzo static int 3072f345d8eSLuigi Rizzo oce_attach(device_t dev) 3082f345d8eSLuigi Rizzo { 3092f345d8eSLuigi Rizzo POCE_SOFTC sc; 3102f345d8eSLuigi Rizzo int rc = 0; 3112f345d8eSLuigi Rizzo 3122f345d8eSLuigi Rizzo sc = device_get_softc(dev); 3132f345d8eSLuigi Rizzo 3142f345d8eSLuigi Rizzo rc = oce_hw_pci_alloc(sc); 3152f345d8eSLuigi Rizzo if (rc) 3162f345d8eSLuigi Rizzo return rc; 3172f345d8eSLuigi Rizzo 3182f345d8eSLuigi Rizzo sc->tx_ring_size = OCE_TX_RING_SIZE; 3192f345d8eSLuigi Rizzo sc->rx_ring_size = OCE_RX_RING_SIZE; 320c2625e6eSJosh Paetzel /* receive fragment size should be multiple of 2K */ 321c2625e6eSJosh Paetzel sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048); 3222f345d8eSLuigi Rizzo sc->flow_control = OCE_DEFAULT_FLOW_CONTROL; 3232f345d8eSLuigi Rizzo sc->promisc = OCE_DEFAULT_PROMISCUOUS; 3242f345d8eSLuigi Rizzo 3252f345d8eSLuigi Rizzo LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock"); 3262f345d8eSLuigi Rizzo LOCK_CREATE(&sc->dev_lock, "Device_lock"); 3272f345d8eSLuigi Rizzo 3282f345d8eSLuigi Rizzo /* initialise the hardware */ 3292f345d8eSLuigi Rizzo rc = oce_hw_init(sc); 3302f345d8eSLuigi Rizzo if (rc) 3312f345d8eSLuigi Rizzo goto pci_res_free; 3322f345d8eSLuigi Rizzo 333c2625e6eSJosh Paetzel oce_read_env_variables(sc); 334c2625e6eSJosh Paetzel 335291a1934SXin LI oce_get_config(sc); 336291a1934SXin LI 3372f345d8eSLuigi Rizzo setup_max_queues_want(sc); 3382f345d8eSLuigi Rizzo 3392f345d8eSLuigi Rizzo rc = oce_setup_intr(sc); 3402f345d8eSLuigi Rizzo if (rc) 3412f345d8eSLuigi Rizzo goto mbox_free; 3422f345d8eSLuigi Rizzo 3432f345d8eSLuigi Rizzo rc = oce_queue_init_all(sc); 3442f345d8eSLuigi Rizzo if (rc) 3452f345d8eSLuigi Rizzo goto intr_free; 3462f345d8eSLuigi Rizzo 3472f345d8eSLuigi Rizzo rc = oce_attach_ifp(sc); 3482f345d8eSLuigi Rizzo if (rc) 3492f345d8eSLuigi Rizzo goto queues_free; 3502f345d8eSLuigi Rizzo 351ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 3522f345d8eSLuigi Rizzo rc = oce_init_lro(sc); 3532f345d8eSLuigi Rizzo if (rc) 3542f345d8eSLuigi Rizzo goto ifp_free; 355ad512958SBjoern A. Zeeb #endif 3562f345d8eSLuigi Rizzo 3572f345d8eSLuigi Rizzo rc = oce_hw_start(sc); 3582f345d8eSLuigi Rizzo if (rc) 359db702c59SEitan Adler goto lro_free; 3602f345d8eSLuigi Rizzo 3612f345d8eSLuigi Rizzo sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 3622f345d8eSLuigi Rizzo oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST); 3632f345d8eSLuigi Rizzo sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 3642f345d8eSLuigi Rizzo oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST); 3652f345d8eSLuigi Rizzo 3662f345d8eSLuigi Rizzo rc = oce_stats_init(sc); 3672f345d8eSLuigi Rizzo if (rc) 3682f345d8eSLuigi Rizzo goto vlan_free; 3692f345d8eSLuigi Rizzo 3702f345d8eSLuigi Rizzo oce_add_sysctls(sc); 3712f345d8eSLuigi Rizzo 372c2625e6eSJosh Paetzel callout_init(&sc->timer, CALLOUT_MPSAFE); 3732f345d8eSLuigi Rizzo rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc); 3742f345d8eSLuigi Rizzo if (rc) 3752f345d8eSLuigi Rizzo goto stats_free; 3762f345d8eSLuigi Rizzo 377c2625e6eSJosh Paetzel sc->next =NULL; 378c2625e6eSJosh Paetzel if (softc_tail != NULL) { 379c2625e6eSJosh Paetzel softc_tail->next = sc; 380c2625e6eSJosh Paetzel } else { 381c2625e6eSJosh Paetzel softc_head = sc; 382c2625e6eSJosh Paetzel } 383c2625e6eSJosh Paetzel softc_tail = sc; 384c2625e6eSJosh Paetzel 3852f345d8eSLuigi Rizzo return 0; 3862f345d8eSLuigi Rizzo 3872f345d8eSLuigi Rizzo stats_free: 3882f345d8eSLuigi Rizzo callout_drain(&sc->timer); 3892f345d8eSLuigi Rizzo oce_stats_free(sc); 3902f345d8eSLuigi Rizzo vlan_free: 3912f345d8eSLuigi Rizzo if (sc->vlan_attach) 3922f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 3932f345d8eSLuigi Rizzo if (sc->vlan_detach) 3942f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 3952f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 3962f345d8eSLuigi Rizzo lro_free: 397ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 3982f345d8eSLuigi Rizzo oce_free_lro(sc); 3992f345d8eSLuigi Rizzo ifp_free: 400ad512958SBjoern A. Zeeb #endif 4012f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp); 4022f345d8eSLuigi Rizzo if_free(sc->ifp); 4032f345d8eSLuigi Rizzo queues_free: 4042f345d8eSLuigi Rizzo oce_queue_release_all(sc); 4052f345d8eSLuigi Rizzo intr_free: 4062f345d8eSLuigi Rizzo oce_intr_free(sc); 4072f345d8eSLuigi Rizzo mbox_free: 4082f345d8eSLuigi Rizzo oce_dma_free(sc, &sc->bsmbx); 4092f345d8eSLuigi Rizzo pci_res_free: 4102f345d8eSLuigi Rizzo oce_hw_pci_free(sc); 4112f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->dev_lock); 4122f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->bmbx_lock); 4132f345d8eSLuigi Rizzo return rc; 4142f345d8eSLuigi Rizzo 4152f345d8eSLuigi Rizzo } 4162f345d8eSLuigi Rizzo 4172f345d8eSLuigi Rizzo 4182f345d8eSLuigi Rizzo static int 4192f345d8eSLuigi Rizzo oce_detach(device_t dev) 4202f345d8eSLuigi Rizzo { 4212f345d8eSLuigi Rizzo POCE_SOFTC sc = device_get_softc(dev); 422c2625e6eSJosh Paetzel POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL; 423c2625e6eSJosh Paetzel 424c2625e6eSJosh Paetzel poce_sc_tmp = softc_head; 425c2625e6eSJosh Paetzel ppoce_sc_tmp1 = &softc_head; 426c2625e6eSJosh Paetzel while (poce_sc_tmp != NULL) { 427c2625e6eSJosh Paetzel if (poce_sc_tmp == sc) { 428c2625e6eSJosh Paetzel *ppoce_sc_tmp1 = sc->next; 429c2625e6eSJosh Paetzel if (sc->next == NULL) { 430c2625e6eSJosh Paetzel softc_tail = poce_sc_tmp2; 431c2625e6eSJosh Paetzel } 432c2625e6eSJosh Paetzel break; 433c2625e6eSJosh Paetzel } 434c2625e6eSJosh Paetzel poce_sc_tmp2 = poce_sc_tmp; 435c2625e6eSJosh Paetzel ppoce_sc_tmp1 = &poce_sc_tmp->next; 436c2625e6eSJosh Paetzel poce_sc_tmp = poce_sc_tmp->next; 437c2625e6eSJosh Paetzel } 4382f345d8eSLuigi Rizzo 4392f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 4402f345d8eSLuigi Rizzo oce_if_deactivate(sc); 4412f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 4422f345d8eSLuigi Rizzo 4432f345d8eSLuigi Rizzo callout_drain(&sc->timer); 4442f345d8eSLuigi Rizzo 4452f345d8eSLuigi Rizzo if (sc->vlan_attach != NULL) 4462f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 4472f345d8eSLuigi Rizzo if (sc->vlan_detach != NULL) 4482f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 4492f345d8eSLuigi Rizzo 4502f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp); 4512f345d8eSLuigi Rizzo 4522f345d8eSLuigi Rizzo if_free(sc->ifp); 4532f345d8eSLuigi Rizzo 4542f345d8eSLuigi Rizzo oce_hw_shutdown(sc); 4552f345d8eSLuigi Rizzo 4562f345d8eSLuigi Rizzo bus_generic_detach(dev); 4572f345d8eSLuigi Rizzo 4582f345d8eSLuigi Rizzo return 0; 4592f345d8eSLuigi Rizzo } 4602f345d8eSLuigi Rizzo 4612f345d8eSLuigi Rizzo 4622f345d8eSLuigi Rizzo static int 4632f345d8eSLuigi Rizzo oce_shutdown(device_t dev) 4642f345d8eSLuigi Rizzo { 4652f345d8eSLuigi Rizzo int rc; 4662f345d8eSLuigi Rizzo 4672f345d8eSLuigi Rizzo rc = oce_detach(dev); 4682f345d8eSLuigi Rizzo 4692f345d8eSLuigi Rizzo return rc; 4702f345d8eSLuigi Rizzo } 4712f345d8eSLuigi Rizzo 4722f345d8eSLuigi Rizzo 4732f345d8eSLuigi Rizzo static int 4742f345d8eSLuigi Rizzo oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 4752f345d8eSLuigi Rizzo { 4762f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data; 4772f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 4782f345d8eSLuigi Rizzo int rc = 0; 4792f345d8eSLuigi Rizzo uint32_t u; 4802f345d8eSLuigi Rizzo 4812f345d8eSLuigi Rizzo switch (command) { 4822f345d8eSLuigi Rizzo 4832f345d8eSLuigi Rizzo case SIOCGIFMEDIA: 4842f345d8eSLuigi Rizzo rc = ifmedia_ioctl(ifp, ifr, &sc->media, command); 4852f345d8eSLuigi Rizzo break; 4862f345d8eSLuigi Rizzo 4872f345d8eSLuigi Rizzo case SIOCSIFMTU: 4882f345d8eSLuigi Rizzo if (ifr->ifr_mtu > OCE_MAX_MTU) 4892f345d8eSLuigi Rizzo rc = EINVAL; 4902f345d8eSLuigi Rizzo else 4912f345d8eSLuigi Rizzo ifp->if_mtu = ifr->ifr_mtu; 4922f345d8eSLuigi Rizzo break; 4932f345d8eSLuigi Rizzo 4942f345d8eSLuigi Rizzo case SIOCSIFFLAGS: 4952f345d8eSLuigi Rizzo if (ifp->if_flags & IFF_UP) { 4962f345d8eSLuigi Rizzo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 4972f345d8eSLuigi Rizzo sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 4982f345d8eSLuigi Rizzo oce_init(sc); 4992f345d8eSLuigi Rizzo } 5002f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Up\n"); 5012f345d8eSLuigi Rizzo } else { 5022f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 5032f345d8eSLuigi Rizzo 5042f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= 5052f345d8eSLuigi Rizzo ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 5062f345d8eSLuigi Rizzo oce_if_deactivate(sc); 5072f345d8eSLuigi Rizzo 5082f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 5092f345d8eSLuigi Rizzo 5102f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Down\n"); 5112f345d8eSLuigi Rizzo } 5122f345d8eSLuigi Rizzo 5132f345d8eSLuigi Rizzo if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) { 5145fbb6830SXin LI if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1)))) 5152f345d8eSLuigi Rizzo sc->promisc = TRUE; 5162f345d8eSLuigi Rizzo } else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) { 5175fbb6830SXin LI if (!oce_rxf_set_promiscuous(sc, 0)) 5182f345d8eSLuigi Rizzo sc->promisc = FALSE; 5192f345d8eSLuigi Rizzo } 5202f345d8eSLuigi Rizzo 5212f345d8eSLuigi Rizzo break; 5222f345d8eSLuigi Rizzo 5232f345d8eSLuigi Rizzo case SIOCADDMULTI: 5242f345d8eSLuigi Rizzo case SIOCDELMULTI: 5252f345d8eSLuigi Rizzo rc = oce_hw_update_multicast(sc); 5262f345d8eSLuigi Rizzo if (rc) 5272f345d8eSLuigi Rizzo device_printf(sc->dev, 5282f345d8eSLuigi Rizzo "Update multicast address failed\n"); 5292f345d8eSLuigi Rizzo break; 5302f345d8eSLuigi Rizzo 5312f345d8eSLuigi Rizzo case SIOCSIFCAP: 5322f345d8eSLuigi Rizzo u = ifr->ifr_reqcap ^ ifp->if_capenable; 5332f345d8eSLuigi Rizzo 5342f345d8eSLuigi Rizzo if (u & IFCAP_TXCSUM) { 5352f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_TXCSUM; 5362f345d8eSLuigi Rizzo ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 5372f345d8eSLuigi Rizzo 5382f345d8eSLuigi Rizzo if (IFCAP_TSO & ifp->if_capenable && 5392f345d8eSLuigi Rizzo !(IFCAP_TXCSUM & ifp->if_capenable)) { 5402f345d8eSLuigi Rizzo ifp->if_capenable &= ~IFCAP_TSO; 5412f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5422f345d8eSLuigi Rizzo if_printf(ifp, 5432f345d8eSLuigi Rizzo "TSO disabled due to -txcsum.\n"); 5442f345d8eSLuigi Rizzo } 5452f345d8eSLuigi Rizzo } 5462f345d8eSLuigi Rizzo 5472f345d8eSLuigi Rizzo if (u & IFCAP_RXCSUM) 5482f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_RXCSUM; 5492f345d8eSLuigi Rizzo 5502f345d8eSLuigi Rizzo if (u & IFCAP_TSO4) { 5512f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_TSO4; 5522f345d8eSLuigi Rizzo 5532f345d8eSLuigi Rizzo if (IFCAP_TSO & ifp->if_capenable) { 5542f345d8eSLuigi Rizzo if (IFCAP_TXCSUM & ifp->if_capenable) 5552f345d8eSLuigi Rizzo ifp->if_hwassist |= CSUM_TSO; 5562f345d8eSLuigi Rizzo else { 5572f345d8eSLuigi Rizzo ifp->if_capenable &= ~IFCAP_TSO; 5582f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5592f345d8eSLuigi Rizzo if_printf(ifp, 5602f345d8eSLuigi Rizzo "Enable txcsum first.\n"); 5612f345d8eSLuigi Rizzo rc = EAGAIN; 5622f345d8eSLuigi Rizzo } 5632f345d8eSLuigi Rizzo } else 5642f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5652f345d8eSLuigi Rizzo } 5662f345d8eSLuigi Rizzo 5672f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWTAGGING) 5682f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 5692f345d8eSLuigi Rizzo 5702f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWFILTER) { 5712f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 5722f345d8eSLuigi Rizzo oce_vid_config(sc); 5732f345d8eSLuigi Rizzo } 574ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 575c2625e6eSJosh Paetzel if (u & IFCAP_LRO) { 5762f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_LRO; 577c2625e6eSJosh Paetzel if(sc->enable_hwlro) { 578c2625e6eSJosh Paetzel if(ifp->if_capenable & IFCAP_LRO) { 579c2625e6eSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 1); 580c2625e6eSJosh Paetzel }else { 581c2625e6eSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 0); 582c2625e6eSJosh Paetzel } 583c2625e6eSJosh Paetzel } 584c2625e6eSJosh Paetzel } 585ad512958SBjoern A. Zeeb #endif 5862f345d8eSLuigi Rizzo 5872f345d8eSLuigi Rizzo break; 5882f345d8eSLuigi Rizzo 5892f345d8eSLuigi Rizzo case SIOCGPRIVATE_0: 5902f345d8eSLuigi Rizzo rc = oce_handle_passthrough(ifp, data); 5912f345d8eSLuigi Rizzo break; 5922f345d8eSLuigi Rizzo default: 5932f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 5942f345d8eSLuigi Rizzo break; 5952f345d8eSLuigi Rizzo } 5962f345d8eSLuigi Rizzo 5972f345d8eSLuigi Rizzo return rc; 5982f345d8eSLuigi Rizzo } 5992f345d8eSLuigi Rizzo 6002f345d8eSLuigi Rizzo 6012f345d8eSLuigi Rizzo static void 6022f345d8eSLuigi Rizzo oce_init(void *arg) 6032f345d8eSLuigi Rizzo { 6042f345d8eSLuigi Rizzo POCE_SOFTC sc = arg; 6052f345d8eSLuigi Rizzo 6062f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 6072f345d8eSLuigi Rizzo 6082f345d8eSLuigi Rizzo if (sc->ifp->if_flags & IFF_UP) { 6092f345d8eSLuigi Rizzo oce_if_deactivate(sc); 6102f345d8eSLuigi Rizzo oce_if_activate(sc); 6112f345d8eSLuigi Rizzo } 6122f345d8eSLuigi Rizzo 6132f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 6142f345d8eSLuigi Rizzo 6152f345d8eSLuigi Rizzo } 6162f345d8eSLuigi Rizzo 6172f345d8eSLuigi Rizzo 6182f345d8eSLuigi Rizzo static int 6192f345d8eSLuigi Rizzo oce_multiq_start(struct ifnet *ifp, struct mbuf *m) 6202f345d8eSLuigi Rizzo { 6212f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 6222f345d8eSLuigi Rizzo struct oce_wq *wq = NULL; 6232f345d8eSLuigi Rizzo int queue_index = 0; 6242f345d8eSLuigi Rizzo int status = 0; 6252f345d8eSLuigi Rizzo 626c2625e6eSJosh Paetzel if (!sc->link_status) 627c2625e6eSJosh Paetzel return ENXIO; 628c2625e6eSJosh Paetzel 629c2529042SHans Petter Selasky if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 6302f345d8eSLuigi Rizzo queue_index = m->m_pkthdr.flowid % sc->nwqs; 6312f345d8eSLuigi Rizzo 6322f345d8eSLuigi Rizzo wq = sc->wq[queue_index]; 6332f345d8eSLuigi Rizzo 634291a1934SXin LI LOCK(&wq->tx_lock); 6352f345d8eSLuigi Rizzo status = oce_multiq_transmit(ifp, m, wq); 6362f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 637291a1934SXin LI 6382f345d8eSLuigi Rizzo return status; 6392f345d8eSLuigi Rizzo 6402f345d8eSLuigi Rizzo } 6412f345d8eSLuigi Rizzo 6422f345d8eSLuigi Rizzo 6432f345d8eSLuigi Rizzo static void 6442f345d8eSLuigi Rizzo oce_multiq_flush(struct ifnet *ifp) 6452f345d8eSLuigi Rizzo { 6462f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 6472f345d8eSLuigi Rizzo struct mbuf *m; 6482f345d8eSLuigi Rizzo int i = 0; 6492f345d8eSLuigi Rizzo 6502f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) { 6512f345d8eSLuigi Rizzo while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) 6522f345d8eSLuigi Rizzo m_freem(m); 6532f345d8eSLuigi Rizzo } 6542f345d8eSLuigi Rizzo if_qflush(ifp); 6552f345d8eSLuigi Rizzo } 6562f345d8eSLuigi Rizzo 6572f345d8eSLuigi Rizzo 6582f345d8eSLuigi Rizzo 6592f345d8eSLuigi Rizzo /***************************************************************************** 6602f345d8eSLuigi Rizzo * Driver interrupt routines functions * 6612f345d8eSLuigi Rizzo *****************************************************************************/ 6622f345d8eSLuigi Rizzo 6632f345d8eSLuigi Rizzo static void 6642f345d8eSLuigi Rizzo oce_intr(void *arg, int pending) 6652f345d8eSLuigi Rizzo { 6662f345d8eSLuigi Rizzo 6672f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 6682f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc; 6692f345d8eSLuigi Rizzo struct oce_eq *eq = ii->eq; 6702f345d8eSLuigi Rizzo struct oce_eqe *eqe; 6712f345d8eSLuigi Rizzo struct oce_cq *cq = NULL; 6722f345d8eSLuigi Rizzo int i, num_eqes = 0; 6732f345d8eSLuigi Rizzo 6742f345d8eSLuigi Rizzo 6752f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 6762f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 6772f345d8eSLuigi Rizzo do { 6782f345d8eSLuigi Rizzo eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 6792f345d8eSLuigi Rizzo if (eqe->evnt == 0) 6802f345d8eSLuigi Rizzo break; 6812f345d8eSLuigi Rizzo eqe->evnt = 0; 6822f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 6832f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 6842f345d8eSLuigi Rizzo RING_GET(eq->ring, 1); 6852f345d8eSLuigi Rizzo num_eqes++; 6862f345d8eSLuigi Rizzo 6872f345d8eSLuigi Rizzo } while (TRUE); 6882f345d8eSLuigi Rizzo 6892f345d8eSLuigi Rizzo if (!num_eqes) 6902f345d8eSLuigi Rizzo goto eq_arm; /* Spurious */ 6912f345d8eSLuigi Rizzo 6922f345d8eSLuigi Rizzo /* Clear EQ entries, but dont arm */ 6932f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE); 6942f345d8eSLuigi Rizzo 6952f345d8eSLuigi Rizzo /* Process TX, RX and MCC. But dont arm CQ*/ 6962f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) { 6972f345d8eSLuigi Rizzo cq = eq->cq[i]; 6982f345d8eSLuigi Rizzo (*cq->cq_handler)(cq->cb_arg); 6992f345d8eSLuigi Rizzo } 7002f345d8eSLuigi Rizzo 7012f345d8eSLuigi Rizzo /* Arm all cqs connected to this EQ */ 7022f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) { 7032f345d8eSLuigi Rizzo cq = eq->cq[i]; 7042f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, 0, TRUE); 7052f345d8eSLuigi Rizzo } 7062f345d8eSLuigi Rizzo 7072f345d8eSLuigi Rizzo eq_arm: 7082f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 709cdaba892SXin LI 7102f345d8eSLuigi Rizzo return; 7112f345d8eSLuigi Rizzo } 7122f345d8eSLuigi Rizzo 7132f345d8eSLuigi Rizzo 7142f345d8eSLuigi Rizzo static int 7152f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc) 7162f345d8eSLuigi Rizzo { 7172f345d8eSLuigi Rizzo int rc = 0, use_intx = 0; 7182f345d8eSLuigi Rizzo int vector = 0, req_vectors = 0; 719c2625e6eSJosh Paetzel int tot_req_vectors, tot_vectors; 7202f345d8eSLuigi Rizzo 721291a1934SXin LI if (is_rss_enabled(sc)) 7222f345d8eSLuigi Rizzo req_vectors = MAX((sc->nrqs - 1), sc->nwqs); 7232f345d8eSLuigi Rizzo else 7242f345d8eSLuigi Rizzo req_vectors = 1; 7252f345d8eSLuigi Rizzo 726c2625e6eSJosh Paetzel tot_req_vectors = req_vectors; 727c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 728c2625e6eSJosh Paetzel if (req_vectors > 1) { 729c2625e6eSJosh Paetzel tot_req_vectors += OCE_RDMA_VECTORS; 730c2625e6eSJosh Paetzel sc->roce_intr_count = OCE_RDMA_VECTORS; 731c2625e6eSJosh Paetzel } 732c2625e6eSJosh Paetzel } 733c2625e6eSJosh Paetzel 7342f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) { 7352f345d8eSLuigi Rizzo sc->intr_count = req_vectors; 736c2625e6eSJosh Paetzel tot_vectors = tot_req_vectors; 737c2625e6eSJosh Paetzel rc = pci_alloc_msix(sc->dev, &tot_vectors); 7382f345d8eSLuigi Rizzo if (rc != 0) { 7392f345d8eSLuigi Rizzo use_intx = 1; 7402f345d8eSLuigi Rizzo pci_release_msi(sc->dev); 741c2625e6eSJosh Paetzel } else { 742c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 743c2625e6eSJosh Paetzel if (tot_vectors < tot_req_vectors) { 744c2625e6eSJosh Paetzel if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) { 745c2625e6eSJosh Paetzel sc->roce_intr_count = (tot_vectors / 2); 746c2625e6eSJosh Paetzel } 747c2625e6eSJosh Paetzel sc->intr_count = tot_vectors - sc->roce_intr_count; 748c2625e6eSJosh Paetzel } 749c2625e6eSJosh Paetzel } else { 750c2625e6eSJosh Paetzel sc->intr_count = tot_vectors; 751c2625e6eSJosh Paetzel } 7522f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_USING_MSIX; 753c2625e6eSJosh Paetzel } 7542f345d8eSLuigi Rizzo } else 7552f345d8eSLuigi Rizzo use_intx = 1; 7562f345d8eSLuigi Rizzo 7572f345d8eSLuigi Rizzo if (use_intx) 7582f345d8eSLuigi Rizzo sc->intr_count = 1; 7592f345d8eSLuigi Rizzo 7602f345d8eSLuigi Rizzo /* Scale number of queues based on intr we got */ 7612f345d8eSLuigi Rizzo update_queues_got(sc); 7622f345d8eSLuigi Rizzo 7632f345d8eSLuigi Rizzo if (use_intx) { 7642f345d8eSLuigi Rizzo device_printf(sc->dev, "Using legacy interrupt\n"); 7652f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr); 7662f345d8eSLuigi Rizzo if (rc) 7672f345d8eSLuigi Rizzo goto error; 7682f345d8eSLuigi Rizzo } else { 7692f345d8eSLuigi Rizzo for (; vector < sc->intr_count; vector++) { 7702f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr); 7712f345d8eSLuigi Rizzo if (rc) 7722f345d8eSLuigi Rizzo goto error; 7732f345d8eSLuigi Rizzo } 7742f345d8eSLuigi Rizzo } 7752f345d8eSLuigi Rizzo 7762f345d8eSLuigi Rizzo return 0; 7772f345d8eSLuigi Rizzo error: 7782f345d8eSLuigi Rizzo oce_intr_free(sc); 7792f345d8eSLuigi Rizzo return rc; 7802f345d8eSLuigi Rizzo } 7812f345d8eSLuigi Rizzo 7822f345d8eSLuigi Rizzo 7832f345d8eSLuigi Rizzo static int 7842f345d8eSLuigi Rizzo oce_fast_isr(void *arg) 7852f345d8eSLuigi Rizzo { 7862f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 7872f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc; 7882f345d8eSLuigi Rizzo 7892f345d8eSLuigi Rizzo if (ii->eq == NULL) 7902f345d8eSLuigi Rizzo return FILTER_STRAY; 7912f345d8eSLuigi Rizzo 7922f345d8eSLuigi Rizzo oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE); 7932f345d8eSLuigi Rizzo 794cbc4d2dbSJohn Baldwin taskqueue_enqueue(ii->tq, &ii->task); 7952f345d8eSLuigi Rizzo 796cdaba892SXin LI ii->eq->intr++; 797cdaba892SXin LI 7982f345d8eSLuigi Rizzo return FILTER_HANDLED; 7992f345d8eSLuigi Rizzo } 8002f345d8eSLuigi Rizzo 8012f345d8eSLuigi Rizzo 8022f345d8eSLuigi Rizzo static int 8032f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) 8042f345d8eSLuigi Rizzo { 8052f345d8eSLuigi Rizzo POCE_INTR_INFO ii = &sc->intrs[vector]; 8062f345d8eSLuigi Rizzo int rc = 0, rr; 8072f345d8eSLuigi Rizzo 8082f345d8eSLuigi Rizzo if (vector >= OCE_MAX_EQ) 8092f345d8eSLuigi Rizzo return (EINVAL); 8102f345d8eSLuigi Rizzo 8112f345d8eSLuigi Rizzo /* Set the resource id for the interrupt. 8122f345d8eSLuigi Rizzo * MSIx is vector + 1 for the resource id, 8132f345d8eSLuigi Rizzo * INTx is 0 for the resource id. 8142f345d8eSLuigi Rizzo */ 8152f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX) 8162f345d8eSLuigi Rizzo rr = vector + 1; 8172f345d8eSLuigi Rizzo else 8182f345d8eSLuigi Rizzo rr = 0; 8192f345d8eSLuigi Rizzo ii->intr_res = bus_alloc_resource_any(sc->dev, 8202f345d8eSLuigi Rizzo SYS_RES_IRQ, 8212f345d8eSLuigi Rizzo &rr, RF_ACTIVE|RF_SHAREABLE); 8222f345d8eSLuigi Rizzo ii->irq_rr = rr; 8232f345d8eSLuigi Rizzo if (ii->intr_res == NULL) { 8242f345d8eSLuigi Rizzo device_printf(sc->dev, 8252f345d8eSLuigi Rizzo "Could not allocate interrupt\n"); 8262f345d8eSLuigi Rizzo rc = ENXIO; 8272f345d8eSLuigi Rizzo return rc; 8282f345d8eSLuigi Rizzo } 8292f345d8eSLuigi Rizzo 8302f345d8eSLuigi Rizzo TASK_INIT(&ii->task, 0, isr, ii); 8312f345d8eSLuigi Rizzo ii->vector = vector; 8322f345d8eSLuigi Rizzo sprintf(ii->task_name, "oce_task[%d]", ii->vector); 8332f345d8eSLuigi Rizzo ii->tq = taskqueue_create_fast(ii->task_name, 8342f345d8eSLuigi Rizzo M_NOWAIT, 8352f345d8eSLuigi Rizzo taskqueue_thread_enqueue, 8362f345d8eSLuigi Rizzo &ii->tq); 8372f345d8eSLuigi Rizzo taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq", 8382f345d8eSLuigi Rizzo device_get_nameunit(sc->dev)); 8392f345d8eSLuigi Rizzo 8402f345d8eSLuigi Rizzo ii->sc = sc; 8412f345d8eSLuigi Rizzo rc = bus_setup_intr(sc->dev, 8422f345d8eSLuigi Rizzo ii->intr_res, 8432f345d8eSLuigi Rizzo INTR_TYPE_NET, 8442f345d8eSLuigi Rizzo oce_fast_isr, NULL, ii, &ii->tag); 8452f345d8eSLuigi Rizzo return rc; 8462f345d8eSLuigi Rizzo 8472f345d8eSLuigi Rizzo } 8482f345d8eSLuigi Rizzo 8492f345d8eSLuigi Rizzo 8502f345d8eSLuigi Rizzo void 8512f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc) 8522f345d8eSLuigi Rizzo { 8532f345d8eSLuigi Rizzo int i = 0; 8542f345d8eSLuigi Rizzo 8552f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) { 8562f345d8eSLuigi Rizzo 8572f345d8eSLuigi Rizzo if (sc->intrs[i].tag != NULL) 8582f345d8eSLuigi Rizzo bus_teardown_intr(sc->dev, sc->intrs[i].intr_res, 8592f345d8eSLuigi Rizzo sc->intrs[i].tag); 8602f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) 8612f345d8eSLuigi Rizzo taskqueue_free(sc->intrs[i].tq); 8622f345d8eSLuigi Rizzo 8632f345d8eSLuigi Rizzo if (sc->intrs[i].intr_res != NULL) 8642f345d8eSLuigi Rizzo bus_release_resource(sc->dev, SYS_RES_IRQ, 8652f345d8eSLuigi Rizzo sc->intrs[i].irq_rr, 8662f345d8eSLuigi Rizzo sc->intrs[i].intr_res); 8672f345d8eSLuigi Rizzo sc->intrs[i].tag = NULL; 8682f345d8eSLuigi Rizzo sc->intrs[i].intr_res = NULL; 8692f345d8eSLuigi Rizzo } 8702f345d8eSLuigi Rizzo 8712f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX) 8722f345d8eSLuigi Rizzo pci_release_msi(sc->dev); 8732f345d8eSLuigi Rizzo 8742f345d8eSLuigi Rizzo } 8752f345d8eSLuigi Rizzo 8762f345d8eSLuigi Rizzo 8772f345d8eSLuigi Rizzo 8782f345d8eSLuigi Rizzo /****************************************************************************** 8792f345d8eSLuigi Rizzo * Media callbacks functions * 8802f345d8eSLuigi Rizzo ******************************************************************************/ 8812f345d8eSLuigi Rizzo 8822f345d8eSLuigi Rizzo static void 8832f345d8eSLuigi Rizzo oce_media_status(struct ifnet *ifp, struct ifmediareq *req) 8842f345d8eSLuigi Rizzo { 8852f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc; 8862f345d8eSLuigi Rizzo 8872f345d8eSLuigi Rizzo 8882f345d8eSLuigi Rizzo req->ifm_status = IFM_AVALID; 8892f345d8eSLuigi Rizzo req->ifm_active = IFM_ETHER; 8902f345d8eSLuigi Rizzo 8912f345d8eSLuigi Rizzo if (sc->link_status == 1) 8922f345d8eSLuigi Rizzo req->ifm_status |= IFM_ACTIVE; 8932f345d8eSLuigi Rizzo else 8942f345d8eSLuigi Rizzo return; 8952f345d8eSLuigi Rizzo 8962f345d8eSLuigi Rizzo switch (sc->link_speed) { 8972f345d8eSLuigi Rizzo case 1: /* 10 Mbps */ 8982f345d8eSLuigi Rizzo req->ifm_active |= IFM_10_T | IFM_FDX; 8992f345d8eSLuigi Rizzo sc->speed = 10; 9002f345d8eSLuigi Rizzo break; 9012f345d8eSLuigi Rizzo case 2: /* 100 Mbps */ 9022f345d8eSLuigi Rizzo req->ifm_active |= IFM_100_TX | IFM_FDX; 9032f345d8eSLuigi Rizzo sc->speed = 100; 9042f345d8eSLuigi Rizzo break; 9052f345d8eSLuigi Rizzo case 3: /* 1 Gbps */ 9062f345d8eSLuigi Rizzo req->ifm_active |= IFM_1000_T | IFM_FDX; 9072f345d8eSLuigi Rizzo sc->speed = 1000; 9082f345d8eSLuigi Rizzo break; 9092f345d8eSLuigi Rizzo case 4: /* 10 Gbps */ 9102f345d8eSLuigi Rizzo req->ifm_active |= IFM_10G_SR | IFM_FDX; 9112f345d8eSLuigi Rizzo sc->speed = 10000; 9122f345d8eSLuigi Rizzo break; 913a4f734b4SXin LI case 5: /* 20 Gbps */ 914a4f734b4SXin LI req->ifm_active |= IFM_10G_SR | IFM_FDX; 915a4f734b4SXin LI sc->speed = 20000; 916a4f734b4SXin LI break; 917a4f734b4SXin LI case 6: /* 25 Gbps */ 918a4f734b4SXin LI req->ifm_active |= IFM_10G_SR | IFM_FDX; 919a4f734b4SXin LI sc->speed = 25000; 920a4f734b4SXin LI break; 921b41206d8SXin LI case 7: /* 40 Gbps */ 922b41206d8SXin LI req->ifm_active |= IFM_40G_SR4 | IFM_FDX; 923b41206d8SXin LI sc->speed = 40000; 924b41206d8SXin LI break; 925a4f734b4SXin LI default: 926a4f734b4SXin LI sc->speed = 0; 927a4f734b4SXin LI break; 9282f345d8eSLuigi Rizzo } 9292f345d8eSLuigi Rizzo 9302f345d8eSLuigi Rizzo return; 9312f345d8eSLuigi Rizzo } 9322f345d8eSLuigi Rizzo 9332f345d8eSLuigi Rizzo 9342f345d8eSLuigi Rizzo int 9352f345d8eSLuigi Rizzo oce_media_change(struct ifnet *ifp) 9362f345d8eSLuigi Rizzo { 9372f345d8eSLuigi Rizzo return 0; 9382f345d8eSLuigi Rizzo } 9392f345d8eSLuigi Rizzo 9402f345d8eSLuigi Rizzo 941c2625e6eSJosh Paetzel static void oce_is_pkt_dest_bmc(POCE_SOFTC sc, 942c2625e6eSJosh Paetzel struct mbuf *m, boolean_t *os2bmc, 943c2625e6eSJosh Paetzel struct mbuf **m_new) 944c2625e6eSJosh Paetzel { 945c2625e6eSJosh Paetzel struct ether_header *eh = NULL; 946c2625e6eSJosh Paetzel 947c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *); 948c2625e6eSJosh Paetzel 949c2625e6eSJosh Paetzel if (!is_os2bmc_enabled(sc) || *os2bmc) { 950c2625e6eSJosh Paetzel *os2bmc = FALSE; 951c2625e6eSJosh Paetzel goto done; 952c2625e6eSJosh Paetzel } 953c2625e6eSJosh Paetzel if (!ETHER_IS_MULTICAST(eh->ether_dhost)) 954c2625e6eSJosh Paetzel goto done; 955c2625e6eSJosh Paetzel 956c2625e6eSJosh Paetzel if (is_mc_allowed_on_bmc(sc, eh) || 957c2625e6eSJosh Paetzel is_bc_allowed_on_bmc(sc, eh) || 958c2625e6eSJosh Paetzel is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) { 959c2625e6eSJosh Paetzel *os2bmc = TRUE; 960c2625e6eSJosh Paetzel goto done; 961c2625e6eSJosh Paetzel } 962c2625e6eSJosh Paetzel 963c2625e6eSJosh Paetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) { 964c2625e6eSJosh Paetzel struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 965c2625e6eSJosh Paetzel uint8_t nexthdr = ip6->ip6_nxt; 966c2625e6eSJosh Paetzel if (nexthdr == IPPROTO_ICMPV6) { 967c2625e6eSJosh Paetzel struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1); 968c2625e6eSJosh Paetzel switch (icmp6->icmp6_type) { 969c2625e6eSJosh Paetzel case ND_ROUTER_ADVERT: 970c2625e6eSJosh Paetzel *os2bmc = is_ipv6_ra_filt_enabled(sc); 971c2625e6eSJosh Paetzel goto done; 972c2625e6eSJosh Paetzel case ND_NEIGHBOR_ADVERT: 973c2625e6eSJosh Paetzel *os2bmc = is_ipv6_na_filt_enabled(sc); 974c2625e6eSJosh Paetzel goto done; 975c2625e6eSJosh Paetzel default: 976c2625e6eSJosh Paetzel break; 977c2625e6eSJosh Paetzel } 978c2625e6eSJosh Paetzel } 979c2625e6eSJosh Paetzel } 980c2625e6eSJosh Paetzel 981c2625e6eSJosh Paetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) { 982c2625e6eSJosh Paetzel struct ip *ip = mtod(m, struct ip *); 983c2625e6eSJosh Paetzel int iphlen = ip->ip_hl << 2; 984c2625e6eSJosh Paetzel struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen); 985c2625e6eSJosh Paetzel switch (uh->uh_dport) { 986c2625e6eSJosh Paetzel case DHCP_CLIENT_PORT: 987c2625e6eSJosh Paetzel *os2bmc = is_dhcp_client_filt_enabled(sc); 988c2625e6eSJosh Paetzel goto done; 989c2625e6eSJosh Paetzel case DHCP_SERVER_PORT: 990c2625e6eSJosh Paetzel *os2bmc = is_dhcp_srvr_filt_enabled(sc); 991c2625e6eSJosh Paetzel goto done; 992c2625e6eSJosh Paetzel case NET_BIOS_PORT1: 993c2625e6eSJosh Paetzel case NET_BIOS_PORT2: 994c2625e6eSJosh Paetzel *os2bmc = is_nbios_filt_enabled(sc); 995c2625e6eSJosh Paetzel goto done; 996c2625e6eSJosh Paetzel case DHCPV6_RAS_PORT: 997c2625e6eSJosh Paetzel *os2bmc = is_ipv6_ras_filt_enabled(sc); 998c2625e6eSJosh Paetzel goto done; 999c2625e6eSJosh Paetzel default: 1000c2625e6eSJosh Paetzel break; 1001c2625e6eSJosh Paetzel } 1002c2625e6eSJosh Paetzel } 1003c2625e6eSJosh Paetzel done: 1004c2625e6eSJosh Paetzel if (*os2bmc) { 1005c2625e6eSJosh Paetzel *m_new = m_dup(m, M_NOWAIT); 1006c2625e6eSJosh Paetzel if (!*m_new) { 1007c2625e6eSJosh Paetzel *os2bmc = FALSE; 1008c2625e6eSJosh Paetzel return; 1009c2625e6eSJosh Paetzel } 1010c2625e6eSJosh Paetzel *m_new = oce_insert_vlan_tag(sc, *m_new, NULL); 1011c2625e6eSJosh Paetzel } 1012c2625e6eSJosh Paetzel } 1013c2625e6eSJosh Paetzel 10142f345d8eSLuigi Rizzo 10152f345d8eSLuigi Rizzo 10162f345d8eSLuigi Rizzo /***************************************************************************** 10172f345d8eSLuigi Rizzo * Transmit routines functions * 10182f345d8eSLuigi Rizzo *****************************************************************************/ 10192f345d8eSLuigi Rizzo 10202f345d8eSLuigi Rizzo static int 10212f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 10222f345d8eSLuigi Rizzo { 10232f345d8eSLuigi Rizzo int rc = 0, i, retry_cnt = 0; 10242f345d8eSLuigi Rizzo bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 1025c2625e6eSJosh Paetzel struct mbuf *m, *m_temp, *m_new = NULL; 10262f345d8eSLuigi Rizzo struct oce_wq *wq = sc->wq[wq_index]; 10272f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 10282f345d8eSLuigi Rizzo struct oce_nic_hdr_wqe *nichdr; 10292f345d8eSLuigi Rizzo struct oce_nic_frag_wqe *nicfrag; 1030c2625e6eSJosh Paetzel struct ether_header *eh = NULL; 10312f345d8eSLuigi Rizzo int num_wqes; 10322f345d8eSLuigi Rizzo uint32_t reg_value; 1033cdaba892SXin LI boolean_t complete = TRUE; 1034c2625e6eSJosh Paetzel boolean_t os2bmc = FALSE; 10352f345d8eSLuigi Rizzo 10362f345d8eSLuigi Rizzo m = *mpp; 10372f345d8eSLuigi Rizzo if (!m) 10382f345d8eSLuigi Rizzo return EINVAL; 10392f345d8eSLuigi Rizzo 10402f345d8eSLuigi Rizzo if (!(m->m_flags & M_PKTHDR)) { 10412f345d8eSLuigi Rizzo rc = ENXIO; 10422f345d8eSLuigi Rizzo goto free_ret; 10432f345d8eSLuigi Rizzo } 10442f345d8eSLuigi Rizzo 1045c2625e6eSJosh Paetzel /* Don't allow non-TSO packets longer than MTU */ 1046c2625e6eSJosh Paetzel if (!is_tso_pkt(m)) { 1047c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *); 1048c2625e6eSJosh Paetzel if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE)) 1049c2625e6eSJosh Paetzel goto free_ret; 1050c2625e6eSJosh Paetzel } 1051c2625e6eSJosh Paetzel 1052cdaba892SXin LI if(oce_tx_asic_stall_verify(sc, m)) { 1053cdaba892SXin LI m = oce_insert_vlan_tag(sc, m, &complete); 1054cdaba892SXin LI if(!m) { 1055cdaba892SXin LI device_printf(sc->dev, "Insertion unsuccessful\n"); 1056cdaba892SXin LI return 0; 1057cdaba892SXin LI } 1058cdaba892SXin LI 1059cdaba892SXin LI } 1060cdaba892SXin LI 1061c2625e6eSJosh Paetzel /* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less 1062c2625e6eSJosh Paetzel * may cause a transmit stall on that port. So the work-around is to 1063c2625e6eSJosh Paetzel * pad short packets (<= 32 bytes) to a 36-byte length. 1064c2625e6eSJosh Paetzel */ 1065c2625e6eSJosh Paetzel if(IS_SH(sc) || IS_XE201(sc) ) { 1066c2625e6eSJosh Paetzel if(m->m_pkthdr.len <= 32) { 1067c2625e6eSJosh Paetzel char buf[36]; 1068c2625e6eSJosh Paetzel bzero((void *)buf, 36); 1069c2625e6eSJosh Paetzel m_append(m, (36 - m->m_pkthdr.len), buf); 1070c2625e6eSJosh Paetzel } 1071c2625e6eSJosh Paetzel } 1072c2625e6eSJosh Paetzel 1073c2625e6eSJosh Paetzel tx_start: 10742f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) { 10752f345d8eSLuigi Rizzo /* consolidate packet buffers for TSO/LSO segment offload */ 10769bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET) 10779bd3250aSLuigi Rizzo m = oce_tso_setup(sc, mpp); 1078ad512958SBjoern A. Zeeb #else 1079ad512958SBjoern A. Zeeb m = NULL; 1080ad512958SBjoern A. Zeeb #endif 10812f345d8eSLuigi Rizzo if (m == NULL) { 10822f345d8eSLuigi Rizzo rc = ENXIO; 10832f345d8eSLuigi Rizzo goto free_ret; 10842f345d8eSLuigi Rizzo } 10852f345d8eSLuigi Rizzo } 10862f345d8eSLuigi Rizzo 1087c2625e6eSJosh Paetzel 1088291a1934SXin LI pd = &wq->pckts[wq->pkt_desc_head]; 1089c2625e6eSJosh Paetzel 10902f345d8eSLuigi Rizzo retry: 10912f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(wq->tag, 10922f345d8eSLuigi Rizzo pd->map, 10932f345d8eSLuigi Rizzo m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 10942f345d8eSLuigi Rizzo if (rc == 0) { 10952f345d8eSLuigi Rizzo num_wqes = pd->nsegs + 1; 1096291a1934SXin LI if (IS_BE(sc) || IS_SH(sc)) { 10972f345d8eSLuigi Rizzo /*Dummy required only for BE3.*/ 10982f345d8eSLuigi Rizzo if (num_wqes & 1) 10992f345d8eSLuigi Rizzo num_wqes++; 11002f345d8eSLuigi Rizzo } 11012f345d8eSLuigi Rizzo if (num_wqes >= RING_NUM_FREE(wq->ring)) { 11022f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map); 11032f345d8eSLuigi Rizzo return EBUSY; 11042f345d8eSLuigi Rizzo } 1105291a1934SXin LI atomic_store_rel_int(&wq->pkt_desc_head, 1106291a1934SXin LI (wq->pkt_desc_head + 1) % \ 1107291a1934SXin LI OCE_WQ_PACKET_ARRAY_SIZE); 11082f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 11092f345d8eSLuigi Rizzo pd->mbuf = m; 11102f345d8eSLuigi Rizzo 11112f345d8eSLuigi Rizzo nichdr = 11122f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 11132f345d8eSLuigi Rizzo nichdr->u0.dw[0] = 0; 11142f345d8eSLuigi Rizzo nichdr->u0.dw[1] = 0; 11152f345d8eSLuigi Rizzo nichdr->u0.dw[2] = 0; 11162f345d8eSLuigi Rizzo nichdr->u0.dw[3] = 0; 11172f345d8eSLuigi Rizzo 1118cdaba892SXin LI nichdr->u0.s.complete = complete; 1119c2625e6eSJosh Paetzel nichdr->u0.s.mgmt = os2bmc; 11202f345d8eSLuigi Rizzo nichdr->u0.s.event = 1; 11212f345d8eSLuigi Rizzo nichdr->u0.s.crc = 1; 11222f345d8eSLuigi Rizzo nichdr->u0.s.forward = 0; 11232f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 11242f345d8eSLuigi Rizzo nichdr->u0.s.udpcs = 11252f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 11262f345d8eSLuigi Rizzo nichdr->u0.s.tcpcs = 11272f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 11282f345d8eSLuigi Rizzo nichdr->u0.s.num_wqe = num_wqes; 11292f345d8eSLuigi Rizzo nichdr->u0.s.total_length = m->m_pkthdr.len; 11305fbb6830SXin LI 11312f345d8eSLuigi Rizzo if (m->m_flags & M_VLANTAG) { 11322f345d8eSLuigi Rizzo nichdr->u0.s.vlan = 1; /*Vlan present*/ 11332f345d8eSLuigi Rizzo nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 11342f345d8eSLuigi Rizzo } 11355fbb6830SXin LI 11362f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) { 11372f345d8eSLuigi Rizzo if (m->m_pkthdr.tso_segsz) { 11382f345d8eSLuigi Rizzo nichdr->u0.s.lso = 1; 11392f345d8eSLuigi Rizzo nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 11402f345d8eSLuigi Rizzo } 1141291a1934SXin LI if (!IS_BE(sc) || !IS_SH(sc)) 11422f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = 1; 11432f345d8eSLuigi Rizzo } 11442f345d8eSLuigi Rizzo 11452f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1146291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11472f345d8eSLuigi Rizzo 11482f345d8eSLuigi Rizzo for (i = 0; i < pd->nsegs; i++) { 11492f345d8eSLuigi Rizzo nicfrag = 11502f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, 11512f345d8eSLuigi Rizzo struct oce_nic_frag_wqe); 11522f345d8eSLuigi Rizzo nicfrag->u0.s.rsvd0 = 0; 11532f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 11542f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 11552f345d8eSLuigi Rizzo nicfrag->u0.s.frag_len = segs[i].ds_len; 11562f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx; 11572f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1158291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11592f345d8eSLuigi Rizzo } 11602f345d8eSLuigi Rizzo if (num_wqes > (pd->nsegs + 1)) { 11612f345d8eSLuigi Rizzo nicfrag = 11622f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, 11632f345d8eSLuigi Rizzo struct oce_nic_frag_wqe); 11642f345d8eSLuigi Rizzo nicfrag->u0.dw[0] = 0; 11652f345d8eSLuigi Rizzo nicfrag->u0.dw[1] = 0; 11662f345d8eSLuigi Rizzo nicfrag->u0.dw[2] = 0; 11672f345d8eSLuigi Rizzo nicfrag->u0.dw[3] = 0; 11682f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx; 11692f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1170291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11712f345d8eSLuigi Rizzo pd->nsegs++; 11722f345d8eSLuigi Rizzo } 11732f345d8eSLuigi Rizzo 1174c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1); 11752f345d8eSLuigi Rizzo wq->tx_stats.tx_reqs++; 11762f345d8eSLuigi Rizzo wq->tx_stats.tx_wrbs += num_wqes; 11772f345d8eSLuigi Rizzo wq->tx_stats.tx_bytes += m->m_pkthdr.len; 11782f345d8eSLuigi Rizzo wq->tx_stats.tx_pkts++; 11792f345d8eSLuigi Rizzo 11802f345d8eSLuigi Rizzo bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 11812f345d8eSLuigi Rizzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 11822f345d8eSLuigi Rizzo reg_value = (num_wqes << 16) | wq->wq_id; 1183c2625e6eSJosh Paetzel 1184c2625e6eSJosh Paetzel /* if os2bmc is not enabled or if the pkt is already tagged as 1185c2625e6eSJosh Paetzel bmc, do nothing 1186c2625e6eSJosh Paetzel */ 1187c2625e6eSJosh Paetzel oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new); 1188c2625e6eSJosh Paetzel 1189291a1934SXin LI OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value); 11902f345d8eSLuigi Rizzo 11912f345d8eSLuigi Rizzo } else if (rc == EFBIG) { 11922f345d8eSLuigi Rizzo if (retry_cnt == 0) { 1193c6499eccSGleb Smirnoff m_temp = m_defrag(m, M_NOWAIT); 11942f345d8eSLuigi Rizzo if (m_temp == NULL) 11952f345d8eSLuigi Rizzo goto free_ret; 11962f345d8eSLuigi Rizzo m = m_temp; 11972f345d8eSLuigi Rizzo *mpp = m_temp; 11982f345d8eSLuigi Rizzo retry_cnt = retry_cnt + 1; 11992f345d8eSLuigi Rizzo goto retry; 12002f345d8eSLuigi Rizzo } else 12012f345d8eSLuigi Rizzo goto free_ret; 12022f345d8eSLuigi Rizzo } else if (rc == ENOMEM) 12032f345d8eSLuigi Rizzo return rc; 12042f345d8eSLuigi Rizzo else 12052f345d8eSLuigi Rizzo goto free_ret; 12062f345d8eSLuigi Rizzo 1207c2625e6eSJosh Paetzel if (os2bmc) { 1208c2625e6eSJosh Paetzel m = m_new; 1209c2625e6eSJosh Paetzel goto tx_start; 1210c2625e6eSJosh Paetzel } 1211c2625e6eSJosh Paetzel 12122f345d8eSLuigi Rizzo return 0; 12132f345d8eSLuigi Rizzo 12142f345d8eSLuigi Rizzo free_ret: 12152f345d8eSLuigi Rizzo m_freem(*mpp); 12162f345d8eSLuigi Rizzo *mpp = NULL; 12172f345d8eSLuigi Rizzo return rc; 12182f345d8eSLuigi Rizzo } 12192f345d8eSLuigi Rizzo 12202f345d8eSLuigi Rizzo 12212f345d8eSLuigi Rizzo static void 1222c2625e6eSJosh Paetzel oce_process_tx_completion(struct oce_wq *wq) 12232f345d8eSLuigi Rizzo { 12242f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 12252f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 12262f345d8eSLuigi Rizzo struct mbuf *m; 12272f345d8eSLuigi Rizzo 1228291a1934SXin LI pd = &wq->pckts[wq->pkt_desc_tail]; 1229291a1934SXin LI atomic_store_rel_int(&wq->pkt_desc_tail, 1230291a1934SXin LI (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE); 1231291a1934SXin LI atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1); 12322f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 12332f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map); 12342f345d8eSLuigi Rizzo 12352f345d8eSLuigi Rizzo m = pd->mbuf; 12362f345d8eSLuigi Rizzo m_freem(m); 12372f345d8eSLuigi Rizzo pd->mbuf = NULL; 12382f345d8eSLuigi Rizzo 1239291a1934SXin LI 12402f345d8eSLuigi Rizzo if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 12412f345d8eSLuigi Rizzo if (wq->ring->num_used < (wq->ring->num_items / 2)) { 12422f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 12432f345d8eSLuigi Rizzo oce_tx_restart(sc, wq); 12442f345d8eSLuigi Rizzo } 12452f345d8eSLuigi Rizzo } 12462f345d8eSLuigi Rizzo } 12472f345d8eSLuigi Rizzo 12482f345d8eSLuigi Rizzo 12492f345d8eSLuigi Rizzo static void 12502f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 12512f345d8eSLuigi Rizzo { 12522f345d8eSLuigi Rizzo 12532f345d8eSLuigi Rizzo if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 12542f345d8eSLuigi Rizzo return; 12552f345d8eSLuigi Rizzo 12562f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 12572f345d8eSLuigi Rizzo if (!drbr_empty(sc->ifp, wq->br)) 12582f345d8eSLuigi Rizzo #else 12592f345d8eSLuigi Rizzo if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 12602f345d8eSLuigi Rizzo #endif 1261cbc4d2dbSJohn Baldwin taskqueue_enqueue(taskqueue_swi, &wq->txtask); 12622f345d8eSLuigi Rizzo 12632f345d8eSLuigi Rizzo } 12642f345d8eSLuigi Rizzo 12659bd3250aSLuigi Rizzo 1266ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 12672f345d8eSLuigi Rizzo static struct mbuf * 12689bd3250aSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp) 12692f345d8eSLuigi Rizzo { 12702f345d8eSLuigi Rizzo struct mbuf *m; 1271ad512958SBjoern A. Zeeb #ifdef INET 12722f345d8eSLuigi Rizzo struct ip *ip; 1273ad512958SBjoern A. Zeeb #endif 1274ad512958SBjoern A. Zeeb #ifdef INET6 12752f345d8eSLuigi Rizzo struct ip6_hdr *ip6; 1276ad512958SBjoern A. Zeeb #endif 12772f345d8eSLuigi Rizzo struct ether_vlan_header *eh; 12782f345d8eSLuigi Rizzo struct tcphdr *th; 12792f345d8eSLuigi Rizzo uint16_t etype; 12809bd3250aSLuigi Rizzo int total_len = 0, ehdrlen = 0; 12812f345d8eSLuigi Rizzo 12822f345d8eSLuigi Rizzo m = *mpp; 12832f345d8eSLuigi Rizzo 12842f345d8eSLuigi Rizzo if (M_WRITABLE(m) == 0) { 1285c6499eccSGleb Smirnoff m = m_dup(*mpp, M_NOWAIT); 12862f345d8eSLuigi Rizzo if (!m) 12872f345d8eSLuigi Rizzo return NULL; 12882f345d8eSLuigi Rizzo m_freem(*mpp); 12892f345d8eSLuigi Rizzo *mpp = m; 12902f345d8eSLuigi Rizzo } 12912f345d8eSLuigi Rizzo 12922f345d8eSLuigi Rizzo eh = mtod(m, struct ether_vlan_header *); 12932f345d8eSLuigi Rizzo if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 12942f345d8eSLuigi Rizzo etype = ntohs(eh->evl_proto); 12952f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 12962f345d8eSLuigi Rizzo } else { 12972f345d8eSLuigi Rizzo etype = ntohs(eh->evl_encap_proto); 12982f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN; 12992f345d8eSLuigi Rizzo } 13002f345d8eSLuigi Rizzo 13012f345d8eSLuigi Rizzo switch (etype) { 1302ad512958SBjoern A. Zeeb #ifdef INET 13032f345d8eSLuigi Rizzo case ETHERTYPE_IP: 13042f345d8eSLuigi Rizzo ip = (struct ip *)(m->m_data + ehdrlen); 13052f345d8eSLuigi Rizzo if (ip->ip_p != IPPROTO_TCP) 13062f345d8eSLuigi Rizzo return NULL; 13072f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 13082f345d8eSLuigi Rizzo 13092f345d8eSLuigi Rizzo total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 13102f345d8eSLuigi Rizzo break; 1311ad512958SBjoern A. Zeeb #endif 1312ad512958SBjoern A. Zeeb #ifdef INET6 13132f345d8eSLuigi Rizzo case ETHERTYPE_IPV6: 13142f345d8eSLuigi Rizzo ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 13152f345d8eSLuigi Rizzo if (ip6->ip6_nxt != IPPROTO_TCP) 13162f345d8eSLuigi Rizzo return NULL; 13172f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 13182f345d8eSLuigi Rizzo 13192f345d8eSLuigi Rizzo total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 13202f345d8eSLuigi Rizzo break; 1321ad512958SBjoern A. Zeeb #endif 13222f345d8eSLuigi Rizzo default: 13232f345d8eSLuigi Rizzo return NULL; 13242f345d8eSLuigi Rizzo } 13252f345d8eSLuigi Rizzo 13262f345d8eSLuigi Rizzo m = m_pullup(m, total_len); 13272f345d8eSLuigi Rizzo if (!m) 13282f345d8eSLuigi Rizzo return NULL; 13292f345d8eSLuigi Rizzo *mpp = m; 13302f345d8eSLuigi Rizzo return m; 13312f345d8eSLuigi Rizzo 13322f345d8eSLuigi Rizzo } 1333ad512958SBjoern A. Zeeb #endif /* INET6 || INET */ 13342f345d8eSLuigi Rizzo 13352f345d8eSLuigi Rizzo void 13362f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending) 13372f345d8eSLuigi Rizzo { 13382f345d8eSLuigi Rizzo struct oce_wq *wq = arg; 13392f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 13402f345d8eSLuigi Rizzo struct ifnet *ifp = sc->ifp; 13412f345d8eSLuigi Rizzo int rc = 0; 13422f345d8eSLuigi Rizzo 13432f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1344291a1934SXin LI LOCK(&wq->tx_lock); 13452f345d8eSLuigi Rizzo rc = oce_multiq_transmit(ifp, NULL, wq); 13462f345d8eSLuigi Rizzo if (rc) { 13472f345d8eSLuigi Rizzo device_printf(sc->dev, 13482f345d8eSLuigi Rizzo "TX[%d] restart failed\n", wq->queue_index); 13492f345d8eSLuigi Rizzo } 13502f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 13512f345d8eSLuigi Rizzo #else 13522f345d8eSLuigi Rizzo oce_start(ifp); 13532f345d8eSLuigi Rizzo #endif 13542f345d8eSLuigi Rizzo 13552f345d8eSLuigi Rizzo } 13562f345d8eSLuigi Rizzo 13572f345d8eSLuigi Rizzo 13582f345d8eSLuigi Rizzo void 13592f345d8eSLuigi Rizzo oce_start(struct ifnet *ifp) 13602f345d8eSLuigi Rizzo { 13612f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 13622f345d8eSLuigi Rizzo struct mbuf *m; 13632f345d8eSLuigi Rizzo int rc = 0; 13649bd3250aSLuigi Rizzo int def_q = 0; /* Defualt tx queue is 0*/ 13652f345d8eSLuigi Rizzo 13662f345d8eSLuigi Rizzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 13672f345d8eSLuigi Rizzo IFF_DRV_RUNNING) 13682f345d8eSLuigi Rizzo return; 13692f345d8eSLuigi Rizzo 1370cdaba892SXin LI if (!sc->link_status) 1371cdaba892SXin LI return; 1372cdaba892SXin LI 13732f345d8eSLuigi Rizzo do { 13742f345d8eSLuigi Rizzo IF_DEQUEUE(&sc->ifp->if_snd, m); 13752f345d8eSLuigi Rizzo if (m == NULL) 13762f345d8eSLuigi Rizzo break; 13779bd3250aSLuigi Rizzo 13789bd3250aSLuigi Rizzo LOCK(&sc->wq[def_q]->tx_lock); 13799bd3250aSLuigi Rizzo rc = oce_tx(sc, &m, def_q); 13809bd3250aSLuigi Rizzo UNLOCK(&sc->wq[def_q]->tx_lock); 13812f345d8eSLuigi Rizzo if (rc) { 13822f345d8eSLuigi Rizzo if (m != NULL) { 13839bd3250aSLuigi Rizzo sc->wq[def_q]->tx_stats.tx_stops ++; 13842f345d8eSLuigi Rizzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 13852f345d8eSLuigi Rizzo IFQ_DRV_PREPEND(&ifp->if_snd, m); 13862f345d8eSLuigi Rizzo m = NULL; 13872f345d8eSLuigi Rizzo } 13882f345d8eSLuigi Rizzo break; 13892f345d8eSLuigi Rizzo } 13902f345d8eSLuigi Rizzo if (m != NULL) 13912f345d8eSLuigi Rizzo ETHER_BPF_MTAP(ifp, m); 13922f345d8eSLuigi Rizzo 13939bd3250aSLuigi Rizzo } while (TRUE); 13942f345d8eSLuigi Rizzo 13952f345d8eSLuigi Rizzo return; 13962f345d8eSLuigi Rizzo } 13972f345d8eSLuigi Rizzo 13982f345d8eSLuigi Rizzo 13992f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */ 14002f345d8eSLuigi Rizzo uint16_t 14012f345d8eSLuigi Rizzo oce_wq_handler(void *arg) 14022f345d8eSLuigi Rizzo { 14032f345d8eSLuigi Rizzo struct oce_wq *wq = (struct oce_wq *)arg; 14042f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 14052f345d8eSLuigi Rizzo struct oce_cq *cq = wq->cq; 14062f345d8eSLuigi Rizzo struct oce_nic_tx_cqe *cqe; 14072f345d8eSLuigi Rizzo int num_cqes = 0; 14082f345d8eSLuigi Rizzo 1409c2625e6eSJosh Paetzel LOCK(&wq->tx_compl_lock); 14102f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 14112f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 14122f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 14132f345d8eSLuigi Rizzo while (cqe->u0.dw[3]) { 14142f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 14152f345d8eSLuigi Rizzo 14162f345d8eSLuigi Rizzo wq->ring->cidx = cqe->u0.s.wqe_index + 1; 14172f345d8eSLuigi Rizzo if (wq->ring->cidx >= wq->ring->num_items) 14182f345d8eSLuigi Rizzo wq->ring->cidx -= wq->ring->num_items; 14192f345d8eSLuigi Rizzo 1420c2625e6eSJosh Paetzel oce_process_tx_completion(wq); 14212f345d8eSLuigi Rizzo wq->tx_stats.tx_compl++; 14222f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 14232f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 14242f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 14252f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 14262f345d8eSLuigi Rizzo cqe = 14272f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 14282f345d8eSLuigi Rizzo num_cqes++; 14292f345d8eSLuigi Rizzo } 14302f345d8eSLuigi Rizzo 14312f345d8eSLuigi Rizzo if (num_cqes) 14322f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 14332f345d8eSLuigi Rizzo 1434c2625e6eSJosh Paetzel UNLOCK(&wq->tx_compl_lock); 1435c2625e6eSJosh Paetzel return num_cqes; 14362f345d8eSLuigi Rizzo } 14372f345d8eSLuigi Rizzo 14382f345d8eSLuigi Rizzo 14392f345d8eSLuigi Rizzo static int 14402f345d8eSLuigi Rizzo oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 14412f345d8eSLuigi Rizzo { 14422f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 14432f345d8eSLuigi Rizzo int status = 0, queue_index = 0; 14442f345d8eSLuigi Rizzo struct mbuf *next = NULL; 14452f345d8eSLuigi Rizzo struct buf_ring *br = NULL; 14462f345d8eSLuigi Rizzo 14472f345d8eSLuigi Rizzo br = wq->br; 14482f345d8eSLuigi Rizzo queue_index = wq->queue_index; 14492f345d8eSLuigi Rizzo 14502f345d8eSLuigi Rizzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 14512f345d8eSLuigi Rizzo IFF_DRV_RUNNING) { 14522f345d8eSLuigi Rizzo if (m != NULL) 14532f345d8eSLuigi Rizzo status = drbr_enqueue(ifp, br, m); 14542f345d8eSLuigi Rizzo return status; 14552f345d8eSLuigi Rizzo } 14562f345d8eSLuigi Rizzo 1457ded5ea6aSRandall Stewart if (m != NULL) { 14582f345d8eSLuigi Rizzo if ((status = drbr_enqueue(ifp, br, m)) != 0) 14592f345d8eSLuigi Rizzo return status; 1460ded5ea6aSRandall Stewart } 1461ded5ea6aSRandall Stewart while ((next = drbr_peek(ifp, br)) != NULL) { 14622f345d8eSLuigi Rizzo if (oce_tx(sc, &next, queue_index)) { 1463ded5ea6aSRandall Stewart if (next == NULL) { 1464ded5ea6aSRandall Stewart drbr_advance(ifp, br); 1465ded5ea6aSRandall Stewart } else { 1466ded5ea6aSRandall Stewart drbr_putback(ifp, br, next); 14672f345d8eSLuigi Rizzo wq->tx_stats.tx_stops ++; 14682f345d8eSLuigi Rizzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 14692f345d8eSLuigi Rizzo } 14702f345d8eSLuigi Rizzo break; 14712f345d8eSLuigi Rizzo } 1472ded5ea6aSRandall Stewart drbr_advance(ifp, br); 1473c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len); 1474063efed2SGleb Smirnoff if (next->m_flags & M_MCAST) 1475c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 14762f345d8eSLuigi Rizzo ETHER_BPF_MTAP(ifp, next); 14772f345d8eSLuigi Rizzo } 14782f345d8eSLuigi Rizzo 1479d398c863SLuigi Rizzo return 0; 14802f345d8eSLuigi Rizzo } 14812f345d8eSLuigi Rizzo 14822f345d8eSLuigi Rizzo 14832f345d8eSLuigi Rizzo 14842f345d8eSLuigi Rizzo 14852f345d8eSLuigi Rizzo /***************************************************************************** 14862f345d8eSLuigi Rizzo * Receive routines functions * 14872f345d8eSLuigi Rizzo *****************************************************************************/ 14882f345d8eSLuigi Rizzo 14892f345d8eSLuigi Rizzo static void 1490c2625e6eSJosh Paetzel oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2) 14912f345d8eSLuigi Rizzo { 1492c2625e6eSJosh Paetzel uint32_t *p; 1493c2625e6eSJosh Paetzel struct ether_header *eh = NULL; 1494c2625e6eSJosh Paetzel struct tcphdr *tcp_hdr = NULL; 1495c2625e6eSJosh Paetzel struct ip *ip4_hdr = NULL; 1496c2625e6eSJosh Paetzel struct ip6_hdr *ip6 = NULL; 1497c2625e6eSJosh Paetzel uint32_t payload_len = 0; 1498c2625e6eSJosh Paetzel 1499c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *); 1500c2625e6eSJosh Paetzel /* correct IP header */ 1501c2625e6eSJosh Paetzel if(!cqe2->ipv6_frame) { 1502c2625e6eSJosh Paetzel ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header)); 1503c2625e6eSJosh Paetzel ip4_hdr->ip_ttl = cqe2->frame_lifespan; 1504c2625e6eSJosh Paetzel ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header)); 1505c2625e6eSJosh Paetzel tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip)); 1506c2625e6eSJosh Paetzel }else { 1507c2625e6eSJosh Paetzel ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header)); 1508c2625e6eSJosh Paetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan; 1509c2625e6eSJosh Paetzel payload_len = cqe2->coalesced_size - sizeof(struct ether_header) 1510c2625e6eSJosh Paetzel - sizeof(struct ip6_hdr); 1511c2625e6eSJosh Paetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len); 1512c2625e6eSJosh Paetzel tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr)); 1513c2625e6eSJosh Paetzel } 1514c2625e6eSJosh Paetzel 1515c2625e6eSJosh Paetzel /* correct tcp header */ 1516c2625e6eSJosh Paetzel tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num); 1517c2625e6eSJosh Paetzel if(cqe2->push) { 1518c2625e6eSJosh Paetzel tcp_hdr->th_flags |= TH_PUSH; 1519c2625e6eSJosh Paetzel } 1520c2625e6eSJosh Paetzel tcp_hdr->th_win = htons(cqe2->tcp_window); 1521c2625e6eSJosh Paetzel tcp_hdr->th_sum = 0xffff; 1522c2625e6eSJosh Paetzel if(cqe2->ts_opt) { 1523c2625e6eSJosh Paetzel p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2); 1524c2625e6eSJosh Paetzel *p = cqe1->tcp_timestamp_val; 1525c2625e6eSJosh Paetzel *(p+1) = cqe1->tcp_timestamp_ecr; 1526c2625e6eSJosh Paetzel } 1527c2625e6eSJosh Paetzel 1528c2625e6eSJosh Paetzel return; 1529c2625e6eSJosh Paetzel } 1530c2625e6eSJosh Paetzel 1531c2625e6eSJosh Paetzel static void 1532c2625e6eSJosh Paetzel oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m) 1533c2625e6eSJosh Paetzel { 1534764c812dSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1535c2625e6eSJosh Paetzel uint32_t i = 0, frag_len = 0; 1536c2625e6eSJosh Paetzel uint32_t len = cqe_info->pkt_size; 1537c2625e6eSJosh Paetzel struct oce_packet_desc *pd; 1538c2625e6eSJosh Paetzel struct mbuf *tail = NULL; 1539764c812dSJosh Paetzel 1540c2625e6eSJosh Paetzel for (i = 0; i < cqe_info->num_frags; i++) { 1541c2625e6eSJosh Paetzel if (rq->ring->cidx == rq->ring->pidx) { 154214410265SConrad Meyer device_printf(sc->dev, 1543c2625e6eSJosh Paetzel "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n"); 1544c2625e6eSJosh Paetzel return; 154514410265SConrad Meyer } 1546c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->cidx]; 154714410265SConrad Meyer 154814410265SConrad Meyer bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 154914410265SConrad Meyer bus_dmamap_unload(rq->tag, pd->map); 1550c2625e6eSJosh Paetzel RING_GET(rq->ring, 1); 155114410265SConrad Meyer rq->pending--; 155214410265SConrad Meyer 155314410265SConrad Meyer frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 155414410265SConrad Meyer pd->mbuf->m_len = frag_len; 155514410265SConrad Meyer 155614410265SConrad Meyer if (tail != NULL) { 155714410265SConrad Meyer /* additional fragments */ 155814410265SConrad Meyer pd->mbuf->m_flags &= ~M_PKTHDR; 155914410265SConrad Meyer tail->m_next = pd->mbuf; 1560c2625e6eSJosh Paetzel if(rq->islro) 1561c2625e6eSJosh Paetzel tail->m_nextpkt = NULL; 156214410265SConrad Meyer tail = pd->mbuf; 156314410265SConrad Meyer } else { 156414410265SConrad Meyer /* first fragment, fill out much of the packet header */ 156514410265SConrad Meyer pd->mbuf->m_pkthdr.len = len; 1566c2625e6eSJosh Paetzel if(rq->islro) 1567c2625e6eSJosh Paetzel pd->mbuf->m_nextpkt = NULL; 156814410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags = 0; 156914410265SConrad Meyer if (IF_CSUM_ENABLED(sc)) { 1570c2625e6eSJosh Paetzel if (cqe_info->l4_cksum_pass) { 1571c2625e6eSJosh Paetzel if(!cqe_info->ipv6_frame) { /* IPV4 */ 157214410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags |= 157314410265SConrad Meyer (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1574c2625e6eSJosh Paetzel }else { /* IPV6 frame */ 1575c2625e6eSJosh Paetzel if(rq->islro) { 1576c2625e6eSJosh Paetzel pd->mbuf->m_pkthdr.csum_flags |= 1577c2625e6eSJosh Paetzel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1578c2625e6eSJosh Paetzel } 1579c2625e6eSJosh Paetzel } 158014410265SConrad Meyer pd->mbuf->m_pkthdr.csum_data = 0xffff; 158114410265SConrad Meyer } 1582c2625e6eSJosh Paetzel if (cqe_info->ip_cksum_pass) { 158314410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags |= 158414410265SConrad Meyer (CSUM_IP_CHECKED|CSUM_IP_VALID); 158514410265SConrad Meyer } 158614410265SConrad Meyer } 1587c2625e6eSJosh Paetzel *m = tail = pd->mbuf; 158814410265SConrad Meyer } 158914410265SConrad Meyer pd->mbuf = NULL; 159014410265SConrad Meyer len -= frag_len; 159114410265SConrad Meyer } 1592764c812dSJosh Paetzel 1593c2625e6eSJosh Paetzel return; 1594c2625e6eSJosh Paetzel } 1595c2625e6eSJosh Paetzel 1596c2625e6eSJosh Paetzel static void 1597c2625e6eSJosh Paetzel oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2) 1598c2625e6eSJosh Paetzel { 1599c2625e6eSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1600c2625e6eSJosh Paetzel struct nic_hwlro_cqe_part1 *cqe1 = NULL; 1601c2625e6eSJosh Paetzel struct mbuf *m = NULL; 1602c2625e6eSJosh Paetzel struct oce_common_cqe_info cq_info; 1603c2625e6eSJosh Paetzel 1604c2625e6eSJosh Paetzel /* parse cqe */ 1605c2625e6eSJosh Paetzel if(cqe2 == NULL) { 1606c2625e6eSJosh Paetzel cq_info.pkt_size = cqe->pkt_size; 1607c2625e6eSJosh Paetzel cq_info.vtag = cqe->vlan_tag; 1608c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe->l4_cksum_pass; 1609c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe->ip_cksum_pass; 1610c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe->ipv6_frame; 1611c2625e6eSJosh Paetzel cq_info.vtp = cqe->vtp; 1612c2625e6eSJosh Paetzel cq_info.qnq = cqe->qnq; 1613c2625e6eSJosh Paetzel }else { 1614c2625e6eSJosh Paetzel cqe1 = (struct nic_hwlro_cqe_part1 *)cqe; 1615c2625e6eSJosh Paetzel cq_info.pkt_size = cqe2->coalesced_size; 1616c2625e6eSJosh Paetzel cq_info.vtag = cqe2->vlan_tag; 1617c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe2->l4_cksum_pass; 1618c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe2->ip_cksum_pass; 1619c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe2->ipv6_frame; 1620c2625e6eSJosh Paetzel cq_info.vtp = cqe2->vtp; 1621c2625e6eSJosh Paetzel cq_info.qnq = cqe1->qnq; 1622c2625e6eSJosh Paetzel } 1623c2625e6eSJosh Paetzel 1624c2625e6eSJosh Paetzel cq_info.vtag = BSWAP_16(cq_info.vtag); 1625c2625e6eSJosh Paetzel 1626c2625e6eSJosh Paetzel cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size; 1627c2625e6eSJosh Paetzel if(cq_info.pkt_size % rq->cfg.frag_size) 1628c2625e6eSJosh Paetzel cq_info.num_frags++; 1629c2625e6eSJosh Paetzel 1630c2625e6eSJosh Paetzel oce_rx_mbuf_chain(rq, &cq_info, &m); 1631c2625e6eSJosh Paetzel 1632764c812dSJosh Paetzel if (m) { 1633c2625e6eSJosh Paetzel if(cqe2) { 1634c2625e6eSJosh Paetzel //assert(cqe2->valid != 0); 1635c2625e6eSJosh Paetzel 1636c2625e6eSJosh Paetzel //assert(cqe2->cqe_type != 2); 1637c2625e6eSJosh Paetzel oce_correct_header(m, cqe1, cqe2); 1638c2625e6eSJosh Paetzel } 1639c2625e6eSJosh Paetzel 1640c2625e6eSJosh Paetzel m->m_pkthdr.rcvif = sc->ifp; 1641c2625e6eSJosh Paetzel #if __FreeBSD_version >= 800000 1642c2625e6eSJosh Paetzel if (rq->queue_index) 1643c2625e6eSJosh Paetzel m->m_pkthdr.flowid = (rq->queue_index - 1); 1644c2625e6eSJosh Paetzel else 1645c2625e6eSJosh Paetzel m->m_pkthdr.flowid = rq->queue_index; 1646c2625e6eSJosh Paetzel M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 1647c2625e6eSJosh Paetzel #endif 1648c2625e6eSJosh Paetzel /* This deternies if vlan tag is Valid */ 1649c2625e6eSJosh Paetzel if (cq_info.vtp) { 1650c2625e6eSJosh Paetzel if (sc->function_mode & FNM_FLEX10_MODE) { 1651c2625e6eSJosh Paetzel /* FLEX10. If QnQ is not set, neglect VLAN */ 1652c2625e6eSJosh Paetzel if (cq_info.qnq) { 1653c2625e6eSJosh Paetzel m->m_pkthdr.ether_vtag = cq_info.vtag; 1654c2625e6eSJosh Paetzel m->m_flags |= M_VLANTAG; 1655c2625e6eSJosh Paetzel } 1656c2625e6eSJosh Paetzel } else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK)) { 1657c2625e6eSJosh Paetzel /* In UMC mode generally pvid will be striped by 1658c2625e6eSJosh Paetzel hw. But in some cases we have seen it comes 1659c2625e6eSJosh Paetzel with pvid. So if pvid == vlan, neglect vlan. 1660c2625e6eSJosh Paetzel */ 1661c2625e6eSJosh Paetzel m->m_pkthdr.ether_vtag = cq_info.vtag; 1662c2625e6eSJosh Paetzel m->m_flags |= M_VLANTAG; 1663c2625e6eSJosh Paetzel } 1664c2625e6eSJosh Paetzel } 1665c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 1666c2625e6eSJosh Paetzel 1667c2625e6eSJosh Paetzel (*sc->ifp->if_input) (sc->ifp, m); 1668c2625e6eSJosh Paetzel 1669c2625e6eSJosh Paetzel /* Update rx stats per queue */ 1670c2625e6eSJosh Paetzel rq->rx_stats.rx_pkts++; 1671c2625e6eSJosh Paetzel rq->rx_stats.rx_bytes += cq_info.pkt_size; 1672c2625e6eSJosh Paetzel rq->rx_stats.rx_frags += cq_info.num_frags; 1673c2625e6eSJosh Paetzel rq->rx_stats.rx_ucast_pkts++; 1674c2625e6eSJosh Paetzel } 1675c2625e6eSJosh Paetzel return; 1676c2625e6eSJosh Paetzel } 1677c2625e6eSJosh Paetzel 1678c2625e6eSJosh Paetzel static void 1679c2625e6eSJosh Paetzel oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1680c2625e6eSJosh Paetzel { 1681c2625e6eSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1682c2625e6eSJosh Paetzel int len; 1683c2625e6eSJosh Paetzel struct mbuf *m = NULL; 1684c2625e6eSJosh Paetzel struct oce_common_cqe_info cq_info; 1685c2625e6eSJosh Paetzel uint16_t vtag = 0; 1686c2625e6eSJosh Paetzel 1687c2625e6eSJosh Paetzel /* Is it a flush compl that has no data */ 1688c2625e6eSJosh Paetzel if(!cqe->u0.s.num_fragments) 1689c2625e6eSJosh Paetzel goto exit; 1690c2625e6eSJosh Paetzel 1691c2625e6eSJosh Paetzel len = cqe->u0.s.pkt_size; 1692c2625e6eSJosh Paetzel if (!len) { 1693c2625e6eSJosh Paetzel /*partial DMA workaround for Lancer*/ 1694c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 169514410265SConrad Meyer goto exit; 169614410265SConrad Meyer } 169714410265SConrad Meyer 1698c2625e6eSJosh Paetzel if (!oce_cqe_portid_valid(sc, cqe)) { 1699c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 1700c2625e6eSJosh Paetzel goto exit; 1701c2625e6eSJosh Paetzel } 1702c2625e6eSJosh Paetzel 1703c2625e6eSJosh Paetzel /* Get vlan_tag value */ 1704c2625e6eSJosh Paetzel if(IS_BE(sc) || IS_SH(sc)) 1705c2625e6eSJosh Paetzel vtag = BSWAP_16(cqe->u0.s.vlan_tag); 1706c2625e6eSJosh Paetzel else 1707c2625e6eSJosh Paetzel vtag = cqe->u0.s.vlan_tag; 1708c2625e6eSJosh Paetzel 1709c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass; 1710c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass; 1711c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe->u0.s.ip_ver; 1712c2625e6eSJosh Paetzel cq_info.num_frags = cqe->u0.s.num_fragments; 1713c2625e6eSJosh Paetzel cq_info.pkt_size = cqe->u0.s.pkt_size; 1714c2625e6eSJosh Paetzel 1715c2625e6eSJosh Paetzel oce_rx_mbuf_chain(rq, &cq_info, &m); 1716c2625e6eSJosh Paetzel 1717c2625e6eSJosh Paetzel if (m) { 17182f345d8eSLuigi Rizzo m->m_pkthdr.rcvif = sc->ifp; 17192f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1720291a1934SXin LI if (rq->queue_index) 1721291a1934SXin LI m->m_pkthdr.flowid = (rq->queue_index - 1); 1722291a1934SXin LI else 17232f345d8eSLuigi Rizzo m->m_pkthdr.flowid = rq->queue_index; 1724c2529042SHans Petter Selasky M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 17252f345d8eSLuigi Rizzo #endif 17269bd3250aSLuigi Rizzo /* This deternies if vlan tag is Valid */ 17272f345d8eSLuigi Rizzo if (oce_cqe_vtp_valid(sc, cqe)) { 17282f345d8eSLuigi Rizzo if (sc->function_mode & FNM_FLEX10_MODE) { 17299bd3250aSLuigi Rizzo /* FLEX10. If QnQ is not set, neglect VLAN */ 17302f345d8eSLuigi Rizzo if (cqe->u0.s.qnq) { 17312f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag; 17322f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG; 17332f345d8eSLuigi Rizzo } 17349bd3250aSLuigi Rizzo } else if (sc->pvid != (vtag & VLAN_VID_MASK)) { 17359bd3250aSLuigi Rizzo /* In UMC mode generally pvid will be striped by 17369bd3250aSLuigi Rizzo hw. But in some cases we have seen it comes 17379bd3250aSLuigi Rizzo with pvid. So if pvid == vlan, neglect vlan. 17389bd3250aSLuigi Rizzo */ 17392f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag; 17402f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG; 17412f345d8eSLuigi Rizzo } 17422f345d8eSLuigi Rizzo } 17432f345d8eSLuigi Rizzo 1744c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 1745ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 17462f345d8eSLuigi Rizzo /* Try to queue to LRO */ 17472f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && 17482f345d8eSLuigi Rizzo (cqe->u0.s.ip_cksum_pass) && 17492f345d8eSLuigi Rizzo (cqe->u0.s.l4_cksum_pass) && 17502f345d8eSLuigi Rizzo (!cqe->u0.s.ip_ver) && 17512f345d8eSLuigi Rizzo (rq->lro.lro_cnt != 0)) { 17522f345d8eSLuigi Rizzo 17532f345d8eSLuigi Rizzo if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 17542f345d8eSLuigi Rizzo rq->lro_pkts_queued ++; 17552f345d8eSLuigi Rizzo goto post_done; 17562f345d8eSLuigi Rizzo } 17572f345d8eSLuigi Rizzo /* If LRO posting fails then try to post to STACK */ 17582f345d8eSLuigi Rizzo } 1759ad512958SBjoern A. Zeeb #endif 17602f345d8eSLuigi Rizzo 17612f345d8eSLuigi Rizzo (*sc->ifp->if_input) (sc->ifp, m); 1762ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 17632f345d8eSLuigi Rizzo post_done: 1764ad512958SBjoern A. Zeeb #endif 17652f345d8eSLuigi Rizzo /* Update rx stats per queue */ 17662f345d8eSLuigi Rizzo rq->rx_stats.rx_pkts++; 17672f345d8eSLuigi Rizzo rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 17682f345d8eSLuigi Rizzo rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 17692f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 17702f345d8eSLuigi Rizzo rq->rx_stats.rx_mcast_pkts++; 17712f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 17722f345d8eSLuigi Rizzo rq->rx_stats.rx_ucast_pkts++; 17732f345d8eSLuigi Rizzo } 17742f345d8eSLuigi Rizzo exit: 17752f345d8eSLuigi Rizzo return; 17762f345d8eSLuigi Rizzo } 17772f345d8eSLuigi Rizzo 17782f345d8eSLuigi Rizzo 1779c2625e6eSJosh Paetzel void 1780c2625e6eSJosh Paetzel oce_discard_rx_comp(struct oce_rq *rq, int num_frags) 17812f345d8eSLuigi Rizzo { 1782c2625e6eSJosh Paetzel uint32_t i = 0; 17832f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 17842f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 17852f345d8eSLuigi Rizzo 17862f345d8eSLuigi Rizzo for (i = 0; i < num_frags; i++) { 1787c2625e6eSJosh Paetzel if (rq->ring->cidx == rq->ring->pidx) { 17882f345d8eSLuigi Rizzo device_printf(sc->dev, 1789c2625e6eSJosh Paetzel "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n"); 1790c2625e6eSJosh Paetzel return; 17912f345d8eSLuigi Rizzo } 1792c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->cidx]; 17932f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 17942f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, pd->map); 1795c2625e6eSJosh Paetzel if (pd->mbuf != NULL) { 17962f345d8eSLuigi Rizzo m_freem(pd->mbuf); 1797c2625e6eSJosh Paetzel pd->mbuf = NULL; 17982f345d8eSLuigi Rizzo } 17992f345d8eSLuigi Rizzo 1800c2625e6eSJosh Paetzel RING_GET(rq->ring, 1); 1801c2625e6eSJosh Paetzel rq->pending--; 1802c2625e6eSJosh Paetzel } 18032f345d8eSLuigi Rizzo } 18042f345d8eSLuigi Rizzo 18052f345d8eSLuigi Rizzo 18062f345d8eSLuigi Rizzo static int 18072f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 18082f345d8eSLuigi Rizzo { 18092f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1; 18102f345d8eSLuigi Rizzo int vtp = 0; 18112f345d8eSLuigi Rizzo 18122f345d8eSLuigi Rizzo if (sc->be3_native) { 18132f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 18142f345d8eSLuigi Rizzo vtp = cqe_v1->u0.s.vlan_tag_present; 18159bd3250aSLuigi Rizzo } else 18162f345d8eSLuigi Rizzo vtp = cqe->u0.s.vlan_tag_present; 18172f345d8eSLuigi Rizzo 18182f345d8eSLuigi Rizzo return vtp; 18192f345d8eSLuigi Rizzo 18202f345d8eSLuigi Rizzo } 18212f345d8eSLuigi Rizzo 18222f345d8eSLuigi Rizzo 18232f345d8eSLuigi Rizzo static int 18242f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 18252f345d8eSLuigi Rizzo { 18262f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1; 18272f345d8eSLuigi Rizzo int port_id = 0; 18282f345d8eSLuigi Rizzo 1829291a1934SXin LI if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) { 18302f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 18312f345d8eSLuigi Rizzo port_id = cqe_v1->u0.s.port; 18322f345d8eSLuigi Rizzo if (sc->port_id != port_id) 18332f345d8eSLuigi Rizzo return 0; 18342f345d8eSLuigi Rizzo } else 18352f345d8eSLuigi Rizzo ;/* For BE3 legacy and Lancer this is dummy */ 18362f345d8eSLuigi Rizzo 18372f345d8eSLuigi Rizzo return 1; 18382f345d8eSLuigi Rizzo 18392f345d8eSLuigi Rizzo } 18402f345d8eSLuigi Rizzo 1841ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 1842c2625e6eSJosh Paetzel void 18432f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq) 18442f345d8eSLuigi Rizzo { 18452f345d8eSLuigi Rizzo struct lro_ctrl *lro = &rq->lro; 18462f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 18472f345d8eSLuigi Rizzo 18482f345d8eSLuigi Rizzo if (!IF_LRO_ENABLED(sc)) 18492f345d8eSLuigi Rizzo return; 18502f345d8eSLuigi Rizzo 18516dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro); 18522f345d8eSLuigi Rizzo rq->lro_pkts_queued = 0; 18532f345d8eSLuigi Rizzo 18542f345d8eSLuigi Rizzo return; 18552f345d8eSLuigi Rizzo } 18562f345d8eSLuigi Rizzo 18572f345d8eSLuigi Rizzo 18582f345d8eSLuigi Rizzo static int 18592f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc) 18602f345d8eSLuigi Rizzo { 18612f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL; 18622f345d8eSLuigi Rizzo int i = 0, rc = 0; 18632f345d8eSLuigi Rizzo 18642f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) { 18652f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro; 18662f345d8eSLuigi Rizzo rc = tcp_lro_init(lro); 18672f345d8eSLuigi Rizzo if (rc != 0) { 18682f345d8eSLuigi Rizzo device_printf(sc->dev, "LRO init failed\n"); 18692f345d8eSLuigi Rizzo return rc; 18702f345d8eSLuigi Rizzo } 18712f345d8eSLuigi Rizzo lro->ifp = sc->ifp; 18722f345d8eSLuigi Rizzo } 18732f345d8eSLuigi Rizzo 18742f345d8eSLuigi Rizzo return rc; 18752f345d8eSLuigi Rizzo } 18769bd3250aSLuigi Rizzo 18772f345d8eSLuigi Rizzo 18782f345d8eSLuigi Rizzo void 18792f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc) 18802f345d8eSLuigi Rizzo { 18812f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL; 18822f345d8eSLuigi Rizzo int i = 0; 18832f345d8eSLuigi Rizzo 18842f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) { 18852f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro; 18862f345d8eSLuigi Rizzo if (lro) 18872f345d8eSLuigi Rizzo tcp_lro_free(lro); 18882f345d8eSLuigi Rizzo } 18892f345d8eSLuigi Rizzo } 1890cdaba892SXin LI #endif 18912f345d8eSLuigi Rizzo 18922f345d8eSLuigi Rizzo int 18932f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count) 18942f345d8eSLuigi Rizzo { 18952f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 18962f345d8eSLuigi Rizzo int i, in, rc; 18972f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 18982f345d8eSLuigi Rizzo bus_dma_segment_t segs[6]; 18992f345d8eSLuigi Rizzo int nsegs, added = 0; 19002f345d8eSLuigi Rizzo struct oce_nic_rqe *rqe; 19012f345d8eSLuigi Rizzo pd_rxulp_db_t rxdb_reg; 1902c2625e6eSJosh Paetzel uint32_t val = 0; 1903c2625e6eSJosh Paetzel uint32_t oce_max_rq_posts = 64; 19042f345d8eSLuigi Rizzo 1905cdaba892SXin LI bzero(&rxdb_reg, sizeof(pd_rxulp_db_t)); 19062f345d8eSLuigi Rizzo for (i = 0; i < count; i++) { 1907c2625e6eSJosh Paetzel in = (rq->ring->pidx + 1) % OCE_RQ_PACKET_ARRAY_SIZE; 19082f345d8eSLuigi Rizzo 1909c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->pidx]; 1910c2625e6eSJosh Paetzel pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size); 1911c2625e6eSJosh Paetzel if (pd->mbuf == NULL) { 1912c2625e6eSJosh Paetzel device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size); 19132f345d8eSLuigi Rizzo break; 1914c2625e6eSJosh Paetzel } 1915c2625e6eSJosh Paetzel pd->mbuf->m_nextpkt = NULL; 19162f345d8eSLuigi Rizzo 1917c2625e6eSJosh Paetzel pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size; 1918c2625e6eSJosh Paetzel 19192f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(rq->tag, 19202f345d8eSLuigi Rizzo pd->map, 19212f345d8eSLuigi Rizzo pd->mbuf, 19222f345d8eSLuigi Rizzo segs, &nsegs, BUS_DMA_NOWAIT); 19232f345d8eSLuigi Rizzo if (rc) { 19242f345d8eSLuigi Rizzo m_free(pd->mbuf); 1925c2625e6eSJosh Paetzel device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc); 19262f345d8eSLuigi Rizzo break; 19272f345d8eSLuigi Rizzo } 19282f345d8eSLuigi Rizzo 19292f345d8eSLuigi Rizzo if (nsegs != 1) { 19302f345d8eSLuigi Rizzo i--; 19312f345d8eSLuigi Rizzo continue; 19322f345d8eSLuigi Rizzo } 19332f345d8eSLuigi Rizzo 19342f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 19352f345d8eSLuigi Rizzo 19362f345d8eSLuigi Rizzo rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 19372f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 19382f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 19392f345d8eSLuigi Rizzo DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 19402f345d8eSLuigi Rizzo RING_PUT(rq->ring, 1); 19412f345d8eSLuigi Rizzo added++; 19422f345d8eSLuigi Rizzo rq->pending++; 19432f345d8eSLuigi Rizzo } 1944c2625e6eSJosh Paetzel oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS; 19452f345d8eSLuigi Rizzo if (added != 0) { 1946c2625e6eSJosh Paetzel for (i = added / oce_max_rq_posts; i > 0; i--) { 1947c2625e6eSJosh Paetzel rxdb_reg.bits.num_posted = oce_max_rq_posts; 19482f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id; 1949c2625e6eSJosh Paetzel if(rq->islro) { 1950c2625e6eSJosh Paetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK; 1951c2625e6eSJosh Paetzel val |= oce_max_rq_posts << 16; 1952c2625e6eSJosh Paetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val); 1953c2625e6eSJosh Paetzel }else { 19542f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1955c2625e6eSJosh Paetzel } 1956c2625e6eSJosh Paetzel added -= oce_max_rq_posts; 19572f345d8eSLuigi Rizzo } 19582f345d8eSLuigi Rizzo if (added > 0) { 19592f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id; 19602f345d8eSLuigi Rizzo rxdb_reg.bits.num_posted = added; 1961c2625e6eSJosh Paetzel if(rq->islro) { 1962c2625e6eSJosh Paetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK; 1963c2625e6eSJosh Paetzel val |= added << 16; 1964c2625e6eSJosh Paetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val); 1965c2625e6eSJosh Paetzel }else { 19662f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 19672f345d8eSLuigi Rizzo } 19682f345d8eSLuigi Rizzo } 1969c2625e6eSJosh Paetzel } 19702f345d8eSLuigi Rizzo 19712f345d8eSLuigi Rizzo return 0; 19722f345d8eSLuigi Rizzo } 19732f345d8eSLuigi Rizzo 1974c2625e6eSJosh Paetzel static void 1975c2625e6eSJosh Paetzel oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq) 1976c2625e6eSJosh Paetzel { 1977c2625e6eSJosh Paetzel if (num_cqes) { 1978c2625e6eSJosh Paetzel oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE); 1979c2625e6eSJosh Paetzel if(!sc->enable_hwlro) { 1980c2625e6eSJosh Paetzel if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1) 1981c2625e6eSJosh Paetzel oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1)); 1982c2625e6eSJosh Paetzel }else { 1983c2625e6eSJosh Paetzel if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64) 1984c2625e6eSJosh Paetzel oce_alloc_rx_bufs(rq, 64); 1985c2625e6eSJosh Paetzel } 1986c2625e6eSJosh Paetzel } 1987c2625e6eSJosh Paetzel 1988c2625e6eSJosh Paetzel return; 1989c2625e6eSJosh Paetzel } 1990c2625e6eSJosh Paetzel 1991c2625e6eSJosh Paetzel uint16_t 1992c2625e6eSJosh Paetzel oce_rq_handler_lro(void *arg) 1993c2625e6eSJosh Paetzel { 1994c2625e6eSJosh Paetzel struct oce_rq *rq = (struct oce_rq *)arg; 1995c2625e6eSJosh Paetzel struct oce_cq *cq = rq->cq; 1996c2625e6eSJosh Paetzel POCE_SOFTC sc = rq->parent; 1997c2625e6eSJosh Paetzel struct nic_hwlro_singleton_cqe *cqe; 1998c2625e6eSJosh Paetzel struct nic_hwlro_cqe_part2 *cqe2; 1999c2625e6eSJosh Paetzel int num_cqes = 0; 2000c2625e6eSJosh Paetzel 2001c2625e6eSJosh Paetzel LOCK(&rq->rx_lock); 2002c2625e6eSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2003c2625e6eSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 2004c2625e6eSJosh Paetzel while (cqe->valid) { 2005c2625e6eSJosh Paetzel if(cqe->cqe_type == 0) { /* singleton cqe */ 2006c2625e6eSJosh Paetzel /* we should not get singleton cqe after cqe1 on same rq */ 2007c2625e6eSJosh Paetzel if(rq->cqe_firstpart != NULL) { 2008c2625e6eSJosh Paetzel device_printf(sc->dev, "Got singleton cqe after cqe1 \n"); 2009c2625e6eSJosh Paetzel goto exit_rq_handler_lro; 2010c2625e6eSJosh Paetzel } 2011c2625e6eSJosh Paetzel if(cqe->error != 0) { 2012c2625e6eSJosh Paetzel rq->rx_stats.rxcp_err++; 2013c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2014c2625e6eSJosh Paetzel } 2015c2625e6eSJosh Paetzel oce_rx_lro(rq, cqe, NULL); 2016c2625e6eSJosh Paetzel rq->rx_stats.rx_compl++; 2017c2625e6eSJosh Paetzel cqe->valid = 0; 2018c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 2019c2625e6eSJosh Paetzel num_cqes++; 2020c2625e6eSJosh Paetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2021c2625e6eSJosh Paetzel break; 2022c2625e6eSJosh Paetzel }else if(cqe->cqe_type == 0x1) { /* first part */ 2023c2625e6eSJosh Paetzel /* we should not get cqe1 after cqe1 on same rq */ 2024c2625e6eSJosh Paetzel if(rq->cqe_firstpart != NULL) { 2025c2625e6eSJosh Paetzel device_printf(sc->dev, "Got cqe1 after cqe1 \n"); 2026c2625e6eSJosh Paetzel goto exit_rq_handler_lro; 2027c2625e6eSJosh Paetzel } 2028c2625e6eSJosh Paetzel rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe; 2029c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 2030c2625e6eSJosh Paetzel }else if(cqe->cqe_type == 0x2) { /* second part */ 2031c2625e6eSJosh Paetzel cqe2 = (struct nic_hwlro_cqe_part2 *)cqe; 2032c2625e6eSJosh Paetzel if(cqe2->error != 0) { 2033c2625e6eSJosh Paetzel rq->rx_stats.rxcp_err++; 2034c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2035c2625e6eSJosh Paetzel } 2036c2625e6eSJosh Paetzel /* We should not get cqe2 without cqe1 */ 2037c2625e6eSJosh Paetzel if(rq->cqe_firstpart == NULL) { 2038c2625e6eSJosh Paetzel device_printf(sc->dev, "Got cqe2 without cqe1 \n"); 2039c2625e6eSJosh Paetzel goto exit_rq_handler_lro; 2040c2625e6eSJosh Paetzel } 2041c2625e6eSJosh Paetzel oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2); 2042c2625e6eSJosh Paetzel 2043c2625e6eSJosh Paetzel rq->rx_stats.rx_compl++; 2044c2625e6eSJosh Paetzel rq->cqe_firstpart->valid = 0; 2045c2625e6eSJosh Paetzel cqe2->valid = 0; 2046c2625e6eSJosh Paetzel rq->cqe_firstpart = NULL; 2047c2625e6eSJosh Paetzel 2048c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 2049c2625e6eSJosh Paetzel num_cqes += 2; 2050c2625e6eSJosh Paetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2051c2625e6eSJosh Paetzel break; 2052c2625e6eSJosh Paetzel } 2053c2625e6eSJosh Paetzel 2054c2625e6eSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2055c2625e6eSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 2056c2625e6eSJosh Paetzel } 2057c2625e6eSJosh Paetzel oce_check_rx_bufs(sc, num_cqes, rq); 2058c2625e6eSJosh Paetzel exit_rq_handler_lro: 2059c2625e6eSJosh Paetzel UNLOCK(&rq->rx_lock); 2060c2625e6eSJosh Paetzel return 0; 2061c2625e6eSJosh Paetzel } 20622f345d8eSLuigi Rizzo 20632f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */ 20642f345d8eSLuigi Rizzo uint16_t 20652f345d8eSLuigi Rizzo oce_rq_handler(void *arg) 20662f345d8eSLuigi Rizzo { 20672f345d8eSLuigi Rizzo struct oce_rq *rq = (struct oce_rq *)arg; 20682f345d8eSLuigi Rizzo struct oce_cq *cq = rq->cq; 20692f345d8eSLuigi Rizzo POCE_SOFTC sc = rq->parent; 20702f345d8eSLuigi Rizzo struct oce_nic_rx_cqe *cqe; 2071c2625e6eSJosh Paetzel int num_cqes = 0; 20722f345d8eSLuigi Rizzo 2073c2625e6eSJosh Paetzel if(rq->islro) { 2074c2625e6eSJosh Paetzel oce_rq_handler_lro(arg); 2075c2625e6eSJosh Paetzel return 0; 2076c2625e6eSJosh Paetzel } 2077c2625e6eSJosh Paetzel LOCK(&rq->rx_lock); 20782f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 20792f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 20802f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 20812f345d8eSLuigi Rizzo while (cqe->u0.dw[2]) { 20822f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 20832f345d8eSLuigi Rizzo 20842f345d8eSLuigi Rizzo if (cqe->u0.s.error == 0) { 2085c2625e6eSJosh Paetzel oce_rx(rq, cqe); 20862f345d8eSLuigi Rizzo } else { 20872f345d8eSLuigi Rizzo rq->rx_stats.rxcp_err++; 2088c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 20892f345d8eSLuigi Rizzo /* Post L3/L4 errors to stack.*/ 2090c2625e6eSJosh Paetzel oce_rx(rq, cqe); 20912f345d8eSLuigi Rizzo } 20922f345d8eSLuigi Rizzo rq->rx_stats.rx_compl++; 20932f345d8eSLuigi Rizzo cqe->u0.dw[2] = 0; 20942f345d8eSLuigi Rizzo 2095ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 20962f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 20972f345d8eSLuigi Rizzo oce_rx_flush_lro(rq); 20982f345d8eSLuigi Rizzo } 2099ad512958SBjoern A. Zeeb #endif 21002f345d8eSLuigi Rizzo 21012f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 21022f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 21032f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 21042f345d8eSLuigi Rizzo cqe = 21052f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 21062f345d8eSLuigi Rizzo num_cqes++; 21072f345d8eSLuigi Rizzo if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 21082f345d8eSLuigi Rizzo break; 21092f345d8eSLuigi Rizzo } 21109bd3250aSLuigi Rizzo 2111ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 21122f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc)) 21132f345d8eSLuigi Rizzo oce_rx_flush_lro(rq); 2114ad512958SBjoern A. Zeeb #endif 21152f345d8eSLuigi Rizzo 2116c2625e6eSJosh Paetzel oce_check_rx_bufs(sc, num_cqes, rq); 2117c2625e6eSJosh Paetzel UNLOCK(&rq->rx_lock); 21182f345d8eSLuigi Rizzo return 0; 21192f345d8eSLuigi Rizzo 21202f345d8eSLuigi Rizzo } 21212f345d8eSLuigi Rizzo 21222f345d8eSLuigi Rizzo 21232f345d8eSLuigi Rizzo 21242f345d8eSLuigi Rizzo 21252f345d8eSLuigi Rizzo /***************************************************************************** 21262f345d8eSLuigi Rizzo * Helper function prototypes in this file * 21272f345d8eSLuigi Rizzo *****************************************************************************/ 21282f345d8eSLuigi Rizzo 21292f345d8eSLuigi Rizzo static int 21302f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc) 21312f345d8eSLuigi Rizzo { 21322f345d8eSLuigi Rizzo 21332f345d8eSLuigi Rizzo sc->ifp = if_alloc(IFT_ETHER); 21342f345d8eSLuigi Rizzo if (!sc->ifp) 21352f345d8eSLuigi Rizzo return ENOMEM; 21362f345d8eSLuigi Rizzo 21372f345d8eSLuigi Rizzo ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 21382f345d8eSLuigi Rizzo ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 21392f345d8eSLuigi Rizzo ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 21402f345d8eSLuigi Rizzo 21412f345d8eSLuigi Rizzo sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 21422f345d8eSLuigi Rizzo sc->ifp->if_ioctl = oce_ioctl; 21432f345d8eSLuigi Rizzo sc->ifp->if_start = oce_start; 21442f345d8eSLuigi Rizzo sc->ifp->if_init = oce_init; 21452f345d8eSLuigi Rizzo sc->ifp->if_mtu = ETHERMTU; 21462f345d8eSLuigi Rizzo sc->ifp->if_softc = sc; 21472f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 21482f345d8eSLuigi Rizzo sc->ifp->if_transmit = oce_multiq_start; 21492f345d8eSLuigi Rizzo sc->ifp->if_qflush = oce_multiq_flush; 21502f345d8eSLuigi Rizzo #endif 21512f345d8eSLuigi Rizzo 21522f345d8eSLuigi Rizzo if_initname(sc->ifp, 21532f345d8eSLuigi Rizzo device_get_name(sc->dev), device_get_unit(sc->dev)); 21542f345d8eSLuigi Rizzo 21552f345d8eSLuigi Rizzo sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 21562f345d8eSLuigi Rizzo IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 21572f345d8eSLuigi Rizzo IFQ_SET_READY(&sc->ifp->if_snd); 21582f345d8eSLuigi Rizzo 21592f345d8eSLuigi Rizzo sc->ifp->if_hwassist = OCE_IF_HWASSIST; 21602f345d8eSLuigi Rizzo sc->ifp->if_hwassist |= CSUM_TSO; 21612f345d8eSLuigi Rizzo sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 21622f345d8eSLuigi Rizzo 21632f345d8eSLuigi Rizzo sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 21642f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_HWCSUM; 21652f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 21669bd3250aSLuigi Rizzo 2167ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 2168ad512958SBjoern A. Zeeb sc->ifp->if_capabilities |= IFCAP_TSO; 21692f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_LRO; 21709bd3250aSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 2171ad512958SBjoern A. Zeeb #endif 21722f345d8eSLuigi Rizzo 21732f345d8eSLuigi Rizzo sc->ifp->if_capenable = sc->ifp->if_capabilities; 2174b245f96cSGleb Smirnoff sc->ifp->if_baudrate = IF_Gbps(10); 21752f345d8eSLuigi Rizzo 21765fbb6830SXin LI #if __FreeBSD_version >= 1000000 21779fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 21789fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomaxsegcount = OCE_MAX_TX_ELEMENTS; 21799fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomaxsegsize = 4096; 21805fbb6830SXin LI #endif 21815fbb6830SXin LI 21822f345d8eSLuigi Rizzo ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 21832f345d8eSLuigi Rizzo 21842f345d8eSLuigi Rizzo return 0; 21852f345d8eSLuigi Rizzo } 21862f345d8eSLuigi Rizzo 21872f345d8eSLuigi Rizzo 21882f345d8eSLuigi Rizzo static void 21892f345d8eSLuigi Rizzo oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 21902f345d8eSLuigi Rizzo { 21912f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 21922f345d8eSLuigi Rizzo 21932f345d8eSLuigi Rizzo if (ifp->if_softc != arg) 21942f345d8eSLuigi Rizzo return; 21952f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095)) 21962f345d8eSLuigi Rizzo return; 21972f345d8eSLuigi Rizzo 21982f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 1; 21992f345d8eSLuigi Rizzo sc->vlans_added++; 22005fbb6830SXin LI if (sc->vlans_added <= (sc->max_vlans + 1)) 22012f345d8eSLuigi Rizzo oce_vid_config(sc); 22022f345d8eSLuigi Rizzo } 22032f345d8eSLuigi Rizzo 22042f345d8eSLuigi Rizzo 22052f345d8eSLuigi Rizzo static void 22062f345d8eSLuigi Rizzo oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 22072f345d8eSLuigi Rizzo { 22082f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 22092f345d8eSLuigi Rizzo 22102f345d8eSLuigi Rizzo if (ifp->if_softc != arg) 22112f345d8eSLuigi Rizzo return; 22122f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095)) 22132f345d8eSLuigi Rizzo return; 22142f345d8eSLuigi Rizzo 22152f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 0; 22162f345d8eSLuigi Rizzo sc->vlans_added--; 22172f345d8eSLuigi Rizzo oce_vid_config(sc); 22182f345d8eSLuigi Rizzo } 22192f345d8eSLuigi Rizzo 22202f345d8eSLuigi Rizzo 22212f345d8eSLuigi Rizzo /* 22222f345d8eSLuigi Rizzo * A max of 64 vlans can be configured in BE. If the user configures 22232f345d8eSLuigi Rizzo * more, place the card in vlan promiscuous mode. 22242f345d8eSLuigi Rizzo */ 22252f345d8eSLuigi Rizzo static int 22262f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc) 22272f345d8eSLuigi Rizzo { 22282f345d8eSLuigi Rizzo struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 22292f345d8eSLuigi Rizzo uint16_t ntags = 0, i; 22302f345d8eSLuigi Rizzo int status = 0; 22312f345d8eSLuigi Rizzo 22322f345d8eSLuigi Rizzo if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 22332f345d8eSLuigi Rizzo (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 22342f345d8eSLuigi Rizzo for (i = 0; i < MAX_VLANS; i++) { 22352f345d8eSLuigi Rizzo if (sc->vlan_tag[i]) { 22362f345d8eSLuigi Rizzo vtags[ntags].vtag = i; 22372f345d8eSLuigi Rizzo ntags++; 22382f345d8eSLuigi Rizzo } 22392f345d8eSLuigi Rizzo } 22402f345d8eSLuigi Rizzo if (ntags) 22412f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id, 22422f345d8eSLuigi Rizzo vtags, ntags, 1, 0); 22432f345d8eSLuigi Rizzo } else 22442f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id, 22452f345d8eSLuigi Rizzo NULL, 0, 1, 1); 22462f345d8eSLuigi Rizzo return status; 22472f345d8eSLuigi Rizzo } 22482f345d8eSLuigi Rizzo 22492f345d8eSLuigi Rizzo 22502f345d8eSLuigi Rizzo static void 22512f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc) 22522f345d8eSLuigi Rizzo { 22532f345d8eSLuigi Rizzo uint32_t old_pmac_id = sc->pmac_id; 22542f345d8eSLuigi Rizzo int status = 0; 22552f345d8eSLuigi Rizzo 22562f345d8eSLuigi Rizzo 22572f345d8eSLuigi Rizzo status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 22582f345d8eSLuigi Rizzo sc->macaddr.size_of_struct); 22592f345d8eSLuigi Rizzo if (!status) 22602f345d8eSLuigi Rizzo return; 22612f345d8eSLuigi Rizzo 22622f345d8eSLuigi Rizzo status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 22632f345d8eSLuigi Rizzo sc->if_id, &sc->pmac_id); 22642f345d8eSLuigi Rizzo if (!status) { 22652f345d8eSLuigi Rizzo status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 22662f345d8eSLuigi Rizzo bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 22672f345d8eSLuigi Rizzo sc->macaddr.size_of_struct); 22682f345d8eSLuigi Rizzo } 22692f345d8eSLuigi Rizzo if (status) 22702f345d8eSLuigi Rizzo device_printf(sc->dev, "Failed update macaddress\n"); 22712f345d8eSLuigi Rizzo 22722f345d8eSLuigi Rizzo } 22732f345d8eSLuigi Rizzo 22742f345d8eSLuigi Rizzo 22752f345d8eSLuigi Rizzo static int 22762f345d8eSLuigi Rizzo oce_handle_passthrough(struct ifnet *ifp, caddr_t data) 22772f345d8eSLuigi Rizzo { 22782f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 22792f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data; 22802f345d8eSLuigi Rizzo int rc = ENXIO; 22812f345d8eSLuigi Rizzo char cookie[32] = {0}; 2282541d96aaSBrooks Davis void *priv_data = ifr_data_get_ptr(ifr); 22832f345d8eSLuigi Rizzo void *ioctl_ptr; 22842f345d8eSLuigi Rizzo uint32_t req_size; 22852f345d8eSLuigi Rizzo struct mbx_hdr req; 22862f345d8eSLuigi Rizzo OCE_DMA_MEM dma_mem; 2287cdaba892SXin LI struct mbx_common_get_cntl_attr *fw_cmd; 22882f345d8eSLuigi Rizzo 22892f345d8eSLuigi Rizzo if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 22902f345d8eSLuigi Rizzo return EFAULT; 22912f345d8eSLuigi Rizzo 22922f345d8eSLuigi Rizzo if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 22932f345d8eSLuigi Rizzo return EINVAL; 22942f345d8eSLuigi Rizzo 22952f345d8eSLuigi Rizzo ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 22962f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 22972f345d8eSLuigi Rizzo return EFAULT; 22982f345d8eSLuigi Rizzo 22992f345d8eSLuigi Rizzo req_size = le32toh(req.u0.req.request_length); 23002f345d8eSLuigi Rizzo if (req_size > 65536) 23012f345d8eSLuigi Rizzo return EINVAL; 23022f345d8eSLuigi Rizzo 23032f345d8eSLuigi Rizzo req_size += sizeof(struct mbx_hdr); 23042f345d8eSLuigi Rizzo rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 23052f345d8eSLuigi Rizzo if (rc) 23062f345d8eSLuigi Rizzo return ENOMEM; 23072f345d8eSLuigi Rizzo 23082f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 23092f345d8eSLuigi Rizzo rc = EFAULT; 23102f345d8eSLuigi Rizzo goto dma_free; 23112f345d8eSLuigi Rizzo } 23122f345d8eSLuigi Rizzo 23132f345d8eSLuigi Rizzo rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 23142f345d8eSLuigi Rizzo if (rc) { 23152f345d8eSLuigi Rizzo rc = EIO; 23162f345d8eSLuigi Rizzo goto dma_free; 23172f345d8eSLuigi Rizzo } 23182f345d8eSLuigi Rizzo 23192f345d8eSLuigi Rizzo if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 23202f345d8eSLuigi Rizzo rc = EFAULT; 23212f345d8eSLuigi Rizzo 2322cdaba892SXin LI /* 2323cdaba892SXin LI firmware is filling all the attributes for this ioctl except 2324cdaba892SXin LI the driver version..so fill it 2325cdaba892SXin LI */ 2326cdaba892SXin LI if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) { 2327cdaba892SXin LI fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr; 2328cdaba892SXin LI strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str, 2329cdaba892SXin LI COMPONENT_REVISION, strlen(COMPONENT_REVISION)); 2330cdaba892SXin LI } 2331cdaba892SXin LI 23322f345d8eSLuigi Rizzo dma_free: 23332f345d8eSLuigi Rizzo oce_dma_free(sc, &dma_mem); 23342f345d8eSLuigi Rizzo return rc; 23352f345d8eSLuigi Rizzo 23362f345d8eSLuigi Rizzo } 23372f345d8eSLuigi Rizzo 2338cdaba892SXin LI static void 2339cdaba892SXin LI oce_eqd_set_periodic(POCE_SOFTC sc) 2340cdaba892SXin LI { 2341cdaba892SXin LI struct oce_set_eqd set_eqd[OCE_MAX_EQ]; 2342cdaba892SXin LI struct oce_aic_obj *aic; 2343cdaba892SXin LI struct oce_eq *eqo; 2344cdaba892SXin LI uint64_t now = 0, delta; 2345cdaba892SXin LI int eqd, i, num = 0; 2346c2625e6eSJosh Paetzel uint32_t tx_reqs = 0, rxpkts = 0, pps; 2347c2625e6eSJosh Paetzel struct oce_wq *wq; 2348c2625e6eSJosh Paetzel struct oce_rq *rq; 2349c2625e6eSJosh Paetzel 2350c2625e6eSJosh Paetzel #define ticks_to_msecs(t) (1000 * (t) / hz) 2351cdaba892SXin LI 2352cdaba892SXin LI for (i = 0 ; i < sc->neqs; i++) { 2353cdaba892SXin LI eqo = sc->eq[i]; 2354cdaba892SXin LI aic = &sc->aic_obj[i]; 2355cdaba892SXin LI /* When setting the static eq delay from the user space */ 2356cdaba892SXin LI if (!aic->enable) { 2357c2625e6eSJosh Paetzel if (aic->ticks) 2358c2625e6eSJosh Paetzel aic->ticks = 0; 2359cdaba892SXin LI eqd = aic->et_eqd; 2360cdaba892SXin LI goto modify_eqd; 2361cdaba892SXin LI } 2362cdaba892SXin LI 2363c2625e6eSJosh Paetzel rq = sc->rq[i]; 2364c2625e6eSJosh Paetzel rxpkts = rq->rx_stats.rx_pkts; 2365c2625e6eSJosh Paetzel wq = sc->wq[i]; 2366c2625e6eSJosh Paetzel tx_reqs = wq->tx_stats.tx_reqs; 2367cdaba892SXin LI now = ticks; 2368cdaba892SXin LI 2369c2625e6eSJosh Paetzel if (!aic->ticks || now < aic->ticks || 2370c2625e6eSJosh Paetzel rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) { 2371c2625e6eSJosh Paetzel aic->prev_rxpkts = rxpkts; 2372c2625e6eSJosh Paetzel aic->prev_txreqs = tx_reqs; 2373c2625e6eSJosh Paetzel aic->ticks = now; 2374c2625e6eSJosh Paetzel continue; 2375c2625e6eSJosh Paetzel } 2376cdaba892SXin LI 2377c2625e6eSJosh Paetzel delta = ticks_to_msecs(now - aic->ticks); 2378cdaba892SXin LI 2379c2625e6eSJosh Paetzel pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) + 2380c2625e6eSJosh Paetzel (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta); 2381c2625e6eSJosh Paetzel eqd = (pps / 15000) << 2; 2382c2625e6eSJosh Paetzel if (eqd < 8) 2383cdaba892SXin LI eqd = 0; 2384cdaba892SXin LI 2385cdaba892SXin LI /* Make sure that the eq delay is in the known range */ 2386cdaba892SXin LI eqd = min(eqd, aic->max_eqd); 2387cdaba892SXin LI eqd = max(eqd, aic->min_eqd); 2388cdaba892SXin LI 2389c2625e6eSJosh Paetzel aic->prev_rxpkts = rxpkts; 2390c2625e6eSJosh Paetzel aic->prev_txreqs = tx_reqs; 2391c2625e6eSJosh Paetzel aic->ticks = now; 2392c2625e6eSJosh Paetzel 2393cdaba892SXin LI modify_eqd: 2394cdaba892SXin LI if (eqd != aic->cur_eqd) { 2395cdaba892SXin LI set_eqd[num].delay_multiplier = (eqd * 65)/100; 2396cdaba892SXin LI set_eqd[num].eq_id = eqo->eq_id; 2397cdaba892SXin LI aic->cur_eqd = eqd; 2398cdaba892SXin LI num++; 2399cdaba892SXin LI } 2400cdaba892SXin LI } 2401cdaba892SXin LI 2402cdaba892SXin LI /* Is there atleast one eq that needs to be modified? */ 2403c2625e6eSJosh Paetzel for(i = 0; i < num; i += 8) { 2404c2625e6eSJosh Paetzel if((num - i) >=8 ) 2405c2625e6eSJosh Paetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8); 2406c2625e6eSJosh Paetzel else 2407c2625e6eSJosh Paetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i)); 2408c2625e6eSJosh Paetzel } 2409c2625e6eSJosh Paetzel 2410cdaba892SXin LI } 24112f345d8eSLuigi Rizzo 24125fbb6830SXin LI static void oce_detect_hw_error(POCE_SOFTC sc) 24135fbb6830SXin LI { 24145fbb6830SXin LI 24155fbb6830SXin LI uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0; 24165fbb6830SXin LI uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; 24175fbb6830SXin LI uint32_t i; 24185fbb6830SXin LI 24195fbb6830SXin LI if (sc->hw_error) 24205fbb6830SXin LI return; 24215fbb6830SXin LI 24225fbb6830SXin LI if (IS_XE201(sc)) { 24235fbb6830SXin LI sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET); 24245fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24255fbb6830SXin LI sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET); 24265fbb6830SXin LI sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET); 24275fbb6830SXin LI } 24285fbb6830SXin LI } else { 24295fbb6830SXin LI ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW); 24305fbb6830SXin LI ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH); 24315fbb6830SXin LI ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK); 24325fbb6830SXin LI ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK); 24335fbb6830SXin LI 24345fbb6830SXin LI ue_low = (ue_low & ~ue_low_mask); 24355fbb6830SXin LI ue_high = (ue_high & ~ue_high_mask); 24365fbb6830SXin LI } 24375fbb6830SXin LI 24385fbb6830SXin LI /* On certain platforms BE hardware can indicate spurious UEs. 24395fbb6830SXin LI * Allow the h/w to stop working completely in case of a real UE. 24405fbb6830SXin LI * Hence not setting the hw_error for UE detection. 24415fbb6830SXin LI */ 24425fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24435fbb6830SXin LI sc->hw_error = TRUE; 24445fbb6830SXin LI device_printf(sc->dev, "Error detected in the card\n"); 24455fbb6830SXin LI } 24465fbb6830SXin LI 24475fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24485fbb6830SXin LI device_printf(sc->dev, 24495fbb6830SXin LI "ERR: sliport status 0x%x\n", sliport_status); 24505fbb6830SXin LI device_printf(sc->dev, 24515fbb6830SXin LI "ERR: sliport error1 0x%x\n", sliport_err1); 24525fbb6830SXin LI device_printf(sc->dev, 24535fbb6830SXin LI "ERR: sliport error2 0x%x\n", sliport_err2); 24545fbb6830SXin LI } 24555fbb6830SXin LI 24565fbb6830SXin LI if (ue_low) { 24575fbb6830SXin LI for (i = 0; ue_low; ue_low >>= 1, i++) { 24585fbb6830SXin LI if (ue_low & 1) 24595fbb6830SXin LI device_printf(sc->dev, "UE: %s bit set\n", 24605fbb6830SXin LI ue_status_low_desc[i]); 24615fbb6830SXin LI } 24625fbb6830SXin LI } 24635fbb6830SXin LI 24645fbb6830SXin LI if (ue_high) { 24655fbb6830SXin LI for (i = 0; ue_high; ue_high >>= 1, i++) { 24665fbb6830SXin LI if (ue_high & 1) 24675fbb6830SXin LI device_printf(sc->dev, "UE: %s bit set\n", 24685fbb6830SXin LI ue_status_hi_desc[i]); 24695fbb6830SXin LI } 24705fbb6830SXin LI } 24715fbb6830SXin LI 24725fbb6830SXin LI } 24735fbb6830SXin LI 24745fbb6830SXin LI 24752f345d8eSLuigi Rizzo static void 24762f345d8eSLuigi Rizzo oce_local_timer(void *arg) 24772f345d8eSLuigi Rizzo { 24782f345d8eSLuigi Rizzo POCE_SOFTC sc = arg; 24792f345d8eSLuigi Rizzo int i = 0; 24802f345d8eSLuigi Rizzo 24815fbb6830SXin LI oce_detect_hw_error(sc); 24822f345d8eSLuigi Rizzo oce_refresh_nic_stats(sc); 24832f345d8eSLuigi Rizzo oce_refresh_queue_stats(sc); 24842f345d8eSLuigi Rizzo oce_mac_addr_set(sc); 24852f345d8eSLuigi Rizzo 24862f345d8eSLuigi Rizzo /* TX Watch Dog*/ 24872f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) 24882f345d8eSLuigi Rizzo oce_tx_restart(sc, sc->wq[i]); 24892f345d8eSLuigi Rizzo 2490cdaba892SXin LI /* calculate and set the eq delay for optimal interrupt rate */ 2491291a1934SXin LI if (IS_BE(sc) || IS_SH(sc)) 2492cdaba892SXin LI oce_eqd_set_periodic(sc); 2493cdaba892SXin LI 24942f345d8eSLuigi Rizzo callout_reset(&sc->timer, hz, oce_local_timer, sc); 24952f345d8eSLuigi Rizzo } 24962f345d8eSLuigi Rizzo 2497c2625e6eSJosh Paetzel static void 2498c2625e6eSJosh Paetzel oce_tx_compl_clean(POCE_SOFTC sc) 2499c2625e6eSJosh Paetzel { 2500c2625e6eSJosh Paetzel struct oce_wq *wq; 2501c2625e6eSJosh Paetzel int i = 0, timeo = 0, num_wqes = 0; 2502c2625e6eSJosh Paetzel int pending_txqs = sc->nwqs; 2503c2625e6eSJosh Paetzel 2504c2625e6eSJosh Paetzel /* Stop polling for compls when HW has been silent for 10ms or 2505c2625e6eSJosh Paetzel * hw_error or no outstanding completions expected 2506c2625e6eSJosh Paetzel */ 2507c2625e6eSJosh Paetzel do { 2508c2625e6eSJosh Paetzel pending_txqs = sc->nwqs; 2509c2625e6eSJosh Paetzel 2510c2625e6eSJosh Paetzel for_all_wq_queues(sc, wq, i) { 2511c2625e6eSJosh Paetzel num_wqes = oce_wq_handler(wq); 2512c2625e6eSJosh Paetzel 2513c2625e6eSJosh Paetzel if(num_wqes) 2514c2625e6eSJosh Paetzel timeo = 0; 2515c2625e6eSJosh Paetzel 2516c2625e6eSJosh Paetzel if(!wq->ring->num_used) 2517c2625e6eSJosh Paetzel pending_txqs--; 2518c2625e6eSJosh Paetzel } 2519c2625e6eSJosh Paetzel 2520c2625e6eSJosh Paetzel if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error) 2521c2625e6eSJosh Paetzel break; 2522c2625e6eSJosh Paetzel 2523c2625e6eSJosh Paetzel DELAY(1000); 2524c2625e6eSJosh Paetzel } while (TRUE); 2525c2625e6eSJosh Paetzel 2526c2625e6eSJosh Paetzel for_all_wq_queues(sc, wq, i) { 2527c2625e6eSJosh Paetzel while(wq->ring->num_used) { 2528c2625e6eSJosh Paetzel LOCK(&wq->tx_compl_lock); 2529c2625e6eSJosh Paetzel oce_process_tx_completion(wq); 2530c2625e6eSJosh Paetzel UNLOCK(&wq->tx_compl_lock); 2531c2625e6eSJosh Paetzel } 2532c2625e6eSJosh Paetzel } 2533c2625e6eSJosh Paetzel 2534c2625e6eSJosh Paetzel } 25352f345d8eSLuigi Rizzo 2536beb0f7e7SJosh Paetzel /* NOTE : This should only be called holding 2537beb0f7e7SJosh Paetzel * DEVICE_LOCK. 2538beb0f7e7SJosh Paetzel */ 25392f345d8eSLuigi Rizzo static void 25402f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc) 25412f345d8eSLuigi Rizzo { 2542c2625e6eSJosh Paetzel int i; 25432f345d8eSLuigi Rizzo struct oce_rq *rq; 25442f345d8eSLuigi Rizzo struct oce_wq *wq; 25452f345d8eSLuigi Rizzo struct oce_eq *eq; 25462f345d8eSLuigi Rizzo 25472f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 25482f345d8eSLuigi Rizzo 2549c2625e6eSJosh Paetzel oce_tx_compl_clean(sc); 25502f345d8eSLuigi Rizzo 25512f345d8eSLuigi Rizzo /* Stop intrs and finish any bottom halves pending */ 25522f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 25532f345d8eSLuigi Rizzo 2554cdaba892SXin LI /* Since taskqueue_drain takes a Gaint Lock, We should not acquire 2555beb0f7e7SJosh Paetzel any other lock. So unlock device lock and require after 2556beb0f7e7SJosh Paetzel completing taskqueue_drain. 2557beb0f7e7SJosh Paetzel */ 2558beb0f7e7SJosh Paetzel UNLOCK(&sc->dev_lock); 25592f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) { 25602f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) { 25612f345d8eSLuigi Rizzo taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 25622f345d8eSLuigi Rizzo } 25632f345d8eSLuigi Rizzo } 2564beb0f7e7SJosh Paetzel LOCK(&sc->dev_lock); 25652f345d8eSLuigi Rizzo 25662f345d8eSLuigi Rizzo /* Delete RX queue in card with flush param */ 25672f345d8eSLuigi Rizzo oce_stop_rx(sc); 25682f345d8eSLuigi Rizzo 25692f345d8eSLuigi Rizzo /* Invalidate any pending cq and eq entries*/ 25702f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) 25712f345d8eSLuigi Rizzo oce_drain_eq(eq); 25722f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) 25732f345d8eSLuigi Rizzo oce_drain_rq_cq(rq); 25742f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) 25752f345d8eSLuigi Rizzo oce_drain_wq_cq(wq); 25762f345d8eSLuigi Rizzo 25772f345d8eSLuigi Rizzo /* But still we need to get MCC aync events. 25782f345d8eSLuigi Rizzo So enable intrs and also arm first EQ 25792f345d8eSLuigi Rizzo */ 25802f345d8eSLuigi Rizzo oce_hw_intr_enable(sc); 25812f345d8eSLuigi Rizzo oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 25822f345d8eSLuigi Rizzo 25832f345d8eSLuigi Rizzo DELAY(10); 25842f345d8eSLuigi Rizzo } 25852f345d8eSLuigi Rizzo 25862f345d8eSLuigi Rizzo 25872f345d8eSLuigi Rizzo static void 25882f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc) 25892f345d8eSLuigi Rizzo { 25902f345d8eSLuigi Rizzo struct oce_eq *eq; 25912f345d8eSLuigi Rizzo struct oce_rq *rq; 25922f345d8eSLuigi Rizzo struct oce_wq *wq; 25932f345d8eSLuigi Rizzo int i, rc = 0; 25942f345d8eSLuigi Rizzo 25952f345d8eSLuigi Rizzo sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 25962f345d8eSLuigi Rizzo 25972f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 25982f345d8eSLuigi Rizzo 25992f345d8eSLuigi Rizzo oce_start_rx(sc); 26002f345d8eSLuigi Rizzo 26012f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 26022f345d8eSLuigi Rizzo rc = oce_start_rq(rq); 26032f345d8eSLuigi Rizzo if (rc) 26042f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start RX\n"); 26052f345d8eSLuigi Rizzo } 26062f345d8eSLuigi Rizzo 26072f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) { 26082f345d8eSLuigi Rizzo rc = oce_start_wq(wq); 26092f345d8eSLuigi Rizzo if (rc) 26102f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start TX\n"); 26112f345d8eSLuigi Rizzo } 26122f345d8eSLuigi Rizzo 26132f345d8eSLuigi Rizzo 26142f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) 26152f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 26162f345d8eSLuigi Rizzo 26172f345d8eSLuigi Rizzo oce_hw_intr_enable(sc); 26182f345d8eSLuigi Rizzo 26192f345d8eSLuigi Rizzo } 26202f345d8eSLuigi Rizzo 26219bd3250aSLuigi Rizzo static void 26229bd3250aSLuigi Rizzo process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe) 26232f345d8eSLuigi Rizzo { 26249bd3250aSLuigi Rizzo /* Update Link status */ 26252f345d8eSLuigi Rizzo if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 26262f345d8eSLuigi Rizzo ASYNC_EVENT_LINK_UP) { 26272f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_UP; 26282f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_UP); 26292f345d8eSLuigi Rizzo } else { 26302f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_DOWN; 26312f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_DOWN); 26322f345d8eSLuigi Rizzo } 26339bd3250aSLuigi Rizzo } 26349bd3250aSLuigi Rizzo 26359bd3250aSLuigi Rizzo 2636c2625e6eSJosh Paetzel static void oce_async_grp5_osbmc_process(POCE_SOFTC sc, 2637c2625e6eSJosh Paetzel struct oce_async_evt_grp5_os2bmc *evt) 2638c2625e6eSJosh Paetzel { 2639c2625e6eSJosh Paetzel DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc)); 2640c2625e6eSJosh Paetzel if (evt->u.s.mgmt_enable) 2641c2625e6eSJosh Paetzel sc->flags |= OCE_FLAGS_OS2BMC; 2642c2625e6eSJosh Paetzel else 2643c2625e6eSJosh Paetzel return; 2644c2625e6eSJosh Paetzel 2645c2625e6eSJosh Paetzel sc->bmc_filt_mask = evt->u.s.arp_filter; 2646c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1); 2647c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2); 2648c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3); 2649c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4); 2650c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5); 2651c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6); 2652c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7); 2653c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8); 2654c2625e6eSJosh Paetzel } 2655c2625e6eSJosh Paetzel 2656c2625e6eSJosh Paetzel 2657c2625e6eSJosh Paetzel static void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe) 2658c2625e6eSJosh Paetzel { 2659c2625e6eSJosh Paetzel struct oce_async_event_grp5_pvid_state *gcqe; 2660c2625e6eSJosh Paetzel struct oce_async_evt_grp5_os2bmc *bmccqe; 2661c2625e6eSJosh Paetzel 2662c2625e6eSJosh Paetzel switch (cqe->u0.s.async_type) { 2663c2625e6eSJosh Paetzel case ASYNC_EVENT_PVID_STATE: 2664c2625e6eSJosh Paetzel /* GRP5 PVID */ 2665c2625e6eSJosh Paetzel gcqe = (struct oce_async_event_grp5_pvid_state *)cqe; 2666c2625e6eSJosh Paetzel if (gcqe->enabled) 2667c2625e6eSJosh Paetzel sc->pvid = gcqe->tag & VLAN_VID_MASK; 2668c2625e6eSJosh Paetzel else 2669c2625e6eSJosh Paetzel sc->pvid = 0; 2670c2625e6eSJosh Paetzel break; 2671c2625e6eSJosh Paetzel case ASYNC_EVENT_OS2BMC: 2672c2625e6eSJosh Paetzel bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe; 2673c2625e6eSJosh Paetzel oce_async_grp5_osbmc_process(sc, bmccqe); 2674c2625e6eSJosh Paetzel break; 2675c2625e6eSJosh Paetzel default: 2676c2625e6eSJosh Paetzel break; 2677c2625e6eSJosh Paetzel } 2678c2625e6eSJosh Paetzel } 2679c2625e6eSJosh Paetzel 26809bd3250aSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */ 26819bd3250aSLuigi Rizzo uint16_t 26829bd3250aSLuigi Rizzo oce_mq_handler(void *arg) 26839bd3250aSLuigi Rizzo { 26849bd3250aSLuigi Rizzo struct oce_mq *mq = (struct oce_mq *)arg; 26859bd3250aSLuigi Rizzo POCE_SOFTC sc = mq->parent; 26869bd3250aSLuigi Rizzo struct oce_cq *cq = mq->cq; 26879bd3250aSLuigi Rizzo int num_cqes = 0, evt_type = 0, optype = 0; 26889bd3250aSLuigi Rizzo struct oce_mq_cqe *cqe; 26899bd3250aSLuigi Rizzo struct oce_async_cqe_link_state *acqe; 2690cdaba892SXin LI struct oce_async_event_qnq *dbgcqe; 26919bd3250aSLuigi Rizzo 26929bd3250aSLuigi Rizzo 26939bd3250aSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 26949bd3250aSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 26959bd3250aSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 26969bd3250aSLuigi Rizzo 26979bd3250aSLuigi Rizzo while (cqe->u0.dw[3]) { 26989bd3250aSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 26999bd3250aSLuigi Rizzo if (cqe->u0.s.async_event) { 27009bd3250aSLuigi Rizzo evt_type = cqe->u0.s.event_type; 27019bd3250aSLuigi Rizzo optype = cqe->u0.s.async_type; 27029bd3250aSLuigi Rizzo if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) { 27039bd3250aSLuigi Rizzo /* Link status evt */ 27049bd3250aSLuigi Rizzo acqe = (struct oce_async_cqe_link_state *)cqe; 27059bd3250aSLuigi Rizzo process_link_state(sc, acqe); 2706c2625e6eSJosh Paetzel } else if (evt_type == ASYNC_EVENT_GRP5) { 2707c2625e6eSJosh Paetzel oce_process_grp5_events(sc, cqe); 2708c2625e6eSJosh Paetzel } else if (evt_type == ASYNC_EVENT_CODE_DEBUG && 2709cdaba892SXin LI optype == ASYNC_EVENT_DEBUG_QNQ) { 2710c2625e6eSJosh Paetzel dbgcqe = (struct oce_async_event_qnq *)cqe; 2711cdaba892SXin LI if(dbgcqe->valid) 2712cdaba892SXin LI sc->qnqid = dbgcqe->vlan_tag; 2713cdaba892SXin LI sc->qnq_debug_event = TRUE; 2714cdaba892SXin LI } 27152f345d8eSLuigi Rizzo } 27162f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 27172f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 27182f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 27192f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 27202f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 27212f345d8eSLuigi Rizzo num_cqes++; 27222f345d8eSLuigi Rizzo } 27232f345d8eSLuigi Rizzo 27242f345d8eSLuigi Rizzo if (num_cqes) 27252f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 27262f345d8eSLuigi Rizzo 27272f345d8eSLuigi Rizzo return 0; 27282f345d8eSLuigi Rizzo } 27292f345d8eSLuigi Rizzo 27302f345d8eSLuigi Rizzo 27312f345d8eSLuigi Rizzo static void 27322f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc) 27332f345d8eSLuigi Rizzo { 27342f345d8eSLuigi Rizzo /* Check if it is FLEX machine. Is so dont use RSS */ 27352f345d8eSLuigi Rizzo if ((sc->function_mode & FNM_FLEX10_MODE) || 27369bd3250aSLuigi Rizzo (sc->function_mode & FNM_UMC_MODE) || 27379bd3250aSLuigi Rizzo (sc->function_mode & FNM_VNIC_MODE) || 2738291a1934SXin LI (!is_rss_enabled(sc)) || 2739a4f734b4SXin LI IS_BE2(sc)) { 27402f345d8eSLuigi Rizzo sc->nrqs = 1; 27412f345d8eSLuigi Rizzo sc->nwqs = 1; 27425fbb6830SXin LI } else { 27435fbb6830SXin LI sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 27445fbb6830SXin LI sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs); 27452f345d8eSLuigi Rizzo } 2746a4f734b4SXin LI 2747a4f734b4SXin LI if (IS_BE2(sc) && is_rss_enabled(sc)) 2748a4f734b4SXin LI sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 27492f345d8eSLuigi Rizzo } 27502f345d8eSLuigi Rizzo 27512f345d8eSLuigi Rizzo 27522f345d8eSLuigi Rizzo static void 27532f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc) 27542f345d8eSLuigi Rizzo { 2755291a1934SXin LI if (is_rss_enabled(sc)) { 27562f345d8eSLuigi Rizzo sc->nrqs = sc->intr_count + 1; 27572f345d8eSLuigi Rizzo sc->nwqs = sc->intr_count; 27582f345d8eSLuigi Rizzo } else { 27592f345d8eSLuigi Rizzo sc->nrqs = 1; 27602f345d8eSLuigi Rizzo sc->nwqs = 1; 27612f345d8eSLuigi Rizzo } 2762a4f734b4SXin LI 2763a4f734b4SXin LI if (IS_BE2(sc)) 2764a4f734b4SXin LI sc->nwqs = 1; 27652f345d8eSLuigi Rizzo } 27662f345d8eSLuigi Rizzo 2767cdaba892SXin LI static int 2768cdaba892SXin LI oce_check_ipv6_ext_hdr(struct mbuf *m) 2769cdaba892SXin LI { 2770cdaba892SXin LI struct ether_header *eh = mtod(m, struct ether_header *); 2771cdaba892SXin LI caddr_t m_datatemp = m->m_data; 2772cdaba892SXin LI 2773cdaba892SXin LI if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 2774cdaba892SXin LI m->m_data += sizeof(struct ether_header); 2775cdaba892SXin LI struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 2776cdaba892SXin LI 2777cdaba892SXin LI if((ip6->ip6_nxt != IPPROTO_TCP) && \ 2778cdaba892SXin LI (ip6->ip6_nxt != IPPROTO_UDP)){ 2779cdaba892SXin LI struct ip6_ext *ip6e = NULL; 2780cdaba892SXin LI m->m_data += sizeof(struct ip6_hdr); 2781cdaba892SXin LI 2782cdaba892SXin LI ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *); 2783cdaba892SXin LI if(ip6e->ip6e_len == 0xff) { 2784cdaba892SXin LI m->m_data = m_datatemp; 2785cdaba892SXin LI return TRUE; 2786cdaba892SXin LI } 2787cdaba892SXin LI } 2788cdaba892SXin LI m->m_data = m_datatemp; 2789cdaba892SXin LI } 2790cdaba892SXin LI return FALSE; 2791cdaba892SXin LI } 2792cdaba892SXin LI 2793cdaba892SXin LI static int 2794cdaba892SXin LI is_be3_a1(POCE_SOFTC sc) 2795cdaba892SXin LI { 2796cdaba892SXin LI if((sc->flags & OCE_FLAGS_BE3) && ((sc->asic_revision & 0xFF) < 2)) { 2797cdaba892SXin LI return TRUE; 2798cdaba892SXin LI } 2799cdaba892SXin LI return FALSE; 2800cdaba892SXin LI } 2801cdaba892SXin LI 2802cdaba892SXin LI static struct mbuf * 2803cdaba892SXin LI oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete) 2804cdaba892SXin LI { 2805cdaba892SXin LI uint16_t vlan_tag = 0; 2806cdaba892SXin LI 2807cdaba892SXin LI if(!M_WRITABLE(m)) 2808cdaba892SXin LI return NULL; 2809cdaba892SXin LI 2810cdaba892SXin LI /* Embed vlan tag in the packet if it is not part of it */ 2811cdaba892SXin LI if(m->m_flags & M_VLANTAG) { 2812cdaba892SXin LI vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 2813cdaba892SXin LI m->m_flags &= ~M_VLANTAG; 2814cdaba892SXin LI } 2815cdaba892SXin LI 2816cdaba892SXin LI /* if UMC, ignore vlan tag insertion and instead insert pvid */ 2817cdaba892SXin LI if(sc->pvid) { 2818cdaba892SXin LI if(!vlan_tag) 2819cdaba892SXin LI vlan_tag = sc->pvid; 2820c2625e6eSJosh Paetzel if (complete) 2821cdaba892SXin LI *complete = FALSE; 2822cdaba892SXin LI } 2823cdaba892SXin LI 2824cdaba892SXin LI if(vlan_tag) { 2825cdaba892SXin LI m = ether_vlanencap(m, vlan_tag); 2826cdaba892SXin LI } 2827cdaba892SXin LI 2828cdaba892SXin LI if(sc->qnqid) { 2829cdaba892SXin LI m = ether_vlanencap(m, sc->qnqid); 2830c2625e6eSJosh Paetzel 2831c2625e6eSJosh Paetzel if (complete) 2832cdaba892SXin LI *complete = FALSE; 2833cdaba892SXin LI } 2834cdaba892SXin LI return m; 2835cdaba892SXin LI } 2836cdaba892SXin LI 2837cdaba892SXin LI static int 2838cdaba892SXin LI oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m) 2839cdaba892SXin LI { 2840cdaba892SXin LI if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \ 2841cdaba892SXin LI oce_check_ipv6_ext_hdr(m)) { 2842cdaba892SXin LI return TRUE; 2843cdaba892SXin LI } 2844cdaba892SXin LI return FALSE; 2845cdaba892SXin LI } 2846291a1934SXin LI 2847291a1934SXin LI static void 2848291a1934SXin LI oce_get_config(POCE_SOFTC sc) 2849291a1934SXin LI { 2850291a1934SXin LI int rc = 0; 2851291a1934SXin LI uint32_t max_rss = 0; 2852291a1934SXin LI 2853291a1934SXin LI if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native)) 2854291a1934SXin LI max_rss = OCE_LEGACY_MODE_RSS; 2855291a1934SXin LI else 2856291a1934SXin LI max_rss = OCE_MAX_RSS; 2857291a1934SXin LI 2858291a1934SXin LI if (!IS_BE(sc)) { 2859b41206d8SXin LI rc = oce_get_profile_config(sc, max_rss); 2860291a1934SXin LI if (rc) { 2861291a1934SXin LI sc->nwqs = OCE_MAX_WQ; 2862291a1934SXin LI sc->nrssqs = max_rss; 2863291a1934SXin LI sc->nrqs = sc->nrssqs + 1; 2864291a1934SXin LI } 2865291a1934SXin LI } 2866b41206d8SXin LI else { /* For BE3 don't rely on fw for determining the resources */ 2867291a1934SXin LI sc->nrssqs = max_rss; 2868291a1934SXin LI sc->nrqs = sc->nrssqs + 1; 2869291a1934SXin LI sc->nwqs = OCE_MAX_WQ; 2870b41206d8SXin LI sc->max_vlans = MAX_VLANFILTER_SIZE; 2871291a1934SXin LI } 2872291a1934SXin LI } 2873c2625e6eSJosh Paetzel 2874c2625e6eSJosh Paetzel static void 2875c2625e6eSJosh Paetzel oce_rdma_close(void) 2876c2625e6eSJosh Paetzel { 2877c2625e6eSJosh Paetzel if (oce_rdma_if != NULL) { 2878c2625e6eSJosh Paetzel oce_rdma_if = NULL; 2879c2625e6eSJosh Paetzel } 2880c2625e6eSJosh Paetzel } 2881c2625e6eSJosh Paetzel 2882c2625e6eSJosh Paetzel static void 2883c2625e6eSJosh Paetzel oce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr) 2884c2625e6eSJosh Paetzel { 2885c2625e6eSJosh Paetzel memcpy(macaddr, sc->macaddr.mac_addr, 6); 2886c2625e6eSJosh Paetzel } 2887c2625e6eSJosh Paetzel 2888c2625e6eSJosh Paetzel int 2889c2625e6eSJosh Paetzel oce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if) 2890c2625e6eSJosh Paetzel { 2891c2625e6eSJosh Paetzel POCE_SOFTC sc; 2892c2625e6eSJosh Paetzel struct oce_dev_info di; 2893c2625e6eSJosh Paetzel int i; 2894c2625e6eSJosh Paetzel 2895c2625e6eSJosh Paetzel if ((rdma_info == NULL) || (rdma_if == NULL)) { 2896c2625e6eSJosh Paetzel return -EINVAL; 2897c2625e6eSJosh Paetzel } 2898c2625e6eSJosh Paetzel 2899c2625e6eSJosh Paetzel if ((rdma_info->size != OCE_RDMA_INFO_SIZE) || 2900c2625e6eSJosh Paetzel (rdma_if->size != OCE_RDMA_IF_SIZE)) { 2901c2625e6eSJosh Paetzel return -ENXIO; 2902c2625e6eSJosh Paetzel } 2903c2625e6eSJosh Paetzel 2904c2625e6eSJosh Paetzel rdma_info->close = oce_rdma_close; 2905c2625e6eSJosh Paetzel rdma_info->mbox_post = oce_mbox_post; 2906c2625e6eSJosh Paetzel rdma_info->common_req_hdr_init = mbx_common_req_hdr_init; 2907c2625e6eSJosh Paetzel rdma_info->get_mac_addr = oce_get_mac_addr; 2908c2625e6eSJosh Paetzel 2909c2625e6eSJosh Paetzel oce_rdma_if = rdma_if; 2910c2625e6eSJosh Paetzel 2911c2625e6eSJosh Paetzel sc = softc_head; 2912c2625e6eSJosh Paetzel while (sc != NULL) { 2913c2625e6eSJosh Paetzel if (oce_rdma_if->announce != NULL) { 2914c2625e6eSJosh Paetzel memset(&di, 0, sizeof(di)); 2915c2625e6eSJosh Paetzel di.dev = sc->dev; 2916c2625e6eSJosh Paetzel di.softc = sc; 2917c2625e6eSJosh Paetzel di.ifp = sc->ifp; 2918c2625e6eSJosh Paetzel di.db_bhandle = sc->db_bhandle; 2919c2625e6eSJosh Paetzel di.db_btag = sc->db_btag; 2920c2625e6eSJosh Paetzel di.db_page_size = 4096; 2921c2625e6eSJosh Paetzel if (sc->flags & OCE_FLAGS_USING_MSIX) { 2922c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_MSIX; 2923c2625e6eSJosh Paetzel } else if (sc->flags & OCE_FLAGS_USING_MSI) { 2924c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_MSI; 2925c2625e6eSJosh Paetzel } else { 2926c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_INTX; 2927c2625e6eSJosh Paetzel } 2928c2625e6eSJosh Paetzel di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk 2929c2625e6eSJosh Paetzel if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) { 2930c2625e6eSJosh Paetzel di.msix.num_vectors = sc->intr_count + sc->roce_intr_count; 2931c2625e6eSJosh Paetzel di.msix.start_vector = sc->intr_count; 2932c2625e6eSJosh Paetzel for (i=0; i<di.msix.num_vectors; i++) { 2933c2625e6eSJosh Paetzel di.msix.vector_list[i] = sc->intrs[i].vector; 2934c2625e6eSJosh Paetzel } 2935c2625e6eSJosh Paetzel } else { 2936c2625e6eSJosh Paetzel } 2937c2625e6eSJosh Paetzel memcpy(di.mac_addr, sc->macaddr.mac_addr, 6); 2938c2625e6eSJosh Paetzel di.vendor_id = pci_get_vendor(sc->dev); 2939c2625e6eSJosh Paetzel di.dev_id = pci_get_device(sc->dev); 2940c2625e6eSJosh Paetzel 2941c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 2942c2625e6eSJosh Paetzel di.flags |= OCE_RDMA_INFO_RDMA_SUPPORTED; 2943c2625e6eSJosh Paetzel } 2944c2625e6eSJosh Paetzel 2945c2625e6eSJosh Paetzel rdma_if->announce(&di); 2946c2625e6eSJosh Paetzel sc = sc->next; 2947c2625e6eSJosh Paetzel } 2948c2625e6eSJosh Paetzel } 2949c2625e6eSJosh Paetzel 2950c2625e6eSJosh Paetzel return 0; 2951c2625e6eSJosh Paetzel } 2952c2625e6eSJosh Paetzel 2953c2625e6eSJosh Paetzel static void 2954c2625e6eSJosh Paetzel oce_read_env_variables( POCE_SOFTC sc ) 2955c2625e6eSJosh Paetzel { 2956c2625e6eSJosh Paetzel char *value = NULL; 2957c2625e6eSJosh Paetzel int rc = 0; 2958c2625e6eSJosh Paetzel 2959c2625e6eSJosh Paetzel /* read if user wants to enable hwlro or swlro */ 2960c2625e6eSJosh Paetzel //value = getenv("oce_enable_hwlro"); 2961c2625e6eSJosh Paetzel if(value && IS_SH(sc)) { 2962c2625e6eSJosh Paetzel sc->enable_hwlro = strtol(value, NULL, 10); 2963c2625e6eSJosh Paetzel if(sc->enable_hwlro) { 2964c2625e6eSJosh Paetzel rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL); 2965c2625e6eSJosh Paetzel if(rc) { 2966c2625e6eSJosh Paetzel device_printf(sc->dev, "no hardware lro support\n"); 2967c2625e6eSJosh Paetzel device_printf(sc->dev, "software lro enabled\n"); 2968c2625e6eSJosh Paetzel sc->enable_hwlro = 0; 2969c2625e6eSJosh Paetzel }else { 2970c2625e6eSJosh Paetzel device_printf(sc->dev, "hardware lro enabled\n"); 2971c2625e6eSJosh Paetzel oce_max_rsp_handled = 32; 2972c2625e6eSJosh Paetzel } 2973c2625e6eSJosh Paetzel }else { 2974c2625e6eSJosh Paetzel device_printf(sc->dev, "software lro enabled\n"); 2975c2625e6eSJosh Paetzel } 2976c2625e6eSJosh Paetzel }else { 2977c2625e6eSJosh Paetzel sc->enable_hwlro = 0; 2978c2625e6eSJosh Paetzel } 2979c2625e6eSJosh Paetzel 2980c2625e6eSJosh Paetzel /* read mbuf size */ 2981c2625e6eSJosh Paetzel //value = getenv("oce_rq_buf_size"); 2982c2625e6eSJosh Paetzel if(value && IS_SH(sc)) { 2983c2625e6eSJosh Paetzel oce_rq_buf_size = strtol(value, NULL, 10); 2984c2625e6eSJosh Paetzel switch(oce_rq_buf_size) { 2985c2625e6eSJosh Paetzel case 2048: 2986c2625e6eSJosh Paetzel case 4096: 2987c2625e6eSJosh Paetzel case 9216: 2988c2625e6eSJosh Paetzel case 16384: 2989c2625e6eSJosh Paetzel break; 2990c2625e6eSJosh Paetzel 2991c2625e6eSJosh Paetzel default: 2992c2625e6eSJosh Paetzel device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n"); 2993c2625e6eSJosh Paetzel oce_rq_buf_size = 2048; 2994c2625e6eSJosh Paetzel } 2995c2625e6eSJosh Paetzel } 2996c2625e6eSJosh Paetzel 2997c2625e6eSJosh Paetzel return; 2998c2625e6eSJosh Paetzel } 2999