12f345d8eSLuigi Rizzo /*-
27282444bSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni *
4291a1934SXin LI * Copyright (C) 2013 Emulex
52f345d8eSLuigi Rizzo * All rights reserved.
62f345d8eSLuigi Rizzo *
72f345d8eSLuigi Rizzo * Redistribution and use in source and binary forms, with or without
82f345d8eSLuigi Rizzo * modification, are permitted provided that the following conditions are met:
92f345d8eSLuigi Rizzo *
102f345d8eSLuigi Rizzo * 1. Redistributions of source code must retain the above copyright notice,
112f345d8eSLuigi Rizzo * this list of conditions and the following disclaimer.
122f345d8eSLuigi Rizzo *
132f345d8eSLuigi Rizzo * 2. Redistributions in binary form must reproduce the above copyright
142f345d8eSLuigi Rizzo * notice, this list of conditions and the following disclaimer in the
152f345d8eSLuigi Rizzo * documentation and/or other materials provided with the distribution.
162f345d8eSLuigi Rizzo *
172f345d8eSLuigi Rizzo * 3. Neither the name of the Emulex Corporation nor the names of its
182f345d8eSLuigi Rizzo * contributors may be used to endorse or promote products derived from
192f345d8eSLuigi Rizzo * this software without specific prior written permission.
202f345d8eSLuigi Rizzo *
212f345d8eSLuigi Rizzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
222f345d8eSLuigi Rizzo * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232f345d8eSLuigi Rizzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242f345d8eSLuigi Rizzo * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
252f345d8eSLuigi Rizzo * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
262f345d8eSLuigi Rizzo * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
272f345d8eSLuigi Rizzo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
282f345d8eSLuigi Rizzo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
292f345d8eSLuigi Rizzo * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
302f345d8eSLuigi Rizzo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
312f345d8eSLuigi Rizzo * POSSIBILITY OF SUCH DAMAGE.
322f345d8eSLuigi Rizzo *
332f345d8eSLuigi Rizzo * Contact Information:
342f345d8eSLuigi Rizzo * freebsd-drivers@emulex.com
352f345d8eSLuigi Rizzo *
362f345d8eSLuigi Rizzo * Emulex
372f345d8eSLuigi Rizzo * 3333 Susan Street
382f345d8eSLuigi Rizzo * Costa Mesa, CA 92626
392f345d8eSLuigi Rizzo */
402f345d8eSLuigi Rizzo
412f345d8eSLuigi Rizzo
42ad512958SBjoern A. Zeeb #include "opt_inet6.h"
43ad512958SBjoern A. Zeeb #include "opt_inet.h"
44ad512958SBjoern A. Zeeb
452f345d8eSLuigi Rizzo #include "oce_if.h"
46c2625e6eSJosh Paetzel #include "oce_user.h"
47c2625e6eSJosh Paetzel
48c2625e6eSJosh Paetzel #define is_tso_pkt(m) (m->m_pkthdr.csum_flags & CSUM_TSO)
492f345d8eSLuigi Rizzo
505fbb6830SXin LI /* UE Status Low CSR */
515fbb6830SXin LI static char *ue_status_low_desc[] = {
525fbb6830SXin LI "CEV",
535fbb6830SXin LI "CTX",
545fbb6830SXin LI "DBUF",
555fbb6830SXin LI "ERX",
565fbb6830SXin LI "Host",
575fbb6830SXin LI "MPU",
585fbb6830SXin LI "NDMA",
595fbb6830SXin LI "PTC ",
605fbb6830SXin LI "RDMA ",
615fbb6830SXin LI "RXF ",
625fbb6830SXin LI "RXIPS ",
635fbb6830SXin LI "RXULP0 ",
645fbb6830SXin LI "RXULP1 ",
655fbb6830SXin LI "RXULP2 ",
665fbb6830SXin LI "TIM ",
675fbb6830SXin LI "TPOST ",
685fbb6830SXin LI "TPRE ",
695fbb6830SXin LI "TXIPS ",
705fbb6830SXin LI "TXULP0 ",
715fbb6830SXin LI "TXULP1 ",
725fbb6830SXin LI "UC ",
735fbb6830SXin LI "WDMA ",
745fbb6830SXin LI "TXULP2 ",
755fbb6830SXin LI "HOST1 ",
765fbb6830SXin LI "P0_OB_LINK ",
775fbb6830SXin LI "P1_OB_LINK ",
785fbb6830SXin LI "HOST_GPIO ",
795fbb6830SXin LI "MBOX ",
805fbb6830SXin LI "AXGMAC0",
815fbb6830SXin LI "AXGMAC1",
825fbb6830SXin LI "JTAG",
835fbb6830SXin LI "MPU_INTPEND"
845fbb6830SXin LI };
855fbb6830SXin LI
865fbb6830SXin LI /* UE Status High CSR */
875fbb6830SXin LI static char *ue_status_hi_desc[] = {
885fbb6830SXin LI "LPCMEMHOST",
895fbb6830SXin LI "MGMT_MAC",
905fbb6830SXin LI "PCS0ONLINE",
915fbb6830SXin LI "MPU_IRAM",
925fbb6830SXin LI "PCS1ONLINE",
935fbb6830SXin LI "PCTL0",
945fbb6830SXin LI "PCTL1",
955fbb6830SXin LI "PMEM",
965fbb6830SXin LI "RR",
975fbb6830SXin LI "TXPB",
985fbb6830SXin LI "RXPP",
995fbb6830SXin LI "XAUI",
1005fbb6830SXin LI "TXP",
1015fbb6830SXin LI "ARM",
1025fbb6830SXin LI "IPC",
1035fbb6830SXin LI "HOST2",
1045fbb6830SXin LI "HOST3",
1055fbb6830SXin LI "HOST4",
1065fbb6830SXin LI "HOST5",
1075fbb6830SXin LI "HOST6",
1085fbb6830SXin LI "HOST7",
1095fbb6830SXin LI "HOST8",
1105fbb6830SXin LI "HOST9",
1115fbb6830SXin LI "NETC",
1125fbb6830SXin LI "Unknown",
1135fbb6830SXin LI "Unknown",
1145fbb6830SXin LI "Unknown",
1155fbb6830SXin LI "Unknown",
1165fbb6830SXin LI "Unknown",
1175fbb6830SXin LI "Unknown",
1185fbb6830SXin LI "Unknown",
1195fbb6830SXin LI "Unknown"
1205fbb6830SXin LI };
1215fbb6830SXin LI
122c2625e6eSJosh Paetzel struct oce_common_cqe_info{
123c2625e6eSJosh Paetzel uint8_t vtp:1;
124c2625e6eSJosh Paetzel uint8_t l4_cksum_pass:1;
125c2625e6eSJosh Paetzel uint8_t ip_cksum_pass:1;
126c2625e6eSJosh Paetzel uint8_t ipv6_frame:1;
127c2625e6eSJosh Paetzel uint8_t qnq:1;
128c2625e6eSJosh Paetzel uint8_t rsvd:3;
129c2625e6eSJosh Paetzel uint8_t num_frags;
130c2625e6eSJosh Paetzel uint16_t pkt_size;
131c2625e6eSJosh Paetzel uint16_t vtag;
132c2625e6eSJosh Paetzel };
133c2625e6eSJosh Paetzel
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);
13967fd4c9dSJustin Hibbits static int oce_ioctl(if_t ifp, u_long command, caddr_t data);
1402f345d8eSLuigi Rizzo static void oce_init(void *xsc);
14167fd4c9dSJustin Hibbits static int oce_multiq_start(if_t ifp, struct mbuf *m);
14267fd4c9dSJustin Hibbits static void oce_multiq_flush(if_t 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 */
15267fd4c9dSJustin Hibbits static void oce_media_status(if_t ifp, struct ifmediareq *req);
15367fd4c9dSJustin Hibbits static int oce_media_change(if_t 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);
158c2625e6eSJosh Paetzel static void oce_process_tx_completion(struct oce_wq *wq);
15967fd4c9dSJustin Hibbits static int oce_multiq_transmit(if_t 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);
165c2625e6eSJosh Paetzel static void oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe);
166c2625e6eSJosh Paetzel static void oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq);
167c2625e6eSJosh Paetzel static uint16_t oce_rq_handler_lro(void *arg);
168c2625e6eSJosh Paetzel static void oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2);
169c2625e6eSJosh Paetzel static void oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2);
170c2625e6eSJosh 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 */
173*aa386085SZhenlei Huang static void oce_attach_ifp(POCE_SOFTC sc);
17467fd4c9dSJustin Hibbits static void oce_add_vlan(void *arg, if_t ifp, uint16_t vtag);
17567fd4c9dSJustin Hibbits static void oce_del_vlan(void *arg, if_t 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);
17867fd4c9dSJustin Hibbits static int oce_handle_passthrough(if_t 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);
189c2625e6eSJosh Paetzel static void oce_read_env_variables(POCE_SOFTC sc);
190c2625e6eSJosh Paetzel
1919bd3250aSLuigi Rizzo /* IP specific */
1929bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
1939bd3250aSLuigi Rizzo static int oce_init_lro(POCE_SOFTC sc);
1949bd3250aSLuigi Rizzo static struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp);
1959bd3250aSLuigi Rizzo #endif
1962f345d8eSLuigi Rizzo
1972f345d8eSLuigi Rizzo static device_method_t oce_dispatch[] = {
1982f345d8eSLuigi Rizzo DEVMETHOD(device_probe, oce_probe),
1992f345d8eSLuigi Rizzo DEVMETHOD(device_attach, oce_attach),
2002f345d8eSLuigi Rizzo DEVMETHOD(device_detach, oce_detach),
2012f345d8eSLuigi Rizzo DEVMETHOD(device_shutdown, oce_shutdown),
20261bfd867SSofian Brabez
20361bfd867SSofian Brabez DEVMETHOD_END
2042f345d8eSLuigi Rizzo };
2052f345d8eSLuigi Rizzo
2062f345d8eSLuigi Rizzo static driver_t oce_driver = {
2072f345d8eSLuigi Rizzo "oce",
2082f345d8eSLuigi Rizzo oce_dispatch,
2092f345d8eSLuigi Rizzo sizeof(OCE_SOFTC)
2102f345d8eSLuigi Rizzo };
2112f345d8eSLuigi Rizzo
2122f345d8eSLuigi Rizzo /* global vars */
2132f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"};
2142f345d8eSLuigi Rizzo
2152f345d8eSLuigi Rizzo /* Module capabilites and parameters */
2162f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED;
2172f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS;
218c2625e6eSJosh Paetzel uint32_t oce_rq_buf_size = 2048;
2192f345d8eSLuigi Rizzo
2202f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled);
2212f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss);
2222f345d8eSLuigi Rizzo
2232f345d8eSLuigi Rizzo /* Supported devices table */
2242f345d8eSLuigi Rizzo static uint32_t supportedDevices[] = {
2252f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2,
2262f345d8eSLuigi Rizzo (PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3,
2272f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3,
2282f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201,
2292f345d8eSLuigi Rizzo (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF,
230291a1934SXin LI (PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH
2312f345d8eSLuigi Rizzo };
2322f345d8eSLuigi Rizzo
2334e75e496SJohn Baldwin DRIVER_MODULE(oce, pci, oce_driver, 0, 0);
2340dc34160SWarner Losh MODULE_PNP_INFO("W32:vendor/device", pci, oce, supportedDevices,
2350dc34160SWarner Losh nitems(supportedDevices));
2360dc34160SWarner Losh MODULE_DEPEND(oce, pci, 1, 1, 1);
2370dc34160SWarner Losh MODULE_DEPEND(oce, ether, 1, 1, 1);
2380dc34160SWarner Losh MODULE_VERSION(oce, 1);
2390dc34160SWarner Losh
240c2625e6eSJosh Paetzel POCE_SOFTC softc_head = NULL;
241c2625e6eSJosh Paetzel POCE_SOFTC softc_tail = NULL;
2422f345d8eSLuigi Rizzo
243c2625e6eSJosh Paetzel struct oce_rdma_if *oce_rdma_if = NULL;
2442f345d8eSLuigi Rizzo
2452f345d8eSLuigi Rizzo /*****************************************************************************
2462f345d8eSLuigi Rizzo * Driver entry points functions *
2472f345d8eSLuigi Rizzo *****************************************************************************/
2482f345d8eSLuigi Rizzo
2492f345d8eSLuigi Rizzo static int
oce_probe(device_t dev)2502f345d8eSLuigi Rizzo oce_probe(device_t dev)
2512f345d8eSLuigi Rizzo {
2529bd3250aSLuigi Rizzo uint16_t vendor = 0;
2539bd3250aSLuigi Rizzo uint16_t device = 0;
2549bd3250aSLuigi Rizzo int i = 0;
2552f345d8eSLuigi Rizzo POCE_SOFTC sc;
2562f345d8eSLuigi Rizzo
2572f345d8eSLuigi Rizzo sc = device_get_softc(dev);
2582f345d8eSLuigi Rizzo bzero(sc, sizeof(OCE_SOFTC));
2592f345d8eSLuigi Rizzo sc->dev = dev;
2602f345d8eSLuigi Rizzo
2612f345d8eSLuigi Rizzo vendor = pci_get_vendor(dev);
2622f345d8eSLuigi Rizzo device = pci_get_device(dev);
2632f345d8eSLuigi Rizzo
2649bd3250aSLuigi Rizzo for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) {
2652f345d8eSLuigi Rizzo if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) {
2662f345d8eSLuigi Rizzo if (device == (supportedDevices[i] & 0xffff)) {
267c704b87bSMark Johnston device_set_descf(dev,
268c704b87bSMark Johnston "%s:%s", "Emulex CNA NIC function",
2692f345d8eSLuigi Rizzo component_revision);
2702f345d8eSLuigi Rizzo
2712f345d8eSLuigi Rizzo switch (device) {
2722f345d8eSLuigi Rizzo case PCI_PRODUCT_BE2:
2732f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE2;
2742f345d8eSLuigi Rizzo break;
2752f345d8eSLuigi Rizzo case PCI_PRODUCT_BE3:
2762f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_BE3;
2772f345d8eSLuigi Rizzo break;
2782f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201:
2792f345d8eSLuigi Rizzo case PCI_PRODUCT_XE201_VF:
2802f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_XE201;
2812f345d8eSLuigi Rizzo break;
282291a1934SXin LI case PCI_PRODUCT_SH:
283291a1934SXin LI sc->flags |= OCE_FLAGS_SH;
284291a1934SXin LI break;
2852f345d8eSLuigi Rizzo default:
2862f345d8eSLuigi Rizzo return ENXIO;
2872f345d8eSLuigi Rizzo }
2882f345d8eSLuigi Rizzo return BUS_PROBE_DEFAULT;
2892f345d8eSLuigi Rizzo }
2902f345d8eSLuigi Rizzo }
2912f345d8eSLuigi Rizzo }
2922f345d8eSLuigi Rizzo
2932f345d8eSLuigi Rizzo return ENXIO;
2942f345d8eSLuigi Rizzo }
2952f345d8eSLuigi Rizzo
2962f345d8eSLuigi Rizzo static int
oce_attach(device_t dev)2972f345d8eSLuigi Rizzo oce_attach(device_t dev)
2982f345d8eSLuigi Rizzo {
2992f345d8eSLuigi Rizzo POCE_SOFTC sc;
3002f345d8eSLuigi Rizzo int rc = 0;
3012f345d8eSLuigi Rizzo
3022f345d8eSLuigi Rizzo sc = device_get_softc(dev);
3032f345d8eSLuigi Rizzo
3042f345d8eSLuigi Rizzo rc = oce_hw_pci_alloc(sc);
3052f345d8eSLuigi Rizzo if (rc)
3062f345d8eSLuigi Rizzo return rc;
3072f345d8eSLuigi Rizzo
3082f345d8eSLuigi Rizzo sc->tx_ring_size = OCE_TX_RING_SIZE;
3092f345d8eSLuigi Rizzo sc->rx_ring_size = OCE_RX_RING_SIZE;
310c2625e6eSJosh Paetzel /* receive fragment size should be multiple of 2K */
311c2625e6eSJosh Paetzel sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048);
3122f345d8eSLuigi Rizzo sc->flow_control = OCE_DEFAULT_FLOW_CONTROL;
3132f345d8eSLuigi Rizzo sc->promisc = OCE_DEFAULT_PROMISCUOUS;
3142f345d8eSLuigi Rizzo
3152f345d8eSLuigi Rizzo LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock");
3162f345d8eSLuigi Rizzo LOCK_CREATE(&sc->dev_lock, "Device_lock");
3172f345d8eSLuigi Rizzo
3182f345d8eSLuigi Rizzo /* initialise the hardware */
3192f345d8eSLuigi Rizzo rc = oce_hw_init(sc);
3202f345d8eSLuigi Rizzo if (rc)
3212f345d8eSLuigi Rizzo goto pci_res_free;
3222f345d8eSLuigi Rizzo
323c2625e6eSJosh Paetzel oce_read_env_variables(sc);
324c2625e6eSJosh Paetzel
325291a1934SXin LI oce_get_config(sc);
326291a1934SXin LI
3272f345d8eSLuigi Rizzo setup_max_queues_want(sc);
3282f345d8eSLuigi Rizzo
3292f345d8eSLuigi Rizzo rc = oce_setup_intr(sc);
3302f345d8eSLuigi Rizzo if (rc)
3312f345d8eSLuigi Rizzo goto mbox_free;
3322f345d8eSLuigi Rizzo
3332f345d8eSLuigi Rizzo rc = oce_queue_init_all(sc);
3342f345d8eSLuigi Rizzo if (rc)
3352f345d8eSLuigi Rizzo goto intr_free;
3362f345d8eSLuigi Rizzo
337*aa386085SZhenlei Huang oce_attach_ifp(sc);
3382f345d8eSLuigi Rizzo
339ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3402f345d8eSLuigi Rizzo rc = oce_init_lro(sc);
3412f345d8eSLuigi Rizzo if (rc)
3422f345d8eSLuigi Rizzo goto ifp_free;
343ad512958SBjoern A. Zeeb #endif
3442f345d8eSLuigi Rizzo
3452f345d8eSLuigi Rizzo rc = oce_hw_start(sc);
3462f345d8eSLuigi Rizzo if (rc)
347db702c59SEitan Adler goto lro_free;
3482f345d8eSLuigi Rizzo
3492f345d8eSLuigi Rizzo sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
3502f345d8eSLuigi Rizzo oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST);
3512f345d8eSLuigi Rizzo sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
3522f345d8eSLuigi Rizzo oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST);
3532f345d8eSLuigi Rizzo
3542f345d8eSLuigi Rizzo rc = oce_stats_init(sc);
3552f345d8eSLuigi Rizzo if (rc)
3562f345d8eSLuigi Rizzo goto vlan_free;
3572f345d8eSLuigi Rizzo
3582f345d8eSLuigi Rizzo oce_add_sysctls(sc);
3592f345d8eSLuigi Rizzo
360c2625e6eSJosh Paetzel callout_init(&sc->timer, CALLOUT_MPSAFE);
3612f345d8eSLuigi Rizzo rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc);
3622f345d8eSLuigi Rizzo if (rc)
3632f345d8eSLuigi Rizzo goto stats_free;
3642f345d8eSLuigi Rizzo
365c2625e6eSJosh Paetzel sc->next =NULL;
366c2625e6eSJosh Paetzel if (softc_tail != NULL) {
367c2625e6eSJosh Paetzel softc_tail->next = sc;
368c2625e6eSJosh Paetzel } else {
369c2625e6eSJosh Paetzel softc_head = sc;
370c2625e6eSJosh Paetzel }
371c2625e6eSJosh Paetzel softc_tail = sc;
372c2625e6eSJosh Paetzel
37345913229SBrooks Davis gone_in_dev(dev, 15, "relatively uncommon 10GbE NIC");
37445913229SBrooks Davis
3752f345d8eSLuigi Rizzo return 0;
3762f345d8eSLuigi Rizzo
3772f345d8eSLuigi Rizzo stats_free:
3782f345d8eSLuigi Rizzo callout_drain(&sc->timer);
3792f345d8eSLuigi Rizzo oce_stats_free(sc);
3802f345d8eSLuigi Rizzo vlan_free:
3812f345d8eSLuigi Rizzo if (sc->vlan_attach)
3822f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
3832f345d8eSLuigi Rizzo if (sc->vlan_detach)
3842f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
3852f345d8eSLuigi Rizzo oce_hw_intr_disable(sc);
3862f345d8eSLuigi Rizzo lro_free:
387ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3882f345d8eSLuigi Rizzo oce_free_lro(sc);
3892f345d8eSLuigi Rizzo ifp_free:
390ad512958SBjoern A. Zeeb #endif
3912f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp);
3922f345d8eSLuigi Rizzo if_free(sc->ifp);
3932f345d8eSLuigi Rizzo oce_queue_release_all(sc);
3942f345d8eSLuigi Rizzo intr_free:
3952f345d8eSLuigi Rizzo oce_intr_free(sc);
3962f345d8eSLuigi Rizzo mbox_free:
3972f345d8eSLuigi Rizzo oce_dma_free(sc, &sc->bsmbx);
3982f345d8eSLuigi Rizzo pci_res_free:
3992f345d8eSLuigi Rizzo oce_hw_pci_free(sc);
4002f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->dev_lock);
4012f345d8eSLuigi Rizzo LOCK_DESTROY(&sc->bmbx_lock);
4022f345d8eSLuigi Rizzo return rc;
4032f345d8eSLuigi Rizzo
4042f345d8eSLuigi Rizzo }
4052f345d8eSLuigi Rizzo
4062f345d8eSLuigi Rizzo static int
oce_detach(device_t dev)4072f345d8eSLuigi Rizzo oce_detach(device_t dev)
4082f345d8eSLuigi Rizzo {
4092f345d8eSLuigi Rizzo POCE_SOFTC sc = device_get_softc(dev);
410c2625e6eSJosh Paetzel POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL;
411c2625e6eSJosh Paetzel
412c2625e6eSJosh Paetzel poce_sc_tmp = softc_head;
413c2625e6eSJosh Paetzel ppoce_sc_tmp1 = &softc_head;
414c2625e6eSJosh Paetzel while (poce_sc_tmp != NULL) {
415c2625e6eSJosh Paetzel if (poce_sc_tmp == sc) {
416c2625e6eSJosh Paetzel *ppoce_sc_tmp1 = sc->next;
417c2625e6eSJosh Paetzel if (sc->next == NULL) {
418c2625e6eSJosh Paetzel softc_tail = poce_sc_tmp2;
419c2625e6eSJosh Paetzel }
420c2625e6eSJosh Paetzel break;
421c2625e6eSJosh Paetzel }
422c2625e6eSJosh Paetzel poce_sc_tmp2 = poce_sc_tmp;
423c2625e6eSJosh Paetzel ppoce_sc_tmp1 = &poce_sc_tmp->next;
424c2625e6eSJosh Paetzel poce_sc_tmp = poce_sc_tmp->next;
425c2625e6eSJosh Paetzel }
4262f345d8eSLuigi Rizzo
4272f345d8eSLuigi Rizzo LOCK(&sc->dev_lock);
4282f345d8eSLuigi Rizzo oce_if_deactivate(sc);
4292f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock);
4302f345d8eSLuigi Rizzo
4312f345d8eSLuigi Rizzo callout_drain(&sc->timer);
4322f345d8eSLuigi Rizzo
4332f345d8eSLuigi Rizzo if (sc->vlan_attach != NULL)
4342f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
4352f345d8eSLuigi Rizzo if (sc->vlan_detach != NULL)
4362f345d8eSLuigi Rizzo EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
4372f345d8eSLuigi Rizzo
4382f345d8eSLuigi Rizzo ether_ifdetach(sc->ifp);
4392f345d8eSLuigi Rizzo
4402f345d8eSLuigi Rizzo if_free(sc->ifp);
4412f345d8eSLuigi Rizzo
4422f345d8eSLuigi Rizzo oce_hw_shutdown(sc);
4432f345d8eSLuigi Rizzo
4442f345d8eSLuigi Rizzo bus_generic_detach(dev);
4452f345d8eSLuigi Rizzo
4462f345d8eSLuigi Rizzo return 0;
4472f345d8eSLuigi Rizzo }
4482f345d8eSLuigi Rizzo
4492f345d8eSLuigi Rizzo static int
oce_shutdown(device_t dev)4502f345d8eSLuigi Rizzo oce_shutdown(device_t dev)
4512f345d8eSLuigi Rizzo {
4522f345d8eSLuigi Rizzo int rc;
4532f345d8eSLuigi Rizzo
4542f345d8eSLuigi Rizzo rc = oce_detach(dev);
4552f345d8eSLuigi Rizzo
4562f345d8eSLuigi Rizzo return rc;
4572f345d8eSLuigi Rizzo }
4582f345d8eSLuigi Rizzo
4592f345d8eSLuigi Rizzo static int
oce_ioctl(if_t ifp,u_long command,caddr_t data)46067fd4c9dSJustin Hibbits oce_ioctl(if_t ifp, u_long command, caddr_t data)
4612f345d8eSLuigi Rizzo {
4622f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data;
46367fd4c9dSJustin Hibbits POCE_SOFTC sc = if_getsoftc(ifp);
464e0dd0fe3SXin LI struct ifi2creq i2c;
465e0dd0fe3SXin LI uint8_t offset = 0;
4662f345d8eSLuigi Rizzo int rc = 0;
4672f345d8eSLuigi Rizzo uint32_t u;
4682f345d8eSLuigi Rizzo
4692f345d8eSLuigi Rizzo switch (command) {
4702f345d8eSLuigi Rizzo case SIOCGIFMEDIA:
4712f345d8eSLuigi Rizzo rc = ifmedia_ioctl(ifp, ifr, &sc->media, command);
4722f345d8eSLuigi Rizzo break;
4732f345d8eSLuigi Rizzo
4742f345d8eSLuigi Rizzo case SIOCSIFMTU:
4752f345d8eSLuigi Rizzo if (ifr->ifr_mtu > OCE_MAX_MTU)
4762f345d8eSLuigi Rizzo rc = EINVAL;
4772f345d8eSLuigi Rizzo else
47867fd4c9dSJustin Hibbits if_setmtu(ifp, ifr->ifr_mtu);
4792f345d8eSLuigi Rizzo break;
4802f345d8eSLuigi Rizzo
4812f345d8eSLuigi Rizzo case SIOCSIFFLAGS:
48267fd4c9dSJustin Hibbits if (if_getflags(ifp) & IFF_UP) {
48367fd4c9dSJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
48467fd4c9dSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
4852f345d8eSLuigi Rizzo oce_init(sc);
4862f345d8eSLuigi Rizzo }
4872f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Up\n");
4882f345d8eSLuigi Rizzo } else {
4892f345d8eSLuigi Rizzo LOCK(&sc->dev_lock);
4902f345d8eSLuigi Rizzo
49167fd4c9dSJustin Hibbits if_setdrvflagbits(sc->ifp, 0,
49267fd4c9dSJustin Hibbits IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
4932f345d8eSLuigi Rizzo oce_if_deactivate(sc);
4942f345d8eSLuigi Rizzo
4952f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock);
4962f345d8eSLuigi Rizzo
4972f345d8eSLuigi Rizzo device_printf(sc->dev, "Interface Down\n");
4982f345d8eSLuigi Rizzo }
4992f345d8eSLuigi Rizzo
50067fd4c9dSJustin Hibbits if ((if_getflags(ifp) & IFF_PROMISC) && !sc->promisc) {
5015fbb6830SXin LI if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1))))
5022f345d8eSLuigi Rizzo sc->promisc = TRUE;
50367fd4c9dSJustin Hibbits } else if (!(if_getflags(ifp) & IFF_PROMISC) && sc->promisc) {
5045fbb6830SXin LI if (!oce_rxf_set_promiscuous(sc, 0))
5052f345d8eSLuigi Rizzo sc->promisc = FALSE;
5062f345d8eSLuigi Rizzo }
5072f345d8eSLuigi Rizzo
5082f345d8eSLuigi Rizzo break;
5092f345d8eSLuigi Rizzo
5102f345d8eSLuigi Rizzo case SIOCADDMULTI:
5112f345d8eSLuigi Rizzo case SIOCDELMULTI:
5122f345d8eSLuigi Rizzo rc = oce_hw_update_multicast(sc);
5132f345d8eSLuigi Rizzo if (rc)
5142f345d8eSLuigi Rizzo device_printf(sc->dev,
5152f345d8eSLuigi Rizzo "Update multicast address failed\n");
5162f345d8eSLuigi Rizzo break;
5172f345d8eSLuigi Rizzo
5182f345d8eSLuigi Rizzo case SIOCSIFCAP:
51967fd4c9dSJustin Hibbits u = ifr->ifr_reqcap ^ if_getcapenable(ifp);
5202f345d8eSLuigi Rizzo
5212f345d8eSLuigi Rizzo if (u & IFCAP_TXCSUM) {
52267fd4c9dSJustin Hibbits if_togglecapenable(ifp, IFCAP_TXCSUM);
52367fd4c9dSJustin Hibbits if_togglehwassist(ifp, (CSUM_TCP | CSUM_UDP | CSUM_IP));
5242f345d8eSLuigi Rizzo
52567fd4c9dSJustin Hibbits if (IFCAP_TSO & if_getcapenable(ifp) &&
52667fd4c9dSJustin Hibbits !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
527cbb9ccf7SRyan Moeller u &= ~IFCAP_TSO;
52867fd4c9dSJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_TSO);
52967fd4c9dSJustin Hibbits if_sethwassistbits(ifp, 0, CSUM_TSO);
5302f345d8eSLuigi Rizzo if_printf(ifp,
5312f345d8eSLuigi Rizzo "TSO disabled due to -txcsum.\n");
5322f345d8eSLuigi Rizzo }
5332f345d8eSLuigi Rizzo }
5342f345d8eSLuigi Rizzo
5352f345d8eSLuigi Rizzo if (u & IFCAP_RXCSUM)
53667fd4c9dSJustin Hibbits if_togglecapenable(ifp, IFCAP_RXCSUM);
5372f345d8eSLuigi Rizzo
5382f345d8eSLuigi Rizzo if (u & IFCAP_TSO4) {
53967fd4c9dSJustin Hibbits if_togglecapenable(ifp, IFCAP_TSO4);
5402f345d8eSLuigi Rizzo
54167fd4c9dSJustin Hibbits if (IFCAP_TSO & if_getcapenable(ifp)) {
54267fd4c9dSJustin Hibbits if (IFCAP_TXCSUM & if_getcapenable(ifp))
54367fd4c9dSJustin Hibbits if_sethwassistbits(ifp, CSUM_TSO, 0);
5442f345d8eSLuigi Rizzo else {
54567fd4c9dSJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_TSO);
54667fd4c9dSJustin Hibbits if_sethwassistbits(ifp, 0, CSUM_TSO);
5472f345d8eSLuigi Rizzo if_printf(ifp,
5482f345d8eSLuigi Rizzo "Enable txcsum first.\n");
5492f345d8eSLuigi Rizzo rc = EAGAIN;
5502f345d8eSLuigi Rizzo }
5512f345d8eSLuigi Rizzo } else
55267fd4c9dSJustin Hibbits if_sethwassistbits(ifp, 0, CSUM_TSO);
5532f345d8eSLuigi Rizzo }
5542f345d8eSLuigi Rizzo
5552f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWTAGGING)
55667fd4c9dSJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
5572f345d8eSLuigi Rizzo
5582f345d8eSLuigi Rizzo if (u & IFCAP_VLAN_HWFILTER) {
55967fd4c9dSJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWFILTER);
5602f345d8eSLuigi Rizzo oce_vid_config(sc);
5612f345d8eSLuigi Rizzo }
562ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
563c2625e6eSJosh Paetzel if (u & IFCAP_LRO) {
56467fd4c9dSJustin Hibbits if_togglecapenable(ifp, IFCAP_LRO);
565c2625e6eSJosh Paetzel if(sc->enable_hwlro) {
56667fd4c9dSJustin Hibbits if(if_getcapenable(ifp) & IFCAP_LRO) {
567c2625e6eSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 1);
568c2625e6eSJosh Paetzel }else {
569c2625e6eSJosh Paetzel rc = oce_mbox_nic_set_iface_lro_config(sc, 0);
570c2625e6eSJosh Paetzel }
571c2625e6eSJosh Paetzel }
572c2625e6eSJosh Paetzel }
573ad512958SBjoern A. Zeeb #endif
5742f345d8eSLuigi Rizzo
5752f345d8eSLuigi Rizzo break;
5762f345d8eSLuigi Rizzo
577e0dd0fe3SXin LI case SIOCGI2C:
578e0dd0fe3SXin LI rc = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
579e0dd0fe3SXin LI if (rc)
580e0dd0fe3SXin LI break;
581e0dd0fe3SXin LI
5826e7ecc9aSMark Johnston if (i2c.dev_addr == PAGE_NUM_A0) {
5836e7ecc9aSMark Johnston offset = i2c.offset;
5846e7ecc9aSMark Johnston } else if (i2c.dev_addr == PAGE_NUM_A2) {
5856e7ecc9aSMark Johnston offset = TRANSCEIVER_A0_SIZE + i2c.offset;
5866e7ecc9aSMark Johnston } else {
587e0dd0fe3SXin LI rc = EINVAL;
588e0dd0fe3SXin LI break;
589e0dd0fe3SXin LI }
590e0dd0fe3SXin LI
5916e7ecc9aSMark Johnston if (i2c.len > sizeof(i2c.data) ||
5926e7ecc9aSMark Johnston i2c.len + offset > sizeof(sfp_vpd_dump_buffer)) {
593e0dd0fe3SXin LI rc = EINVAL;
594e0dd0fe3SXin LI break;
595e0dd0fe3SXin LI }
596e0dd0fe3SXin LI
597e0dd0fe3SXin LI rc = oce_mbox_read_transrecv_data(sc, i2c.dev_addr);
598e0dd0fe3SXin LI if (rc) {
599e0dd0fe3SXin LI rc = -rc;
600e0dd0fe3SXin LI break;
601e0dd0fe3SXin LI }
602e0dd0fe3SXin LI
603e0dd0fe3SXin LI memcpy(&i2c.data[0], &sfp_vpd_dump_buffer[offset], i2c.len);
604e0dd0fe3SXin LI
605e0dd0fe3SXin LI rc = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c));
606e0dd0fe3SXin LI break;
607e0dd0fe3SXin LI
6082f345d8eSLuigi Rizzo case SIOCGPRIVATE_0:
609c76ddeebSMark Johnston rc = priv_check(curthread, PRIV_DRIVER);
610c76ddeebSMark Johnston if (rc != 0)
611c76ddeebSMark Johnston break;
6122f345d8eSLuigi Rizzo rc = oce_handle_passthrough(ifp, data);
6132f345d8eSLuigi Rizzo break;
6142f345d8eSLuigi Rizzo default:
6152f345d8eSLuigi Rizzo rc = ether_ioctl(ifp, command, data);
6162f345d8eSLuigi Rizzo break;
6172f345d8eSLuigi Rizzo }
6182f345d8eSLuigi Rizzo
6192f345d8eSLuigi Rizzo return rc;
6202f345d8eSLuigi Rizzo }
6212f345d8eSLuigi Rizzo
6222f345d8eSLuigi Rizzo static void
oce_init(void * arg)6232f345d8eSLuigi Rizzo oce_init(void *arg)
6242f345d8eSLuigi Rizzo {
6252f345d8eSLuigi Rizzo POCE_SOFTC sc = arg;
6262f345d8eSLuigi Rizzo
6272f345d8eSLuigi Rizzo LOCK(&sc->dev_lock);
6282f345d8eSLuigi Rizzo
62967fd4c9dSJustin Hibbits if (if_getflags(sc->ifp) & IFF_UP) {
6302f345d8eSLuigi Rizzo oce_if_deactivate(sc);
6312f345d8eSLuigi Rizzo oce_if_activate(sc);
6322f345d8eSLuigi Rizzo }
6332f345d8eSLuigi Rizzo
6342f345d8eSLuigi Rizzo UNLOCK(&sc->dev_lock);
6352f345d8eSLuigi Rizzo
6362f345d8eSLuigi Rizzo }
6372f345d8eSLuigi Rizzo
6382f345d8eSLuigi Rizzo static int
oce_multiq_start(if_t ifp,struct mbuf * m)63967fd4c9dSJustin Hibbits oce_multiq_start(if_t ifp, struct mbuf *m)
6402f345d8eSLuigi Rizzo {
64167fd4c9dSJustin Hibbits POCE_SOFTC sc = if_getsoftc(ifp);
6422f345d8eSLuigi Rizzo struct oce_wq *wq = NULL;
6432f345d8eSLuigi Rizzo int queue_index = 0;
6442f345d8eSLuigi Rizzo int status = 0;
6452f345d8eSLuigi Rizzo
646c2625e6eSJosh Paetzel if (!sc->link_status)
647c2625e6eSJosh Paetzel return ENXIO;
648c2625e6eSJosh Paetzel
649c2529042SHans Petter Selasky if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
6502f345d8eSLuigi Rizzo queue_index = m->m_pkthdr.flowid % sc->nwqs;
6512f345d8eSLuigi Rizzo
6522f345d8eSLuigi Rizzo wq = sc->wq[queue_index];
6532f345d8eSLuigi Rizzo
654291a1934SXin LI LOCK(&wq->tx_lock);
6552f345d8eSLuigi Rizzo status = oce_multiq_transmit(ifp, m, wq);
6562f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock);
657291a1934SXin LI
6582f345d8eSLuigi Rizzo return status;
6592f345d8eSLuigi Rizzo
6602f345d8eSLuigi Rizzo }
6612f345d8eSLuigi Rizzo
6622f345d8eSLuigi Rizzo static void
oce_multiq_flush(if_t ifp)66367fd4c9dSJustin Hibbits oce_multiq_flush(if_t ifp)
6642f345d8eSLuigi Rizzo {
66567fd4c9dSJustin Hibbits POCE_SOFTC sc = if_getsoftc(ifp);
6662f345d8eSLuigi Rizzo struct mbuf *m;
6672f345d8eSLuigi Rizzo int i = 0;
6682f345d8eSLuigi Rizzo
6692f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++) {
6702f345d8eSLuigi Rizzo while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
6712f345d8eSLuigi Rizzo m_freem(m);
6722f345d8eSLuigi Rizzo }
6732f345d8eSLuigi Rizzo if_qflush(ifp);
6742f345d8eSLuigi Rizzo }
6752f345d8eSLuigi Rizzo
6762f345d8eSLuigi Rizzo /*****************************************************************************
6772f345d8eSLuigi Rizzo * Driver interrupt routines functions *
6782f345d8eSLuigi Rizzo *****************************************************************************/
6792f345d8eSLuigi Rizzo
6802f345d8eSLuigi Rizzo static void
oce_intr(void * arg,int pending)6812f345d8eSLuigi Rizzo oce_intr(void *arg, int pending)
6822f345d8eSLuigi Rizzo {
6832f345d8eSLuigi Rizzo
6842f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
6852f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc;
6862f345d8eSLuigi Rizzo struct oce_eq *eq = ii->eq;
6872f345d8eSLuigi Rizzo struct oce_eqe *eqe;
6882f345d8eSLuigi Rizzo struct oce_cq *cq = NULL;
6892f345d8eSLuigi Rizzo int i, num_eqes = 0;
6902f345d8eSLuigi Rizzo
6912f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
6922f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE);
6932f345d8eSLuigi Rizzo do {
6942f345d8eSLuigi Rizzo eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
6952f345d8eSLuigi Rizzo if (eqe->evnt == 0)
6962f345d8eSLuigi Rizzo break;
6972f345d8eSLuigi Rizzo eqe->evnt = 0;
6982f345d8eSLuigi Rizzo bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
6992f345d8eSLuigi Rizzo BUS_DMASYNC_POSTWRITE);
7002f345d8eSLuigi Rizzo RING_GET(eq->ring, 1);
7012f345d8eSLuigi Rizzo num_eqes++;
7022f345d8eSLuigi Rizzo
7032f345d8eSLuigi Rizzo } while (TRUE);
7042f345d8eSLuigi Rizzo
7052f345d8eSLuigi Rizzo if (!num_eqes)
7062f345d8eSLuigi Rizzo goto eq_arm; /* Spurious */
7072f345d8eSLuigi Rizzo
7082f345d8eSLuigi Rizzo /* Clear EQ entries, but dont arm */
7092f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
7102f345d8eSLuigi Rizzo
7112f345d8eSLuigi Rizzo /* Process TX, RX and MCC. But dont arm CQ*/
7122f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) {
7132f345d8eSLuigi Rizzo cq = eq->cq[i];
7142f345d8eSLuigi Rizzo (*cq->cq_handler)(cq->cb_arg);
7152f345d8eSLuigi Rizzo }
7162f345d8eSLuigi Rizzo
7172f345d8eSLuigi Rizzo /* Arm all cqs connected to this EQ */
7182f345d8eSLuigi Rizzo for (i = 0; i < eq->cq_valid; i++) {
7192f345d8eSLuigi Rizzo cq = eq->cq[i];
7202f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, 0, TRUE);
7212f345d8eSLuigi Rizzo }
7222f345d8eSLuigi Rizzo
7232f345d8eSLuigi Rizzo eq_arm:
7242f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
725cdaba892SXin LI
7262f345d8eSLuigi Rizzo return;
7272f345d8eSLuigi Rizzo }
7282f345d8eSLuigi Rizzo
7292f345d8eSLuigi Rizzo static int
oce_setup_intr(POCE_SOFTC sc)7302f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc)
7312f345d8eSLuigi Rizzo {
7322f345d8eSLuigi Rizzo int rc = 0, use_intx = 0;
7332f345d8eSLuigi Rizzo int vector = 0, req_vectors = 0;
734c2625e6eSJosh Paetzel int tot_req_vectors, tot_vectors;
7352f345d8eSLuigi Rizzo
736291a1934SXin LI if (is_rss_enabled(sc))
7372f345d8eSLuigi Rizzo req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
7382f345d8eSLuigi Rizzo else
7392f345d8eSLuigi Rizzo req_vectors = 1;
7402f345d8eSLuigi Rizzo
741c2625e6eSJosh Paetzel tot_req_vectors = req_vectors;
742c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
743c2625e6eSJosh Paetzel if (req_vectors > 1) {
744c2625e6eSJosh Paetzel tot_req_vectors += OCE_RDMA_VECTORS;
745c2625e6eSJosh Paetzel sc->roce_intr_count = OCE_RDMA_VECTORS;
746c2625e6eSJosh Paetzel }
747c2625e6eSJosh Paetzel }
748c2625e6eSJosh Paetzel
7492f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
7502f345d8eSLuigi Rizzo sc->intr_count = req_vectors;
751c2625e6eSJosh Paetzel tot_vectors = tot_req_vectors;
752c2625e6eSJosh Paetzel rc = pci_alloc_msix(sc->dev, &tot_vectors);
7532f345d8eSLuigi Rizzo if (rc != 0) {
7542f345d8eSLuigi Rizzo use_intx = 1;
7552f345d8eSLuigi Rizzo pci_release_msi(sc->dev);
756c2625e6eSJosh Paetzel } else {
757c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
758c2625e6eSJosh Paetzel if (tot_vectors < tot_req_vectors) {
759c2625e6eSJosh Paetzel if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) {
760c2625e6eSJosh Paetzel sc->roce_intr_count = (tot_vectors / 2);
761c2625e6eSJosh Paetzel }
762c2625e6eSJosh Paetzel sc->intr_count = tot_vectors - sc->roce_intr_count;
763c2625e6eSJosh Paetzel }
764c2625e6eSJosh Paetzel } else {
765c2625e6eSJosh Paetzel sc->intr_count = tot_vectors;
766c2625e6eSJosh Paetzel }
7672f345d8eSLuigi Rizzo sc->flags |= OCE_FLAGS_USING_MSIX;
768c2625e6eSJosh Paetzel }
7692f345d8eSLuigi Rizzo } else
7702f345d8eSLuigi Rizzo use_intx = 1;
7712f345d8eSLuigi Rizzo
7722f345d8eSLuigi Rizzo if (use_intx)
7732f345d8eSLuigi Rizzo sc->intr_count = 1;
7742f345d8eSLuigi Rizzo
7752f345d8eSLuigi Rizzo /* Scale number of queues based on intr we got */
7762f345d8eSLuigi Rizzo update_queues_got(sc);
7772f345d8eSLuigi Rizzo
7782f345d8eSLuigi Rizzo if (use_intx) {
7792f345d8eSLuigi Rizzo device_printf(sc->dev, "Using legacy interrupt\n");
7802f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr);
7812f345d8eSLuigi Rizzo if (rc)
7822f345d8eSLuigi Rizzo goto error;
7832f345d8eSLuigi Rizzo } else {
7842f345d8eSLuigi Rizzo for (; vector < sc->intr_count; vector++) {
7852f345d8eSLuigi Rizzo rc = oce_alloc_intr(sc, vector, oce_intr);
7862f345d8eSLuigi Rizzo if (rc)
7872f345d8eSLuigi Rizzo goto error;
7882f345d8eSLuigi Rizzo }
7892f345d8eSLuigi Rizzo }
7902f345d8eSLuigi Rizzo
7912f345d8eSLuigi Rizzo return 0;
7922f345d8eSLuigi Rizzo error:
7932f345d8eSLuigi Rizzo oce_intr_free(sc);
7942f345d8eSLuigi Rizzo return rc;
7952f345d8eSLuigi Rizzo }
7962f345d8eSLuigi Rizzo
7972f345d8eSLuigi Rizzo static int
oce_fast_isr(void * arg)7982f345d8eSLuigi Rizzo oce_fast_isr(void *arg)
7992f345d8eSLuigi Rizzo {
8002f345d8eSLuigi Rizzo POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
8012f345d8eSLuigi Rizzo POCE_SOFTC sc = ii->sc;
8022f345d8eSLuigi Rizzo
8032f345d8eSLuigi Rizzo if (ii->eq == NULL)
8042f345d8eSLuigi Rizzo return FILTER_STRAY;
8052f345d8eSLuigi Rizzo
8062f345d8eSLuigi Rizzo oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
8072f345d8eSLuigi Rizzo
808cbc4d2dbSJohn Baldwin taskqueue_enqueue(ii->tq, &ii->task);
8092f345d8eSLuigi Rizzo
810cdaba892SXin LI ii->eq->intr++;
811cdaba892SXin LI
8122f345d8eSLuigi Rizzo return FILTER_HANDLED;
8132f345d8eSLuigi Rizzo }
8142f345d8eSLuigi Rizzo
8152f345d8eSLuigi Rizzo static int
oce_alloc_intr(POCE_SOFTC sc,int vector,void (* isr)(void * arg,int pending))8162f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
8172f345d8eSLuigi Rizzo {
818ab7de25cSKyle Evans POCE_INTR_INFO ii;
8192f345d8eSLuigi Rizzo int rc = 0, rr;
8202f345d8eSLuigi Rizzo
8212f345d8eSLuigi Rizzo if (vector >= OCE_MAX_EQ)
8222f345d8eSLuigi Rizzo return (EINVAL);
8232f345d8eSLuigi Rizzo
824ab7de25cSKyle Evans ii = &sc->intrs[vector];
825ab7de25cSKyle Evans
8262f345d8eSLuigi Rizzo /* Set the resource id for the interrupt.
8272f345d8eSLuigi Rizzo * MSIx is vector + 1 for the resource id,
8282f345d8eSLuigi Rizzo * INTx is 0 for the resource id.
8292f345d8eSLuigi Rizzo */
8302f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX)
8312f345d8eSLuigi Rizzo rr = vector + 1;
8322f345d8eSLuigi Rizzo else
8332f345d8eSLuigi Rizzo rr = 0;
8342f345d8eSLuigi Rizzo ii->intr_res = bus_alloc_resource_any(sc->dev,
8352f345d8eSLuigi Rizzo SYS_RES_IRQ,
8362f345d8eSLuigi Rizzo &rr, RF_ACTIVE|RF_SHAREABLE);
8372f345d8eSLuigi Rizzo ii->irq_rr = rr;
8382f345d8eSLuigi Rizzo if (ii->intr_res == NULL) {
8392f345d8eSLuigi Rizzo device_printf(sc->dev,
8402f345d8eSLuigi Rizzo "Could not allocate interrupt\n");
8412f345d8eSLuigi Rizzo rc = ENXIO;
8422f345d8eSLuigi Rizzo return rc;
8432f345d8eSLuigi Rizzo }
8442f345d8eSLuigi Rizzo
8452f345d8eSLuigi Rizzo TASK_INIT(&ii->task, 0, isr, ii);
8462f345d8eSLuigi Rizzo ii->vector = vector;
8472f345d8eSLuigi Rizzo sprintf(ii->task_name, "oce_task[%d]", ii->vector);
8482f345d8eSLuigi Rizzo ii->tq = taskqueue_create_fast(ii->task_name,
8492f345d8eSLuigi Rizzo M_NOWAIT,
8502f345d8eSLuigi Rizzo taskqueue_thread_enqueue,
8512f345d8eSLuigi Rizzo &ii->tq);
8522f345d8eSLuigi Rizzo taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
8532f345d8eSLuigi Rizzo device_get_nameunit(sc->dev));
8542f345d8eSLuigi Rizzo
8552f345d8eSLuigi Rizzo ii->sc = sc;
8562f345d8eSLuigi Rizzo rc = bus_setup_intr(sc->dev,
8572f345d8eSLuigi Rizzo ii->intr_res,
8582f345d8eSLuigi Rizzo INTR_TYPE_NET,
8592f345d8eSLuigi Rizzo oce_fast_isr, NULL, ii, &ii->tag);
8602f345d8eSLuigi Rizzo return rc;
8612f345d8eSLuigi Rizzo
8622f345d8eSLuigi Rizzo }
8632f345d8eSLuigi Rizzo
8642f345d8eSLuigi Rizzo void
oce_intr_free(POCE_SOFTC sc)8652f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc)
8662f345d8eSLuigi Rizzo {
8672f345d8eSLuigi Rizzo int i = 0;
8682f345d8eSLuigi Rizzo
8692f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) {
8702f345d8eSLuigi Rizzo
8712f345d8eSLuigi Rizzo if (sc->intrs[i].tag != NULL)
8722f345d8eSLuigi Rizzo bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
8732f345d8eSLuigi Rizzo sc->intrs[i].tag);
8742f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL)
8752f345d8eSLuigi Rizzo taskqueue_free(sc->intrs[i].tq);
8762f345d8eSLuigi Rizzo
8772f345d8eSLuigi Rizzo if (sc->intrs[i].intr_res != NULL)
8782f345d8eSLuigi Rizzo bus_release_resource(sc->dev, SYS_RES_IRQ,
8792f345d8eSLuigi Rizzo sc->intrs[i].irq_rr,
8802f345d8eSLuigi Rizzo sc->intrs[i].intr_res);
8812f345d8eSLuigi Rizzo sc->intrs[i].tag = NULL;
8822f345d8eSLuigi Rizzo sc->intrs[i].intr_res = NULL;
8832f345d8eSLuigi Rizzo }
8842f345d8eSLuigi Rizzo
8852f345d8eSLuigi Rizzo if (sc->flags & OCE_FLAGS_USING_MSIX)
8862f345d8eSLuigi Rizzo pci_release_msi(sc->dev);
8872f345d8eSLuigi Rizzo
8882f345d8eSLuigi Rizzo }
8892f345d8eSLuigi Rizzo
8902f345d8eSLuigi Rizzo /******************************************************************************
8912f345d8eSLuigi Rizzo * Media callbacks functions *
8922f345d8eSLuigi Rizzo ******************************************************************************/
8932f345d8eSLuigi Rizzo
8942f345d8eSLuigi Rizzo static void
oce_media_status(if_t ifp,struct ifmediareq * req)89567fd4c9dSJustin Hibbits oce_media_status(if_t ifp, struct ifmediareq *req)
8962f345d8eSLuigi Rizzo {
89767fd4c9dSJustin Hibbits POCE_SOFTC sc = (POCE_SOFTC) if_getsoftc(ifp);
8982f345d8eSLuigi Rizzo
8992f345d8eSLuigi Rizzo req->ifm_status = IFM_AVALID;
9002f345d8eSLuigi Rizzo req->ifm_active = IFM_ETHER;
9012f345d8eSLuigi Rizzo
9022f345d8eSLuigi Rizzo if (sc->link_status == 1)
9032f345d8eSLuigi Rizzo req->ifm_status |= IFM_ACTIVE;
9042f345d8eSLuigi Rizzo else
9052f345d8eSLuigi Rizzo return;
9062f345d8eSLuigi Rizzo
9072f345d8eSLuigi Rizzo switch (sc->link_speed) {
9082f345d8eSLuigi Rizzo case 1: /* 10 Mbps */
9092f345d8eSLuigi Rizzo req->ifm_active |= IFM_10_T | IFM_FDX;
9102f345d8eSLuigi Rizzo sc->speed = 10;
9112f345d8eSLuigi Rizzo break;
9122f345d8eSLuigi Rizzo case 2: /* 100 Mbps */
9132f345d8eSLuigi Rizzo req->ifm_active |= IFM_100_TX | IFM_FDX;
9142f345d8eSLuigi Rizzo sc->speed = 100;
9152f345d8eSLuigi Rizzo break;
9162f345d8eSLuigi Rizzo case 3: /* 1 Gbps */
9172f345d8eSLuigi Rizzo req->ifm_active |= IFM_1000_T | IFM_FDX;
9182f345d8eSLuigi Rizzo sc->speed = 1000;
9192f345d8eSLuigi Rizzo break;
9202f345d8eSLuigi Rizzo case 4: /* 10 Gbps */
9212f345d8eSLuigi Rizzo req->ifm_active |= IFM_10G_SR | IFM_FDX;
9222f345d8eSLuigi Rizzo sc->speed = 10000;
9232f345d8eSLuigi Rizzo break;
924a4f734b4SXin LI case 5: /* 20 Gbps */
925a4f734b4SXin LI req->ifm_active |= IFM_10G_SR | IFM_FDX;
926a4f734b4SXin LI sc->speed = 20000;
927a4f734b4SXin LI break;
928a4f734b4SXin LI case 6: /* 25 Gbps */
929a4f734b4SXin LI req->ifm_active |= IFM_10G_SR | IFM_FDX;
930a4f734b4SXin LI sc->speed = 25000;
931a4f734b4SXin LI break;
932b41206d8SXin LI case 7: /* 40 Gbps */
933b41206d8SXin LI req->ifm_active |= IFM_40G_SR4 | IFM_FDX;
934b41206d8SXin LI sc->speed = 40000;
935b41206d8SXin LI break;
936a4f734b4SXin LI default:
937a4f734b4SXin LI sc->speed = 0;
938a4f734b4SXin LI break;
9392f345d8eSLuigi Rizzo }
9402f345d8eSLuigi Rizzo
9412f345d8eSLuigi Rizzo return;
9422f345d8eSLuigi Rizzo }
9432f345d8eSLuigi Rizzo
9442f345d8eSLuigi Rizzo int
oce_media_change(if_t ifp)94567fd4c9dSJustin Hibbits oce_media_change(if_t ifp)
9462f345d8eSLuigi Rizzo {
9472f345d8eSLuigi Rizzo return 0;
9482f345d8eSLuigi Rizzo }
9492f345d8eSLuigi Rizzo
oce_is_pkt_dest_bmc(POCE_SOFTC sc,struct mbuf * m,boolean_t * os2bmc,struct mbuf ** m_new)950c2625e6eSJosh Paetzel static void oce_is_pkt_dest_bmc(POCE_SOFTC sc,
951c2625e6eSJosh Paetzel struct mbuf *m, boolean_t *os2bmc,
952c2625e6eSJosh Paetzel struct mbuf **m_new)
953c2625e6eSJosh Paetzel {
954c2625e6eSJosh Paetzel struct ether_header *eh = NULL;
955c2625e6eSJosh Paetzel
956c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *);
957c2625e6eSJosh Paetzel
958c2625e6eSJosh Paetzel if (!is_os2bmc_enabled(sc) || *os2bmc) {
959c2625e6eSJosh Paetzel *os2bmc = FALSE;
960c2625e6eSJosh Paetzel goto done;
961c2625e6eSJosh Paetzel }
962c2625e6eSJosh Paetzel if (!ETHER_IS_MULTICAST(eh->ether_dhost))
963c2625e6eSJosh Paetzel goto done;
964c2625e6eSJosh Paetzel
965c2625e6eSJosh Paetzel if (is_mc_allowed_on_bmc(sc, eh) ||
966c2625e6eSJosh Paetzel is_bc_allowed_on_bmc(sc, eh) ||
967c2625e6eSJosh Paetzel is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) {
968c2625e6eSJosh Paetzel *os2bmc = TRUE;
969c2625e6eSJosh Paetzel goto done;
970c2625e6eSJosh Paetzel }
971c2625e6eSJosh Paetzel
972c2625e6eSJosh Paetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) {
973c2625e6eSJosh Paetzel struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
974c2625e6eSJosh Paetzel uint8_t nexthdr = ip6->ip6_nxt;
975c2625e6eSJosh Paetzel if (nexthdr == IPPROTO_ICMPV6) {
976c2625e6eSJosh Paetzel struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1);
977c2625e6eSJosh Paetzel switch (icmp6->icmp6_type) {
978c2625e6eSJosh Paetzel case ND_ROUTER_ADVERT:
979c2625e6eSJosh Paetzel *os2bmc = is_ipv6_ra_filt_enabled(sc);
980c2625e6eSJosh Paetzel goto done;
981c2625e6eSJosh Paetzel case ND_NEIGHBOR_ADVERT:
982c2625e6eSJosh Paetzel *os2bmc = is_ipv6_na_filt_enabled(sc);
983c2625e6eSJosh Paetzel goto done;
984c2625e6eSJosh Paetzel default:
985c2625e6eSJosh Paetzel break;
986c2625e6eSJosh Paetzel }
987c2625e6eSJosh Paetzel }
988c2625e6eSJosh Paetzel }
989c2625e6eSJosh Paetzel
990c2625e6eSJosh Paetzel if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) {
991c2625e6eSJosh Paetzel struct ip *ip = mtod(m, struct ip *);
992c2625e6eSJosh Paetzel int iphlen = ip->ip_hl << 2;
993c2625e6eSJosh Paetzel struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen);
994c2625e6eSJosh Paetzel switch (uh->uh_dport) {
995c2625e6eSJosh Paetzel case DHCP_CLIENT_PORT:
996c2625e6eSJosh Paetzel *os2bmc = is_dhcp_client_filt_enabled(sc);
997c2625e6eSJosh Paetzel goto done;
998c2625e6eSJosh Paetzel case DHCP_SERVER_PORT:
999c2625e6eSJosh Paetzel *os2bmc = is_dhcp_srvr_filt_enabled(sc);
1000c2625e6eSJosh Paetzel goto done;
1001c2625e6eSJosh Paetzel case NET_BIOS_PORT1:
1002c2625e6eSJosh Paetzel case NET_BIOS_PORT2:
1003c2625e6eSJosh Paetzel *os2bmc = is_nbios_filt_enabled(sc);
1004c2625e6eSJosh Paetzel goto done;
1005c2625e6eSJosh Paetzel case DHCPV6_RAS_PORT:
1006c2625e6eSJosh Paetzel *os2bmc = is_ipv6_ras_filt_enabled(sc);
1007c2625e6eSJosh Paetzel goto done;
1008c2625e6eSJosh Paetzel default:
1009c2625e6eSJosh Paetzel break;
1010c2625e6eSJosh Paetzel }
1011c2625e6eSJosh Paetzel }
1012c2625e6eSJosh Paetzel done:
1013c2625e6eSJosh Paetzel if (*os2bmc) {
1014c2625e6eSJosh Paetzel *m_new = m_dup(m, M_NOWAIT);
1015c2625e6eSJosh Paetzel if (!*m_new) {
1016c2625e6eSJosh Paetzel *os2bmc = FALSE;
1017c2625e6eSJosh Paetzel return;
1018c2625e6eSJosh Paetzel }
1019c2625e6eSJosh Paetzel *m_new = oce_insert_vlan_tag(sc, *m_new, NULL);
1020c2625e6eSJosh Paetzel }
1021c2625e6eSJosh Paetzel }
1022c2625e6eSJosh Paetzel
10232f345d8eSLuigi Rizzo /*****************************************************************************
10242f345d8eSLuigi Rizzo * Transmit routines functions *
10252f345d8eSLuigi Rizzo *****************************************************************************/
10262f345d8eSLuigi Rizzo
10272f345d8eSLuigi Rizzo static int
oce_tx(POCE_SOFTC sc,struct mbuf ** mpp,int wq_index)10282f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
10292f345d8eSLuigi Rizzo {
10302f345d8eSLuigi Rizzo int rc = 0, i, retry_cnt = 0;
10312f345d8eSLuigi Rizzo bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
1032c2625e6eSJosh Paetzel struct mbuf *m, *m_temp, *m_new = NULL;
10332f345d8eSLuigi Rizzo struct oce_wq *wq = sc->wq[wq_index];
10342f345d8eSLuigi Rizzo struct oce_packet_desc *pd;
10352f345d8eSLuigi Rizzo struct oce_nic_hdr_wqe *nichdr;
10362f345d8eSLuigi Rizzo struct oce_nic_frag_wqe *nicfrag;
1037c2625e6eSJosh Paetzel struct ether_header *eh = NULL;
10382f345d8eSLuigi Rizzo int num_wqes;
10392f345d8eSLuigi Rizzo uint32_t reg_value;
1040cdaba892SXin LI boolean_t complete = TRUE;
1041c2625e6eSJosh Paetzel boolean_t os2bmc = FALSE;
10422f345d8eSLuigi Rizzo
10432f345d8eSLuigi Rizzo m = *mpp;
10442f345d8eSLuigi Rizzo if (!m)
10452f345d8eSLuigi Rizzo return EINVAL;
10462f345d8eSLuigi Rizzo
10472f345d8eSLuigi Rizzo if (!(m->m_flags & M_PKTHDR)) {
10482f345d8eSLuigi Rizzo rc = ENXIO;
10492f345d8eSLuigi Rizzo goto free_ret;
10502f345d8eSLuigi Rizzo }
10512f345d8eSLuigi Rizzo
1052c2625e6eSJosh Paetzel /* Don't allow non-TSO packets longer than MTU */
1053c2625e6eSJosh Paetzel if (!is_tso_pkt(m)) {
1054c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *);
1055c2625e6eSJosh Paetzel if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE))
1056c2625e6eSJosh Paetzel goto free_ret;
1057c2625e6eSJosh Paetzel }
1058c2625e6eSJosh Paetzel
1059cdaba892SXin LI if(oce_tx_asic_stall_verify(sc, m)) {
1060cdaba892SXin LI m = oce_insert_vlan_tag(sc, m, &complete);
1061cdaba892SXin LI if(!m) {
1062cdaba892SXin LI device_printf(sc->dev, "Insertion unsuccessful\n");
1063cdaba892SXin LI return 0;
1064cdaba892SXin LI }
1065cdaba892SXin LI }
1066cdaba892SXin LI
1067c2625e6eSJosh Paetzel /* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less
1068c2625e6eSJosh Paetzel * may cause a transmit stall on that port. So the work-around is to
1069c2625e6eSJosh Paetzel * pad short packets (<= 32 bytes) to a 36-byte length.
1070c2625e6eSJosh Paetzel */
1071c2625e6eSJosh Paetzel if(IS_SH(sc) || IS_XE201(sc) ) {
1072c2625e6eSJosh Paetzel if(m->m_pkthdr.len <= 32) {
1073c2625e6eSJosh Paetzel char buf[36];
1074c2625e6eSJosh Paetzel bzero((void *)buf, 36);
1075c2625e6eSJosh Paetzel m_append(m, (36 - m->m_pkthdr.len), buf);
1076c2625e6eSJosh Paetzel }
1077c2625e6eSJosh Paetzel }
1078c2625e6eSJosh Paetzel
1079c2625e6eSJosh Paetzel tx_start:
10802f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) {
10812f345d8eSLuigi Rizzo /* consolidate packet buffers for TSO/LSO segment offload */
10829bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
10839bd3250aSLuigi Rizzo m = oce_tso_setup(sc, mpp);
1084ad512958SBjoern A. Zeeb #else
1085ad512958SBjoern A. Zeeb m = NULL;
1086ad512958SBjoern A. Zeeb #endif
10872f345d8eSLuigi Rizzo if (m == NULL) {
10882f345d8eSLuigi Rizzo rc = ENXIO;
10892f345d8eSLuigi Rizzo goto free_ret;
10902f345d8eSLuigi Rizzo }
10912f345d8eSLuigi Rizzo }
10922f345d8eSLuigi Rizzo
1093291a1934SXin LI pd = &wq->pckts[wq->pkt_desc_head];
1094c2625e6eSJosh Paetzel
10952f345d8eSLuigi Rizzo retry:
10962f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(wq->tag,
10972f345d8eSLuigi Rizzo pd->map,
10982f345d8eSLuigi Rizzo m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
10992f345d8eSLuigi Rizzo if (rc == 0) {
11002f345d8eSLuigi Rizzo num_wqes = pd->nsegs + 1;
1101291a1934SXin LI if (IS_BE(sc) || IS_SH(sc)) {
11022f345d8eSLuigi Rizzo /*Dummy required only for BE3.*/
11032f345d8eSLuigi Rizzo if (num_wqes & 1)
11042f345d8eSLuigi Rizzo num_wqes++;
11052f345d8eSLuigi Rizzo }
11062f345d8eSLuigi Rizzo if (num_wqes >= RING_NUM_FREE(wq->ring)) {
11072f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map);
11082f345d8eSLuigi Rizzo return EBUSY;
11092f345d8eSLuigi Rizzo }
1110291a1934SXin LI atomic_store_rel_int(&wq->pkt_desc_head,
1111291a1934SXin LI (wq->pkt_desc_head + 1) % \
1112291a1934SXin LI OCE_WQ_PACKET_ARRAY_SIZE);
11132f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
11142f345d8eSLuigi Rizzo pd->mbuf = m;
11152f345d8eSLuigi Rizzo
11162f345d8eSLuigi Rizzo nichdr =
11172f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
11182f345d8eSLuigi Rizzo nichdr->u0.dw[0] = 0;
11192f345d8eSLuigi Rizzo nichdr->u0.dw[1] = 0;
11202f345d8eSLuigi Rizzo nichdr->u0.dw[2] = 0;
11212f345d8eSLuigi Rizzo nichdr->u0.dw[3] = 0;
11222f345d8eSLuigi Rizzo
1123cdaba892SXin LI nichdr->u0.s.complete = complete;
1124c2625e6eSJosh Paetzel nichdr->u0.s.mgmt = os2bmc;
11252f345d8eSLuigi Rizzo nichdr->u0.s.event = 1;
11262f345d8eSLuigi Rizzo nichdr->u0.s.crc = 1;
11272f345d8eSLuigi Rizzo nichdr->u0.s.forward = 0;
11282f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
11292f345d8eSLuigi Rizzo nichdr->u0.s.udpcs =
11302f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
11312f345d8eSLuigi Rizzo nichdr->u0.s.tcpcs =
11322f345d8eSLuigi Rizzo (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
11332f345d8eSLuigi Rizzo nichdr->u0.s.num_wqe = num_wqes;
11342f345d8eSLuigi Rizzo nichdr->u0.s.total_length = m->m_pkthdr.len;
11355fbb6830SXin LI
11362f345d8eSLuigi Rizzo if (m->m_flags & M_VLANTAG) {
11372f345d8eSLuigi Rizzo nichdr->u0.s.vlan = 1; /*Vlan present*/
11382f345d8eSLuigi Rizzo nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
11392f345d8eSLuigi Rizzo }
11405fbb6830SXin LI
11412f345d8eSLuigi Rizzo if (m->m_pkthdr.csum_flags & CSUM_TSO) {
11422f345d8eSLuigi Rizzo if (m->m_pkthdr.tso_segsz) {
11432f345d8eSLuigi Rizzo nichdr->u0.s.lso = 1;
11442f345d8eSLuigi Rizzo nichdr->u0.s.lso_mss = m->m_pkthdr.tso_segsz;
11452f345d8eSLuigi Rizzo }
1146291a1934SXin LI if (!IS_BE(sc) || !IS_SH(sc))
11472f345d8eSLuigi Rizzo nichdr->u0.s.ipcs = 1;
11482f345d8eSLuigi Rizzo }
11492f345d8eSLuigi Rizzo
11502f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1);
1151291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1);
11522f345d8eSLuigi Rizzo
11532f345d8eSLuigi Rizzo for (i = 0; i < pd->nsegs; i++) {
11542f345d8eSLuigi Rizzo nicfrag =
11552f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring,
11562f345d8eSLuigi Rizzo struct oce_nic_frag_wqe);
11572f345d8eSLuigi Rizzo nicfrag->u0.s.rsvd0 = 0;
11582f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
11592f345d8eSLuigi Rizzo nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
11602f345d8eSLuigi Rizzo nicfrag->u0.s.frag_len = segs[i].ds_len;
11612f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx;
11622f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1);
1163291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1);
11642f345d8eSLuigi Rizzo }
11652f345d8eSLuigi Rizzo if (num_wqes > (pd->nsegs + 1)) {
11662f345d8eSLuigi Rizzo nicfrag =
11672f345d8eSLuigi Rizzo RING_GET_PRODUCER_ITEM_VA(wq->ring,
11682f345d8eSLuigi Rizzo struct oce_nic_frag_wqe);
11692f345d8eSLuigi Rizzo nicfrag->u0.dw[0] = 0;
11702f345d8eSLuigi Rizzo nicfrag->u0.dw[1] = 0;
11712f345d8eSLuigi Rizzo nicfrag->u0.dw[2] = 0;
11722f345d8eSLuigi Rizzo nicfrag->u0.dw[3] = 0;
11732f345d8eSLuigi Rizzo pd->wqe_idx = wq->ring->pidx;
11742f345d8eSLuigi Rizzo RING_PUT(wq->ring, 1);
1175291a1934SXin LI atomic_add_int(&wq->ring->num_used, 1);
11762f345d8eSLuigi Rizzo pd->nsegs++;
11772f345d8eSLuigi Rizzo }
11782f345d8eSLuigi Rizzo
1179c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
11802f345d8eSLuigi Rizzo wq->tx_stats.tx_reqs++;
11812f345d8eSLuigi Rizzo wq->tx_stats.tx_wrbs += num_wqes;
11822f345d8eSLuigi Rizzo wq->tx_stats.tx_bytes += m->m_pkthdr.len;
11832f345d8eSLuigi Rizzo wq->tx_stats.tx_pkts++;
11842f345d8eSLuigi Rizzo
11852f345d8eSLuigi Rizzo bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
11862f345d8eSLuigi Rizzo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11872f345d8eSLuigi Rizzo reg_value = (num_wqes << 16) | wq->wq_id;
1188c2625e6eSJosh Paetzel
1189c2625e6eSJosh Paetzel /* if os2bmc is not enabled or if the pkt is already tagged as
1190c2625e6eSJosh Paetzel bmc, do nothing
1191c2625e6eSJosh Paetzel */
1192c2625e6eSJosh Paetzel oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new);
1193c2625e6eSJosh Paetzel
1194b75a7728SConrad Meyer if_inc_counter(sc->ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
1195b75a7728SConrad Meyer if (m->m_flags & M_MCAST)
1196b75a7728SConrad Meyer if_inc_counter(sc->ifp, IFCOUNTER_OMCASTS, 1);
1197b75a7728SConrad Meyer ETHER_BPF_MTAP(sc->ifp, m);
1198b75a7728SConrad Meyer
1199291a1934SXin LI OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value);
12002f345d8eSLuigi Rizzo
12012f345d8eSLuigi Rizzo } else if (rc == EFBIG) {
12022f345d8eSLuigi Rizzo if (retry_cnt == 0) {
1203c6499eccSGleb Smirnoff m_temp = m_defrag(m, M_NOWAIT);
12042f345d8eSLuigi Rizzo if (m_temp == NULL)
12052f345d8eSLuigi Rizzo goto free_ret;
12062f345d8eSLuigi Rizzo m = m_temp;
12072f345d8eSLuigi Rizzo *mpp = m_temp;
12082f345d8eSLuigi Rizzo retry_cnt = retry_cnt + 1;
12092f345d8eSLuigi Rizzo goto retry;
12102f345d8eSLuigi Rizzo } else
12112f345d8eSLuigi Rizzo goto free_ret;
12122f345d8eSLuigi Rizzo } else if (rc == ENOMEM)
12132f345d8eSLuigi Rizzo return rc;
12142f345d8eSLuigi Rizzo else
12152f345d8eSLuigi Rizzo goto free_ret;
12162f345d8eSLuigi Rizzo
1217c2625e6eSJosh Paetzel if (os2bmc) {
1218c2625e6eSJosh Paetzel m = m_new;
1219c2625e6eSJosh Paetzel goto tx_start;
1220c2625e6eSJosh Paetzel }
1221c2625e6eSJosh Paetzel
12222f345d8eSLuigi Rizzo return 0;
12232f345d8eSLuigi Rizzo
12242f345d8eSLuigi Rizzo free_ret:
12252f345d8eSLuigi Rizzo m_freem(*mpp);
12262f345d8eSLuigi Rizzo *mpp = NULL;
12272f345d8eSLuigi Rizzo return rc;
12282f345d8eSLuigi Rizzo }
12292f345d8eSLuigi Rizzo
12302f345d8eSLuigi Rizzo static void
oce_process_tx_completion(struct oce_wq * wq)1231c2625e6eSJosh Paetzel oce_process_tx_completion(struct oce_wq *wq)
12322f345d8eSLuigi Rizzo {
12332f345d8eSLuigi Rizzo struct oce_packet_desc *pd;
12342f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
12352f345d8eSLuigi Rizzo struct mbuf *m;
12362f345d8eSLuigi Rizzo
1237291a1934SXin LI pd = &wq->pckts[wq->pkt_desc_tail];
1238291a1934SXin LI atomic_store_rel_int(&wq->pkt_desc_tail,
1239291a1934SXin LI (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE);
1240291a1934SXin LI atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1);
12412f345d8eSLuigi Rizzo bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
12422f345d8eSLuigi Rizzo bus_dmamap_unload(wq->tag, pd->map);
12432f345d8eSLuigi Rizzo
12442f345d8eSLuigi Rizzo m = pd->mbuf;
12452f345d8eSLuigi Rizzo m_freem(m);
12462f345d8eSLuigi Rizzo pd->mbuf = NULL;
12472f345d8eSLuigi Rizzo
124867fd4c9dSJustin Hibbits if (if_getdrvflags(sc->ifp) & IFF_DRV_OACTIVE) {
12492f345d8eSLuigi Rizzo if (wq->ring->num_used < (wq->ring->num_items / 2)) {
125067fd4c9dSJustin Hibbits if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_OACTIVE));
12512f345d8eSLuigi Rizzo oce_tx_restart(sc, wq);
12522f345d8eSLuigi Rizzo }
12532f345d8eSLuigi Rizzo }
12542f345d8eSLuigi Rizzo }
12552f345d8eSLuigi Rizzo
12562f345d8eSLuigi Rizzo static void
oce_tx_restart(POCE_SOFTC sc,struct oce_wq * wq)12572f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
12582f345d8eSLuigi Rizzo {
12592f345d8eSLuigi Rizzo
126067fd4c9dSJustin Hibbits if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
12612f345d8eSLuigi Rizzo return;
12622f345d8eSLuigi Rizzo
12632f345d8eSLuigi Rizzo if (!drbr_empty(sc->ifp, wq->br))
1264cbc4d2dbSJohn Baldwin taskqueue_enqueue(taskqueue_swi, &wq->txtask);
12652f345d8eSLuigi Rizzo
12662f345d8eSLuigi Rizzo }
12672f345d8eSLuigi Rizzo
1268ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
12692f345d8eSLuigi Rizzo static struct mbuf *
oce_tso_setup(POCE_SOFTC sc,struct mbuf ** mpp)12709bd3250aSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
12712f345d8eSLuigi Rizzo {
12722f345d8eSLuigi Rizzo struct mbuf *m;
1273ad512958SBjoern A. Zeeb #ifdef INET
12742f345d8eSLuigi Rizzo struct ip *ip;
1275ad512958SBjoern A. Zeeb #endif
1276ad512958SBjoern A. Zeeb #ifdef INET6
12772f345d8eSLuigi Rizzo struct ip6_hdr *ip6;
1278ad512958SBjoern A. Zeeb #endif
12792f345d8eSLuigi Rizzo struct ether_vlan_header *eh;
12802f345d8eSLuigi Rizzo struct tcphdr *th;
12812f345d8eSLuigi Rizzo uint16_t etype;
12829bd3250aSLuigi Rizzo int total_len = 0, ehdrlen = 0;
12832f345d8eSLuigi Rizzo
12842f345d8eSLuigi Rizzo m = *mpp;
12852f345d8eSLuigi Rizzo
12862f345d8eSLuigi Rizzo if (M_WRITABLE(m) == 0) {
1287c6499eccSGleb Smirnoff m = m_dup(*mpp, M_NOWAIT);
12882f345d8eSLuigi Rizzo if (!m)
12892f345d8eSLuigi Rizzo return NULL;
12902f345d8eSLuigi Rizzo m_freem(*mpp);
12912f345d8eSLuigi Rizzo *mpp = m;
12922f345d8eSLuigi Rizzo }
12932f345d8eSLuigi Rizzo
12942f345d8eSLuigi Rizzo eh = mtod(m, struct ether_vlan_header *);
12952f345d8eSLuigi Rizzo if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
12962f345d8eSLuigi Rizzo etype = ntohs(eh->evl_proto);
12972f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
12982f345d8eSLuigi Rizzo } else {
12992f345d8eSLuigi Rizzo etype = ntohs(eh->evl_encap_proto);
13002f345d8eSLuigi Rizzo ehdrlen = ETHER_HDR_LEN;
13012f345d8eSLuigi Rizzo }
13022f345d8eSLuigi Rizzo
13032f345d8eSLuigi Rizzo switch (etype) {
1304ad512958SBjoern A. Zeeb #ifdef INET
13052f345d8eSLuigi Rizzo case ETHERTYPE_IP:
13062f345d8eSLuigi Rizzo ip = (struct ip *)(m->m_data + ehdrlen);
13072f345d8eSLuigi Rizzo if (ip->ip_p != IPPROTO_TCP)
13082f345d8eSLuigi Rizzo return NULL;
13092f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
13102f345d8eSLuigi Rizzo
13112f345d8eSLuigi Rizzo total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
13122f345d8eSLuigi Rizzo break;
1313ad512958SBjoern A. Zeeb #endif
1314ad512958SBjoern A. Zeeb #ifdef INET6
13152f345d8eSLuigi Rizzo case ETHERTYPE_IPV6:
13162f345d8eSLuigi Rizzo ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
13172f345d8eSLuigi Rizzo if (ip6->ip6_nxt != IPPROTO_TCP)
13182f345d8eSLuigi Rizzo return NULL;
13192f345d8eSLuigi Rizzo th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
13202f345d8eSLuigi Rizzo
13212f345d8eSLuigi Rizzo total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
13222f345d8eSLuigi Rizzo break;
1323ad512958SBjoern A. Zeeb #endif
13242f345d8eSLuigi Rizzo default:
13252f345d8eSLuigi Rizzo return NULL;
13262f345d8eSLuigi Rizzo }
13272f345d8eSLuigi Rizzo
13282f345d8eSLuigi Rizzo m = m_pullup(m, total_len);
13292f345d8eSLuigi Rizzo *mpp = m;
13302f345d8eSLuigi Rizzo return m;
13312f345d8eSLuigi Rizzo }
1332ad512958SBjoern A. Zeeb #endif /* INET6 || INET */
13332f345d8eSLuigi Rizzo
13342f345d8eSLuigi Rizzo void
oce_tx_task(void * arg,int npending)13352f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending)
13362f345d8eSLuigi Rizzo {
13372f345d8eSLuigi Rizzo struct oce_wq *wq = arg;
13382f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent;
133967fd4c9dSJustin Hibbits if_t ifp = sc->ifp;
13402f345d8eSLuigi Rizzo int rc = 0;
13412f345d8eSLuigi Rizzo
1342291a1934SXin LI LOCK(&wq->tx_lock);
13432f345d8eSLuigi Rizzo rc = oce_multiq_transmit(ifp, NULL, wq);
13442f345d8eSLuigi Rizzo if (rc) {
13452f345d8eSLuigi Rizzo device_printf(sc->dev,
13462f345d8eSLuigi Rizzo "TX[%d] restart failed\n", wq->queue_index);
13472f345d8eSLuigi Rizzo }
13482f345d8eSLuigi Rizzo UNLOCK(&wq->tx_lock);
13492f345d8eSLuigi Rizzo }
13502f345d8eSLuigi Rizzo
13512f345d8eSLuigi Rizzo void
oce_start(if_t ifp)135267fd4c9dSJustin Hibbits oce_start(if_t ifp)
13532f345d8eSLuigi Rizzo {
135467fd4c9dSJustin Hibbits POCE_SOFTC sc = if_getsoftc(ifp);
13552f345d8eSLuigi Rizzo struct mbuf *m;
13562f345d8eSLuigi Rizzo int rc = 0;
13579bd3250aSLuigi Rizzo int def_q = 0; /* Defualt tx queue is 0*/
13582f345d8eSLuigi Rizzo
135967fd4c9dSJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
13602f345d8eSLuigi Rizzo IFF_DRV_RUNNING)
13612f345d8eSLuigi Rizzo return;
13622f345d8eSLuigi Rizzo
1363cdaba892SXin LI if (!sc->link_status)
1364cdaba892SXin LI return;
1365cdaba892SXin LI
1366b75a7728SConrad Meyer while (true) {
136767fd4c9dSJustin Hibbits m = if_dequeue(sc->ifp);
13682f345d8eSLuigi Rizzo if (m == NULL)
13692f345d8eSLuigi Rizzo break;
13709bd3250aSLuigi Rizzo
13719bd3250aSLuigi Rizzo LOCK(&sc->wq[def_q]->tx_lock);
13729bd3250aSLuigi Rizzo rc = oce_tx(sc, &m, def_q);
13739bd3250aSLuigi Rizzo UNLOCK(&sc->wq[def_q]->tx_lock);
13742f345d8eSLuigi Rizzo if (rc) {
13752f345d8eSLuigi Rizzo if (m != NULL) {
13769bd3250aSLuigi Rizzo sc->wq[def_q]->tx_stats.tx_stops ++;
137767fd4c9dSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
137867fd4c9dSJustin Hibbits if_sendq_prepend(ifp, m);
13792f345d8eSLuigi Rizzo m = NULL;
13802f345d8eSLuigi Rizzo }
13812f345d8eSLuigi Rizzo break;
13822f345d8eSLuigi Rizzo }
1383b75a7728SConrad Meyer }
13842f345d8eSLuigi Rizzo }
13852f345d8eSLuigi Rizzo
13862f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */
13872f345d8eSLuigi Rizzo uint16_t
oce_wq_handler(void * arg)13882f345d8eSLuigi Rizzo oce_wq_handler(void *arg)
13892f345d8eSLuigi Rizzo {
13902f345d8eSLuigi Rizzo struct oce_wq *wq = (struct oce_wq *)arg;
13912f345d8eSLuigi Rizzo POCE_SOFTC sc = wq->parent;
13922f345d8eSLuigi Rizzo struct oce_cq *cq = wq->cq;
13932f345d8eSLuigi Rizzo struct oce_nic_tx_cqe *cqe;
13942f345d8eSLuigi Rizzo int num_cqes = 0;
13952f345d8eSLuigi Rizzo
1396c2625e6eSJosh Paetzel LOCK(&wq->tx_compl_lock);
13972f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag,
13982f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
13992f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
14002f345d8eSLuigi Rizzo while (cqe->u0.dw[3]) {
14012f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
14022f345d8eSLuigi Rizzo
14032f345d8eSLuigi Rizzo wq->ring->cidx = cqe->u0.s.wqe_index + 1;
14042f345d8eSLuigi Rizzo if (wq->ring->cidx >= wq->ring->num_items)
14052f345d8eSLuigi Rizzo wq->ring->cidx -= wq->ring->num_items;
14062f345d8eSLuigi Rizzo
1407c2625e6eSJosh Paetzel oce_process_tx_completion(wq);
14082f345d8eSLuigi Rizzo wq->tx_stats.tx_compl++;
14092f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0;
14102f345d8eSLuigi Rizzo RING_GET(cq->ring, 1);
14112f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag,
14122f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
14132f345d8eSLuigi Rizzo cqe =
14142f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
14152f345d8eSLuigi Rizzo num_cqes++;
14162f345d8eSLuigi Rizzo }
14172f345d8eSLuigi Rizzo
14182f345d8eSLuigi Rizzo if (num_cqes)
14192f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
14202f345d8eSLuigi Rizzo
1421c2625e6eSJosh Paetzel UNLOCK(&wq->tx_compl_lock);
1422c2625e6eSJosh Paetzel return num_cqes;
14232f345d8eSLuigi Rizzo }
14242f345d8eSLuigi Rizzo
14252f345d8eSLuigi Rizzo static int
oce_multiq_transmit(if_t ifp,struct mbuf * m,struct oce_wq * wq)142667fd4c9dSJustin Hibbits oce_multiq_transmit(if_t ifp, struct mbuf *m, struct oce_wq *wq)
14272f345d8eSLuigi Rizzo {
142867fd4c9dSJustin Hibbits POCE_SOFTC sc = if_getsoftc(ifp);
14292f345d8eSLuigi Rizzo int status = 0, queue_index = 0;
14302f345d8eSLuigi Rizzo struct mbuf *next = NULL;
14312f345d8eSLuigi Rizzo struct buf_ring *br = NULL;
14322f345d8eSLuigi Rizzo
14332f345d8eSLuigi Rizzo br = wq->br;
14342f345d8eSLuigi Rizzo queue_index = wq->queue_index;
14352f345d8eSLuigi Rizzo
143667fd4c9dSJustin Hibbits if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
14372f345d8eSLuigi Rizzo IFF_DRV_RUNNING) {
14382f345d8eSLuigi Rizzo if (m != NULL)
14392f345d8eSLuigi Rizzo status = drbr_enqueue(ifp, br, m);
14402f345d8eSLuigi Rizzo return status;
14412f345d8eSLuigi Rizzo }
14422f345d8eSLuigi Rizzo
1443ded5ea6aSRandall Stewart if (m != NULL) {
14442f345d8eSLuigi Rizzo if ((status = drbr_enqueue(ifp, br, m)) != 0)
14452f345d8eSLuigi Rizzo return status;
1446ded5ea6aSRandall Stewart }
1447ded5ea6aSRandall Stewart while ((next = drbr_peek(ifp, br)) != NULL) {
14482f345d8eSLuigi Rizzo if (oce_tx(sc, &next, queue_index)) {
1449ded5ea6aSRandall Stewart if (next == NULL) {
1450ded5ea6aSRandall Stewart drbr_advance(ifp, br);
1451ded5ea6aSRandall Stewart } else {
1452ded5ea6aSRandall Stewart drbr_putback(ifp, br, next);
14532f345d8eSLuigi Rizzo wq->tx_stats.tx_stops ++;
145467fd4c9dSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
14552f345d8eSLuigi Rizzo }
14562f345d8eSLuigi Rizzo break;
14572f345d8eSLuigi Rizzo }
1458ded5ea6aSRandall Stewart drbr_advance(ifp, br);
14592f345d8eSLuigi Rizzo }
14602f345d8eSLuigi Rizzo
1461d398c863SLuigi Rizzo return 0;
14622f345d8eSLuigi Rizzo }
14632f345d8eSLuigi Rizzo
14642f345d8eSLuigi Rizzo /*****************************************************************************
14652f345d8eSLuigi Rizzo * Receive routines functions *
14662f345d8eSLuigi Rizzo *****************************************************************************/
14672f345d8eSLuigi Rizzo
14682f345d8eSLuigi Rizzo static void
oce_correct_header(struct mbuf * m,struct nic_hwlro_cqe_part1 * cqe1,struct nic_hwlro_cqe_part2 * cqe2)1469c2625e6eSJosh Paetzel oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2)
14702f345d8eSLuigi Rizzo {
1471c2625e6eSJosh Paetzel uint32_t *p;
1472c2625e6eSJosh Paetzel struct ether_header *eh = NULL;
1473c2625e6eSJosh Paetzel struct tcphdr *tcp_hdr = NULL;
1474c2625e6eSJosh Paetzel struct ip *ip4_hdr = NULL;
1475c2625e6eSJosh Paetzel struct ip6_hdr *ip6 = NULL;
1476c2625e6eSJosh Paetzel uint32_t payload_len = 0;
1477c2625e6eSJosh Paetzel
1478c2625e6eSJosh Paetzel eh = mtod(m, struct ether_header *);
1479c2625e6eSJosh Paetzel /* correct IP header */
1480c2625e6eSJosh Paetzel if(!cqe2->ipv6_frame) {
1481c2625e6eSJosh Paetzel ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header));
1482c2625e6eSJosh Paetzel ip4_hdr->ip_ttl = cqe2->frame_lifespan;
1483c2625e6eSJosh Paetzel ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header));
1484c2625e6eSJosh Paetzel tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip));
1485c2625e6eSJosh Paetzel }else {
1486c2625e6eSJosh Paetzel ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header));
1487c2625e6eSJosh Paetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan;
1488c2625e6eSJosh Paetzel payload_len = cqe2->coalesced_size - sizeof(struct ether_header)
1489c2625e6eSJosh Paetzel - sizeof(struct ip6_hdr);
1490c2625e6eSJosh Paetzel ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len);
1491c2625e6eSJosh Paetzel tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr));
1492c2625e6eSJosh Paetzel }
1493c2625e6eSJosh Paetzel
1494c2625e6eSJosh Paetzel /* correct tcp header */
1495c2625e6eSJosh Paetzel tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num);
1496c2625e6eSJosh Paetzel if(cqe2->push) {
1497c2625e6eSJosh Paetzel tcp_hdr->th_flags |= TH_PUSH;
1498c2625e6eSJosh Paetzel }
1499c2625e6eSJosh Paetzel tcp_hdr->th_win = htons(cqe2->tcp_window);
1500c2625e6eSJosh Paetzel tcp_hdr->th_sum = 0xffff;
1501c2625e6eSJosh Paetzel if(cqe2->ts_opt) {
1502c2625e6eSJosh Paetzel p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2);
1503c2625e6eSJosh Paetzel *p = cqe1->tcp_timestamp_val;
1504c2625e6eSJosh Paetzel *(p+1) = cqe1->tcp_timestamp_ecr;
1505c2625e6eSJosh Paetzel }
1506c2625e6eSJosh Paetzel
1507c2625e6eSJosh Paetzel return;
1508c2625e6eSJosh Paetzel }
1509c2625e6eSJosh Paetzel
1510c2625e6eSJosh Paetzel static void
oce_rx_mbuf_chain(struct oce_rq * rq,struct oce_common_cqe_info * cqe_info,struct mbuf ** m)1511c2625e6eSJosh Paetzel oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m)
1512c2625e6eSJosh Paetzel {
1513764c812dSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1514c2625e6eSJosh Paetzel uint32_t i = 0, frag_len = 0;
1515c2625e6eSJosh Paetzel uint32_t len = cqe_info->pkt_size;
1516c2625e6eSJosh Paetzel struct oce_packet_desc *pd;
1517c2625e6eSJosh Paetzel struct mbuf *tail = NULL;
1518764c812dSJosh Paetzel
1519c2625e6eSJosh Paetzel for (i = 0; i < cqe_info->num_frags; i++) {
1520c2625e6eSJosh Paetzel if (rq->ring->cidx == rq->ring->pidx) {
152114410265SConrad Meyer device_printf(sc->dev,
1522c2625e6eSJosh Paetzel "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n");
1523c2625e6eSJosh Paetzel return;
152414410265SConrad Meyer }
1525c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->cidx];
152614410265SConrad Meyer
152714410265SConrad Meyer bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
152814410265SConrad Meyer bus_dmamap_unload(rq->tag, pd->map);
1529c2625e6eSJosh Paetzel RING_GET(rq->ring, 1);
153014410265SConrad Meyer rq->pending--;
153114410265SConrad Meyer
153214410265SConrad Meyer frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
153314410265SConrad Meyer pd->mbuf->m_len = frag_len;
153414410265SConrad Meyer
153514410265SConrad Meyer if (tail != NULL) {
153614410265SConrad Meyer /* additional fragments */
153714410265SConrad Meyer pd->mbuf->m_flags &= ~M_PKTHDR;
153814410265SConrad Meyer tail->m_next = pd->mbuf;
1539c2625e6eSJosh Paetzel if(rq->islro)
1540c2625e6eSJosh Paetzel tail->m_nextpkt = NULL;
154114410265SConrad Meyer tail = pd->mbuf;
154214410265SConrad Meyer } else {
154314410265SConrad Meyer /* first fragment, fill out much of the packet header */
154414410265SConrad Meyer pd->mbuf->m_pkthdr.len = len;
1545c2625e6eSJosh Paetzel if(rq->islro)
1546c2625e6eSJosh Paetzel pd->mbuf->m_nextpkt = NULL;
154714410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags = 0;
154814410265SConrad Meyer if (IF_CSUM_ENABLED(sc)) {
1549c2625e6eSJosh Paetzel if (cqe_info->l4_cksum_pass) {
1550c2625e6eSJosh Paetzel if(!cqe_info->ipv6_frame) { /* IPV4 */
155114410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags |=
155214410265SConrad Meyer (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1553c2625e6eSJosh Paetzel }else { /* IPV6 frame */
1554c2625e6eSJosh Paetzel if(rq->islro) {
1555c2625e6eSJosh Paetzel pd->mbuf->m_pkthdr.csum_flags |=
1556c2625e6eSJosh Paetzel (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1557c2625e6eSJosh Paetzel }
1558c2625e6eSJosh Paetzel }
155914410265SConrad Meyer pd->mbuf->m_pkthdr.csum_data = 0xffff;
156014410265SConrad Meyer }
1561c2625e6eSJosh Paetzel if (cqe_info->ip_cksum_pass) {
156214410265SConrad Meyer pd->mbuf->m_pkthdr.csum_flags |=
156314410265SConrad Meyer (CSUM_IP_CHECKED|CSUM_IP_VALID);
156414410265SConrad Meyer }
156514410265SConrad Meyer }
1566c2625e6eSJosh Paetzel *m = tail = pd->mbuf;
156714410265SConrad Meyer }
156814410265SConrad Meyer pd->mbuf = NULL;
156914410265SConrad Meyer len -= frag_len;
157014410265SConrad Meyer }
1571764c812dSJosh Paetzel
1572c2625e6eSJosh Paetzel return;
1573c2625e6eSJosh Paetzel }
1574c2625e6eSJosh Paetzel
1575c2625e6eSJosh Paetzel static void
oce_rx_lro(struct oce_rq * rq,struct nic_hwlro_singleton_cqe * cqe,struct nic_hwlro_cqe_part2 * cqe2)1576c2625e6eSJosh Paetzel oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2)
1577c2625e6eSJosh Paetzel {
1578c2625e6eSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1579c2625e6eSJosh Paetzel struct nic_hwlro_cqe_part1 *cqe1 = NULL;
1580c2625e6eSJosh Paetzel struct mbuf *m = NULL;
1581c2625e6eSJosh Paetzel struct oce_common_cqe_info cq_info;
1582c2625e6eSJosh Paetzel
1583c2625e6eSJosh Paetzel /* parse cqe */
1584c2625e6eSJosh Paetzel if(cqe2 == NULL) {
1585c2625e6eSJosh Paetzel cq_info.pkt_size = cqe->pkt_size;
1586c2625e6eSJosh Paetzel cq_info.vtag = cqe->vlan_tag;
1587c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe->l4_cksum_pass;
1588c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe->ip_cksum_pass;
1589c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe->ipv6_frame;
1590c2625e6eSJosh Paetzel cq_info.vtp = cqe->vtp;
1591c2625e6eSJosh Paetzel cq_info.qnq = cqe->qnq;
1592c2625e6eSJosh Paetzel }else {
1593c2625e6eSJosh Paetzel cqe1 = (struct nic_hwlro_cqe_part1 *)cqe;
1594c2625e6eSJosh Paetzel cq_info.pkt_size = cqe2->coalesced_size;
1595c2625e6eSJosh Paetzel cq_info.vtag = cqe2->vlan_tag;
1596c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe2->l4_cksum_pass;
1597c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe2->ip_cksum_pass;
1598c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe2->ipv6_frame;
1599c2625e6eSJosh Paetzel cq_info.vtp = cqe2->vtp;
1600c2625e6eSJosh Paetzel cq_info.qnq = cqe1->qnq;
1601c2625e6eSJosh Paetzel }
1602c2625e6eSJosh Paetzel
1603c2625e6eSJosh Paetzel cq_info.vtag = BSWAP_16(cq_info.vtag);
1604c2625e6eSJosh Paetzel
1605c2625e6eSJosh Paetzel cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size;
1606c2625e6eSJosh Paetzel if(cq_info.pkt_size % rq->cfg.frag_size)
1607c2625e6eSJosh Paetzel cq_info.num_frags++;
1608c2625e6eSJosh Paetzel
1609c2625e6eSJosh Paetzel oce_rx_mbuf_chain(rq, &cq_info, &m);
1610c2625e6eSJosh Paetzel
1611764c812dSJosh Paetzel if (m) {
1612c2625e6eSJosh Paetzel if(cqe2) {
1613c2625e6eSJosh Paetzel //assert(cqe2->valid != 0);
1614c2625e6eSJosh Paetzel
1615c2625e6eSJosh Paetzel //assert(cqe2->cqe_type != 2);
1616c2625e6eSJosh Paetzel oce_correct_header(m, cqe1, cqe2);
1617c2625e6eSJosh Paetzel }
1618c2625e6eSJosh Paetzel
1619c2625e6eSJosh Paetzel m->m_pkthdr.rcvif = sc->ifp;
1620c2625e6eSJosh Paetzel if (rq->queue_index)
1621c2625e6eSJosh Paetzel m->m_pkthdr.flowid = (rq->queue_index - 1);
1622c2625e6eSJosh Paetzel else
1623c2625e6eSJosh Paetzel m->m_pkthdr.flowid = rq->queue_index;
1624c2625e6eSJosh Paetzel M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1625a9208e98SWarner Losh
1626c2625e6eSJosh Paetzel /* This deternies if vlan tag is Valid */
1627c2625e6eSJosh Paetzel if (cq_info.vtp) {
1628c2625e6eSJosh Paetzel if (sc->function_mode & FNM_FLEX10_MODE) {
1629c2625e6eSJosh Paetzel /* FLEX10. If QnQ is not set, neglect VLAN */
1630c2625e6eSJosh Paetzel if (cq_info.qnq) {
1631c2625e6eSJosh Paetzel m->m_pkthdr.ether_vtag = cq_info.vtag;
1632c2625e6eSJosh Paetzel m->m_flags |= M_VLANTAG;
1633c2625e6eSJosh Paetzel }
1634c2625e6eSJosh Paetzel } else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK)) {
1635c2625e6eSJosh Paetzel /* In UMC mode generally pvid will be striped by
1636c2625e6eSJosh Paetzel hw. But in some cases we have seen it comes
1637c2625e6eSJosh Paetzel with pvid. So if pvid == vlan, neglect vlan.
1638c2625e6eSJosh Paetzel */
1639c2625e6eSJosh Paetzel m->m_pkthdr.ether_vtag = cq_info.vtag;
1640c2625e6eSJosh Paetzel m->m_flags |= M_VLANTAG;
1641c2625e6eSJosh Paetzel }
1642c2625e6eSJosh Paetzel }
1643c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1644c2625e6eSJosh Paetzel
164567fd4c9dSJustin Hibbits if_input(sc->ifp, m);
1646c2625e6eSJosh Paetzel
1647c2625e6eSJosh Paetzel /* Update rx stats per queue */
1648c2625e6eSJosh Paetzel rq->rx_stats.rx_pkts++;
1649c2625e6eSJosh Paetzel rq->rx_stats.rx_bytes += cq_info.pkt_size;
1650c2625e6eSJosh Paetzel rq->rx_stats.rx_frags += cq_info.num_frags;
1651c2625e6eSJosh Paetzel rq->rx_stats.rx_ucast_pkts++;
1652c2625e6eSJosh Paetzel }
1653c2625e6eSJosh Paetzel return;
1654c2625e6eSJosh Paetzel }
1655c2625e6eSJosh Paetzel
1656c2625e6eSJosh Paetzel static void
oce_rx(struct oce_rq * rq,struct oce_nic_rx_cqe * cqe)1657c2625e6eSJosh Paetzel oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
1658c2625e6eSJosh Paetzel {
1659c2625e6eSJosh Paetzel POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1660c2625e6eSJosh Paetzel int len;
1661c2625e6eSJosh Paetzel struct mbuf *m = NULL;
1662c2625e6eSJosh Paetzel struct oce_common_cqe_info cq_info;
1663c2625e6eSJosh Paetzel uint16_t vtag = 0;
1664c2625e6eSJosh Paetzel
1665c2625e6eSJosh Paetzel /* Is it a flush compl that has no data */
1666c2625e6eSJosh Paetzel if(!cqe->u0.s.num_fragments)
1667c2625e6eSJosh Paetzel goto exit;
1668c2625e6eSJosh Paetzel
1669c2625e6eSJosh Paetzel len = cqe->u0.s.pkt_size;
1670c2625e6eSJosh Paetzel if (!len) {
1671c2625e6eSJosh Paetzel /*partial DMA workaround for Lancer*/
1672c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
167314410265SConrad Meyer goto exit;
167414410265SConrad Meyer }
167514410265SConrad Meyer
1676c2625e6eSJosh Paetzel if (!oce_cqe_portid_valid(sc, cqe)) {
1677c2625e6eSJosh Paetzel oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
1678c2625e6eSJosh Paetzel goto exit;
1679c2625e6eSJosh Paetzel }
1680c2625e6eSJosh Paetzel
1681c2625e6eSJosh Paetzel /* Get vlan_tag value */
1682c2625e6eSJosh Paetzel if(IS_BE(sc) || IS_SH(sc))
1683c2625e6eSJosh Paetzel vtag = BSWAP_16(cqe->u0.s.vlan_tag);
1684c2625e6eSJosh Paetzel else
1685c2625e6eSJosh Paetzel vtag = cqe->u0.s.vlan_tag;
1686c2625e6eSJosh Paetzel
1687c2625e6eSJosh Paetzel cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass;
1688c2625e6eSJosh Paetzel cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass;
1689c2625e6eSJosh Paetzel cq_info.ipv6_frame = cqe->u0.s.ip_ver;
1690c2625e6eSJosh Paetzel cq_info.num_frags = cqe->u0.s.num_fragments;
1691c2625e6eSJosh Paetzel cq_info.pkt_size = cqe->u0.s.pkt_size;
1692c2625e6eSJosh Paetzel
1693c2625e6eSJosh Paetzel oce_rx_mbuf_chain(rq, &cq_info, &m);
1694c2625e6eSJosh Paetzel
1695c2625e6eSJosh Paetzel if (m) {
16962f345d8eSLuigi Rizzo m->m_pkthdr.rcvif = sc->ifp;
1697291a1934SXin LI if (rq->queue_index)
1698291a1934SXin LI m->m_pkthdr.flowid = (rq->queue_index - 1);
1699291a1934SXin LI else
17002f345d8eSLuigi Rizzo m->m_pkthdr.flowid = rq->queue_index;
1701c2529042SHans Petter Selasky M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1702a9208e98SWarner Losh
17039bd3250aSLuigi Rizzo /* This deternies if vlan tag is Valid */
17042f345d8eSLuigi Rizzo if (oce_cqe_vtp_valid(sc, cqe)) {
17052f345d8eSLuigi Rizzo if (sc->function_mode & FNM_FLEX10_MODE) {
17069bd3250aSLuigi Rizzo /* FLEX10. If QnQ is not set, neglect VLAN */
17072f345d8eSLuigi Rizzo if (cqe->u0.s.qnq) {
17082f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag;
17092f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG;
17102f345d8eSLuigi Rizzo }
17119bd3250aSLuigi Rizzo } else if (sc->pvid != (vtag & VLAN_VID_MASK)) {
17129bd3250aSLuigi Rizzo /* In UMC mode generally pvid will be striped by
17139bd3250aSLuigi Rizzo hw. But in some cases we have seen it comes
17149bd3250aSLuigi Rizzo with pvid. So if pvid == vlan, neglect vlan.
17159bd3250aSLuigi Rizzo */
17162f345d8eSLuigi Rizzo m->m_pkthdr.ether_vtag = vtag;
17172f345d8eSLuigi Rizzo m->m_flags |= M_VLANTAG;
17182f345d8eSLuigi Rizzo }
17192f345d8eSLuigi Rizzo }
17202f345d8eSLuigi Rizzo
1721c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1722ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
17232f345d8eSLuigi Rizzo /* Try to queue to LRO */
17242f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) &&
17252f345d8eSLuigi Rizzo (cqe->u0.s.ip_cksum_pass) &&
17262f345d8eSLuigi Rizzo (cqe->u0.s.l4_cksum_pass) &&
17272f345d8eSLuigi Rizzo (!cqe->u0.s.ip_ver) &&
17282f345d8eSLuigi Rizzo (rq->lro.lro_cnt != 0)) {
17292f345d8eSLuigi Rizzo if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
17302f345d8eSLuigi Rizzo rq->lro_pkts_queued ++;
17312f345d8eSLuigi Rizzo goto post_done;
17322f345d8eSLuigi Rizzo }
17332f345d8eSLuigi Rizzo /* If LRO posting fails then try to post to STACK */
17342f345d8eSLuigi Rizzo }
1735ad512958SBjoern A. Zeeb #endif
17362f345d8eSLuigi Rizzo
173767fd4c9dSJustin Hibbits if_input(sc->ifp, m);
1738ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
17392f345d8eSLuigi Rizzo post_done:
1740ad512958SBjoern A. Zeeb #endif
17412f345d8eSLuigi Rizzo /* Update rx stats per queue */
17422f345d8eSLuigi Rizzo rq->rx_stats.rx_pkts++;
17432f345d8eSLuigi Rizzo rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
17442f345d8eSLuigi Rizzo rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
17452f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
17462f345d8eSLuigi Rizzo rq->rx_stats.rx_mcast_pkts++;
17472f345d8eSLuigi Rizzo if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
17482f345d8eSLuigi Rizzo rq->rx_stats.rx_ucast_pkts++;
17492f345d8eSLuigi Rizzo }
17502f345d8eSLuigi Rizzo exit:
17512f345d8eSLuigi Rizzo return;
17522f345d8eSLuigi Rizzo }
17532f345d8eSLuigi Rizzo
1754c2625e6eSJosh Paetzel void
oce_discard_rx_comp(struct oce_rq * rq,int num_frags)1755c2625e6eSJosh Paetzel oce_discard_rx_comp(struct oce_rq *rq, int num_frags)
17562f345d8eSLuigi Rizzo {
1757c2625e6eSJosh Paetzel uint32_t i = 0;
17582f345d8eSLuigi Rizzo struct oce_packet_desc *pd;
17592f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
17602f345d8eSLuigi Rizzo
17612f345d8eSLuigi Rizzo for (i = 0; i < num_frags; i++) {
1762c2625e6eSJosh Paetzel if (rq->ring->cidx == rq->ring->pidx) {
17632f345d8eSLuigi Rizzo device_printf(sc->dev,
1764c2625e6eSJosh Paetzel "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n");
1765c2625e6eSJosh Paetzel return;
17662f345d8eSLuigi Rizzo }
1767c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->cidx];
17682f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
17692f345d8eSLuigi Rizzo bus_dmamap_unload(rq->tag, pd->map);
1770c2625e6eSJosh Paetzel if (pd->mbuf != NULL) {
17712f345d8eSLuigi Rizzo m_freem(pd->mbuf);
1772c2625e6eSJosh Paetzel pd->mbuf = NULL;
17732f345d8eSLuigi Rizzo }
17742f345d8eSLuigi Rizzo
1775c2625e6eSJosh Paetzel RING_GET(rq->ring, 1);
1776c2625e6eSJosh Paetzel rq->pending--;
1777c2625e6eSJosh Paetzel }
17782f345d8eSLuigi Rizzo }
17792f345d8eSLuigi Rizzo
17802f345d8eSLuigi Rizzo static int
oce_cqe_vtp_valid(POCE_SOFTC sc,struct oce_nic_rx_cqe * cqe)17812f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
17822f345d8eSLuigi Rizzo {
17832f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1;
17842f345d8eSLuigi Rizzo int vtp = 0;
17852f345d8eSLuigi Rizzo
17862f345d8eSLuigi Rizzo if (sc->be3_native) {
17872f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
17882f345d8eSLuigi Rizzo vtp = cqe_v1->u0.s.vlan_tag_present;
17899bd3250aSLuigi Rizzo } else
17902f345d8eSLuigi Rizzo vtp = cqe->u0.s.vlan_tag_present;
17912f345d8eSLuigi Rizzo
17922f345d8eSLuigi Rizzo return vtp;
17932f345d8eSLuigi Rizzo
17942f345d8eSLuigi Rizzo }
17952f345d8eSLuigi Rizzo
17962f345d8eSLuigi Rizzo static int
oce_cqe_portid_valid(POCE_SOFTC sc,struct oce_nic_rx_cqe * cqe)17972f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
17982f345d8eSLuigi Rizzo {
17992f345d8eSLuigi Rizzo struct oce_nic_rx_cqe_v1 *cqe_v1;
18002f345d8eSLuigi Rizzo int port_id = 0;
18012f345d8eSLuigi Rizzo
1802291a1934SXin LI if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) {
18032f345d8eSLuigi Rizzo cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
18042f345d8eSLuigi Rizzo port_id = cqe_v1->u0.s.port;
18052f345d8eSLuigi Rizzo if (sc->port_id != port_id)
18062f345d8eSLuigi Rizzo return 0;
18072f345d8eSLuigi Rizzo } else
18082f345d8eSLuigi Rizzo ;/* For BE3 legacy and Lancer this is dummy */
18092f345d8eSLuigi Rizzo
18102f345d8eSLuigi Rizzo return 1;
18112f345d8eSLuigi Rizzo
18122f345d8eSLuigi Rizzo }
18132f345d8eSLuigi Rizzo
1814ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
1815c2625e6eSJosh Paetzel void
oce_rx_flush_lro(struct oce_rq * rq)18162f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq)
18172f345d8eSLuigi Rizzo {
18182f345d8eSLuigi Rizzo struct lro_ctrl *lro = &rq->lro;
18192f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
18202f345d8eSLuigi Rizzo
18212f345d8eSLuigi Rizzo if (!IF_LRO_ENABLED(sc))
18222f345d8eSLuigi Rizzo return;
18232f345d8eSLuigi Rizzo
18246dd38b87SSepherosa Ziehau tcp_lro_flush_all(lro);
18252f345d8eSLuigi Rizzo rq->lro_pkts_queued = 0;
18262f345d8eSLuigi Rizzo
18272f345d8eSLuigi Rizzo return;
18282f345d8eSLuigi Rizzo }
18292f345d8eSLuigi Rizzo
18302f345d8eSLuigi Rizzo static int
oce_init_lro(POCE_SOFTC sc)18312f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc)
18322f345d8eSLuigi Rizzo {
18332f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL;
18342f345d8eSLuigi Rizzo int i = 0, rc = 0;
18352f345d8eSLuigi Rizzo
18362f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) {
18372f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro;
18382f345d8eSLuigi Rizzo rc = tcp_lro_init(lro);
18392f345d8eSLuigi Rizzo if (rc != 0) {
18402f345d8eSLuigi Rizzo device_printf(sc->dev, "LRO init failed\n");
18412f345d8eSLuigi Rizzo return rc;
18422f345d8eSLuigi Rizzo }
18432f345d8eSLuigi Rizzo lro->ifp = sc->ifp;
18442f345d8eSLuigi Rizzo }
18452f345d8eSLuigi Rizzo
18462f345d8eSLuigi Rizzo return rc;
18472f345d8eSLuigi Rizzo }
18489bd3250aSLuigi Rizzo
18492f345d8eSLuigi Rizzo void
oce_free_lro(POCE_SOFTC sc)18502f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc)
18512f345d8eSLuigi Rizzo {
18522f345d8eSLuigi Rizzo struct lro_ctrl *lro = NULL;
18532f345d8eSLuigi Rizzo int i = 0;
18542f345d8eSLuigi Rizzo
18552f345d8eSLuigi Rizzo for (i = 0; i < sc->nrqs; i++) {
18562f345d8eSLuigi Rizzo lro = &sc->rq[i]->lro;
18572f345d8eSLuigi Rizzo if (lro)
18582f345d8eSLuigi Rizzo tcp_lro_free(lro);
18592f345d8eSLuigi Rizzo }
18602f345d8eSLuigi Rizzo }
1861cdaba892SXin LI #endif
18622f345d8eSLuigi Rizzo
18632f345d8eSLuigi Rizzo int
oce_alloc_rx_bufs(struct oce_rq * rq,int count)18642f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count)
18652f345d8eSLuigi Rizzo {
18662f345d8eSLuigi Rizzo POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
186719c099a8SJohn Baldwin int i, rc;
18682f345d8eSLuigi Rizzo struct oce_packet_desc *pd;
18692f345d8eSLuigi Rizzo bus_dma_segment_t segs[6];
18702f345d8eSLuigi Rizzo int nsegs, added = 0;
18712f345d8eSLuigi Rizzo struct oce_nic_rqe *rqe;
18722f345d8eSLuigi Rizzo pd_rxulp_db_t rxdb_reg;
1873c2625e6eSJosh Paetzel uint32_t val = 0;
1874c2625e6eSJosh Paetzel uint32_t oce_max_rq_posts = 64;
18752f345d8eSLuigi Rizzo
1876cdaba892SXin LI bzero(&rxdb_reg, sizeof(pd_rxulp_db_t));
18772f345d8eSLuigi Rizzo for (i = 0; i < count; i++) {
1878c2625e6eSJosh Paetzel pd = &rq->pckts[rq->ring->pidx];
1879c2625e6eSJosh Paetzel pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size);
1880c2625e6eSJosh Paetzel if (pd->mbuf == NULL) {
1881c2625e6eSJosh Paetzel device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size);
18822f345d8eSLuigi Rizzo break;
1883c2625e6eSJosh Paetzel }
1884c2625e6eSJosh Paetzel pd->mbuf->m_nextpkt = NULL;
18852f345d8eSLuigi Rizzo
1886c2625e6eSJosh Paetzel pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size;
1887c2625e6eSJosh Paetzel
18882f345d8eSLuigi Rizzo rc = bus_dmamap_load_mbuf_sg(rq->tag,
18892f345d8eSLuigi Rizzo pd->map,
18902f345d8eSLuigi Rizzo pd->mbuf,
18912f345d8eSLuigi Rizzo segs, &nsegs, BUS_DMA_NOWAIT);
18922f345d8eSLuigi Rizzo if (rc) {
18932f345d8eSLuigi Rizzo m_free(pd->mbuf);
1894c2625e6eSJosh Paetzel device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc);
18952f345d8eSLuigi Rizzo break;
18962f345d8eSLuigi Rizzo }
18972f345d8eSLuigi Rizzo
18982f345d8eSLuigi Rizzo if (nsegs != 1) {
18992f345d8eSLuigi Rizzo i--;
19002f345d8eSLuigi Rizzo continue;
19012f345d8eSLuigi Rizzo }
19022f345d8eSLuigi Rizzo
19032f345d8eSLuigi Rizzo bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
19042f345d8eSLuigi Rizzo
19052f345d8eSLuigi Rizzo rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
19062f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
19072f345d8eSLuigi Rizzo rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
19082f345d8eSLuigi Rizzo DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
19092f345d8eSLuigi Rizzo RING_PUT(rq->ring, 1);
19102f345d8eSLuigi Rizzo added++;
19112f345d8eSLuigi Rizzo rq->pending++;
19122f345d8eSLuigi Rizzo }
1913c2625e6eSJosh Paetzel oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS;
19142f345d8eSLuigi Rizzo if (added != 0) {
1915c2625e6eSJosh Paetzel for (i = added / oce_max_rq_posts; i > 0; i--) {
1916c2625e6eSJosh Paetzel rxdb_reg.bits.num_posted = oce_max_rq_posts;
19172f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id;
1918c2625e6eSJosh Paetzel if(rq->islro) {
1919c2625e6eSJosh Paetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1920c2625e6eSJosh Paetzel val |= oce_max_rq_posts << 16;
1921c2625e6eSJosh Paetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
1922c2625e6eSJosh Paetzel }else {
19232f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1924c2625e6eSJosh Paetzel }
1925c2625e6eSJosh Paetzel added -= oce_max_rq_posts;
19262f345d8eSLuigi Rizzo }
19272f345d8eSLuigi Rizzo if (added > 0) {
19282f345d8eSLuigi Rizzo rxdb_reg.bits.qid = rq->rq_id;
19292f345d8eSLuigi Rizzo rxdb_reg.bits.num_posted = added;
1930c2625e6eSJosh Paetzel if(rq->islro) {
1931c2625e6eSJosh Paetzel val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1932c2625e6eSJosh Paetzel val |= added << 16;
1933c2625e6eSJosh Paetzel OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
1934c2625e6eSJosh Paetzel }else {
19352f345d8eSLuigi Rizzo OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
19362f345d8eSLuigi Rizzo }
19372f345d8eSLuigi Rizzo }
1938c2625e6eSJosh Paetzel }
19392f345d8eSLuigi Rizzo
19402f345d8eSLuigi Rizzo return 0;
19412f345d8eSLuigi Rizzo }
19422f345d8eSLuigi Rizzo
1943c2625e6eSJosh Paetzel static void
oce_check_rx_bufs(POCE_SOFTC sc,uint32_t num_cqes,struct oce_rq * rq)1944c2625e6eSJosh Paetzel oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq)
1945c2625e6eSJosh Paetzel {
1946c2625e6eSJosh Paetzel if (num_cqes) {
1947c2625e6eSJosh Paetzel oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE);
1948c2625e6eSJosh Paetzel if(!sc->enable_hwlro) {
1949c2625e6eSJosh Paetzel if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1)
1950c2625e6eSJosh Paetzel oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1));
1951c2625e6eSJosh Paetzel }else {
1952c2625e6eSJosh Paetzel if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64)
1953c2625e6eSJosh Paetzel oce_alloc_rx_bufs(rq, 64);
1954c2625e6eSJosh Paetzel }
1955c2625e6eSJosh Paetzel }
1956c2625e6eSJosh Paetzel
1957c2625e6eSJosh Paetzel return;
1958c2625e6eSJosh Paetzel }
1959c2625e6eSJosh Paetzel
1960c2625e6eSJosh Paetzel uint16_t
oce_rq_handler_lro(void * arg)1961c2625e6eSJosh Paetzel oce_rq_handler_lro(void *arg)
1962c2625e6eSJosh Paetzel {
1963c2625e6eSJosh Paetzel struct oce_rq *rq = (struct oce_rq *)arg;
1964c2625e6eSJosh Paetzel struct oce_cq *cq = rq->cq;
1965c2625e6eSJosh Paetzel POCE_SOFTC sc = rq->parent;
1966c2625e6eSJosh Paetzel struct nic_hwlro_singleton_cqe *cqe;
1967c2625e6eSJosh Paetzel struct nic_hwlro_cqe_part2 *cqe2;
1968c2625e6eSJosh Paetzel int num_cqes = 0;
1969c2625e6eSJosh Paetzel
1970c2625e6eSJosh Paetzel LOCK(&rq->rx_lock);
1971c2625e6eSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1972c2625e6eSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
1973c2625e6eSJosh Paetzel while (cqe->valid) {
1974c2625e6eSJosh Paetzel if(cqe->cqe_type == 0) { /* singleton cqe */
1975c2625e6eSJosh Paetzel /* we should not get singleton cqe after cqe1 on same rq */
1976c2625e6eSJosh Paetzel if(rq->cqe_firstpart != NULL) {
1977c2625e6eSJosh Paetzel device_printf(sc->dev, "Got singleton cqe after cqe1 \n");
1978c2625e6eSJosh Paetzel goto exit_rq_handler_lro;
1979c2625e6eSJosh Paetzel }
1980c2625e6eSJosh Paetzel if(cqe->error != 0) {
1981c2625e6eSJosh Paetzel rq->rx_stats.rxcp_err++;
1982c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
1983c2625e6eSJosh Paetzel }
1984c2625e6eSJosh Paetzel oce_rx_lro(rq, cqe, NULL);
1985c2625e6eSJosh Paetzel rq->rx_stats.rx_compl++;
1986c2625e6eSJosh Paetzel cqe->valid = 0;
1987c2625e6eSJosh Paetzel RING_GET(cq->ring, 1);
1988c2625e6eSJosh Paetzel num_cqes++;
1989c2625e6eSJosh Paetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
1990c2625e6eSJosh Paetzel break;
1991c2625e6eSJosh Paetzel }else if(cqe->cqe_type == 0x1) { /* first part */
1992c2625e6eSJosh Paetzel /* we should not get cqe1 after cqe1 on same rq */
1993c2625e6eSJosh Paetzel if(rq->cqe_firstpart != NULL) {
1994c2625e6eSJosh Paetzel device_printf(sc->dev, "Got cqe1 after cqe1 \n");
1995c2625e6eSJosh Paetzel goto exit_rq_handler_lro;
1996c2625e6eSJosh Paetzel }
1997c2625e6eSJosh Paetzel rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe;
1998c2625e6eSJosh Paetzel RING_GET(cq->ring, 1);
1999c2625e6eSJosh Paetzel }else if(cqe->cqe_type == 0x2) { /* second part */
2000c2625e6eSJosh Paetzel cqe2 = (struct nic_hwlro_cqe_part2 *)cqe;
2001c2625e6eSJosh Paetzel if(cqe2->error != 0) {
2002c2625e6eSJosh Paetzel rq->rx_stats.rxcp_err++;
2003c2625e6eSJosh Paetzel if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
2004c2625e6eSJosh Paetzel }
2005c2625e6eSJosh Paetzel /* We should not get cqe2 without cqe1 */
2006c2625e6eSJosh Paetzel if(rq->cqe_firstpart == NULL) {
2007c2625e6eSJosh Paetzel device_printf(sc->dev, "Got cqe2 without cqe1 \n");
2008c2625e6eSJosh Paetzel goto exit_rq_handler_lro;
2009c2625e6eSJosh Paetzel }
2010c2625e6eSJosh Paetzel oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2);
2011c2625e6eSJosh Paetzel
2012c2625e6eSJosh Paetzel rq->rx_stats.rx_compl++;
2013c2625e6eSJosh Paetzel rq->cqe_firstpart->valid = 0;
2014c2625e6eSJosh Paetzel cqe2->valid = 0;
2015c2625e6eSJosh Paetzel rq->cqe_firstpart = NULL;
2016c2625e6eSJosh Paetzel
2017c2625e6eSJosh Paetzel RING_GET(cq->ring, 1);
2018c2625e6eSJosh Paetzel num_cqes += 2;
2019c2625e6eSJosh Paetzel if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
2020c2625e6eSJosh Paetzel break;
2021c2625e6eSJosh Paetzel }
2022c2625e6eSJosh Paetzel
2023c2625e6eSJosh Paetzel bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2024c2625e6eSJosh Paetzel cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
2025c2625e6eSJosh Paetzel }
2026c2625e6eSJosh Paetzel oce_check_rx_bufs(sc, num_cqes, rq);
2027c2625e6eSJosh Paetzel exit_rq_handler_lro:
2028c2625e6eSJosh Paetzel UNLOCK(&rq->rx_lock);
2029c2625e6eSJosh Paetzel return 0;
2030c2625e6eSJosh Paetzel }
20312f345d8eSLuigi Rizzo
20322f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */
20332f345d8eSLuigi Rizzo uint16_t
oce_rq_handler(void * arg)20342f345d8eSLuigi Rizzo oce_rq_handler(void *arg)
20352f345d8eSLuigi Rizzo {
2036e363f832SMichael Tuexen struct epoch_tracker et;
20372f345d8eSLuigi Rizzo struct oce_rq *rq = (struct oce_rq *)arg;
20382f345d8eSLuigi Rizzo struct oce_cq *cq = rq->cq;
20392f345d8eSLuigi Rizzo POCE_SOFTC sc = rq->parent;
20402f345d8eSLuigi Rizzo struct oce_nic_rx_cqe *cqe;
2041c2625e6eSJosh Paetzel int num_cqes = 0;
20422f345d8eSLuigi Rizzo
2043e363f832SMichael Tuexen NET_EPOCH_ENTER(et);
2044c2625e6eSJosh Paetzel if(rq->islro) {
2045c2625e6eSJosh Paetzel oce_rq_handler_lro(arg);
2046e363f832SMichael Tuexen NET_EPOCH_EXIT(et);
2047c2625e6eSJosh Paetzel return 0;
2048c2625e6eSJosh Paetzel }
2049c2625e6eSJosh Paetzel LOCK(&rq->rx_lock);
20502f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag,
20512f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
20522f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
20532f345d8eSLuigi Rizzo while (cqe->u0.dw[2]) {
20542f345d8eSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
20552f345d8eSLuigi Rizzo
20562f345d8eSLuigi Rizzo if (cqe->u0.s.error == 0) {
2057c2625e6eSJosh Paetzel oce_rx(rq, cqe);
20582f345d8eSLuigi Rizzo } else {
20592f345d8eSLuigi Rizzo rq->rx_stats.rxcp_err++;
2060c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
20612f345d8eSLuigi Rizzo /* Post L3/L4 errors to stack.*/
2062c2625e6eSJosh Paetzel oce_rx(rq, cqe);
20632f345d8eSLuigi Rizzo }
20642f345d8eSLuigi Rizzo rq->rx_stats.rx_compl++;
20652f345d8eSLuigi Rizzo cqe->u0.dw[2] = 0;
20662f345d8eSLuigi Rizzo
2067ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
20682f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
20692f345d8eSLuigi Rizzo oce_rx_flush_lro(rq);
20702f345d8eSLuigi Rizzo }
2071ad512958SBjoern A. Zeeb #endif
20722f345d8eSLuigi Rizzo
20732f345d8eSLuigi Rizzo RING_GET(cq->ring, 1);
20742f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag,
20752f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
20762f345d8eSLuigi Rizzo cqe =
20772f345d8eSLuigi Rizzo RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
20782f345d8eSLuigi Rizzo num_cqes++;
20792f345d8eSLuigi Rizzo if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
20802f345d8eSLuigi Rizzo break;
20812f345d8eSLuigi Rizzo }
20829bd3250aSLuigi Rizzo
2083ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
20842f345d8eSLuigi Rizzo if (IF_LRO_ENABLED(sc))
20852f345d8eSLuigi Rizzo oce_rx_flush_lro(rq);
2086ad512958SBjoern A. Zeeb #endif
20872f345d8eSLuigi Rizzo
2088c2625e6eSJosh Paetzel oce_check_rx_bufs(sc, num_cqes, rq);
2089c2625e6eSJosh Paetzel UNLOCK(&rq->rx_lock);
2090e363f832SMichael Tuexen NET_EPOCH_EXIT(et);
20912f345d8eSLuigi Rizzo return 0;
20922f345d8eSLuigi Rizzo
20932f345d8eSLuigi Rizzo }
20942f345d8eSLuigi Rizzo
20952f345d8eSLuigi Rizzo /*****************************************************************************
20962f345d8eSLuigi Rizzo * Helper function prototypes in this file *
20972f345d8eSLuigi Rizzo *****************************************************************************/
20982f345d8eSLuigi Rizzo
2099*aa386085SZhenlei Huang static void
oce_attach_ifp(POCE_SOFTC sc)21002f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc)
21012f345d8eSLuigi Rizzo {
21022f345d8eSLuigi Rizzo
21032f345d8eSLuigi Rizzo sc->ifp = if_alloc(IFT_ETHER);
21042f345d8eSLuigi Rizzo
21052f345d8eSLuigi Rizzo ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
21062f345d8eSLuigi Rizzo ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
21072f345d8eSLuigi Rizzo ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
21082f345d8eSLuigi Rizzo
2109a6b55ee6SGleb Smirnoff if_setflags(sc->ifp, IFF_BROADCAST | IFF_MULTICAST);
211067fd4c9dSJustin Hibbits if_setioctlfn(sc->ifp, oce_ioctl);
211167fd4c9dSJustin Hibbits if_setstartfn(sc->ifp, oce_start);
211267fd4c9dSJustin Hibbits if_setinitfn(sc->ifp, oce_init);
211367fd4c9dSJustin Hibbits if_setmtu(sc->ifp, ETHERMTU);
211467fd4c9dSJustin Hibbits if_setsoftc(sc->ifp, sc);
211567fd4c9dSJustin Hibbits if_settransmitfn(sc->ifp, oce_multiq_start);
211667fd4c9dSJustin Hibbits if_setqflushfn(sc->ifp, oce_multiq_flush);
21172f345d8eSLuigi Rizzo
21182f345d8eSLuigi Rizzo if_initname(sc->ifp,
21192f345d8eSLuigi Rizzo device_get_name(sc->dev), device_get_unit(sc->dev));
21202f345d8eSLuigi Rizzo
212167fd4c9dSJustin Hibbits if_setsendqlen(sc->ifp, OCE_MAX_TX_DESC - 1);
212267fd4c9dSJustin Hibbits if_setsendqready(sc->ifp);
21232f345d8eSLuigi Rizzo
212467fd4c9dSJustin Hibbits if_sethwassist(sc->ifp, OCE_IF_HWASSIST);
212567fd4c9dSJustin Hibbits if_sethwassistbits(sc->ifp, CSUM_TSO, 0);
212667fd4c9dSJustin Hibbits if_sethwassistbits(sc->ifp, (CSUM_IP | CSUM_TCP | CSUM_UDP), 0);
21272f345d8eSLuigi Rizzo
212867fd4c9dSJustin Hibbits if_setcapabilities(sc->ifp, OCE_IF_CAPABILITIES);
212967fd4c9dSJustin Hibbits if_setcapabilitiesbit(sc->ifp, IFCAP_HWCSUM, 0);
213067fd4c9dSJustin Hibbits if_setcapabilitiesbit(sc->ifp, IFCAP_VLAN_HWFILTER, 0);
21319bd3250aSLuigi Rizzo
2132ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
213367fd4c9dSJustin Hibbits if_setcapabilitiesbit(sc->ifp, IFCAP_TSO, 0);
213467fd4c9dSJustin Hibbits if_setcapabilitiesbit(sc->ifp, IFCAP_LRO, 0);
213567fd4c9dSJustin Hibbits if_setcapabilitiesbit(sc->ifp, IFCAP_VLAN_HWTSO, 0);
2136ad512958SBjoern A. Zeeb #endif
21372f345d8eSLuigi Rizzo
213867fd4c9dSJustin Hibbits if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp));
213967fd4c9dSJustin Hibbits if_setbaudrate(sc->ifp, IF_Gbps(10));
21402f345d8eSLuigi Rizzo
214167fd4c9dSJustin Hibbits if_sethwtsomax(sc->ifp, 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
214267fd4c9dSJustin Hibbits if_sethwtsomaxsegcount(sc->ifp, OCE_MAX_TX_ELEMENTS);
214367fd4c9dSJustin Hibbits if_sethwtsomaxsegsize(sc->ifp, 4096);
21445fbb6830SXin LI
21452f345d8eSLuigi Rizzo ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
21462f345d8eSLuigi Rizzo }
21472f345d8eSLuigi Rizzo
21482f345d8eSLuigi Rizzo static void
oce_add_vlan(void * arg,if_t ifp,uint16_t vtag)214967fd4c9dSJustin Hibbits oce_add_vlan(void *arg, if_t ifp, uint16_t vtag)
21502f345d8eSLuigi Rizzo {
215167fd4c9dSJustin Hibbits POCE_SOFTC sc = if_getsoftc(ifp);
21522f345d8eSLuigi Rizzo
215367fd4c9dSJustin Hibbits if (if_getsoftc(ifp) != arg)
21542f345d8eSLuigi Rizzo return;
21552f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095))
21562f345d8eSLuigi Rizzo return;
21572f345d8eSLuigi Rizzo
21582f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 1;
21592f345d8eSLuigi Rizzo sc->vlans_added++;
21605fbb6830SXin LI if (sc->vlans_added <= (sc->max_vlans + 1))
21612f345d8eSLuigi Rizzo oce_vid_config(sc);
21622f345d8eSLuigi Rizzo }
21632f345d8eSLuigi Rizzo
21642f345d8eSLuigi Rizzo static void
oce_del_vlan(void * arg,if_t ifp,uint16_t vtag)216567fd4c9dSJustin Hibbits oce_del_vlan(void *arg, if_t ifp, uint16_t vtag)
21662f345d8eSLuigi Rizzo {
216767fd4c9dSJustin Hibbits POCE_SOFTC sc = if_getsoftc(ifp);
21682f345d8eSLuigi Rizzo
216967fd4c9dSJustin Hibbits if (if_getsoftc(ifp) != arg)
21702f345d8eSLuigi Rizzo return;
21712f345d8eSLuigi Rizzo if ((vtag == 0) || (vtag > 4095))
21722f345d8eSLuigi Rizzo return;
21732f345d8eSLuigi Rizzo
21742f345d8eSLuigi Rizzo sc->vlan_tag[vtag] = 0;
21752f345d8eSLuigi Rizzo sc->vlans_added--;
21762f345d8eSLuigi Rizzo oce_vid_config(sc);
21772f345d8eSLuigi Rizzo }
21782f345d8eSLuigi Rizzo
21792f345d8eSLuigi Rizzo /*
21802f345d8eSLuigi Rizzo * A max of 64 vlans can be configured in BE. If the user configures
21812f345d8eSLuigi Rizzo * more, place the card in vlan promiscuous mode.
21822f345d8eSLuigi Rizzo */
21832f345d8eSLuigi Rizzo static int
oce_vid_config(POCE_SOFTC sc)21842f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc)
21852f345d8eSLuigi Rizzo {
21862f345d8eSLuigi Rizzo struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
21872f345d8eSLuigi Rizzo uint16_t ntags = 0, i;
21882f345d8eSLuigi Rizzo int status = 0;
21892f345d8eSLuigi Rizzo
21902f345d8eSLuigi Rizzo if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
219167fd4c9dSJustin Hibbits (if_getcapenable(sc->ifp) & IFCAP_VLAN_HWFILTER)) {
21922f345d8eSLuigi Rizzo for (i = 0; i < MAX_VLANS; i++) {
21932f345d8eSLuigi Rizzo if (sc->vlan_tag[i]) {
21942f345d8eSLuigi Rizzo vtags[ntags].vtag = i;
21952f345d8eSLuigi Rizzo ntags++;
21962f345d8eSLuigi Rizzo }
21972f345d8eSLuigi Rizzo }
21982f345d8eSLuigi Rizzo if (ntags)
21992f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id,
22002f345d8eSLuigi Rizzo vtags, ntags, 1, 0);
22012f345d8eSLuigi Rizzo } else
22022f345d8eSLuigi Rizzo status = oce_config_vlan(sc, (uint8_t) sc->if_id,
22032f345d8eSLuigi Rizzo NULL, 0, 1, 1);
22042f345d8eSLuigi Rizzo return status;
22052f345d8eSLuigi Rizzo }
22062f345d8eSLuigi Rizzo
22072f345d8eSLuigi Rizzo static void
oce_mac_addr_set(POCE_SOFTC sc)22082f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc)
22092f345d8eSLuigi Rizzo {
22102f345d8eSLuigi Rizzo uint32_t old_pmac_id = sc->pmac_id;
22112f345d8eSLuigi Rizzo int status = 0;
22122f345d8eSLuigi Rizzo
221367fd4c9dSJustin Hibbits status = bcmp((if_getlladdr(sc->ifp)), sc->macaddr.mac_addr,
22142f345d8eSLuigi Rizzo sc->macaddr.size_of_struct);
22152f345d8eSLuigi Rizzo if (!status)
22162f345d8eSLuigi Rizzo return;
22172f345d8eSLuigi Rizzo
221867fd4c9dSJustin Hibbits status = oce_mbox_macaddr_add(sc, (uint8_t *)(if_getlladdr(sc->ifp)),
22192f345d8eSLuigi Rizzo sc->if_id, &sc->pmac_id);
22202f345d8eSLuigi Rizzo if (!status) {
22212f345d8eSLuigi Rizzo status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
222267fd4c9dSJustin Hibbits bcopy((if_getlladdr(sc->ifp)), sc->macaddr.mac_addr,
22232f345d8eSLuigi Rizzo sc->macaddr.size_of_struct);
22242f345d8eSLuigi Rizzo }
22252f345d8eSLuigi Rizzo if (status)
22262f345d8eSLuigi Rizzo device_printf(sc->dev, "Failed update macaddress\n");
22272f345d8eSLuigi Rizzo
22282f345d8eSLuigi Rizzo }
22292f345d8eSLuigi Rizzo
22302f345d8eSLuigi Rizzo static int
oce_handle_passthrough(if_t ifp,caddr_t data)223167fd4c9dSJustin Hibbits oce_handle_passthrough(if_t ifp, caddr_t data)
22322f345d8eSLuigi Rizzo {
223367fd4c9dSJustin Hibbits POCE_SOFTC sc = if_getsoftc(ifp);
22342f345d8eSLuigi Rizzo struct ifreq *ifr = (struct ifreq *)data;
22352f345d8eSLuigi Rizzo int rc = ENXIO;
22362f345d8eSLuigi Rizzo char cookie[32] = {0};
2237541d96aaSBrooks Davis void *priv_data = ifr_data_get_ptr(ifr);
22382f345d8eSLuigi Rizzo void *ioctl_ptr;
22392f345d8eSLuigi Rizzo uint32_t req_size;
22402f345d8eSLuigi Rizzo struct mbx_hdr req;
22412f345d8eSLuigi Rizzo OCE_DMA_MEM dma_mem;
22422f345d8eSLuigi Rizzo
22432f345d8eSLuigi Rizzo if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
22442f345d8eSLuigi Rizzo return EFAULT;
22452f345d8eSLuigi Rizzo
22462f345d8eSLuigi Rizzo if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
22472f345d8eSLuigi Rizzo return EINVAL;
22482f345d8eSLuigi Rizzo
22492f345d8eSLuigi Rizzo ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
22502f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
22512f345d8eSLuigi Rizzo return EFAULT;
22522f345d8eSLuigi Rizzo
22532f345d8eSLuigi Rizzo req_size = le32toh(req.u0.req.request_length);
22542f345d8eSLuigi Rizzo if (req_size > 65536)
22552f345d8eSLuigi Rizzo return EINVAL;
22562f345d8eSLuigi Rizzo
22572f345d8eSLuigi Rizzo req_size += sizeof(struct mbx_hdr);
22582f345d8eSLuigi Rizzo rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
22592f345d8eSLuigi Rizzo if (rc)
22602f345d8eSLuigi Rizzo return ENOMEM;
22612f345d8eSLuigi Rizzo
22622f345d8eSLuigi Rizzo if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
22632f345d8eSLuigi Rizzo rc = EFAULT;
22642f345d8eSLuigi Rizzo goto dma_free;
22652f345d8eSLuigi Rizzo }
22662f345d8eSLuigi Rizzo
22672f345d8eSLuigi Rizzo rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
22682f345d8eSLuigi Rizzo if (rc) {
22692f345d8eSLuigi Rizzo rc = EIO;
22702f345d8eSLuigi Rizzo goto dma_free;
22712f345d8eSLuigi Rizzo }
22722f345d8eSLuigi Rizzo
2273758927a9SBrooks Davis if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) {
22742f345d8eSLuigi Rizzo rc = EFAULT;
2275758927a9SBrooks Davis goto dma_free;
2276758927a9SBrooks Davis }
22772f345d8eSLuigi Rizzo
2278cdaba892SXin LI /*
2279cdaba892SXin LI firmware is filling all the attributes for this ioctl except
2280cdaba892SXin LI the driver version..so fill it
2281cdaba892SXin LI */
2282cdaba892SXin LI if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) {
2283758927a9SBrooks Davis struct mbx_common_get_cntl_attr *fw_cmd =
2284758927a9SBrooks Davis (struct mbx_common_get_cntl_attr *)ioctl_ptr;
2285758927a9SBrooks Davis _Static_assert(sizeof(COMPONENT_REVISION) <=
2286758927a9SBrooks Davis sizeof(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str),
2287758927a9SBrooks Davis "driver version string too long");
2288758927a9SBrooks Davis
2289758927a9SBrooks Davis rc = copyout(COMPONENT_REVISION,
2290758927a9SBrooks Davis fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str,
2291758927a9SBrooks Davis sizeof(COMPONENT_REVISION));
2292cdaba892SXin LI }
2293cdaba892SXin LI
22942f345d8eSLuigi Rizzo dma_free:
22952f345d8eSLuigi Rizzo oce_dma_free(sc, &dma_mem);
22962f345d8eSLuigi Rizzo return rc;
22972f345d8eSLuigi Rizzo
22982f345d8eSLuigi Rizzo }
22992f345d8eSLuigi Rizzo
2300cdaba892SXin LI static void
oce_eqd_set_periodic(POCE_SOFTC sc)2301cdaba892SXin LI oce_eqd_set_periodic(POCE_SOFTC sc)
2302cdaba892SXin LI {
2303cdaba892SXin LI struct oce_set_eqd set_eqd[OCE_MAX_EQ];
2304cdaba892SXin LI struct oce_aic_obj *aic;
2305cdaba892SXin LI struct oce_eq *eqo;
2306cdaba892SXin LI uint64_t now = 0, delta;
2307cdaba892SXin LI int eqd, i, num = 0;
2308c2625e6eSJosh Paetzel uint32_t tx_reqs = 0, rxpkts = 0, pps;
2309c2625e6eSJosh Paetzel struct oce_wq *wq;
2310c2625e6eSJosh Paetzel struct oce_rq *rq;
2311c2625e6eSJosh Paetzel
2312c2625e6eSJosh Paetzel #define ticks_to_msecs(t) (1000 * (t) / hz)
2313cdaba892SXin LI
2314cdaba892SXin LI for (i = 0 ; i < sc->neqs; i++) {
2315cdaba892SXin LI eqo = sc->eq[i];
2316cdaba892SXin LI aic = &sc->aic_obj[i];
2317cdaba892SXin LI /* When setting the static eq delay from the user space */
2318cdaba892SXin LI if (!aic->enable) {
2319c2625e6eSJosh Paetzel if (aic->ticks)
2320c2625e6eSJosh Paetzel aic->ticks = 0;
2321cdaba892SXin LI eqd = aic->et_eqd;
2322cdaba892SXin LI goto modify_eqd;
2323cdaba892SXin LI }
2324cdaba892SXin LI
232535828280SAlexander Motin if (i == 0) {
232635828280SAlexander Motin rq = sc->rq[0];
2327c2625e6eSJosh Paetzel rxpkts = rq->rx_stats.rx_pkts;
232835828280SAlexander Motin } else
232935828280SAlexander Motin rxpkts = 0;
233035828280SAlexander Motin if (i + 1 < sc->nrqs) {
233135828280SAlexander Motin rq = sc->rq[i + 1];
233235828280SAlexander Motin rxpkts += rq->rx_stats.rx_pkts;
233335828280SAlexander Motin }
233435828280SAlexander Motin if (i < sc->nwqs) {
2335c2625e6eSJosh Paetzel wq = sc->wq[i];
2336c2625e6eSJosh Paetzel tx_reqs = wq->tx_stats.tx_reqs;
233735828280SAlexander Motin } else
233835828280SAlexander Motin tx_reqs = 0;
2339cdaba892SXin LI now = ticks;
2340cdaba892SXin LI
2341c2625e6eSJosh Paetzel if (!aic->ticks || now < aic->ticks ||
2342c2625e6eSJosh Paetzel rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) {
2343c2625e6eSJosh Paetzel aic->prev_rxpkts = rxpkts;
2344c2625e6eSJosh Paetzel aic->prev_txreqs = tx_reqs;
2345c2625e6eSJosh Paetzel aic->ticks = now;
2346c2625e6eSJosh Paetzel continue;
2347c2625e6eSJosh Paetzel }
2348cdaba892SXin LI
2349c2625e6eSJosh Paetzel delta = ticks_to_msecs(now - aic->ticks);
2350cdaba892SXin LI
2351c2625e6eSJosh Paetzel pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) +
2352c2625e6eSJosh Paetzel (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta);
2353c2625e6eSJosh Paetzel eqd = (pps / 15000) << 2;
2354c2625e6eSJosh Paetzel if (eqd < 8)
2355cdaba892SXin LI eqd = 0;
2356cdaba892SXin LI
2357cdaba892SXin LI /* Make sure that the eq delay is in the known range */
2358cdaba892SXin LI eqd = min(eqd, aic->max_eqd);
2359cdaba892SXin LI eqd = max(eqd, aic->min_eqd);
2360cdaba892SXin LI
2361c2625e6eSJosh Paetzel aic->prev_rxpkts = rxpkts;
2362c2625e6eSJosh Paetzel aic->prev_txreqs = tx_reqs;
2363c2625e6eSJosh Paetzel aic->ticks = now;
2364c2625e6eSJosh Paetzel
2365cdaba892SXin LI modify_eqd:
2366cdaba892SXin LI if (eqd != aic->cur_eqd) {
2367cdaba892SXin LI set_eqd[num].delay_multiplier = (eqd * 65)/100;
2368cdaba892SXin LI set_eqd[num].eq_id = eqo->eq_id;
2369cdaba892SXin LI aic->cur_eqd = eqd;
2370cdaba892SXin LI num++;
2371cdaba892SXin LI }
2372cdaba892SXin LI }
2373cdaba892SXin LI
2374cdaba892SXin LI /* Is there atleast one eq that needs to be modified? */
2375c2625e6eSJosh Paetzel for(i = 0; i < num; i += 8) {
2376c2625e6eSJosh Paetzel if((num - i) >=8 )
2377c2625e6eSJosh Paetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8);
2378c2625e6eSJosh Paetzel else
2379c2625e6eSJosh Paetzel oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i));
2380c2625e6eSJosh Paetzel }
2381c2625e6eSJosh Paetzel
2382cdaba892SXin LI }
23832f345d8eSLuigi Rizzo
oce_detect_hw_error(POCE_SOFTC sc)23845fbb6830SXin LI static void oce_detect_hw_error(POCE_SOFTC sc)
23855fbb6830SXin LI {
23865fbb6830SXin LI
23875fbb6830SXin LI uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0;
23885fbb6830SXin LI uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
23895fbb6830SXin LI uint32_t i;
23905fbb6830SXin LI
23915fbb6830SXin LI if (sc->hw_error)
23925fbb6830SXin LI return;
23935fbb6830SXin LI
23945fbb6830SXin LI if (IS_XE201(sc)) {
23955fbb6830SXin LI sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET);
23965fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
23975fbb6830SXin LI sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET);
23985fbb6830SXin LI sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET);
23995fbb6830SXin LI }
24005fbb6830SXin LI } else {
24015fbb6830SXin LI ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW);
24025fbb6830SXin LI ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH);
24035fbb6830SXin LI ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK);
24045fbb6830SXin LI ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK);
24055fbb6830SXin LI
24065fbb6830SXin LI ue_low = (ue_low & ~ue_low_mask);
24075fbb6830SXin LI ue_high = (ue_high & ~ue_high_mask);
24085fbb6830SXin LI }
24095fbb6830SXin LI
24105fbb6830SXin LI /* On certain platforms BE hardware can indicate spurious UEs.
24115fbb6830SXin LI * Allow the h/w to stop working completely in case of a real UE.
24125fbb6830SXin LI * Hence not setting the hw_error for UE detection.
24135fbb6830SXin LI */
24145fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24155fbb6830SXin LI sc->hw_error = TRUE;
24165fbb6830SXin LI device_printf(sc->dev, "Error detected in the card\n");
24175fbb6830SXin LI }
24185fbb6830SXin LI
24195fbb6830SXin LI if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24205fbb6830SXin LI device_printf(sc->dev,
24215fbb6830SXin LI "ERR: sliport status 0x%x\n", sliport_status);
24225fbb6830SXin LI device_printf(sc->dev,
24235fbb6830SXin LI "ERR: sliport error1 0x%x\n", sliport_err1);
24245fbb6830SXin LI device_printf(sc->dev,
24255fbb6830SXin LI "ERR: sliport error2 0x%x\n", sliport_err2);
24265fbb6830SXin LI }
24275fbb6830SXin LI
24285fbb6830SXin LI if (ue_low) {
24295fbb6830SXin LI for (i = 0; ue_low; ue_low >>= 1, i++) {
24305fbb6830SXin LI if (ue_low & 1)
24315fbb6830SXin LI device_printf(sc->dev, "UE: %s bit set\n",
24325fbb6830SXin LI ue_status_low_desc[i]);
24335fbb6830SXin LI }
24345fbb6830SXin LI }
24355fbb6830SXin LI
24365fbb6830SXin LI if (ue_high) {
24375fbb6830SXin LI for (i = 0; ue_high; ue_high >>= 1, i++) {
24385fbb6830SXin LI if (ue_high & 1)
24395fbb6830SXin LI device_printf(sc->dev, "UE: %s bit set\n",
24405fbb6830SXin LI ue_status_hi_desc[i]);
24415fbb6830SXin LI }
24425fbb6830SXin LI }
24435fbb6830SXin LI
24445fbb6830SXin LI }
24455fbb6830SXin LI
24462f345d8eSLuigi Rizzo static void
oce_local_timer(void * arg)24472f345d8eSLuigi Rizzo oce_local_timer(void *arg)
24482f345d8eSLuigi Rizzo {
24492f345d8eSLuigi Rizzo POCE_SOFTC sc = arg;
24502f345d8eSLuigi Rizzo int i = 0;
24512f345d8eSLuigi Rizzo
24525fbb6830SXin LI oce_detect_hw_error(sc);
24532f345d8eSLuigi Rizzo oce_refresh_nic_stats(sc);
24542f345d8eSLuigi Rizzo oce_refresh_queue_stats(sc);
24552f345d8eSLuigi Rizzo oce_mac_addr_set(sc);
24562f345d8eSLuigi Rizzo
24572f345d8eSLuigi Rizzo /* TX Watch Dog*/
24582f345d8eSLuigi Rizzo for (i = 0; i < sc->nwqs; i++)
24592f345d8eSLuigi Rizzo oce_tx_restart(sc, sc->wq[i]);
24602f345d8eSLuigi Rizzo
2461cdaba892SXin LI /* calculate and set the eq delay for optimal interrupt rate */
2462291a1934SXin LI if (IS_BE(sc) || IS_SH(sc))
2463cdaba892SXin LI oce_eqd_set_periodic(sc);
2464cdaba892SXin LI
24652f345d8eSLuigi Rizzo callout_reset(&sc->timer, hz, oce_local_timer, sc);
24662f345d8eSLuigi Rizzo }
24672f345d8eSLuigi Rizzo
2468c2625e6eSJosh Paetzel static void
oce_tx_compl_clean(POCE_SOFTC sc)2469c2625e6eSJosh Paetzel oce_tx_compl_clean(POCE_SOFTC sc)
2470c2625e6eSJosh Paetzel {
2471c2625e6eSJosh Paetzel struct oce_wq *wq;
2472c2625e6eSJosh Paetzel int i = 0, timeo = 0, num_wqes = 0;
2473c2625e6eSJosh Paetzel int pending_txqs = sc->nwqs;
2474c2625e6eSJosh Paetzel
2475c2625e6eSJosh Paetzel /* Stop polling for compls when HW has been silent for 10ms or
2476c2625e6eSJosh Paetzel * hw_error or no outstanding completions expected
2477c2625e6eSJosh Paetzel */
2478c2625e6eSJosh Paetzel do {
2479c2625e6eSJosh Paetzel pending_txqs = sc->nwqs;
2480c2625e6eSJosh Paetzel
2481c2625e6eSJosh Paetzel for_all_wq_queues(sc, wq, i) {
2482c2625e6eSJosh Paetzel num_wqes = oce_wq_handler(wq);
2483c2625e6eSJosh Paetzel
2484c2625e6eSJosh Paetzel if(num_wqes)
2485c2625e6eSJosh Paetzel timeo = 0;
2486c2625e6eSJosh Paetzel
2487c2625e6eSJosh Paetzel if(!wq->ring->num_used)
2488c2625e6eSJosh Paetzel pending_txqs--;
2489c2625e6eSJosh Paetzel }
2490c2625e6eSJosh Paetzel
2491c2625e6eSJosh Paetzel if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error)
2492c2625e6eSJosh Paetzel break;
2493c2625e6eSJosh Paetzel
2494c2625e6eSJosh Paetzel DELAY(1000);
2495c2625e6eSJosh Paetzel } while (TRUE);
2496c2625e6eSJosh Paetzel
2497c2625e6eSJosh Paetzel for_all_wq_queues(sc, wq, i) {
2498c2625e6eSJosh Paetzel while(wq->ring->num_used) {
2499c2625e6eSJosh Paetzel LOCK(&wq->tx_compl_lock);
2500c2625e6eSJosh Paetzel oce_process_tx_completion(wq);
2501c2625e6eSJosh Paetzel UNLOCK(&wq->tx_compl_lock);
2502c2625e6eSJosh Paetzel }
2503c2625e6eSJosh Paetzel }
2504c2625e6eSJosh Paetzel
2505c2625e6eSJosh Paetzel }
25062f345d8eSLuigi Rizzo
2507beb0f7e7SJosh Paetzel /* NOTE : This should only be called holding
2508beb0f7e7SJosh Paetzel * DEVICE_LOCK.
2509beb0f7e7SJosh Paetzel */
25102f345d8eSLuigi Rizzo static void
oce_if_deactivate(POCE_SOFTC sc)25112f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc)
25122f345d8eSLuigi Rizzo {
2513c2625e6eSJosh Paetzel int i;
25142f345d8eSLuigi Rizzo struct oce_rq *rq;
25152f345d8eSLuigi Rizzo struct oce_wq *wq;
25162f345d8eSLuigi Rizzo struct oce_eq *eq;
25172f345d8eSLuigi Rizzo
251867fd4c9dSJustin Hibbits if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
25192f345d8eSLuigi Rizzo
2520c2625e6eSJosh Paetzel oce_tx_compl_clean(sc);
25212f345d8eSLuigi Rizzo
25222f345d8eSLuigi Rizzo /* Stop intrs and finish any bottom halves pending */
25232f345d8eSLuigi Rizzo oce_hw_intr_disable(sc);
25242f345d8eSLuigi Rizzo
2525cdaba892SXin LI /* Since taskqueue_drain takes a Gaint Lock, We should not acquire
2526beb0f7e7SJosh Paetzel any other lock. So unlock device lock and require after
2527beb0f7e7SJosh Paetzel completing taskqueue_drain.
2528beb0f7e7SJosh Paetzel */
2529beb0f7e7SJosh Paetzel UNLOCK(&sc->dev_lock);
25302f345d8eSLuigi Rizzo for (i = 0; i < sc->intr_count; i++) {
25312f345d8eSLuigi Rizzo if (sc->intrs[i].tq != NULL) {
25322f345d8eSLuigi Rizzo taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
25332f345d8eSLuigi Rizzo }
25342f345d8eSLuigi Rizzo }
2535beb0f7e7SJosh Paetzel LOCK(&sc->dev_lock);
25362f345d8eSLuigi Rizzo
25372f345d8eSLuigi Rizzo /* Delete RX queue in card with flush param */
25382f345d8eSLuigi Rizzo oce_stop_rx(sc);
25392f345d8eSLuigi Rizzo
25402f345d8eSLuigi Rizzo /* Invalidate any pending cq and eq entries*/
25412f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i)
25422f345d8eSLuigi Rizzo oce_drain_eq(eq);
25432f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i)
25442f345d8eSLuigi Rizzo oce_drain_rq_cq(rq);
25452f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i)
25462f345d8eSLuigi Rizzo oce_drain_wq_cq(wq);
25472f345d8eSLuigi Rizzo
25482f345d8eSLuigi Rizzo /* But still we need to get MCC aync events.
25492f345d8eSLuigi Rizzo So enable intrs and also arm first EQ
25502f345d8eSLuigi Rizzo */
25512f345d8eSLuigi Rizzo oce_hw_intr_enable(sc);
25522f345d8eSLuigi Rizzo oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
25532f345d8eSLuigi Rizzo
25542f345d8eSLuigi Rizzo DELAY(10);
25552f345d8eSLuigi Rizzo }
25562f345d8eSLuigi Rizzo
25572f345d8eSLuigi Rizzo static void
oce_if_activate(POCE_SOFTC sc)25582f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc)
25592f345d8eSLuigi Rizzo {
25602f345d8eSLuigi Rizzo struct oce_eq *eq;
25612f345d8eSLuigi Rizzo struct oce_rq *rq;
25622f345d8eSLuigi Rizzo struct oce_wq *wq;
25632f345d8eSLuigi Rizzo int i, rc = 0;
25642f345d8eSLuigi Rizzo
256567fd4c9dSJustin Hibbits if_setdrvflagbits(sc->ifp, IFF_DRV_RUNNING , 0);
25662f345d8eSLuigi Rizzo
25672f345d8eSLuigi Rizzo oce_hw_intr_disable(sc);
25682f345d8eSLuigi Rizzo
25692f345d8eSLuigi Rizzo oce_start_rx(sc);
25702f345d8eSLuigi Rizzo
25712f345d8eSLuigi Rizzo for_all_rq_queues(sc, rq, i) {
25722f345d8eSLuigi Rizzo rc = oce_start_rq(rq);
25732f345d8eSLuigi Rizzo if (rc)
25742f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start RX\n");
25752f345d8eSLuigi Rizzo }
25762f345d8eSLuigi Rizzo
25772f345d8eSLuigi Rizzo for_all_wq_queues(sc, wq, i) {
25782f345d8eSLuigi Rizzo rc = oce_start_wq(wq);
25792f345d8eSLuigi Rizzo if (rc)
25802f345d8eSLuigi Rizzo device_printf(sc->dev, "Unable to start TX\n");
25812f345d8eSLuigi Rizzo }
25822f345d8eSLuigi Rizzo
25832f345d8eSLuigi Rizzo for_all_evnt_queues(sc, eq, i)
25842f345d8eSLuigi Rizzo oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
25852f345d8eSLuigi Rizzo
25862f345d8eSLuigi Rizzo oce_hw_intr_enable(sc);
25872f345d8eSLuigi Rizzo
25882f345d8eSLuigi Rizzo }
25892f345d8eSLuigi Rizzo
25909bd3250aSLuigi Rizzo static void
process_link_state(POCE_SOFTC sc,struct oce_async_cqe_link_state * acqe)25919bd3250aSLuigi Rizzo process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
25922f345d8eSLuigi Rizzo {
25939bd3250aSLuigi Rizzo /* Update Link status */
25942f345d8eSLuigi Rizzo if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
25952f345d8eSLuigi Rizzo ASYNC_EVENT_LINK_UP) {
25962f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_UP;
25972f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_UP);
25982f345d8eSLuigi Rizzo } else {
25992f345d8eSLuigi Rizzo sc->link_status = ASYNC_EVENT_LINK_DOWN;
26002f345d8eSLuigi Rizzo if_link_state_change(sc->ifp, LINK_STATE_DOWN);
26012f345d8eSLuigi Rizzo }
26029bd3250aSLuigi Rizzo }
26039bd3250aSLuigi Rizzo
oce_async_grp5_osbmc_process(POCE_SOFTC sc,struct oce_async_evt_grp5_os2bmc * evt)2604c2625e6eSJosh Paetzel static void oce_async_grp5_osbmc_process(POCE_SOFTC sc,
2605c2625e6eSJosh Paetzel struct oce_async_evt_grp5_os2bmc *evt)
2606c2625e6eSJosh Paetzel {
2607c2625e6eSJosh Paetzel DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc));
2608c2625e6eSJosh Paetzel if (evt->u.s.mgmt_enable)
2609c2625e6eSJosh Paetzel sc->flags |= OCE_FLAGS_OS2BMC;
2610c2625e6eSJosh Paetzel else
2611c2625e6eSJosh Paetzel return;
2612c2625e6eSJosh Paetzel
2613c2625e6eSJosh Paetzel sc->bmc_filt_mask = evt->u.s.arp_filter;
2614c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1);
2615c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2);
2616c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3);
2617c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4);
2618c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5);
2619c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6);
2620c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7);
2621c2625e6eSJosh Paetzel sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8);
2622c2625e6eSJosh Paetzel }
2623c2625e6eSJosh Paetzel
oce_process_grp5_events(POCE_SOFTC sc,struct oce_mq_cqe * cqe)2624c2625e6eSJosh Paetzel static void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe)
2625c2625e6eSJosh Paetzel {
2626c2625e6eSJosh Paetzel struct oce_async_event_grp5_pvid_state *gcqe;
2627c2625e6eSJosh Paetzel struct oce_async_evt_grp5_os2bmc *bmccqe;
2628c2625e6eSJosh Paetzel
2629c2625e6eSJosh Paetzel switch (cqe->u0.s.async_type) {
2630c2625e6eSJosh Paetzel case ASYNC_EVENT_PVID_STATE:
2631c2625e6eSJosh Paetzel /* GRP5 PVID */
2632c2625e6eSJosh Paetzel gcqe = (struct oce_async_event_grp5_pvid_state *)cqe;
2633c2625e6eSJosh Paetzel if (gcqe->enabled)
2634c2625e6eSJosh Paetzel sc->pvid = gcqe->tag & VLAN_VID_MASK;
2635c2625e6eSJosh Paetzel else
2636c2625e6eSJosh Paetzel sc->pvid = 0;
2637c2625e6eSJosh Paetzel break;
2638c2625e6eSJosh Paetzel case ASYNC_EVENT_OS2BMC:
2639c2625e6eSJosh Paetzel bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe;
2640c2625e6eSJosh Paetzel oce_async_grp5_osbmc_process(sc, bmccqe);
2641c2625e6eSJosh Paetzel break;
2642c2625e6eSJosh Paetzel default:
2643c2625e6eSJosh Paetzel break;
2644c2625e6eSJosh Paetzel }
2645c2625e6eSJosh Paetzel }
2646c2625e6eSJosh Paetzel
26479bd3250aSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */
26489bd3250aSLuigi Rizzo uint16_t
oce_mq_handler(void * arg)26499bd3250aSLuigi Rizzo oce_mq_handler(void *arg)
26509bd3250aSLuigi Rizzo {
26519bd3250aSLuigi Rizzo struct oce_mq *mq = (struct oce_mq *)arg;
26529bd3250aSLuigi Rizzo POCE_SOFTC sc = mq->parent;
26539bd3250aSLuigi Rizzo struct oce_cq *cq = mq->cq;
26549bd3250aSLuigi Rizzo int num_cqes = 0, evt_type = 0, optype = 0;
26559bd3250aSLuigi Rizzo struct oce_mq_cqe *cqe;
26569bd3250aSLuigi Rizzo struct oce_async_cqe_link_state *acqe;
2657cdaba892SXin LI struct oce_async_event_qnq *dbgcqe;
26589bd3250aSLuigi Rizzo
26599bd3250aSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag,
26609bd3250aSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
26619bd3250aSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
26629bd3250aSLuigi Rizzo
26639bd3250aSLuigi Rizzo while (cqe->u0.dw[3]) {
26649bd3250aSLuigi Rizzo DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
26659bd3250aSLuigi Rizzo if (cqe->u0.s.async_event) {
26669bd3250aSLuigi Rizzo evt_type = cqe->u0.s.event_type;
26679bd3250aSLuigi Rizzo optype = cqe->u0.s.async_type;
26689bd3250aSLuigi Rizzo if (evt_type == ASYNC_EVENT_CODE_LINK_STATE) {
26699bd3250aSLuigi Rizzo /* Link status evt */
26709bd3250aSLuigi Rizzo acqe = (struct oce_async_cqe_link_state *)cqe;
26719bd3250aSLuigi Rizzo process_link_state(sc, acqe);
2672c2625e6eSJosh Paetzel } else if (evt_type == ASYNC_EVENT_GRP5) {
2673c2625e6eSJosh Paetzel oce_process_grp5_events(sc, cqe);
2674c2625e6eSJosh Paetzel } else if (evt_type == ASYNC_EVENT_CODE_DEBUG &&
2675cdaba892SXin LI optype == ASYNC_EVENT_DEBUG_QNQ) {
2676c2625e6eSJosh Paetzel dbgcqe = (struct oce_async_event_qnq *)cqe;
2677cdaba892SXin LI if(dbgcqe->valid)
2678cdaba892SXin LI sc->qnqid = dbgcqe->vlan_tag;
2679cdaba892SXin LI sc->qnq_debug_event = TRUE;
2680cdaba892SXin LI }
26812f345d8eSLuigi Rizzo }
26822f345d8eSLuigi Rizzo cqe->u0.dw[3] = 0;
26832f345d8eSLuigi Rizzo RING_GET(cq->ring, 1);
26842f345d8eSLuigi Rizzo bus_dmamap_sync(cq->ring->dma.tag,
26852f345d8eSLuigi Rizzo cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
26862f345d8eSLuigi Rizzo cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
26872f345d8eSLuigi Rizzo num_cqes++;
26882f345d8eSLuigi Rizzo }
26892f345d8eSLuigi Rizzo
26902f345d8eSLuigi Rizzo if (num_cqes)
26912f345d8eSLuigi Rizzo oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
26922f345d8eSLuigi Rizzo
26932f345d8eSLuigi Rizzo return 0;
26942f345d8eSLuigi Rizzo }
26952f345d8eSLuigi Rizzo
26962f345d8eSLuigi Rizzo static void
setup_max_queues_want(POCE_SOFTC sc)26972f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc)
26982f345d8eSLuigi Rizzo {
26992f345d8eSLuigi Rizzo /* Check if it is FLEX machine. Is so dont use RSS */
27002f345d8eSLuigi Rizzo if ((sc->function_mode & FNM_FLEX10_MODE) ||
27019bd3250aSLuigi Rizzo (sc->function_mode & FNM_UMC_MODE) ||
27029bd3250aSLuigi Rizzo (sc->function_mode & FNM_VNIC_MODE) ||
2703291a1934SXin LI (!is_rss_enabled(sc)) ||
2704a4f734b4SXin LI IS_BE2(sc)) {
27052f345d8eSLuigi Rizzo sc->nrqs = 1;
27062f345d8eSLuigi Rizzo sc->nwqs = 1;
27075fbb6830SXin LI } else {
27085fbb6830SXin LI sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
27095fbb6830SXin LI sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs);
27102f345d8eSLuigi Rizzo }
2711a4f734b4SXin LI
2712a4f734b4SXin LI if (IS_BE2(sc) && is_rss_enabled(sc))
2713a4f734b4SXin LI sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
27142f345d8eSLuigi Rizzo }
27152f345d8eSLuigi Rizzo
27162f345d8eSLuigi Rizzo static void
update_queues_got(POCE_SOFTC sc)27172f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc)
27182f345d8eSLuigi Rizzo {
2719291a1934SXin LI if (is_rss_enabled(sc)) {
27202f345d8eSLuigi Rizzo sc->nrqs = sc->intr_count + 1;
27212f345d8eSLuigi Rizzo sc->nwqs = sc->intr_count;
27222f345d8eSLuigi Rizzo } else {
27232f345d8eSLuigi Rizzo sc->nrqs = 1;
27242f345d8eSLuigi Rizzo sc->nwqs = 1;
27252f345d8eSLuigi Rizzo }
2726a4f734b4SXin LI
2727a4f734b4SXin LI if (IS_BE2(sc))
2728a4f734b4SXin LI sc->nwqs = 1;
27292f345d8eSLuigi Rizzo }
27302f345d8eSLuigi Rizzo
2731cdaba892SXin LI static int
oce_check_ipv6_ext_hdr(struct mbuf * m)2732cdaba892SXin LI oce_check_ipv6_ext_hdr(struct mbuf *m)
2733cdaba892SXin LI {
2734cdaba892SXin LI struct ether_header *eh = mtod(m, struct ether_header *);
2735cdaba892SXin LI caddr_t m_datatemp = m->m_data;
2736cdaba892SXin LI
2737cdaba892SXin LI if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2738cdaba892SXin LI m->m_data += sizeof(struct ether_header);
2739cdaba892SXin LI struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2740cdaba892SXin LI
2741cdaba892SXin LI if((ip6->ip6_nxt != IPPROTO_TCP) && \
2742cdaba892SXin LI (ip6->ip6_nxt != IPPROTO_UDP)){
2743cdaba892SXin LI struct ip6_ext *ip6e = NULL;
2744cdaba892SXin LI m->m_data += sizeof(struct ip6_hdr);
2745cdaba892SXin LI
2746cdaba892SXin LI ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *);
2747cdaba892SXin LI if(ip6e->ip6e_len == 0xff) {
2748cdaba892SXin LI m->m_data = m_datatemp;
2749cdaba892SXin LI return TRUE;
2750cdaba892SXin LI }
2751cdaba892SXin LI }
2752cdaba892SXin LI m->m_data = m_datatemp;
2753cdaba892SXin LI }
2754cdaba892SXin LI return FALSE;
2755cdaba892SXin LI }
2756cdaba892SXin LI
2757cdaba892SXin LI static int
is_be3_a1(POCE_SOFTC sc)2758cdaba892SXin LI is_be3_a1(POCE_SOFTC sc)
2759cdaba892SXin LI {
2760cdaba892SXin LI if((sc->flags & OCE_FLAGS_BE3) && ((sc->asic_revision & 0xFF) < 2)) {
2761cdaba892SXin LI return TRUE;
2762cdaba892SXin LI }
2763cdaba892SXin LI return FALSE;
2764cdaba892SXin LI }
2765cdaba892SXin LI
2766cdaba892SXin LI static struct mbuf *
oce_insert_vlan_tag(POCE_SOFTC sc,struct mbuf * m,boolean_t * complete)2767cdaba892SXin LI oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete)
2768cdaba892SXin LI {
2769cdaba892SXin LI uint16_t vlan_tag = 0;
2770cdaba892SXin LI
2771cdaba892SXin LI if(!M_WRITABLE(m))
2772cdaba892SXin LI return NULL;
2773cdaba892SXin LI
2774cdaba892SXin LI /* Embed vlan tag in the packet if it is not part of it */
2775cdaba892SXin LI if(m->m_flags & M_VLANTAG) {
2776cdaba892SXin LI vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
2777cdaba892SXin LI m->m_flags &= ~M_VLANTAG;
2778cdaba892SXin LI }
2779cdaba892SXin LI
2780cdaba892SXin LI /* if UMC, ignore vlan tag insertion and instead insert pvid */
2781cdaba892SXin LI if(sc->pvid) {
2782cdaba892SXin LI if(!vlan_tag)
2783cdaba892SXin LI vlan_tag = sc->pvid;
2784c2625e6eSJosh Paetzel if (complete)
2785cdaba892SXin LI *complete = FALSE;
2786cdaba892SXin LI }
2787cdaba892SXin LI
2788cdaba892SXin LI if(vlan_tag) {
2789cdaba892SXin LI m = ether_vlanencap(m, vlan_tag);
2790cdaba892SXin LI }
2791cdaba892SXin LI
2792cdaba892SXin LI if(sc->qnqid) {
2793cdaba892SXin LI m = ether_vlanencap(m, sc->qnqid);
2794c2625e6eSJosh Paetzel
2795c2625e6eSJosh Paetzel if (complete)
2796cdaba892SXin LI *complete = FALSE;
2797cdaba892SXin LI }
2798cdaba892SXin LI return m;
2799cdaba892SXin LI }
2800cdaba892SXin LI
2801cdaba892SXin LI static int
oce_tx_asic_stall_verify(POCE_SOFTC sc,struct mbuf * m)2802cdaba892SXin LI oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m)
2803cdaba892SXin LI {
2804cdaba892SXin LI if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \
2805cdaba892SXin LI oce_check_ipv6_ext_hdr(m)) {
2806cdaba892SXin LI return TRUE;
2807cdaba892SXin LI }
2808cdaba892SXin LI return FALSE;
2809cdaba892SXin LI }
2810291a1934SXin LI
2811291a1934SXin LI static void
oce_get_config(POCE_SOFTC sc)2812291a1934SXin LI oce_get_config(POCE_SOFTC sc)
2813291a1934SXin LI {
2814291a1934SXin LI int rc = 0;
2815291a1934SXin LI uint32_t max_rss = 0;
2816291a1934SXin LI
2817291a1934SXin LI if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native))
2818291a1934SXin LI max_rss = OCE_LEGACY_MODE_RSS;
2819291a1934SXin LI else
2820291a1934SXin LI max_rss = OCE_MAX_RSS;
2821291a1934SXin LI
2822291a1934SXin LI if (!IS_BE(sc)) {
2823b41206d8SXin LI rc = oce_get_profile_config(sc, max_rss);
2824291a1934SXin LI if (rc) {
2825291a1934SXin LI sc->nwqs = OCE_MAX_WQ;
2826291a1934SXin LI sc->nrssqs = max_rss;
2827291a1934SXin LI sc->nrqs = sc->nrssqs + 1;
2828291a1934SXin LI }
2829291a1934SXin LI }
2830b41206d8SXin LI else { /* For BE3 don't rely on fw for determining the resources */
2831291a1934SXin LI sc->nrssqs = max_rss;
2832291a1934SXin LI sc->nrqs = sc->nrssqs + 1;
2833291a1934SXin LI sc->nwqs = OCE_MAX_WQ;
2834b41206d8SXin LI sc->max_vlans = MAX_VLANFILTER_SIZE;
2835291a1934SXin LI }
2836291a1934SXin LI }
2837c2625e6eSJosh Paetzel
2838c2625e6eSJosh Paetzel static void
oce_rdma_close(void)2839c2625e6eSJosh Paetzel oce_rdma_close(void)
2840c2625e6eSJosh Paetzel {
2841c2625e6eSJosh Paetzel if (oce_rdma_if != NULL) {
2842c2625e6eSJosh Paetzel oce_rdma_if = NULL;
2843c2625e6eSJosh Paetzel }
2844c2625e6eSJosh Paetzel }
2845c2625e6eSJosh Paetzel
2846c2625e6eSJosh Paetzel static void
oce_get_mac_addr(POCE_SOFTC sc,uint8_t * macaddr)2847c2625e6eSJosh Paetzel oce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr)
2848c2625e6eSJosh Paetzel {
2849c2625e6eSJosh Paetzel memcpy(macaddr, sc->macaddr.mac_addr, 6);
2850c2625e6eSJosh Paetzel }
2851c2625e6eSJosh Paetzel
2852c2625e6eSJosh Paetzel int
oce_register_rdma(POCE_RDMA_INFO rdma_info,POCE_RDMA_IF rdma_if)2853c2625e6eSJosh Paetzel oce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if)
2854c2625e6eSJosh Paetzel {
2855c2625e6eSJosh Paetzel POCE_SOFTC sc;
2856c2625e6eSJosh Paetzel struct oce_dev_info di;
2857c2625e6eSJosh Paetzel int i;
2858c2625e6eSJosh Paetzel
2859c2625e6eSJosh Paetzel if ((rdma_info == NULL) || (rdma_if == NULL)) {
2860c2625e6eSJosh Paetzel return -EINVAL;
2861c2625e6eSJosh Paetzel }
2862c2625e6eSJosh Paetzel
2863c2625e6eSJosh Paetzel if ((rdma_info->size != OCE_RDMA_INFO_SIZE) ||
2864c2625e6eSJosh Paetzel (rdma_if->size != OCE_RDMA_IF_SIZE)) {
2865c2625e6eSJosh Paetzel return -ENXIO;
2866c2625e6eSJosh Paetzel }
2867c2625e6eSJosh Paetzel
2868c2625e6eSJosh Paetzel rdma_info->close = oce_rdma_close;
2869c2625e6eSJosh Paetzel rdma_info->mbox_post = oce_mbox_post;
2870c2625e6eSJosh Paetzel rdma_info->common_req_hdr_init = mbx_common_req_hdr_init;
2871c2625e6eSJosh Paetzel rdma_info->get_mac_addr = oce_get_mac_addr;
2872c2625e6eSJosh Paetzel
2873c2625e6eSJosh Paetzel oce_rdma_if = rdma_if;
2874c2625e6eSJosh Paetzel
2875c2625e6eSJosh Paetzel sc = softc_head;
2876c2625e6eSJosh Paetzel while (sc != NULL) {
2877c2625e6eSJosh Paetzel if (oce_rdma_if->announce != NULL) {
2878c2625e6eSJosh Paetzel memset(&di, 0, sizeof(di));
2879c2625e6eSJosh Paetzel di.dev = sc->dev;
2880c2625e6eSJosh Paetzel di.softc = sc;
2881c2625e6eSJosh Paetzel di.ifp = sc->ifp;
2882c2625e6eSJosh Paetzel di.db_bhandle = sc->db_bhandle;
2883c2625e6eSJosh Paetzel di.db_btag = sc->db_btag;
2884c2625e6eSJosh Paetzel di.db_page_size = 4096;
2885c2625e6eSJosh Paetzel if (sc->flags & OCE_FLAGS_USING_MSIX) {
2886c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_MSIX;
2887c2625e6eSJosh Paetzel } else if (sc->flags & OCE_FLAGS_USING_MSI) {
2888c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_MSI;
2889c2625e6eSJosh Paetzel } else {
2890c2625e6eSJosh Paetzel di.intr_mode = OCE_INTERRUPT_MODE_INTX;
2891c2625e6eSJosh Paetzel }
2892c2625e6eSJosh Paetzel di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk
2893c2625e6eSJosh Paetzel if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) {
2894c2625e6eSJosh Paetzel di.msix.num_vectors = sc->intr_count + sc->roce_intr_count;
2895c2625e6eSJosh Paetzel di.msix.start_vector = sc->intr_count;
2896c2625e6eSJosh Paetzel for (i=0; i<di.msix.num_vectors; i++) {
2897c2625e6eSJosh Paetzel di.msix.vector_list[i] = sc->intrs[i].vector;
2898c2625e6eSJosh Paetzel }
2899c2625e6eSJosh Paetzel } else {
2900c2625e6eSJosh Paetzel }
2901c2625e6eSJosh Paetzel memcpy(di.mac_addr, sc->macaddr.mac_addr, 6);
2902c2625e6eSJosh Paetzel di.vendor_id = pci_get_vendor(sc->dev);
2903c2625e6eSJosh Paetzel di.dev_id = pci_get_device(sc->dev);
2904c2625e6eSJosh Paetzel
2905c2625e6eSJosh Paetzel if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
2906c2625e6eSJosh Paetzel di.flags |= OCE_RDMA_INFO_RDMA_SUPPORTED;
2907c2625e6eSJosh Paetzel }
2908c2625e6eSJosh Paetzel
2909c2625e6eSJosh Paetzel rdma_if->announce(&di);
2910c2625e6eSJosh Paetzel sc = sc->next;
2911c2625e6eSJosh Paetzel }
2912c2625e6eSJosh Paetzel }
2913c2625e6eSJosh Paetzel
2914c2625e6eSJosh Paetzel return 0;
2915c2625e6eSJosh Paetzel }
2916c2625e6eSJosh Paetzel
2917c2625e6eSJosh Paetzel static void
oce_read_env_variables(POCE_SOFTC sc)2918c2625e6eSJosh Paetzel oce_read_env_variables( POCE_SOFTC sc )
2919c2625e6eSJosh Paetzel {
2920c2625e6eSJosh Paetzel char *value = NULL;
2921c2625e6eSJosh Paetzel int rc = 0;
2922c2625e6eSJosh Paetzel
2923c2625e6eSJosh Paetzel /* read if user wants to enable hwlro or swlro */
2924c2625e6eSJosh Paetzel //value = getenv("oce_enable_hwlro");
2925c2625e6eSJosh Paetzel if(value && IS_SH(sc)) {
2926c2625e6eSJosh Paetzel sc->enable_hwlro = strtol(value, NULL, 10);
2927c2625e6eSJosh Paetzel if(sc->enable_hwlro) {
2928c2625e6eSJosh Paetzel rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL);
2929c2625e6eSJosh Paetzel if(rc) {
2930c2625e6eSJosh Paetzel device_printf(sc->dev, "no hardware lro support\n");
2931c2625e6eSJosh Paetzel device_printf(sc->dev, "software lro enabled\n");
2932c2625e6eSJosh Paetzel sc->enable_hwlro = 0;
2933c2625e6eSJosh Paetzel }else {
2934c2625e6eSJosh Paetzel device_printf(sc->dev, "hardware lro enabled\n");
2935c2625e6eSJosh Paetzel oce_max_rsp_handled = 32;
2936c2625e6eSJosh Paetzel }
2937c2625e6eSJosh Paetzel }else {
2938c2625e6eSJosh Paetzel device_printf(sc->dev, "software lro enabled\n");
2939c2625e6eSJosh Paetzel }
2940c2625e6eSJosh Paetzel }else {
2941c2625e6eSJosh Paetzel sc->enable_hwlro = 0;
2942c2625e6eSJosh Paetzel }
2943c2625e6eSJosh Paetzel
2944c2625e6eSJosh Paetzel /* read mbuf size */
2945c2625e6eSJosh Paetzel //value = getenv("oce_rq_buf_size");
2946c2625e6eSJosh Paetzel if(value && IS_SH(sc)) {
2947c2625e6eSJosh Paetzel oce_rq_buf_size = strtol(value, NULL, 10);
2948c2625e6eSJosh Paetzel switch(oce_rq_buf_size) {
2949c2625e6eSJosh Paetzel case 2048:
2950c2625e6eSJosh Paetzel case 4096:
2951c2625e6eSJosh Paetzel case 9216:
2952c2625e6eSJosh Paetzel case 16384:
2953c2625e6eSJosh Paetzel break;
2954c2625e6eSJosh Paetzel
2955c2625e6eSJosh Paetzel default:
2956c2625e6eSJosh Paetzel device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n");
2957c2625e6eSJosh Paetzel oce_rq_buf_size = 2048;
2958c2625e6eSJosh Paetzel }
2959c2625e6eSJosh Paetzel }
2960c2625e6eSJosh Paetzel
2961c2625e6eSJosh Paetzel return;
2962c2625e6eSJosh Paetzel }
2963