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 DRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0); 2182f345d8eSLuigi Rizzo MODULE_DEPEND(oce, pci, 1, 1, 1); 2192f345d8eSLuigi Rizzo MODULE_DEPEND(oce, ether, 1, 1, 1); 2202f345d8eSLuigi Rizzo MODULE_VERSION(oce, 1); 2212f345d8eSLuigi Rizzo 2222f345d8eSLuigi Rizzo 2232f345d8eSLuigi Rizzo /* global vars */ 2242f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"}; 2252f345d8eSLuigi Rizzo 2262f345d8eSLuigi Rizzo /* Module capabilites and parameters */ 2272f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED; 2282f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS; 229c2625e6eSJosh Paetzel uint32_t oce_rq_buf_size = 2048; 2302f345d8eSLuigi Rizzo 2312f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled); 2322f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss); 2332f345d8eSLuigi Rizzo 2342f345d8eSLuigi Rizzo 2352f345d8eSLuigi Rizzo /* Supported devices table */ 2362f345d8eSLuigi Rizzo static uint32_t supportedDevices[] = { 2372f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2, 2382f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3, 2392f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3, 2402f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201, 2412f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF, 242291a1934SXin LI (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH 2432f345d8eSLuigi Rizzo }; 2442f345d8eSLuigi Rizzo 245c2625e6eSJosh Paetzel POCE_SOFTC softc_head = NULL; 246c2625e6eSJosh Paetzel POCE_SOFTC softc_tail = NULL; 2472f345d8eSLuigi Rizzo 248c2625e6eSJosh Paetzel struct oce_rdma_if *oce_rdma_if = NULL; 2492f345d8eSLuigi Rizzo 2502f345d8eSLuigi Rizzo /***************************************************************************** 2512f345d8eSLuigi Rizzo * Driver entry points functions * 2522f345d8eSLuigi Rizzo *****************************************************************************/ 2532f345d8eSLuigi Rizzo 2542f345d8eSLuigi Rizzo static int 2552f345d8eSLuigi Rizzo oce_probe(device_t dev) 2562f345d8eSLuigi Rizzo { 2579bd3250aSLuigi Rizzo uint16_t vendor = 0; 2589bd3250aSLuigi Rizzo uint16_t device = 0; 2599bd3250aSLuigi Rizzo int i = 0; 2609bd3250aSLuigi Rizzo char str[256] = {0}; 2612f345d8eSLuigi Rizzo POCE_SOFTC sc; 2622f345d8eSLuigi Rizzo 2632f345d8eSLuigi Rizzo sc = device_get_softc(dev); 2642f345d8eSLuigi Rizzo bzero(sc, sizeof(OCE_SOFTC)); 2652f345d8eSLuigi Rizzo sc->dev = dev; 2662f345d8eSLuigi Rizzo 2672f345d8eSLuigi Rizzo vendor = pci_get_vendor(dev); 2682f345d8eSLuigi Rizzo device = pci_get_device(dev); 2692f345d8eSLuigi Rizzo 2709bd3250aSLuigi Rizzo for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) { 2712f345d8eSLuigi Rizzo if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) { 2722f345d8eSLuigi Rizzo if (device == (supportedDevices[i] & 0xffff)) { 2739bd3250aSLuigi Rizzo sprintf(str, "%s:%s", "Emulex CNA NIC function", 2742f345d8eSLuigi Rizzo component_revision); 2752f345d8eSLuigi Rizzo device_set_desc_copy(dev, str); 2762f345d8eSLuigi Rizzo 2772f345d8eSLuigi Rizzo switch (device) { 2782f345d8eSLuigi Rizzo case PCI_PRODUCT_BE2: 2792f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE2; 2802f345d8eSLuigi Rizzo break; 2812f345d8eSLuigi Rizzo case PCI_PRODUCT_BE3: 2822f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE3; 2832f345d8eSLuigi Rizzo break; 2842f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201: 2852f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201_VF: 2862f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_XE201; 2872f345d8eSLuigi Rizzo break; 288291a1934SXin LI case PCI_PRODUCT_SH: 289291a1934SXin LI sc->flags |= OCE_FLAGS_SH; 290291a1934SXin LI break; 2912f345d8eSLuigi Rizzo default: 2922f345d8eSLuigi Rizzo return ENXIO; 2932f345d8eSLuigi Rizzo } 2942f345d8eSLuigi Rizzo return BUS_PROBE_DEFAULT; 2952f345d8eSLuigi Rizzo } 2962f345d8eSLuigi Rizzo } 2972f345d8eSLuigi Rizzo } 2982f345d8eSLuigi Rizzo 2992f345d8eSLuigi Rizzo return ENXIO; 3002f345d8eSLuigi Rizzo } 3012f345d8eSLuigi Rizzo 3022f345d8eSLuigi Rizzo 3032f345d8eSLuigi Rizzo static int 3042f345d8eSLuigi Rizzo oce_attach(device_t dev) 3052f345d8eSLuigi Rizzo { 3062f345d8eSLuigi Rizzo POCE_SOFTC sc; 3072f345d8eSLuigi Rizzo int rc = 0; 3082f345d8eSLuigi Rizzo 3092f345d8eSLuigi Rizzo sc = device_get_softc(dev); 3102f345d8eSLuigi Rizzo 3112f345d8eSLuigi Rizzo rc = oce_hw_pci_alloc(sc); 3122f345d8eSLuigi Rizzo if (rc) 3132f345d8eSLuigi Rizzo return rc; 3142f345d8eSLuigi Rizzo 3152f345d8eSLuigi Rizzo sc->tx_ring_size = OCE_TX_RING_SIZE; 3162f345d8eSLuigi Rizzo sc->rx_ring_size = OCE_RX_RING_SIZE; 317c2625e6eSJosh Paetzel /* receive fragment size should be multiple of 2K */ 318c2625e6eSJosh Paetzel sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048); 3192f345d8eSLuigi Rizzo sc->flow_control = OCE_DEFAULT_FLOW_CONTROL; 3202f345d8eSLuigi Rizzo sc->promisc = OCE_DEFAULT_PROMISCUOUS; 3212f345d8eSLuigi Rizzo 3222f345d8eSLuigi Rizzo LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock"); 3232f345d8eSLuigi Rizzo LOCK_CREATE(&sc->dev_lock, "Device_lock"); 3242f345d8eSLuigi Rizzo 3252f345d8eSLuigi Rizzo /* initialise the hardware */ 3262f345d8eSLuigi Rizzo rc = oce_hw_init(sc); 3272f345d8eSLuigi Rizzo if (rc) 3282f345d8eSLuigi Rizzo goto pci_res_free; 3292f345d8eSLuigi Rizzo 330c2625e6eSJosh Paetzel oce_read_env_variables(sc); 331c2625e6eSJosh Paetzel 332291a1934SXin LI oce_get_config(sc); 333291a1934SXin LI 3342f345d8eSLuigi Rizzo setup_max_queues_want(sc); 3352f345d8eSLuigi Rizzo 3362f345d8eSLuigi Rizzo rc = oce_setup_intr(sc); 3372f345d8eSLuigi Rizzo if (rc) 3382f345d8eSLuigi Rizzo goto mbox_free; 3392f345d8eSLuigi Rizzo 3402f345d8eSLuigi Rizzo rc = oce_queue_init_all(sc); 3412f345d8eSLuigi Rizzo if (rc) 3422f345d8eSLuigi Rizzo goto intr_free; 3432f345d8eSLuigi Rizzo 3442f345d8eSLuigi Rizzo rc = oce_attach_ifp(sc); 3452f345d8eSLuigi Rizzo if (rc) 3462f345d8eSLuigi Rizzo goto queues_free; 3472f345d8eSLuigi Rizzo 348ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 3492f345d8eSLuigi Rizzo rc = oce_init_lro(sc); 3502f345d8eSLuigi Rizzo if (rc) 3512f345d8eSLuigi Rizzo goto ifp_free; 352ad512958SBjoern A. Zeeb #endif 3532f345d8eSLuigi Rizzo 3542f345d8eSLuigi Rizzo rc = oce_hw_start(sc); 3552f345d8eSLuigi Rizzo if (rc) 356db702c59SEitan Adler goto lro_free; 3572f345d8eSLuigi Rizzo 3582f345d8eSLuigi Rizzo sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 3592f345d8eSLuigi Rizzo oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST); 3602f345d8eSLuigi Rizzo sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 3612f345d8eSLuigi Rizzo oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST); 3622f345d8eSLuigi Rizzo 3632f345d8eSLuigi Rizzo rc = oce_stats_init(sc); 3642f345d8eSLuigi Rizzo if (rc) 3652f345d8eSLuigi Rizzo goto vlan_free; 3662f345d8eSLuigi Rizzo 3672f345d8eSLuigi Rizzo oce_add_sysctls(sc); 3682f345d8eSLuigi Rizzo 369c2625e6eSJosh Paetzel callout_init(&sc->timer, CALLOUT_MPSAFE); 3702f345d8eSLuigi Rizzo rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc); 3712f345d8eSLuigi Rizzo if (rc) 3722f345d8eSLuigi Rizzo goto stats_free; 3732f345d8eSLuigi Rizzo 374c2625e6eSJosh Paetzel sc->next =NULL; 375c2625e6eSJosh Paetzel if (softc_tail != NULL) { 376c2625e6eSJosh Paetzel softc_tail->next = sc; 377c2625e6eSJosh Paetzel } else { 378c2625e6eSJosh Paetzel softc_head = sc; 379c2625e6eSJosh Paetzel } 380c2625e6eSJosh Paetzel softc_tail = sc; 381c2625e6eSJosh Paetzel 3822f345d8eSLuigi Rizzo return 0; 3832f345d8eSLuigi Rizzo 3842f345d8eSLuigi Rizzo stats_free: 3852f345d8eSLuigi Rizzo callout_drain(&sc->timer); 3862f345d8eSLuigi Rizzo oce_stats_free(sc); 3872f345d8eSLuigi Rizzo vlan_free: 3882f345d8eSLuigi Rizzo if (sc->vlan_attach) 3892f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 3902f345d8eSLuigi Rizzo if (sc->vlan_detach) 3912f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 3922f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 3932f345d8eSLuigi Rizzo lro_free: 394ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 3952f345d8eSLuigi Rizzo oce_free_lro(sc); 3962f345d8eSLuigi Rizzo ifp_free: 397ad512958SBjoern A. Zeeb #endif 3982f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp); 3992f345d8eSLuigi Rizzo if_free(sc->ifp); 4002f345d8eSLuigi Rizzo queues_free: 4012f345d8eSLuigi Rizzo oce_queue_release_all(sc); 4022f345d8eSLuigi Rizzo intr_free: 4032f345d8eSLuigi Rizzo oce_intr_free(sc); 4042f345d8eSLuigi Rizzo mbox_free: 4052f345d8eSLuigi Rizzo oce_dma_free(sc, &sc->bsmbx); 4062f345d8eSLuigi Rizzo pci_res_free: 4072f345d8eSLuigi Rizzo oce_hw_pci_free(sc); 4082f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->dev_lock); 4092f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->bmbx_lock); 4102f345d8eSLuigi Rizzo return rc; 4112f345d8eSLuigi Rizzo 4122f345d8eSLuigi Rizzo } 4132f345d8eSLuigi Rizzo 4142f345d8eSLuigi Rizzo 4152f345d8eSLuigi Rizzo static int 4162f345d8eSLuigi Rizzo oce_detach(device_t dev) 4172f345d8eSLuigi Rizzo { 4182f345d8eSLuigi Rizzo POCE_SOFTC sc = device_get_softc(dev); 419c2625e6eSJosh Paetzel POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL; 420c2625e6eSJosh Paetzel 421c2625e6eSJosh Paetzel poce_sc_tmp = softc_head; 422c2625e6eSJosh Paetzel ppoce_sc_tmp1 = &softc_head; 423c2625e6eSJosh Paetzel while (poce_sc_tmp != NULL) { 424c2625e6eSJosh Paetzel if (poce_sc_tmp == sc) { 425c2625e6eSJosh Paetzel *ppoce_sc_tmp1 = sc->next; 426c2625e6eSJosh Paetzel if (sc->next == NULL) { 427c2625e6eSJosh Paetzel softc_tail = poce_sc_tmp2; 428c2625e6eSJosh Paetzel } 429c2625e6eSJosh Paetzel break; 430c2625e6eSJosh Paetzel } 431c2625e6eSJosh Paetzel poce_sc_tmp2 = poce_sc_tmp; 432c2625e6eSJosh Paetzel ppoce_sc_tmp1 = &poce_sc_tmp->next; 433c2625e6eSJosh Paetzel poce_sc_tmp = poce_sc_tmp->next; 434c2625e6eSJosh Paetzel } 4352f345d8eSLuigi Rizzo 4362f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 4372f345d8eSLuigi Rizzo oce_if_deactivate(sc); 4382f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 4392f345d8eSLuigi Rizzo 4402f345d8eSLuigi Rizzo callout_drain(&sc->timer); 4412f345d8eSLuigi Rizzo 4422f345d8eSLuigi Rizzo if (sc->vlan_attach != NULL) 4432f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 4442f345d8eSLuigi Rizzo if (sc->vlan_detach != NULL) 4452f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 4462f345d8eSLuigi Rizzo 4472f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp); 4482f345d8eSLuigi Rizzo 4492f345d8eSLuigi Rizzo if_free(sc->ifp); 4502f345d8eSLuigi Rizzo 4512f345d8eSLuigi Rizzo oce_hw_shutdown(sc); 4522f345d8eSLuigi Rizzo 4532f345d8eSLuigi Rizzo bus_generic_detach(dev); 4542f345d8eSLuigi Rizzo 4552f345d8eSLuigi Rizzo return 0; 4562f345d8eSLuigi Rizzo } 4572f345d8eSLuigi Rizzo 4582f345d8eSLuigi Rizzo 4592f345d8eSLuigi Rizzo static int 4602f345d8eSLuigi Rizzo oce_shutdown(device_t dev) 4612f345d8eSLuigi Rizzo { 4622f345d8eSLuigi Rizzo int rc; 4632f345d8eSLuigi Rizzo 4642f345d8eSLuigi Rizzo rc = oce_detach(dev); 4652f345d8eSLuigi Rizzo 4662f345d8eSLuigi Rizzo return rc; 4672f345d8eSLuigi Rizzo } 4682f345d8eSLuigi Rizzo 4692f345d8eSLuigi Rizzo 4702f345d8eSLuigi Rizzo static int 4712f345d8eSLuigi Rizzo oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 4722f345d8eSLuigi Rizzo { 4732f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data; 4742f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 4752f345d8eSLuigi Rizzo int rc = 0; 4762f345d8eSLuigi Rizzo uint32_t u; 4772f345d8eSLuigi Rizzo 4782f345d8eSLuigi Rizzo switch (command) { 4792f345d8eSLuigi Rizzo 4802f345d8eSLuigi Rizzo case SIOCGIFMEDIA: 4812f345d8eSLuigi Rizzo rc = ifmedia_ioctl(ifp, ifr, &sc->media, command); 4822f345d8eSLuigi Rizzo break; 4832f345d8eSLuigi Rizzo 4842f345d8eSLuigi Rizzo case SIOCSIFMTU: 4852f345d8eSLuigi Rizzo if (ifr->ifr_mtu > OCE_MAX_MTU) 4862f345d8eSLuigi Rizzo rc = EINVAL; 4872f345d8eSLuigi Rizzo else 4882f345d8eSLuigi Rizzo ifp->if_mtu = ifr->ifr_mtu; 4892f345d8eSLuigi Rizzo break; 4902f345d8eSLuigi Rizzo 4912f345d8eSLuigi Rizzo case SIOCSIFFLAGS: 4922f345d8eSLuigi Rizzo if (ifp->if_flags & IFF_UP) { 4932f345d8eSLuigi Rizzo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 4942f345d8eSLuigi Rizzo sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 4952f345d8eSLuigi Rizzo oce_init(sc); 4962f345d8eSLuigi Rizzo } 4972f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Up\n"); 4982f345d8eSLuigi Rizzo } else { 4992f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 5002f345d8eSLuigi Rizzo 5012f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= 5022f345d8eSLuigi Rizzo ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 5032f345d8eSLuigi Rizzo oce_if_deactivate(sc); 5042f345d8eSLuigi Rizzo 5052f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 5062f345d8eSLuigi Rizzo 5072f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Down\n"); 5082f345d8eSLuigi Rizzo } 5092f345d8eSLuigi Rizzo 5102f345d8eSLuigi Rizzo if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) { 5115fbb6830SXin LI if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1)))) 5122f345d8eSLuigi Rizzo sc->promisc = TRUE; 5132f345d8eSLuigi Rizzo } else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) { 5145fbb6830SXin LI if (!oce_rxf_set_promiscuous(sc, 0)) 5152f345d8eSLuigi Rizzo sc->promisc = FALSE; 5162f345d8eSLuigi Rizzo } 5172f345d8eSLuigi Rizzo 5182f345d8eSLuigi Rizzo break; 5192f345d8eSLuigi Rizzo 5202f345d8eSLuigi Rizzo case SIOCADDMULTI: 5212f345d8eSLuigi Rizzo case SIOCDELMULTI: 5222f345d8eSLuigi Rizzo rc = oce_hw_update_multicast(sc); 5232f345d8eSLuigi Rizzo if (rc) 5242f345d8eSLuigi Rizzo device_printf(sc->dev, 5252f345d8eSLuigi Rizzo "Update multicast address failed\n"); 5262f345d8eSLuigi Rizzo break; 5272f345d8eSLuigi Rizzo 5282f345d8eSLuigi Rizzo case SIOCSIFCAP: 5292f345d8eSLuigi Rizzo u = ifr->ifr_reqcap ^ ifp->if_capenable; 5302f345d8eSLuigi Rizzo 5312f345d8eSLuigi Rizzo if (u & IFCAP_TXCSUM) { 5322f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_TXCSUM; 5332f345d8eSLuigi Rizzo ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 5342f345d8eSLuigi Rizzo 5352f345d8eSLuigi Rizzo if (IFCAP_TSO & ifp->if_capenable && 5362f345d8eSLuigi Rizzo !(IFCAP_TXCSUM & ifp->if_capenable)) { 5372f345d8eSLuigi Rizzo ifp->if_capenable &= ~IFCAP_TSO; 5382f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5392f345d8eSLuigi Rizzo if_printf(ifp, 5402f345d8eSLuigi Rizzo "TSO disabled due to -txcsum.\n"); 5412f345d8eSLuigi Rizzo } 5422f345d8eSLuigi Rizzo } 5432f345d8eSLuigi Rizzo 5442f345d8eSLuigi Rizzo if (u & IFCAP_RXCSUM) 5452f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_RXCSUM; 5462f345d8eSLuigi Rizzo 5472f345d8eSLuigi Rizzo if (u & IFCAP_TSO4) { 5482f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_TSO4; 5492f345d8eSLuigi Rizzo 5502f345d8eSLuigi Rizzo if (IFCAP_TSO & ifp->if_capenable) { 5512f345d8eSLuigi Rizzo if (IFCAP_TXCSUM & ifp->if_capenable) 5522f345d8eSLuigi Rizzo ifp->if_hwassist |= CSUM_TSO; 5532f345d8eSLuigi Rizzo else { 5542f345d8eSLuigi Rizzo ifp->if_capenable &= ~IFCAP_TSO; 5552f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5562f345d8eSLuigi Rizzo if_printf(ifp, 5572f345d8eSLuigi Rizzo "Enable txcsum first.\n"); 5582f345d8eSLuigi Rizzo rc = EAGAIN; 5592f345d8eSLuigi Rizzo } 5602f345d8eSLuigi Rizzo } else 5612f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5622f345d8eSLuigi Rizzo } 5632f345d8eSLuigi Rizzo 5642f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWTAGGING) 5652f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 5662f345d8eSLuigi Rizzo 5672f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWFILTER) { 5682f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 5692f345d8eSLuigi Rizzo oce_vid_config(sc); 5702f345d8eSLuigi Rizzo } 571ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 572c2625e6eSJosh Paetzel if (u & IFCAP_LRO) { 5732f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_LRO; 574c2625e6eSJosh Paetzel if(sc->enable_hwlro) { 575c2625e6eSJosh Paetzel if(ifp->if_capenable & IFCAP_LRO) { 576c2625e6eSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 1); 577c2625e6eSJosh Paetzel }else { 578c2625e6eSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 0); 579c2625e6eSJosh Paetzel } 580c2625e6eSJosh Paetzel } 581c2625e6eSJosh Paetzel } 582ad512958SBjoern A. Zeeb #endif 5832f345d8eSLuigi Rizzo 5842f345d8eSLuigi Rizzo break; 5852f345d8eSLuigi Rizzo 5862f345d8eSLuigi Rizzo case SIOCGPRIVATE_0: 5872f345d8eSLuigi Rizzo rc = oce_handle_passthrough(ifp, data); 5882f345d8eSLuigi Rizzo break; 5892f345d8eSLuigi Rizzo default: 5902f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 5912f345d8eSLuigi Rizzo break; 5922f345d8eSLuigi Rizzo } 5932f345d8eSLuigi Rizzo 5942f345d8eSLuigi Rizzo return rc; 5952f345d8eSLuigi Rizzo } 5962f345d8eSLuigi Rizzo 5972f345d8eSLuigi Rizzo 5982f345d8eSLuigi Rizzo static void 5992f345d8eSLuigi Rizzo oce_init(void *arg) 6002f345d8eSLuigi Rizzo { 6012f345d8eSLuigi Rizzo POCE_SOFTC sc = arg; 6022f345d8eSLuigi Rizzo 6032f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 6042f345d8eSLuigi Rizzo 6052f345d8eSLuigi Rizzo if (sc->ifp->if_flags & IFF_UP) { 6062f345d8eSLuigi Rizzo oce_if_deactivate(sc); 6072f345d8eSLuigi Rizzo oce_if_activate(sc); 6082f345d8eSLuigi Rizzo } 6092f345d8eSLuigi Rizzo 6102f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 6112f345d8eSLuigi Rizzo 6122f345d8eSLuigi Rizzo } 6132f345d8eSLuigi Rizzo 6142f345d8eSLuigi Rizzo 6152f345d8eSLuigi Rizzo static int 6162f345d8eSLuigi Rizzo oce_multiq_start(struct ifnet *ifp, struct mbuf *m) 6172f345d8eSLuigi Rizzo { 6182f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 6192f345d8eSLuigi Rizzo struct oce_wq *wq = NULL; 6202f345d8eSLuigi Rizzo int queue_index = 0; 6212f345d8eSLuigi Rizzo int status = 0; 6222f345d8eSLuigi Rizzo 623c2625e6eSJosh Paetzel if (!sc->link_status) 624c2625e6eSJosh Paetzel return ENXIO; 625c2625e6eSJosh Paetzel 626c2529042SHans Petter Selasky if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 6272f345d8eSLuigi Rizzo queue_index = m->m_pkthdr.flowid % sc->nwqs; 6282f345d8eSLuigi Rizzo 6292f345d8eSLuigi Rizzo wq = sc->wq[queue_index]; 6302f345d8eSLuigi Rizzo 631291a1934SXin LI LOCK(&wq->tx_lock); 6322f345d8eSLuigi Rizzo status = oce_multiq_transmit(ifp, m, wq); 6332f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 634291a1934SXin LI 6352f345d8eSLuigi Rizzo return status; 6362f345d8eSLuigi Rizzo 6372f345d8eSLuigi Rizzo } 6382f345d8eSLuigi Rizzo 6392f345d8eSLuigi Rizzo 6402f345d8eSLuigi Rizzo static void 6412f345d8eSLuigi Rizzo oce_multiq_flush(struct ifnet *ifp) 6422f345d8eSLuigi Rizzo { 6432f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 6442f345d8eSLuigi Rizzo struct mbuf *m; 6452f345d8eSLuigi Rizzo int i = 0; 6462f345d8eSLuigi Rizzo 6472f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) { 6482f345d8eSLuigi Rizzo while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) 6492f345d8eSLuigi Rizzo m_freem(m); 6502f345d8eSLuigi Rizzo } 6512f345d8eSLuigi Rizzo if_qflush(ifp); 6522f345d8eSLuigi Rizzo } 6532f345d8eSLuigi Rizzo 6542f345d8eSLuigi Rizzo 6552f345d8eSLuigi Rizzo 6562f345d8eSLuigi Rizzo /***************************************************************************** 6572f345d8eSLuigi Rizzo * Driver interrupt routines functions * 6582f345d8eSLuigi Rizzo *****************************************************************************/ 6592f345d8eSLuigi Rizzo 6602f345d8eSLuigi Rizzo static void 6612f345d8eSLuigi Rizzo oce_intr(void *arg, int pending) 6622f345d8eSLuigi Rizzo { 6632f345d8eSLuigi Rizzo 6642f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 6652f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc; 6662f345d8eSLuigi Rizzo struct oce_eq *eq = ii->eq; 6672f345d8eSLuigi Rizzo struct oce_eqe *eqe; 6682f345d8eSLuigi Rizzo struct oce_cq *cq = NULL; 6692f345d8eSLuigi Rizzo int i, num_eqes = 0; 6702f345d8eSLuigi Rizzo 6712f345d8eSLuigi Rizzo 6722f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 6732f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 6742f345d8eSLuigi Rizzo do { 6752f345d8eSLuigi Rizzo eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 6762f345d8eSLuigi Rizzo if (eqe->evnt == 0) 6772f345d8eSLuigi Rizzo break; 6782f345d8eSLuigi Rizzo eqe->evnt = 0; 6792f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 6802f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 6812f345d8eSLuigi Rizzo RING_GET(eq->ring, 1); 6822f345d8eSLuigi Rizzo num_eqes++; 6832f345d8eSLuigi Rizzo 6842f345d8eSLuigi Rizzo } while (TRUE); 6852f345d8eSLuigi Rizzo 6862f345d8eSLuigi Rizzo if (!num_eqes) 6872f345d8eSLuigi Rizzo goto eq_arm; /* Spurious */ 6882f345d8eSLuigi Rizzo 6892f345d8eSLuigi Rizzo /* Clear EQ entries, but dont arm */ 6902f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE); 6912f345d8eSLuigi Rizzo 6922f345d8eSLuigi Rizzo /* Process TX, RX and MCC. But dont arm CQ*/ 6932f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) { 6942f345d8eSLuigi Rizzo cq = eq->cq[i]; 6952f345d8eSLuigi Rizzo (*cq->cq_handler)(cq->cb_arg); 6962f345d8eSLuigi Rizzo } 6972f345d8eSLuigi Rizzo 6982f345d8eSLuigi Rizzo /* Arm all cqs connected to this EQ */ 6992f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) { 7002f345d8eSLuigi Rizzo cq = eq->cq[i]; 7012f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, 0, TRUE); 7022f345d8eSLuigi Rizzo } 7032f345d8eSLuigi Rizzo 7042f345d8eSLuigi Rizzo eq_arm: 7052f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 706cdaba892SXin LI 7072f345d8eSLuigi Rizzo return; 7082f345d8eSLuigi Rizzo } 7092f345d8eSLuigi Rizzo 7102f345d8eSLuigi Rizzo 7112f345d8eSLuigi Rizzo static int 7122f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc) 7132f345d8eSLuigi Rizzo { 7142f345d8eSLuigi Rizzo int rc = 0, use_intx = 0; 7152f345d8eSLuigi Rizzo int vector = 0, req_vectors = 0; 716c2625e6eSJosh Paetzel int tot_req_vectors, tot_vectors; 7172f345d8eSLuigi Rizzo 718291a1934SXin LI if (is_rss_enabled(sc)) 7192f345d8eSLuigi Rizzo req_vectors = MAX((sc->nrqs - 1), sc->nwqs); 7202f345d8eSLuigi Rizzo else 7212f345d8eSLuigi Rizzo req_vectors = 1; 7222f345d8eSLuigi Rizzo 723c2625e6eSJosh Paetzel tot_req_vectors = req_vectors; 724c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 725c2625e6eSJosh Paetzel if (req_vectors > 1) { 726c2625e6eSJosh Paetzel tot_req_vectors += OCE_RDMA_VECTORS; 727c2625e6eSJosh Paetzel sc->roce_intr_count = OCE_RDMA_VECTORS; 728c2625e6eSJosh Paetzel } 729c2625e6eSJosh Paetzel } 730c2625e6eSJosh Paetzel 7312f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) { 7322f345d8eSLuigi Rizzo sc->intr_count = req_vectors; 733c2625e6eSJosh Paetzel tot_vectors = tot_req_vectors; 734c2625e6eSJosh Paetzel rc = pci_alloc_msix(sc->dev, &tot_vectors); 7352f345d8eSLuigi Rizzo if (rc != 0) { 7362f345d8eSLuigi Rizzo use_intx = 1; 7372f345d8eSLuigi Rizzo pci_release_msi(sc->dev); 738c2625e6eSJosh Paetzel } else { 739c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 740c2625e6eSJosh Paetzel if (tot_vectors < tot_req_vectors) { 741c2625e6eSJosh Paetzel if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) { 742c2625e6eSJosh Paetzel sc->roce_intr_count = (tot_vectors / 2); 743c2625e6eSJosh Paetzel } 744c2625e6eSJosh Paetzel sc->intr_count = tot_vectors - sc->roce_intr_count; 745c2625e6eSJosh Paetzel } 746c2625e6eSJosh Paetzel } else { 747c2625e6eSJosh Paetzel sc->intr_count = tot_vectors; 748c2625e6eSJosh Paetzel } 7492f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_USING_MSIX; 750c2625e6eSJosh Paetzel } 7512f345d8eSLuigi Rizzo } else 7522f345d8eSLuigi Rizzo use_intx = 1; 7532f345d8eSLuigi Rizzo 7542f345d8eSLuigi Rizzo if (use_intx) 7552f345d8eSLuigi Rizzo sc->intr_count = 1; 7562f345d8eSLuigi Rizzo 7572f345d8eSLuigi Rizzo /* Scale number of queues based on intr we got */ 7582f345d8eSLuigi Rizzo update_queues_got(sc); 7592f345d8eSLuigi Rizzo 7602f345d8eSLuigi Rizzo if (use_intx) { 7612f345d8eSLuigi Rizzo device_printf(sc->dev, "Using legacy interrupt\n"); 7622f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr); 7632f345d8eSLuigi Rizzo if (rc) 7642f345d8eSLuigi Rizzo goto error; 7652f345d8eSLuigi Rizzo } else { 7662f345d8eSLuigi Rizzo for (; vector < sc->intr_count; vector++) { 7672f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr); 7682f345d8eSLuigi Rizzo if (rc) 7692f345d8eSLuigi Rizzo goto error; 7702f345d8eSLuigi Rizzo } 7712f345d8eSLuigi Rizzo } 7722f345d8eSLuigi Rizzo 7732f345d8eSLuigi Rizzo return 0; 7742f345d8eSLuigi Rizzo error: 7752f345d8eSLuigi Rizzo oce_intr_free(sc); 7762f345d8eSLuigi Rizzo return rc; 7772f345d8eSLuigi Rizzo } 7782f345d8eSLuigi Rizzo 7792f345d8eSLuigi Rizzo 7802f345d8eSLuigi Rizzo static int 7812f345d8eSLuigi Rizzo oce_fast_isr(void *arg) 7822f345d8eSLuigi Rizzo { 7832f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 7842f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc; 7852f345d8eSLuigi Rizzo 7862f345d8eSLuigi Rizzo if (ii->eq == NULL) 7872f345d8eSLuigi Rizzo return FILTER_STRAY; 7882f345d8eSLuigi Rizzo 7892f345d8eSLuigi Rizzo oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE); 7902f345d8eSLuigi Rizzo 791cbc4d2dbSJohn Baldwin taskqueue_enqueue(ii->tq, &ii->task); 7922f345d8eSLuigi Rizzo 793cdaba892SXin LI ii->eq->intr++; 794cdaba892SXin LI 7952f345d8eSLuigi Rizzo return FILTER_HANDLED; 7962f345d8eSLuigi Rizzo } 7972f345d8eSLuigi Rizzo 7982f345d8eSLuigi Rizzo 7992f345d8eSLuigi Rizzo static int 8002f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) 8012f345d8eSLuigi Rizzo { 8022f345d8eSLuigi Rizzo POCE_INTR_INFO ii = &sc->intrs[vector]; 8032f345d8eSLuigi Rizzo int rc = 0, rr; 8042f345d8eSLuigi Rizzo 8052f345d8eSLuigi Rizzo if (vector >= OCE_MAX_EQ) 8062f345d8eSLuigi Rizzo return (EINVAL); 8072f345d8eSLuigi Rizzo 8082f345d8eSLuigi Rizzo /* Set the resource id for the interrupt. 8092f345d8eSLuigi Rizzo * MSIx is vector + 1 for the resource id, 8102f345d8eSLuigi Rizzo * INTx is 0 for the resource id. 8112f345d8eSLuigi Rizzo */ 8122f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX) 8132f345d8eSLuigi Rizzo rr = vector + 1; 8142f345d8eSLuigi Rizzo else 8152f345d8eSLuigi Rizzo rr = 0; 8162f345d8eSLuigi Rizzo ii->intr_res = bus_alloc_resource_any(sc->dev, 8172f345d8eSLuigi Rizzo SYS_RES_IRQ, 8182f345d8eSLuigi Rizzo &rr, RF_ACTIVE|RF_SHAREABLE); 8192f345d8eSLuigi Rizzo ii->irq_rr = rr; 8202f345d8eSLuigi Rizzo if (ii->intr_res == NULL) { 8212f345d8eSLuigi Rizzo device_printf(sc->dev, 8222f345d8eSLuigi Rizzo "Could not allocate interrupt\n"); 8232f345d8eSLuigi Rizzo rc = ENXIO; 8242f345d8eSLuigi Rizzo return rc; 8252f345d8eSLuigi Rizzo } 8262f345d8eSLuigi Rizzo 8272f345d8eSLuigi Rizzo TASK_INIT(&ii->task, 0, isr, ii); 8282f345d8eSLuigi Rizzo ii->vector = vector; 8292f345d8eSLuigi Rizzo sprintf(ii->task_name, "oce_task[%d]", ii->vector); 8302f345d8eSLuigi Rizzo ii->tq = taskqueue_create_fast(ii->task_name, 8312f345d8eSLuigi Rizzo M_NOWAIT, 8322f345d8eSLuigi Rizzo taskqueue_thread_enqueue, 8332f345d8eSLuigi Rizzo &ii->tq); 8342f345d8eSLuigi Rizzo taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq", 8352f345d8eSLuigi Rizzo device_get_nameunit(sc->dev)); 8362f345d8eSLuigi Rizzo 8372f345d8eSLuigi Rizzo ii->sc = sc; 8382f345d8eSLuigi Rizzo rc = bus_setup_intr(sc->dev, 8392f345d8eSLuigi Rizzo ii->intr_res, 8402f345d8eSLuigi Rizzo INTR_TYPE_NET, 8412f345d8eSLuigi Rizzo oce_fast_isr, NULL, ii, &ii->tag); 8422f345d8eSLuigi Rizzo return rc; 8432f345d8eSLuigi Rizzo 8442f345d8eSLuigi Rizzo } 8452f345d8eSLuigi Rizzo 8462f345d8eSLuigi Rizzo 8472f345d8eSLuigi Rizzo void 8482f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc) 8492f345d8eSLuigi Rizzo { 8502f345d8eSLuigi Rizzo int i = 0; 8512f345d8eSLuigi Rizzo 8522f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) { 8532f345d8eSLuigi Rizzo 8542f345d8eSLuigi Rizzo if (sc->intrs[i].tag != NULL) 8552f345d8eSLuigi Rizzo bus_teardown_intr(sc->dev, sc->intrs[i].intr_res, 8562f345d8eSLuigi Rizzo sc->intrs[i].tag); 8572f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) 8582f345d8eSLuigi Rizzo taskqueue_free(sc->intrs[i].tq); 8592f345d8eSLuigi Rizzo 8602f345d8eSLuigi Rizzo if (sc->intrs[i].intr_res != NULL) 8612f345d8eSLuigi Rizzo bus_release_resource(sc->dev, SYS_RES_IRQ, 8622f345d8eSLuigi Rizzo sc->intrs[i].irq_rr, 8632f345d8eSLuigi Rizzo sc->intrs[i].intr_res); 8642f345d8eSLuigi Rizzo sc->intrs[i].tag = NULL; 8652f345d8eSLuigi Rizzo sc->intrs[i].intr_res = NULL; 8662f345d8eSLuigi Rizzo } 8672f345d8eSLuigi Rizzo 8682f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX) 8692f345d8eSLuigi Rizzo pci_release_msi(sc->dev); 8702f345d8eSLuigi Rizzo 8712f345d8eSLuigi Rizzo } 8722f345d8eSLuigi Rizzo 8732f345d8eSLuigi Rizzo 8742f345d8eSLuigi Rizzo 8752f345d8eSLuigi Rizzo /****************************************************************************** 8762f345d8eSLuigi Rizzo * Media callbacks functions * 8772f345d8eSLuigi Rizzo ******************************************************************************/ 8782f345d8eSLuigi Rizzo 8792f345d8eSLuigi Rizzo static void 8802f345d8eSLuigi Rizzo oce_media_status(struct ifnet *ifp, struct ifmediareq *req) 8812f345d8eSLuigi Rizzo { 8822f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc; 8832f345d8eSLuigi Rizzo 8842f345d8eSLuigi Rizzo 8852f345d8eSLuigi Rizzo req->ifm_status = IFM_AVALID; 8862f345d8eSLuigi Rizzo req->ifm_active = IFM_ETHER; 8872f345d8eSLuigi Rizzo 8882f345d8eSLuigi Rizzo if (sc->link_status == 1) 8892f345d8eSLuigi Rizzo req->ifm_status |= IFM_ACTIVE; 8902f345d8eSLuigi Rizzo else 8912f345d8eSLuigi Rizzo return; 8922f345d8eSLuigi Rizzo 8932f345d8eSLuigi Rizzo switch (sc->link_speed) { 8942f345d8eSLuigi Rizzo case 1: /* 10 Mbps */ 8952f345d8eSLuigi Rizzo req->ifm_active |= IFM_10_T | IFM_FDX; 8962f345d8eSLuigi Rizzo sc->speed = 10; 8972f345d8eSLuigi Rizzo break; 8982f345d8eSLuigi Rizzo case 2: /* 100 Mbps */ 8992f345d8eSLuigi Rizzo req->ifm_active |= IFM_100_TX | IFM_FDX; 9002f345d8eSLuigi Rizzo sc->speed = 100; 9012f345d8eSLuigi Rizzo break; 9022f345d8eSLuigi Rizzo case 3: /* 1 Gbps */ 9032f345d8eSLuigi Rizzo req->ifm_active |= IFM_1000_T | IFM_FDX; 9042f345d8eSLuigi Rizzo sc->speed = 1000; 9052f345d8eSLuigi Rizzo break; 9062f345d8eSLuigi Rizzo case 4: /* 10 Gbps */ 9072f345d8eSLuigi Rizzo req->ifm_active |= IFM_10G_SR | IFM_FDX; 9082f345d8eSLuigi Rizzo sc->speed = 10000; 9092f345d8eSLuigi Rizzo break; 910a4f734b4SXin LI case 5: /* 20 Gbps */ 911a4f734b4SXin LI req->ifm_active |= IFM_10G_SR | IFM_FDX; 912a4f734b4SXin LI sc->speed = 20000; 913a4f734b4SXin LI break; 914a4f734b4SXin LI case 6: /* 25 Gbps */ 915a4f734b4SXin LI req->ifm_active |= IFM_10G_SR | IFM_FDX; 916a4f734b4SXin LI sc->speed = 25000; 917a4f734b4SXin LI break; 918b41206d8SXin LI case 7: /* 40 Gbps */ 919b41206d8SXin LI req->ifm_active |= IFM_40G_SR4 | IFM_FDX; 920b41206d8SXin LI sc->speed = 40000; 921b41206d8SXin LI break; 922a4f734b4SXin LI default: 923a4f734b4SXin LI sc->speed = 0; 924a4f734b4SXin LI break; 9252f345d8eSLuigi Rizzo } 9262f345d8eSLuigi Rizzo 9272f345d8eSLuigi Rizzo return; 9282f345d8eSLuigi Rizzo } 9292f345d8eSLuigi Rizzo 9302f345d8eSLuigi Rizzo 9312f345d8eSLuigi Rizzo int 9322f345d8eSLuigi Rizzo oce_media_change(struct ifnet *ifp) 9332f345d8eSLuigi Rizzo { 9342f345d8eSLuigi Rizzo return 0; 9352f345d8eSLuigi Rizzo } 9362f345d8eSLuigi Rizzo 9372f345d8eSLuigi Rizzo 938c2625e6eSJosh Paetzel static void oce_is_pkt_dest_bmc(POCE_SOFTC sc, 939c2625e6eSJosh Paetzel struct mbuf *m, boolean_t *os2bmc, 940c2625e6eSJosh Paetzel struct mbuf **m_new) 941c2625e6eSJosh Paetzel { 942c2625e6eSJosh Paetzel struct ether_header *eh = NULL; 943c2625e6eSJosh Paetzel 944c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *); 945c2625e6eSJosh Paetzel 946c2625e6eSJosh Paetzel if (!is_os2bmc_enabled(sc) || *os2bmc) { 947c2625e6eSJosh Paetzel *os2bmc = FALSE; 948c2625e6eSJosh Paetzel goto done; 949c2625e6eSJosh Paetzel } 950c2625e6eSJosh Paetzel if (!ETHER_IS_MULTICAST(eh->ether_dhost)) 951c2625e6eSJosh Paetzel goto done; 952c2625e6eSJosh Paetzel 953c2625e6eSJosh Paetzel if (is_mc_allowed_on_bmc(sc, eh) || 954c2625e6eSJosh Paetzel is_bc_allowed_on_bmc(sc, eh) || 955c2625e6eSJosh Paetzel is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) { 956c2625e6eSJosh Paetzel *os2bmc = TRUE; 957c2625e6eSJosh Paetzel goto done; 958c2625e6eSJosh Paetzel } 959c2625e6eSJosh Paetzel 960c2625e6eSJosh Paetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) { 961c2625e6eSJosh Paetzel struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 962c2625e6eSJosh Paetzel uint8_t nexthdr = ip6->ip6_nxt; 963c2625e6eSJosh Paetzel if (nexthdr == IPPROTO_ICMPV6) { 964c2625e6eSJosh Paetzel struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1); 965c2625e6eSJosh Paetzel switch (icmp6->icmp6_type) { 966c2625e6eSJosh Paetzel case ND_ROUTER_ADVERT: 967c2625e6eSJosh Paetzel *os2bmc = is_ipv6_ra_filt_enabled(sc); 968c2625e6eSJosh Paetzel goto done; 969c2625e6eSJosh Paetzel case ND_NEIGHBOR_ADVERT: 970c2625e6eSJosh Paetzel *os2bmc = is_ipv6_na_filt_enabled(sc); 971c2625e6eSJosh Paetzel goto done; 972c2625e6eSJosh Paetzel default: 973c2625e6eSJosh Paetzel break; 974c2625e6eSJosh Paetzel } 975c2625e6eSJosh Paetzel } 976c2625e6eSJosh Paetzel } 977c2625e6eSJosh Paetzel 978c2625e6eSJosh Paetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) { 979c2625e6eSJosh Paetzel struct ip *ip = mtod(m, struct ip *); 980c2625e6eSJosh Paetzel int iphlen = ip->ip_hl << 2; 981c2625e6eSJosh Paetzel struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen); 982c2625e6eSJosh Paetzel switch (uh->uh_dport) { 983c2625e6eSJosh Paetzel case DHCP_CLIENT_PORT: 984c2625e6eSJosh Paetzel *os2bmc = is_dhcp_client_filt_enabled(sc); 985c2625e6eSJosh Paetzel goto done; 986c2625e6eSJosh Paetzel case DHCP_SERVER_PORT: 987c2625e6eSJosh Paetzel *os2bmc = is_dhcp_srvr_filt_enabled(sc); 988c2625e6eSJosh Paetzel goto done; 989c2625e6eSJosh Paetzel case NET_BIOS_PORT1: 990c2625e6eSJosh Paetzel case NET_BIOS_PORT2: 991c2625e6eSJosh Paetzel *os2bmc = is_nbios_filt_enabled(sc); 992c2625e6eSJosh Paetzel goto done; 993c2625e6eSJosh Paetzel case DHCPV6_RAS_PORT: 994c2625e6eSJosh Paetzel *os2bmc = is_ipv6_ras_filt_enabled(sc); 995c2625e6eSJosh Paetzel goto done; 996c2625e6eSJosh Paetzel default: 997c2625e6eSJosh Paetzel break; 998c2625e6eSJosh Paetzel } 999c2625e6eSJosh Paetzel } 1000c2625e6eSJosh Paetzel done: 1001c2625e6eSJosh Paetzel if (*os2bmc) { 1002c2625e6eSJosh Paetzel *m_new = m_dup(m, M_NOWAIT); 1003c2625e6eSJosh Paetzel if (!*m_new) { 1004c2625e6eSJosh Paetzel *os2bmc = FALSE; 1005c2625e6eSJosh Paetzel return; 1006c2625e6eSJosh Paetzel } 1007c2625e6eSJosh Paetzel *m_new = oce_insert_vlan_tag(sc, *m_new, NULL); 1008c2625e6eSJosh Paetzel } 1009c2625e6eSJosh Paetzel } 1010c2625e6eSJosh Paetzel 10112f345d8eSLuigi Rizzo 10122f345d8eSLuigi Rizzo 10132f345d8eSLuigi Rizzo /***************************************************************************** 10142f345d8eSLuigi Rizzo * Transmit routines functions * 10152f345d8eSLuigi Rizzo *****************************************************************************/ 10162f345d8eSLuigi Rizzo 10172f345d8eSLuigi Rizzo static int 10182f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 10192f345d8eSLuigi Rizzo { 10202f345d8eSLuigi Rizzo int rc = 0, i, retry_cnt = 0; 10212f345d8eSLuigi Rizzo bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 1022c2625e6eSJosh Paetzel struct mbuf *m, *m_temp, *m_new = NULL; 10232f345d8eSLuigi Rizzo struct oce_wq *wq = sc->wq[wq_index]; 10242f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 10252f345d8eSLuigi Rizzo struct oce_nic_hdr_wqe *nichdr; 10262f345d8eSLuigi Rizzo struct oce_nic_frag_wqe *nicfrag; 1027c2625e6eSJosh Paetzel struct ether_header *eh = NULL; 10282f345d8eSLuigi Rizzo int num_wqes; 10292f345d8eSLuigi Rizzo uint32_t reg_value; 1030cdaba892SXin LI boolean_t complete = TRUE; 1031c2625e6eSJosh Paetzel boolean_t os2bmc = FALSE; 10322f345d8eSLuigi Rizzo 10332f345d8eSLuigi Rizzo m = *mpp; 10342f345d8eSLuigi Rizzo if (!m) 10352f345d8eSLuigi Rizzo return EINVAL; 10362f345d8eSLuigi Rizzo 10372f345d8eSLuigi Rizzo if (!(m->m_flags & M_PKTHDR)) { 10382f345d8eSLuigi Rizzo rc = ENXIO; 10392f345d8eSLuigi Rizzo goto free_ret; 10402f345d8eSLuigi Rizzo } 10412f345d8eSLuigi Rizzo 1042c2625e6eSJosh Paetzel /* Don't allow non-TSO packets longer than MTU */ 1043c2625e6eSJosh Paetzel if (!is_tso_pkt(m)) { 1044c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *); 1045c2625e6eSJosh Paetzel if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE)) 1046c2625e6eSJosh Paetzel goto free_ret; 1047c2625e6eSJosh Paetzel } 1048c2625e6eSJosh Paetzel 1049cdaba892SXin LI if(oce_tx_asic_stall_verify(sc, m)) { 1050cdaba892SXin LI m = oce_insert_vlan_tag(sc, m, &complete); 1051cdaba892SXin LI if(!m) { 1052cdaba892SXin LI device_printf(sc->dev, "Insertion unsuccessful\n"); 1053cdaba892SXin LI return 0; 1054cdaba892SXin LI } 1055cdaba892SXin LI 1056cdaba892SXin LI } 1057cdaba892SXin LI 1058c2625e6eSJosh Paetzel /* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less 1059c2625e6eSJosh Paetzel * may cause a transmit stall on that port. So the work-around is to 1060c2625e6eSJosh Paetzel * pad short packets (<= 32 bytes) to a 36-byte length. 1061c2625e6eSJosh Paetzel */ 1062c2625e6eSJosh Paetzel if(IS_SH(sc) || IS_XE201(sc) ) { 1063c2625e6eSJosh Paetzel if(m->m_pkthdr.len <= 32) { 1064c2625e6eSJosh Paetzel char buf[36]; 1065c2625e6eSJosh Paetzel bzero((void *)buf, 36); 1066c2625e6eSJosh Paetzel m_append(m, (36 - m->m_pkthdr.len), buf); 1067c2625e6eSJosh Paetzel } 1068c2625e6eSJosh Paetzel } 1069c2625e6eSJosh Paetzel 1070c2625e6eSJosh Paetzel tx_start: 10712f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) { 10722f345d8eSLuigi Rizzo /* consolidate packet buffers for TSO/LSO segment offload */ 10739bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET) 10749bd3250aSLuigi Rizzo m = oce_tso_setup(sc, mpp); 1075ad512958SBjoern A. Zeeb #else 1076ad512958SBjoern A. Zeeb m = NULL; 1077ad512958SBjoern A. Zeeb #endif 10782f345d8eSLuigi Rizzo if (m == NULL) { 10792f345d8eSLuigi Rizzo rc = ENXIO; 10802f345d8eSLuigi Rizzo goto free_ret; 10812f345d8eSLuigi Rizzo } 10822f345d8eSLuigi Rizzo } 10832f345d8eSLuigi Rizzo 1084c2625e6eSJosh Paetzel 1085291a1934SXin LI pd = &wq->pckts[wq->pkt_desc_head]; 1086c2625e6eSJosh Paetzel 10872f345d8eSLuigi Rizzo retry: 10882f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(wq->tag, 10892f345d8eSLuigi Rizzo pd->map, 10902f345d8eSLuigi Rizzo m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 10912f345d8eSLuigi Rizzo if (rc == 0) { 10922f345d8eSLuigi Rizzo num_wqes = pd->nsegs + 1; 1093291a1934SXin LI if (IS_BE(sc) || IS_SH(sc)) { 10942f345d8eSLuigi Rizzo /*Dummy required only for BE3.*/ 10952f345d8eSLuigi Rizzo if (num_wqes & 1) 10962f345d8eSLuigi Rizzo num_wqes++; 10972f345d8eSLuigi Rizzo } 10982f345d8eSLuigi Rizzo if (num_wqes >= RING_NUM_FREE(wq->ring)) { 10992f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map); 11002f345d8eSLuigi Rizzo return EBUSY; 11012f345d8eSLuigi Rizzo } 1102291a1934SXin LI atomic_store_rel_int(&wq->pkt_desc_head, 1103291a1934SXin LI (wq->pkt_desc_head + 1) % \ 1104291a1934SXin LI OCE_WQ_PACKET_ARRAY_SIZE); 11052f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 11062f345d8eSLuigi Rizzo pd->mbuf = m; 11072f345d8eSLuigi Rizzo 11082f345d8eSLuigi Rizzo nichdr = 11092f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 11102f345d8eSLuigi Rizzo nichdr->u0.dw[0] = 0; 11112f345d8eSLuigi Rizzo nichdr->u0.dw[1] = 0; 11122f345d8eSLuigi Rizzo nichdr->u0.dw[2] = 0; 11132f345d8eSLuigi Rizzo nichdr->u0.dw[3] = 0; 11142f345d8eSLuigi Rizzo 1115cdaba892SXin LI nichdr->u0.s.complete = complete; 1116c2625e6eSJosh Paetzel nichdr->u0.s.mgmt = os2bmc; 11172f345d8eSLuigi Rizzo nichdr->u0.s.event = 1; 11182f345d8eSLuigi Rizzo nichdr->u0.s.crc = 1; 11192f345d8eSLuigi Rizzo nichdr->u0.s.forward = 0; 11202f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 11212f345d8eSLuigi Rizzo nichdr->u0.s.udpcs = 11222f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 11232f345d8eSLuigi Rizzo nichdr->u0.s.tcpcs = 11242f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 11252f345d8eSLuigi Rizzo nichdr->u0.s.num_wqe = num_wqes; 11262f345d8eSLuigi Rizzo nichdr->u0.s.total_length = m->m_pkthdr.len; 11275fbb6830SXin LI 11282f345d8eSLuigi Rizzo if (m->m_flags & M_VLANTAG) { 11292f345d8eSLuigi Rizzo nichdr->u0.s.vlan = 1; /*Vlan present*/ 11302f345d8eSLuigi Rizzo nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 11312f345d8eSLuigi Rizzo } 11325fbb6830SXin LI 11332f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) { 11342f345d8eSLuigi Rizzo if (m->m_pkthdr.tso_segsz) { 11352f345d8eSLuigi Rizzo nichdr->u0.s.lso = 1; 11362f345d8eSLuigi Rizzo nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 11372f345d8eSLuigi Rizzo } 1138291a1934SXin LI if (!IS_BE(sc) || !IS_SH(sc)) 11392f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = 1; 11402f345d8eSLuigi Rizzo } 11412f345d8eSLuigi Rizzo 11422f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1143291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11442f345d8eSLuigi Rizzo 11452f345d8eSLuigi Rizzo for (i = 0; i < pd->nsegs; i++) { 11462f345d8eSLuigi Rizzo nicfrag = 11472f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, 11482f345d8eSLuigi Rizzo struct oce_nic_frag_wqe); 11492f345d8eSLuigi Rizzo nicfrag->u0.s.rsvd0 = 0; 11502f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 11512f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 11522f345d8eSLuigi Rizzo nicfrag->u0.s.frag_len = segs[i].ds_len; 11532f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx; 11542f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1155291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11562f345d8eSLuigi Rizzo } 11572f345d8eSLuigi Rizzo if (num_wqes > (pd->nsegs + 1)) { 11582f345d8eSLuigi Rizzo nicfrag = 11592f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, 11602f345d8eSLuigi Rizzo struct oce_nic_frag_wqe); 11612f345d8eSLuigi Rizzo nicfrag->u0.dw[0] = 0; 11622f345d8eSLuigi Rizzo nicfrag->u0.dw[1] = 0; 11632f345d8eSLuigi Rizzo nicfrag->u0.dw[2] = 0; 11642f345d8eSLuigi Rizzo nicfrag->u0.dw[3] = 0; 11652f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx; 11662f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1167291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11682f345d8eSLuigi Rizzo pd->nsegs++; 11692f345d8eSLuigi Rizzo } 11702f345d8eSLuigi Rizzo 1171c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1); 11722f345d8eSLuigi Rizzo wq->tx_stats.tx_reqs++; 11732f345d8eSLuigi Rizzo wq->tx_stats.tx_wrbs += num_wqes; 11742f345d8eSLuigi Rizzo wq->tx_stats.tx_bytes += m->m_pkthdr.len; 11752f345d8eSLuigi Rizzo wq->tx_stats.tx_pkts++; 11762f345d8eSLuigi Rizzo 11772f345d8eSLuigi Rizzo bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 11782f345d8eSLuigi Rizzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 11792f345d8eSLuigi Rizzo reg_value = (num_wqes << 16) | wq->wq_id; 1180c2625e6eSJosh Paetzel 1181c2625e6eSJosh Paetzel /* if os2bmc is not enabled or if the pkt is already tagged as 1182c2625e6eSJosh Paetzel bmc, do nothing 1183c2625e6eSJosh Paetzel */ 1184c2625e6eSJosh Paetzel oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new); 1185c2625e6eSJosh Paetzel 1186291a1934SXin LI OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value); 11872f345d8eSLuigi Rizzo 11882f345d8eSLuigi Rizzo } else if (rc == EFBIG) { 11892f345d8eSLuigi Rizzo if (retry_cnt == 0) { 1190c6499eccSGleb Smirnoff m_temp = m_defrag(m, M_NOWAIT); 11912f345d8eSLuigi Rizzo if (m_temp == NULL) 11922f345d8eSLuigi Rizzo goto free_ret; 11932f345d8eSLuigi Rizzo m = m_temp; 11942f345d8eSLuigi Rizzo *mpp = m_temp; 11952f345d8eSLuigi Rizzo retry_cnt = retry_cnt + 1; 11962f345d8eSLuigi Rizzo goto retry; 11972f345d8eSLuigi Rizzo } else 11982f345d8eSLuigi Rizzo goto free_ret; 11992f345d8eSLuigi Rizzo } else if (rc == ENOMEM) 12002f345d8eSLuigi Rizzo return rc; 12012f345d8eSLuigi Rizzo else 12022f345d8eSLuigi Rizzo goto free_ret; 12032f345d8eSLuigi Rizzo 1204c2625e6eSJosh Paetzel if (os2bmc) { 1205c2625e6eSJosh Paetzel m = m_new; 1206c2625e6eSJosh Paetzel goto tx_start; 1207c2625e6eSJosh Paetzel } 1208c2625e6eSJosh Paetzel 12092f345d8eSLuigi Rizzo return 0; 12102f345d8eSLuigi Rizzo 12112f345d8eSLuigi Rizzo free_ret: 12122f345d8eSLuigi Rizzo m_freem(*mpp); 12132f345d8eSLuigi Rizzo *mpp = NULL; 12142f345d8eSLuigi Rizzo return rc; 12152f345d8eSLuigi Rizzo } 12162f345d8eSLuigi Rizzo 12172f345d8eSLuigi Rizzo 12182f345d8eSLuigi Rizzo static void 1219c2625e6eSJosh Paetzel oce_process_tx_completion(struct oce_wq *wq) 12202f345d8eSLuigi Rizzo { 12212f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 12222f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 12232f345d8eSLuigi Rizzo struct mbuf *m; 12242f345d8eSLuigi Rizzo 1225291a1934SXin LI pd = &wq->pckts[wq->pkt_desc_tail]; 1226291a1934SXin LI atomic_store_rel_int(&wq->pkt_desc_tail, 1227291a1934SXin LI (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE); 1228291a1934SXin LI atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1); 12292f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 12302f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map); 12312f345d8eSLuigi Rizzo 12322f345d8eSLuigi Rizzo m = pd->mbuf; 12332f345d8eSLuigi Rizzo m_freem(m); 12342f345d8eSLuigi Rizzo pd->mbuf = NULL; 12352f345d8eSLuigi Rizzo 1236291a1934SXin LI 12372f345d8eSLuigi Rizzo if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 12382f345d8eSLuigi Rizzo if (wq->ring->num_used < (wq->ring->num_items / 2)) { 12392f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 12402f345d8eSLuigi Rizzo oce_tx_restart(sc, wq); 12412f345d8eSLuigi Rizzo } 12422f345d8eSLuigi Rizzo } 12432f345d8eSLuigi Rizzo } 12442f345d8eSLuigi Rizzo 12452f345d8eSLuigi Rizzo 12462f345d8eSLuigi Rizzo static void 12472f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 12482f345d8eSLuigi Rizzo { 12492f345d8eSLuigi Rizzo 12502f345d8eSLuigi Rizzo if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 12512f345d8eSLuigi Rizzo return; 12522f345d8eSLuigi Rizzo 12532f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 12542f345d8eSLuigi Rizzo if (!drbr_empty(sc->ifp, wq->br)) 12552f345d8eSLuigi Rizzo #else 12562f345d8eSLuigi Rizzo if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 12572f345d8eSLuigi Rizzo #endif 1258cbc4d2dbSJohn Baldwin taskqueue_enqueue(taskqueue_swi, &wq->txtask); 12592f345d8eSLuigi Rizzo 12602f345d8eSLuigi Rizzo } 12612f345d8eSLuigi Rizzo 12629bd3250aSLuigi Rizzo 1263ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 12642f345d8eSLuigi Rizzo static struct mbuf * 12659bd3250aSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp) 12662f345d8eSLuigi Rizzo { 12672f345d8eSLuigi Rizzo struct mbuf *m; 1268ad512958SBjoern A. Zeeb #ifdef INET 12692f345d8eSLuigi Rizzo struct ip *ip; 1270ad512958SBjoern A. Zeeb #endif 1271ad512958SBjoern A. Zeeb #ifdef INET6 12722f345d8eSLuigi Rizzo struct ip6_hdr *ip6; 1273ad512958SBjoern A. Zeeb #endif 12742f345d8eSLuigi Rizzo struct ether_vlan_header *eh; 12752f345d8eSLuigi Rizzo struct tcphdr *th; 12762f345d8eSLuigi Rizzo uint16_t etype; 12779bd3250aSLuigi Rizzo int total_len = 0, ehdrlen = 0; 12782f345d8eSLuigi Rizzo 12792f345d8eSLuigi Rizzo m = *mpp; 12802f345d8eSLuigi Rizzo 12812f345d8eSLuigi Rizzo if (M_WRITABLE(m) == 0) { 1282c6499eccSGleb Smirnoff m = m_dup(*mpp, M_NOWAIT); 12832f345d8eSLuigi Rizzo if (!m) 12842f345d8eSLuigi Rizzo return NULL; 12852f345d8eSLuigi Rizzo m_freem(*mpp); 12862f345d8eSLuigi Rizzo *mpp = m; 12872f345d8eSLuigi Rizzo } 12882f345d8eSLuigi Rizzo 12892f345d8eSLuigi Rizzo eh = mtod(m, struct ether_vlan_header *); 12902f345d8eSLuigi Rizzo if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 12912f345d8eSLuigi Rizzo etype = ntohs(eh->evl_proto); 12922f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 12932f345d8eSLuigi Rizzo } else { 12942f345d8eSLuigi Rizzo etype = ntohs(eh->evl_encap_proto); 12952f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN; 12962f345d8eSLuigi Rizzo } 12972f345d8eSLuigi Rizzo 12982f345d8eSLuigi Rizzo switch (etype) { 1299ad512958SBjoern A. Zeeb #ifdef INET 13002f345d8eSLuigi Rizzo case ETHERTYPE_IP: 13012f345d8eSLuigi Rizzo ip = (struct ip *)(m->m_data + ehdrlen); 13022f345d8eSLuigi Rizzo if (ip->ip_p != IPPROTO_TCP) 13032f345d8eSLuigi Rizzo return NULL; 13042f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 13052f345d8eSLuigi Rizzo 13062f345d8eSLuigi Rizzo total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 13072f345d8eSLuigi Rizzo break; 1308ad512958SBjoern A. Zeeb #endif 1309ad512958SBjoern A. Zeeb #ifdef INET6 13102f345d8eSLuigi Rizzo case ETHERTYPE_IPV6: 13112f345d8eSLuigi Rizzo ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 13122f345d8eSLuigi Rizzo if (ip6->ip6_nxt != IPPROTO_TCP) 13132f345d8eSLuigi Rizzo return NULL; 13142f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 13152f345d8eSLuigi Rizzo 13162f345d8eSLuigi Rizzo total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 13172f345d8eSLuigi Rizzo break; 1318ad512958SBjoern A. Zeeb #endif 13192f345d8eSLuigi Rizzo default: 13202f345d8eSLuigi Rizzo return NULL; 13212f345d8eSLuigi Rizzo } 13222f345d8eSLuigi Rizzo 13232f345d8eSLuigi Rizzo m = m_pullup(m, total_len); 13242f345d8eSLuigi Rizzo if (!m) 13252f345d8eSLuigi Rizzo return NULL; 13262f345d8eSLuigi Rizzo *mpp = m; 13272f345d8eSLuigi Rizzo return m; 13282f345d8eSLuigi Rizzo 13292f345d8eSLuigi Rizzo } 1330ad512958SBjoern A. Zeeb #endif /* INET6 || INET */ 13312f345d8eSLuigi Rizzo 13322f345d8eSLuigi Rizzo void 13332f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending) 13342f345d8eSLuigi Rizzo { 13352f345d8eSLuigi Rizzo struct oce_wq *wq = arg; 13362f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 13372f345d8eSLuigi Rizzo struct ifnet *ifp = sc->ifp; 13382f345d8eSLuigi Rizzo int rc = 0; 13392f345d8eSLuigi Rizzo 13402f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1341291a1934SXin LI LOCK(&wq->tx_lock); 13422f345d8eSLuigi Rizzo rc = oce_multiq_transmit(ifp, NULL, wq); 13432f345d8eSLuigi Rizzo if (rc) { 13442f345d8eSLuigi Rizzo device_printf(sc->dev, 13452f345d8eSLuigi Rizzo "TX[%d] restart failed\n", wq->queue_index); 13462f345d8eSLuigi Rizzo } 13472f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 13482f345d8eSLuigi Rizzo #else 13492f345d8eSLuigi Rizzo oce_start(ifp); 13502f345d8eSLuigi Rizzo #endif 13512f345d8eSLuigi Rizzo 13522f345d8eSLuigi Rizzo } 13532f345d8eSLuigi Rizzo 13542f345d8eSLuigi Rizzo 13552f345d8eSLuigi Rizzo void 13562f345d8eSLuigi Rizzo oce_start(struct ifnet *ifp) 13572f345d8eSLuigi Rizzo { 13582f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 13592f345d8eSLuigi Rizzo struct mbuf *m; 13602f345d8eSLuigi Rizzo int rc = 0; 13619bd3250aSLuigi Rizzo int def_q = 0; /* Defualt tx queue is 0*/ 13622f345d8eSLuigi Rizzo 13632f345d8eSLuigi Rizzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 13642f345d8eSLuigi Rizzo IFF_DRV_RUNNING) 13652f345d8eSLuigi Rizzo return; 13662f345d8eSLuigi Rizzo 1367cdaba892SXin LI if (!sc->link_status) 1368cdaba892SXin LI return; 1369cdaba892SXin LI 13702f345d8eSLuigi Rizzo do { 13712f345d8eSLuigi Rizzo IF_DEQUEUE(&sc->ifp->if_snd, m); 13722f345d8eSLuigi Rizzo if (m == NULL) 13732f345d8eSLuigi Rizzo break; 13749bd3250aSLuigi Rizzo 13759bd3250aSLuigi Rizzo LOCK(&sc->wq[def_q]->tx_lock); 13769bd3250aSLuigi Rizzo rc = oce_tx(sc, &m, def_q); 13779bd3250aSLuigi Rizzo UNLOCK(&sc->wq[def_q]->tx_lock); 13782f345d8eSLuigi Rizzo if (rc) { 13792f345d8eSLuigi Rizzo if (m != NULL) { 13809bd3250aSLuigi Rizzo sc->wq[def_q]->tx_stats.tx_stops ++; 13812f345d8eSLuigi Rizzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 13822f345d8eSLuigi Rizzo IFQ_DRV_PREPEND(&ifp->if_snd, m); 13832f345d8eSLuigi Rizzo m = NULL; 13842f345d8eSLuigi Rizzo } 13852f345d8eSLuigi Rizzo break; 13862f345d8eSLuigi Rizzo } 13872f345d8eSLuigi Rizzo if (m != NULL) 13882f345d8eSLuigi Rizzo ETHER_BPF_MTAP(ifp, m); 13892f345d8eSLuigi Rizzo 13909bd3250aSLuigi Rizzo } while (TRUE); 13912f345d8eSLuigi Rizzo 13922f345d8eSLuigi Rizzo return; 13932f345d8eSLuigi Rizzo } 13942f345d8eSLuigi Rizzo 13952f345d8eSLuigi Rizzo 13962f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */ 13972f345d8eSLuigi Rizzo uint16_t 13982f345d8eSLuigi Rizzo oce_wq_handler(void *arg) 13992f345d8eSLuigi Rizzo { 14002f345d8eSLuigi Rizzo struct oce_wq *wq = (struct oce_wq *)arg; 14012f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 14022f345d8eSLuigi Rizzo struct oce_cq *cq = wq->cq; 14032f345d8eSLuigi Rizzo struct oce_nic_tx_cqe *cqe; 14042f345d8eSLuigi Rizzo int num_cqes = 0; 14052f345d8eSLuigi Rizzo 1406c2625e6eSJosh Paetzel LOCK(&wq->tx_compl_lock); 14072f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 14082f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 14092f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 14102f345d8eSLuigi Rizzo while (cqe->u0.dw[3]) { 14112f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 14122f345d8eSLuigi Rizzo 14132f345d8eSLuigi Rizzo wq->ring->cidx = cqe->u0.s.wqe_index + 1; 14142f345d8eSLuigi Rizzo if (wq->ring->cidx >= wq->ring->num_items) 14152f345d8eSLuigi Rizzo wq->ring->cidx -= wq->ring->num_items; 14162f345d8eSLuigi Rizzo 1417c2625e6eSJosh Paetzel oce_process_tx_completion(wq); 14182f345d8eSLuigi Rizzo wq->tx_stats.tx_compl++; 14192f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 14202f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 14212f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 14222f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 14232f345d8eSLuigi Rizzo cqe = 14242f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 14252f345d8eSLuigi Rizzo num_cqes++; 14262f345d8eSLuigi Rizzo } 14272f345d8eSLuigi Rizzo 14282f345d8eSLuigi Rizzo if (num_cqes) 14292f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 14302f345d8eSLuigi Rizzo 1431c2625e6eSJosh Paetzel UNLOCK(&wq->tx_compl_lock); 1432c2625e6eSJosh Paetzel return num_cqes; 14332f345d8eSLuigi Rizzo } 14342f345d8eSLuigi Rizzo 14352f345d8eSLuigi Rizzo 14362f345d8eSLuigi Rizzo static int 14372f345d8eSLuigi Rizzo oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 14382f345d8eSLuigi Rizzo { 14392f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 14402f345d8eSLuigi Rizzo int status = 0, queue_index = 0; 14412f345d8eSLuigi Rizzo struct mbuf *next = NULL; 14422f345d8eSLuigi Rizzo struct buf_ring *br = NULL; 14432f345d8eSLuigi Rizzo 14442f345d8eSLuigi Rizzo br = wq->br; 14452f345d8eSLuigi Rizzo queue_index = wq->queue_index; 14462f345d8eSLuigi Rizzo 14472f345d8eSLuigi Rizzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 14482f345d8eSLuigi Rizzo IFF_DRV_RUNNING) { 14492f345d8eSLuigi Rizzo if (m != NULL) 14502f345d8eSLuigi Rizzo status = drbr_enqueue(ifp, br, m); 14512f345d8eSLuigi Rizzo return status; 14522f345d8eSLuigi Rizzo } 14532f345d8eSLuigi Rizzo 1454ded5ea6aSRandall Stewart if (m != NULL) { 14552f345d8eSLuigi Rizzo if ((status = drbr_enqueue(ifp, br, m)) != 0) 14562f345d8eSLuigi Rizzo return status; 1457ded5ea6aSRandall Stewart } 1458ded5ea6aSRandall Stewart while ((next = drbr_peek(ifp, br)) != NULL) { 14592f345d8eSLuigi Rizzo if (oce_tx(sc, &next, queue_index)) { 1460ded5ea6aSRandall Stewart if (next == NULL) { 1461ded5ea6aSRandall Stewart drbr_advance(ifp, br); 1462ded5ea6aSRandall Stewart } else { 1463ded5ea6aSRandall Stewart drbr_putback(ifp, br, next); 14642f345d8eSLuigi Rizzo wq->tx_stats.tx_stops ++; 14652f345d8eSLuigi Rizzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 14662f345d8eSLuigi Rizzo } 14672f345d8eSLuigi Rizzo break; 14682f345d8eSLuigi Rizzo } 1469ded5ea6aSRandall Stewart drbr_advance(ifp, br); 1470c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len); 1471063efed2SGleb Smirnoff if (next->m_flags & M_MCAST) 1472c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 14732f345d8eSLuigi Rizzo ETHER_BPF_MTAP(ifp, next); 14742f345d8eSLuigi Rizzo } 14752f345d8eSLuigi Rizzo 1476d398c863SLuigi Rizzo return 0; 14772f345d8eSLuigi Rizzo } 14782f345d8eSLuigi Rizzo 14792f345d8eSLuigi Rizzo 14802f345d8eSLuigi Rizzo 14812f345d8eSLuigi Rizzo 14822f345d8eSLuigi Rizzo /***************************************************************************** 14832f345d8eSLuigi Rizzo * Receive routines functions * 14842f345d8eSLuigi Rizzo *****************************************************************************/ 14852f345d8eSLuigi Rizzo 14862f345d8eSLuigi Rizzo static void 1487c2625e6eSJosh Paetzel oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2) 14882f345d8eSLuigi Rizzo { 1489c2625e6eSJosh Paetzel uint32_t *p; 1490c2625e6eSJosh Paetzel struct ether_header *eh = NULL; 1491c2625e6eSJosh Paetzel struct tcphdr *tcp_hdr = NULL; 1492c2625e6eSJosh Paetzel struct ip *ip4_hdr = NULL; 1493c2625e6eSJosh Paetzel struct ip6_hdr *ip6 = NULL; 1494c2625e6eSJosh Paetzel uint32_t payload_len = 0; 1495c2625e6eSJosh Paetzel 1496c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *); 1497c2625e6eSJosh Paetzel /* correct IP header */ 1498c2625e6eSJosh Paetzel if(!cqe2->ipv6_frame) { 1499c2625e6eSJosh Paetzel ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header)); 1500c2625e6eSJosh Paetzel ip4_hdr->ip_ttl = cqe2->frame_lifespan; 1501c2625e6eSJosh Paetzel ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header)); 1502c2625e6eSJosh Paetzel tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip)); 1503c2625e6eSJosh Paetzel }else { 1504c2625e6eSJosh Paetzel ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header)); 1505c2625e6eSJosh Paetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan; 1506c2625e6eSJosh Paetzel payload_len = cqe2->coalesced_size - sizeof(struct ether_header) 1507c2625e6eSJosh Paetzel - sizeof(struct ip6_hdr); 1508c2625e6eSJosh Paetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len); 1509c2625e6eSJosh Paetzel tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr)); 1510c2625e6eSJosh Paetzel } 1511c2625e6eSJosh Paetzel 1512c2625e6eSJosh Paetzel /* correct tcp header */ 1513c2625e6eSJosh Paetzel tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num); 1514c2625e6eSJosh Paetzel if(cqe2->push) { 1515c2625e6eSJosh Paetzel tcp_hdr->th_flags |= TH_PUSH; 1516c2625e6eSJosh Paetzel } 1517c2625e6eSJosh Paetzel tcp_hdr->th_win = htons(cqe2->tcp_window); 1518c2625e6eSJosh Paetzel tcp_hdr->th_sum = 0xffff; 1519c2625e6eSJosh Paetzel if(cqe2->ts_opt) { 1520c2625e6eSJosh Paetzel p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2); 1521c2625e6eSJosh Paetzel *p = cqe1->tcp_timestamp_val; 1522c2625e6eSJosh Paetzel *(p+1) = cqe1->tcp_timestamp_ecr; 1523c2625e6eSJosh Paetzel } 1524c2625e6eSJosh Paetzel 1525c2625e6eSJosh Paetzel return; 1526c2625e6eSJosh Paetzel } 1527c2625e6eSJosh Paetzel 1528c2625e6eSJosh Paetzel static void 1529c2625e6eSJosh Paetzel oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m) 1530c2625e6eSJosh Paetzel { 1531764c812dSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1532c2625e6eSJosh Paetzel uint32_t i = 0, frag_len = 0; 1533c2625e6eSJosh Paetzel uint32_t len = cqe_info->pkt_size; 1534c2625e6eSJosh Paetzel struct oce_packet_desc *pd; 1535c2625e6eSJosh Paetzel struct mbuf *tail = NULL; 1536764c812dSJosh Paetzel 1537c2625e6eSJosh Paetzel for (i = 0; i < cqe_info->num_frags; i++) { 1538c2625e6eSJosh Paetzel if (rq->ring->cidx == rq->ring->pidx) { 153914410265SConrad Meyer device_printf(sc->dev, 1540c2625e6eSJosh Paetzel "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n"); 1541c2625e6eSJosh Paetzel return; 154214410265SConrad Meyer } 1543c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->cidx]; 154414410265SConrad Meyer 154514410265SConrad Meyer bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 154614410265SConrad Meyer bus_dmamap_unload(rq->tag, pd->map); 1547c2625e6eSJosh Paetzel RING_GET(rq->ring, 1); 154814410265SConrad Meyer rq->pending--; 154914410265SConrad Meyer 155014410265SConrad Meyer frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 155114410265SConrad Meyer pd->mbuf->m_len = frag_len; 155214410265SConrad Meyer 155314410265SConrad Meyer if (tail != NULL) { 155414410265SConrad Meyer /* additional fragments */ 155514410265SConrad Meyer pd->mbuf->m_flags &= ~M_PKTHDR; 155614410265SConrad Meyer tail->m_next = pd->mbuf; 1557c2625e6eSJosh Paetzel if(rq->islro) 1558c2625e6eSJosh Paetzel tail->m_nextpkt = NULL; 155914410265SConrad Meyer tail = pd->mbuf; 156014410265SConrad Meyer } else { 156114410265SConrad Meyer /* first fragment, fill out much of the packet header */ 156214410265SConrad Meyer pd->mbuf->m_pkthdr.len = len; 1563c2625e6eSJosh Paetzel if(rq->islro) 1564c2625e6eSJosh Paetzel pd->mbuf->m_nextpkt = NULL; 156514410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags = 0; 156614410265SConrad Meyer if (IF_CSUM_ENABLED(sc)) { 1567c2625e6eSJosh Paetzel if (cqe_info->l4_cksum_pass) { 1568c2625e6eSJosh Paetzel if(!cqe_info->ipv6_frame) { /* IPV4 */ 156914410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags |= 157014410265SConrad Meyer (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1571c2625e6eSJosh Paetzel }else { /* IPV6 frame */ 1572c2625e6eSJosh Paetzel if(rq->islro) { 1573c2625e6eSJosh Paetzel pd->mbuf->m_pkthdr.csum_flags |= 1574c2625e6eSJosh Paetzel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1575c2625e6eSJosh Paetzel } 1576c2625e6eSJosh Paetzel } 157714410265SConrad Meyer pd->mbuf->m_pkthdr.csum_data = 0xffff; 157814410265SConrad Meyer } 1579c2625e6eSJosh Paetzel if (cqe_info->ip_cksum_pass) { 158014410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags |= 158114410265SConrad Meyer (CSUM_IP_CHECKED|CSUM_IP_VALID); 158214410265SConrad Meyer } 158314410265SConrad Meyer } 1584c2625e6eSJosh Paetzel *m = tail = pd->mbuf; 158514410265SConrad Meyer } 158614410265SConrad Meyer pd->mbuf = NULL; 158714410265SConrad Meyer len -= frag_len; 158814410265SConrad Meyer } 1589764c812dSJosh Paetzel 1590c2625e6eSJosh Paetzel return; 1591c2625e6eSJosh Paetzel } 1592c2625e6eSJosh Paetzel 1593c2625e6eSJosh Paetzel static void 1594c2625e6eSJosh Paetzel oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2) 1595c2625e6eSJosh Paetzel { 1596c2625e6eSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1597c2625e6eSJosh Paetzel struct nic_hwlro_cqe_part1 *cqe1 = NULL; 1598c2625e6eSJosh Paetzel struct mbuf *m = NULL; 1599c2625e6eSJosh Paetzel struct oce_common_cqe_info cq_info; 1600c2625e6eSJosh Paetzel 1601c2625e6eSJosh Paetzel /* parse cqe */ 1602c2625e6eSJosh Paetzel if(cqe2 == NULL) { 1603c2625e6eSJosh Paetzel cq_info.pkt_size = cqe->pkt_size; 1604c2625e6eSJosh Paetzel cq_info.vtag = cqe->vlan_tag; 1605c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe->l4_cksum_pass; 1606c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe->ip_cksum_pass; 1607c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe->ipv6_frame; 1608c2625e6eSJosh Paetzel cq_info.vtp = cqe->vtp; 1609c2625e6eSJosh Paetzel cq_info.qnq = cqe->qnq; 1610c2625e6eSJosh Paetzel }else { 1611c2625e6eSJosh Paetzel cqe1 = (struct nic_hwlro_cqe_part1 *)cqe; 1612c2625e6eSJosh Paetzel cq_info.pkt_size = cqe2->coalesced_size; 1613c2625e6eSJosh Paetzel cq_info.vtag = cqe2->vlan_tag; 1614c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe2->l4_cksum_pass; 1615c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe2->ip_cksum_pass; 1616c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe2->ipv6_frame; 1617c2625e6eSJosh Paetzel cq_info.vtp = cqe2->vtp; 1618c2625e6eSJosh Paetzel cq_info.qnq = cqe1->qnq; 1619c2625e6eSJosh Paetzel } 1620c2625e6eSJosh Paetzel 1621c2625e6eSJosh Paetzel cq_info.vtag = BSWAP_16(cq_info.vtag); 1622c2625e6eSJosh Paetzel 1623c2625e6eSJosh Paetzel cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size; 1624c2625e6eSJosh Paetzel if(cq_info.pkt_size % rq->cfg.frag_size) 1625c2625e6eSJosh Paetzel cq_info.num_frags++; 1626c2625e6eSJosh Paetzel 1627c2625e6eSJosh Paetzel oce_rx_mbuf_chain(rq, &cq_info, &m); 1628c2625e6eSJosh Paetzel 1629764c812dSJosh Paetzel if (m) { 1630c2625e6eSJosh Paetzel if(cqe2) { 1631c2625e6eSJosh Paetzel //assert(cqe2->valid != 0); 1632c2625e6eSJosh Paetzel 1633c2625e6eSJosh Paetzel //assert(cqe2->cqe_type != 2); 1634c2625e6eSJosh Paetzel oce_correct_header(m, cqe1, cqe2); 1635c2625e6eSJosh Paetzel } 1636c2625e6eSJosh Paetzel 1637c2625e6eSJosh Paetzel m->m_pkthdr.rcvif = sc->ifp; 1638c2625e6eSJosh Paetzel #if __FreeBSD_version >= 800000 1639c2625e6eSJosh Paetzel if (rq->queue_index) 1640c2625e6eSJosh Paetzel m->m_pkthdr.flowid = (rq->queue_index - 1); 1641c2625e6eSJosh Paetzel else 1642c2625e6eSJosh Paetzel m->m_pkthdr.flowid = rq->queue_index; 1643c2625e6eSJosh Paetzel M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 1644c2625e6eSJosh Paetzel #endif 1645c2625e6eSJosh Paetzel /* This deternies if vlan tag is Valid */ 1646c2625e6eSJosh Paetzel if (cq_info.vtp) { 1647c2625e6eSJosh Paetzel if (sc->function_mode & FNM_FLEX10_MODE) { 1648c2625e6eSJosh Paetzel /* FLEX10. If QnQ is not set, neglect VLAN */ 1649c2625e6eSJosh Paetzel if (cq_info.qnq) { 1650c2625e6eSJosh Paetzel m->m_pkthdr.ether_vtag = cq_info.vtag; 1651c2625e6eSJosh Paetzel m->m_flags |= M_VLANTAG; 1652c2625e6eSJosh Paetzel } 1653c2625e6eSJosh Paetzel } else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK)) { 1654c2625e6eSJosh Paetzel /* In UMC mode generally pvid will be striped by 1655c2625e6eSJosh Paetzel hw. But in some cases we have seen it comes 1656c2625e6eSJosh Paetzel with pvid. So if pvid == vlan, neglect vlan. 1657c2625e6eSJosh Paetzel */ 1658c2625e6eSJosh Paetzel m->m_pkthdr.ether_vtag = cq_info.vtag; 1659c2625e6eSJosh Paetzel m->m_flags |= M_VLANTAG; 1660c2625e6eSJosh Paetzel } 1661c2625e6eSJosh Paetzel } 1662c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 1663c2625e6eSJosh Paetzel 1664c2625e6eSJosh Paetzel (*sc->ifp->if_input) (sc->ifp, m); 1665c2625e6eSJosh Paetzel 1666c2625e6eSJosh Paetzel /* Update rx stats per queue */ 1667c2625e6eSJosh Paetzel rq->rx_stats.rx_pkts++; 1668c2625e6eSJosh Paetzel rq->rx_stats.rx_bytes += cq_info.pkt_size; 1669c2625e6eSJosh Paetzel rq->rx_stats.rx_frags += cq_info.num_frags; 1670c2625e6eSJosh Paetzel rq->rx_stats.rx_ucast_pkts++; 1671c2625e6eSJosh Paetzel } 1672c2625e6eSJosh Paetzel return; 1673c2625e6eSJosh Paetzel } 1674c2625e6eSJosh Paetzel 1675c2625e6eSJosh Paetzel static void 1676c2625e6eSJosh Paetzel oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1677c2625e6eSJosh Paetzel { 1678c2625e6eSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1679c2625e6eSJosh Paetzel int len; 1680c2625e6eSJosh Paetzel struct mbuf *m = NULL; 1681c2625e6eSJosh Paetzel struct oce_common_cqe_info cq_info; 1682c2625e6eSJosh Paetzel uint16_t vtag = 0; 1683c2625e6eSJosh Paetzel 1684c2625e6eSJosh Paetzel /* Is it a flush compl that has no data */ 1685c2625e6eSJosh Paetzel if(!cqe->u0.s.num_fragments) 1686c2625e6eSJosh Paetzel goto exit; 1687c2625e6eSJosh Paetzel 1688c2625e6eSJosh Paetzel len = cqe->u0.s.pkt_size; 1689c2625e6eSJosh Paetzel if (!len) { 1690c2625e6eSJosh Paetzel /*partial DMA workaround for Lancer*/ 1691c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 169214410265SConrad Meyer goto exit; 169314410265SConrad Meyer } 169414410265SConrad Meyer 1695c2625e6eSJosh Paetzel if (!oce_cqe_portid_valid(sc, cqe)) { 1696c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 1697c2625e6eSJosh Paetzel goto exit; 1698c2625e6eSJosh Paetzel } 1699c2625e6eSJosh Paetzel 1700c2625e6eSJosh Paetzel /* Get vlan_tag value */ 1701c2625e6eSJosh Paetzel if(IS_BE(sc) || IS_SH(sc)) 1702c2625e6eSJosh Paetzel vtag = BSWAP_16(cqe->u0.s.vlan_tag); 1703c2625e6eSJosh Paetzel else 1704c2625e6eSJosh Paetzel vtag = cqe->u0.s.vlan_tag; 1705c2625e6eSJosh Paetzel 1706c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass; 1707c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass; 1708c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe->u0.s.ip_ver; 1709c2625e6eSJosh Paetzel cq_info.num_frags = cqe->u0.s.num_fragments; 1710c2625e6eSJosh Paetzel cq_info.pkt_size = cqe->u0.s.pkt_size; 1711c2625e6eSJosh Paetzel 1712c2625e6eSJosh Paetzel oce_rx_mbuf_chain(rq, &cq_info, &m); 1713c2625e6eSJosh Paetzel 1714c2625e6eSJosh Paetzel if (m) { 17152f345d8eSLuigi Rizzo m->m_pkthdr.rcvif = sc->ifp; 17162f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1717291a1934SXin LI if (rq->queue_index) 1718291a1934SXin LI m->m_pkthdr.flowid = (rq->queue_index - 1); 1719291a1934SXin LI else 17202f345d8eSLuigi Rizzo m->m_pkthdr.flowid = rq->queue_index; 1721c2529042SHans Petter Selasky M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 17222f345d8eSLuigi Rizzo #endif 17239bd3250aSLuigi Rizzo /* This deternies if vlan tag is Valid */ 17242f345d8eSLuigi Rizzo if (oce_cqe_vtp_valid(sc, cqe)) { 17252f345d8eSLuigi Rizzo if (sc->function_mode & FNM_FLEX10_MODE) { 17269bd3250aSLuigi Rizzo /* FLEX10. If QnQ is not set, neglect VLAN */ 17272f345d8eSLuigi Rizzo if (cqe->u0.s.qnq) { 17282f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag; 17292f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG; 17302f345d8eSLuigi Rizzo } 17319bd3250aSLuigi Rizzo } else if (sc->pvid != (vtag & VLAN_VID_MASK)) { 17329bd3250aSLuigi Rizzo /* In UMC mode generally pvid will be striped by 17339bd3250aSLuigi Rizzo hw. But in some cases we have seen it comes 17349bd3250aSLuigi Rizzo with pvid. So if pvid == vlan, neglect vlan. 17359bd3250aSLuigi Rizzo */ 17362f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag; 17372f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG; 17382f345d8eSLuigi Rizzo } 17392f345d8eSLuigi Rizzo } 17402f345d8eSLuigi Rizzo 1741c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 1742ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 17432f345d8eSLuigi Rizzo /* Try to queue to LRO */ 17442f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && 17452f345d8eSLuigi Rizzo (cqe->u0.s.ip_cksum_pass) && 17462f345d8eSLuigi Rizzo (cqe->u0.s.l4_cksum_pass) && 17472f345d8eSLuigi Rizzo (!cqe->u0.s.ip_ver) && 17482f345d8eSLuigi Rizzo (rq->lro.lro_cnt != 0)) { 17492f345d8eSLuigi Rizzo 17502f345d8eSLuigi Rizzo if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 17512f345d8eSLuigi Rizzo rq->lro_pkts_queued ++; 17522f345d8eSLuigi Rizzo goto post_done; 17532f345d8eSLuigi Rizzo } 17542f345d8eSLuigi Rizzo /* If LRO posting fails then try to post to STACK */ 17552f345d8eSLuigi Rizzo } 1756ad512958SBjoern A. Zeeb #endif 17572f345d8eSLuigi Rizzo 17582f345d8eSLuigi Rizzo (*sc->ifp->if_input) (sc->ifp, m); 1759ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 17602f345d8eSLuigi Rizzo post_done: 1761ad512958SBjoern A. Zeeb #endif 17622f345d8eSLuigi Rizzo /* Update rx stats per queue */ 17632f345d8eSLuigi Rizzo rq->rx_stats.rx_pkts++; 17642f345d8eSLuigi Rizzo rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 17652f345d8eSLuigi Rizzo rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 17662f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 17672f345d8eSLuigi Rizzo rq->rx_stats.rx_mcast_pkts++; 17682f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 17692f345d8eSLuigi Rizzo rq->rx_stats.rx_ucast_pkts++; 17702f345d8eSLuigi Rizzo } 17712f345d8eSLuigi Rizzo exit: 17722f345d8eSLuigi Rizzo return; 17732f345d8eSLuigi Rizzo } 17742f345d8eSLuigi Rizzo 17752f345d8eSLuigi Rizzo 1776c2625e6eSJosh Paetzel void 1777c2625e6eSJosh Paetzel oce_discard_rx_comp(struct oce_rq *rq, int num_frags) 17782f345d8eSLuigi Rizzo { 1779c2625e6eSJosh Paetzel uint32_t i = 0; 17802f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 17812f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 17822f345d8eSLuigi Rizzo 17832f345d8eSLuigi Rizzo for (i = 0; i < num_frags; i++) { 1784c2625e6eSJosh Paetzel if (rq->ring->cidx == rq->ring->pidx) { 17852f345d8eSLuigi Rizzo device_printf(sc->dev, 1786c2625e6eSJosh Paetzel "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n"); 1787c2625e6eSJosh Paetzel return; 17882f345d8eSLuigi Rizzo } 1789c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->cidx]; 17902f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 17912f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, pd->map); 1792c2625e6eSJosh Paetzel if (pd->mbuf != NULL) { 17932f345d8eSLuigi Rizzo m_freem(pd->mbuf); 1794c2625e6eSJosh Paetzel pd->mbuf = NULL; 17952f345d8eSLuigi Rizzo } 17962f345d8eSLuigi Rizzo 1797c2625e6eSJosh Paetzel RING_GET(rq->ring, 1); 1798c2625e6eSJosh Paetzel rq->pending--; 1799c2625e6eSJosh Paetzel } 18002f345d8eSLuigi Rizzo } 18012f345d8eSLuigi Rizzo 18022f345d8eSLuigi Rizzo 18032f345d8eSLuigi Rizzo static int 18042f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 18052f345d8eSLuigi Rizzo { 18062f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1; 18072f345d8eSLuigi Rizzo int vtp = 0; 18082f345d8eSLuigi Rizzo 18092f345d8eSLuigi Rizzo if (sc->be3_native) { 18102f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 18112f345d8eSLuigi Rizzo vtp = cqe_v1->u0.s.vlan_tag_present; 18129bd3250aSLuigi Rizzo } else 18132f345d8eSLuigi Rizzo vtp = cqe->u0.s.vlan_tag_present; 18142f345d8eSLuigi Rizzo 18152f345d8eSLuigi Rizzo return vtp; 18162f345d8eSLuigi Rizzo 18172f345d8eSLuigi Rizzo } 18182f345d8eSLuigi Rizzo 18192f345d8eSLuigi Rizzo 18202f345d8eSLuigi Rizzo static int 18212f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 18222f345d8eSLuigi Rizzo { 18232f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1; 18242f345d8eSLuigi Rizzo int port_id = 0; 18252f345d8eSLuigi Rizzo 1826291a1934SXin LI if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) { 18272f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 18282f345d8eSLuigi Rizzo port_id = cqe_v1->u0.s.port; 18292f345d8eSLuigi Rizzo if (sc->port_id != port_id) 18302f345d8eSLuigi Rizzo return 0; 18312f345d8eSLuigi Rizzo } else 18322f345d8eSLuigi Rizzo ;/* For BE3 legacy and Lancer this is dummy */ 18332f345d8eSLuigi Rizzo 18342f345d8eSLuigi Rizzo return 1; 18352f345d8eSLuigi Rizzo 18362f345d8eSLuigi Rizzo } 18372f345d8eSLuigi Rizzo 1838ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 1839c2625e6eSJosh Paetzel void 18402f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq) 18412f345d8eSLuigi Rizzo { 18422f345d8eSLuigi Rizzo struct lro_ctrl *lro = &rq->lro; 18432f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 18442f345d8eSLuigi Rizzo 18452f345d8eSLuigi Rizzo if (!IF_LRO_ENABLED(sc)) 18462f345d8eSLuigi Rizzo return; 18472f345d8eSLuigi Rizzo 18486dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro); 18492f345d8eSLuigi Rizzo rq->lro_pkts_queued = 0; 18502f345d8eSLuigi Rizzo 18512f345d8eSLuigi Rizzo return; 18522f345d8eSLuigi Rizzo } 18532f345d8eSLuigi Rizzo 18542f345d8eSLuigi Rizzo 18552f345d8eSLuigi Rizzo static int 18562f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc) 18572f345d8eSLuigi Rizzo { 18582f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL; 18592f345d8eSLuigi Rizzo int i = 0, rc = 0; 18602f345d8eSLuigi Rizzo 18612f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) { 18622f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro; 18632f345d8eSLuigi Rizzo rc = tcp_lro_init(lro); 18642f345d8eSLuigi Rizzo if (rc != 0) { 18652f345d8eSLuigi Rizzo device_printf(sc->dev, "LRO init failed\n"); 18662f345d8eSLuigi Rizzo return rc; 18672f345d8eSLuigi Rizzo } 18682f345d8eSLuigi Rizzo lro->ifp = sc->ifp; 18692f345d8eSLuigi Rizzo } 18702f345d8eSLuigi Rizzo 18712f345d8eSLuigi Rizzo return rc; 18722f345d8eSLuigi Rizzo } 18739bd3250aSLuigi Rizzo 18742f345d8eSLuigi Rizzo 18752f345d8eSLuigi Rizzo void 18762f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc) 18772f345d8eSLuigi Rizzo { 18782f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL; 18792f345d8eSLuigi Rizzo int i = 0; 18802f345d8eSLuigi Rizzo 18812f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) { 18822f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro; 18832f345d8eSLuigi Rizzo if (lro) 18842f345d8eSLuigi Rizzo tcp_lro_free(lro); 18852f345d8eSLuigi Rizzo } 18862f345d8eSLuigi Rizzo } 1887cdaba892SXin LI #endif 18882f345d8eSLuigi Rizzo 18892f345d8eSLuigi Rizzo int 18902f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count) 18912f345d8eSLuigi Rizzo { 18922f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 18932f345d8eSLuigi Rizzo int i, in, rc; 18942f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 18952f345d8eSLuigi Rizzo bus_dma_segment_t segs[6]; 18962f345d8eSLuigi Rizzo int nsegs, added = 0; 18972f345d8eSLuigi Rizzo struct oce_nic_rqe *rqe; 18982f345d8eSLuigi Rizzo pd_rxulp_db_t rxdb_reg; 1899c2625e6eSJosh Paetzel uint32_t val = 0; 1900c2625e6eSJosh Paetzel uint32_t oce_max_rq_posts = 64; 19012f345d8eSLuigi Rizzo 1902cdaba892SXin LI bzero(&rxdb_reg, sizeof(pd_rxulp_db_t)); 19032f345d8eSLuigi Rizzo for (i = 0; i < count; i++) { 1904c2625e6eSJosh Paetzel in = (rq->ring->pidx + 1) % OCE_RQ_PACKET_ARRAY_SIZE; 19052f345d8eSLuigi Rizzo 1906c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->pidx]; 1907c2625e6eSJosh Paetzel pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size); 1908c2625e6eSJosh Paetzel if (pd->mbuf == NULL) { 1909c2625e6eSJosh Paetzel device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size); 19102f345d8eSLuigi Rizzo break; 1911c2625e6eSJosh Paetzel } 1912c2625e6eSJosh Paetzel pd->mbuf->m_nextpkt = NULL; 19132f345d8eSLuigi Rizzo 1914c2625e6eSJosh Paetzel pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size; 1915c2625e6eSJosh Paetzel 19162f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(rq->tag, 19172f345d8eSLuigi Rizzo pd->map, 19182f345d8eSLuigi Rizzo pd->mbuf, 19192f345d8eSLuigi Rizzo segs, &nsegs, BUS_DMA_NOWAIT); 19202f345d8eSLuigi Rizzo if (rc) { 19212f345d8eSLuigi Rizzo m_free(pd->mbuf); 1922c2625e6eSJosh Paetzel device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc); 19232f345d8eSLuigi Rizzo break; 19242f345d8eSLuigi Rizzo } 19252f345d8eSLuigi Rizzo 19262f345d8eSLuigi Rizzo if (nsegs != 1) { 19272f345d8eSLuigi Rizzo i--; 19282f345d8eSLuigi Rizzo continue; 19292f345d8eSLuigi Rizzo } 19302f345d8eSLuigi Rizzo 19312f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 19322f345d8eSLuigi Rizzo 19332f345d8eSLuigi Rizzo rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 19342f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 19352f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 19362f345d8eSLuigi Rizzo DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 19372f345d8eSLuigi Rizzo RING_PUT(rq->ring, 1); 19382f345d8eSLuigi Rizzo added++; 19392f345d8eSLuigi Rizzo rq->pending++; 19402f345d8eSLuigi Rizzo } 1941c2625e6eSJosh Paetzel oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS; 19422f345d8eSLuigi Rizzo if (added != 0) { 1943c2625e6eSJosh Paetzel for (i = added / oce_max_rq_posts; i > 0; i--) { 1944c2625e6eSJosh Paetzel rxdb_reg.bits.num_posted = oce_max_rq_posts; 19452f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id; 1946c2625e6eSJosh Paetzel if(rq->islro) { 1947c2625e6eSJosh Paetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK; 1948c2625e6eSJosh Paetzel val |= oce_max_rq_posts << 16; 1949c2625e6eSJosh Paetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val); 1950c2625e6eSJosh Paetzel }else { 19512f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1952c2625e6eSJosh Paetzel } 1953c2625e6eSJosh Paetzel added -= oce_max_rq_posts; 19542f345d8eSLuigi Rizzo } 19552f345d8eSLuigi Rizzo if (added > 0) { 19562f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id; 19572f345d8eSLuigi Rizzo rxdb_reg.bits.num_posted = added; 1958c2625e6eSJosh Paetzel if(rq->islro) { 1959c2625e6eSJosh Paetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK; 1960c2625e6eSJosh Paetzel val |= added << 16; 1961c2625e6eSJosh Paetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val); 1962c2625e6eSJosh Paetzel }else { 19632f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 19642f345d8eSLuigi Rizzo } 19652f345d8eSLuigi Rizzo } 1966c2625e6eSJosh Paetzel } 19672f345d8eSLuigi Rizzo 19682f345d8eSLuigi Rizzo return 0; 19692f345d8eSLuigi Rizzo } 19702f345d8eSLuigi Rizzo 1971c2625e6eSJosh Paetzel static void 1972c2625e6eSJosh Paetzel oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq) 1973c2625e6eSJosh Paetzel { 1974c2625e6eSJosh Paetzel if (num_cqes) { 1975c2625e6eSJosh Paetzel oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE); 1976c2625e6eSJosh Paetzel if(!sc->enable_hwlro) { 1977c2625e6eSJosh Paetzel if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1) 1978c2625e6eSJosh Paetzel oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1)); 1979c2625e6eSJosh Paetzel }else { 1980c2625e6eSJosh Paetzel if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64) 1981c2625e6eSJosh Paetzel oce_alloc_rx_bufs(rq, 64); 1982c2625e6eSJosh Paetzel } 1983c2625e6eSJosh Paetzel } 1984c2625e6eSJosh Paetzel 1985c2625e6eSJosh Paetzel return; 1986c2625e6eSJosh Paetzel } 1987c2625e6eSJosh Paetzel 1988c2625e6eSJosh Paetzel uint16_t 1989c2625e6eSJosh Paetzel oce_rq_handler_lro(void *arg) 1990c2625e6eSJosh Paetzel { 1991c2625e6eSJosh Paetzel struct oce_rq *rq = (struct oce_rq *)arg; 1992c2625e6eSJosh Paetzel struct oce_cq *cq = rq->cq; 1993c2625e6eSJosh Paetzel POCE_SOFTC sc = rq->parent; 1994c2625e6eSJosh Paetzel struct nic_hwlro_singleton_cqe *cqe; 1995c2625e6eSJosh Paetzel struct nic_hwlro_cqe_part2 *cqe2; 1996c2625e6eSJosh Paetzel int num_cqes = 0; 1997c2625e6eSJosh Paetzel 1998c2625e6eSJosh Paetzel LOCK(&rq->rx_lock); 1999c2625e6eSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2000c2625e6eSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 2001c2625e6eSJosh Paetzel while (cqe->valid) { 2002c2625e6eSJosh Paetzel if(cqe->cqe_type == 0) { /* singleton cqe */ 2003c2625e6eSJosh Paetzel /* we should not get singleton cqe after cqe1 on same rq */ 2004c2625e6eSJosh Paetzel if(rq->cqe_firstpart != NULL) { 2005c2625e6eSJosh Paetzel device_printf(sc->dev, "Got singleton cqe after cqe1 \n"); 2006c2625e6eSJosh Paetzel goto exit_rq_handler_lro; 2007c2625e6eSJosh Paetzel } 2008c2625e6eSJosh Paetzel if(cqe->error != 0) { 2009c2625e6eSJosh Paetzel rq->rx_stats.rxcp_err++; 2010c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2011c2625e6eSJosh Paetzel } 2012c2625e6eSJosh Paetzel oce_rx_lro(rq, cqe, NULL); 2013c2625e6eSJosh Paetzel rq->rx_stats.rx_compl++; 2014c2625e6eSJosh Paetzel cqe->valid = 0; 2015c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 2016c2625e6eSJosh Paetzel num_cqes++; 2017c2625e6eSJosh Paetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2018c2625e6eSJosh Paetzel break; 2019c2625e6eSJosh Paetzel }else if(cqe->cqe_type == 0x1) { /* first part */ 2020c2625e6eSJosh Paetzel /* we should not get cqe1 after cqe1 on same rq */ 2021c2625e6eSJosh Paetzel if(rq->cqe_firstpart != NULL) { 2022c2625e6eSJosh Paetzel device_printf(sc->dev, "Got cqe1 after cqe1 \n"); 2023c2625e6eSJosh Paetzel goto exit_rq_handler_lro; 2024c2625e6eSJosh Paetzel } 2025c2625e6eSJosh Paetzel rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe; 2026c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 2027c2625e6eSJosh Paetzel }else if(cqe->cqe_type == 0x2) { /* second part */ 2028c2625e6eSJosh Paetzel cqe2 = (struct nic_hwlro_cqe_part2 *)cqe; 2029c2625e6eSJosh Paetzel if(cqe2->error != 0) { 2030c2625e6eSJosh Paetzel rq->rx_stats.rxcp_err++; 2031c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2032c2625e6eSJosh Paetzel } 2033c2625e6eSJosh Paetzel /* We should not get cqe2 without cqe1 */ 2034c2625e6eSJosh Paetzel if(rq->cqe_firstpart == NULL) { 2035c2625e6eSJosh Paetzel device_printf(sc->dev, "Got cqe2 without cqe1 \n"); 2036c2625e6eSJosh Paetzel goto exit_rq_handler_lro; 2037c2625e6eSJosh Paetzel } 2038c2625e6eSJosh Paetzel oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2); 2039c2625e6eSJosh Paetzel 2040c2625e6eSJosh Paetzel rq->rx_stats.rx_compl++; 2041c2625e6eSJosh Paetzel rq->cqe_firstpart->valid = 0; 2042c2625e6eSJosh Paetzel cqe2->valid = 0; 2043c2625e6eSJosh Paetzel rq->cqe_firstpart = NULL; 2044c2625e6eSJosh Paetzel 2045c2625e6eSJosh Paetzel RING_GET(cq->ring, 1); 2046c2625e6eSJosh Paetzel num_cqes += 2; 2047c2625e6eSJosh Paetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2048c2625e6eSJosh Paetzel break; 2049c2625e6eSJosh Paetzel } 2050c2625e6eSJosh Paetzel 2051c2625e6eSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2052c2625e6eSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 2053c2625e6eSJosh Paetzel } 2054c2625e6eSJosh Paetzel oce_check_rx_bufs(sc, num_cqes, rq); 2055c2625e6eSJosh Paetzel exit_rq_handler_lro: 2056c2625e6eSJosh Paetzel UNLOCK(&rq->rx_lock); 2057c2625e6eSJosh Paetzel return 0; 2058c2625e6eSJosh Paetzel } 20592f345d8eSLuigi Rizzo 20602f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */ 20612f345d8eSLuigi Rizzo uint16_t 20622f345d8eSLuigi Rizzo oce_rq_handler(void *arg) 20632f345d8eSLuigi Rizzo { 20642f345d8eSLuigi Rizzo struct oce_rq *rq = (struct oce_rq *)arg; 20652f345d8eSLuigi Rizzo struct oce_cq *cq = rq->cq; 20662f345d8eSLuigi Rizzo POCE_SOFTC sc = rq->parent; 20672f345d8eSLuigi Rizzo struct oce_nic_rx_cqe *cqe; 2068c2625e6eSJosh Paetzel int num_cqes = 0; 20692f345d8eSLuigi Rizzo 2070c2625e6eSJosh Paetzel if(rq->islro) { 2071c2625e6eSJosh Paetzel oce_rq_handler_lro(arg); 2072c2625e6eSJosh Paetzel return 0; 2073c2625e6eSJosh Paetzel } 2074c2625e6eSJosh Paetzel LOCK(&rq->rx_lock); 20752f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 20762f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 20772f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 20782f345d8eSLuigi Rizzo while (cqe->u0.dw[2]) { 20792f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 20802f345d8eSLuigi Rizzo 20812f345d8eSLuigi Rizzo if (cqe->u0.s.error == 0) { 2082c2625e6eSJosh Paetzel oce_rx(rq, cqe); 20832f345d8eSLuigi Rizzo } else { 20842f345d8eSLuigi Rizzo rq->rx_stats.rxcp_err++; 2085c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 20862f345d8eSLuigi Rizzo /* Post L3/L4 errors to stack.*/ 2087c2625e6eSJosh Paetzel oce_rx(rq, cqe); 20882f345d8eSLuigi Rizzo } 20892f345d8eSLuigi Rizzo rq->rx_stats.rx_compl++; 20902f345d8eSLuigi Rizzo cqe->u0.dw[2] = 0; 20912f345d8eSLuigi Rizzo 2092ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 20932f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 20942f345d8eSLuigi Rizzo oce_rx_flush_lro(rq); 20952f345d8eSLuigi Rizzo } 2096ad512958SBjoern A. Zeeb #endif 20972f345d8eSLuigi Rizzo 20982f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 20992f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 21002f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 21012f345d8eSLuigi Rizzo cqe = 21022f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 21032f345d8eSLuigi Rizzo num_cqes++; 21042f345d8eSLuigi Rizzo if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 21052f345d8eSLuigi Rizzo break; 21062f345d8eSLuigi Rizzo } 21079bd3250aSLuigi Rizzo 2108ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 21092f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc)) 21102f345d8eSLuigi Rizzo oce_rx_flush_lro(rq); 2111ad512958SBjoern A. Zeeb #endif 21122f345d8eSLuigi Rizzo 2113c2625e6eSJosh Paetzel oce_check_rx_bufs(sc, num_cqes, rq); 2114c2625e6eSJosh Paetzel UNLOCK(&rq->rx_lock); 21152f345d8eSLuigi Rizzo return 0; 21162f345d8eSLuigi Rizzo 21172f345d8eSLuigi Rizzo } 21182f345d8eSLuigi Rizzo 21192f345d8eSLuigi Rizzo 21202f345d8eSLuigi Rizzo 21212f345d8eSLuigi Rizzo 21222f345d8eSLuigi Rizzo /***************************************************************************** 21232f345d8eSLuigi Rizzo * Helper function prototypes in this file * 21242f345d8eSLuigi Rizzo *****************************************************************************/ 21252f345d8eSLuigi Rizzo 21262f345d8eSLuigi Rizzo static int 21272f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc) 21282f345d8eSLuigi Rizzo { 21292f345d8eSLuigi Rizzo 21302f345d8eSLuigi Rizzo sc->ifp = if_alloc(IFT_ETHER); 21312f345d8eSLuigi Rizzo if (!sc->ifp) 21322f345d8eSLuigi Rizzo return ENOMEM; 21332f345d8eSLuigi Rizzo 21342f345d8eSLuigi Rizzo ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 21352f345d8eSLuigi Rizzo ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 21362f345d8eSLuigi Rizzo ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 21372f345d8eSLuigi Rizzo 21382f345d8eSLuigi Rizzo sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 21392f345d8eSLuigi Rizzo sc->ifp->if_ioctl = oce_ioctl; 21402f345d8eSLuigi Rizzo sc->ifp->if_start = oce_start; 21412f345d8eSLuigi Rizzo sc->ifp->if_init = oce_init; 21422f345d8eSLuigi Rizzo sc->ifp->if_mtu = ETHERMTU; 21432f345d8eSLuigi Rizzo sc->ifp->if_softc = sc; 21442f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 21452f345d8eSLuigi Rizzo sc->ifp->if_transmit = oce_multiq_start; 21462f345d8eSLuigi Rizzo sc->ifp->if_qflush = oce_multiq_flush; 21472f345d8eSLuigi Rizzo #endif 21482f345d8eSLuigi Rizzo 21492f345d8eSLuigi Rizzo if_initname(sc->ifp, 21502f345d8eSLuigi Rizzo device_get_name(sc->dev), device_get_unit(sc->dev)); 21512f345d8eSLuigi Rizzo 21522f345d8eSLuigi Rizzo sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 21532f345d8eSLuigi Rizzo IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 21542f345d8eSLuigi Rizzo IFQ_SET_READY(&sc->ifp->if_snd); 21552f345d8eSLuigi Rizzo 21562f345d8eSLuigi Rizzo sc->ifp->if_hwassist = OCE_IF_HWASSIST; 21572f345d8eSLuigi Rizzo sc->ifp->if_hwassist |= CSUM_TSO; 21582f345d8eSLuigi Rizzo sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 21592f345d8eSLuigi Rizzo 21602f345d8eSLuigi Rizzo sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 21612f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_HWCSUM; 21622f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 21639bd3250aSLuigi Rizzo 2164ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 2165ad512958SBjoern A. Zeeb sc->ifp->if_capabilities |= IFCAP_TSO; 21662f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_LRO; 21679bd3250aSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 2168ad512958SBjoern A. Zeeb #endif 21692f345d8eSLuigi Rizzo 21702f345d8eSLuigi Rizzo sc->ifp->if_capenable = sc->ifp->if_capabilities; 2171b245f96cSGleb Smirnoff sc->ifp->if_baudrate = IF_Gbps(10); 21722f345d8eSLuigi Rizzo 21735fbb6830SXin LI #if __FreeBSD_version >= 1000000 21749fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 21759fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomaxsegcount = OCE_MAX_TX_ELEMENTS; 21769fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomaxsegsize = 4096; 21775fbb6830SXin LI #endif 21785fbb6830SXin LI 21792f345d8eSLuigi Rizzo ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 21802f345d8eSLuigi Rizzo 21812f345d8eSLuigi Rizzo return 0; 21822f345d8eSLuigi Rizzo } 21832f345d8eSLuigi Rizzo 21842f345d8eSLuigi Rizzo 21852f345d8eSLuigi Rizzo static void 21862f345d8eSLuigi Rizzo oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 21872f345d8eSLuigi Rizzo { 21882f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 21892f345d8eSLuigi Rizzo 21902f345d8eSLuigi Rizzo if (ifp->if_softc != arg) 21912f345d8eSLuigi Rizzo return; 21922f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095)) 21932f345d8eSLuigi Rizzo return; 21942f345d8eSLuigi Rizzo 21952f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 1; 21962f345d8eSLuigi Rizzo sc->vlans_added++; 21975fbb6830SXin LI if (sc->vlans_added <= (sc->max_vlans + 1)) 21982f345d8eSLuigi Rizzo oce_vid_config(sc); 21992f345d8eSLuigi Rizzo } 22002f345d8eSLuigi Rizzo 22012f345d8eSLuigi Rizzo 22022f345d8eSLuigi Rizzo static void 22032f345d8eSLuigi Rizzo oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 22042f345d8eSLuigi Rizzo { 22052f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 22062f345d8eSLuigi Rizzo 22072f345d8eSLuigi Rizzo if (ifp->if_softc != arg) 22082f345d8eSLuigi Rizzo return; 22092f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095)) 22102f345d8eSLuigi Rizzo return; 22112f345d8eSLuigi Rizzo 22122f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 0; 22132f345d8eSLuigi Rizzo sc->vlans_added--; 22142f345d8eSLuigi Rizzo oce_vid_config(sc); 22152f345d8eSLuigi Rizzo } 22162f345d8eSLuigi Rizzo 22172f345d8eSLuigi Rizzo 22182f345d8eSLuigi Rizzo /* 22192f345d8eSLuigi Rizzo * A max of 64 vlans can be configured in BE. If the user configures 22202f345d8eSLuigi Rizzo * more, place the card in vlan promiscuous mode. 22212f345d8eSLuigi Rizzo */ 22222f345d8eSLuigi Rizzo static int 22232f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc) 22242f345d8eSLuigi Rizzo { 22252f345d8eSLuigi Rizzo struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 22262f345d8eSLuigi Rizzo uint16_t ntags = 0, i; 22272f345d8eSLuigi Rizzo int status = 0; 22282f345d8eSLuigi Rizzo 22292f345d8eSLuigi Rizzo if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 22302f345d8eSLuigi Rizzo (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 22312f345d8eSLuigi Rizzo for (i = 0; i < MAX_VLANS; i++) { 22322f345d8eSLuigi Rizzo if (sc->vlan_tag[i]) { 22332f345d8eSLuigi Rizzo vtags[ntags].vtag = i; 22342f345d8eSLuigi Rizzo ntags++; 22352f345d8eSLuigi Rizzo } 22362f345d8eSLuigi Rizzo } 22372f345d8eSLuigi Rizzo if (ntags) 22382f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id, 22392f345d8eSLuigi Rizzo vtags, ntags, 1, 0); 22402f345d8eSLuigi Rizzo } else 22412f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id, 22422f345d8eSLuigi Rizzo NULL, 0, 1, 1); 22432f345d8eSLuigi Rizzo return status; 22442f345d8eSLuigi Rizzo } 22452f345d8eSLuigi Rizzo 22462f345d8eSLuigi Rizzo 22472f345d8eSLuigi Rizzo static void 22482f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc) 22492f345d8eSLuigi Rizzo { 22502f345d8eSLuigi Rizzo uint32_t old_pmac_id = sc->pmac_id; 22512f345d8eSLuigi Rizzo int status = 0; 22522f345d8eSLuigi Rizzo 22532f345d8eSLuigi Rizzo 22542f345d8eSLuigi Rizzo status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 22552f345d8eSLuigi Rizzo sc->macaddr.size_of_struct); 22562f345d8eSLuigi Rizzo if (!status) 22572f345d8eSLuigi Rizzo return; 22582f345d8eSLuigi Rizzo 22592f345d8eSLuigi Rizzo status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 22602f345d8eSLuigi Rizzo sc->if_id, &sc->pmac_id); 22612f345d8eSLuigi Rizzo if (!status) { 22622f345d8eSLuigi Rizzo status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 22632f345d8eSLuigi Rizzo bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 22642f345d8eSLuigi Rizzo sc->macaddr.size_of_struct); 22652f345d8eSLuigi Rizzo } 22662f345d8eSLuigi Rizzo if (status) 22672f345d8eSLuigi Rizzo device_printf(sc->dev, "Failed update macaddress\n"); 22682f345d8eSLuigi Rizzo 22692f345d8eSLuigi Rizzo } 22702f345d8eSLuigi Rizzo 22712f345d8eSLuigi Rizzo 22722f345d8eSLuigi Rizzo static int 22732f345d8eSLuigi Rizzo oce_handle_passthrough(struct ifnet *ifp, caddr_t data) 22742f345d8eSLuigi Rizzo { 22752f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 22762f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data; 22772f345d8eSLuigi Rizzo int rc = ENXIO; 22782f345d8eSLuigi Rizzo char cookie[32] = {0}; 2279*541d96aaSBrooks Davis void *priv_data = ifr_data_get_ptr(ifr); 22802f345d8eSLuigi Rizzo void *ioctl_ptr; 22812f345d8eSLuigi Rizzo uint32_t req_size; 22822f345d8eSLuigi Rizzo struct mbx_hdr req; 22832f345d8eSLuigi Rizzo OCE_DMA_MEM dma_mem; 2284cdaba892SXin LI struct mbx_common_get_cntl_attr *fw_cmd; 22852f345d8eSLuigi Rizzo 22862f345d8eSLuigi Rizzo if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 22872f345d8eSLuigi Rizzo return EFAULT; 22882f345d8eSLuigi Rizzo 22892f345d8eSLuigi Rizzo if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 22902f345d8eSLuigi Rizzo return EINVAL; 22912f345d8eSLuigi Rizzo 22922f345d8eSLuigi Rizzo ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 22932f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 22942f345d8eSLuigi Rizzo return EFAULT; 22952f345d8eSLuigi Rizzo 22962f345d8eSLuigi Rizzo req_size = le32toh(req.u0.req.request_length); 22972f345d8eSLuigi Rizzo if (req_size > 65536) 22982f345d8eSLuigi Rizzo return EINVAL; 22992f345d8eSLuigi Rizzo 23002f345d8eSLuigi Rizzo req_size += sizeof(struct mbx_hdr); 23012f345d8eSLuigi Rizzo rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 23022f345d8eSLuigi Rizzo if (rc) 23032f345d8eSLuigi Rizzo return ENOMEM; 23042f345d8eSLuigi Rizzo 23052f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 23062f345d8eSLuigi Rizzo rc = EFAULT; 23072f345d8eSLuigi Rizzo goto dma_free; 23082f345d8eSLuigi Rizzo } 23092f345d8eSLuigi Rizzo 23102f345d8eSLuigi Rizzo rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 23112f345d8eSLuigi Rizzo if (rc) { 23122f345d8eSLuigi Rizzo rc = EIO; 23132f345d8eSLuigi Rizzo goto dma_free; 23142f345d8eSLuigi Rizzo } 23152f345d8eSLuigi Rizzo 23162f345d8eSLuigi Rizzo if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 23172f345d8eSLuigi Rizzo rc = EFAULT; 23182f345d8eSLuigi Rizzo 2319cdaba892SXin LI /* 2320cdaba892SXin LI firmware is filling all the attributes for this ioctl except 2321cdaba892SXin LI the driver version..so fill it 2322cdaba892SXin LI */ 2323cdaba892SXin LI if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) { 2324cdaba892SXin LI fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr; 2325cdaba892SXin LI strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str, 2326cdaba892SXin LI COMPONENT_REVISION, strlen(COMPONENT_REVISION)); 2327cdaba892SXin LI } 2328cdaba892SXin LI 23292f345d8eSLuigi Rizzo dma_free: 23302f345d8eSLuigi Rizzo oce_dma_free(sc, &dma_mem); 23312f345d8eSLuigi Rizzo return rc; 23322f345d8eSLuigi Rizzo 23332f345d8eSLuigi Rizzo } 23342f345d8eSLuigi Rizzo 2335cdaba892SXin LI static void 2336cdaba892SXin LI oce_eqd_set_periodic(POCE_SOFTC sc) 2337cdaba892SXin LI { 2338cdaba892SXin LI struct oce_set_eqd set_eqd[OCE_MAX_EQ]; 2339cdaba892SXin LI struct oce_aic_obj *aic; 2340cdaba892SXin LI struct oce_eq *eqo; 2341cdaba892SXin LI uint64_t now = 0, delta; 2342cdaba892SXin LI int eqd, i, num = 0; 2343c2625e6eSJosh Paetzel uint32_t tx_reqs = 0, rxpkts = 0, pps; 2344c2625e6eSJosh Paetzel struct oce_wq *wq; 2345c2625e6eSJosh Paetzel struct oce_rq *rq; 2346c2625e6eSJosh Paetzel 2347c2625e6eSJosh Paetzel #define ticks_to_msecs(t) (1000 * (t) / hz) 2348cdaba892SXin LI 2349cdaba892SXin LI for (i = 0 ; i < sc->neqs; i++) { 2350cdaba892SXin LI eqo = sc->eq[i]; 2351cdaba892SXin LI aic = &sc->aic_obj[i]; 2352cdaba892SXin LI /* When setting the static eq delay from the user space */ 2353cdaba892SXin LI if (!aic->enable) { 2354c2625e6eSJosh Paetzel if (aic->ticks) 2355c2625e6eSJosh Paetzel aic->ticks = 0; 2356cdaba892SXin LI eqd = aic->et_eqd; 2357cdaba892SXin LI goto modify_eqd; 2358cdaba892SXin LI } 2359cdaba892SXin LI 2360c2625e6eSJosh Paetzel rq = sc->rq[i]; 2361c2625e6eSJosh Paetzel rxpkts = rq->rx_stats.rx_pkts; 2362c2625e6eSJosh Paetzel wq = sc->wq[i]; 2363c2625e6eSJosh Paetzel tx_reqs = wq->tx_stats.tx_reqs; 2364cdaba892SXin LI now = ticks; 2365cdaba892SXin LI 2366c2625e6eSJosh Paetzel if (!aic->ticks || now < aic->ticks || 2367c2625e6eSJosh Paetzel rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) { 2368c2625e6eSJosh Paetzel aic->prev_rxpkts = rxpkts; 2369c2625e6eSJosh Paetzel aic->prev_txreqs = tx_reqs; 2370c2625e6eSJosh Paetzel aic->ticks = now; 2371c2625e6eSJosh Paetzel continue; 2372c2625e6eSJosh Paetzel } 2373cdaba892SXin LI 2374c2625e6eSJosh Paetzel delta = ticks_to_msecs(now - aic->ticks); 2375cdaba892SXin LI 2376c2625e6eSJosh Paetzel pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) + 2377c2625e6eSJosh Paetzel (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta); 2378c2625e6eSJosh Paetzel eqd = (pps / 15000) << 2; 2379c2625e6eSJosh Paetzel if (eqd < 8) 2380cdaba892SXin LI eqd = 0; 2381cdaba892SXin LI 2382cdaba892SXin LI /* Make sure that the eq delay is in the known range */ 2383cdaba892SXin LI eqd = min(eqd, aic->max_eqd); 2384cdaba892SXin LI eqd = max(eqd, aic->min_eqd); 2385cdaba892SXin LI 2386c2625e6eSJosh Paetzel aic->prev_rxpkts = rxpkts; 2387c2625e6eSJosh Paetzel aic->prev_txreqs = tx_reqs; 2388c2625e6eSJosh Paetzel aic->ticks = now; 2389c2625e6eSJosh Paetzel 2390cdaba892SXin LI modify_eqd: 2391cdaba892SXin LI if (eqd != aic->cur_eqd) { 2392cdaba892SXin LI set_eqd[num].delay_multiplier = (eqd * 65)/100; 2393cdaba892SXin LI set_eqd[num].eq_id = eqo->eq_id; 2394cdaba892SXin LI aic->cur_eqd = eqd; 2395cdaba892SXin LI num++; 2396cdaba892SXin LI } 2397cdaba892SXin LI } 2398cdaba892SXin LI 2399cdaba892SXin LI /* Is there atleast one eq that needs to be modified? */ 2400c2625e6eSJosh Paetzel for(i = 0; i < num; i += 8) { 2401c2625e6eSJosh Paetzel if((num - i) >=8 ) 2402c2625e6eSJosh Paetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8); 2403c2625e6eSJosh Paetzel else 2404c2625e6eSJosh Paetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i)); 2405c2625e6eSJosh Paetzel } 2406c2625e6eSJosh Paetzel 2407cdaba892SXin LI } 24082f345d8eSLuigi Rizzo 24095fbb6830SXin LI static void oce_detect_hw_error(POCE_SOFTC sc) 24105fbb6830SXin LI { 24115fbb6830SXin LI 24125fbb6830SXin LI uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0; 24135fbb6830SXin LI uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; 24145fbb6830SXin LI uint32_t i; 24155fbb6830SXin LI 24165fbb6830SXin LI if (sc->hw_error) 24175fbb6830SXin LI return; 24185fbb6830SXin LI 24195fbb6830SXin LI if (IS_XE201(sc)) { 24205fbb6830SXin LI sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET); 24215fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24225fbb6830SXin LI sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET); 24235fbb6830SXin LI sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET); 24245fbb6830SXin LI } 24255fbb6830SXin LI } else { 24265fbb6830SXin LI ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW); 24275fbb6830SXin LI ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH); 24285fbb6830SXin LI ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK); 24295fbb6830SXin LI ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK); 24305fbb6830SXin LI 24315fbb6830SXin LI ue_low = (ue_low & ~ue_low_mask); 24325fbb6830SXin LI ue_high = (ue_high & ~ue_high_mask); 24335fbb6830SXin LI } 24345fbb6830SXin LI 24355fbb6830SXin LI /* On certain platforms BE hardware can indicate spurious UEs. 24365fbb6830SXin LI * Allow the h/w to stop working completely in case of a real UE. 24375fbb6830SXin LI * Hence not setting the hw_error for UE detection. 24385fbb6830SXin LI */ 24395fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24405fbb6830SXin LI sc->hw_error = TRUE; 24415fbb6830SXin LI device_printf(sc->dev, "Error detected in the card\n"); 24425fbb6830SXin LI } 24435fbb6830SXin LI 24445fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24455fbb6830SXin LI device_printf(sc->dev, 24465fbb6830SXin LI "ERR: sliport status 0x%x\n", sliport_status); 24475fbb6830SXin LI device_printf(sc->dev, 24485fbb6830SXin LI "ERR: sliport error1 0x%x\n", sliport_err1); 24495fbb6830SXin LI device_printf(sc->dev, 24505fbb6830SXin LI "ERR: sliport error2 0x%x\n", sliport_err2); 24515fbb6830SXin LI } 24525fbb6830SXin LI 24535fbb6830SXin LI if (ue_low) { 24545fbb6830SXin LI for (i = 0; ue_low; ue_low >>= 1, i++) { 24555fbb6830SXin LI if (ue_low & 1) 24565fbb6830SXin LI device_printf(sc->dev, "UE: %s bit set\n", 24575fbb6830SXin LI ue_status_low_desc[i]); 24585fbb6830SXin LI } 24595fbb6830SXin LI } 24605fbb6830SXin LI 24615fbb6830SXin LI if (ue_high) { 24625fbb6830SXin LI for (i = 0; ue_high; ue_high >>= 1, i++) { 24635fbb6830SXin LI if (ue_high & 1) 24645fbb6830SXin LI device_printf(sc->dev, "UE: %s bit set\n", 24655fbb6830SXin LI ue_status_hi_desc[i]); 24665fbb6830SXin LI } 24675fbb6830SXin LI } 24685fbb6830SXin LI 24695fbb6830SXin LI } 24705fbb6830SXin LI 24715fbb6830SXin LI 24722f345d8eSLuigi Rizzo static void 24732f345d8eSLuigi Rizzo oce_local_timer(void *arg) 24742f345d8eSLuigi Rizzo { 24752f345d8eSLuigi Rizzo POCE_SOFTC sc = arg; 24762f345d8eSLuigi Rizzo int i = 0; 24772f345d8eSLuigi Rizzo 24785fbb6830SXin LI oce_detect_hw_error(sc); 24792f345d8eSLuigi Rizzo oce_refresh_nic_stats(sc); 24802f345d8eSLuigi Rizzo oce_refresh_queue_stats(sc); 24812f345d8eSLuigi Rizzo oce_mac_addr_set(sc); 24822f345d8eSLuigi Rizzo 24832f345d8eSLuigi Rizzo /* TX Watch Dog*/ 24842f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) 24852f345d8eSLuigi Rizzo oce_tx_restart(sc, sc->wq[i]); 24862f345d8eSLuigi Rizzo 2487cdaba892SXin LI /* calculate and set the eq delay for optimal interrupt rate */ 2488291a1934SXin LI if (IS_BE(sc) || IS_SH(sc)) 2489cdaba892SXin LI oce_eqd_set_periodic(sc); 2490cdaba892SXin LI 24912f345d8eSLuigi Rizzo callout_reset(&sc->timer, hz, oce_local_timer, sc); 24922f345d8eSLuigi Rizzo } 24932f345d8eSLuigi Rizzo 2494c2625e6eSJosh Paetzel static void 2495c2625e6eSJosh Paetzel oce_tx_compl_clean(POCE_SOFTC sc) 2496c2625e6eSJosh Paetzel { 2497c2625e6eSJosh Paetzel struct oce_wq *wq; 2498c2625e6eSJosh Paetzel int i = 0, timeo = 0, num_wqes = 0; 2499c2625e6eSJosh Paetzel int pending_txqs = sc->nwqs; 2500c2625e6eSJosh Paetzel 2501c2625e6eSJosh Paetzel /* Stop polling for compls when HW has been silent for 10ms or 2502c2625e6eSJosh Paetzel * hw_error or no outstanding completions expected 2503c2625e6eSJosh Paetzel */ 2504c2625e6eSJosh Paetzel do { 2505c2625e6eSJosh Paetzel pending_txqs = sc->nwqs; 2506c2625e6eSJosh Paetzel 2507c2625e6eSJosh Paetzel for_all_wq_queues(sc, wq, i) { 2508c2625e6eSJosh Paetzel num_wqes = oce_wq_handler(wq); 2509c2625e6eSJosh Paetzel 2510c2625e6eSJosh Paetzel if(num_wqes) 2511c2625e6eSJosh Paetzel timeo = 0; 2512c2625e6eSJosh Paetzel 2513c2625e6eSJosh Paetzel if(!wq->ring->num_used) 2514c2625e6eSJosh Paetzel pending_txqs--; 2515c2625e6eSJosh Paetzel } 2516c2625e6eSJosh Paetzel 2517c2625e6eSJosh Paetzel if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error) 2518c2625e6eSJosh Paetzel break; 2519c2625e6eSJosh Paetzel 2520c2625e6eSJosh Paetzel DELAY(1000); 2521c2625e6eSJosh Paetzel } while (TRUE); 2522c2625e6eSJosh Paetzel 2523c2625e6eSJosh Paetzel for_all_wq_queues(sc, wq, i) { 2524c2625e6eSJosh Paetzel while(wq->ring->num_used) { 2525c2625e6eSJosh Paetzel LOCK(&wq->tx_compl_lock); 2526c2625e6eSJosh Paetzel oce_process_tx_completion(wq); 2527c2625e6eSJosh Paetzel UNLOCK(&wq->tx_compl_lock); 2528c2625e6eSJosh Paetzel } 2529c2625e6eSJosh Paetzel } 2530c2625e6eSJosh Paetzel 2531c2625e6eSJosh Paetzel } 25322f345d8eSLuigi Rizzo 2533beb0f7e7SJosh Paetzel /* NOTE : This should only be called holding 2534beb0f7e7SJosh Paetzel * DEVICE_LOCK. 2535beb0f7e7SJosh Paetzel */ 25362f345d8eSLuigi Rizzo static void 25372f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc) 25382f345d8eSLuigi Rizzo { 2539c2625e6eSJosh Paetzel int i; 25402f345d8eSLuigi Rizzo struct oce_rq *rq; 25412f345d8eSLuigi Rizzo struct oce_wq *wq; 25422f345d8eSLuigi Rizzo struct oce_eq *eq; 25432f345d8eSLuigi Rizzo 25442f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 25452f345d8eSLuigi Rizzo 2546c2625e6eSJosh Paetzel oce_tx_compl_clean(sc); 25472f345d8eSLuigi Rizzo 25482f345d8eSLuigi Rizzo /* Stop intrs and finish any bottom halves pending */ 25492f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 25502f345d8eSLuigi Rizzo 2551cdaba892SXin LI /* Since taskqueue_drain takes a Gaint Lock, We should not acquire 2552beb0f7e7SJosh Paetzel any other lock. So unlock device lock and require after 2553beb0f7e7SJosh Paetzel completing taskqueue_drain. 2554beb0f7e7SJosh Paetzel */ 2555beb0f7e7SJosh Paetzel UNLOCK(&sc->dev_lock); 25562f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) { 25572f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) { 25582f345d8eSLuigi Rizzo taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 25592f345d8eSLuigi Rizzo } 25602f345d8eSLuigi Rizzo } 2561beb0f7e7SJosh Paetzel LOCK(&sc->dev_lock); 25622f345d8eSLuigi Rizzo 25632f345d8eSLuigi Rizzo /* Delete RX queue in card with flush param */ 25642f345d8eSLuigi Rizzo oce_stop_rx(sc); 25652f345d8eSLuigi Rizzo 25662f345d8eSLuigi Rizzo /* Invalidate any pending cq and eq entries*/ 25672f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) 25682f345d8eSLuigi Rizzo oce_drain_eq(eq); 25692f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) 25702f345d8eSLuigi Rizzo oce_drain_rq_cq(rq); 25712f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) 25722f345d8eSLuigi Rizzo oce_drain_wq_cq(wq); 25732f345d8eSLuigi Rizzo 25742f345d8eSLuigi Rizzo /* But still we need to get MCC aync events. 25752f345d8eSLuigi Rizzo So enable intrs and also arm first EQ 25762f345d8eSLuigi Rizzo */ 25772f345d8eSLuigi Rizzo oce_hw_intr_enable(sc); 25782f345d8eSLuigi Rizzo oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 25792f345d8eSLuigi Rizzo 25802f345d8eSLuigi Rizzo DELAY(10); 25812f345d8eSLuigi Rizzo } 25822f345d8eSLuigi Rizzo 25832f345d8eSLuigi Rizzo 25842f345d8eSLuigi Rizzo static void 25852f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc) 25862f345d8eSLuigi Rizzo { 25872f345d8eSLuigi Rizzo struct oce_eq *eq; 25882f345d8eSLuigi Rizzo struct oce_rq *rq; 25892f345d8eSLuigi Rizzo struct oce_wq *wq; 25902f345d8eSLuigi Rizzo int i, rc = 0; 25912f345d8eSLuigi Rizzo 25922f345d8eSLuigi Rizzo sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 25932f345d8eSLuigi Rizzo 25942f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 25952f345d8eSLuigi Rizzo 25962f345d8eSLuigi Rizzo oce_start_rx(sc); 25972f345d8eSLuigi Rizzo 25982f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 25992f345d8eSLuigi Rizzo rc = oce_start_rq(rq); 26002f345d8eSLuigi Rizzo if (rc) 26012f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start RX\n"); 26022f345d8eSLuigi Rizzo } 26032f345d8eSLuigi Rizzo 26042f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) { 26052f345d8eSLuigi Rizzo rc = oce_start_wq(wq); 26062f345d8eSLuigi Rizzo if (rc) 26072f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start TX\n"); 26082f345d8eSLuigi Rizzo } 26092f345d8eSLuigi Rizzo 26102f345d8eSLuigi Rizzo 26112f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) 26122f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 26132f345d8eSLuigi Rizzo 26142f345d8eSLuigi Rizzo oce_hw_intr_enable(sc); 26152f345d8eSLuigi Rizzo 26162f345d8eSLuigi Rizzo } 26172f345d8eSLuigi Rizzo 26189bd3250aSLuigi Rizzo static void 26199bd3250aSLuigi Rizzo process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe) 26202f345d8eSLuigi Rizzo { 26219bd3250aSLuigi Rizzo /* Update Link status */ 26222f345d8eSLuigi Rizzo if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 26232f345d8eSLuigi Rizzo ASYNC_EVENT_LINK_UP) { 26242f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_UP; 26252f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_UP); 26262f345d8eSLuigi Rizzo } else { 26272f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_DOWN; 26282f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_DOWN); 26292f345d8eSLuigi Rizzo } 26309bd3250aSLuigi Rizzo } 26319bd3250aSLuigi Rizzo 26329bd3250aSLuigi Rizzo 2633c2625e6eSJosh Paetzel static void oce_async_grp5_osbmc_process(POCE_SOFTC sc, 2634c2625e6eSJosh Paetzel struct oce_async_evt_grp5_os2bmc *evt) 2635c2625e6eSJosh Paetzel { 2636c2625e6eSJosh Paetzel DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc)); 2637c2625e6eSJosh Paetzel if (evt->u.s.mgmt_enable) 2638c2625e6eSJosh Paetzel sc->flags |= OCE_FLAGS_OS2BMC; 2639c2625e6eSJosh Paetzel else 2640c2625e6eSJosh Paetzel return; 2641c2625e6eSJosh Paetzel 2642c2625e6eSJosh Paetzel sc->bmc_filt_mask = evt->u.s.arp_filter; 2643c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1); 2644c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2); 2645c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3); 2646c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4); 2647c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5); 2648c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6); 2649c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7); 2650c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8); 2651c2625e6eSJosh Paetzel } 2652c2625e6eSJosh Paetzel 2653c2625e6eSJosh Paetzel 2654c2625e6eSJosh Paetzel static void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe) 2655c2625e6eSJosh Paetzel { 2656c2625e6eSJosh Paetzel struct oce_async_event_grp5_pvid_state *gcqe; 2657c2625e6eSJosh Paetzel struct oce_async_evt_grp5_os2bmc *bmccqe; 2658c2625e6eSJosh Paetzel 2659c2625e6eSJosh Paetzel switch (cqe->u0.s.async_type) { 2660c2625e6eSJosh Paetzel case ASYNC_EVENT_PVID_STATE: 2661c2625e6eSJosh Paetzel /* GRP5 PVID */ 2662c2625e6eSJosh Paetzel gcqe = (struct oce_async_event_grp5_pvid_state *)cqe; 2663c2625e6eSJosh Paetzel if (gcqe->enabled) 2664c2625e6eSJosh Paetzel sc->pvid = gcqe->tag & VLAN_VID_MASK; 2665c2625e6eSJosh Paetzel else 2666c2625e6eSJosh Paetzel sc->pvid = 0; 2667c2625e6eSJosh Paetzel break; 2668c2625e6eSJosh Paetzel case ASYNC_EVENT_OS2BMC: 2669c2625e6eSJosh Paetzel bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe; 2670c2625e6eSJosh Paetzel oce_async_grp5_osbmc_process(sc, bmccqe); 2671c2625e6eSJosh Paetzel break; 2672c2625e6eSJosh Paetzel default: 2673c2625e6eSJosh Paetzel break; 2674c2625e6eSJosh Paetzel } 2675c2625e6eSJosh Paetzel } 2676c2625e6eSJosh Paetzel 26779bd3250aSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */ 26789bd3250aSLuigi Rizzo uint16_t 26799bd3250aSLuigi Rizzo oce_mq_handler(void *arg) 26809bd3250aSLuigi Rizzo { 26819bd3250aSLuigi Rizzo struct oce_mq *mq = (struct oce_mq *)arg; 26829bd3250aSLuigi Rizzo POCE_SOFTC sc = mq->parent; 26839bd3250aSLuigi Rizzo struct oce_cq *cq = mq->cq; 26849bd3250aSLuigi Rizzo int num_cqes = 0, evt_type = 0, optype = 0; 26859bd3250aSLuigi Rizzo struct oce_mq_cqe *cqe; 26869bd3250aSLuigi Rizzo struct oce_async_cqe_link_state *acqe; 2687cdaba892SXin LI struct oce_async_event_qnq *dbgcqe; 26889bd3250aSLuigi Rizzo 26899bd3250aSLuigi Rizzo 26909bd3250aSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 26919bd3250aSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 26929bd3250aSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 26939bd3250aSLuigi Rizzo 26949bd3250aSLuigi Rizzo while (cqe->u0.dw[3]) { 26959bd3250aSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 26969bd3250aSLuigi Rizzo if (cqe->u0.s.async_event) { 26979bd3250aSLuigi Rizzo evt_type = cqe->u0.s.event_type; 26989bd3250aSLuigi Rizzo optype = cqe->u0.s.async_type; 26999bd3250aSLuigi Rizzo if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) { 27009bd3250aSLuigi Rizzo /* Link status evt */ 27019bd3250aSLuigi Rizzo acqe = (struct oce_async_cqe_link_state *)cqe; 27029bd3250aSLuigi Rizzo process_link_state(sc, acqe); 2703c2625e6eSJosh Paetzel } else if (evt_type == ASYNC_EVENT_GRP5) { 2704c2625e6eSJosh Paetzel oce_process_grp5_events(sc, cqe); 2705c2625e6eSJosh Paetzel } else if (evt_type == ASYNC_EVENT_CODE_DEBUG && 2706cdaba892SXin LI optype == ASYNC_EVENT_DEBUG_QNQ) { 2707c2625e6eSJosh Paetzel dbgcqe = (struct oce_async_event_qnq *)cqe; 2708cdaba892SXin LI if(dbgcqe->valid) 2709cdaba892SXin LI sc->qnqid = dbgcqe->vlan_tag; 2710cdaba892SXin LI sc->qnq_debug_event = TRUE; 2711cdaba892SXin LI } 27122f345d8eSLuigi Rizzo } 27132f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 27142f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 27152f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 27162f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 27172f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 27182f345d8eSLuigi Rizzo num_cqes++; 27192f345d8eSLuigi Rizzo } 27202f345d8eSLuigi Rizzo 27212f345d8eSLuigi Rizzo if (num_cqes) 27222f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 27232f345d8eSLuigi Rizzo 27242f345d8eSLuigi Rizzo return 0; 27252f345d8eSLuigi Rizzo } 27262f345d8eSLuigi Rizzo 27272f345d8eSLuigi Rizzo 27282f345d8eSLuigi Rizzo static void 27292f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc) 27302f345d8eSLuigi Rizzo { 27312f345d8eSLuigi Rizzo /* Check if it is FLEX machine. Is so dont use RSS */ 27322f345d8eSLuigi Rizzo if ((sc->function_mode & FNM_FLEX10_MODE) || 27339bd3250aSLuigi Rizzo (sc->function_mode & FNM_UMC_MODE) || 27349bd3250aSLuigi Rizzo (sc->function_mode & FNM_VNIC_MODE) || 2735291a1934SXin LI (!is_rss_enabled(sc)) || 2736a4f734b4SXin LI IS_BE2(sc)) { 27372f345d8eSLuigi Rizzo sc->nrqs = 1; 27382f345d8eSLuigi Rizzo sc->nwqs = 1; 27395fbb6830SXin LI } else { 27405fbb6830SXin LI sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 27415fbb6830SXin LI sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs); 27422f345d8eSLuigi Rizzo } 2743a4f734b4SXin LI 2744a4f734b4SXin LI if (IS_BE2(sc) && is_rss_enabled(sc)) 2745a4f734b4SXin LI sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 27462f345d8eSLuigi Rizzo } 27472f345d8eSLuigi Rizzo 27482f345d8eSLuigi Rizzo 27492f345d8eSLuigi Rizzo static void 27502f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc) 27512f345d8eSLuigi Rizzo { 2752291a1934SXin LI if (is_rss_enabled(sc)) { 27532f345d8eSLuigi Rizzo sc->nrqs = sc->intr_count + 1; 27542f345d8eSLuigi Rizzo sc->nwqs = sc->intr_count; 27552f345d8eSLuigi Rizzo } else { 27562f345d8eSLuigi Rizzo sc->nrqs = 1; 27572f345d8eSLuigi Rizzo sc->nwqs = 1; 27582f345d8eSLuigi Rizzo } 2759a4f734b4SXin LI 2760a4f734b4SXin LI if (IS_BE2(sc)) 2761a4f734b4SXin LI sc->nwqs = 1; 27622f345d8eSLuigi Rizzo } 27632f345d8eSLuigi Rizzo 2764cdaba892SXin LI static int 2765cdaba892SXin LI oce_check_ipv6_ext_hdr(struct mbuf *m) 2766cdaba892SXin LI { 2767cdaba892SXin LI struct ether_header *eh = mtod(m, struct ether_header *); 2768cdaba892SXin LI caddr_t m_datatemp = m->m_data; 2769cdaba892SXin LI 2770cdaba892SXin LI if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 2771cdaba892SXin LI m->m_data += sizeof(struct ether_header); 2772cdaba892SXin LI struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 2773cdaba892SXin LI 2774cdaba892SXin LI if((ip6->ip6_nxt != IPPROTO_TCP) && \ 2775cdaba892SXin LI (ip6->ip6_nxt != IPPROTO_UDP)){ 2776cdaba892SXin LI struct ip6_ext *ip6e = NULL; 2777cdaba892SXin LI m->m_data += sizeof(struct ip6_hdr); 2778cdaba892SXin LI 2779cdaba892SXin LI ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *); 2780cdaba892SXin LI if(ip6e->ip6e_len == 0xff) { 2781cdaba892SXin LI m->m_data = m_datatemp; 2782cdaba892SXin LI return TRUE; 2783cdaba892SXin LI } 2784cdaba892SXin LI } 2785cdaba892SXin LI m->m_data = m_datatemp; 2786cdaba892SXin LI } 2787cdaba892SXin LI return FALSE; 2788cdaba892SXin LI } 2789cdaba892SXin LI 2790cdaba892SXin LI static int 2791cdaba892SXin LI is_be3_a1(POCE_SOFTC sc) 2792cdaba892SXin LI { 2793cdaba892SXin LI if((sc->flags & OCE_FLAGS_BE3) && ((sc->asic_revision & 0xFF) < 2)) { 2794cdaba892SXin LI return TRUE; 2795cdaba892SXin LI } 2796cdaba892SXin LI return FALSE; 2797cdaba892SXin LI } 2798cdaba892SXin LI 2799cdaba892SXin LI static struct mbuf * 2800cdaba892SXin LI oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete) 2801cdaba892SXin LI { 2802cdaba892SXin LI uint16_t vlan_tag = 0; 2803cdaba892SXin LI 2804cdaba892SXin LI if(!M_WRITABLE(m)) 2805cdaba892SXin LI return NULL; 2806cdaba892SXin LI 2807cdaba892SXin LI /* Embed vlan tag in the packet if it is not part of it */ 2808cdaba892SXin LI if(m->m_flags & M_VLANTAG) { 2809cdaba892SXin LI vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 2810cdaba892SXin LI m->m_flags &= ~M_VLANTAG; 2811cdaba892SXin LI } 2812cdaba892SXin LI 2813cdaba892SXin LI /* if UMC, ignore vlan tag insertion and instead insert pvid */ 2814cdaba892SXin LI if(sc->pvid) { 2815cdaba892SXin LI if(!vlan_tag) 2816cdaba892SXin LI vlan_tag = sc->pvid; 2817c2625e6eSJosh Paetzel if (complete) 2818cdaba892SXin LI *complete = FALSE; 2819cdaba892SXin LI } 2820cdaba892SXin LI 2821cdaba892SXin LI if(vlan_tag) { 2822cdaba892SXin LI m = ether_vlanencap(m, vlan_tag); 2823cdaba892SXin LI } 2824cdaba892SXin LI 2825cdaba892SXin LI if(sc->qnqid) { 2826cdaba892SXin LI m = ether_vlanencap(m, sc->qnqid); 2827c2625e6eSJosh Paetzel 2828c2625e6eSJosh Paetzel if (complete) 2829cdaba892SXin LI *complete = FALSE; 2830cdaba892SXin LI } 2831cdaba892SXin LI return m; 2832cdaba892SXin LI } 2833cdaba892SXin LI 2834cdaba892SXin LI static int 2835cdaba892SXin LI oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m) 2836cdaba892SXin LI { 2837cdaba892SXin LI if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \ 2838cdaba892SXin LI oce_check_ipv6_ext_hdr(m)) { 2839cdaba892SXin LI return TRUE; 2840cdaba892SXin LI } 2841cdaba892SXin LI return FALSE; 2842cdaba892SXin LI } 2843291a1934SXin LI 2844291a1934SXin LI static void 2845291a1934SXin LI oce_get_config(POCE_SOFTC sc) 2846291a1934SXin LI { 2847291a1934SXin LI int rc = 0; 2848291a1934SXin LI uint32_t max_rss = 0; 2849291a1934SXin LI 2850291a1934SXin LI if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native)) 2851291a1934SXin LI max_rss = OCE_LEGACY_MODE_RSS; 2852291a1934SXin LI else 2853291a1934SXin LI max_rss = OCE_MAX_RSS; 2854291a1934SXin LI 2855291a1934SXin LI if (!IS_BE(sc)) { 2856b41206d8SXin LI rc = oce_get_profile_config(sc, max_rss); 2857291a1934SXin LI if (rc) { 2858291a1934SXin LI sc->nwqs = OCE_MAX_WQ; 2859291a1934SXin LI sc->nrssqs = max_rss; 2860291a1934SXin LI sc->nrqs = sc->nrssqs + 1; 2861291a1934SXin LI } 2862291a1934SXin LI } 2863b41206d8SXin LI else { /* For BE3 don't rely on fw for determining the resources */ 2864291a1934SXin LI sc->nrssqs = max_rss; 2865291a1934SXin LI sc->nrqs = sc->nrssqs + 1; 2866291a1934SXin LI sc->nwqs = OCE_MAX_WQ; 2867b41206d8SXin LI sc->max_vlans = MAX_VLANFILTER_SIZE; 2868291a1934SXin LI } 2869291a1934SXin LI } 2870c2625e6eSJosh Paetzel 2871c2625e6eSJosh Paetzel static void 2872c2625e6eSJosh Paetzel oce_rdma_close(void) 2873c2625e6eSJosh Paetzel { 2874c2625e6eSJosh Paetzel if (oce_rdma_if != NULL) { 2875c2625e6eSJosh Paetzel oce_rdma_if = NULL; 2876c2625e6eSJosh Paetzel } 2877c2625e6eSJosh Paetzel } 2878c2625e6eSJosh Paetzel 2879c2625e6eSJosh Paetzel static void 2880c2625e6eSJosh Paetzel oce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr) 2881c2625e6eSJosh Paetzel { 2882c2625e6eSJosh Paetzel memcpy(macaddr, sc->macaddr.mac_addr, 6); 2883c2625e6eSJosh Paetzel } 2884c2625e6eSJosh Paetzel 2885c2625e6eSJosh Paetzel int 2886c2625e6eSJosh Paetzel oce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if) 2887c2625e6eSJosh Paetzel { 2888c2625e6eSJosh Paetzel POCE_SOFTC sc; 2889c2625e6eSJosh Paetzel struct oce_dev_info di; 2890c2625e6eSJosh Paetzel int i; 2891c2625e6eSJosh Paetzel 2892c2625e6eSJosh Paetzel if ((rdma_info == NULL) || (rdma_if == NULL)) { 2893c2625e6eSJosh Paetzel return -EINVAL; 2894c2625e6eSJosh Paetzel } 2895c2625e6eSJosh Paetzel 2896c2625e6eSJosh Paetzel if ((rdma_info->size != OCE_RDMA_INFO_SIZE) || 2897c2625e6eSJosh Paetzel (rdma_if->size != OCE_RDMA_IF_SIZE)) { 2898c2625e6eSJosh Paetzel return -ENXIO; 2899c2625e6eSJosh Paetzel } 2900c2625e6eSJosh Paetzel 2901c2625e6eSJosh Paetzel rdma_info->close = oce_rdma_close; 2902c2625e6eSJosh Paetzel rdma_info->mbox_post = oce_mbox_post; 2903c2625e6eSJosh Paetzel rdma_info->common_req_hdr_init = mbx_common_req_hdr_init; 2904c2625e6eSJosh Paetzel rdma_info->get_mac_addr = oce_get_mac_addr; 2905c2625e6eSJosh Paetzel 2906c2625e6eSJosh Paetzel oce_rdma_if = rdma_if; 2907c2625e6eSJosh Paetzel 2908c2625e6eSJosh Paetzel sc = softc_head; 2909c2625e6eSJosh Paetzel while (sc != NULL) { 2910c2625e6eSJosh Paetzel if (oce_rdma_if->announce != NULL) { 2911c2625e6eSJosh Paetzel memset(&di, 0, sizeof(di)); 2912c2625e6eSJosh Paetzel di.dev = sc->dev; 2913c2625e6eSJosh Paetzel di.softc = sc; 2914c2625e6eSJosh Paetzel di.ifp = sc->ifp; 2915c2625e6eSJosh Paetzel di.db_bhandle = sc->db_bhandle; 2916c2625e6eSJosh Paetzel di.db_btag = sc->db_btag; 2917c2625e6eSJosh Paetzel di.db_page_size = 4096; 2918c2625e6eSJosh Paetzel if (sc->flags & OCE_FLAGS_USING_MSIX) { 2919c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_MSIX; 2920c2625e6eSJosh Paetzel } else if (sc->flags & OCE_FLAGS_USING_MSI) { 2921c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_MSI; 2922c2625e6eSJosh Paetzel } else { 2923c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_INTX; 2924c2625e6eSJosh Paetzel } 2925c2625e6eSJosh Paetzel di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk 2926c2625e6eSJosh Paetzel if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) { 2927c2625e6eSJosh Paetzel di.msix.num_vectors = sc->intr_count + sc->roce_intr_count; 2928c2625e6eSJosh Paetzel di.msix.start_vector = sc->intr_count; 2929c2625e6eSJosh Paetzel for (i=0; i<di.msix.num_vectors; i++) { 2930c2625e6eSJosh Paetzel di.msix.vector_list[i] = sc->intrs[i].vector; 2931c2625e6eSJosh Paetzel } 2932c2625e6eSJosh Paetzel } else { 2933c2625e6eSJosh Paetzel } 2934c2625e6eSJosh Paetzel memcpy(di.mac_addr, sc->macaddr.mac_addr, 6); 2935c2625e6eSJosh Paetzel di.vendor_id = pci_get_vendor(sc->dev); 2936c2625e6eSJosh Paetzel di.dev_id = pci_get_device(sc->dev); 2937c2625e6eSJosh Paetzel 2938c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 2939c2625e6eSJosh Paetzel di.flags |= OCE_RDMA_INFO_RDMA_SUPPORTED; 2940c2625e6eSJosh Paetzel } 2941c2625e6eSJosh Paetzel 2942c2625e6eSJosh Paetzel rdma_if->announce(&di); 2943c2625e6eSJosh Paetzel sc = sc->next; 2944c2625e6eSJosh Paetzel } 2945c2625e6eSJosh Paetzel } 2946c2625e6eSJosh Paetzel 2947c2625e6eSJosh Paetzel return 0; 2948c2625e6eSJosh Paetzel } 2949c2625e6eSJosh Paetzel 2950c2625e6eSJosh Paetzel static void 2951c2625e6eSJosh Paetzel oce_read_env_variables( POCE_SOFTC sc ) 2952c2625e6eSJosh Paetzel { 2953c2625e6eSJosh Paetzel char *value = NULL; 2954c2625e6eSJosh Paetzel int rc = 0; 2955c2625e6eSJosh Paetzel 2956c2625e6eSJosh Paetzel /* read if user wants to enable hwlro or swlro */ 2957c2625e6eSJosh Paetzel //value = getenv("oce_enable_hwlro"); 2958c2625e6eSJosh Paetzel if(value && IS_SH(sc)) { 2959c2625e6eSJosh Paetzel sc->enable_hwlro = strtol(value, NULL, 10); 2960c2625e6eSJosh Paetzel if(sc->enable_hwlro) { 2961c2625e6eSJosh Paetzel rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL); 2962c2625e6eSJosh Paetzel if(rc) { 2963c2625e6eSJosh Paetzel device_printf(sc->dev, "no hardware lro support\n"); 2964c2625e6eSJosh Paetzel device_printf(sc->dev, "software lro enabled\n"); 2965c2625e6eSJosh Paetzel sc->enable_hwlro = 0; 2966c2625e6eSJosh Paetzel }else { 2967c2625e6eSJosh Paetzel device_printf(sc->dev, "hardware lro enabled\n"); 2968c2625e6eSJosh Paetzel oce_max_rsp_handled = 32; 2969c2625e6eSJosh Paetzel } 2970c2625e6eSJosh Paetzel }else { 2971c2625e6eSJosh Paetzel device_printf(sc->dev, "software lro enabled\n"); 2972c2625e6eSJosh Paetzel } 2973c2625e6eSJosh Paetzel }else { 2974c2625e6eSJosh Paetzel sc->enable_hwlro = 0; 2975c2625e6eSJosh Paetzel } 2976c2625e6eSJosh Paetzel 2977c2625e6eSJosh Paetzel /* read mbuf size */ 2978c2625e6eSJosh Paetzel //value = getenv("oce_rq_buf_size"); 2979c2625e6eSJosh Paetzel if(value && IS_SH(sc)) { 2980c2625e6eSJosh Paetzel oce_rq_buf_size = strtol(value, NULL, 10); 2981c2625e6eSJosh Paetzel switch(oce_rq_buf_size) { 2982c2625e6eSJosh Paetzel case 2048: 2983c2625e6eSJosh Paetzel case 4096: 2984c2625e6eSJosh Paetzel case 9216: 2985c2625e6eSJosh Paetzel case 16384: 2986c2625e6eSJosh Paetzel break; 2987c2625e6eSJosh Paetzel 2988c2625e6eSJosh Paetzel default: 2989c2625e6eSJosh Paetzel device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n"); 2990c2625e6eSJosh Paetzel oce_rq_buf_size = 2048; 2991c2625e6eSJosh Paetzel } 2992c2625e6eSJosh Paetzel } 2993c2625e6eSJosh Paetzel 2994c2625e6eSJosh Paetzel return; 2995c2625e6eSJosh Paetzel } 2996