12f345d8eSLuigi Rizzo /*- 2291a1934SXin LI * Copyright (C) 2013 Emulex 32f345d8eSLuigi Rizzo * All rights reserved. 42f345d8eSLuigi Rizzo * 52f345d8eSLuigi Rizzo * Redistribution and use in source and binary forms, with or without 62f345d8eSLuigi Rizzo * modification, are permitted provided that the following conditions are met: 72f345d8eSLuigi Rizzo * 82f345d8eSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright notice, 92f345d8eSLuigi Rizzo * this list of conditions and the following disclaimer. 102f345d8eSLuigi Rizzo * 112f345d8eSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright 122f345d8eSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the 132f345d8eSLuigi Rizzo * documentation and/or other materials provided with the distribution. 142f345d8eSLuigi Rizzo * 152f345d8eSLuigi Rizzo * 3. Neither the name of the Emulex Corporation nor the names of its 162f345d8eSLuigi Rizzo * contributors may be used to endorse or promote products derived from 172f345d8eSLuigi Rizzo * this software without specific prior written permission. 182f345d8eSLuigi Rizzo * 192f345d8eSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 202f345d8eSLuigi Rizzo * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 212f345d8eSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 222f345d8eSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 232f345d8eSLuigi Rizzo * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 242f345d8eSLuigi Rizzo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 252f345d8eSLuigi Rizzo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 262f345d8eSLuigi Rizzo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 272f345d8eSLuigi Rizzo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 282f345d8eSLuigi Rizzo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 292f345d8eSLuigi Rizzo * POSSIBILITY OF SUCH DAMAGE. 302f345d8eSLuigi Rizzo * 312f345d8eSLuigi Rizzo * Contact Information: 322f345d8eSLuigi Rizzo * freebsd-drivers@emulex.com 332f345d8eSLuigi Rizzo * 342f345d8eSLuigi Rizzo * Emulex 352f345d8eSLuigi Rizzo * 3333 Susan Street 362f345d8eSLuigi Rizzo * Costa Mesa, CA 92626 372f345d8eSLuigi Rizzo */ 382f345d8eSLuigi Rizzo 392f345d8eSLuigi Rizzo /* $FreeBSD$ */ 402f345d8eSLuigi Rizzo 41ad512958SBjoern A. Zeeb #include "opt_inet6.h" 42ad512958SBjoern A. Zeeb #include "opt_inet.h" 43ad512958SBjoern A. Zeeb 442f345d8eSLuigi Rizzo #include "oce_if.h" 45*764c812dSJosh Paetzel #include "oce_user.h" 46*764c812dSJosh Paetzel 47*764c812dSJosh Paetzel #define is_tso_pkt(m) (m->m_pkthdr.csum_flags & CSUM_TSO) 482f345d8eSLuigi Rizzo 495fbb6830SXin LI /* UE Status Low CSR */ 505fbb6830SXin LI static char *ue_status_low_desc[] = { 515fbb6830SXin LI "CEV", 525fbb6830SXin LI "CTX", 535fbb6830SXin LI "DBUF", 545fbb6830SXin LI "ERX", 555fbb6830SXin LI "Host", 565fbb6830SXin LI "MPU", 575fbb6830SXin LI "NDMA", 585fbb6830SXin LI "PTC ", 595fbb6830SXin LI "RDMA ", 605fbb6830SXin LI "RXF ", 615fbb6830SXin LI "RXIPS ", 625fbb6830SXin LI "RXULP0 ", 635fbb6830SXin LI "RXULP1 ", 645fbb6830SXin LI "RXULP2 ", 655fbb6830SXin LI "TIM ", 665fbb6830SXin LI "TPOST ", 675fbb6830SXin LI "TPRE ", 685fbb6830SXin LI "TXIPS ", 695fbb6830SXin LI "TXULP0 ", 705fbb6830SXin LI "TXULP1 ", 715fbb6830SXin LI "UC ", 725fbb6830SXin LI "WDMA ", 735fbb6830SXin LI "TXULP2 ", 745fbb6830SXin LI "HOST1 ", 755fbb6830SXin LI "P0_OB_LINK ", 765fbb6830SXin LI "P1_OB_LINK ", 775fbb6830SXin LI "HOST_GPIO ", 785fbb6830SXin LI "MBOX ", 795fbb6830SXin LI "AXGMAC0", 805fbb6830SXin LI "AXGMAC1", 815fbb6830SXin LI "JTAG", 825fbb6830SXin LI "MPU_INTPEND" 835fbb6830SXin LI }; 845fbb6830SXin LI 855fbb6830SXin LI /* UE Status High CSR */ 865fbb6830SXin LI static char *ue_status_hi_desc[] = { 875fbb6830SXin LI "LPCMEMHOST", 885fbb6830SXin LI "MGMT_MAC", 895fbb6830SXin LI "PCS0ONLINE", 905fbb6830SXin LI "MPU_IRAM", 915fbb6830SXin LI "PCS1ONLINE", 925fbb6830SXin LI "PCTL0", 935fbb6830SXin LI "PCTL1", 945fbb6830SXin LI "PMEM", 955fbb6830SXin LI "RR", 965fbb6830SXin LI "TXPB", 975fbb6830SXin LI "RXPP", 985fbb6830SXin LI "XAUI", 995fbb6830SXin LI "TXP", 1005fbb6830SXin LI "ARM", 1015fbb6830SXin LI "IPC", 1025fbb6830SXin LI "HOST2", 1035fbb6830SXin LI "HOST3", 1045fbb6830SXin LI "HOST4", 1055fbb6830SXin LI "HOST5", 1065fbb6830SXin LI "HOST6", 1075fbb6830SXin LI "HOST7", 1085fbb6830SXin LI "HOST8", 1095fbb6830SXin LI "HOST9", 1105fbb6830SXin LI "NETC", 1115fbb6830SXin LI "Unknown", 1125fbb6830SXin LI "Unknown", 1135fbb6830SXin LI "Unknown", 1145fbb6830SXin LI "Unknown", 1155fbb6830SXin LI "Unknown", 1165fbb6830SXin LI "Unknown", 1175fbb6830SXin LI "Unknown", 1185fbb6830SXin LI "Unknown" 1195fbb6830SXin LI }; 1205fbb6830SXin LI 121*764c812dSJosh Paetzel struct oce_common_cqe_info{ 122*764c812dSJosh Paetzel uint8_t vtp:1; 123*764c812dSJosh Paetzel uint8_t l4_cksum_pass:1; 124*764c812dSJosh Paetzel uint8_t ip_cksum_pass:1; 125*764c812dSJosh Paetzel uint8_t ipv6_frame:1; 126*764c812dSJosh Paetzel uint8_t qnq:1; 127*764c812dSJosh Paetzel uint8_t rsvd:3; 128*764c812dSJosh Paetzel uint8_t num_frags; 129*764c812dSJosh Paetzel uint16_t pkt_size; 130*764c812dSJosh Paetzel uint16_t vtag; 131*764c812dSJosh Paetzel }; 132*764c812dSJosh Paetzel 1332f345d8eSLuigi Rizzo 1342f345d8eSLuigi Rizzo /* Driver entry points prototypes */ 1352f345d8eSLuigi Rizzo static int oce_probe(device_t dev); 1362f345d8eSLuigi Rizzo static int oce_attach(device_t dev); 1372f345d8eSLuigi Rizzo static int oce_detach(device_t dev); 1382f345d8eSLuigi Rizzo static int oce_shutdown(device_t dev); 1392f345d8eSLuigi Rizzo static int oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 1402f345d8eSLuigi Rizzo static void oce_init(void *xsc); 1412f345d8eSLuigi Rizzo static int oce_multiq_start(struct ifnet *ifp, struct mbuf *m); 1422f345d8eSLuigi Rizzo static void oce_multiq_flush(struct ifnet *ifp); 1432f345d8eSLuigi Rizzo 1442f345d8eSLuigi Rizzo /* Driver interrupt routines protypes */ 1452f345d8eSLuigi Rizzo static void oce_intr(void *arg, int pending); 1462f345d8eSLuigi Rizzo static int oce_setup_intr(POCE_SOFTC sc); 1472f345d8eSLuigi Rizzo static int oce_fast_isr(void *arg); 1482f345d8eSLuigi Rizzo static int oce_alloc_intr(POCE_SOFTC sc, int vector, 1492f345d8eSLuigi Rizzo void (*isr) (void *arg, int pending)); 1502f345d8eSLuigi Rizzo 1512f345d8eSLuigi Rizzo /* Media callbacks prototypes */ 1522f345d8eSLuigi Rizzo static void oce_media_status(struct ifnet *ifp, struct ifmediareq *req); 1532f345d8eSLuigi Rizzo static int oce_media_change(struct ifnet *ifp); 1542f345d8eSLuigi Rizzo 1552f345d8eSLuigi Rizzo /* Transmit routines prototypes */ 1562f345d8eSLuigi Rizzo static int oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index); 1572f345d8eSLuigi Rizzo static void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq); 158*764c812dSJosh Paetzel static void oce_process_tx_completion(struct oce_wq *wq); 1592f345d8eSLuigi Rizzo static int oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, 1602f345d8eSLuigi Rizzo struct oce_wq *wq); 1612f345d8eSLuigi Rizzo 1622f345d8eSLuigi Rizzo /* Receive routines prototypes */ 1632f345d8eSLuigi Rizzo static int oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 1642f345d8eSLuigi Rizzo static int oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe); 165*764c812dSJosh Paetzel static void oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe); 166*764c812dSJosh Paetzel static void oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq); 167*764c812dSJosh Paetzel static uint16_t oce_rq_handler_lro(void *arg); 168*764c812dSJosh Paetzel static void oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2); 169*764c812dSJosh Paetzel static void oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2); 170*764c812dSJosh Paetzel static void oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m); 1712f345d8eSLuigi Rizzo 1722f345d8eSLuigi Rizzo /* Helper function prototypes in this file */ 1732f345d8eSLuigi Rizzo static int oce_attach_ifp(POCE_SOFTC sc); 1742f345d8eSLuigi Rizzo static void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 1752f345d8eSLuigi Rizzo static void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag); 1762f345d8eSLuigi Rizzo static int oce_vid_config(POCE_SOFTC sc); 1772f345d8eSLuigi Rizzo static void oce_mac_addr_set(POCE_SOFTC sc); 1782f345d8eSLuigi Rizzo static int oce_handle_passthrough(struct ifnet *ifp, caddr_t data); 1792f345d8eSLuigi Rizzo static void oce_local_timer(void *arg); 1802f345d8eSLuigi Rizzo static void oce_if_deactivate(POCE_SOFTC sc); 1812f345d8eSLuigi Rizzo static void oce_if_activate(POCE_SOFTC sc); 1822f345d8eSLuigi Rizzo static void setup_max_queues_want(POCE_SOFTC sc); 1832f345d8eSLuigi Rizzo static void update_queues_got(POCE_SOFTC sc); 1849bd3250aSLuigi Rizzo static void process_link_state(POCE_SOFTC sc, 1859bd3250aSLuigi Rizzo struct oce_async_cqe_link_state *acqe); 186cdaba892SXin LI static int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m); 187291a1934SXin LI static void oce_get_config(POCE_SOFTC sc); 188cdaba892SXin LI static struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete); 189*764c812dSJosh Paetzel static void oce_read_env_variables(POCE_SOFTC sc); 190*764c812dSJosh Paetzel 1919bd3250aSLuigi Rizzo 1929bd3250aSLuigi Rizzo /* IP specific */ 1939bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET) 1949bd3250aSLuigi Rizzo static int oce_init_lro(POCE_SOFTC sc); 1959bd3250aSLuigi Rizzo static struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp); 1969bd3250aSLuigi Rizzo #endif 1972f345d8eSLuigi Rizzo 1982f345d8eSLuigi Rizzo static device_method_t oce_dispatch[] = { 1992f345d8eSLuigi Rizzo DEVMETHOD(device_probe, oce_probe), 2002f345d8eSLuigi Rizzo DEVMETHOD(device_attach, oce_attach), 2012f345d8eSLuigi Rizzo DEVMETHOD(device_detach, oce_detach), 2022f345d8eSLuigi Rizzo DEVMETHOD(device_shutdown, oce_shutdown), 20361bfd867SSofian Brabez 20461bfd867SSofian Brabez DEVMETHOD_END 2052f345d8eSLuigi Rizzo }; 2062f345d8eSLuigi Rizzo 2072f345d8eSLuigi Rizzo static driver_t oce_driver = { 2082f345d8eSLuigi Rizzo "oce", 2092f345d8eSLuigi Rizzo oce_dispatch, 2102f345d8eSLuigi Rizzo sizeof(OCE_SOFTC) 2112f345d8eSLuigi Rizzo }; 2122f345d8eSLuigi Rizzo static devclass_t oce_devclass; 2132f345d8eSLuigi Rizzo 2142f345d8eSLuigi Rizzo 2152f345d8eSLuigi Rizzo DRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0); 2162f345d8eSLuigi Rizzo MODULE_DEPEND(oce, pci, 1, 1, 1); 2172f345d8eSLuigi Rizzo MODULE_DEPEND(oce, ether, 1, 1, 1); 2182f345d8eSLuigi Rizzo MODULE_VERSION(oce, 1); 2192f345d8eSLuigi Rizzo 2202f345d8eSLuigi Rizzo 2212f345d8eSLuigi Rizzo /* global vars */ 2222f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"}; 2232f345d8eSLuigi Rizzo 2242f345d8eSLuigi Rizzo /* Module capabilites and parameters */ 2252f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED; 2262f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS; 227*764c812dSJosh Paetzel uint32_t oce_rq_buf_size = 2048; 2282f345d8eSLuigi Rizzo 2292f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled); 2302f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss); 2312f345d8eSLuigi Rizzo 2322f345d8eSLuigi Rizzo 2332f345d8eSLuigi Rizzo /* Supported devices table */ 2342f345d8eSLuigi Rizzo static uint32_t supportedDevices[] = { 2352f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2, 2362f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3, 2372f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3, 2382f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201, 2392f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF, 240291a1934SXin LI (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH 2412f345d8eSLuigi Rizzo }; 2422f345d8eSLuigi Rizzo 243*764c812dSJosh Paetzel POCE_SOFTC softc_head = NULL; 244*764c812dSJosh Paetzel POCE_SOFTC softc_tail = NULL; 2452f345d8eSLuigi Rizzo 246*764c812dSJosh Paetzel struct oce_rdma_if *oce_rdma_if = NULL; 2472f345d8eSLuigi Rizzo 2482f345d8eSLuigi Rizzo /***************************************************************************** 2492f345d8eSLuigi Rizzo * Driver entry points functions * 2502f345d8eSLuigi Rizzo *****************************************************************************/ 2512f345d8eSLuigi Rizzo 2522f345d8eSLuigi Rizzo static int 2532f345d8eSLuigi Rizzo oce_probe(device_t dev) 2542f345d8eSLuigi Rizzo { 2559bd3250aSLuigi Rizzo uint16_t vendor = 0; 2569bd3250aSLuigi Rizzo uint16_t device = 0; 2579bd3250aSLuigi Rizzo int i = 0; 2589bd3250aSLuigi Rizzo char str[256] = {0}; 2592f345d8eSLuigi Rizzo POCE_SOFTC sc; 2602f345d8eSLuigi Rizzo 2612f345d8eSLuigi Rizzo sc = device_get_softc(dev); 2622f345d8eSLuigi Rizzo bzero(sc, sizeof(OCE_SOFTC)); 2632f345d8eSLuigi Rizzo sc->dev = dev; 2642f345d8eSLuigi Rizzo 2652f345d8eSLuigi Rizzo vendor = pci_get_vendor(dev); 2662f345d8eSLuigi Rizzo device = pci_get_device(dev); 2672f345d8eSLuigi Rizzo 2689bd3250aSLuigi Rizzo for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) { 2692f345d8eSLuigi Rizzo if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) { 2702f345d8eSLuigi Rizzo if (device == (supportedDevices[i] & 0xffff)) { 2719bd3250aSLuigi Rizzo sprintf(str, "%s:%s", "Emulex CNA NIC function", 2722f345d8eSLuigi Rizzo component_revision); 2732f345d8eSLuigi Rizzo device_set_desc_copy(dev, str); 2742f345d8eSLuigi Rizzo 2752f345d8eSLuigi Rizzo switch (device) { 2762f345d8eSLuigi Rizzo case PCI_PRODUCT_BE2: 2772f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE2; 2782f345d8eSLuigi Rizzo break; 2792f345d8eSLuigi Rizzo case PCI_PRODUCT_BE3: 2802f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE3; 2812f345d8eSLuigi Rizzo break; 2822f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201: 2832f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201_VF: 2842f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_XE201; 2852f345d8eSLuigi Rizzo break; 286291a1934SXin LI case PCI_PRODUCT_SH: 287291a1934SXin LI sc->flags |= OCE_FLAGS_SH; 288291a1934SXin LI break; 2892f345d8eSLuigi Rizzo default: 2902f345d8eSLuigi Rizzo return ENXIO; 2912f345d8eSLuigi Rizzo } 2922f345d8eSLuigi Rizzo return BUS_PROBE_DEFAULT; 2932f345d8eSLuigi Rizzo } 2942f345d8eSLuigi Rizzo } 2952f345d8eSLuigi Rizzo } 2962f345d8eSLuigi Rizzo 2972f345d8eSLuigi Rizzo return ENXIO; 2982f345d8eSLuigi Rizzo } 2992f345d8eSLuigi Rizzo 3002f345d8eSLuigi Rizzo 3012f345d8eSLuigi Rizzo static int 3022f345d8eSLuigi Rizzo oce_attach(device_t dev) 3032f345d8eSLuigi Rizzo { 3042f345d8eSLuigi Rizzo POCE_SOFTC sc; 3052f345d8eSLuigi Rizzo int rc = 0; 3062f345d8eSLuigi Rizzo 3072f345d8eSLuigi Rizzo sc = device_get_softc(dev); 3082f345d8eSLuigi Rizzo 3092f345d8eSLuigi Rizzo rc = oce_hw_pci_alloc(sc); 3102f345d8eSLuigi Rizzo if (rc) 3112f345d8eSLuigi Rizzo return rc; 3122f345d8eSLuigi Rizzo 3132f345d8eSLuigi Rizzo sc->tx_ring_size = OCE_TX_RING_SIZE; 3142f345d8eSLuigi Rizzo sc->rx_ring_size = OCE_RX_RING_SIZE; 315*764c812dSJosh Paetzel /* receive fragment size should be multiple of 2K */ 316*764c812dSJosh Paetzel sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048); 3172f345d8eSLuigi Rizzo sc->flow_control = OCE_DEFAULT_FLOW_CONTROL; 3182f345d8eSLuigi Rizzo sc->promisc = OCE_DEFAULT_PROMISCUOUS; 3192f345d8eSLuigi Rizzo 3202f345d8eSLuigi Rizzo LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock"); 3212f345d8eSLuigi Rizzo LOCK_CREATE(&sc->dev_lock, "Device_lock"); 3222f345d8eSLuigi Rizzo 3232f345d8eSLuigi Rizzo /* initialise the hardware */ 3242f345d8eSLuigi Rizzo rc = oce_hw_init(sc); 3252f345d8eSLuigi Rizzo if (rc) 3262f345d8eSLuigi Rizzo goto pci_res_free; 3272f345d8eSLuigi Rizzo 328*764c812dSJosh Paetzel oce_read_env_variables(sc); 329*764c812dSJosh Paetzel 330291a1934SXin LI oce_get_config(sc); 331291a1934SXin LI 3322f345d8eSLuigi Rizzo setup_max_queues_want(sc); 3332f345d8eSLuigi Rizzo 3342f345d8eSLuigi Rizzo rc = oce_setup_intr(sc); 3352f345d8eSLuigi Rizzo if (rc) 3362f345d8eSLuigi Rizzo goto mbox_free; 3372f345d8eSLuigi Rizzo 3382f345d8eSLuigi Rizzo rc = oce_queue_init_all(sc); 3392f345d8eSLuigi Rizzo if (rc) 3402f345d8eSLuigi Rizzo goto intr_free; 3412f345d8eSLuigi Rizzo 3422f345d8eSLuigi Rizzo rc = oce_attach_ifp(sc); 3432f345d8eSLuigi Rizzo if (rc) 3442f345d8eSLuigi Rizzo goto queues_free; 3452f345d8eSLuigi Rizzo 346ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 3472f345d8eSLuigi Rizzo rc = oce_init_lro(sc); 3482f345d8eSLuigi Rizzo if (rc) 3492f345d8eSLuigi Rizzo goto ifp_free; 350ad512958SBjoern A. Zeeb #endif 3512f345d8eSLuigi Rizzo 3522f345d8eSLuigi Rizzo rc = oce_hw_start(sc); 3532f345d8eSLuigi Rizzo if (rc) 354db702c59SEitan Adler goto lro_free; 3552f345d8eSLuigi Rizzo 3562f345d8eSLuigi Rizzo sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 3572f345d8eSLuigi Rizzo oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST); 3582f345d8eSLuigi Rizzo sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 3592f345d8eSLuigi Rizzo oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST); 3602f345d8eSLuigi Rizzo 3612f345d8eSLuigi Rizzo rc = oce_stats_init(sc); 3622f345d8eSLuigi Rizzo if (rc) 3632f345d8eSLuigi Rizzo goto vlan_free; 3642f345d8eSLuigi Rizzo 3652f345d8eSLuigi Rizzo oce_add_sysctls(sc); 3662f345d8eSLuigi Rizzo 367*764c812dSJosh Paetzel callout_init(&sc->timer, CALLOUT_MPSAFE); 3682f345d8eSLuigi Rizzo rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc); 3692f345d8eSLuigi Rizzo if (rc) 3702f345d8eSLuigi Rizzo goto stats_free; 3712f345d8eSLuigi Rizzo 372*764c812dSJosh Paetzel sc->next =NULL; 373*764c812dSJosh Paetzel if (softc_tail != NULL) { 374*764c812dSJosh Paetzel softc_tail->next = sc; 375*764c812dSJosh Paetzel } else { 376*764c812dSJosh Paetzel softc_head = sc; 377*764c812dSJosh Paetzel } 378*764c812dSJosh Paetzel softc_tail = sc; 379*764c812dSJosh Paetzel 3802f345d8eSLuigi Rizzo return 0; 3812f345d8eSLuigi Rizzo 3822f345d8eSLuigi Rizzo stats_free: 3832f345d8eSLuigi Rizzo callout_drain(&sc->timer); 3842f345d8eSLuigi Rizzo oce_stats_free(sc); 3852f345d8eSLuigi Rizzo vlan_free: 3862f345d8eSLuigi Rizzo if (sc->vlan_attach) 3872f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 3882f345d8eSLuigi Rizzo if (sc->vlan_detach) 3892f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 3902f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 3912f345d8eSLuigi Rizzo lro_free: 392ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 3932f345d8eSLuigi Rizzo oce_free_lro(sc); 3942f345d8eSLuigi Rizzo ifp_free: 395ad512958SBjoern A. Zeeb #endif 3962f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp); 3972f345d8eSLuigi Rizzo if_free(sc->ifp); 3982f345d8eSLuigi Rizzo queues_free: 3992f345d8eSLuigi Rizzo oce_queue_release_all(sc); 4002f345d8eSLuigi Rizzo intr_free: 4012f345d8eSLuigi Rizzo oce_intr_free(sc); 4022f345d8eSLuigi Rizzo mbox_free: 4032f345d8eSLuigi Rizzo oce_dma_free(sc, &sc->bsmbx); 4042f345d8eSLuigi Rizzo pci_res_free: 4052f345d8eSLuigi Rizzo oce_hw_pci_free(sc); 4062f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->dev_lock); 4072f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->bmbx_lock); 4082f345d8eSLuigi Rizzo return rc; 4092f345d8eSLuigi Rizzo 4102f345d8eSLuigi Rizzo } 4112f345d8eSLuigi Rizzo 4122f345d8eSLuigi Rizzo 4132f345d8eSLuigi Rizzo static int 4142f345d8eSLuigi Rizzo oce_detach(device_t dev) 4152f345d8eSLuigi Rizzo { 4162f345d8eSLuigi Rizzo POCE_SOFTC sc = device_get_softc(dev); 417*764c812dSJosh Paetzel POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL; 418*764c812dSJosh Paetzel 419*764c812dSJosh Paetzel poce_sc_tmp = softc_head; 420*764c812dSJosh Paetzel ppoce_sc_tmp1 = &softc_head; 421*764c812dSJosh Paetzel while (poce_sc_tmp != NULL) { 422*764c812dSJosh Paetzel if (poce_sc_tmp == sc) { 423*764c812dSJosh Paetzel *ppoce_sc_tmp1 = sc->next; 424*764c812dSJosh Paetzel if (sc->next == NULL) { 425*764c812dSJosh Paetzel softc_tail = poce_sc_tmp2; 426*764c812dSJosh Paetzel } 427*764c812dSJosh Paetzel break; 428*764c812dSJosh Paetzel } 429*764c812dSJosh Paetzel poce_sc_tmp2 = poce_sc_tmp; 430*764c812dSJosh Paetzel ppoce_sc_tmp1 = &poce_sc_tmp->next; 431*764c812dSJosh Paetzel poce_sc_tmp = poce_sc_tmp->next; 432*764c812dSJosh Paetzel } 4332f345d8eSLuigi Rizzo 4342f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 4352f345d8eSLuigi Rizzo oce_if_deactivate(sc); 4362f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 4372f345d8eSLuigi Rizzo 4382f345d8eSLuigi Rizzo callout_drain(&sc->timer); 4392f345d8eSLuigi Rizzo 4402f345d8eSLuigi Rizzo if (sc->vlan_attach != NULL) 4412f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); 4422f345d8eSLuigi Rizzo if (sc->vlan_detach != NULL) 4432f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); 4442f345d8eSLuigi Rizzo 4452f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp); 4462f345d8eSLuigi Rizzo 4472f345d8eSLuigi Rizzo if_free(sc->ifp); 4482f345d8eSLuigi Rizzo 4492f345d8eSLuigi Rizzo oce_hw_shutdown(sc); 4502f345d8eSLuigi Rizzo 4512f345d8eSLuigi Rizzo bus_generic_detach(dev); 4522f345d8eSLuigi Rizzo 4532f345d8eSLuigi Rizzo return 0; 4542f345d8eSLuigi Rizzo } 4552f345d8eSLuigi Rizzo 4562f345d8eSLuigi Rizzo 4572f345d8eSLuigi Rizzo static int 4582f345d8eSLuigi Rizzo oce_shutdown(device_t dev) 4592f345d8eSLuigi Rizzo { 4602f345d8eSLuigi Rizzo int rc; 4612f345d8eSLuigi Rizzo 4622f345d8eSLuigi Rizzo rc = oce_detach(dev); 4632f345d8eSLuigi Rizzo 4642f345d8eSLuigi Rizzo return rc; 4652f345d8eSLuigi Rizzo } 4662f345d8eSLuigi Rizzo 4672f345d8eSLuigi Rizzo 4682f345d8eSLuigi Rizzo static int 4692f345d8eSLuigi Rizzo oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 4702f345d8eSLuigi Rizzo { 4712f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data; 4722f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 4732f345d8eSLuigi Rizzo int rc = 0; 4742f345d8eSLuigi Rizzo uint32_t u; 4752f345d8eSLuigi Rizzo 4762f345d8eSLuigi Rizzo switch (command) { 4772f345d8eSLuigi Rizzo 4782f345d8eSLuigi Rizzo case SIOCGIFMEDIA: 4792f345d8eSLuigi Rizzo rc = ifmedia_ioctl(ifp, ifr, &sc->media, command); 4802f345d8eSLuigi Rizzo break; 4812f345d8eSLuigi Rizzo 4822f345d8eSLuigi Rizzo case SIOCSIFMTU: 4832f345d8eSLuigi Rizzo if (ifr->ifr_mtu > OCE_MAX_MTU) 4842f345d8eSLuigi Rizzo rc = EINVAL; 4852f345d8eSLuigi Rizzo else 4862f345d8eSLuigi Rizzo ifp->if_mtu = ifr->ifr_mtu; 4872f345d8eSLuigi Rizzo break; 4882f345d8eSLuigi Rizzo 4892f345d8eSLuigi Rizzo case SIOCSIFFLAGS: 4902f345d8eSLuigi Rizzo if (ifp->if_flags & IFF_UP) { 4912f345d8eSLuigi Rizzo if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 4922f345d8eSLuigi Rizzo sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 4932f345d8eSLuigi Rizzo oce_init(sc); 4942f345d8eSLuigi Rizzo } 4952f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Up\n"); 4962f345d8eSLuigi Rizzo } else { 4972f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 4982f345d8eSLuigi Rizzo 4992f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= 5002f345d8eSLuigi Rizzo ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 5012f345d8eSLuigi Rizzo oce_if_deactivate(sc); 5022f345d8eSLuigi Rizzo 5032f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 5042f345d8eSLuigi Rizzo 5052f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Down\n"); 5062f345d8eSLuigi Rizzo } 5072f345d8eSLuigi Rizzo 5082f345d8eSLuigi Rizzo if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) { 5095fbb6830SXin LI if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1)))) 5102f345d8eSLuigi Rizzo sc->promisc = TRUE; 5112f345d8eSLuigi Rizzo } else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) { 5125fbb6830SXin LI if (!oce_rxf_set_promiscuous(sc, 0)) 5132f345d8eSLuigi Rizzo sc->promisc = FALSE; 5142f345d8eSLuigi Rizzo } 5152f345d8eSLuigi Rizzo 5162f345d8eSLuigi Rizzo break; 5172f345d8eSLuigi Rizzo 5182f345d8eSLuigi Rizzo case SIOCADDMULTI: 5192f345d8eSLuigi Rizzo case SIOCDELMULTI: 5202f345d8eSLuigi Rizzo rc = oce_hw_update_multicast(sc); 5212f345d8eSLuigi Rizzo if (rc) 5222f345d8eSLuigi Rizzo device_printf(sc->dev, 5232f345d8eSLuigi Rizzo "Update multicast address failed\n"); 5242f345d8eSLuigi Rizzo break; 5252f345d8eSLuigi Rizzo 5262f345d8eSLuigi Rizzo case SIOCSIFCAP: 5272f345d8eSLuigi Rizzo u = ifr->ifr_reqcap ^ ifp->if_capenable; 5282f345d8eSLuigi Rizzo 5292f345d8eSLuigi Rizzo if (u & IFCAP_TXCSUM) { 5302f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_TXCSUM; 5312f345d8eSLuigi Rizzo ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 5322f345d8eSLuigi Rizzo 5332f345d8eSLuigi Rizzo if (IFCAP_TSO & ifp->if_capenable && 5342f345d8eSLuigi Rizzo !(IFCAP_TXCSUM & ifp->if_capenable)) { 5352f345d8eSLuigi Rizzo ifp->if_capenable &= ~IFCAP_TSO; 5362f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5372f345d8eSLuigi Rizzo if_printf(ifp, 5382f345d8eSLuigi Rizzo "TSO disabled due to -txcsum.\n"); 5392f345d8eSLuigi Rizzo } 5402f345d8eSLuigi Rizzo } 5412f345d8eSLuigi Rizzo 5422f345d8eSLuigi Rizzo if (u & IFCAP_RXCSUM) 5432f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_RXCSUM; 5442f345d8eSLuigi Rizzo 5452f345d8eSLuigi Rizzo if (u & IFCAP_TSO4) { 5462f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_TSO4; 5472f345d8eSLuigi Rizzo 5482f345d8eSLuigi Rizzo if (IFCAP_TSO & ifp->if_capenable) { 5492f345d8eSLuigi Rizzo if (IFCAP_TXCSUM & ifp->if_capenable) 5502f345d8eSLuigi Rizzo ifp->if_hwassist |= CSUM_TSO; 5512f345d8eSLuigi Rizzo else { 5522f345d8eSLuigi Rizzo ifp->if_capenable &= ~IFCAP_TSO; 5532f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5542f345d8eSLuigi Rizzo if_printf(ifp, 5552f345d8eSLuigi Rizzo "Enable txcsum first.\n"); 5562f345d8eSLuigi Rizzo rc = EAGAIN; 5572f345d8eSLuigi Rizzo } 5582f345d8eSLuigi Rizzo } else 5592f345d8eSLuigi Rizzo ifp->if_hwassist &= ~CSUM_TSO; 5602f345d8eSLuigi Rizzo } 5612f345d8eSLuigi Rizzo 5622f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWTAGGING) 5632f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 5642f345d8eSLuigi Rizzo 5652f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWFILTER) { 5662f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; 5672f345d8eSLuigi Rizzo oce_vid_config(sc); 5682f345d8eSLuigi Rizzo } 569ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 570*764c812dSJosh Paetzel if (u & IFCAP_LRO) { 5712f345d8eSLuigi Rizzo ifp->if_capenable ^= IFCAP_LRO; 572*764c812dSJosh Paetzel if(sc->enable_hwlro) { 573*764c812dSJosh Paetzel if(ifp->if_capenable & IFCAP_LRO) { 574*764c812dSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 1); 575*764c812dSJosh Paetzel }else { 576*764c812dSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 0); 577*764c812dSJosh Paetzel } 578*764c812dSJosh Paetzel } 579*764c812dSJosh Paetzel } 580ad512958SBjoern A. Zeeb #endif 5812f345d8eSLuigi Rizzo 5822f345d8eSLuigi Rizzo break; 5832f345d8eSLuigi Rizzo 5842f345d8eSLuigi Rizzo case SIOCGPRIVATE_0: 5852f345d8eSLuigi Rizzo rc = oce_handle_passthrough(ifp, data); 5862f345d8eSLuigi Rizzo break; 5872f345d8eSLuigi Rizzo default: 5882f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data); 5892f345d8eSLuigi Rizzo break; 5902f345d8eSLuigi Rizzo } 5912f345d8eSLuigi Rizzo 5922f345d8eSLuigi Rizzo return rc; 5932f345d8eSLuigi Rizzo } 5942f345d8eSLuigi Rizzo 5952f345d8eSLuigi Rizzo 5962f345d8eSLuigi Rizzo static void 5972f345d8eSLuigi Rizzo oce_init(void *arg) 5982f345d8eSLuigi Rizzo { 5992f345d8eSLuigi Rizzo POCE_SOFTC sc = arg; 6002f345d8eSLuigi Rizzo 6012f345d8eSLuigi Rizzo LOCK(&sc->dev_lock); 6022f345d8eSLuigi Rizzo 6032f345d8eSLuigi Rizzo if (sc->ifp->if_flags & IFF_UP) { 6042f345d8eSLuigi Rizzo oce_if_deactivate(sc); 6052f345d8eSLuigi Rizzo oce_if_activate(sc); 6062f345d8eSLuigi Rizzo } 6072f345d8eSLuigi Rizzo 6082f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock); 6092f345d8eSLuigi Rizzo 6102f345d8eSLuigi Rizzo } 6112f345d8eSLuigi Rizzo 6122f345d8eSLuigi Rizzo 6132f345d8eSLuigi Rizzo static int 6142f345d8eSLuigi Rizzo oce_multiq_start(struct ifnet *ifp, struct mbuf *m) 6152f345d8eSLuigi Rizzo { 6162f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 6172f345d8eSLuigi Rizzo struct oce_wq *wq = NULL; 6182f345d8eSLuigi Rizzo int queue_index = 0; 6192f345d8eSLuigi Rizzo int status = 0; 6202f345d8eSLuigi Rizzo 621*764c812dSJosh Paetzel if (!sc->link_status) 622*764c812dSJosh Paetzel return ENXIO; 623*764c812dSJosh Paetzel 624c2529042SHans Petter Selasky if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 6252f345d8eSLuigi Rizzo queue_index = m->m_pkthdr.flowid % sc->nwqs; 6262f345d8eSLuigi Rizzo 6272f345d8eSLuigi Rizzo wq = sc->wq[queue_index]; 6282f345d8eSLuigi Rizzo 629291a1934SXin LI LOCK(&wq->tx_lock); 6302f345d8eSLuigi Rizzo status = oce_multiq_transmit(ifp, m, wq); 6312f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 632291a1934SXin LI 6332f345d8eSLuigi Rizzo return status; 6342f345d8eSLuigi Rizzo 6352f345d8eSLuigi Rizzo } 6362f345d8eSLuigi Rizzo 6372f345d8eSLuigi Rizzo 6382f345d8eSLuigi Rizzo static void 6392f345d8eSLuigi Rizzo oce_multiq_flush(struct ifnet *ifp) 6402f345d8eSLuigi Rizzo { 6412f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 6422f345d8eSLuigi Rizzo struct mbuf *m; 6432f345d8eSLuigi Rizzo int i = 0; 6442f345d8eSLuigi Rizzo 6452f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) { 6462f345d8eSLuigi Rizzo while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL) 6472f345d8eSLuigi Rizzo m_freem(m); 6482f345d8eSLuigi Rizzo } 6492f345d8eSLuigi Rizzo if_qflush(ifp); 6502f345d8eSLuigi Rizzo } 6512f345d8eSLuigi Rizzo 6522f345d8eSLuigi Rizzo 6532f345d8eSLuigi Rizzo 6542f345d8eSLuigi Rizzo /***************************************************************************** 6552f345d8eSLuigi Rizzo * Driver interrupt routines functions * 6562f345d8eSLuigi Rizzo *****************************************************************************/ 6572f345d8eSLuigi Rizzo 6582f345d8eSLuigi Rizzo static void 6592f345d8eSLuigi Rizzo oce_intr(void *arg, int pending) 6602f345d8eSLuigi Rizzo { 6612f345d8eSLuigi Rizzo 6622f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 6632f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc; 6642f345d8eSLuigi Rizzo struct oce_eq *eq = ii->eq; 6652f345d8eSLuigi Rizzo struct oce_eqe *eqe; 6662f345d8eSLuigi Rizzo struct oce_cq *cq = NULL; 6672f345d8eSLuigi Rizzo int i, num_eqes = 0; 6682f345d8eSLuigi Rizzo 6692f345d8eSLuigi Rizzo 6702f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 6712f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 6722f345d8eSLuigi Rizzo do { 6732f345d8eSLuigi Rizzo eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe); 6742f345d8eSLuigi Rizzo if (eqe->evnt == 0) 6752f345d8eSLuigi Rizzo break; 6762f345d8eSLuigi Rizzo eqe->evnt = 0; 6772f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map, 6782f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE); 6792f345d8eSLuigi Rizzo RING_GET(eq->ring, 1); 6802f345d8eSLuigi Rizzo num_eqes++; 6812f345d8eSLuigi Rizzo 6822f345d8eSLuigi Rizzo } while (TRUE); 6832f345d8eSLuigi Rizzo 6842f345d8eSLuigi Rizzo if (!num_eqes) 6852f345d8eSLuigi Rizzo goto eq_arm; /* Spurious */ 6862f345d8eSLuigi Rizzo 6872f345d8eSLuigi Rizzo /* Clear EQ entries, but dont arm */ 6882f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE); 6892f345d8eSLuigi Rizzo 6902f345d8eSLuigi Rizzo /* Process TX, RX and MCC. But dont arm CQ*/ 6912f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) { 6922f345d8eSLuigi Rizzo cq = eq->cq[i]; 6932f345d8eSLuigi Rizzo (*cq->cq_handler)(cq->cb_arg); 6942f345d8eSLuigi Rizzo } 6952f345d8eSLuigi Rizzo 6962f345d8eSLuigi Rizzo /* Arm all cqs connected to this EQ */ 6972f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) { 6982f345d8eSLuigi Rizzo cq = eq->cq[i]; 6992f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, 0, TRUE); 7002f345d8eSLuigi Rizzo } 7012f345d8eSLuigi Rizzo 7022f345d8eSLuigi Rizzo eq_arm: 7032f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 704cdaba892SXin LI 7052f345d8eSLuigi Rizzo return; 7062f345d8eSLuigi Rizzo } 7072f345d8eSLuigi Rizzo 7082f345d8eSLuigi Rizzo 7092f345d8eSLuigi Rizzo static int 7102f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc) 7112f345d8eSLuigi Rizzo { 7122f345d8eSLuigi Rizzo int rc = 0, use_intx = 0; 7132f345d8eSLuigi Rizzo int vector = 0, req_vectors = 0; 714*764c812dSJosh Paetzel int tot_req_vectors, tot_vectors; 7152f345d8eSLuigi Rizzo 716291a1934SXin LI if (is_rss_enabled(sc)) 7172f345d8eSLuigi Rizzo req_vectors = MAX((sc->nrqs - 1), sc->nwqs); 7182f345d8eSLuigi Rizzo else 7192f345d8eSLuigi Rizzo req_vectors = 1; 7202f345d8eSLuigi Rizzo 721*764c812dSJosh Paetzel tot_req_vectors = req_vectors; 722*764c812dSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 723*764c812dSJosh Paetzel if (req_vectors > 1) { 724*764c812dSJosh Paetzel tot_req_vectors += OCE_RDMA_VECTORS; 725*764c812dSJosh Paetzel sc->roce_intr_count = OCE_RDMA_VECTORS; 726*764c812dSJosh Paetzel } 727*764c812dSJosh Paetzel } 728*764c812dSJosh Paetzel 7292f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) { 7302f345d8eSLuigi Rizzo sc->intr_count = req_vectors; 731*764c812dSJosh Paetzel tot_vectors = tot_req_vectors; 732*764c812dSJosh Paetzel rc = pci_alloc_msix(sc->dev, &tot_vectors); 7332f345d8eSLuigi Rizzo if (rc != 0) { 7342f345d8eSLuigi Rizzo use_intx = 1; 7352f345d8eSLuigi Rizzo pci_release_msi(sc->dev); 736*764c812dSJosh Paetzel } else { 737*764c812dSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 738*764c812dSJosh Paetzel if (tot_vectors < tot_req_vectors) { 739*764c812dSJosh Paetzel if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) { 740*764c812dSJosh Paetzel sc->roce_intr_count = (tot_vectors / 2); 741*764c812dSJosh Paetzel } 742*764c812dSJosh Paetzel sc->intr_count = tot_vectors - sc->roce_intr_count; 743*764c812dSJosh Paetzel } 744*764c812dSJosh Paetzel } else { 745*764c812dSJosh Paetzel sc->intr_count = tot_vectors; 746*764c812dSJosh Paetzel } 7472f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_USING_MSIX; 748*764c812dSJosh Paetzel } 7492f345d8eSLuigi Rizzo } else 7502f345d8eSLuigi Rizzo use_intx = 1; 7512f345d8eSLuigi Rizzo 7522f345d8eSLuigi Rizzo if (use_intx) 7532f345d8eSLuigi Rizzo sc->intr_count = 1; 7542f345d8eSLuigi Rizzo 7552f345d8eSLuigi Rizzo /* Scale number of queues based on intr we got */ 7562f345d8eSLuigi Rizzo update_queues_got(sc); 7572f345d8eSLuigi Rizzo 7582f345d8eSLuigi Rizzo if (use_intx) { 7592f345d8eSLuigi Rizzo device_printf(sc->dev, "Using legacy interrupt\n"); 7602f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr); 7612f345d8eSLuigi Rizzo if (rc) 7622f345d8eSLuigi Rizzo goto error; 7632f345d8eSLuigi Rizzo } else { 7642f345d8eSLuigi Rizzo for (; vector < sc->intr_count; vector++) { 7652f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr); 7662f345d8eSLuigi Rizzo if (rc) 7672f345d8eSLuigi Rizzo goto error; 7682f345d8eSLuigi Rizzo } 7692f345d8eSLuigi Rizzo } 7702f345d8eSLuigi Rizzo 7712f345d8eSLuigi Rizzo return 0; 7722f345d8eSLuigi Rizzo error: 7732f345d8eSLuigi Rizzo oce_intr_free(sc); 7742f345d8eSLuigi Rizzo return rc; 7752f345d8eSLuigi Rizzo } 7762f345d8eSLuigi Rizzo 7772f345d8eSLuigi Rizzo 7782f345d8eSLuigi Rizzo static int 7792f345d8eSLuigi Rizzo oce_fast_isr(void *arg) 7802f345d8eSLuigi Rizzo { 7812f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg; 7822f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc; 7832f345d8eSLuigi Rizzo 7842f345d8eSLuigi Rizzo if (ii->eq == NULL) 7852f345d8eSLuigi Rizzo return FILTER_STRAY; 7862f345d8eSLuigi Rizzo 7872f345d8eSLuigi Rizzo oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE); 7882f345d8eSLuigi Rizzo 789cbc4d2dbSJohn Baldwin taskqueue_enqueue(ii->tq, &ii->task); 7902f345d8eSLuigi Rizzo 791cdaba892SXin LI ii->eq->intr++; 792cdaba892SXin LI 7932f345d8eSLuigi Rizzo return FILTER_HANDLED; 7942f345d8eSLuigi Rizzo } 7952f345d8eSLuigi Rizzo 7962f345d8eSLuigi Rizzo 7972f345d8eSLuigi Rizzo static int 7982f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending)) 7992f345d8eSLuigi Rizzo { 8002f345d8eSLuigi Rizzo POCE_INTR_INFO ii = &sc->intrs[vector]; 8012f345d8eSLuigi Rizzo int rc = 0, rr; 8022f345d8eSLuigi Rizzo 8032f345d8eSLuigi Rizzo if (vector >= OCE_MAX_EQ) 8042f345d8eSLuigi Rizzo return (EINVAL); 8052f345d8eSLuigi Rizzo 8062f345d8eSLuigi Rizzo /* Set the resource id for the interrupt. 8072f345d8eSLuigi Rizzo * MSIx is vector + 1 for the resource id, 8082f345d8eSLuigi Rizzo * INTx is 0 for the resource id. 8092f345d8eSLuigi Rizzo */ 8102f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX) 8112f345d8eSLuigi Rizzo rr = vector + 1; 8122f345d8eSLuigi Rizzo else 8132f345d8eSLuigi Rizzo rr = 0; 8142f345d8eSLuigi Rizzo ii->intr_res = bus_alloc_resource_any(sc->dev, 8152f345d8eSLuigi Rizzo SYS_RES_IRQ, 8162f345d8eSLuigi Rizzo &rr, RF_ACTIVE|RF_SHAREABLE); 8172f345d8eSLuigi Rizzo ii->irq_rr = rr; 8182f345d8eSLuigi Rizzo if (ii->intr_res == NULL) { 8192f345d8eSLuigi Rizzo device_printf(sc->dev, 8202f345d8eSLuigi Rizzo "Could not allocate interrupt\n"); 8212f345d8eSLuigi Rizzo rc = ENXIO; 8222f345d8eSLuigi Rizzo return rc; 8232f345d8eSLuigi Rizzo } 8242f345d8eSLuigi Rizzo 8252f345d8eSLuigi Rizzo TASK_INIT(&ii->task, 0, isr, ii); 8262f345d8eSLuigi Rizzo ii->vector = vector; 8272f345d8eSLuigi Rizzo sprintf(ii->task_name, "oce_task[%d]", ii->vector); 8282f345d8eSLuigi Rizzo ii->tq = taskqueue_create_fast(ii->task_name, 8292f345d8eSLuigi Rizzo M_NOWAIT, 8302f345d8eSLuigi Rizzo taskqueue_thread_enqueue, 8312f345d8eSLuigi Rizzo &ii->tq); 8322f345d8eSLuigi Rizzo taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq", 8332f345d8eSLuigi Rizzo device_get_nameunit(sc->dev)); 8342f345d8eSLuigi Rizzo 8352f345d8eSLuigi Rizzo ii->sc = sc; 8362f345d8eSLuigi Rizzo rc = bus_setup_intr(sc->dev, 8372f345d8eSLuigi Rizzo ii->intr_res, 8382f345d8eSLuigi Rizzo INTR_TYPE_NET, 8392f345d8eSLuigi Rizzo oce_fast_isr, NULL, ii, &ii->tag); 8402f345d8eSLuigi Rizzo return rc; 8412f345d8eSLuigi Rizzo 8422f345d8eSLuigi Rizzo } 8432f345d8eSLuigi Rizzo 8442f345d8eSLuigi Rizzo 8452f345d8eSLuigi Rizzo void 8462f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc) 8472f345d8eSLuigi Rizzo { 8482f345d8eSLuigi Rizzo int i = 0; 8492f345d8eSLuigi Rizzo 8502f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) { 8512f345d8eSLuigi Rizzo 8522f345d8eSLuigi Rizzo if (sc->intrs[i].tag != NULL) 8532f345d8eSLuigi Rizzo bus_teardown_intr(sc->dev, sc->intrs[i].intr_res, 8542f345d8eSLuigi Rizzo sc->intrs[i].tag); 8552f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) 8562f345d8eSLuigi Rizzo taskqueue_free(sc->intrs[i].tq); 8572f345d8eSLuigi Rizzo 8582f345d8eSLuigi Rizzo if (sc->intrs[i].intr_res != NULL) 8592f345d8eSLuigi Rizzo bus_release_resource(sc->dev, SYS_RES_IRQ, 8602f345d8eSLuigi Rizzo sc->intrs[i].irq_rr, 8612f345d8eSLuigi Rizzo sc->intrs[i].intr_res); 8622f345d8eSLuigi Rizzo sc->intrs[i].tag = NULL; 8632f345d8eSLuigi Rizzo sc->intrs[i].intr_res = NULL; 8642f345d8eSLuigi Rizzo } 8652f345d8eSLuigi Rizzo 8662f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX) 8672f345d8eSLuigi Rizzo pci_release_msi(sc->dev); 8682f345d8eSLuigi Rizzo 8692f345d8eSLuigi Rizzo } 8702f345d8eSLuigi Rizzo 8712f345d8eSLuigi Rizzo 8722f345d8eSLuigi Rizzo 8732f345d8eSLuigi Rizzo /****************************************************************************** 8742f345d8eSLuigi Rizzo * Media callbacks functions * 8752f345d8eSLuigi Rizzo ******************************************************************************/ 8762f345d8eSLuigi Rizzo 8772f345d8eSLuigi Rizzo static void 8782f345d8eSLuigi Rizzo oce_media_status(struct ifnet *ifp, struct ifmediareq *req) 8792f345d8eSLuigi Rizzo { 8802f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc; 8812f345d8eSLuigi Rizzo 8822f345d8eSLuigi Rizzo 8832f345d8eSLuigi Rizzo req->ifm_status = IFM_AVALID; 8842f345d8eSLuigi Rizzo req->ifm_active = IFM_ETHER; 8852f345d8eSLuigi Rizzo 8862f345d8eSLuigi Rizzo if (sc->link_status == 1) 8872f345d8eSLuigi Rizzo req->ifm_status |= IFM_ACTIVE; 8882f345d8eSLuigi Rizzo else 8892f345d8eSLuigi Rizzo return; 8902f345d8eSLuigi Rizzo 8912f345d8eSLuigi Rizzo switch (sc->link_speed) { 8922f345d8eSLuigi Rizzo case 1: /* 10 Mbps */ 8932f345d8eSLuigi Rizzo req->ifm_active |= IFM_10_T | IFM_FDX; 8942f345d8eSLuigi Rizzo sc->speed = 10; 8952f345d8eSLuigi Rizzo break; 8962f345d8eSLuigi Rizzo case 2: /* 100 Mbps */ 8972f345d8eSLuigi Rizzo req->ifm_active |= IFM_100_TX | IFM_FDX; 8982f345d8eSLuigi Rizzo sc->speed = 100; 8992f345d8eSLuigi Rizzo break; 9002f345d8eSLuigi Rizzo case 3: /* 1 Gbps */ 9012f345d8eSLuigi Rizzo req->ifm_active |= IFM_1000_T | IFM_FDX; 9022f345d8eSLuigi Rizzo sc->speed = 1000; 9032f345d8eSLuigi Rizzo break; 9042f345d8eSLuigi Rizzo case 4: /* 10 Gbps */ 9052f345d8eSLuigi Rizzo req->ifm_active |= IFM_10G_SR | IFM_FDX; 9062f345d8eSLuigi Rizzo sc->speed = 10000; 9072f345d8eSLuigi Rizzo break; 908a4f734b4SXin LI case 5: /* 20 Gbps */ 909a4f734b4SXin LI req->ifm_active |= IFM_10G_SR | IFM_FDX; 910a4f734b4SXin LI sc->speed = 20000; 911a4f734b4SXin LI break; 912a4f734b4SXin LI case 6: /* 25 Gbps */ 913a4f734b4SXin LI req->ifm_active |= IFM_10G_SR | IFM_FDX; 914a4f734b4SXin LI sc->speed = 25000; 915a4f734b4SXin LI break; 916b41206d8SXin LI case 7: /* 40 Gbps */ 917b41206d8SXin LI req->ifm_active |= IFM_40G_SR4 | IFM_FDX; 918b41206d8SXin LI sc->speed = 40000; 919b41206d8SXin LI break; 920a4f734b4SXin LI default: 921a4f734b4SXin LI sc->speed = 0; 922a4f734b4SXin LI break; 9232f345d8eSLuigi Rizzo } 9242f345d8eSLuigi Rizzo 9252f345d8eSLuigi Rizzo return; 9262f345d8eSLuigi Rizzo } 9272f345d8eSLuigi Rizzo 9282f345d8eSLuigi Rizzo 9292f345d8eSLuigi Rizzo int 9302f345d8eSLuigi Rizzo oce_media_change(struct ifnet *ifp) 9312f345d8eSLuigi Rizzo { 9322f345d8eSLuigi Rizzo return 0; 9332f345d8eSLuigi Rizzo } 9342f345d8eSLuigi Rizzo 9352f345d8eSLuigi Rizzo 936*764c812dSJosh Paetzel static void oce_is_pkt_dest_bmc(POCE_SOFTC sc, 937*764c812dSJosh Paetzel struct mbuf *m, boolean_t *os2bmc, 938*764c812dSJosh Paetzel struct mbuf **m_new) 939*764c812dSJosh Paetzel { 940*764c812dSJosh Paetzel struct ether_header *eh = NULL; 941*764c812dSJosh Paetzel 942*764c812dSJosh Paetzel eh = mtod(m, struct ether_header *); 943*764c812dSJosh Paetzel 944*764c812dSJosh Paetzel if (!is_os2bmc_enabled(sc) || *os2bmc) { 945*764c812dSJosh Paetzel *os2bmc = FALSE; 946*764c812dSJosh Paetzel goto done; 947*764c812dSJosh Paetzel } 948*764c812dSJosh Paetzel if (!ETHER_IS_MULTICAST(eh->ether_dhost)) 949*764c812dSJosh Paetzel goto done; 950*764c812dSJosh Paetzel 951*764c812dSJosh Paetzel if (is_mc_allowed_on_bmc(sc, eh) || 952*764c812dSJosh Paetzel is_bc_allowed_on_bmc(sc, eh) || 953*764c812dSJosh Paetzel is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) { 954*764c812dSJosh Paetzel *os2bmc = TRUE; 955*764c812dSJosh Paetzel goto done; 956*764c812dSJosh Paetzel } 957*764c812dSJosh Paetzel 958*764c812dSJosh Paetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) { 959*764c812dSJosh Paetzel struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 960*764c812dSJosh Paetzel uint8_t nexthdr = ip6->ip6_nxt; 961*764c812dSJosh Paetzel if (nexthdr == IPPROTO_ICMPV6) { 962*764c812dSJosh Paetzel struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1); 963*764c812dSJosh Paetzel switch (icmp6->icmp6_type) { 964*764c812dSJosh Paetzel case ND_ROUTER_ADVERT: 965*764c812dSJosh Paetzel *os2bmc = is_ipv6_ra_filt_enabled(sc); 966*764c812dSJosh Paetzel goto done; 967*764c812dSJosh Paetzel case ND_NEIGHBOR_ADVERT: 968*764c812dSJosh Paetzel *os2bmc = is_ipv6_na_filt_enabled(sc); 969*764c812dSJosh Paetzel goto done; 970*764c812dSJosh Paetzel default: 971*764c812dSJosh Paetzel break; 972*764c812dSJosh Paetzel } 973*764c812dSJosh Paetzel } 974*764c812dSJosh Paetzel } 975*764c812dSJosh Paetzel 976*764c812dSJosh Paetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) { 977*764c812dSJosh Paetzel struct ip *ip = mtod(m, struct ip *); 978*764c812dSJosh Paetzel int iphlen = ip->ip_hl << 2; 979*764c812dSJosh Paetzel struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen); 980*764c812dSJosh Paetzel switch (uh->uh_dport) { 981*764c812dSJosh Paetzel case DHCP_CLIENT_PORT: 982*764c812dSJosh Paetzel *os2bmc = is_dhcp_client_filt_enabled(sc); 983*764c812dSJosh Paetzel goto done; 984*764c812dSJosh Paetzel case DHCP_SERVER_PORT: 985*764c812dSJosh Paetzel *os2bmc = is_dhcp_srvr_filt_enabled(sc); 986*764c812dSJosh Paetzel goto done; 987*764c812dSJosh Paetzel case NET_BIOS_PORT1: 988*764c812dSJosh Paetzel case NET_BIOS_PORT2: 989*764c812dSJosh Paetzel *os2bmc = is_nbios_filt_enabled(sc); 990*764c812dSJosh Paetzel goto done; 991*764c812dSJosh Paetzel case DHCPV6_RAS_PORT: 992*764c812dSJosh Paetzel *os2bmc = is_ipv6_ras_filt_enabled(sc); 993*764c812dSJosh Paetzel goto done; 994*764c812dSJosh Paetzel default: 995*764c812dSJosh Paetzel break; 996*764c812dSJosh Paetzel } 997*764c812dSJosh Paetzel } 998*764c812dSJosh Paetzel done: 999*764c812dSJosh Paetzel if (*os2bmc) { 1000*764c812dSJosh Paetzel *m_new = m_dup(m, M_NOWAIT); 1001*764c812dSJosh Paetzel if (!*m_new) { 1002*764c812dSJosh Paetzel *os2bmc = FALSE; 1003*764c812dSJosh Paetzel return; 1004*764c812dSJosh Paetzel } 1005*764c812dSJosh Paetzel *m_new = oce_insert_vlan_tag(sc, *m_new, NULL); 1006*764c812dSJosh Paetzel } 1007*764c812dSJosh Paetzel } 1008*764c812dSJosh Paetzel 10092f345d8eSLuigi Rizzo 10102f345d8eSLuigi Rizzo 10112f345d8eSLuigi Rizzo /***************************************************************************** 10122f345d8eSLuigi Rizzo * Transmit routines functions * 10132f345d8eSLuigi Rizzo *****************************************************************************/ 10142f345d8eSLuigi Rizzo 10152f345d8eSLuigi Rizzo static int 10162f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index) 10172f345d8eSLuigi Rizzo { 10182f345d8eSLuigi Rizzo int rc = 0, i, retry_cnt = 0; 10192f345d8eSLuigi Rizzo bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS]; 1020*764c812dSJosh Paetzel struct mbuf *m, *m_temp, *m_new = NULL; 10212f345d8eSLuigi Rizzo struct oce_wq *wq = sc->wq[wq_index]; 10222f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 10232f345d8eSLuigi Rizzo struct oce_nic_hdr_wqe *nichdr; 10242f345d8eSLuigi Rizzo struct oce_nic_frag_wqe *nicfrag; 1025*764c812dSJosh Paetzel struct ether_header *eh = NULL; 10262f345d8eSLuigi Rizzo int num_wqes; 10272f345d8eSLuigi Rizzo uint32_t reg_value; 1028cdaba892SXin LI boolean_t complete = TRUE; 1029*764c812dSJosh Paetzel boolean_t os2bmc = FALSE; 10302f345d8eSLuigi Rizzo 10312f345d8eSLuigi Rizzo m = *mpp; 10322f345d8eSLuigi Rizzo if (!m) 10332f345d8eSLuigi Rizzo return EINVAL; 10342f345d8eSLuigi Rizzo 10352f345d8eSLuigi Rizzo if (!(m->m_flags & M_PKTHDR)) { 10362f345d8eSLuigi Rizzo rc = ENXIO; 10372f345d8eSLuigi Rizzo goto free_ret; 10382f345d8eSLuigi Rizzo } 10392f345d8eSLuigi Rizzo 1040*764c812dSJosh Paetzel /* Don't allow non-TSO packets longer than MTU */ 1041*764c812dSJosh Paetzel if (!is_tso_pkt(m)) { 1042*764c812dSJosh Paetzel eh = mtod(m, struct ether_header *); 1043*764c812dSJosh Paetzel if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE)) 1044*764c812dSJosh Paetzel goto free_ret; 1045*764c812dSJosh Paetzel } 1046*764c812dSJosh Paetzel 1047cdaba892SXin LI if(oce_tx_asic_stall_verify(sc, m)) { 1048cdaba892SXin LI m = oce_insert_vlan_tag(sc, m, &complete); 1049cdaba892SXin LI if(!m) { 1050cdaba892SXin LI device_printf(sc->dev, "Insertion unsuccessful\n"); 1051cdaba892SXin LI return 0; 1052cdaba892SXin LI } 1053cdaba892SXin LI 1054cdaba892SXin LI } 1055cdaba892SXin LI 1056*764c812dSJosh Paetzel /* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less 1057*764c812dSJosh Paetzel * may cause a transmit stall on that port. So the work-around is to 1058*764c812dSJosh Paetzel * pad short packets (<= 32 bytes) to a 36-byte length. 1059*764c812dSJosh Paetzel */ 1060*764c812dSJosh Paetzel if(IS_SH(sc) || IS_XE201(sc) ) { 1061*764c812dSJosh Paetzel if(m->m_pkthdr.len <= 32) { 1062*764c812dSJosh Paetzel char buf[36]; 1063*764c812dSJosh Paetzel bzero((void *)buf, 36); 1064*764c812dSJosh Paetzel m_append(m, (36 - m->m_pkthdr.len), buf); 1065*764c812dSJosh Paetzel } 1066*764c812dSJosh Paetzel } 1067*764c812dSJosh Paetzel 1068*764c812dSJosh Paetzel tx_start: 10692f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) { 10702f345d8eSLuigi Rizzo /* consolidate packet buffers for TSO/LSO segment offload */ 10719bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET) 10729bd3250aSLuigi Rizzo m = oce_tso_setup(sc, mpp); 1073ad512958SBjoern A. Zeeb #else 1074ad512958SBjoern A. Zeeb m = NULL; 1075ad512958SBjoern A. Zeeb #endif 10762f345d8eSLuigi Rizzo if (m == NULL) { 10772f345d8eSLuigi Rizzo rc = ENXIO; 10782f345d8eSLuigi Rizzo goto free_ret; 10792f345d8eSLuigi Rizzo } 10802f345d8eSLuigi Rizzo } 10812f345d8eSLuigi Rizzo 1082*764c812dSJosh Paetzel 1083291a1934SXin LI pd = &wq->pckts[wq->pkt_desc_head]; 1084*764c812dSJosh Paetzel 10852f345d8eSLuigi Rizzo retry: 10862f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(wq->tag, 10872f345d8eSLuigi Rizzo pd->map, 10882f345d8eSLuigi Rizzo m, segs, &pd->nsegs, BUS_DMA_NOWAIT); 10892f345d8eSLuigi Rizzo if (rc == 0) { 10902f345d8eSLuigi Rizzo num_wqes = pd->nsegs + 1; 1091291a1934SXin LI if (IS_BE(sc) || IS_SH(sc)) { 10922f345d8eSLuigi Rizzo /*Dummy required only for BE3.*/ 10932f345d8eSLuigi Rizzo if (num_wqes & 1) 10942f345d8eSLuigi Rizzo num_wqes++; 10952f345d8eSLuigi Rizzo } 10962f345d8eSLuigi Rizzo if (num_wqes >= RING_NUM_FREE(wq->ring)) { 10972f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map); 10982f345d8eSLuigi Rizzo return EBUSY; 10992f345d8eSLuigi Rizzo } 1100291a1934SXin LI atomic_store_rel_int(&wq->pkt_desc_head, 1101291a1934SXin LI (wq->pkt_desc_head + 1) % \ 1102291a1934SXin LI OCE_WQ_PACKET_ARRAY_SIZE); 11032f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE); 11042f345d8eSLuigi Rizzo pd->mbuf = m; 11052f345d8eSLuigi Rizzo 11062f345d8eSLuigi Rizzo nichdr = 11072f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe); 11082f345d8eSLuigi Rizzo nichdr->u0.dw[0] = 0; 11092f345d8eSLuigi Rizzo nichdr->u0.dw[1] = 0; 11102f345d8eSLuigi Rizzo nichdr->u0.dw[2] = 0; 11112f345d8eSLuigi Rizzo nichdr->u0.dw[3] = 0; 11122f345d8eSLuigi Rizzo 1113cdaba892SXin LI nichdr->u0.s.complete = complete; 1114*764c812dSJosh Paetzel nichdr->u0.s.mgmt = os2bmc; 11152f345d8eSLuigi Rizzo nichdr->u0.s.event = 1; 11162f345d8eSLuigi Rizzo nichdr->u0.s.crc = 1; 11172f345d8eSLuigi Rizzo nichdr->u0.s.forward = 0; 11182f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0; 11192f345d8eSLuigi Rizzo nichdr->u0.s.udpcs = 11202f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0; 11212f345d8eSLuigi Rizzo nichdr->u0.s.tcpcs = 11222f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0; 11232f345d8eSLuigi Rizzo nichdr->u0.s.num_wqe = num_wqes; 11242f345d8eSLuigi Rizzo nichdr->u0.s.total_length = m->m_pkthdr.len; 11255fbb6830SXin LI 11262f345d8eSLuigi Rizzo if (m->m_flags & M_VLANTAG) { 11272f345d8eSLuigi Rizzo nichdr->u0.s.vlan = 1; /*Vlan present*/ 11282f345d8eSLuigi Rizzo nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag; 11292f345d8eSLuigi Rizzo } 11305fbb6830SXin LI 11312f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) { 11322f345d8eSLuigi Rizzo if (m->m_pkthdr.tso_segsz) { 11332f345d8eSLuigi Rizzo nichdr->u0.s.lso = 1; 11342f345d8eSLuigi Rizzo nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz; 11352f345d8eSLuigi Rizzo } 1136291a1934SXin LI if (!IS_BE(sc) || !IS_SH(sc)) 11372f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = 1; 11382f345d8eSLuigi Rizzo } 11392f345d8eSLuigi Rizzo 11402f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1141291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11422f345d8eSLuigi Rizzo 11432f345d8eSLuigi Rizzo for (i = 0; i < pd->nsegs; i++) { 11442f345d8eSLuigi Rizzo nicfrag = 11452f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, 11462f345d8eSLuigi Rizzo struct oce_nic_frag_wqe); 11472f345d8eSLuigi Rizzo nicfrag->u0.s.rsvd0 = 0; 11482f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr); 11492f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr); 11502f345d8eSLuigi Rizzo nicfrag->u0.s.frag_len = segs[i].ds_len; 11512f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx; 11522f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1153291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11542f345d8eSLuigi Rizzo } 11552f345d8eSLuigi Rizzo if (num_wqes > (pd->nsegs + 1)) { 11562f345d8eSLuigi Rizzo nicfrag = 11572f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, 11582f345d8eSLuigi Rizzo struct oce_nic_frag_wqe); 11592f345d8eSLuigi Rizzo nicfrag->u0.dw[0] = 0; 11602f345d8eSLuigi Rizzo nicfrag->u0.dw[1] = 0; 11612f345d8eSLuigi Rizzo nicfrag->u0.dw[2] = 0; 11622f345d8eSLuigi Rizzo nicfrag->u0.dw[3] = 0; 11632f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx; 11642f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1); 1165291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1); 11662f345d8eSLuigi Rizzo pd->nsegs++; 11672f345d8eSLuigi Rizzo } 11682f345d8eSLuigi Rizzo 1169c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1); 11702f345d8eSLuigi Rizzo wq->tx_stats.tx_reqs++; 11712f345d8eSLuigi Rizzo wq->tx_stats.tx_wrbs += num_wqes; 11722f345d8eSLuigi Rizzo wq->tx_stats.tx_bytes += m->m_pkthdr.len; 11732f345d8eSLuigi Rizzo wq->tx_stats.tx_pkts++; 11742f345d8eSLuigi Rizzo 11752f345d8eSLuigi Rizzo bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map, 11762f345d8eSLuigi Rizzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 11772f345d8eSLuigi Rizzo reg_value = (num_wqes << 16) | wq->wq_id; 1178*764c812dSJosh Paetzel 1179*764c812dSJosh Paetzel /* if os2bmc is not enabled or if the pkt is already tagged as 1180*764c812dSJosh Paetzel bmc, do nothing 1181*764c812dSJosh Paetzel */ 1182*764c812dSJosh Paetzel oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new); 1183*764c812dSJosh Paetzel 1184291a1934SXin LI OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value); 11852f345d8eSLuigi Rizzo 11862f345d8eSLuigi Rizzo } else if (rc == EFBIG) { 11872f345d8eSLuigi Rizzo if (retry_cnt == 0) { 1188c6499eccSGleb Smirnoff m_temp = m_defrag(m, M_NOWAIT); 11892f345d8eSLuigi Rizzo if (m_temp == NULL) 11902f345d8eSLuigi Rizzo goto free_ret; 11912f345d8eSLuigi Rizzo m = m_temp; 11922f345d8eSLuigi Rizzo *mpp = m_temp; 11932f345d8eSLuigi Rizzo retry_cnt = retry_cnt + 1; 11942f345d8eSLuigi Rizzo goto retry; 11952f345d8eSLuigi Rizzo } else 11962f345d8eSLuigi Rizzo goto free_ret; 11972f345d8eSLuigi Rizzo } else if (rc == ENOMEM) 11982f345d8eSLuigi Rizzo return rc; 11992f345d8eSLuigi Rizzo else 12002f345d8eSLuigi Rizzo goto free_ret; 12012f345d8eSLuigi Rizzo 1202*764c812dSJosh Paetzel if (os2bmc) { 1203*764c812dSJosh Paetzel m = m_new; 1204*764c812dSJosh Paetzel goto tx_start; 1205*764c812dSJosh Paetzel } 1206*764c812dSJosh Paetzel 12072f345d8eSLuigi Rizzo return 0; 12082f345d8eSLuigi Rizzo 12092f345d8eSLuigi Rizzo free_ret: 12102f345d8eSLuigi Rizzo m_freem(*mpp); 12112f345d8eSLuigi Rizzo *mpp = NULL; 12122f345d8eSLuigi Rizzo return rc; 12132f345d8eSLuigi Rizzo } 12142f345d8eSLuigi Rizzo 12152f345d8eSLuigi Rizzo 12162f345d8eSLuigi Rizzo static void 1217*764c812dSJosh Paetzel oce_process_tx_completion(struct oce_wq *wq) 12182f345d8eSLuigi Rizzo { 12192f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 12202f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) wq->parent; 12212f345d8eSLuigi Rizzo struct mbuf *m; 12222f345d8eSLuigi Rizzo 1223291a1934SXin LI pd = &wq->pckts[wq->pkt_desc_tail]; 1224291a1934SXin LI atomic_store_rel_int(&wq->pkt_desc_tail, 1225291a1934SXin LI (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE); 1226291a1934SXin LI atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1); 12272f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 12282f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map); 12292f345d8eSLuigi Rizzo 12302f345d8eSLuigi Rizzo m = pd->mbuf; 12312f345d8eSLuigi Rizzo m_freem(m); 12322f345d8eSLuigi Rizzo pd->mbuf = NULL; 12332f345d8eSLuigi Rizzo 1234291a1934SXin LI 12352f345d8eSLuigi Rizzo if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) { 12362f345d8eSLuigi Rizzo if (wq->ring->num_used < (wq->ring->num_items / 2)) { 12372f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE); 12382f345d8eSLuigi Rizzo oce_tx_restart(sc, wq); 12392f345d8eSLuigi Rizzo } 12402f345d8eSLuigi Rizzo } 12412f345d8eSLuigi Rizzo } 12422f345d8eSLuigi Rizzo 12432f345d8eSLuigi Rizzo 12442f345d8eSLuigi Rizzo static void 12452f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq) 12462f345d8eSLuigi Rizzo { 12472f345d8eSLuigi Rizzo 12482f345d8eSLuigi Rizzo if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) 12492f345d8eSLuigi Rizzo return; 12502f345d8eSLuigi Rizzo 12512f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 12522f345d8eSLuigi Rizzo if (!drbr_empty(sc->ifp, wq->br)) 12532f345d8eSLuigi Rizzo #else 12542f345d8eSLuigi Rizzo if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd)) 12552f345d8eSLuigi Rizzo #endif 1256cbc4d2dbSJohn Baldwin taskqueue_enqueue(taskqueue_swi, &wq->txtask); 12572f345d8eSLuigi Rizzo 12582f345d8eSLuigi Rizzo } 12592f345d8eSLuigi Rizzo 12609bd3250aSLuigi Rizzo 1261ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 12622f345d8eSLuigi Rizzo static struct mbuf * 12639bd3250aSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp) 12642f345d8eSLuigi Rizzo { 12652f345d8eSLuigi Rizzo struct mbuf *m; 1266ad512958SBjoern A. Zeeb #ifdef INET 12672f345d8eSLuigi Rizzo struct ip *ip; 1268ad512958SBjoern A. Zeeb #endif 1269ad512958SBjoern A. Zeeb #ifdef INET6 12702f345d8eSLuigi Rizzo struct ip6_hdr *ip6; 1271ad512958SBjoern A. Zeeb #endif 12722f345d8eSLuigi Rizzo struct ether_vlan_header *eh; 12732f345d8eSLuigi Rizzo struct tcphdr *th; 12742f345d8eSLuigi Rizzo uint16_t etype; 12759bd3250aSLuigi Rizzo int total_len = 0, ehdrlen = 0; 12762f345d8eSLuigi Rizzo 12772f345d8eSLuigi Rizzo m = *mpp; 12782f345d8eSLuigi Rizzo 12792f345d8eSLuigi Rizzo if (M_WRITABLE(m) == 0) { 1280c6499eccSGleb Smirnoff m = m_dup(*mpp, M_NOWAIT); 12812f345d8eSLuigi Rizzo if (!m) 12822f345d8eSLuigi Rizzo return NULL; 12832f345d8eSLuigi Rizzo m_freem(*mpp); 12842f345d8eSLuigi Rizzo *mpp = m; 12852f345d8eSLuigi Rizzo } 12862f345d8eSLuigi Rizzo 12872f345d8eSLuigi Rizzo eh = mtod(m, struct ether_vlan_header *); 12882f345d8eSLuigi Rizzo if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 12892f345d8eSLuigi Rizzo etype = ntohs(eh->evl_proto); 12902f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 12912f345d8eSLuigi Rizzo } else { 12922f345d8eSLuigi Rizzo etype = ntohs(eh->evl_encap_proto); 12932f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN; 12942f345d8eSLuigi Rizzo } 12952f345d8eSLuigi Rizzo 12962f345d8eSLuigi Rizzo switch (etype) { 1297ad512958SBjoern A. Zeeb #ifdef INET 12982f345d8eSLuigi Rizzo case ETHERTYPE_IP: 12992f345d8eSLuigi Rizzo ip = (struct ip *)(m->m_data + ehdrlen); 13002f345d8eSLuigi Rizzo if (ip->ip_p != IPPROTO_TCP) 13012f345d8eSLuigi Rizzo return NULL; 13022f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); 13032f345d8eSLuigi Rizzo 13042f345d8eSLuigi Rizzo total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2); 13052f345d8eSLuigi Rizzo break; 1306ad512958SBjoern A. Zeeb #endif 1307ad512958SBjoern A. Zeeb #ifdef INET6 13082f345d8eSLuigi Rizzo case ETHERTYPE_IPV6: 13092f345d8eSLuigi Rizzo ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); 13102f345d8eSLuigi Rizzo if (ip6->ip6_nxt != IPPROTO_TCP) 13112f345d8eSLuigi Rizzo return NULL; 13122f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr)); 13132f345d8eSLuigi Rizzo 13142f345d8eSLuigi Rizzo total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2); 13152f345d8eSLuigi Rizzo break; 1316ad512958SBjoern A. Zeeb #endif 13172f345d8eSLuigi Rizzo default: 13182f345d8eSLuigi Rizzo return NULL; 13192f345d8eSLuigi Rizzo } 13202f345d8eSLuigi Rizzo 13212f345d8eSLuigi Rizzo m = m_pullup(m, total_len); 13222f345d8eSLuigi Rizzo if (!m) 13232f345d8eSLuigi Rizzo return NULL; 13242f345d8eSLuigi Rizzo *mpp = m; 13252f345d8eSLuigi Rizzo return m; 13262f345d8eSLuigi Rizzo 13272f345d8eSLuigi Rizzo } 1328ad512958SBjoern A. Zeeb #endif /* INET6 || INET */ 13292f345d8eSLuigi Rizzo 13302f345d8eSLuigi Rizzo void 13312f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending) 13322f345d8eSLuigi Rizzo { 13332f345d8eSLuigi Rizzo struct oce_wq *wq = arg; 13342f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 13352f345d8eSLuigi Rizzo struct ifnet *ifp = sc->ifp; 13362f345d8eSLuigi Rizzo int rc = 0; 13372f345d8eSLuigi Rizzo 13382f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1339291a1934SXin LI LOCK(&wq->tx_lock); 13402f345d8eSLuigi Rizzo rc = oce_multiq_transmit(ifp, NULL, wq); 13412f345d8eSLuigi Rizzo if (rc) { 13422f345d8eSLuigi Rizzo device_printf(sc->dev, 13432f345d8eSLuigi Rizzo "TX[%d] restart failed\n", wq->queue_index); 13442f345d8eSLuigi Rizzo } 13452f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock); 13462f345d8eSLuigi Rizzo #else 13472f345d8eSLuigi Rizzo oce_start(ifp); 13482f345d8eSLuigi Rizzo #endif 13492f345d8eSLuigi Rizzo 13502f345d8eSLuigi Rizzo } 13512f345d8eSLuigi Rizzo 13522f345d8eSLuigi Rizzo 13532f345d8eSLuigi Rizzo void 13542f345d8eSLuigi Rizzo oce_start(struct ifnet *ifp) 13552f345d8eSLuigi Rizzo { 13562f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 13572f345d8eSLuigi Rizzo struct mbuf *m; 13582f345d8eSLuigi Rizzo int rc = 0; 13599bd3250aSLuigi Rizzo int def_q = 0; /* Defualt tx queue is 0*/ 13602f345d8eSLuigi Rizzo 13612f345d8eSLuigi Rizzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 13622f345d8eSLuigi Rizzo IFF_DRV_RUNNING) 13632f345d8eSLuigi Rizzo return; 13642f345d8eSLuigi Rizzo 1365cdaba892SXin LI if (!sc->link_status) 1366cdaba892SXin LI return; 1367cdaba892SXin LI 13682f345d8eSLuigi Rizzo do { 13692f345d8eSLuigi Rizzo IF_DEQUEUE(&sc->ifp->if_snd, m); 13702f345d8eSLuigi Rizzo if (m == NULL) 13712f345d8eSLuigi Rizzo break; 13729bd3250aSLuigi Rizzo 13739bd3250aSLuigi Rizzo LOCK(&sc->wq[def_q]->tx_lock); 13749bd3250aSLuigi Rizzo rc = oce_tx(sc, &m, def_q); 13759bd3250aSLuigi Rizzo UNLOCK(&sc->wq[def_q]->tx_lock); 13762f345d8eSLuigi Rizzo if (rc) { 13772f345d8eSLuigi Rizzo if (m != NULL) { 13789bd3250aSLuigi Rizzo sc->wq[def_q]->tx_stats.tx_stops ++; 13792f345d8eSLuigi Rizzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 13802f345d8eSLuigi Rizzo IFQ_DRV_PREPEND(&ifp->if_snd, m); 13812f345d8eSLuigi Rizzo m = NULL; 13822f345d8eSLuigi Rizzo } 13832f345d8eSLuigi Rizzo break; 13842f345d8eSLuigi Rizzo } 13852f345d8eSLuigi Rizzo if (m != NULL) 13862f345d8eSLuigi Rizzo ETHER_BPF_MTAP(ifp, m); 13872f345d8eSLuigi Rizzo 13889bd3250aSLuigi Rizzo } while (TRUE); 13892f345d8eSLuigi Rizzo 13902f345d8eSLuigi Rizzo return; 13912f345d8eSLuigi Rizzo } 13922f345d8eSLuigi Rizzo 13932f345d8eSLuigi Rizzo 13942f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */ 13952f345d8eSLuigi Rizzo uint16_t 13962f345d8eSLuigi Rizzo oce_wq_handler(void *arg) 13972f345d8eSLuigi Rizzo { 13982f345d8eSLuigi Rizzo struct oce_wq *wq = (struct oce_wq *)arg; 13992f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent; 14002f345d8eSLuigi Rizzo struct oce_cq *cq = wq->cq; 14012f345d8eSLuigi Rizzo struct oce_nic_tx_cqe *cqe; 14022f345d8eSLuigi Rizzo int num_cqes = 0; 14032f345d8eSLuigi Rizzo 1404*764c812dSJosh Paetzel LOCK(&wq->tx_compl_lock); 14052f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 14062f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 14072f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 14082f345d8eSLuigi Rizzo while (cqe->u0.dw[3]) { 14092f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe)); 14102f345d8eSLuigi Rizzo 14112f345d8eSLuigi Rizzo wq->ring->cidx = cqe->u0.s.wqe_index + 1; 14122f345d8eSLuigi Rizzo if (wq->ring->cidx >= wq->ring->num_items) 14132f345d8eSLuigi Rizzo wq->ring->cidx -= wq->ring->num_items; 14142f345d8eSLuigi Rizzo 1415*764c812dSJosh Paetzel oce_process_tx_completion(wq); 14162f345d8eSLuigi Rizzo wq->tx_stats.tx_compl++; 14172f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 14182f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 14192f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 14202f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 14212f345d8eSLuigi Rizzo cqe = 14222f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe); 14232f345d8eSLuigi Rizzo num_cqes++; 14242f345d8eSLuigi Rizzo } 14252f345d8eSLuigi Rizzo 14262f345d8eSLuigi Rizzo if (num_cqes) 14272f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 14282f345d8eSLuigi Rizzo 1429*764c812dSJosh Paetzel UNLOCK(&wq->tx_compl_lock); 1430*764c812dSJosh Paetzel return num_cqes; 14312f345d8eSLuigi Rizzo } 14322f345d8eSLuigi Rizzo 14332f345d8eSLuigi Rizzo 14342f345d8eSLuigi Rizzo static int 14352f345d8eSLuigi Rizzo oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq) 14362f345d8eSLuigi Rizzo { 14372f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 14382f345d8eSLuigi Rizzo int status = 0, queue_index = 0; 14392f345d8eSLuigi Rizzo struct mbuf *next = NULL; 14402f345d8eSLuigi Rizzo struct buf_ring *br = NULL; 14412f345d8eSLuigi Rizzo 14422f345d8eSLuigi Rizzo br = wq->br; 14432f345d8eSLuigi Rizzo queue_index = wq->queue_index; 14442f345d8eSLuigi Rizzo 14452f345d8eSLuigi Rizzo if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 14462f345d8eSLuigi Rizzo IFF_DRV_RUNNING) { 14472f345d8eSLuigi Rizzo if (m != NULL) 14482f345d8eSLuigi Rizzo status = drbr_enqueue(ifp, br, m); 14492f345d8eSLuigi Rizzo return status; 14502f345d8eSLuigi Rizzo } 14512f345d8eSLuigi Rizzo 1452ded5ea6aSRandall Stewart if (m != NULL) { 14532f345d8eSLuigi Rizzo if ((status = drbr_enqueue(ifp, br, m)) != 0) 14542f345d8eSLuigi Rizzo return status; 1455ded5ea6aSRandall Stewart } 1456ded5ea6aSRandall Stewart while ((next = drbr_peek(ifp, br)) != NULL) { 14572f345d8eSLuigi Rizzo if (oce_tx(sc, &next, queue_index)) { 1458ded5ea6aSRandall Stewart if (next == NULL) { 1459ded5ea6aSRandall Stewart drbr_advance(ifp, br); 1460ded5ea6aSRandall Stewart } else { 1461ded5ea6aSRandall Stewart drbr_putback(ifp, br, next); 14622f345d8eSLuigi Rizzo wq->tx_stats.tx_stops ++; 14632f345d8eSLuigi Rizzo ifp->if_drv_flags |= IFF_DRV_OACTIVE; 14642f345d8eSLuigi Rizzo } 14652f345d8eSLuigi Rizzo break; 14662f345d8eSLuigi Rizzo } 1467ded5ea6aSRandall Stewart drbr_advance(ifp, br); 1468c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len); 1469063efed2SGleb Smirnoff if (next->m_flags & M_MCAST) 1470c8dfaf38SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 14712f345d8eSLuigi Rizzo ETHER_BPF_MTAP(ifp, next); 14722f345d8eSLuigi Rizzo } 14732f345d8eSLuigi Rizzo 1474d398c863SLuigi Rizzo return 0; 14752f345d8eSLuigi Rizzo } 14762f345d8eSLuigi Rizzo 14772f345d8eSLuigi Rizzo 14782f345d8eSLuigi Rizzo 14792f345d8eSLuigi Rizzo 14802f345d8eSLuigi Rizzo /***************************************************************************** 14812f345d8eSLuigi Rizzo * Receive routines functions * 14822f345d8eSLuigi Rizzo *****************************************************************************/ 14832f345d8eSLuigi Rizzo 14842f345d8eSLuigi Rizzo static void 1485*764c812dSJosh Paetzel oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2) 14862f345d8eSLuigi Rizzo { 1487*764c812dSJosh Paetzel uint32_t *p; 1488*764c812dSJosh Paetzel struct ether_header *eh = NULL; 1489*764c812dSJosh Paetzel struct tcphdr *tcp_hdr = NULL; 1490*764c812dSJosh Paetzel struct ip *ip4_hdr = NULL; 1491*764c812dSJosh Paetzel struct ip6_hdr *ip6 = NULL; 1492*764c812dSJosh Paetzel uint32_t payload_len = 0; 1493*764c812dSJosh Paetzel 1494*764c812dSJosh Paetzel eh = mtod(m, struct ether_header *); 1495*764c812dSJosh Paetzel /* correct IP header */ 1496*764c812dSJosh Paetzel if(!cqe2->ipv6_frame) { 1497*764c812dSJosh Paetzel ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header)); 1498*764c812dSJosh Paetzel ip4_hdr->ip_ttl = cqe2->frame_lifespan; 1499*764c812dSJosh Paetzel ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header)); 1500*764c812dSJosh Paetzel tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip)); 1501*764c812dSJosh Paetzel }else { 1502*764c812dSJosh Paetzel ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header)); 1503*764c812dSJosh Paetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan; 1504*764c812dSJosh Paetzel payload_len = cqe2->coalesced_size - sizeof(struct ether_header) 1505*764c812dSJosh Paetzel - sizeof(struct ip6_hdr); 1506*764c812dSJosh Paetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len); 1507*764c812dSJosh Paetzel tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr)); 1508*764c812dSJosh Paetzel } 1509*764c812dSJosh Paetzel 1510*764c812dSJosh Paetzel /* correct tcp header */ 1511*764c812dSJosh Paetzel tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num); 1512*764c812dSJosh Paetzel if(cqe2->push) { 1513*764c812dSJosh Paetzel tcp_hdr->th_flags |= TH_PUSH; 1514*764c812dSJosh Paetzel } 1515*764c812dSJosh Paetzel tcp_hdr->th_win = htons(cqe2->tcp_window); 1516*764c812dSJosh Paetzel tcp_hdr->th_sum = 0xffff; 1517*764c812dSJosh Paetzel if(cqe2->ts_opt) { 1518*764c812dSJosh Paetzel p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2); 1519*764c812dSJosh Paetzel *p = cqe1->tcp_timestamp_val; 1520*764c812dSJosh Paetzel *(p+1) = cqe1->tcp_timestamp_ecr; 1521*764c812dSJosh Paetzel } 1522*764c812dSJosh Paetzel 1523*764c812dSJosh Paetzel return; 1524*764c812dSJosh Paetzel } 1525*764c812dSJosh Paetzel 1526*764c812dSJosh Paetzel static void 1527*764c812dSJosh Paetzel oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m) 1528*764c812dSJosh Paetzel { 15292f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1530*764c812dSJosh Paetzel uint32_t i = 0, frag_len = 0; 1531*764c812dSJosh Paetzel uint32_t len = cqe_info->pkt_size; 1532*764c812dSJosh Paetzel struct oce_packet_desc *pd; 1533*764c812dSJosh Paetzel struct mbuf *tail = NULL; 15342f345d8eSLuigi Rizzo 1535*764c812dSJosh Paetzel for (i = 0; i < cqe_info->num_frags; i++) { 1536*764c812dSJosh Paetzel if (rq->ring->cidx == rq->ring->pidx) { 15372f345d8eSLuigi Rizzo device_printf(sc->dev, 1538*764c812dSJosh Paetzel "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n"); 1539*764c812dSJosh Paetzel return; 15402f345d8eSLuigi Rizzo } 1541*764c812dSJosh Paetzel pd = &rq->pckts[rq->ring->cidx]; 15422f345d8eSLuigi Rizzo 15432f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 15442f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, pd->map); 1545*764c812dSJosh Paetzel RING_GET(rq->ring, 1); 15462f345d8eSLuigi Rizzo rq->pending--; 15472f345d8eSLuigi Rizzo 15482f345d8eSLuigi Rizzo frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len; 15492f345d8eSLuigi Rizzo pd->mbuf->m_len = frag_len; 15502f345d8eSLuigi Rizzo 15512f345d8eSLuigi Rizzo if (tail != NULL) { 15522f345d8eSLuigi Rizzo /* additional fragments */ 15532f345d8eSLuigi Rizzo pd->mbuf->m_flags &= ~M_PKTHDR; 15542f345d8eSLuigi Rizzo tail->m_next = pd->mbuf; 1555*764c812dSJosh Paetzel if(rq->islro) 1556*764c812dSJosh Paetzel tail->m_nextpkt = NULL; 15572f345d8eSLuigi Rizzo tail = pd->mbuf; 15582f345d8eSLuigi Rizzo } else { 15592f345d8eSLuigi Rizzo /* first fragment, fill out much of the packet header */ 15602f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.len = len; 1561*764c812dSJosh Paetzel if(rq->islro) 1562*764c812dSJosh Paetzel pd->mbuf->m_nextpkt = NULL; 15632f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.csum_flags = 0; 15642f345d8eSLuigi Rizzo if (IF_CSUM_ENABLED(sc)) { 1565*764c812dSJosh Paetzel if (cqe_info->l4_cksum_pass) { 1566*764c812dSJosh Paetzel if(!cqe_info->ipv6_frame) { /* IPV4 */ 15672f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.csum_flags |= 15682f345d8eSLuigi Rizzo (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1569*764c812dSJosh Paetzel }else { /* IPV6 frame */ 1570*764c812dSJosh Paetzel if(rq->islro) { 1571*764c812dSJosh Paetzel pd->mbuf->m_pkthdr.csum_flags |= 1572*764c812dSJosh Paetzel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); 1573*764c812dSJosh Paetzel } 1574*764c812dSJosh Paetzel } 15752f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.csum_data = 0xffff; 15762f345d8eSLuigi Rizzo } 1577*764c812dSJosh Paetzel if (cqe_info->ip_cksum_pass) { 15782f345d8eSLuigi Rizzo pd->mbuf->m_pkthdr.csum_flags |= 15792f345d8eSLuigi Rizzo (CSUM_IP_CHECKED|CSUM_IP_VALID); 15802f345d8eSLuigi Rizzo } 15812f345d8eSLuigi Rizzo } 1582*764c812dSJosh Paetzel *m = tail = pd->mbuf; 15832f345d8eSLuigi Rizzo } 15842f345d8eSLuigi Rizzo pd->mbuf = NULL; 15852f345d8eSLuigi Rizzo len -= frag_len; 15862f345d8eSLuigi Rizzo } 15872f345d8eSLuigi Rizzo 1588*764c812dSJosh Paetzel return; 1589*764c812dSJosh Paetzel } 1590*764c812dSJosh Paetzel 1591*764c812dSJosh Paetzel static void 1592*764c812dSJosh Paetzel oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2) 1593*764c812dSJosh Paetzel { 1594*764c812dSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1595*764c812dSJosh Paetzel struct nic_hwlro_cqe_part1 *cqe1 = NULL; 1596*764c812dSJosh Paetzel struct mbuf *m = NULL; 1597*764c812dSJosh Paetzel struct oce_common_cqe_info cq_info; 1598*764c812dSJosh Paetzel 1599*764c812dSJosh Paetzel /* parse cqe */ 1600*764c812dSJosh Paetzel if(cqe2 == NULL) { 1601*764c812dSJosh Paetzel cq_info.pkt_size = cqe->pkt_size; 1602*764c812dSJosh Paetzel cq_info.vtag = cqe->vlan_tag; 1603*764c812dSJosh Paetzel cq_info.l4_cksum_pass = cqe->l4_cksum_pass; 1604*764c812dSJosh Paetzel cq_info.ip_cksum_pass = cqe->ip_cksum_pass; 1605*764c812dSJosh Paetzel cq_info.ipv6_frame = cqe->ipv6_frame; 1606*764c812dSJosh Paetzel cq_info.vtp = cqe->vtp; 1607*764c812dSJosh Paetzel cq_info.qnq = cqe->qnq; 1608*764c812dSJosh Paetzel }else { 1609*764c812dSJosh Paetzel cqe1 = (struct nic_hwlro_cqe_part1 *)cqe; 1610*764c812dSJosh Paetzel cq_info.pkt_size = cqe2->coalesced_size; 1611*764c812dSJosh Paetzel cq_info.vtag = cqe2->vlan_tag; 1612*764c812dSJosh Paetzel cq_info.l4_cksum_pass = cqe2->l4_cksum_pass; 1613*764c812dSJosh Paetzel cq_info.ip_cksum_pass = cqe2->ip_cksum_pass; 1614*764c812dSJosh Paetzel cq_info.ipv6_frame = cqe2->ipv6_frame; 1615*764c812dSJosh Paetzel cq_info.vtp = cqe2->vtp; 1616*764c812dSJosh Paetzel cq_info.qnq = cqe1->qnq; 1617*764c812dSJosh Paetzel } 1618*764c812dSJosh Paetzel 1619*764c812dSJosh Paetzel cq_info.vtag = BSWAP_16(cq_info.vtag); 1620*764c812dSJosh Paetzel 1621*764c812dSJosh Paetzel cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size; 1622*764c812dSJosh Paetzel if(cq_info.pkt_size % rq->cfg.frag_size) 1623*764c812dSJosh Paetzel cq_info.num_frags++; 1624*764c812dSJosh Paetzel 1625*764c812dSJosh Paetzel oce_rx_mbuf_chain(rq, &cq_info, &m); 1626*764c812dSJosh Paetzel 16272f345d8eSLuigi Rizzo if (m) { 1628*764c812dSJosh Paetzel if(cqe2) { 1629*764c812dSJosh Paetzel //assert(cqe2->valid != 0); 1630*764c812dSJosh Paetzel 1631*764c812dSJosh Paetzel //assert(cqe2->cqe_type != 2); 1632*764c812dSJosh Paetzel oce_correct_header(m, cqe1, cqe2); 1633*764c812dSJosh Paetzel } 1634*764c812dSJosh Paetzel 1635*764c812dSJosh Paetzel m->m_pkthdr.rcvif = sc->ifp; 1636*764c812dSJosh Paetzel #if __FreeBSD_version >= 800000 1637*764c812dSJosh Paetzel if (rq->queue_index) 1638*764c812dSJosh Paetzel m->m_pkthdr.flowid = (rq->queue_index - 1); 1639*764c812dSJosh Paetzel else 1640*764c812dSJosh Paetzel m->m_pkthdr.flowid = rq->queue_index; 1641*764c812dSJosh Paetzel M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 1642*764c812dSJosh Paetzel #endif 1643*764c812dSJosh Paetzel /* This deternies if vlan tag is Valid */ 1644*764c812dSJosh Paetzel if (cq_info.vtp) { 1645*764c812dSJosh Paetzel if (sc->function_mode & FNM_FLEX10_MODE) { 1646*764c812dSJosh Paetzel /* FLEX10. If QnQ is not set, neglect VLAN */ 1647*764c812dSJosh Paetzel if (cq_info.qnq) { 1648*764c812dSJosh Paetzel m->m_pkthdr.ether_vtag = cq_info.vtag; 1649*764c812dSJosh Paetzel m->m_flags |= M_VLANTAG; 1650*764c812dSJosh Paetzel } 1651*764c812dSJosh Paetzel } else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK)) { 1652*764c812dSJosh Paetzel /* In UMC mode generally pvid will be striped by 1653*764c812dSJosh Paetzel hw. But in some cases we have seen it comes 1654*764c812dSJosh Paetzel with pvid. So if pvid == vlan, neglect vlan. 1655*764c812dSJosh Paetzel */ 1656*764c812dSJosh Paetzel m->m_pkthdr.ether_vtag = cq_info.vtag; 1657*764c812dSJosh Paetzel m->m_flags |= M_VLANTAG; 1658*764c812dSJosh Paetzel } 1659*764c812dSJosh Paetzel } 1660*764c812dSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 1661*764c812dSJosh Paetzel 1662*764c812dSJosh Paetzel (*sc->ifp->if_input) (sc->ifp, m); 1663*764c812dSJosh Paetzel 1664*764c812dSJosh Paetzel /* Update rx stats per queue */ 1665*764c812dSJosh Paetzel rq->rx_stats.rx_pkts++; 1666*764c812dSJosh Paetzel rq->rx_stats.rx_bytes += cq_info.pkt_size; 1667*764c812dSJosh Paetzel rq->rx_stats.rx_frags += cq_info.num_frags; 1668*764c812dSJosh Paetzel rq->rx_stats.rx_ucast_pkts++; 1669*764c812dSJosh Paetzel } 1670*764c812dSJosh Paetzel return; 1671*764c812dSJosh Paetzel } 1672*764c812dSJosh Paetzel 1673*764c812dSJosh Paetzel static void 1674*764c812dSJosh Paetzel oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe) 1675*764c812dSJosh Paetzel { 1676*764c812dSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 1677*764c812dSJosh Paetzel int len; 1678*764c812dSJosh Paetzel struct mbuf *m = NULL; 1679*764c812dSJosh Paetzel struct oce_common_cqe_info cq_info; 1680*764c812dSJosh Paetzel uint16_t vtag = 0; 1681*764c812dSJosh Paetzel 1682*764c812dSJosh Paetzel /* Is it a flush compl that has no data */ 1683*764c812dSJosh Paetzel if(!cqe->u0.s.num_fragments) 1684*764c812dSJosh Paetzel goto exit; 1685*764c812dSJosh Paetzel 1686*764c812dSJosh Paetzel len = cqe->u0.s.pkt_size; 1687*764c812dSJosh Paetzel if (!len) { 1688*764c812dSJosh Paetzel /*partial DMA workaround for Lancer*/ 1689*764c812dSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 16902f345d8eSLuigi Rizzo goto exit; 16912f345d8eSLuigi Rizzo } 16922f345d8eSLuigi Rizzo 1693*764c812dSJosh Paetzel if (!oce_cqe_portid_valid(sc, cqe)) { 1694*764c812dSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments); 1695*764c812dSJosh Paetzel goto exit; 1696*764c812dSJosh Paetzel } 1697*764c812dSJosh Paetzel 1698*764c812dSJosh Paetzel /* Get vlan_tag value */ 1699*764c812dSJosh Paetzel if(IS_BE(sc) || IS_SH(sc)) 1700*764c812dSJosh Paetzel vtag = BSWAP_16(cqe->u0.s.vlan_tag); 1701*764c812dSJosh Paetzel else 1702*764c812dSJosh Paetzel vtag = cqe->u0.s.vlan_tag; 1703*764c812dSJosh Paetzel 1704*764c812dSJosh Paetzel cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass; 1705*764c812dSJosh Paetzel cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass; 1706*764c812dSJosh Paetzel cq_info.ipv6_frame = cqe->u0.s.ip_ver; 1707*764c812dSJosh Paetzel cq_info.num_frags = cqe->u0.s.num_fragments; 1708*764c812dSJosh Paetzel cq_info.pkt_size = cqe->u0.s.pkt_size; 1709*764c812dSJosh Paetzel 1710*764c812dSJosh Paetzel oce_rx_mbuf_chain(rq, &cq_info, &m); 1711*764c812dSJosh Paetzel 1712*764c812dSJosh Paetzel if (m) { 17132f345d8eSLuigi Rizzo m->m_pkthdr.rcvif = sc->ifp; 17142f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 1715291a1934SXin LI if (rq->queue_index) 1716291a1934SXin LI m->m_pkthdr.flowid = (rq->queue_index - 1); 1717291a1934SXin LI else 17182f345d8eSLuigi Rizzo m->m_pkthdr.flowid = rq->queue_index; 1719c2529042SHans Petter Selasky M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); 17202f345d8eSLuigi Rizzo #endif 17219bd3250aSLuigi Rizzo /* This deternies if vlan tag is Valid */ 17222f345d8eSLuigi Rizzo if (oce_cqe_vtp_valid(sc, cqe)) { 17232f345d8eSLuigi Rizzo if (sc->function_mode & FNM_FLEX10_MODE) { 17249bd3250aSLuigi Rizzo /* FLEX10. If QnQ is not set, neglect VLAN */ 17252f345d8eSLuigi Rizzo if (cqe->u0.s.qnq) { 17262f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag; 17272f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG; 17282f345d8eSLuigi Rizzo } 17299bd3250aSLuigi Rizzo } else if (sc->pvid != (vtag & VLAN_VID_MASK)) { 17309bd3250aSLuigi Rizzo /* In UMC mode generally pvid will be striped by 17319bd3250aSLuigi Rizzo hw. But in some cases we have seen it comes 17329bd3250aSLuigi Rizzo with pvid. So if pvid == vlan, neglect vlan. 17339bd3250aSLuigi Rizzo */ 17342f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag; 17352f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG; 17362f345d8eSLuigi Rizzo } 17372f345d8eSLuigi Rizzo } 17382f345d8eSLuigi Rizzo 1739c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1); 1740ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 17412f345d8eSLuigi Rizzo /* Try to queue to LRO */ 17422f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && 17432f345d8eSLuigi Rizzo (cqe->u0.s.ip_cksum_pass) && 17442f345d8eSLuigi Rizzo (cqe->u0.s.l4_cksum_pass) && 17452f345d8eSLuigi Rizzo (!cqe->u0.s.ip_ver) && 17462f345d8eSLuigi Rizzo (rq->lro.lro_cnt != 0)) { 17472f345d8eSLuigi Rizzo 17482f345d8eSLuigi Rizzo if (tcp_lro_rx(&rq->lro, m, 0) == 0) { 17492f345d8eSLuigi Rizzo rq->lro_pkts_queued ++; 17502f345d8eSLuigi Rizzo goto post_done; 17512f345d8eSLuigi Rizzo } 17522f345d8eSLuigi Rizzo /* If LRO posting fails then try to post to STACK */ 17532f345d8eSLuigi Rizzo } 1754ad512958SBjoern A. Zeeb #endif 17552f345d8eSLuigi Rizzo 17562f345d8eSLuigi Rizzo (*sc->ifp->if_input) (sc->ifp, m); 1757ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 17582f345d8eSLuigi Rizzo post_done: 1759ad512958SBjoern A. Zeeb #endif 17602f345d8eSLuigi Rizzo /* Update rx stats per queue */ 17612f345d8eSLuigi Rizzo rq->rx_stats.rx_pkts++; 17622f345d8eSLuigi Rizzo rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size; 17632f345d8eSLuigi Rizzo rq->rx_stats.rx_frags += cqe->u0.s.num_fragments; 17642f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET) 17652f345d8eSLuigi Rizzo rq->rx_stats.rx_mcast_pkts++; 17662f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET) 17672f345d8eSLuigi Rizzo rq->rx_stats.rx_ucast_pkts++; 17682f345d8eSLuigi Rizzo } 17692f345d8eSLuigi Rizzo exit: 17702f345d8eSLuigi Rizzo return; 17712f345d8eSLuigi Rizzo } 17722f345d8eSLuigi Rizzo 17732f345d8eSLuigi Rizzo 1774*764c812dSJosh Paetzel void 1775*764c812dSJosh Paetzel oce_discard_rx_comp(struct oce_rq *rq, int num_frags) 17762f345d8eSLuigi Rizzo { 1777*764c812dSJosh Paetzel uint32_t i = 0; 17782f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 17792f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 17802f345d8eSLuigi Rizzo 17812f345d8eSLuigi Rizzo for (i = 0; i < num_frags; i++) { 1782*764c812dSJosh Paetzel if (rq->ring->cidx == rq->ring->pidx) { 17832f345d8eSLuigi Rizzo device_printf(sc->dev, 1784*764c812dSJosh Paetzel "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n"); 1785*764c812dSJosh Paetzel return; 17862f345d8eSLuigi Rizzo } 1787*764c812dSJosh Paetzel pd = &rq->pckts[rq->ring->cidx]; 17882f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE); 17892f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, pd->map); 1790*764c812dSJosh Paetzel if (pd->mbuf != NULL) { 17912f345d8eSLuigi Rizzo m_freem(pd->mbuf); 1792*764c812dSJosh Paetzel pd->mbuf = NULL; 17932f345d8eSLuigi Rizzo } 17942f345d8eSLuigi Rizzo 1795*764c812dSJosh Paetzel RING_GET(rq->ring, 1); 1796*764c812dSJosh Paetzel rq->pending--; 1797*764c812dSJosh Paetzel } 17982f345d8eSLuigi Rizzo } 17992f345d8eSLuigi Rizzo 18002f345d8eSLuigi Rizzo 18012f345d8eSLuigi Rizzo static int 18022f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 18032f345d8eSLuigi Rizzo { 18042f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1; 18052f345d8eSLuigi Rizzo int vtp = 0; 18062f345d8eSLuigi Rizzo 18072f345d8eSLuigi Rizzo if (sc->be3_native) { 18082f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 18092f345d8eSLuigi Rizzo vtp = cqe_v1->u0.s.vlan_tag_present; 18109bd3250aSLuigi Rizzo } else 18112f345d8eSLuigi Rizzo vtp = cqe->u0.s.vlan_tag_present; 18122f345d8eSLuigi Rizzo 18132f345d8eSLuigi Rizzo return vtp; 18142f345d8eSLuigi Rizzo 18152f345d8eSLuigi Rizzo } 18162f345d8eSLuigi Rizzo 18172f345d8eSLuigi Rizzo 18182f345d8eSLuigi Rizzo static int 18192f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe) 18202f345d8eSLuigi Rizzo { 18212f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1; 18222f345d8eSLuigi Rizzo int port_id = 0; 18232f345d8eSLuigi Rizzo 1824291a1934SXin LI if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) { 18252f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe; 18262f345d8eSLuigi Rizzo port_id = cqe_v1->u0.s.port; 18272f345d8eSLuigi Rizzo if (sc->port_id != port_id) 18282f345d8eSLuigi Rizzo return 0; 18292f345d8eSLuigi Rizzo } else 18302f345d8eSLuigi Rizzo ;/* For BE3 legacy and Lancer this is dummy */ 18312f345d8eSLuigi Rizzo 18322f345d8eSLuigi Rizzo return 1; 18332f345d8eSLuigi Rizzo 18342f345d8eSLuigi Rizzo } 18352f345d8eSLuigi Rizzo 1836ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 1837*764c812dSJosh Paetzel void 18382f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq) 18392f345d8eSLuigi Rizzo { 18402f345d8eSLuigi Rizzo struct lro_ctrl *lro = &rq->lro; 18412f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 18422f345d8eSLuigi Rizzo 18432f345d8eSLuigi Rizzo if (!IF_LRO_ENABLED(sc)) 18442f345d8eSLuigi Rizzo return; 18452f345d8eSLuigi Rizzo 18466dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro); 18472f345d8eSLuigi Rizzo rq->lro_pkts_queued = 0; 18482f345d8eSLuigi Rizzo 18492f345d8eSLuigi Rizzo return; 18502f345d8eSLuigi Rizzo } 18512f345d8eSLuigi Rizzo 18522f345d8eSLuigi Rizzo 18532f345d8eSLuigi Rizzo static int 18542f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc) 18552f345d8eSLuigi Rizzo { 18562f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL; 18572f345d8eSLuigi Rizzo int i = 0, rc = 0; 18582f345d8eSLuigi Rizzo 18592f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) { 18602f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro; 18612f345d8eSLuigi Rizzo rc = tcp_lro_init(lro); 18622f345d8eSLuigi Rizzo if (rc != 0) { 18632f345d8eSLuigi Rizzo device_printf(sc->dev, "LRO init failed\n"); 18642f345d8eSLuigi Rizzo return rc; 18652f345d8eSLuigi Rizzo } 18662f345d8eSLuigi Rizzo lro->ifp = sc->ifp; 18672f345d8eSLuigi Rizzo } 18682f345d8eSLuigi Rizzo 18692f345d8eSLuigi Rizzo return rc; 18702f345d8eSLuigi Rizzo } 18719bd3250aSLuigi Rizzo 18722f345d8eSLuigi Rizzo 18732f345d8eSLuigi Rizzo void 18742f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc) 18752f345d8eSLuigi Rizzo { 18762f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL; 18772f345d8eSLuigi Rizzo int i = 0; 18782f345d8eSLuigi Rizzo 18792f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) { 18802f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro; 18812f345d8eSLuigi Rizzo if (lro) 18822f345d8eSLuigi Rizzo tcp_lro_free(lro); 18832f345d8eSLuigi Rizzo } 18842f345d8eSLuigi Rizzo } 1885cdaba892SXin LI #endif 18862f345d8eSLuigi Rizzo 18872f345d8eSLuigi Rizzo int 18882f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count) 18892f345d8eSLuigi Rizzo { 18902f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent; 18912f345d8eSLuigi Rizzo int i, in, rc; 18922f345d8eSLuigi Rizzo struct oce_packet_desc *pd; 18932f345d8eSLuigi Rizzo bus_dma_segment_t segs[6]; 18942f345d8eSLuigi Rizzo int nsegs, added = 0; 18952f345d8eSLuigi Rizzo struct oce_nic_rqe *rqe; 18962f345d8eSLuigi Rizzo pd_rxulp_db_t rxdb_reg; 1897*764c812dSJosh Paetzel uint32_t val = 0; 1898*764c812dSJosh Paetzel uint32_t oce_max_rq_posts = 64; 18992f345d8eSLuigi Rizzo 1900cdaba892SXin LI bzero(&rxdb_reg, sizeof(pd_rxulp_db_t)); 19012f345d8eSLuigi Rizzo for (i = 0; i < count; i++) { 1902*764c812dSJosh Paetzel in = (rq->ring->pidx + 1) % OCE_RQ_PACKET_ARRAY_SIZE; 19032f345d8eSLuigi Rizzo 1904*764c812dSJosh Paetzel pd = &rq->pckts[rq->ring->pidx]; 1905*764c812dSJosh Paetzel pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size); 1906*764c812dSJosh Paetzel if (pd->mbuf == NULL) { 1907*764c812dSJosh Paetzel device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size); 19082f345d8eSLuigi Rizzo break; 1909*764c812dSJosh Paetzel } 1910*764c812dSJosh Paetzel pd->mbuf->m_nextpkt = NULL; 19112f345d8eSLuigi Rizzo 1912*764c812dSJosh Paetzel pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size; 1913*764c812dSJosh Paetzel 19142f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(rq->tag, 19152f345d8eSLuigi Rizzo pd->map, 19162f345d8eSLuigi Rizzo pd->mbuf, 19172f345d8eSLuigi Rizzo segs, &nsegs, BUS_DMA_NOWAIT); 19182f345d8eSLuigi Rizzo if (rc) { 19192f345d8eSLuigi Rizzo m_free(pd->mbuf); 1920*764c812dSJosh Paetzel device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc); 19212f345d8eSLuigi Rizzo break; 19222f345d8eSLuigi Rizzo } 19232f345d8eSLuigi Rizzo 19242f345d8eSLuigi Rizzo if (nsegs != 1) { 19252f345d8eSLuigi Rizzo i--; 19262f345d8eSLuigi Rizzo continue; 19272f345d8eSLuigi Rizzo } 19282f345d8eSLuigi Rizzo 19292f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD); 19302f345d8eSLuigi Rizzo 19312f345d8eSLuigi Rizzo rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe); 19322f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr); 19332f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr); 19342f345d8eSLuigi Rizzo DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe)); 19352f345d8eSLuigi Rizzo RING_PUT(rq->ring, 1); 19362f345d8eSLuigi Rizzo added++; 19372f345d8eSLuigi Rizzo rq->pending++; 19382f345d8eSLuigi Rizzo } 1939*764c812dSJosh Paetzel oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS; 19402f345d8eSLuigi Rizzo if (added != 0) { 1941*764c812dSJosh Paetzel for (i = added / oce_max_rq_posts; i > 0; i--) { 1942*764c812dSJosh Paetzel rxdb_reg.bits.num_posted = oce_max_rq_posts; 19432f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id; 1944*764c812dSJosh Paetzel if(rq->islro) { 1945*764c812dSJosh Paetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK; 1946*764c812dSJosh Paetzel val |= oce_max_rq_posts << 16; 1947*764c812dSJosh Paetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val); 1948*764c812dSJosh Paetzel }else { 19492f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 1950*764c812dSJosh Paetzel } 1951*764c812dSJosh Paetzel added -= oce_max_rq_posts; 19522f345d8eSLuigi Rizzo } 19532f345d8eSLuigi Rizzo if (added > 0) { 19542f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id; 19552f345d8eSLuigi Rizzo rxdb_reg.bits.num_posted = added; 1956*764c812dSJosh Paetzel if(rq->islro) { 1957*764c812dSJosh Paetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK; 1958*764c812dSJosh Paetzel val |= added << 16; 1959*764c812dSJosh Paetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val); 1960*764c812dSJosh Paetzel }else { 19612f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0); 19622f345d8eSLuigi Rizzo } 19632f345d8eSLuigi Rizzo } 1964*764c812dSJosh Paetzel } 19652f345d8eSLuigi Rizzo 19662f345d8eSLuigi Rizzo return 0; 19672f345d8eSLuigi Rizzo } 19682f345d8eSLuigi Rizzo 1969*764c812dSJosh Paetzel static void 1970*764c812dSJosh Paetzel oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq) 1971*764c812dSJosh Paetzel { 1972*764c812dSJosh Paetzel if (num_cqes) { 1973*764c812dSJosh Paetzel oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE); 1974*764c812dSJosh Paetzel if(!sc->enable_hwlro) { 1975*764c812dSJosh Paetzel if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1) 1976*764c812dSJosh Paetzel oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1)); 1977*764c812dSJosh Paetzel }else { 1978*764c812dSJosh Paetzel if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64) 1979*764c812dSJosh Paetzel oce_alloc_rx_bufs(rq, 64); 1980*764c812dSJosh Paetzel } 1981*764c812dSJosh Paetzel } 1982*764c812dSJosh Paetzel 1983*764c812dSJosh Paetzel return; 1984*764c812dSJosh Paetzel } 1985*764c812dSJosh Paetzel 1986*764c812dSJosh Paetzel uint16_t 1987*764c812dSJosh Paetzel oce_rq_handler_lro(void *arg) 1988*764c812dSJosh Paetzel { 1989*764c812dSJosh Paetzel struct oce_rq *rq = (struct oce_rq *)arg; 1990*764c812dSJosh Paetzel struct oce_cq *cq = rq->cq; 1991*764c812dSJosh Paetzel POCE_SOFTC sc = rq->parent; 1992*764c812dSJosh Paetzel struct nic_hwlro_singleton_cqe *cqe; 1993*764c812dSJosh Paetzel struct nic_hwlro_cqe_part2 *cqe2; 1994*764c812dSJosh Paetzel int num_cqes = 0; 1995*764c812dSJosh Paetzel 1996*764c812dSJosh Paetzel LOCK(&rq->rx_lock); 1997*764c812dSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 1998*764c812dSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 1999*764c812dSJosh Paetzel while (cqe->valid) { 2000*764c812dSJosh Paetzel if(cqe->cqe_type == 0) { /* singleton cqe */ 2001*764c812dSJosh Paetzel /* we should not get singleton cqe after cqe1 on same rq */ 2002*764c812dSJosh Paetzel if(rq->cqe_firstpart != NULL) { 2003*764c812dSJosh Paetzel device_printf(sc->dev, "Got singleton cqe after cqe1 \n"); 2004*764c812dSJosh Paetzel goto exit_rq_handler_lro; 2005*764c812dSJosh Paetzel } 2006*764c812dSJosh Paetzel if(cqe->error != 0) { 2007*764c812dSJosh Paetzel rq->rx_stats.rxcp_err++; 2008*764c812dSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2009*764c812dSJosh Paetzel } 2010*764c812dSJosh Paetzel oce_rx_lro(rq, cqe, NULL); 2011*764c812dSJosh Paetzel rq->rx_stats.rx_compl++; 2012*764c812dSJosh Paetzel cqe->valid = 0; 2013*764c812dSJosh Paetzel RING_GET(cq->ring, 1); 2014*764c812dSJosh Paetzel num_cqes++; 2015*764c812dSJosh Paetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2016*764c812dSJosh Paetzel break; 2017*764c812dSJosh Paetzel }else if(cqe->cqe_type == 0x1) { /* first part */ 2018*764c812dSJosh Paetzel /* we should not get cqe1 after cqe1 on same rq */ 2019*764c812dSJosh Paetzel if(rq->cqe_firstpart != NULL) { 2020*764c812dSJosh Paetzel device_printf(sc->dev, "Got cqe1 after cqe1 \n"); 2021*764c812dSJosh Paetzel goto exit_rq_handler_lro; 2022*764c812dSJosh Paetzel } 2023*764c812dSJosh Paetzel rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe; 2024*764c812dSJosh Paetzel RING_GET(cq->ring, 1); 2025*764c812dSJosh Paetzel }else if(cqe->cqe_type == 0x2) { /* second part */ 2026*764c812dSJosh Paetzel cqe2 = (struct nic_hwlro_cqe_part2 *)cqe; 2027*764c812dSJosh Paetzel if(cqe2->error != 0) { 2028*764c812dSJosh Paetzel rq->rx_stats.rxcp_err++; 2029*764c812dSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 2030*764c812dSJosh Paetzel } 2031*764c812dSJosh Paetzel /* We should not get cqe2 without cqe1 */ 2032*764c812dSJosh Paetzel if(rq->cqe_firstpart == NULL) { 2033*764c812dSJosh Paetzel device_printf(sc->dev, "Got cqe2 without cqe1 \n"); 2034*764c812dSJosh Paetzel goto exit_rq_handler_lro; 2035*764c812dSJosh Paetzel } 2036*764c812dSJosh Paetzel oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2); 2037*764c812dSJosh Paetzel 2038*764c812dSJosh Paetzel rq->rx_stats.rx_compl++; 2039*764c812dSJosh Paetzel rq->cqe_firstpart->valid = 0; 2040*764c812dSJosh Paetzel cqe2->valid = 0; 2041*764c812dSJosh Paetzel rq->cqe_firstpart = NULL; 2042*764c812dSJosh Paetzel 2043*764c812dSJosh Paetzel RING_GET(cq->ring, 1); 2044*764c812dSJosh Paetzel num_cqes += 2; 2045*764c812dSJosh Paetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 2046*764c812dSJosh Paetzel break; 2047*764c812dSJosh Paetzel } 2048*764c812dSJosh Paetzel 2049*764c812dSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 2050*764c812dSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe); 2051*764c812dSJosh Paetzel } 2052*764c812dSJosh Paetzel oce_check_rx_bufs(sc, num_cqes, rq); 2053*764c812dSJosh Paetzel exit_rq_handler_lro: 2054*764c812dSJosh Paetzel UNLOCK(&rq->rx_lock); 2055*764c812dSJosh Paetzel return 0; 2056*764c812dSJosh Paetzel } 20572f345d8eSLuigi Rizzo 20582f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */ 20592f345d8eSLuigi Rizzo uint16_t 20602f345d8eSLuigi Rizzo oce_rq_handler(void *arg) 20612f345d8eSLuigi Rizzo { 20622f345d8eSLuigi Rizzo struct oce_rq *rq = (struct oce_rq *)arg; 20632f345d8eSLuigi Rizzo struct oce_cq *cq = rq->cq; 20642f345d8eSLuigi Rizzo POCE_SOFTC sc = rq->parent; 20652f345d8eSLuigi Rizzo struct oce_nic_rx_cqe *cqe; 2066*764c812dSJosh Paetzel int num_cqes = 0; 20672f345d8eSLuigi Rizzo 2068*764c812dSJosh Paetzel if(rq->islro) { 2069*764c812dSJosh Paetzel oce_rq_handler_lro(arg); 2070*764c812dSJosh Paetzel return 0; 2071*764c812dSJosh Paetzel } 2072*764c812dSJosh Paetzel LOCK(&rq->rx_lock); 20732f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 20742f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 20752f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 20762f345d8eSLuigi Rizzo while (cqe->u0.dw[2]) { 20772f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe)); 20782f345d8eSLuigi Rizzo 20792f345d8eSLuigi Rizzo if (cqe->u0.s.error == 0) { 2080*764c812dSJosh Paetzel oce_rx(rq, cqe); 20812f345d8eSLuigi Rizzo } else { 20822f345d8eSLuigi Rizzo rq->rx_stats.rxcp_err++; 2083c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1); 20842f345d8eSLuigi Rizzo /* Post L3/L4 errors to stack.*/ 2085*764c812dSJosh Paetzel oce_rx(rq, cqe); 20862f345d8eSLuigi Rizzo } 20872f345d8eSLuigi Rizzo rq->rx_stats.rx_compl++; 20882f345d8eSLuigi Rizzo cqe->u0.dw[2] = 0; 20892f345d8eSLuigi Rizzo 2090ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 20912f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) { 20922f345d8eSLuigi Rizzo oce_rx_flush_lro(rq); 20932f345d8eSLuigi Rizzo } 2094ad512958SBjoern A. Zeeb #endif 20952f345d8eSLuigi Rizzo 20962f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 20972f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 20982f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 20992f345d8eSLuigi Rizzo cqe = 21002f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe); 21012f345d8eSLuigi Rizzo num_cqes++; 21022f345d8eSLuigi Rizzo if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled)) 21032f345d8eSLuigi Rizzo break; 21042f345d8eSLuigi Rizzo } 21059bd3250aSLuigi Rizzo 2106ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 21072f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc)) 21082f345d8eSLuigi Rizzo oce_rx_flush_lro(rq); 2109ad512958SBjoern A. Zeeb #endif 21102f345d8eSLuigi Rizzo 2111*764c812dSJosh Paetzel oce_check_rx_bufs(sc, num_cqes, rq); 2112*764c812dSJosh Paetzel UNLOCK(&rq->rx_lock); 21132f345d8eSLuigi Rizzo return 0; 21142f345d8eSLuigi Rizzo 21152f345d8eSLuigi Rizzo } 21162f345d8eSLuigi Rizzo 21172f345d8eSLuigi Rizzo 21182f345d8eSLuigi Rizzo 21192f345d8eSLuigi Rizzo 21202f345d8eSLuigi Rizzo /***************************************************************************** 21212f345d8eSLuigi Rizzo * Helper function prototypes in this file * 21222f345d8eSLuigi Rizzo *****************************************************************************/ 21232f345d8eSLuigi Rizzo 21242f345d8eSLuigi Rizzo static int 21252f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc) 21262f345d8eSLuigi Rizzo { 21272f345d8eSLuigi Rizzo 21282f345d8eSLuigi Rizzo sc->ifp = if_alloc(IFT_ETHER); 21292f345d8eSLuigi Rizzo if (!sc->ifp) 21302f345d8eSLuigi Rizzo return ENOMEM; 21312f345d8eSLuigi Rizzo 21322f345d8eSLuigi Rizzo ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status); 21332f345d8eSLuigi Rizzo ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL); 21342f345d8eSLuigi Rizzo ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO); 21352f345d8eSLuigi Rizzo 21362f345d8eSLuigi Rizzo sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 21372f345d8eSLuigi Rizzo sc->ifp->if_ioctl = oce_ioctl; 21382f345d8eSLuigi Rizzo sc->ifp->if_start = oce_start; 21392f345d8eSLuigi Rizzo sc->ifp->if_init = oce_init; 21402f345d8eSLuigi Rizzo sc->ifp->if_mtu = ETHERMTU; 21412f345d8eSLuigi Rizzo sc->ifp->if_softc = sc; 21422f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000 21432f345d8eSLuigi Rizzo sc->ifp->if_transmit = oce_multiq_start; 21442f345d8eSLuigi Rizzo sc->ifp->if_qflush = oce_multiq_flush; 21452f345d8eSLuigi Rizzo #endif 21462f345d8eSLuigi Rizzo 21472f345d8eSLuigi Rizzo if_initname(sc->ifp, 21482f345d8eSLuigi Rizzo device_get_name(sc->dev), device_get_unit(sc->dev)); 21492f345d8eSLuigi Rizzo 21502f345d8eSLuigi Rizzo sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1; 21512f345d8eSLuigi Rizzo IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen); 21522f345d8eSLuigi Rizzo IFQ_SET_READY(&sc->ifp->if_snd); 21532f345d8eSLuigi Rizzo 21542f345d8eSLuigi Rizzo sc->ifp->if_hwassist = OCE_IF_HWASSIST; 21552f345d8eSLuigi Rizzo sc->ifp->if_hwassist |= CSUM_TSO; 21562f345d8eSLuigi Rizzo sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP); 21572f345d8eSLuigi Rizzo 21582f345d8eSLuigi Rizzo sc->ifp->if_capabilities = OCE_IF_CAPABILITIES; 21592f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_HWCSUM; 21602f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; 21619bd3250aSLuigi Rizzo 2162ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET) 2163ad512958SBjoern A. Zeeb sc->ifp->if_capabilities |= IFCAP_TSO; 21642f345d8eSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_LRO; 21659bd3250aSLuigi Rizzo sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 2166ad512958SBjoern A. Zeeb #endif 21672f345d8eSLuigi Rizzo 21682f345d8eSLuigi Rizzo sc->ifp->if_capenable = sc->ifp->if_capabilities; 2169b245f96cSGleb Smirnoff sc->ifp->if_baudrate = IF_Gbps(10); 21702f345d8eSLuigi Rizzo 21715fbb6830SXin LI #if __FreeBSD_version >= 1000000 21729fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 21739fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomaxsegcount = OCE_MAX_TX_ELEMENTS; 21749fd573c3SHans Petter Selasky sc->ifp->if_hw_tsomaxsegsize = 4096; 21755fbb6830SXin LI #endif 21765fbb6830SXin LI 21772f345d8eSLuigi Rizzo ether_ifattach(sc->ifp, sc->macaddr.mac_addr); 21782f345d8eSLuigi Rizzo 21792f345d8eSLuigi Rizzo return 0; 21802f345d8eSLuigi Rizzo } 21812f345d8eSLuigi Rizzo 21822f345d8eSLuigi Rizzo 21832f345d8eSLuigi Rizzo static void 21842f345d8eSLuigi Rizzo oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 21852f345d8eSLuigi Rizzo { 21862f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 21872f345d8eSLuigi Rizzo 21882f345d8eSLuigi Rizzo if (ifp->if_softc != arg) 21892f345d8eSLuigi Rizzo return; 21902f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095)) 21912f345d8eSLuigi Rizzo return; 21922f345d8eSLuigi Rizzo 21932f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 1; 21942f345d8eSLuigi Rizzo sc->vlans_added++; 21955fbb6830SXin LI if (sc->vlans_added <= (sc->max_vlans + 1)) 21962f345d8eSLuigi Rizzo oce_vid_config(sc); 21972f345d8eSLuigi Rizzo } 21982f345d8eSLuigi Rizzo 21992f345d8eSLuigi Rizzo 22002f345d8eSLuigi Rizzo static void 22012f345d8eSLuigi Rizzo oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag) 22022f345d8eSLuigi Rizzo { 22032f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 22042f345d8eSLuigi Rizzo 22052f345d8eSLuigi Rizzo if (ifp->if_softc != arg) 22062f345d8eSLuigi Rizzo return; 22072f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095)) 22082f345d8eSLuigi Rizzo return; 22092f345d8eSLuigi Rizzo 22102f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 0; 22112f345d8eSLuigi Rizzo sc->vlans_added--; 22122f345d8eSLuigi Rizzo oce_vid_config(sc); 22132f345d8eSLuigi Rizzo } 22142f345d8eSLuigi Rizzo 22152f345d8eSLuigi Rizzo 22162f345d8eSLuigi Rizzo /* 22172f345d8eSLuigi Rizzo * A max of 64 vlans can be configured in BE. If the user configures 22182f345d8eSLuigi Rizzo * more, place the card in vlan promiscuous mode. 22192f345d8eSLuigi Rizzo */ 22202f345d8eSLuigi Rizzo static int 22212f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc) 22222f345d8eSLuigi Rizzo { 22232f345d8eSLuigi Rizzo struct normal_vlan vtags[MAX_VLANFILTER_SIZE]; 22242f345d8eSLuigi Rizzo uint16_t ntags = 0, i; 22252f345d8eSLuigi Rizzo int status = 0; 22262f345d8eSLuigi Rizzo 22272f345d8eSLuigi Rizzo if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) && 22282f345d8eSLuigi Rizzo (sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) { 22292f345d8eSLuigi Rizzo for (i = 0; i < MAX_VLANS; i++) { 22302f345d8eSLuigi Rizzo if (sc->vlan_tag[i]) { 22312f345d8eSLuigi Rizzo vtags[ntags].vtag = i; 22322f345d8eSLuigi Rizzo ntags++; 22332f345d8eSLuigi Rizzo } 22342f345d8eSLuigi Rizzo } 22352f345d8eSLuigi Rizzo if (ntags) 22362f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id, 22372f345d8eSLuigi Rizzo vtags, ntags, 1, 0); 22382f345d8eSLuigi Rizzo } else 22392f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id, 22402f345d8eSLuigi Rizzo NULL, 0, 1, 1); 22412f345d8eSLuigi Rizzo return status; 22422f345d8eSLuigi Rizzo } 22432f345d8eSLuigi Rizzo 22442f345d8eSLuigi Rizzo 22452f345d8eSLuigi Rizzo static void 22462f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc) 22472f345d8eSLuigi Rizzo { 22482f345d8eSLuigi Rizzo uint32_t old_pmac_id = sc->pmac_id; 22492f345d8eSLuigi Rizzo int status = 0; 22502f345d8eSLuigi Rizzo 22512f345d8eSLuigi Rizzo 22522f345d8eSLuigi Rizzo status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 22532f345d8eSLuigi Rizzo sc->macaddr.size_of_struct); 22542f345d8eSLuigi Rizzo if (!status) 22552f345d8eSLuigi Rizzo return; 22562f345d8eSLuigi Rizzo 22572f345d8eSLuigi Rizzo status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)), 22582f345d8eSLuigi Rizzo sc->if_id, &sc->pmac_id); 22592f345d8eSLuigi Rizzo if (!status) { 22602f345d8eSLuigi Rizzo status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id); 22612f345d8eSLuigi Rizzo bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr, 22622f345d8eSLuigi Rizzo sc->macaddr.size_of_struct); 22632f345d8eSLuigi Rizzo } 22642f345d8eSLuigi Rizzo if (status) 22652f345d8eSLuigi Rizzo device_printf(sc->dev, "Failed update macaddress\n"); 22662f345d8eSLuigi Rizzo 22672f345d8eSLuigi Rizzo } 22682f345d8eSLuigi Rizzo 22692f345d8eSLuigi Rizzo 22702f345d8eSLuigi Rizzo static int 22712f345d8eSLuigi Rizzo oce_handle_passthrough(struct ifnet *ifp, caddr_t data) 22722f345d8eSLuigi Rizzo { 22732f345d8eSLuigi Rizzo POCE_SOFTC sc = ifp->if_softc; 22742f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data; 22752f345d8eSLuigi Rizzo int rc = ENXIO; 22762f345d8eSLuigi Rizzo char cookie[32] = {0}; 22772f345d8eSLuigi Rizzo void *priv_data = (void *)ifr->ifr_data; 22782f345d8eSLuigi Rizzo void *ioctl_ptr; 22792f345d8eSLuigi Rizzo uint32_t req_size; 22802f345d8eSLuigi Rizzo struct mbx_hdr req; 22812f345d8eSLuigi Rizzo OCE_DMA_MEM dma_mem; 2282cdaba892SXin LI struct mbx_common_get_cntl_attr *fw_cmd; 22832f345d8eSLuigi Rizzo 22842f345d8eSLuigi Rizzo if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE))) 22852f345d8eSLuigi Rizzo return EFAULT; 22862f345d8eSLuigi Rizzo 22872f345d8eSLuigi Rizzo if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE))) 22882f345d8eSLuigi Rizzo return EINVAL; 22892f345d8eSLuigi Rizzo 22902f345d8eSLuigi Rizzo ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE); 22912f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr))) 22922f345d8eSLuigi Rizzo return EFAULT; 22932f345d8eSLuigi Rizzo 22942f345d8eSLuigi Rizzo req_size = le32toh(req.u0.req.request_length); 22952f345d8eSLuigi Rizzo if (req_size > 65536) 22962f345d8eSLuigi Rizzo return EINVAL; 22972f345d8eSLuigi Rizzo 22982f345d8eSLuigi Rizzo req_size += sizeof(struct mbx_hdr); 22992f345d8eSLuigi Rizzo rc = oce_dma_alloc(sc, req_size, &dma_mem, 0); 23002f345d8eSLuigi Rizzo if (rc) 23012f345d8eSLuigi Rizzo return ENOMEM; 23022f345d8eSLuigi Rizzo 23032f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) { 23042f345d8eSLuigi Rizzo rc = EFAULT; 23052f345d8eSLuigi Rizzo goto dma_free; 23062f345d8eSLuigi Rizzo } 23072f345d8eSLuigi Rizzo 23082f345d8eSLuigi Rizzo rc = oce_pass_through_mbox(sc, &dma_mem, req_size); 23092f345d8eSLuigi Rizzo if (rc) { 23102f345d8eSLuigi Rizzo rc = EIO; 23112f345d8eSLuigi Rizzo goto dma_free; 23122f345d8eSLuigi Rizzo } 23132f345d8eSLuigi Rizzo 23142f345d8eSLuigi Rizzo if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) 23152f345d8eSLuigi Rizzo rc = EFAULT; 23162f345d8eSLuigi Rizzo 2317cdaba892SXin LI /* 2318cdaba892SXin LI firmware is filling all the attributes for this ioctl except 2319cdaba892SXin LI the driver version..so fill it 2320cdaba892SXin LI */ 2321cdaba892SXin LI if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) { 2322cdaba892SXin LI fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr; 2323cdaba892SXin LI strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str, 2324cdaba892SXin LI COMPONENT_REVISION, strlen(COMPONENT_REVISION)); 2325cdaba892SXin LI } 2326cdaba892SXin LI 23272f345d8eSLuigi Rizzo dma_free: 23282f345d8eSLuigi Rizzo oce_dma_free(sc, &dma_mem); 23292f345d8eSLuigi Rizzo return rc; 23302f345d8eSLuigi Rizzo 23312f345d8eSLuigi Rizzo } 23322f345d8eSLuigi Rizzo 2333cdaba892SXin LI static void 2334cdaba892SXin LI oce_eqd_set_periodic(POCE_SOFTC sc) 2335cdaba892SXin LI { 2336cdaba892SXin LI struct oce_set_eqd set_eqd[OCE_MAX_EQ]; 2337cdaba892SXin LI struct oce_aic_obj *aic; 2338cdaba892SXin LI struct oce_eq *eqo; 2339cdaba892SXin LI uint64_t now = 0, delta; 2340cdaba892SXin LI int eqd, i, num = 0; 2341*764c812dSJosh Paetzel uint32_t tx_reqs = 0, rxpkts = 0, pps; 2342*764c812dSJosh Paetzel struct oce_wq *wq; 2343*764c812dSJosh Paetzel struct oce_rq *rq; 2344*764c812dSJosh Paetzel 2345*764c812dSJosh Paetzel #define ticks_to_msecs(t) (1000 * (t) / hz) 2346cdaba892SXin LI 2347cdaba892SXin LI for (i = 0 ; i < sc->neqs; i++) { 2348cdaba892SXin LI eqo = sc->eq[i]; 2349cdaba892SXin LI aic = &sc->aic_obj[i]; 2350cdaba892SXin LI /* When setting the static eq delay from the user space */ 2351cdaba892SXin LI if (!aic->enable) { 2352*764c812dSJosh Paetzel if (aic->ticks) 2353*764c812dSJosh Paetzel aic->ticks = 0; 2354cdaba892SXin LI eqd = aic->et_eqd; 2355cdaba892SXin LI goto modify_eqd; 2356cdaba892SXin LI } 2357cdaba892SXin LI 2358*764c812dSJosh Paetzel rq = sc->rq[i]; 2359*764c812dSJosh Paetzel rxpkts = rq->rx_stats.rx_pkts; 2360*764c812dSJosh Paetzel wq = sc->wq[i]; 2361*764c812dSJosh Paetzel tx_reqs = wq->tx_stats.tx_reqs; 2362cdaba892SXin LI now = ticks; 2363cdaba892SXin LI 2364*764c812dSJosh Paetzel if (!aic->ticks || now < aic->ticks || 2365*764c812dSJosh Paetzel rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) { 2366*764c812dSJosh Paetzel aic->prev_rxpkts = rxpkts; 2367*764c812dSJosh Paetzel aic->prev_txreqs = tx_reqs; 2368*764c812dSJosh Paetzel aic->ticks = now; 2369*764c812dSJosh Paetzel continue; 2370*764c812dSJosh Paetzel } 2371cdaba892SXin LI 2372*764c812dSJosh Paetzel delta = ticks_to_msecs(now - aic->ticks); 2373cdaba892SXin LI 2374*764c812dSJosh Paetzel pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) + 2375*764c812dSJosh Paetzel (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta); 2376*764c812dSJosh Paetzel eqd = (pps / 15000) << 2; 2377*764c812dSJosh Paetzel if (eqd < 8) 2378cdaba892SXin LI eqd = 0; 2379cdaba892SXin LI 2380cdaba892SXin LI /* Make sure that the eq delay is in the known range */ 2381cdaba892SXin LI eqd = min(eqd, aic->max_eqd); 2382cdaba892SXin LI eqd = max(eqd, aic->min_eqd); 2383cdaba892SXin LI 2384*764c812dSJosh Paetzel aic->prev_rxpkts = rxpkts; 2385*764c812dSJosh Paetzel aic->prev_txreqs = tx_reqs; 2386*764c812dSJosh Paetzel aic->ticks = now; 2387*764c812dSJosh Paetzel 2388cdaba892SXin LI modify_eqd: 2389cdaba892SXin LI if (eqd != aic->cur_eqd) { 2390cdaba892SXin LI set_eqd[num].delay_multiplier = (eqd * 65)/100; 2391cdaba892SXin LI set_eqd[num].eq_id = eqo->eq_id; 2392cdaba892SXin LI aic->cur_eqd = eqd; 2393cdaba892SXin LI num++; 2394cdaba892SXin LI } 2395cdaba892SXin LI } 2396cdaba892SXin LI 2397cdaba892SXin LI /* Is there atleast one eq that needs to be modified? */ 2398*764c812dSJosh Paetzel for(i = 0; i < num; i += 8) { 2399*764c812dSJosh Paetzel if((num - i) >=8 ) 2400*764c812dSJosh Paetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8); 2401*764c812dSJosh Paetzel else 2402*764c812dSJosh Paetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i)); 2403*764c812dSJosh Paetzel } 2404*764c812dSJosh Paetzel 2405cdaba892SXin LI } 24062f345d8eSLuigi Rizzo 24075fbb6830SXin LI static void oce_detect_hw_error(POCE_SOFTC sc) 24085fbb6830SXin LI { 24095fbb6830SXin LI 24105fbb6830SXin LI uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0; 24115fbb6830SXin LI uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; 24125fbb6830SXin LI uint32_t i; 24135fbb6830SXin LI 24145fbb6830SXin LI if (sc->hw_error) 24155fbb6830SXin LI return; 24165fbb6830SXin LI 24175fbb6830SXin LI if (IS_XE201(sc)) { 24185fbb6830SXin LI sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET); 24195fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24205fbb6830SXin LI sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET); 24215fbb6830SXin LI sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET); 24225fbb6830SXin LI } 24235fbb6830SXin LI } else { 24245fbb6830SXin LI ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW); 24255fbb6830SXin LI ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH); 24265fbb6830SXin LI ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK); 24275fbb6830SXin LI ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK); 24285fbb6830SXin LI 24295fbb6830SXin LI ue_low = (ue_low & ~ue_low_mask); 24305fbb6830SXin LI ue_high = (ue_high & ~ue_high_mask); 24315fbb6830SXin LI } 24325fbb6830SXin LI 24335fbb6830SXin LI /* On certain platforms BE hardware can indicate spurious UEs. 24345fbb6830SXin LI * Allow the h/w to stop working completely in case of a real UE. 24355fbb6830SXin LI * Hence not setting the hw_error for UE detection. 24365fbb6830SXin LI */ 24375fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24385fbb6830SXin LI sc->hw_error = TRUE; 24395fbb6830SXin LI device_printf(sc->dev, "Error detected in the card\n"); 24405fbb6830SXin LI } 24415fbb6830SXin LI 24425fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) { 24435fbb6830SXin LI device_printf(sc->dev, 24445fbb6830SXin LI "ERR: sliport status 0x%x\n", sliport_status); 24455fbb6830SXin LI device_printf(sc->dev, 24465fbb6830SXin LI "ERR: sliport error1 0x%x\n", sliport_err1); 24475fbb6830SXin LI device_printf(sc->dev, 24485fbb6830SXin LI "ERR: sliport error2 0x%x\n", sliport_err2); 24495fbb6830SXin LI } 24505fbb6830SXin LI 24515fbb6830SXin LI if (ue_low) { 24525fbb6830SXin LI for (i = 0; ue_low; ue_low >>= 1, i++) { 24535fbb6830SXin LI if (ue_low & 1) 24545fbb6830SXin LI device_printf(sc->dev, "UE: %s bit set\n", 24555fbb6830SXin LI ue_status_low_desc[i]); 24565fbb6830SXin LI } 24575fbb6830SXin LI } 24585fbb6830SXin LI 24595fbb6830SXin LI if (ue_high) { 24605fbb6830SXin LI for (i = 0; ue_high; ue_high >>= 1, i++) { 24615fbb6830SXin LI if (ue_high & 1) 24625fbb6830SXin LI device_printf(sc->dev, "UE: %s bit set\n", 24635fbb6830SXin LI ue_status_hi_desc[i]); 24645fbb6830SXin LI } 24655fbb6830SXin LI } 24665fbb6830SXin LI 24675fbb6830SXin LI } 24685fbb6830SXin LI 24695fbb6830SXin LI 24702f345d8eSLuigi Rizzo static void 24712f345d8eSLuigi Rizzo oce_local_timer(void *arg) 24722f345d8eSLuigi Rizzo { 24732f345d8eSLuigi Rizzo POCE_SOFTC sc = arg; 24742f345d8eSLuigi Rizzo int i = 0; 24752f345d8eSLuigi Rizzo 24765fbb6830SXin LI oce_detect_hw_error(sc); 24772f345d8eSLuigi Rizzo oce_refresh_nic_stats(sc); 24782f345d8eSLuigi Rizzo oce_refresh_queue_stats(sc); 24792f345d8eSLuigi Rizzo oce_mac_addr_set(sc); 24802f345d8eSLuigi Rizzo 24812f345d8eSLuigi Rizzo /* TX Watch Dog*/ 24822f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) 24832f345d8eSLuigi Rizzo oce_tx_restart(sc, sc->wq[i]); 24842f345d8eSLuigi Rizzo 2485cdaba892SXin LI /* calculate and set the eq delay for optimal interrupt rate */ 2486291a1934SXin LI if (IS_BE(sc) || IS_SH(sc)) 2487cdaba892SXin LI oce_eqd_set_periodic(sc); 2488cdaba892SXin LI 24892f345d8eSLuigi Rizzo callout_reset(&sc->timer, hz, oce_local_timer, sc); 24902f345d8eSLuigi Rizzo } 24912f345d8eSLuigi Rizzo 2492*764c812dSJosh Paetzel static void 2493*764c812dSJosh Paetzel oce_tx_compl_clean(POCE_SOFTC sc) 2494*764c812dSJosh Paetzel { 2495*764c812dSJosh Paetzel struct oce_wq *wq; 2496*764c812dSJosh Paetzel int i = 0, timeo = 0, num_wqes = 0; 2497*764c812dSJosh Paetzel int pending_txqs = sc->nwqs; 2498*764c812dSJosh Paetzel 2499*764c812dSJosh Paetzel /* Stop polling for compls when HW has been silent for 10ms or 2500*764c812dSJosh Paetzel * hw_error or no outstanding completions expected 2501*764c812dSJosh Paetzel */ 2502*764c812dSJosh Paetzel do { 2503*764c812dSJosh Paetzel pending_txqs = sc->nwqs; 2504*764c812dSJosh Paetzel 2505*764c812dSJosh Paetzel for_all_wq_queues(sc, wq, i) { 2506*764c812dSJosh Paetzel num_wqes = oce_wq_handler(wq); 2507*764c812dSJosh Paetzel 2508*764c812dSJosh Paetzel if(num_wqes) 2509*764c812dSJosh Paetzel timeo = 0; 2510*764c812dSJosh Paetzel 2511*764c812dSJosh Paetzel if(!wq->ring->num_used) 2512*764c812dSJosh Paetzel pending_txqs--; 2513*764c812dSJosh Paetzel } 2514*764c812dSJosh Paetzel 2515*764c812dSJosh Paetzel if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error) 2516*764c812dSJosh Paetzel break; 2517*764c812dSJosh Paetzel 2518*764c812dSJosh Paetzel DELAY(1000); 2519*764c812dSJosh Paetzel } while (TRUE); 2520*764c812dSJosh Paetzel 2521*764c812dSJosh Paetzel for_all_wq_queues(sc, wq, i) { 2522*764c812dSJosh Paetzel while(wq->ring->num_used) { 2523*764c812dSJosh Paetzel LOCK(&wq->tx_compl_lock); 2524*764c812dSJosh Paetzel oce_process_tx_completion(wq); 2525*764c812dSJosh Paetzel UNLOCK(&wq->tx_compl_lock); 2526*764c812dSJosh Paetzel } 2527*764c812dSJosh Paetzel } 2528*764c812dSJosh Paetzel 2529*764c812dSJosh Paetzel } 25302f345d8eSLuigi Rizzo 2531beb0f7e7SJosh Paetzel /* NOTE : This should only be called holding 2532beb0f7e7SJosh Paetzel * DEVICE_LOCK. 2533beb0f7e7SJosh Paetzel */ 25342f345d8eSLuigi Rizzo static void 25352f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc) 25362f345d8eSLuigi Rizzo { 2537*764c812dSJosh Paetzel int i; 25382f345d8eSLuigi Rizzo struct oce_rq *rq; 25392f345d8eSLuigi Rizzo struct oce_wq *wq; 25402f345d8eSLuigi Rizzo struct oce_eq *eq; 25412f345d8eSLuigi Rizzo 25422f345d8eSLuigi Rizzo sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 25432f345d8eSLuigi Rizzo 2544*764c812dSJosh Paetzel oce_tx_compl_clean(sc); 25452f345d8eSLuigi Rizzo 25462f345d8eSLuigi Rizzo /* Stop intrs and finish any bottom halves pending */ 25472f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 25482f345d8eSLuigi Rizzo 2549cdaba892SXin LI /* Since taskqueue_drain takes a Gaint Lock, We should not acquire 2550beb0f7e7SJosh Paetzel any other lock. So unlock device lock and require after 2551beb0f7e7SJosh Paetzel completing taskqueue_drain. 2552beb0f7e7SJosh Paetzel */ 2553beb0f7e7SJosh Paetzel UNLOCK(&sc->dev_lock); 25542f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) { 25552f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) { 25562f345d8eSLuigi Rizzo taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task); 25572f345d8eSLuigi Rizzo } 25582f345d8eSLuigi Rizzo } 2559beb0f7e7SJosh Paetzel LOCK(&sc->dev_lock); 25602f345d8eSLuigi Rizzo 25612f345d8eSLuigi Rizzo /* Delete RX queue in card with flush param */ 25622f345d8eSLuigi Rizzo oce_stop_rx(sc); 25632f345d8eSLuigi Rizzo 25642f345d8eSLuigi Rizzo /* Invalidate any pending cq and eq entries*/ 25652f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) 25662f345d8eSLuigi Rizzo oce_drain_eq(eq); 25672f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) 25682f345d8eSLuigi Rizzo oce_drain_rq_cq(rq); 25692f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) 25702f345d8eSLuigi Rizzo oce_drain_wq_cq(wq); 25712f345d8eSLuigi Rizzo 25722f345d8eSLuigi Rizzo /* But still we need to get MCC aync events. 25732f345d8eSLuigi Rizzo So enable intrs and also arm first EQ 25742f345d8eSLuigi Rizzo */ 25752f345d8eSLuigi Rizzo oce_hw_intr_enable(sc); 25762f345d8eSLuigi Rizzo oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE); 25772f345d8eSLuigi Rizzo 25782f345d8eSLuigi Rizzo DELAY(10); 25792f345d8eSLuigi Rizzo } 25802f345d8eSLuigi Rizzo 25812f345d8eSLuigi Rizzo 25822f345d8eSLuigi Rizzo static void 25832f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc) 25842f345d8eSLuigi Rizzo { 25852f345d8eSLuigi Rizzo struct oce_eq *eq; 25862f345d8eSLuigi Rizzo struct oce_rq *rq; 25872f345d8eSLuigi Rizzo struct oce_wq *wq; 25882f345d8eSLuigi Rizzo int i, rc = 0; 25892f345d8eSLuigi Rizzo 25902f345d8eSLuigi Rizzo sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; 25912f345d8eSLuigi Rizzo 25922f345d8eSLuigi Rizzo oce_hw_intr_disable(sc); 25932f345d8eSLuigi Rizzo 25942f345d8eSLuigi Rizzo oce_start_rx(sc); 25952f345d8eSLuigi Rizzo 25962f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) { 25972f345d8eSLuigi Rizzo rc = oce_start_rq(rq); 25982f345d8eSLuigi Rizzo if (rc) 25992f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start RX\n"); 26002f345d8eSLuigi Rizzo } 26012f345d8eSLuigi Rizzo 26022f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) { 26032f345d8eSLuigi Rizzo rc = oce_start_wq(wq); 26042f345d8eSLuigi Rizzo if (rc) 26052f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start TX\n"); 26062f345d8eSLuigi Rizzo } 26072f345d8eSLuigi Rizzo 26082f345d8eSLuigi Rizzo 26092f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i) 26102f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE); 26112f345d8eSLuigi Rizzo 26122f345d8eSLuigi Rizzo oce_hw_intr_enable(sc); 26132f345d8eSLuigi Rizzo 26142f345d8eSLuigi Rizzo } 26152f345d8eSLuigi Rizzo 26169bd3250aSLuigi Rizzo static void 26179bd3250aSLuigi Rizzo process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe) 26182f345d8eSLuigi Rizzo { 26199bd3250aSLuigi Rizzo /* Update Link status */ 26202f345d8eSLuigi Rizzo if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) == 26212f345d8eSLuigi Rizzo ASYNC_EVENT_LINK_UP) { 26222f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_UP; 26232f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_UP); 26242f345d8eSLuigi Rizzo } else { 26252f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_DOWN; 26262f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_DOWN); 26272f345d8eSLuigi Rizzo } 26289bd3250aSLuigi Rizzo } 26299bd3250aSLuigi Rizzo 26309bd3250aSLuigi Rizzo 2631*764c812dSJosh Paetzel static void oce_async_grp5_osbmc_process(POCE_SOFTC sc, 2632*764c812dSJosh Paetzel struct oce_async_evt_grp5_os2bmc *evt) 2633*764c812dSJosh Paetzel { 2634*764c812dSJosh Paetzel DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc)); 2635*764c812dSJosh Paetzel if (evt->u.s.mgmt_enable) 2636*764c812dSJosh Paetzel sc->flags |= OCE_FLAGS_OS2BMC; 2637*764c812dSJosh Paetzel else 2638*764c812dSJosh Paetzel return; 2639*764c812dSJosh Paetzel 2640*764c812dSJosh Paetzel sc->bmc_filt_mask = evt->u.s.arp_filter; 2641*764c812dSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1); 2642*764c812dSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2); 2643*764c812dSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3); 2644*764c812dSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4); 2645*764c812dSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5); 2646*764c812dSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6); 2647*764c812dSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7); 2648*764c812dSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8); 2649*764c812dSJosh Paetzel } 2650*764c812dSJosh Paetzel 2651*764c812dSJosh Paetzel 2652*764c812dSJosh Paetzel static void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe) 2653*764c812dSJosh Paetzel { 2654*764c812dSJosh Paetzel struct oce_async_event_grp5_pvid_state *gcqe; 2655*764c812dSJosh Paetzel struct oce_async_evt_grp5_os2bmc *bmccqe; 2656*764c812dSJosh Paetzel 2657*764c812dSJosh Paetzel switch (cqe->u0.s.async_type) { 2658*764c812dSJosh Paetzel case ASYNC_EVENT_PVID_STATE: 2659*764c812dSJosh Paetzel /* GRP5 PVID */ 2660*764c812dSJosh Paetzel gcqe = (struct oce_async_event_grp5_pvid_state *)cqe; 2661*764c812dSJosh Paetzel if (gcqe->enabled) 2662*764c812dSJosh Paetzel sc->pvid = gcqe->tag & VLAN_VID_MASK; 2663*764c812dSJosh Paetzel else 2664*764c812dSJosh Paetzel sc->pvid = 0; 2665*764c812dSJosh Paetzel break; 2666*764c812dSJosh Paetzel case ASYNC_EVENT_OS2BMC: 2667*764c812dSJosh Paetzel bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe; 2668*764c812dSJosh Paetzel oce_async_grp5_osbmc_process(sc, bmccqe); 2669*764c812dSJosh Paetzel break; 2670*764c812dSJosh Paetzel default: 2671*764c812dSJosh Paetzel break; 2672*764c812dSJosh Paetzel } 2673*764c812dSJosh Paetzel } 2674*764c812dSJosh Paetzel 26759bd3250aSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */ 26769bd3250aSLuigi Rizzo uint16_t 26779bd3250aSLuigi Rizzo oce_mq_handler(void *arg) 26789bd3250aSLuigi Rizzo { 26799bd3250aSLuigi Rizzo struct oce_mq *mq = (struct oce_mq *)arg; 26809bd3250aSLuigi Rizzo POCE_SOFTC sc = mq->parent; 26819bd3250aSLuigi Rizzo struct oce_cq *cq = mq->cq; 26829bd3250aSLuigi Rizzo int num_cqes = 0, evt_type = 0, optype = 0; 26839bd3250aSLuigi Rizzo struct oce_mq_cqe *cqe; 26849bd3250aSLuigi Rizzo struct oce_async_cqe_link_state *acqe; 2685cdaba892SXin LI struct oce_async_event_qnq *dbgcqe; 26869bd3250aSLuigi Rizzo 26879bd3250aSLuigi Rizzo 26889bd3250aSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 26899bd3250aSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 26909bd3250aSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 26919bd3250aSLuigi Rizzo 26929bd3250aSLuigi Rizzo while (cqe->u0.dw[3]) { 26939bd3250aSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe)); 26949bd3250aSLuigi Rizzo if (cqe->u0.s.async_event) { 26959bd3250aSLuigi Rizzo evt_type = cqe->u0.s.event_type; 26969bd3250aSLuigi Rizzo optype = cqe->u0.s.async_type; 26979bd3250aSLuigi Rizzo if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) { 26989bd3250aSLuigi Rizzo /* Link status evt */ 26999bd3250aSLuigi Rizzo acqe = (struct oce_async_cqe_link_state *)cqe; 27009bd3250aSLuigi Rizzo process_link_state(sc, acqe); 2701*764c812dSJosh Paetzel } else if (evt_type == ASYNC_EVENT_GRP5) { 2702*764c812dSJosh Paetzel oce_process_grp5_events(sc, cqe); 2703*764c812dSJosh Paetzel } else if (evt_type == ASYNC_EVENT_CODE_DEBUG && 2704cdaba892SXin LI optype == ASYNC_EVENT_DEBUG_QNQ) { 2705*764c812dSJosh Paetzel dbgcqe = (struct oce_async_event_qnq *)cqe; 2706cdaba892SXin LI if(dbgcqe->valid) 2707cdaba892SXin LI sc->qnqid = dbgcqe->vlan_tag; 2708cdaba892SXin LI sc->qnq_debug_event = TRUE; 2709cdaba892SXin LI } 27102f345d8eSLuigi Rizzo } 27112f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0; 27122f345d8eSLuigi Rizzo RING_GET(cq->ring, 1); 27132f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag, 27142f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE); 27152f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe); 27162f345d8eSLuigi Rizzo num_cqes++; 27172f345d8eSLuigi Rizzo } 27182f345d8eSLuigi Rizzo 27192f345d8eSLuigi Rizzo if (num_cqes) 27202f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE); 27212f345d8eSLuigi Rizzo 27222f345d8eSLuigi Rizzo return 0; 27232f345d8eSLuigi Rizzo } 27242f345d8eSLuigi Rizzo 27252f345d8eSLuigi Rizzo 27262f345d8eSLuigi Rizzo static void 27272f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc) 27282f345d8eSLuigi Rizzo { 27292f345d8eSLuigi Rizzo /* Check if it is FLEX machine. Is so dont use RSS */ 27302f345d8eSLuigi Rizzo if ((sc->function_mode & FNM_FLEX10_MODE) || 27319bd3250aSLuigi Rizzo (sc->function_mode & FNM_UMC_MODE) || 27329bd3250aSLuigi Rizzo (sc->function_mode & FNM_VNIC_MODE) || 2733291a1934SXin LI (!is_rss_enabled(sc)) || 2734a4f734b4SXin LI IS_BE2(sc)) { 27352f345d8eSLuigi Rizzo sc->nrqs = 1; 27362f345d8eSLuigi Rizzo sc->nwqs = 1; 27375fbb6830SXin LI } else { 27385fbb6830SXin LI sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 27395fbb6830SXin LI sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs); 27402f345d8eSLuigi Rizzo } 2741a4f734b4SXin LI 2742a4f734b4SXin LI if (IS_BE2(sc) && is_rss_enabled(sc)) 2743a4f734b4SXin LI sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1; 27442f345d8eSLuigi Rizzo } 27452f345d8eSLuigi Rizzo 27462f345d8eSLuigi Rizzo 27472f345d8eSLuigi Rizzo static void 27482f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc) 27492f345d8eSLuigi Rizzo { 2750291a1934SXin LI if (is_rss_enabled(sc)) { 27512f345d8eSLuigi Rizzo sc->nrqs = sc->intr_count + 1; 27522f345d8eSLuigi Rizzo sc->nwqs = sc->intr_count; 27532f345d8eSLuigi Rizzo } else { 27542f345d8eSLuigi Rizzo sc->nrqs = 1; 27552f345d8eSLuigi Rizzo sc->nwqs = 1; 27562f345d8eSLuigi Rizzo } 2757a4f734b4SXin LI 2758a4f734b4SXin LI if (IS_BE2(sc)) 2759a4f734b4SXin LI sc->nwqs = 1; 27602f345d8eSLuigi Rizzo } 27612f345d8eSLuigi Rizzo 2762cdaba892SXin LI static int 2763cdaba892SXin LI oce_check_ipv6_ext_hdr(struct mbuf *m) 2764cdaba892SXin LI { 2765cdaba892SXin LI struct ether_header *eh = mtod(m, struct ether_header *); 2766cdaba892SXin LI caddr_t m_datatemp = m->m_data; 2767cdaba892SXin LI 2768cdaba892SXin LI if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 2769cdaba892SXin LI m->m_data += sizeof(struct ether_header); 2770cdaba892SXin LI struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 2771cdaba892SXin LI 2772cdaba892SXin LI if((ip6->ip6_nxt != IPPROTO_TCP) && \ 2773cdaba892SXin LI (ip6->ip6_nxt != IPPROTO_UDP)){ 2774cdaba892SXin LI struct ip6_ext *ip6e = NULL; 2775cdaba892SXin LI m->m_data += sizeof(struct ip6_hdr); 2776cdaba892SXin LI 2777cdaba892SXin LI ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *); 2778cdaba892SXin LI if(ip6e->ip6e_len == 0xff) { 2779cdaba892SXin LI m->m_data = m_datatemp; 2780cdaba892SXin LI return TRUE; 2781cdaba892SXin LI } 2782cdaba892SXin LI } 2783cdaba892SXin LI m->m_data = m_datatemp; 2784cdaba892SXin LI } 2785cdaba892SXin LI return FALSE; 2786cdaba892SXin LI } 2787cdaba892SXin LI 2788cdaba892SXin LI static int 2789cdaba892SXin LI is_be3_a1(POCE_SOFTC sc) 2790cdaba892SXin LI { 2791cdaba892SXin LI if((sc->flags & OCE_FLAGS_BE3) && ((sc->asic_revision & 0xFF) < 2)) { 2792cdaba892SXin LI return TRUE; 2793cdaba892SXin LI } 2794cdaba892SXin LI return FALSE; 2795cdaba892SXin LI } 2796cdaba892SXin LI 2797cdaba892SXin LI static struct mbuf * 2798cdaba892SXin LI oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete) 2799cdaba892SXin LI { 2800cdaba892SXin LI uint16_t vlan_tag = 0; 2801cdaba892SXin LI 2802cdaba892SXin LI if(!M_WRITABLE(m)) 2803cdaba892SXin LI return NULL; 2804cdaba892SXin LI 2805cdaba892SXin LI /* Embed vlan tag in the packet if it is not part of it */ 2806cdaba892SXin LI if(m->m_flags & M_VLANTAG) { 2807cdaba892SXin LI vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); 2808cdaba892SXin LI m->m_flags &= ~M_VLANTAG; 2809cdaba892SXin LI } 2810cdaba892SXin LI 2811cdaba892SXin LI /* if UMC, ignore vlan tag insertion and instead insert pvid */ 2812cdaba892SXin LI if(sc->pvid) { 2813cdaba892SXin LI if(!vlan_tag) 2814cdaba892SXin LI vlan_tag = sc->pvid; 2815*764c812dSJosh Paetzel if (complete) 2816cdaba892SXin LI *complete = FALSE; 2817cdaba892SXin LI } 2818cdaba892SXin LI 2819cdaba892SXin LI if(vlan_tag) { 2820cdaba892SXin LI m = ether_vlanencap(m, vlan_tag); 2821cdaba892SXin LI } 2822cdaba892SXin LI 2823cdaba892SXin LI if(sc->qnqid) { 2824cdaba892SXin LI m = ether_vlanencap(m, sc->qnqid); 2825*764c812dSJosh Paetzel 2826*764c812dSJosh Paetzel if (complete) 2827cdaba892SXin LI *complete = FALSE; 2828cdaba892SXin LI } 2829cdaba892SXin LI return m; 2830cdaba892SXin LI } 2831cdaba892SXin LI 2832cdaba892SXin LI static int 2833cdaba892SXin LI oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m) 2834cdaba892SXin LI { 2835cdaba892SXin LI if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \ 2836cdaba892SXin LI oce_check_ipv6_ext_hdr(m)) { 2837cdaba892SXin LI return TRUE; 2838cdaba892SXin LI } 2839cdaba892SXin LI return FALSE; 2840cdaba892SXin LI } 2841291a1934SXin LI 2842291a1934SXin LI static void 2843291a1934SXin LI oce_get_config(POCE_SOFTC sc) 2844291a1934SXin LI { 2845291a1934SXin LI int rc = 0; 2846291a1934SXin LI uint32_t max_rss = 0; 2847291a1934SXin LI 2848291a1934SXin LI if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native)) 2849291a1934SXin LI max_rss = OCE_LEGACY_MODE_RSS; 2850291a1934SXin LI else 2851291a1934SXin LI max_rss = OCE_MAX_RSS; 2852291a1934SXin LI 2853291a1934SXin LI if (!IS_BE(sc)) { 2854b41206d8SXin LI rc = oce_get_profile_config(sc, max_rss); 2855291a1934SXin LI if (rc) { 2856291a1934SXin LI sc->nwqs = OCE_MAX_WQ; 2857291a1934SXin LI sc->nrssqs = max_rss; 2858291a1934SXin LI sc->nrqs = sc->nrssqs + 1; 2859291a1934SXin LI } 2860291a1934SXin LI } 2861b41206d8SXin LI else { /* For BE3 don't rely on fw for determining the resources */ 2862291a1934SXin LI sc->nrssqs = max_rss; 2863291a1934SXin LI sc->nrqs = sc->nrssqs + 1; 2864291a1934SXin LI sc->nwqs = OCE_MAX_WQ; 2865b41206d8SXin LI sc->max_vlans = MAX_VLANFILTER_SIZE; 2866291a1934SXin LI } 2867291a1934SXin LI } 2868*764c812dSJosh Paetzel 2869*764c812dSJosh Paetzel static void 2870*764c812dSJosh Paetzel oce_rdma_close(void) 2871*764c812dSJosh Paetzel { 2872*764c812dSJosh Paetzel if (oce_rdma_if != NULL) { 2873*764c812dSJosh Paetzel oce_rdma_if = NULL; 2874*764c812dSJosh Paetzel } 2875*764c812dSJosh Paetzel } 2876*764c812dSJosh Paetzel 2877*764c812dSJosh Paetzel static void 2878*764c812dSJosh Paetzel oce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr) 2879*764c812dSJosh Paetzel { 2880*764c812dSJosh Paetzel memcpy(macaddr, sc->macaddr.mac_addr, 6); 2881*764c812dSJosh Paetzel } 2882*764c812dSJosh Paetzel 2883*764c812dSJosh Paetzel int 2884*764c812dSJosh Paetzel oce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if) 2885*764c812dSJosh Paetzel { 2886*764c812dSJosh Paetzel POCE_SOFTC sc; 2887*764c812dSJosh Paetzel struct oce_dev_info di; 2888*764c812dSJosh Paetzel int i; 2889*764c812dSJosh Paetzel 2890*764c812dSJosh Paetzel if ((rdma_info == NULL) || (rdma_if == NULL)) { 2891*764c812dSJosh Paetzel return -EINVAL; 2892*764c812dSJosh Paetzel } 2893*764c812dSJosh Paetzel 2894*764c812dSJosh Paetzel if ((rdma_info->size != OCE_RDMA_INFO_SIZE) || 2895*764c812dSJosh Paetzel (rdma_if->size != OCE_RDMA_IF_SIZE)) { 2896*764c812dSJosh Paetzel return -ENXIO; 2897*764c812dSJosh Paetzel } 2898*764c812dSJosh Paetzel 2899*764c812dSJosh Paetzel rdma_info->close = oce_rdma_close; 2900*764c812dSJosh Paetzel rdma_info->mbox_post = oce_mbox_post; 2901*764c812dSJosh Paetzel rdma_info->common_req_hdr_init = mbx_common_req_hdr_init; 2902*764c812dSJosh Paetzel rdma_info->get_mac_addr = oce_get_mac_addr; 2903*764c812dSJosh Paetzel 2904*764c812dSJosh Paetzel oce_rdma_if = rdma_if; 2905*764c812dSJosh Paetzel 2906*764c812dSJosh Paetzel sc = softc_head; 2907*764c812dSJosh Paetzel while (sc != NULL) { 2908*764c812dSJosh Paetzel if (oce_rdma_if->announce != NULL) { 2909*764c812dSJosh Paetzel memset(&di, 0, sizeof(di)); 2910*764c812dSJosh Paetzel di.dev = sc->dev; 2911*764c812dSJosh Paetzel di.softc = sc; 2912*764c812dSJosh Paetzel di.ifp = sc->ifp; 2913*764c812dSJosh Paetzel di.db_bhandle = sc->db_bhandle; 2914*764c812dSJosh Paetzel di.db_btag = sc->db_btag; 2915*764c812dSJosh Paetzel di.db_page_size = 4096; 2916*764c812dSJosh Paetzel if (sc->flags & OCE_FLAGS_USING_MSIX) { 2917*764c812dSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_MSIX; 2918*764c812dSJosh Paetzel } else if (sc->flags & OCE_FLAGS_USING_MSI) { 2919*764c812dSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_MSI; 2920*764c812dSJosh Paetzel } else { 2921*764c812dSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_INTX; 2922*764c812dSJosh Paetzel } 2923*764c812dSJosh Paetzel di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk 2924*764c812dSJosh Paetzel if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) { 2925*764c812dSJosh Paetzel di.msix.num_vectors = sc->intr_count + sc->roce_intr_count; 2926*764c812dSJosh Paetzel di.msix.start_vector = sc->intr_count; 2927*764c812dSJosh Paetzel for (i=0; i<di.msix.num_vectors; i++) { 2928*764c812dSJosh Paetzel di.msix.vector_list[i] = sc->intrs[i].vector; 2929*764c812dSJosh Paetzel } 2930*764c812dSJosh Paetzel } else { 2931*764c812dSJosh Paetzel } 2932*764c812dSJosh Paetzel memcpy(di.mac_addr, sc->macaddr.mac_addr, 6); 2933*764c812dSJosh Paetzel di.vendor_id = pci_get_vendor(sc->dev); 2934*764c812dSJosh Paetzel di.dev_id = pci_get_device(sc->dev); 2935*764c812dSJosh Paetzel 2936*764c812dSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) { 2937*764c812dSJosh Paetzel di.flags |= OCE_RDMA_INFO_RDMA_SUPPORTED; 2938*764c812dSJosh Paetzel } 2939*764c812dSJosh Paetzel 2940*764c812dSJosh Paetzel rdma_if->announce(&di); 2941*764c812dSJosh Paetzel sc = sc->next; 2942*764c812dSJosh Paetzel } 2943*764c812dSJosh Paetzel } 2944*764c812dSJosh Paetzel 2945*764c812dSJosh Paetzel return 0; 2946*764c812dSJosh Paetzel } 2947*764c812dSJosh Paetzel 2948*764c812dSJosh Paetzel static void 2949*764c812dSJosh Paetzel oce_read_env_variables( POCE_SOFTC sc ) 2950*764c812dSJosh Paetzel { 2951*764c812dSJosh Paetzel char *value = NULL; 2952*764c812dSJosh Paetzel int rc = 0; 2953*764c812dSJosh Paetzel 2954*764c812dSJosh Paetzel /* read if user wants to enable hwlro or swlro */ 2955*764c812dSJosh Paetzel //value = getenv("oce_enable_hwlro"); 2956*764c812dSJosh Paetzel if(value && IS_SH(sc)) { 2957*764c812dSJosh Paetzel sc->enable_hwlro = strtol(value, NULL, 10); 2958*764c812dSJosh Paetzel if(sc->enable_hwlro) { 2959*764c812dSJosh Paetzel rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL); 2960*764c812dSJosh Paetzel if(rc) { 2961*764c812dSJosh Paetzel device_printf(sc->dev, "no hardware lro support\n"); 2962*764c812dSJosh Paetzel device_printf(sc->dev, "software lro enabled\n"); 2963*764c812dSJosh Paetzel sc->enable_hwlro = 0; 2964*764c812dSJosh Paetzel }else { 2965*764c812dSJosh Paetzel device_printf(sc->dev, "hardware lro enabled\n"); 2966*764c812dSJosh Paetzel oce_max_rsp_handled = 32; 2967*764c812dSJosh Paetzel } 2968*764c812dSJosh Paetzel }else { 2969*764c812dSJosh Paetzel device_printf(sc->dev, "software lro enabled\n"); 2970*764c812dSJosh Paetzel } 2971*764c812dSJosh Paetzel }else { 2972*764c812dSJosh Paetzel sc->enable_hwlro = 0; 2973*764c812dSJosh Paetzel } 2974*764c812dSJosh Paetzel 2975*764c812dSJosh Paetzel /* read mbuf size */ 2976*764c812dSJosh Paetzel //value = getenv("oce_rq_buf_size"); 2977*764c812dSJosh Paetzel if(value && IS_SH(sc)) { 2978*764c812dSJosh Paetzel oce_rq_buf_size = strtol(value, NULL, 10); 2979*764c812dSJosh Paetzel switch(oce_rq_buf_size) { 2980*764c812dSJosh Paetzel case 2048: 2981*764c812dSJosh Paetzel case 4096: 2982*764c812dSJosh Paetzel case 9216: 2983*764c812dSJosh Paetzel case 16384: 2984*764c812dSJosh Paetzel break; 2985*764c812dSJosh Paetzel 2986*764c812dSJosh Paetzel default: 2987*764c812dSJosh Paetzel device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n"); 2988*764c812dSJosh Paetzel oce_rq_buf_size = 2048; 2989*764c812dSJosh Paetzel } 2990*764c812dSJosh Paetzel } 2991*764c812dSJosh Paetzel 2992*764c812dSJosh Paetzel return; 2993*764c812dSJosh Paetzel } 2994