xref: /freebsd/sys/dev/oce/oce_if.c (revision c8dfaf382fa6df9dc6fd1e1c3356e0c8bf607e6a)
12f345d8eSLuigi Rizzo /*-
2291a1934SXin LI  * Copyright (C) 2013 Emulex
32f345d8eSLuigi Rizzo  * All rights reserved.
42f345d8eSLuigi Rizzo  *
52f345d8eSLuigi Rizzo  * Redistribution and use in source and binary forms, with or without
62f345d8eSLuigi Rizzo  * modification, are permitted provided that the following conditions are met:
72f345d8eSLuigi Rizzo  *
82f345d8eSLuigi Rizzo  * 1. Redistributions of source code must retain the above copyright notice,
92f345d8eSLuigi Rizzo  *    this list of conditions and the following disclaimer.
102f345d8eSLuigi Rizzo  *
112f345d8eSLuigi Rizzo  * 2. Redistributions in binary form must reproduce the above copyright
122f345d8eSLuigi Rizzo  *    notice, this list of conditions and the following disclaimer in the
132f345d8eSLuigi Rizzo  *    documentation and/or other materials provided with the distribution.
142f345d8eSLuigi Rizzo  *
152f345d8eSLuigi Rizzo  * 3. Neither the name of the Emulex Corporation nor the names of its
162f345d8eSLuigi Rizzo  *    contributors may be used to endorse or promote products derived from
172f345d8eSLuigi Rizzo  *    this software without specific prior written permission.
182f345d8eSLuigi Rizzo  *
192f345d8eSLuigi Rizzo  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
202f345d8eSLuigi Rizzo  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
212f345d8eSLuigi Rizzo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
222f345d8eSLuigi Rizzo  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
232f345d8eSLuigi Rizzo  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
242f345d8eSLuigi Rizzo  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
252f345d8eSLuigi Rizzo  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
262f345d8eSLuigi Rizzo  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
272f345d8eSLuigi Rizzo  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
282f345d8eSLuigi Rizzo  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
292f345d8eSLuigi Rizzo  * POSSIBILITY OF SUCH DAMAGE.
302f345d8eSLuigi Rizzo  *
312f345d8eSLuigi Rizzo  * Contact Information:
322f345d8eSLuigi Rizzo  * freebsd-drivers@emulex.com
332f345d8eSLuigi Rizzo  *
342f345d8eSLuigi Rizzo  * Emulex
352f345d8eSLuigi Rizzo  * 3333 Susan Street
362f345d8eSLuigi Rizzo  * Costa Mesa, CA 92626
372f345d8eSLuigi Rizzo  */
382f345d8eSLuigi Rizzo 
392f345d8eSLuigi Rizzo /* $FreeBSD$ */
402f345d8eSLuigi Rizzo 
41ad512958SBjoern A. Zeeb #include "opt_inet6.h"
42ad512958SBjoern A. Zeeb #include "opt_inet.h"
43ad512958SBjoern A. Zeeb 
442f345d8eSLuigi Rizzo #include "oce_if.h"
452f345d8eSLuigi Rizzo 
465fbb6830SXin LI /* UE Status Low CSR */
475fbb6830SXin LI static char *ue_status_low_desc[] = {
485fbb6830SXin LI 	"CEV",
495fbb6830SXin LI 	"CTX",
505fbb6830SXin LI 	"DBUF",
515fbb6830SXin LI 	"ERX",
525fbb6830SXin LI 	"Host",
535fbb6830SXin LI 	"MPU",
545fbb6830SXin LI 	"NDMA",
555fbb6830SXin LI 	"PTC ",
565fbb6830SXin LI 	"RDMA ",
575fbb6830SXin LI 	"RXF ",
585fbb6830SXin LI 	"RXIPS ",
595fbb6830SXin LI 	"RXULP0 ",
605fbb6830SXin LI 	"RXULP1 ",
615fbb6830SXin LI 	"RXULP2 ",
625fbb6830SXin LI 	"TIM ",
635fbb6830SXin LI 	"TPOST ",
645fbb6830SXin LI 	"TPRE ",
655fbb6830SXin LI 	"TXIPS ",
665fbb6830SXin LI 	"TXULP0 ",
675fbb6830SXin LI 	"TXULP1 ",
685fbb6830SXin LI 	"UC ",
695fbb6830SXin LI 	"WDMA ",
705fbb6830SXin LI 	"TXULP2 ",
715fbb6830SXin LI 	"HOST1 ",
725fbb6830SXin LI 	"P0_OB_LINK ",
735fbb6830SXin LI 	"P1_OB_LINK ",
745fbb6830SXin LI 	"HOST_GPIO ",
755fbb6830SXin LI 	"MBOX ",
765fbb6830SXin LI 	"AXGMAC0",
775fbb6830SXin LI 	"AXGMAC1",
785fbb6830SXin LI 	"JTAG",
795fbb6830SXin LI 	"MPU_INTPEND"
805fbb6830SXin LI };
815fbb6830SXin LI 
825fbb6830SXin LI /* UE Status High CSR */
835fbb6830SXin LI static char *ue_status_hi_desc[] = {
845fbb6830SXin LI 	"LPCMEMHOST",
855fbb6830SXin LI 	"MGMT_MAC",
865fbb6830SXin LI 	"PCS0ONLINE",
875fbb6830SXin LI 	"MPU_IRAM",
885fbb6830SXin LI 	"PCS1ONLINE",
895fbb6830SXin LI 	"PCTL0",
905fbb6830SXin LI 	"PCTL1",
915fbb6830SXin LI 	"PMEM",
925fbb6830SXin LI 	"RR",
935fbb6830SXin LI 	"TXPB",
945fbb6830SXin LI 	"RXPP",
955fbb6830SXin LI 	"XAUI",
965fbb6830SXin LI 	"TXP",
975fbb6830SXin LI 	"ARM",
985fbb6830SXin LI 	"IPC",
995fbb6830SXin LI 	"HOST2",
1005fbb6830SXin LI 	"HOST3",
1015fbb6830SXin LI 	"HOST4",
1025fbb6830SXin LI 	"HOST5",
1035fbb6830SXin LI 	"HOST6",
1045fbb6830SXin LI 	"HOST7",
1055fbb6830SXin LI 	"HOST8",
1065fbb6830SXin LI 	"HOST9",
1075fbb6830SXin LI 	"NETC",
1085fbb6830SXin LI 	"Unknown",
1095fbb6830SXin LI 	"Unknown",
1105fbb6830SXin LI 	"Unknown",
1115fbb6830SXin LI 	"Unknown",
1125fbb6830SXin LI 	"Unknown",
1135fbb6830SXin LI 	"Unknown",
1145fbb6830SXin LI 	"Unknown",
1155fbb6830SXin LI 	"Unknown"
1165fbb6830SXin LI };
1175fbb6830SXin LI 
1182f345d8eSLuigi Rizzo 
1192f345d8eSLuigi Rizzo /* Driver entry points prototypes */
1202f345d8eSLuigi Rizzo static int  oce_probe(device_t dev);
1212f345d8eSLuigi Rizzo static int  oce_attach(device_t dev);
1222f345d8eSLuigi Rizzo static int  oce_detach(device_t dev);
1232f345d8eSLuigi Rizzo static int  oce_shutdown(device_t dev);
1242f345d8eSLuigi Rizzo static int  oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
1252f345d8eSLuigi Rizzo static void oce_init(void *xsc);
1262f345d8eSLuigi Rizzo static int  oce_multiq_start(struct ifnet *ifp, struct mbuf *m);
1272f345d8eSLuigi Rizzo static void oce_multiq_flush(struct ifnet *ifp);
1282f345d8eSLuigi Rizzo 
1292f345d8eSLuigi Rizzo /* Driver interrupt routines protypes */
1302f345d8eSLuigi Rizzo static void oce_intr(void *arg, int pending);
1312f345d8eSLuigi Rizzo static int  oce_setup_intr(POCE_SOFTC sc);
1322f345d8eSLuigi Rizzo static int  oce_fast_isr(void *arg);
1332f345d8eSLuigi Rizzo static int  oce_alloc_intr(POCE_SOFTC sc, int vector,
1342f345d8eSLuigi Rizzo 			  void (*isr) (void *arg, int pending));
1352f345d8eSLuigi Rizzo 
1362f345d8eSLuigi Rizzo /* Media callbacks prototypes */
1372f345d8eSLuigi Rizzo static void oce_media_status(struct ifnet *ifp, struct ifmediareq *req);
1382f345d8eSLuigi Rizzo static int  oce_media_change(struct ifnet *ifp);
1392f345d8eSLuigi Rizzo 
1402f345d8eSLuigi Rizzo /* Transmit routines prototypes */
1412f345d8eSLuigi Rizzo static int  oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index);
1422f345d8eSLuigi Rizzo static void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq);
1432f345d8eSLuigi Rizzo static void oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx,
1442f345d8eSLuigi Rizzo 					uint32_t status);
1452f345d8eSLuigi Rizzo static int  oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m,
1462f345d8eSLuigi Rizzo 				 struct oce_wq *wq);
1472f345d8eSLuigi Rizzo 
1482f345d8eSLuigi Rizzo /* Receive routines prototypes */
1492f345d8eSLuigi Rizzo static void oce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe);
1502f345d8eSLuigi Rizzo static int  oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
1512f345d8eSLuigi Rizzo static int  oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
1522f345d8eSLuigi Rizzo static void oce_rx(struct oce_rq *rq, uint32_t rqe_idx,
1532f345d8eSLuigi Rizzo 						struct oce_nic_rx_cqe *cqe);
1542f345d8eSLuigi Rizzo 
1552f345d8eSLuigi Rizzo /* Helper function prototypes in this file */
1562f345d8eSLuigi Rizzo static int  oce_attach_ifp(POCE_SOFTC sc);
1572f345d8eSLuigi Rizzo static void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag);
1582f345d8eSLuigi Rizzo static void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag);
1592f345d8eSLuigi Rizzo static int  oce_vid_config(POCE_SOFTC sc);
1602f345d8eSLuigi Rizzo static void oce_mac_addr_set(POCE_SOFTC sc);
1612f345d8eSLuigi Rizzo static int  oce_handle_passthrough(struct ifnet *ifp, caddr_t data);
1622f345d8eSLuigi Rizzo static void oce_local_timer(void *arg);
1632f345d8eSLuigi Rizzo static void oce_if_deactivate(POCE_SOFTC sc);
1642f345d8eSLuigi Rizzo static void oce_if_activate(POCE_SOFTC sc);
1652f345d8eSLuigi Rizzo static void setup_max_queues_want(POCE_SOFTC sc);
1662f345d8eSLuigi Rizzo static void update_queues_got(POCE_SOFTC sc);
1679bd3250aSLuigi Rizzo static void process_link_state(POCE_SOFTC sc,
1689bd3250aSLuigi Rizzo 		 struct oce_async_cqe_link_state *acqe);
169cdaba892SXin LI static int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m);
170291a1934SXin LI static void oce_get_config(POCE_SOFTC sc);
171cdaba892SXin LI static struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete);
1729bd3250aSLuigi Rizzo 
1739bd3250aSLuigi Rizzo /* IP specific */
1749bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
1759bd3250aSLuigi Rizzo static int  oce_init_lro(POCE_SOFTC sc);
1769bd3250aSLuigi Rizzo static void oce_rx_flush_lro(struct oce_rq *rq);
1779bd3250aSLuigi Rizzo static struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp);
1789bd3250aSLuigi Rizzo #endif
1792f345d8eSLuigi Rizzo 
1802f345d8eSLuigi Rizzo static device_method_t oce_dispatch[] = {
1812f345d8eSLuigi Rizzo 	DEVMETHOD(device_probe, oce_probe),
1822f345d8eSLuigi Rizzo 	DEVMETHOD(device_attach, oce_attach),
1832f345d8eSLuigi Rizzo 	DEVMETHOD(device_detach, oce_detach),
1842f345d8eSLuigi Rizzo 	DEVMETHOD(device_shutdown, oce_shutdown),
18561bfd867SSofian Brabez 
18661bfd867SSofian Brabez 	DEVMETHOD_END
1872f345d8eSLuigi Rizzo };
1882f345d8eSLuigi Rizzo 
1892f345d8eSLuigi Rizzo static driver_t oce_driver = {
1902f345d8eSLuigi Rizzo 	"oce",
1912f345d8eSLuigi Rizzo 	oce_dispatch,
1922f345d8eSLuigi Rizzo 	sizeof(OCE_SOFTC)
1932f345d8eSLuigi Rizzo };
1942f345d8eSLuigi Rizzo static devclass_t oce_devclass;
1952f345d8eSLuigi Rizzo 
1962f345d8eSLuigi Rizzo 
1972f345d8eSLuigi Rizzo DRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0);
1982f345d8eSLuigi Rizzo MODULE_DEPEND(oce, pci, 1, 1, 1);
1992f345d8eSLuigi Rizzo MODULE_DEPEND(oce, ether, 1, 1, 1);
2002f345d8eSLuigi Rizzo MODULE_VERSION(oce, 1);
2012f345d8eSLuigi Rizzo 
2022f345d8eSLuigi Rizzo 
2032f345d8eSLuigi Rizzo /* global vars */
2042f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"};
2052f345d8eSLuigi Rizzo 
2062f345d8eSLuigi Rizzo /* Module capabilites and parameters */
2072f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED;
2082f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS;
2092f345d8eSLuigi Rizzo 
2102f345d8eSLuigi Rizzo 
2112f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled);
2122f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss);
2132f345d8eSLuigi Rizzo 
2142f345d8eSLuigi Rizzo 
2152f345d8eSLuigi Rizzo /* Supported devices table */
2162f345d8eSLuigi Rizzo static uint32_t supportedDevices[] =  {
2172f345d8eSLuigi Rizzo 	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2,
2182f345d8eSLuigi Rizzo 	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3,
2192f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3,
2202f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201,
2212f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF,
222291a1934SXin LI 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH
2232f345d8eSLuigi Rizzo };
2242f345d8eSLuigi Rizzo 
2252f345d8eSLuigi Rizzo 
2262f345d8eSLuigi Rizzo 
2272f345d8eSLuigi Rizzo 
2282f345d8eSLuigi Rizzo /*****************************************************************************
2292f345d8eSLuigi Rizzo  *			Driver entry points functions                        *
2302f345d8eSLuigi Rizzo  *****************************************************************************/
2312f345d8eSLuigi Rizzo 
2322f345d8eSLuigi Rizzo static int
2332f345d8eSLuigi Rizzo oce_probe(device_t dev)
2342f345d8eSLuigi Rizzo {
2359bd3250aSLuigi Rizzo 	uint16_t vendor = 0;
2369bd3250aSLuigi Rizzo 	uint16_t device = 0;
2379bd3250aSLuigi Rizzo 	int i = 0;
2389bd3250aSLuigi Rizzo 	char str[256] = {0};
2392f345d8eSLuigi Rizzo 	POCE_SOFTC sc;
2402f345d8eSLuigi Rizzo 
2412f345d8eSLuigi Rizzo 	sc = device_get_softc(dev);
2422f345d8eSLuigi Rizzo 	bzero(sc, sizeof(OCE_SOFTC));
2432f345d8eSLuigi Rizzo 	sc->dev = dev;
2442f345d8eSLuigi Rizzo 
2452f345d8eSLuigi Rizzo 	vendor = pci_get_vendor(dev);
2462f345d8eSLuigi Rizzo 	device = pci_get_device(dev);
2472f345d8eSLuigi Rizzo 
2489bd3250aSLuigi Rizzo 	for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) {
2492f345d8eSLuigi Rizzo 		if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) {
2502f345d8eSLuigi Rizzo 			if (device == (supportedDevices[i] & 0xffff)) {
2519bd3250aSLuigi Rizzo 				sprintf(str, "%s:%s", "Emulex CNA NIC function",
2522f345d8eSLuigi Rizzo 					component_revision);
2532f345d8eSLuigi Rizzo 				device_set_desc_copy(dev, str);
2542f345d8eSLuigi Rizzo 
2552f345d8eSLuigi Rizzo 				switch (device) {
2562f345d8eSLuigi Rizzo 				case PCI_PRODUCT_BE2:
2572f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_BE2;
2582f345d8eSLuigi Rizzo 					break;
2592f345d8eSLuigi Rizzo 				case PCI_PRODUCT_BE3:
2602f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_BE3;
2612f345d8eSLuigi Rizzo 					break;
2622f345d8eSLuigi Rizzo 				case PCI_PRODUCT_XE201:
2632f345d8eSLuigi Rizzo 				case PCI_PRODUCT_XE201_VF:
2642f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_XE201;
2652f345d8eSLuigi Rizzo 					break;
266291a1934SXin LI 				case PCI_PRODUCT_SH:
267291a1934SXin LI 					sc->flags |= OCE_FLAGS_SH;
268291a1934SXin LI 					break;
2692f345d8eSLuigi Rizzo 				default:
2702f345d8eSLuigi Rizzo 					return ENXIO;
2712f345d8eSLuigi Rizzo 				}
2722f345d8eSLuigi Rizzo 				return BUS_PROBE_DEFAULT;
2732f345d8eSLuigi Rizzo 			}
2742f345d8eSLuigi Rizzo 		}
2752f345d8eSLuigi Rizzo 	}
2762f345d8eSLuigi Rizzo 
2772f345d8eSLuigi Rizzo 	return ENXIO;
2782f345d8eSLuigi Rizzo }
2792f345d8eSLuigi Rizzo 
2802f345d8eSLuigi Rizzo 
2812f345d8eSLuigi Rizzo static int
2822f345d8eSLuigi Rizzo oce_attach(device_t dev)
2832f345d8eSLuigi Rizzo {
2842f345d8eSLuigi Rizzo 	POCE_SOFTC sc;
2852f345d8eSLuigi Rizzo 	int rc = 0;
2862f345d8eSLuigi Rizzo 
2872f345d8eSLuigi Rizzo 	sc = device_get_softc(dev);
2882f345d8eSLuigi Rizzo 
2892f345d8eSLuigi Rizzo 	rc = oce_hw_pci_alloc(sc);
2902f345d8eSLuigi Rizzo 	if (rc)
2912f345d8eSLuigi Rizzo 		return rc;
2922f345d8eSLuigi Rizzo 
2932f345d8eSLuigi Rizzo 	sc->tx_ring_size = OCE_TX_RING_SIZE;
2942f345d8eSLuigi Rizzo 	sc->rx_ring_size = OCE_RX_RING_SIZE;
2952f345d8eSLuigi Rizzo 	sc->rq_frag_size = OCE_RQ_BUF_SIZE;
2962f345d8eSLuigi Rizzo 	sc->flow_control = OCE_DEFAULT_FLOW_CONTROL;
2972f345d8eSLuigi Rizzo 	sc->promisc	 = OCE_DEFAULT_PROMISCUOUS;
2982f345d8eSLuigi Rizzo 
2992f345d8eSLuigi Rizzo 	LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock");
3002f345d8eSLuigi Rizzo 	LOCK_CREATE(&sc->dev_lock,  "Device_lock");
3012f345d8eSLuigi Rizzo 
3022f345d8eSLuigi Rizzo 	/* initialise the hardware */
3032f345d8eSLuigi Rizzo 	rc = oce_hw_init(sc);
3042f345d8eSLuigi Rizzo 	if (rc)
3052f345d8eSLuigi Rizzo 		goto pci_res_free;
3062f345d8eSLuigi Rizzo 
307291a1934SXin LI 	oce_get_config(sc);
308291a1934SXin LI 
3092f345d8eSLuigi Rizzo 	setup_max_queues_want(sc);
3102f345d8eSLuigi Rizzo 
3112f345d8eSLuigi Rizzo 	rc = oce_setup_intr(sc);
3122f345d8eSLuigi Rizzo 	if (rc)
3132f345d8eSLuigi Rizzo 		goto mbox_free;
3142f345d8eSLuigi Rizzo 
3152f345d8eSLuigi Rizzo 	rc = oce_queue_init_all(sc);
3162f345d8eSLuigi Rizzo 	if (rc)
3172f345d8eSLuigi Rizzo 		goto intr_free;
3182f345d8eSLuigi Rizzo 
3192f345d8eSLuigi Rizzo 	rc = oce_attach_ifp(sc);
3202f345d8eSLuigi Rizzo 	if (rc)
3212f345d8eSLuigi Rizzo 		goto queues_free;
3222f345d8eSLuigi Rizzo 
323ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3242f345d8eSLuigi Rizzo 	rc = oce_init_lro(sc);
3252f345d8eSLuigi Rizzo 	if (rc)
3262f345d8eSLuigi Rizzo 		goto ifp_free;
327ad512958SBjoern A. Zeeb #endif
3282f345d8eSLuigi Rizzo 
3292f345d8eSLuigi Rizzo 	rc = oce_hw_start(sc);
3302f345d8eSLuigi Rizzo 	if (rc)
331db702c59SEitan Adler 		goto lro_free;
3322f345d8eSLuigi Rizzo 
3332f345d8eSLuigi Rizzo 	sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
3342f345d8eSLuigi Rizzo 				oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST);
3352f345d8eSLuigi Rizzo 	sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
3362f345d8eSLuigi Rizzo 				oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST);
3372f345d8eSLuigi Rizzo 
3382f345d8eSLuigi Rizzo 	rc = oce_stats_init(sc);
3392f345d8eSLuigi Rizzo 	if (rc)
3402f345d8eSLuigi Rizzo 		goto vlan_free;
3412f345d8eSLuigi Rizzo 
3422f345d8eSLuigi Rizzo 	oce_add_sysctls(sc);
3432f345d8eSLuigi Rizzo 
3442f345d8eSLuigi Rizzo 	callout_init(&sc->timer, CALLOUT_MPSAFE);
3452f345d8eSLuigi Rizzo 	rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc);
3462f345d8eSLuigi Rizzo 	if (rc)
3472f345d8eSLuigi Rizzo 		goto stats_free;
3482f345d8eSLuigi Rizzo 
3492f345d8eSLuigi Rizzo 	return 0;
3502f345d8eSLuigi Rizzo 
3512f345d8eSLuigi Rizzo stats_free:
3522f345d8eSLuigi Rizzo 	callout_drain(&sc->timer);
3532f345d8eSLuigi Rizzo 	oce_stats_free(sc);
3542f345d8eSLuigi Rizzo vlan_free:
3552f345d8eSLuigi Rizzo 	if (sc->vlan_attach)
3562f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
3572f345d8eSLuigi Rizzo 	if (sc->vlan_detach)
3582f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
3592f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
3602f345d8eSLuigi Rizzo lro_free:
361ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3622f345d8eSLuigi Rizzo 	oce_free_lro(sc);
3632f345d8eSLuigi Rizzo ifp_free:
364ad512958SBjoern A. Zeeb #endif
3652f345d8eSLuigi Rizzo 	ether_ifdetach(sc->ifp);
3662f345d8eSLuigi Rizzo 	if_free(sc->ifp);
3672f345d8eSLuigi Rizzo queues_free:
3682f345d8eSLuigi Rizzo 	oce_queue_release_all(sc);
3692f345d8eSLuigi Rizzo intr_free:
3702f345d8eSLuigi Rizzo 	oce_intr_free(sc);
3712f345d8eSLuigi Rizzo mbox_free:
3722f345d8eSLuigi Rizzo 	oce_dma_free(sc, &sc->bsmbx);
3732f345d8eSLuigi Rizzo pci_res_free:
3742f345d8eSLuigi Rizzo 	oce_hw_pci_free(sc);
3752f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->dev_lock);
3762f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->bmbx_lock);
3772f345d8eSLuigi Rizzo 	return rc;
3782f345d8eSLuigi Rizzo 
3792f345d8eSLuigi Rizzo }
3802f345d8eSLuigi Rizzo 
3812f345d8eSLuigi Rizzo 
3822f345d8eSLuigi Rizzo static int
3832f345d8eSLuigi Rizzo oce_detach(device_t dev)
3842f345d8eSLuigi Rizzo {
3852f345d8eSLuigi Rizzo 	POCE_SOFTC sc = device_get_softc(dev);
3862f345d8eSLuigi Rizzo 
3872f345d8eSLuigi Rizzo 	LOCK(&sc->dev_lock);
3882f345d8eSLuigi Rizzo 	oce_if_deactivate(sc);
3892f345d8eSLuigi Rizzo 	UNLOCK(&sc->dev_lock);
3902f345d8eSLuigi Rizzo 
3912f345d8eSLuigi Rizzo 	callout_drain(&sc->timer);
3922f345d8eSLuigi Rizzo 
3932f345d8eSLuigi Rizzo 	if (sc->vlan_attach != NULL)
3942f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
3952f345d8eSLuigi Rizzo 	if (sc->vlan_detach != NULL)
3962f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
3972f345d8eSLuigi Rizzo 
3982f345d8eSLuigi Rizzo 	ether_ifdetach(sc->ifp);
3992f345d8eSLuigi Rizzo 
4002f345d8eSLuigi Rizzo 	if_free(sc->ifp);
4012f345d8eSLuigi Rizzo 
4022f345d8eSLuigi Rizzo 	oce_hw_shutdown(sc);
4032f345d8eSLuigi Rizzo 
4042f345d8eSLuigi Rizzo 	bus_generic_detach(dev);
4052f345d8eSLuigi Rizzo 
4062f345d8eSLuigi Rizzo 	return 0;
4072f345d8eSLuigi Rizzo }
4082f345d8eSLuigi Rizzo 
4092f345d8eSLuigi Rizzo 
4102f345d8eSLuigi Rizzo static int
4112f345d8eSLuigi Rizzo oce_shutdown(device_t dev)
4122f345d8eSLuigi Rizzo {
4132f345d8eSLuigi Rizzo 	int rc;
4142f345d8eSLuigi Rizzo 
4152f345d8eSLuigi Rizzo 	rc = oce_detach(dev);
4162f345d8eSLuigi Rizzo 
4172f345d8eSLuigi Rizzo 	return rc;
4182f345d8eSLuigi Rizzo }
4192f345d8eSLuigi Rizzo 
4202f345d8eSLuigi Rizzo 
4212f345d8eSLuigi Rizzo static int
4222f345d8eSLuigi Rizzo oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
4232f345d8eSLuigi Rizzo {
4242f345d8eSLuigi Rizzo 	struct ifreq *ifr = (struct ifreq *)data;
4252f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
4262f345d8eSLuigi Rizzo 	int rc = 0;
4272f345d8eSLuigi Rizzo 	uint32_t u;
4282f345d8eSLuigi Rizzo 
4292f345d8eSLuigi Rizzo 	switch (command) {
4302f345d8eSLuigi Rizzo 
4312f345d8eSLuigi Rizzo 	case SIOCGIFMEDIA:
4322f345d8eSLuigi Rizzo 		rc = ifmedia_ioctl(ifp, ifr, &sc->media, command);
4332f345d8eSLuigi Rizzo 		break;
4342f345d8eSLuigi Rizzo 
4352f345d8eSLuigi Rizzo 	case SIOCSIFMTU:
4362f345d8eSLuigi Rizzo 		if (ifr->ifr_mtu > OCE_MAX_MTU)
4372f345d8eSLuigi Rizzo 			rc = EINVAL;
4382f345d8eSLuigi Rizzo 		else
4392f345d8eSLuigi Rizzo 			ifp->if_mtu = ifr->ifr_mtu;
4402f345d8eSLuigi Rizzo 		break;
4412f345d8eSLuigi Rizzo 
4422f345d8eSLuigi Rizzo 	case SIOCSIFFLAGS:
4432f345d8eSLuigi Rizzo 		if (ifp->if_flags & IFF_UP) {
4442f345d8eSLuigi Rizzo 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
4452f345d8eSLuigi Rizzo 				sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
4462f345d8eSLuigi Rizzo 				oce_init(sc);
4472f345d8eSLuigi Rizzo 			}
4482f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Interface Up\n");
4492f345d8eSLuigi Rizzo 		} else {
4502f345d8eSLuigi Rizzo 			LOCK(&sc->dev_lock);
4512f345d8eSLuigi Rizzo 
4522f345d8eSLuigi Rizzo 			sc->ifp->if_drv_flags &=
4532f345d8eSLuigi Rizzo 			    ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
4542f345d8eSLuigi Rizzo 			oce_if_deactivate(sc);
4552f345d8eSLuigi Rizzo 
4562f345d8eSLuigi Rizzo 			UNLOCK(&sc->dev_lock);
4572f345d8eSLuigi Rizzo 
4582f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Interface Down\n");
4592f345d8eSLuigi Rizzo 		}
4602f345d8eSLuigi Rizzo 
4612f345d8eSLuigi Rizzo 		if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) {
4625fbb6830SXin LI 			if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1))))
4632f345d8eSLuigi Rizzo 				sc->promisc = TRUE;
4642f345d8eSLuigi Rizzo 		} else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) {
4655fbb6830SXin LI 			if (!oce_rxf_set_promiscuous(sc, 0))
4662f345d8eSLuigi Rizzo 				sc->promisc = FALSE;
4672f345d8eSLuigi Rizzo 		}
4682f345d8eSLuigi Rizzo 
4692f345d8eSLuigi Rizzo 		break;
4702f345d8eSLuigi Rizzo 
4712f345d8eSLuigi Rizzo 	case SIOCADDMULTI:
4722f345d8eSLuigi Rizzo 	case SIOCDELMULTI:
4732f345d8eSLuigi Rizzo 		rc = oce_hw_update_multicast(sc);
4742f345d8eSLuigi Rizzo 		if (rc)
4752f345d8eSLuigi Rizzo 			device_printf(sc->dev,
4762f345d8eSLuigi Rizzo 				"Update multicast address failed\n");
4772f345d8eSLuigi Rizzo 		break;
4782f345d8eSLuigi Rizzo 
4792f345d8eSLuigi Rizzo 	case SIOCSIFCAP:
4802f345d8eSLuigi Rizzo 		u = ifr->ifr_reqcap ^ ifp->if_capenable;
4812f345d8eSLuigi Rizzo 
4822f345d8eSLuigi Rizzo 		if (u & IFCAP_TXCSUM) {
4832f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_TXCSUM;
4842f345d8eSLuigi Rizzo 			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
4852f345d8eSLuigi Rizzo 
4862f345d8eSLuigi Rizzo 			if (IFCAP_TSO & ifp->if_capenable &&
4872f345d8eSLuigi Rizzo 			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
4882f345d8eSLuigi Rizzo 				ifp->if_capenable &= ~IFCAP_TSO;
4892f345d8eSLuigi Rizzo 				ifp->if_hwassist &= ~CSUM_TSO;
4902f345d8eSLuigi Rizzo 				if_printf(ifp,
4912f345d8eSLuigi Rizzo 					 "TSO disabled due to -txcsum.\n");
4922f345d8eSLuigi Rizzo 			}
4932f345d8eSLuigi Rizzo 		}
4942f345d8eSLuigi Rizzo 
4952f345d8eSLuigi Rizzo 		if (u & IFCAP_RXCSUM)
4962f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_RXCSUM;
4972f345d8eSLuigi Rizzo 
4982f345d8eSLuigi Rizzo 		if (u & IFCAP_TSO4) {
4992f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_TSO4;
5002f345d8eSLuigi Rizzo 
5012f345d8eSLuigi Rizzo 			if (IFCAP_TSO & ifp->if_capenable) {
5022f345d8eSLuigi Rizzo 				if (IFCAP_TXCSUM & ifp->if_capenable)
5032f345d8eSLuigi Rizzo 					ifp->if_hwassist |= CSUM_TSO;
5042f345d8eSLuigi Rizzo 				else {
5052f345d8eSLuigi Rizzo 					ifp->if_capenable &= ~IFCAP_TSO;
5062f345d8eSLuigi Rizzo 					ifp->if_hwassist &= ~CSUM_TSO;
5072f345d8eSLuigi Rizzo 					if_printf(ifp,
5082f345d8eSLuigi Rizzo 					    "Enable txcsum first.\n");
5092f345d8eSLuigi Rizzo 					rc = EAGAIN;
5102f345d8eSLuigi Rizzo 				}
5112f345d8eSLuigi Rizzo 			} else
5122f345d8eSLuigi Rizzo 				ifp->if_hwassist &= ~CSUM_TSO;
5132f345d8eSLuigi Rizzo 		}
5142f345d8eSLuigi Rizzo 
5152f345d8eSLuigi Rizzo 		if (u & IFCAP_VLAN_HWTAGGING)
5162f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
5172f345d8eSLuigi Rizzo 
5182f345d8eSLuigi Rizzo 		if (u & IFCAP_VLAN_HWFILTER) {
5192f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
5202f345d8eSLuigi Rizzo 			oce_vid_config(sc);
5212f345d8eSLuigi Rizzo 		}
522ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
5232f345d8eSLuigi Rizzo 		if (u & IFCAP_LRO)
5242f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_LRO;
525ad512958SBjoern A. Zeeb #endif
5262f345d8eSLuigi Rizzo 
5272f345d8eSLuigi Rizzo 		break;
5282f345d8eSLuigi Rizzo 
5292f345d8eSLuigi Rizzo 	case SIOCGPRIVATE_0:
5302f345d8eSLuigi Rizzo 		rc = oce_handle_passthrough(ifp, data);
5312f345d8eSLuigi Rizzo 		break;
5322f345d8eSLuigi Rizzo 	default:
5332f345d8eSLuigi Rizzo 		rc = ether_ioctl(ifp, command, data);
5342f345d8eSLuigi Rizzo 		break;
5352f345d8eSLuigi Rizzo 	}
5362f345d8eSLuigi Rizzo 
5372f345d8eSLuigi Rizzo 	return rc;
5382f345d8eSLuigi Rizzo }
5392f345d8eSLuigi Rizzo 
5402f345d8eSLuigi Rizzo 
5412f345d8eSLuigi Rizzo static void
5422f345d8eSLuigi Rizzo oce_init(void *arg)
5432f345d8eSLuigi Rizzo {
5442f345d8eSLuigi Rizzo 	POCE_SOFTC sc = arg;
5452f345d8eSLuigi Rizzo 
5462f345d8eSLuigi Rizzo 	LOCK(&sc->dev_lock);
5472f345d8eSLuigi Rizzo 
5482f345d8eSLuigi Rizzo 	if (sc->ifp->if_flags & IFF_UP) {
5492f345d8eSLuigi Rizzo 		oce_if_deactivate(sc);
5502f345d8eSLuigi Rizzo 		oce_if_activate(sc);
5512f345d8eSLuigi Rizzo 	}
5522f345d8eSLuigi Rizzo 
5532f345d8eSLuigi Rizzo 	UNLOCK(&sc->dev_lock);
5542f345d8eSLuigi Rizzo 
5552f345d8eSLuigi Rizzo }
5562f345d8eSLuigi Rizzo 
5572f345d8eSLuigi Rizzo 
5582f345d8eSLuigi Rizzo static int
5592f345d8eSLuigi Rizzo oce_multiq_start(struct ifnet *ifp, struct mbuf *m)
5602f345d8eSLuigi Rizzo {
5612f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
5622f345d8eSLuigi Rizzo 	struct oce_wq *wq = NULL;
5632f345d8eSLuigi Rizzo 	int queue_index = 0;
5642f345d8eSLuigi Rizzo 	int status = 0;
5652f345d8eSLuigi Rizzo 
5662f345d8eSLuigi Rizzo 	if ((m->m_flags & M_FLOWID) != 0)
5672f345d8eSLuigi Rizzo 		queue_index = m->m_pkthdr.flowid % sc->nwqs;
5682f345d8eSLuigi Rizzo 
5692f345d8eSLuigi Rizzo 	wq = sc->wq[queue_index];
5702f345d8eSLuigi Rizzo 
571291a1934SXin LI 	LOCK(&wq->tx_lock);
5722f345d8eSLuigi Rizzo 	status = oce_multiq_transmit(ifp, m, wq);
5732f345d8eSLuigi Rizzo 	UNLOCK(&wq->tx_lock);
574291a1934SXin LI 
5752f345d8eSLuigi Rizzo 	return status;
5762f345d8eSLuigi Rizzo 
5772f345d8eSLuigi Rizzo }
5782f345d8eSLuigi Rizzo 
5792f345d8eSLuigi Rizzo 
5802f345d8eSLuigi Rizzo static void
5812f345d8eSLuigi Rizzo oce_multiq_flush(struct ifnet *ifp)
5822f345d8eSLuigi Rizzo {
5832f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
5842f345d8eSLuigi Rizzo 	struct mbuf     *m;
5852f345d8eSLuigi Rizzo 	int i = 0;
5862f345d8eSLuigi Rizzo 
5872f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nwqs; i++) {
5882f345d8eSLuigi Rizzo 		while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
5892f345d8eSLuigi Rizzo 			m_freem(m);
5902f345d8eSLuigi Rizzo 	}
5912f345d8eSLuigi Rizzo 	if_qflush(ifp);
5922f345d8eSLuigi Rizzo }
5932f345d8eSLuigi Rizzo 
5942f345d8eSLuigi Rizzo 
5952f345d8eSLuigi Rizzo 
5962f345d8eSLuigi Rizzo /*****************************************************************************
5972f345d8eSLuigi Rizzo  *                   Driver interrupt routines functions                     *
5982f345d8eSLuigi Rizzo  *****************************************************************************/
5992f345d8eSLuigi Rizzo 
6002f345d8eSLuigi Rizzo static void
6012f345d8eSLuigi Rizzo oce_intr(void *arg, int pending)
6022f345d8eSLuigi Rizzo {
6032f345d8eSLuigi Rizzo 
6042f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
6052f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ii->sc;
6062f345d8eSLuigi Rizzo 	struct oce_eq *eq = ii->eq;
6072f345d8eSLuigi Rizzo 	struct oce_eqe *eqe;
6082f345d8eSLuigi Rizzo 	struct oce_cq *cq = NULL;
6092f345d8eSLuigi Rizzo 	int i, num_eqes = 0;
6102f345d8eSLuigi Rizzo 
6112f345d8eSLuigi Rizzo 
6122f345d8eSLuigi Rizzo 	bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
6132f345d8eSLuigi Rizzo 				 BUS_DMASYNC_POSTWRITE);
6142f345d8eSLuigi Rizzo 	do {
6152f345d8eSLuigi Rizzo 		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
6162f345d8eSLuigi Rizzo 		if (eqe->evnt == 0)
6172f345d8eSLuigi Rizzo 			break;
6182f345d8eSLuigi Rizzo 		eqe->evnt = 0;
6192f345d8eSLuigi Rizzo 		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
6202f345d8eSLuigi Rizzo 					BUS_DMASYNC_POSTWRITE);
6212f345d8eSLuigi Rizzo 		RING_GET(eq->ring, 1);
6222f345d8eSLuigi Rizzo 		num_eqes++;
6232f345d8eSLuigi Rizzo 
6242f345d8eSLuigi Rizzo 	} while (TRUE);
6252f345d8eSLuigi Rizzo 
6262f345d8eSLuigi Rizzo 	if (!num_eqes)
6272f345d8eSLuigi Rizzo 		goto eq_arm; /* Spurious */
6282f345d8eSLuigi Rizzo 
6292f345d8eSLuigi Rizzo  	/* Clear EQ entries, but dont arm */
6302f345d8eSLuigi Rizzo 	oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
6312f345d8eSLuigi Rizzo 
6322f345d8eSLuigi Rizzo 	/* Process TX, RX and MCC. But dont arm CQ*/
6332f345d8eSLuigi Rizzo 	for (i = 0; i < eq->cq_valid; i++) {
6342f345d8eSLuigi Rizzo 		cq = eq->cq[i];
6352f345d8eSLuigi Rizzo 		(*cq->cq_handler)(cq->cb_arg);
6362f345d8eSLuigi Rizzo 	}
6372f345d8eSLuigi Rizzo 
6382f345d8eSLuigi Rizzo 	/* Arm all cqs connected to this EQ */
6392f345d8eSLuigi Rizzo 	for (i = 0; i < eq->cq_valid; i++) {
6402f345d8eSLuigi Rizzo 		cq = eq->cq[i];
6412f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, 0, TRUE);
6422f345d8eSLuigi Rizzo 	}
6432f345d8eSLuigi Rizzo 
6442f345d8eSLuigi Rizzo eq_arm:
6452f345d8eSLuigi Rizzo 	oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
646cdaba892SXin LI 
6472f345d8eSLuigi Rizzo 	return;
6482f345d8eSLuigi Rizzo }
6492f345d8eSLuigi Rizzo 
6502f345d8eSLuigi Rizzo 
6512f345d8eSLuigi Rizzo static int
6522f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc)
6532f345d8eSLuigi Rizzo {
6542f345d8eSLuigi Rizzo 	int rc = 0, use_intx = 0;
6552f345d8eSLuigi Rizzo 	int vector = 0, req_vectors = 0;
6562f345d8eSLuigi Rizzo 
657291a1934SXin LI 	if (is_rss_enabled(sc))
6582f345d8eSLuigi Rizzo 		req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
6592f345d8eSLuigi Rizzo 	else
6602f345d8eSLuigi Rizzo 		req_vectors = 1;
6612f345d8eSLuigi Rizzo 
6622f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
6632f345d8eSLuigi Rizzo 		sc->intr_count = req_vectors;
6642f345d8eSLuigi Rizzo 		rc = pci_alloc_msix(sc->dev, &sc->intr_count);
6652f345d8eSLuigi Rizzo 		if (rc != 0) {
6662f345d8eSLuigi Rizzo 			use_intx = 1;
6672f345d8eSLuigi Rizzo 			pci_release_msi(sc->dev);
6682f345d8eSLuigi Rizzo 		} else
6692f345d8eSLuigi Rizzo 			sc->flags |= OCE_FLAGS_USING_MSIX;
6702f345d8eSLuigi Rizzo 	} else
6712f345d8eSLuigi Rizzo 		use_intx = 1;
6722f345d8eSLuigi Rizzo 
6732f345d8eSLuigi Rizzo 	if (use_intx)
6742f345d8eSLuigi Rizzo 		sc->intr_count = 1;
6752f345d8eSLuigi Rizzo 
6762f345d8eSLuigi Rizzo 	/* Scale number of queues based on intr we got */
6772f345d8eSLuigi Rizzo 	update_queues_got(sc);
6782f345d8eSLuigi Rizzo 
6792f345d8eSLuigi Rizzo 	if (use_intx) {
6802f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Using legacy interrupt\n");
6812f345d8eSLuigi Rizzo 		rc = oce_alloc_intr(sc, vector, oce_intr);
6822f345d8eSLuigi Rizzo 		if (rc)
6832f345d8eSLuigi Rizzo 			goto error;
6842f345d8eSLuigi Rizzo 	} else {
6852f345d8eSLuigi Rizzo 		for (; vector < sc->intr_count; vector++) {
6862f345d8eSLuigi Rizzo 			rc = oce_alloc_intr(sc, vector, oce_intr);
6872f345d8eSLuigi Rizzo 			if (rc)
6882f345d8eSLuigi Rizzo 				goto error;
6892f345d8eSLuigi Rizzo 		}
6902f345d8eSLuigi Rizzo 	}
6912f345d8eSLuigi Rizzo 
6922f345d8eSLuigi Rizzo 	return 0;
6932f345d8eSLuigi Rizzo error:
6942f345d8eSLuigi Rizzo 	oce_intr_free(sc);
6952f345d8eSLuigi Rizzo 	return rc;
6962f345d8eSLuigi Rizzo }
6972f345d8eSLuigi Rizzo 
6982f345d8eSLuigi Rizzo 
6992f345d8eSLuigi Rizzo static int
7002f345d8eSLuigi Rizzo oce_fast_isr(void *arg)
7012f345d8eSLuigi Rizzo {
7022f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
7032f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ii->sc;
7042f345d8eSLuigi Rizzo 
7052f345d8eSLuigi Rizzo 	if (ii->eq == NULL)
7062f345d8eSLuigi Rizzo 		return FILTER_STRAY;
7072f345d8eSLuigi Rizzo 
7082f345d8eSLuigi Rizzo 	oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
7092f345d8eSLuigi Rizzo 
7102f345d8eSLuigi Rizzo 	taskqueue_enqueue_fast(ii->tq, &ii->task);
7112f345d8eSLuigi Rizzo 
712cdaba892SXin LI  	ii->eq->intr++;
713cdaba892SXin LI 
7142f345d8eSLuigi Rizzo 	return FILTER_HANDLED;
7152f345d8eSLuigi Rizzo }
7162f345d8eSLuigi Rizzo 
7172f345d8eSLuigi Rizzo 
7182f345d8eSLuigi Rizzo static int
7192f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
7202f345d8eSLuigi Rizzo {
7212f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = &sc->intrs[vector];
7222f345d8eSLuigi Rizzo 	int rc = 0, rr;
7232f345d8eSLuigi Rizzo 
7242f345d8eSLuigi Rizzo 	if (vector >= OCE_MAX_EQ)
7252f345d8eSLuigi Rizzo 		return (EINVAL);
7262f345d8eSLuigi Rizzo 
7272f345d8eSLuigi Rizzo 	/* Set the resource id for the interrupt.
7282f345d8eSLuigi Rizzo 	 * MSIx is vector + 1 for the resource id,
7292f345d8eSLuigi Rizzo 	 * INTx is 0 for the resource id.
7302f345d8eSLuigi Rizzo 	 */
7312f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_USING_MSIX)
7322f345d8eSLuigi Rizzo 		rr = vector + 1;
7332f345d8eSLuigi Rizzo 	else
7342f345d8eSLuigi Rizzo 		rr = 0;
7352f345d8eSLuigi Rizzo 	ii->intr_res = bus_alloc_resource_any(sc->dev,
7362f345d8eSLuigi Rizzo 					      SYS_RES_IRQ,
7372f345d8eSLuigi Rizzo 					      &rr, RF_ACTIVE|RF_SHAREABLE);
7382f345d8eSLuigi Rizzo 	ii->irq_rr = rr;
7392f345d8eSLuigi Rizzo 	if (ii->intr_res == NULL) {
7402f345d8eSLuigi Rizzo 		device_printf(sc->dev,
7412f345d8eSLuigi Rizzo 			  "Could not allocate interrupt\n");
7422f345d8eSLuigi Rizzo 		rc = ENXIO;
7432f345d8eSLuigi Rizzo 		return rc;
7442f345d8eSLuigi Rizzo 	}
7452f345d8eSLuigi Rizzo 
7462f345d8eSLuigi Rizzo 	TASK_INIT(&ii->task, 0, isr, ii);
7472f345d8eSLuigi Rizzo 	ii->vector = vector;
7482f345d8eSLuigi Rizzo 	sprintf(ii->task_name, "oce_task[%d]", ii->vector);
7492f345d8eSLuigi Rizzo 	ii->tq = taskqueue_create_fast(ii->task_name,
7502f345d8eSLuigi Rizzo 			M_NOWAIT,
7512f345d8eSLuigi Rizzo 			taskqueue_thread_enqueue,
7522f345d8eSLuigi Rizzo 			&ii->tq);
7532f345d8eSLuigi Rizzo 	taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
7542f345d8eSLuigi Rizzo 			device_get_nameunit(sc->dev));
7552f345d8eSLuigi Rizzo 
7562f345d8eSLuigi Rizzo 	ii->sc = sc;
7572f345d8eSLuigi Rizzo 	rc = bus_setup_intr(sc->dev,
7582f345d8eSLuigi Rizzo 			ii->intr_res,
7592f345d8eSLuigi Rizzo 			INTR_TYPE_NET,
7602f345d8eSLuigi Rizzo 			oce_fast_isr, NULL, ii, &ii->tag);
7612f345d8eSLuigi Rizzo 	return rc;
7622f345d8eSLuigi Rizzo 
7632f345d8eSLuigi Rizzo }
7642f345d8eSLuigi Rizzo 
7652f345d8eSLuigi Rizzo 
7662f345d8eSLuigi Rizzo void
7672f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc)
7682f345d8eSLuigi Rizzo {
7692f345d8eSLuigi Rizzo 	int i = 0;
7702f345d8eSLuigi Rizzo 
7712f345d8eSLuigi Rizzo 	for (i = 0; i < sc->intr_count; i++) {
7722f345d8eSLuigi Rizzo 
7732f345d8eSLuigi Rizzo 		if (sc->intrs[i].tag != NULL)
7742f345d8eSLuigi Rizzo 			bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
7752f345d8eSLuigi Rizzo 						sc->intrs[i].tag);
7762f345d8eSLuigi Rizzo 		if (sc->intrs[i].tq != NULL)
7772f345d8eSLuigi Rizzo 			taskqueue_free(sc->intrs[i].tq);
7782f345d8eSLuigi Rizzo 
7792f345d8eSLuigi Rizzo 		if (sc->intrs[i].intr_res != NULL)
7802f345d8eSLuigi Rizzo 			bus_release_resource(sc->dev, SYS_RES_IRQ,
7812f345d8eSLuigi Rizzo 						sc->intrs[i].irq_rr,
7822f345d8eSLuigi Rizzo 						sc->intrs[i].intr_res);
7832f345d8eSLuigi Rizzo 		sc->intrs[i].tag = NULL;
7842f345d8eSLuigi Rizzo 		sc->intrs[i].intr_res = NULL;
7852f345d8eSLuigi Rizzo 	}
7862f345d8eSLuigi Rizzo 
7872f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_USING_MSIX)
7882f345d8eSLuigi Rizzo 		pci_release_msi(sc->dev);
7892f345d8eSLuigi Rizzo 
7902f345d8eSLuigi Rizzo }
7912f345d8eSLuigi Rizzo 
7922f345d8eSLuigi Rizzo 
7932f345d8eSLuigi Rizzo 
7942f345d8eSLuigi Rizzo /******************************************************************************
7952f345d8eSLuigi Rizzo *			  Media callbacks functions 			      *
7962f345d8eSLuigi Rizzo ******************************************************************************/
7972f345d8eSLuigi Rizzo 
7982f345d8eSLuigi Rizzo static void
7992f345d8eSLuigi Rizzo oce_media_status(struct ifnet *ifp, struct ifmediareq *req)
8002f345d8eSLuigi Rizzo {
8012f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc;
8022f345d8eSLuigi Rizzo 
8032f345d8eSLuigi Rizzo 
8042f345d8eSLuigi Rizzo 	req->ifm_status = IFM_AVALID;
8052f345d8eSLuigi Rizzo 	req->ifm_active = IFM_ETHER;
8062f345d8eSLuigi Rizzo 
8072f345d8eSLuigi Rizzo 	if (sc->link_status == 1)
8082f345d8eSLuigi Rizzo 		req->ifm_status |= IFM_ACTIVE;
8092f345d8eSLuigi Rizzo 	else
8102f345d8eSLuigi Rizzo 		return;
8112f345d8eSLuigi Rizzo 
8122f345d8eSLuigi Rizzo 	switch (sc->link_speed) {
8132f345d8eSLuigi Rizzo 	case 1: /* 10 Mbps */
8142f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_10_T | IFM_FDX;
8152f345d8eSLuigi Rizzo 		sc->speed = 10;
8162f345d8eSLuigi Rizzo 		break;
8172f345d8eSLuigi Rizzo 	case 2: /* 100 Mbps */
8182f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_100_TX | IFM_FDX;
8192f345d8eSLuigi Rizzo 		sc->speed = 100;
8202f345d8eSLuigi Rizzo 		break;
8212f345d8eSLuigi Rizzo 	case 3: /* 1 Gbps */
8222f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_1000_T | IFM_FDX;
8232f345d8eSLuigi Rizzo 		sc->speed = 1000;
8242f345d8eSLuigi Rizzo 		break;
8252f345d8eSLuigi Rizzo 	case 4: /* 10 Gbps */
8262f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
8272f345d8eSLuigi Rizzo 		sc->speed = 10000;
8282f345d8eSLuigi Rizzo 		break;
829a4f734b4SXin LI 	case 5: /* 20 Gbps */
830a4f734b4SXin LI 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
831a4f734b4SXin LI 		sc->speed = 20000;
832a4f734b4SXin LI 		break;
833a4f734b4SXin LI 	case 6: /* 25 Gbps */
834a4f734b4SXin LI 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
835a4f734b4SXin LI 		sc->speed = 25000;
836a4f734b4SXin LI 		break;
837b41206d8SXin LI 	case 7: /* 40 Gbps */
838b41206d8SXin LI 		req->ifm_active |= IFM_40G_SR4 | IFM_FDX;
839b41206d8SXin LI 		sc->speed = 40000;
840b41206d8SXin LI 		break;
841a4f734b4SXin LI 	default:
842a4f734b4SXin LI 		sc->speed = 0;
843a4f734b4SXin LI 		break;
8442f345d8eSLuigi Rizzo 	}
8452f345d8eSLuigi Rizzo 
8462f345d8eSLuigi Rizzo 	return;
8472f345d8eSLuigi Rizzo }
8482f345d8eSLuigi Rizzo 
8492f345d8eSLuigi Rizzo 
8502f345d8eSLuigi Rizzo int
8512f345d8eSLuigi Rizzo oce_media_change(struct ifnet *ifp)
8522f345d8eSLuigi Rizzo {
8532f345d8eSLuigi Rizzo 	return 0;
8542f345d8eSLuigi Rizzo }
8552f345d8eSLuigi Rizzo 
8562f345d8eSLuigi Rizzo 
8572f345d8eSLuigi Rizzo 
8582f345d8eSLuigi Rizzo 
8592f345d8eSLuigi Rizzo /*****************************************************************************
8602f345d8eSLuigi Rizzo  *			  Transmit routines functions			     *
8612f345d8eSLuigi Rizzo  *****************************************************************************/
8622f345d8eSLuigi Rizzo 
8632f345d8eSLuigi Rizzo static int
8642f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
8652f345d8eSLuigi Rizzo {
8662f345d8eSLuigi Rizzo 	int rc = 0, i, retry_cnt = 0;
8672f345d8eSLuigi Rizzo 	bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
8682f345d8eSLuigi Rizzo 	struct mbuf *m, *m_temp;
8692f345d8eSLuigi Rizzo 	struct oce_wq *wq = sc->wq[wq_index];
8702f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
8712f345d8eSLuigi Rizzo 	struct oce_nic_hdr_wqe *nichdr;
8722f345d8eSLuigi Rizzo 	struct oce_nic_frag_wqe *nicfrag;
8732f345d8eSLuigi Rizzo 	int num_wqes;
8742f345d8eSLuigi Rizzo 	uint32_t reg_value;
875cdaba892SXin LI 	boolean_t complete = TRUE;
8762f345d8eSLuigi Rizzo 
8772f345d8eSLuigi Rizzo 	m = *mpp;
8782f345d8eSLuigi Rizzo 	if (!m)
8792f345d8eSLuigi Rizzo 		return EINVAL;
8802f345d8eSLuigi Rizzo 
8812f345d8eSLuigi Rizzo 	if (!(m->m_flags & M_PKTHDR)) {
8822f345d8eSLuigi Rizzo 		rc = ENXIO;
8832f345d8eSLuigi Rizzo 		goto free_ret;
8842f345d8eSLuigi Rizzo 	}
8852f345d8eSLuigi Rizzo 
886cdaba892SXin LI 	if(oce_tx_asic_stall_verify(sc, m)) {
887cdaba892SXin LI 		m = oce_insert_vlan_tag(sc, m, &complete);
888cdaba892SXin LI 		if(!m) {
889cdaba892SXin LI 			device_printf(sc->dev, "Insertion unsuccessful\n");
890cdaba892SXin LI 			return 0;
891cdaba892SXin LI 		}
892cdaba892SXin LI 
893cdaba892SXin LI 	}
894cdaba892SXin LI 
8952f345d8eSLuigi Rizzo 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
8962f345d8eSLuigi Rizzo 		/* consolidate packet buffers for TSO/LSO segment offload */
8979bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
8989bd3250aSLuigi Rizzo 		m = oce_tso_setup(sc, mpp);
899ad512958SBjoern A. Zeeb #else
900ad512958SBjoern A. Zeeb 		m = NULL;
901ad512958SBjoern A. Zeeb #endif
9022f345d8eSLuigi Rizzo 		if (m == NULL) {
9032f345d8eSLuigi Rizzo 			rc = ENXIO;
9042f345d8eSLuigi Rizzo 			goto free_ret;
9052f345d8eSLuigi Rizzo 		}
9062f345d8eSLuigi Rizzo 	}
9072f345d8eSLuigi Rizzo 
908291a1934SXin LI 	pd = &wq->pckts[wq->pkt_desc_head];
9092f345d8eSLuigi Rizzo retry:
9102f345d8eSLuigi Rizzo 	rc = bus_dmamap_load_mbuf_sg(wq->tag,
9112f345d8eSLuigi Rizzo 				     pd->map,
9122f345d8eSLuigi Rizzo 				     m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
9132f345d8eSLuigi Rizzo 	if (rc == 0) {
9142f345d8eSLuigi Rizzo 		num_wqes = pd->nsegs + 1;
915291a1934SXin LI 		if (IS_BE(sc) || IS_SH(sc)) {
9162f345d8eSLuigi Rizzo 			/*Dummy required only for BE3.*/
9172f345d8eSLuigi Rizzo 			if (num_wqes & 1)
9182f345d8eSLuigi Rizzo 				num_wqes++;
9192f345d8eSLuigi Rizzo 		}
9202f345d8eSLuigi Rizzo 		if (num_wqes >= RING_NUM_FREE(wq->ring)) {
9212f345d8eSLuigi Rizzo 			bus_dmamap_unload(wq->tag, pd->map);
9222f345d8eSLuigi Rizzo 			return EBUSY;
9232f345d8eSLuigi Rizzo 		}
924291a1934SXin LI 		atomic_store_rel_int(&wq->pkt_desc_head,
925291a1934SXin LI 				     (wq->pkt_desc_head + 1) % \
926291a1934SXin LI 				      OCE_WQ_PACKET_ARRAY_SIZE);
9272f345d8eSLuigi Rizzo 		bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
9282f345d8eSLuigi Rizzo 		pd->mbuf = m;
9292f345d8eSLuigi Rizzo 
9302f345d8eSLuigi Rizzo 		nichdr =
9312f345d8eSLuigi Rizzo 		    RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
9322f345d8eSLuigi Rizzo 		nichdr->u0.dw[0] = 0;
9332f345d8eSLuigi Rizzo 		nichdr->u0.dw[1] = 0;
9342f345d8eSLuigi Rizzo 		nichdr->u0.dw[2] = 0;
9352f345d8eSLuigi Rizzo 		nichdr->u0.dw[3] = 0;
9362f345d8eSLuigi Rizzo 
937cdaba892SXin LI 		nichdr->u0.s.complete = complete;
9382f345d8eSLuigi Rizzo 		nichdr->u0.s.event = 1;
9392f345d8eSLuigi Rizzo 		nichdr->u0.s.crc = 1;
9402f345d8eSLuigi Rizzo 		nichdr->u0.s.forward = 0;
9412f345d8eSLuigi Rizzo 		nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
9422f345d8eSLuigi Rizzo 		nichdr->u0.s.udpcs =
9432f345d8eSLuigi Rizzo 			(m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
9442f345d8eSLuigi Rizzo 		nichdr->u0.s.tcpcs =
9452f345d8eSLuigi Rizzo 			(m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
9462f345d8eSLuigi Rizzo 		nichdr->u0.s.num_wqe = num_wqes;
9472f345d8eSLuigi Rizzo 		nichdr->u0.s.total_length = m->m_pkthdr.len;
9485fbb6830SXin LI 
9492f345d8eSLuigi Rizzo 		if (m->m_flags & M_VLANTAG) {
9502f345d8eSLuigi Rizzo 			nichdr->u0.s.vlan = 1; /*Vlan present*/
9512f345d8eSLuigi Rizzo 			nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
9522f345d8eSLuigi Rizzo 		}
9535fbb6830SXin LI 
9542f345d8eSLuigi Rizzo 		if (m->m_pkthdr.csum_flags & CSUM_TSO) {
9552f345d8eSLuigi Rizzo 			if (m->m_pkthdr.tso_segsz) {
9562f345d8eSLuigi Rizzo 				nichdr->u0.s.lso = 1;
9572f345d8eSLuigi Rizzo 				nichdr->u0.s.lso_mss  = m->m_pkthdr.tso_segsz;
9582f345d8eSLuigi Rizzo 			}
959291a1934SXin LI 			if (!IS_BE(sc) || !IS_SH(sc))
9602f345d8eSLuigi Rizzo 				nichdr->u0.s.ipcs = 1;
9612f345d8eSLuigi Rizzo 		}
9622f345d8eSLuigi Rizzo 
9632f345d8eSLuigi Rizzo 		RING_PUT(wq->ring, 1);
964291a1934SXin LI 		atomic_add_int(&wq->ring->num_used, 1);
9652f345d8eSLuigi Rizzo 
9662f345d8eSLuigi Rizzo 		for (i = 0; i < pd->nsegs; i++) {
9672f345d8eSLuigi Rizzo 			nicfrag =
9682f345d8eSLuigi Rizzo 			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
9692f345d8eSLuigi Rizzo 						      struct oce_nic_frag_wqe);
9702f345d8eSLuigi Rizzo 			nicfrag->u0.s.rsvd0 = 0;
9712f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
9722f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
9732f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_len = segs[i].ds_len;
9742f345d8eSLuigi Rizzo 			pd->wqe_idx = wq->ring->pidx;
9752f345d8eSLuigi Rizzo 			RING_PUT(wq->ring, 1);
976291a1934SXin LI 			atomic_add_int(&wq->ring->num_used, 1);
9772f345d8eSLuigi Rizzo 		}
9782f345d8eSLuigi Rizzo 		if (num_wqes > (pd->nsegs + 1)) {
9792f345d8eSLuigi Rizzo 			nicfrag =
9802f345d8eSLuigi Rizzo 			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
9812f345d8eSLuigi Rizzo 						      struct oce_nic_frag_wqe);
9822f345d8eSLuigi Rizzo 			nicfrag->u0.dw[0] = 0;
9832f345d8eSLuigi Rizzo 			nicfrag->u0.dw[1] = 0;
9842f345d8eSLuigi Rizzo 			nicfrag->u0.dw[2] = 0;
9852f345d8eSLuigi Rizzo 			nicfrag->u0.dw[3] = 0;
9862f345d8eSLuigi Rizzo 			pd->wqe_idx = wq->ring->pidx;
9872f345d8eSLuigi Rizzo 			RING_PUT(wq->ring, 1);
988291a1934SXin LI 			atomic_add_int(&wq->ring->num_used, 1);
9892f345d8eSLuigi Rizzo 			pd->nsegs++;
9902f345d8eSLuigi Rizzo 		}
9912f345d8eSLuigi Rizzo 
992*c8dfaf38SGleb Smirnoff 		if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
9932f345d8eSLuigi Rizzo 		wq->tx_stats.tx_reqs++;
9942f345d8eSLuigi Rizzo 		wq->tx_stats.tx_wrbs += num_wqes;
9952f345d8eSLuigi Rizzo 		wq->tx_stats.tx_bytes += m->m_pkthdr.len;
9962f345d8eSLuigi Rizzo 		wq->tx_stats.tx_pkts++;
9972f345d8eSLuigi Rizzo 
9982f345d8eSLuigi Rizzo 		bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
9992f345d8eSLuigi Rizzo 				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
10002f345d8eSLuigi Rizzo 		reg_value = (num_wqes << 16) | wq->wq_id;
1001291a1934SXin LI 		OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value);
10022f345d8eSLuigi Rizzo 
10032f345d8eSLuigi Rizzo 	} else if (rc == EFBIG)	{
10042f345d8eSLuigi Rizzo 		if (retry_cnt == 0) {
1005c6499eccSGleb Smirnoff 			m_temp = m_defrag(m, M_NOWAIT);
10062f345d8eSLuigi Rizzo 			if (m_temp == NULL)
10072f345d8eSLuigi Rizzo 				goto free_ret;
10082f345d8eSLuigi Rizzo 			m = m_temp;
10092f345d8eSLuigi Rizzo 			*mpp = m_temp;
10102f345d8eSLuigi Rizzo 			retry_cnt = retry_cnt + 1;
10112f345d8eSLuigi Rizzo 			goto retry;
10122f345d8eSLuigi Rizzo 		} else
10132f345d8eSLuigi Rizzo 			goto free_ret;
10142f345d8eSLuigi Rizzo 	} else if (rc == ENOMEM)
10152f345d8eSLuigi Rizzo 		return rc;
10162f345d8eSLuigi Rizzo 	else
10172f345d8eSLuigi Rizzo 		goto free_ret;
10182f345d8eSLuigi Rizzo 
10192f345d8eSLuigi Rizzo 	return 0;
10202f345d8eSLuigi Rizzo 
10212f345d8eSLuigi Rizzo free_ret:
10222f345d8eSLuigi Rizzo 	m_freem(*mpp);
10232f345d8eSLuigi Rizzo 	*mpp = NULL;
10242f345d8eSLuigi Rizzo 	return rc;
10252f345d8eSLuigi Rizzo }
10262f345d8eSLuigi Rizzo 
10272f345d8eSLuigi Rizzo 
10282f345d8eSLuigi Rizzo static void
10292f345d8eSLuigi Rizzo oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status)
10302f345d8eSLuigi Rizzo {
10312f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
10322f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
10332f345d8eSLuigi Rizzo 	struct mbuf *m;
10342f345d8eSLuigi Rizzo 
1035291a1934SXin LI 	pd = &wq->pckts[wq->pkt_desc_tail];
1036291a1934SXin LI 	atomic_store_rel_int(&wq->pkt_desc_tail,
1037291a1934SXin LI 			     (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE);
1038291a1934SXin LI 	atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1);
10392f345d8eSLuigi Rizzo 	bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
10402f345d8eSLuigi Rizzo 	bus_dmamap_unload(wq->tag, pd->map);
10412f345d8eSLuigi Rizzo 
10422f345d8eSLuigi Rizzo 	m = pd->mbuf;
10432f345d8eSLuigi Rizzo 	m_freem(m);
10442f345d8eSLuigi Rizzo 	pd->mbuf = NULL;
10452f345d8eSLuigi Rizzo 
1046291a1934SXin LI 
10472f345d8eSLuigi Rizzo 	if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) {
10482f345d8eSLuigi Rizzo 		if (wq->ring->num_used < (wq->ring->num_items / 2)) {
10492f345d8eSLuigi Rizzo 			sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
10502f345d8eSLuigi Rizzo 			oce_tx_restart(sc, wq);
10512f345d8eSLuigi Rizzo 		}
10522f345d8eSLuigi Rizzo 	}
10532f345d8eSLuigi Rizzo }
10542f345d8eSLuigi Rizzo 
10552f345d8eSLuigi Rizzo 
10562f345d8eSLuigi Rizzo static void
10572f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
10582f345d8eSLuigi Rizzo {
10592f345d8eSLuigi Rizzo 
10602f345d8eSLuigi Rizzo 	if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
10612f345d8eSLuigi Rizzo 		return;
10622f345d8eSLuigi Rizzo 
10632f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000
10642f345d8eSLuigi Rizzo 	if (!drbr_empty(sc->ifp, wq->br))
10652f345d8eSLuigi Rizzo #else
10662f345d8eSLuigi Rizzo 	if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd))
10672f345d8eSLuigi Rizzo #endif
10682f345d8eSLuigi Rizzo 		taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask);
10692f345d8eSLuigi Rizzo 
10702f345d8eSLuigi Rizzo }
10712f345d8eSLuigi Rizzo 
10729bd3250aSLuigi Rizzo 
1073ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
10742f345d8eSLuigi Rizzo static struct mbuf *
10759bd3250aSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
10762f345d8eSLuigi Rizzo {
10772f345d8eSLuigi Rizzo 	struct mbuf *m;
1078ad512958SBjoern A. Zeeb #ifdef INET
10792f345d8eSLuigi Rizzo 	struct ip *ip;
1080ad512958SBjoern A. Zeeb #endif
1081ad512958SBjoern A. Zeeb #ifdef INET6
10822f345d8eSLuigi Rizzo 	struct ip6_hdr *ip6;
1083ad512958SBjoern A. Zeeb #endif
10842f345d8eSLuigi Rizzo 	struct ether_vlan_header *eh;
10852f345d8eSLuigi Rizzo 	struct tcphdr *th;
10862f345d8eSLuigi Rizzo 	uint16_t etype;
10879bd3250aSLuigi Rizzo 	int total_len = 0, ehdrlen = 0;
10882f345d8eSLuigi Rizzo 
10892f345d8eSLuigi Rizzo 	m = *mpp;
10902f345d8eSLuigi Rizzo 
10912f345d8eSLuigi Rizzo 	if (M_WRITABLE(m) == 0) {
1092c6499eccSGleb Smirnoff 		m = m_dup(*mpp, M_NOWAIT);
10932f345d8eSLuigi Rizzo 		if (!m)
10942f345d8eSLuigi Rizzo 			return NULL;
10952f345d8eSLuigi Rizzo 		m_freem(*mpp);
10962f345d8eSLuigi Rizzo 		*mpp = m;
10972f345d8eSLuigi Rizzo 	}
10982f345d8eSLuigi Rizzo 
10992f345d8eSLuigi Rizzo 	eh = mtod(m, struct ether_vlan_header *);
11002f345d8eSLuigi Rizzo 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
11012f345d8eSLuigi Rizzo 		etype = ntohs(eh->evl_proto);
11022f345d8eSLuigi Rizzo 		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
11032f345d8eSLuigi Rizzo 	} else {
11042f345d8eSLuigi Rizzo 		etype = ntohs(eh->evl_encap_proto);
11052f345d8eSLuigi Rizzo 		ehdrlen = ETHER_HDR_LEN;
11062f345d8eSLuigi Rizzo 	}
11072f345d8eSLuigi Rizzo 
11082f345d8eSLuigi Rizzo 	switch (etype) {
1109ad512958SBjoern A. Zeeb #ifdef INET
11102f345d8eSLuigi Rizzo 	case ETHERTYPE_IP:
11112f345d8eSLuigi Rizzo 		ip = (struct ip *)(m->m_data + ehdrlen);
11122f345d8eSLuigi Rizzo 		if (ip->ip_p != IPPROTO_TCP)
11132f345d8eSLuigi Rizzo 			return NULL;
11142f345d8eSLuigi Rizzo 		th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
11152f345d8eSLuigi Rizzo 
11162f345d8eSLuigi Rizzo 		total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
11172f345d8eSLuigi Rizzo 		break;
1118ad512958SBjoern A. Zeeb #endif
1119ad512958SBjoern A. Zeeb #ifdef INET6
11202f345d8eSLuigi Rizzo 	case ETHERTYPE_IPV6:
11212f345d8eSLuigi Rizzo 		ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
11222f345d8eSLuigi Rizzo 		if (ip6->ip6_nxt != IPPROTO_TCP)
11232f345d8eSLuigi Rizzo 			return NULL;
11242f345d8eSLuigi Rizzo 		th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
11252f345d8eSLuigi Rizzo 
11262f345d8eSLuigi Rizzo 		total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
11272f345d8eSLuigi Rizzo 		break;
1128ad512958SBjoern A. Zeeb #endif
11292f345d8eSLuigi Rizzo 	default:
11302f345d8eSLuigi Rizzo 		return NULL;
11312f345d8eSLuigi Rizzo 	}
11322f345d8eSLuigi Rizzo 
11332f345d8eSLuigi Rizzo 	m = m_pullup(m, total_len);
11342f345d8eSLuigi Rizzo 	if (!m)
11352f345d8eSLuigi Rizzo 		return NULL;
11362f345d8eSLuigi Rizzo 	*mpp = m;
11372f345d8eSLuigi Rizzo 	return m;
11382f345d8eSLuigi Rizzo 
11392f345d8eSLuigi Rizzo }
1140ad512958SBjoern A. Zeeb #endif /* INET6 || INET */
11412f345d8eSLuigi Rizzo 
11422f345d8eSLuigi Rizzo void
11432f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending)
11442f345d8eSLuigi Rizzo {
11452f345d8eSLuigi Rizzo 	struct oce_wq *wq = arg;
11462f345d8eSLuigi Rizzo 	POCE_SOFTC sc = wq->parent;
11472f345d8eSLuigi Rizzo 	struct ifnet *ifp = sc->ifp;
11482f345d8eSLuigi Rizzo 	int rc = 0;
11492f345d8eSLuigi Rizzo 
11502f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000
1151291a1934SXin LI 	LOCK(&wq->tx_lock);
11522f345d8eSLuigi Rizzo 	rc = oce_multiq_transmit(ifp, NULL, wq);
11532f345d8eSLuigi Rizzo 	if (rc) {
11542f345d8eSLuigi Rizzo 		device_printf(sc->dev,
11552f345d8eSLuigi Rizzo 				"TX[%d] restart failed\n", wq->queue_index);
11562f345d8eSLuigi Rizzo 	}
11572f345d8eSLuigi Rizzo 	UNLOCK(&wq->tx_lock);
11582f345d8eSLuigi Rizzo #else
11592f345d8eSLuigi Rizzo 	oce_start(ifp);
11602f345d8eSLuigi Rizzo #endif
11612f345d8eSLuigi Rizzo 
11622f345d8eSLuigi Rizzo }
11632f345d8eSLuigi Rizzo 
11642f345d8eSLuigi Rizzo 
11652f345d8eSLuigi Rizzo void
11662f345d8eSLuigi Rizzo oce_start(struct ifnet *ifp)
11672f345d8eSLuigi Rizzo {
11682f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
11692f345d8eSLuigi Rizzo 	struct mbuf *m;
11702f345d8eSLuigi Rizzo 	int rc = 0;
11719bd3250aSLuigi Rizzo 	int def_q = 0; /* Defualt tx queue is 0*/
11722f345d8eSLuigi Rizzo 
11732f345d8eSLuigi Rizzo 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
11742f345d8eSLuigi Rizzo 			IFF_DRV_RUNNING)
11752f345d8eSLuigi Rizzo 		return;
11762f345d8eSLuigi Rizzo 
1177cdaba892SXin LI 	if (!sc->link_status)
1178cdaba892SXin LI 		return;
1179cdaba892SXin LI 
11802f345d8eSLuigi Rizzo 	do {
11812f345d8eSLuigi Rizzo 		IF_DEQUEUE(&sc->ifp->if_snd, m);
11822f345d8eSLuigi Rizzo 		if (m == NULL)
11832f345d8eSLuigi Rizzo 			break;
11849bd3250aSLuigi Rizzo 
11859bd3250aSLuigi Rizzo 		LOCK(&sc->wq[def_q]->tx_lock);
11869bd3250aSLuigi Rizzo 		rc = oce_tx(sc, &m, def_q);
11879bd3250aSLuigi Rizzo 		UNLOCK(&sc->wq[def_q]->tx_lock);
11882f345d8eSLuigi Rizzo 		if (rc) {
11892f345d8eSLuigi Rizzo 			if (m != NULL) {
11909bd3250aSLuigi Rizzo 				sc->wq[def_q]->tx_stats.tx_stops ++;
11912f345d8eSLuigi Rizzo 				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
11922f345d8eSLuigi Rizzo 				IFQ_DRV_PREPEND(&ifp->if_snd, m);
11932f345d8eSLuigi Rizzo 				m = NULL;
11942f345d8eSLuigi Rizzo 			}
11952f345d8eSLuigi Rizzo 			break;
11962f345d8eSLuigi Rizzo 		}
11972f345d8eSLuigi Rizzo 		if (m != NULL)
11982f345d8eSLuigi Rizzo 			ETHER_BPF_MTAP(ifp, m);
11992f345d8eSLuigi Rizzo 
12009bd3250aSLuigi Rizzo 	} while (TRUE);
12012f345d8eSLuigi Rizzo 
12022f345d8eSLuigi Rizzo 	return;
12032f345d8eSLuigi Rizzo }
12042f345d8eSLuigi Rizzo 
12052f345d8eSLuigi Rizzo 
12062f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */
12072f345d8eSLuigi Rizzo uint16_t
12082f345d8eSLuigi Rizzo oce_wq_handler(void *arg)
12092f345d8eSLuigi Rizzo {
12102f345d8eSLuigi Rizzo 	struct oce_wq *wq = (struct oce_wq *)arg;
12112f345d8eSLuigi Rizzo 	POCE_SOFTC sc = wq->parent;
12122f345d8eSLuigi Rizzo 	struct oce_cq *cq = wq->cq;
12132f345d8eSLuigi Rizzo 	struct oce_nic_tx_cqe *cqe;
12142f345d8eSLuigi Rizzo 	int num_cqes = 0;
12152f345d8eSLuigi Rizzo 
12162f345d8eSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
12172f345d8eSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
12182f345d8eSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
12192f345d8eSLuigi Rizzo 	while (cqe->u0.dw[3]) {
12202f345d8eSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
12212f345d8eSLuigi Rizzo 
12222f345d8eSLuigi Rizzo 		wq->ring->cidx = cqe->u0.s.wqe_index + 1;
12232f345d8eSLuigi Rizzo 		if (wq->ring->cidx >= wq->ring->num_items)
12242f345d8eSLuigi Rizzo 			wq->ring->cidx -= wq->ring->num_items;
12252f345d8eSLuigi Rizzo 
12262f345d8eSLuigi Rizzo 		oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status);
12272f345d8eSLuigi Rizzo 		wq->tx_stats.tx_compl++;
12282f345d8eSLuigi Rizzo 		cqe->u0.dw[3] = 0;
12292f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
12302f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
12312f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
12322f345d8eSLuigi Rizzo 		cqe =
12332f345d8eSLuigi Rizzo 		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
12342f345d8eSLuigi Rizzo 		num_cqes++;
12352f345d8eSLuigi Rizzo 	}
12362f345d8eSLuigi Rizzo 
12372f345d8eSLuigi Rizzo 	if (num_cqes)
12382f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
12392f345d8eSLuigi Rizzo 
12402f345d8eSLuigi Rizzo 	return 0;
12412f345d8eSLuigi Rizzo }
12422f345d8eSLuigi Rizzo 
12432f345d8eSLuigi Rizzo 
12442f345d8eSLuigi Rizzo static int
12452f345d8eSLuigi Rizzo oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq)
12462f345d8eSLuigi Rizzo {
12472f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
12482f345d8eSLuigi Rizzo 	int status = 0, queue_index = 0;
12492f345d8eSLuigi Rizzo 	struct mbuf *next = NULL;
12502f345d8eSLuigi Rizzo 	struct buf_ring *br = NULL;
12512f345d8eSLuigi Rizzo 
12522f345d8eSLuigi Rizzo 	br  = wq->br;
12532f345d8eSLuigi Rizzo 	queue_index = wq->queue_index;
12542f345d8eSLuigi Rizzo 
12552f345d8eSLuigi Rizzo 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
12562f345d8eSLuigi Rizzo 		IFF_DRV_RUNNING) {
12572f345d8eSLuigi Rizzo 		if (m != NULL)
12582f345d8eSLuigi Rizzo 			status = drbr_enqueue(ifp, br, m);
12592f345d8eSLuigi Rizzo 		return status;
12602f345d8eSLuigi Rizzo 	}
12612f345d8eSLuigi Rizzo 
1262ded5ea6aSRandall Stewart 	if (m != NULL) {
12632f345d8eSLuigi Rizzo 		if ((status = drbr_enqueue(ifp, br, m)) != 0)
12642f345d8eSLuigi Rizzo 			return status;
1265ded5ea6aSRandall Stewart 	}
1266ded5ea6aSRandall Stewart 	while ((next = drbr_peek(ifp, br)) != NULL) {
12672f345d8eSLuigi Rizzo 		if (oce_tx(sc, &next, queue_index)) {
1268ded5ea6aSRandall Stewart 			if (next == NULL) {
1269ded5ea6aSRandall Stewart 				drbr_advance(ifp, br);
1270ded5ea6aSRandall Stewart 			} else {
1271ded5ea6aSRandall Stewart 				drbr_putback(ifp, br, next);
12722f345d8eSLuigi Rizzo 				wq->tx_stats.tx_stops ++;
12732f345d8eSLuigi Rizzo 				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
12742f345d8eSLuigi Rizzo 			}
12752f345d8eSLuigi Rizzo 			break;
12762f345d8eSLuigi Rizzo 		}
1277ded5ea6aSRandall Stewart 		drbr_advance(ifp, br);
1278*c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len);
1279063efed2SGleb Smirnoff 		if (next->m_flags & M_MCAST)
1280*c8dfaf38SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
12812f345d8eSLuigi Rizzo 		ETHER_BPF_MTAP(ifp, next);
12822f345d8eSLuigi Rizzo 	}
12832f345d8eSLuigi Rizzo 
1284d398c863SLuigi Rizzo 	return 0;
12852f345d8eSLuigi Rizzo }
12862f345d8eSLuigi Rizzo 
12872f345d8eSLuigi Rizzo 
12882f345d8eSLuigi Rizzo 
12892f345d8eSLuigi Rizzo 
12902f345d8eSLuigi Rizzo /*****************************************************************************
12912f345d8eSLuigi Rizzo  *			    Receive  routines functions 		     *
12922f345d8eSLuigi Rizzo  *****************************************************************************/
12932f345d8eSLuigi Rizzo 
12942f345d8eSLuigi Rizzo static void
12952f345d8eSLuigi Rizzo oce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe)
12962f345d8eSLuigi Rizzo {
12972f345d8eSLuigi Rizzo 	uint32_t out;
12982f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
12992f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
13002f345d8eSLuigi Rizzo 	int i, len, frag_len;
13012f345d8eSLuigi Rizzo 	struct mbuf *m = NULL, *tail = NULL;
13022f345d8eSLuigi Rizzo 	uint16_t vtag;
13032f345d8eSLuigi Rizzo 
13042f345d8eSLuigi Rizzo 	len = cqe->u0.s.pkt_size;
13052f345d8eSLuigi Rizzo 	if (!len) {
13062f345d8eSLuigi Rizzo 		/*partial DMA workaround for Lancer*/
13072f345d8eSLuigi Rizzo 		oce_discard_rx_comp(rq, cqe);
13082f345d8eSLuigi Rizzo 		goto exit;
13092f345d8eSLuigi Rizzo 	}
13102f345d8eSLuigi Rizzo 
13119bd3250aSLuigi Rizzo 	 /* Get vlan_tag value */
1312291a1934SXin LI 	if(IS_BE(sc) || IS_SH(sc))
13139bd3250aSLuigi Rizzo 		vtag = BSWAP_16(cqe->u0.s.vlan_tag);
13149bd3250aSLuigi Rizzo 	else
13159bd3250aSLuigi Rizzo 		vtag = cqe->u0.s.vlan_tag;
13169bd3250aSLuigi Rizzo 
13179bd3250aSLuigi Rizzo 
13182f345d8eSLuigi Rizzo 	for (i = 0; i < cqe->u0.s.num_fragments; i++) {
13192f345d8eSLuigi Rizzo 
13202f345d8eSLuigi Rizzo 		if (rq->packets_out == rq->packets_in) {
13212f345d8eSLuigi Rizzo 			device_printf(sc->dev,
13222f345d8eSLuigi Rizzo 				  "RQ transmit descriptor missing\n");
13232f345d8eSLuigi Rizzo 		}
13242f345d8eSLuigi Rizzo 		out = rq->packets_out + 1;
13252f345d8eSLuigi Rizzo 		if (out == OCE_RQ_PACKET_ARRAY_SIZE)
13262f345d8eSLuigi Rizzo 			out = 0;
13272f345d8eSLuigi Rizzo 		pd = &rq->pckts[rq->packets_out];
13282f345d8eSLuigi Rizzo 		rq->packets_out = out;
13292f345d8eSLuigi Rizzo 
13302f345d8eSLuigi Rizzo 		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
13312f345d8eSLuigi Rizzo 		bus_dmamap_unload(rq->tag, pd->map);
13322f345d8eSLuigi Rizzo 		rq->pending--;
13332f345d8eSLuigi Rizzo 
13342f345d8eSLuigi Rizzo 		frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
13352f345d8eSLuigi Rizzo 		pd->mbuf->m_len = frag_len;
13362f345d8eSLuigi Rizzo 
13372f345d8eSLuigi Rizzo 		if (tail != NULL) {
13382f345d8eSLuigi Rizzo 			/* additional fragments */
13392f345d8eSLuigi Rizzo 			pd->mbuf->m_flags &= ~M_PKTHDR;
13402f345d8eSLuigi Rizzo 			tail->m_next = pd->mbuf;
13412f345d8eSLuigi Rizzo 			tail = pd->mbuf;
13422f345d8eSLuigi Rizzo 		} else {
13432f345d8eSLuigi Rizzo 			/* first fragment, fill out much of the packet header */
13442f345d8eSLuigi Rizzo 			pd->mbuf->m_pkthdr.len = len;
13452f345d8eSLuigi Rizzo 			pd->mbuf->m_pkthdr.csum_flags = 0;
13462f345d8eSLuigi Rizzo 			if (IF_CSUM_ENABLED(sc)) {
13472f345d8eSLuigi Rizzo 				if (cqe->u0.s.l4_cksum_pass) {
13482f345d8eSLuigi Rizzo 					pd->mbuf->m_pkthdr.csum_flags |=
13492f345d8eSLuigi Rizzo 					    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
13502f345d8eSLuigi Rizzo 					pd->mbuf->m_pkthdr.csum_data = 0xffff;
13512f345d8eSLuigi Rizzo 				}
13522f345d8eSLuigi Rizzo 				if (cqe->u0.s.ip_cksum_pass) {
13539bd3250aSLuigi Rizzo 					if (!cqe->u0.s.ip_ver) { /* IPV4 */
13542f345d8eSLuigi Rizzo 						pd->mbuf->m_pkthdr.csum_flags |=
13552f345d8eSLuigi Rizzo 						(CSUM_IP_CHECKED|CSUM_IP_VALID);
13562f345d8eSLuigi Rizzo 					}
13572f345d8eSLuigi Rizzo 				}
13582f345d8eSLuigi Rizzo 			}
13592f345d8eSLuigi Rizzo 			m = tail = pd->mbuf;
13602f345d8eSLuigi Rizzo 		}
13612f345d8eSLuigi Rizzo 		pd->mbuf = NULL;
13622f345d8eSLuigi Rizzo 		len -= frag_len;
13632f345d8eSLuigi Rizzo 	}
13642f345d8eSLuigi Rizzo 
13652f345d8eSLuigi Rizzo 	if (m) {
13662f345d8eSLuigi Rizzo 		if (!oce_cqe_portid_valid(sc, cqe)) {
13672f345d8eSLuigi Rizzo 			 m_freem(m);
13682f345d8eSLuigi Rizzo 			 goto exit;
13692f345d8eSLuigi Rizzo 		}
13702f345d8eSLuigi Rizzo 
13712f345d8eSLuigi Rizzo 		m->m_pkthdr.rcvif = sc->ifp;
13722f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000
1373291a1934SXin LI 		if (rq->queue_index)
1374291a1934SXin LI 			m->m_pkthdr.flowid = (rq->queue_index - 1);
1375291a1934SXin LI 		else
13762f345d8eSLuigi Rizzo 			m->m_pkthdr.flowid = rq->queue_index;
13772f345d8eSLuigi Rizzo 		m->m_flags |= M_FLOWID;
13782f345d8eSLuigi Rizzo #endif
13799bd3250aSLuigi Rizzo 		/* This deternies if vlan tag is Valid */
13802f345d8eSLuigi Rizzo 		if (oce_cqe_vtp_valid(sc, cqe)) {
13812f345d8eSLuigi Rizzo 			if (sc->function_mode & FNM_FLEX10_MODE) {
13829bd3250aSLuigi Rizzo 				/* FLEX10. If QnQ is not set, neglect VLAN */
13832f345d8eSLuigi Rizzo 				if (cqe->u0.s.qnq) {
13842f345d8eSLuigi Rizzo 					m->m_pkthdr.ether_vtag = vtag;
13852f345d8eSLuigi Rizzo 					m->m_flags |= M_VLANTAG;
13862f345d8eSLuigi Rizzo 				}
13879bd3250aSLuigi Rizzo 			} else if (sc->pvid != (vtag & VLAN_VID_MASK))  {
13889bd3250aSLuigi Rizzo 				/* In UMC mode generally pvid will be striped by
13899bd3250aSLuigi Rizzo 				   hw. But in some cases we have seen it comes
13909bd3250aSLuigi Rizzo 				   with pvid. So if pvid == vlan, neglect vlan.
13919bd3250aSLuigi Rizzo 				*/
13922f345d8eSLuigi Rizzo 				m->m_pkthdr.ether_vtag = vtag;
13932f345d8eSLuigi Rizzo 				m->m_flags |= M_VLANTAG;
13942f345d8eSLuigi Rizzo 			}
13952f345d8eSLuigi Rizzo 		}
13962f345d8eSLuigi Rizzo 
1397*c8dfaf38SGleb Smirnoff 		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1398ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
13992f345d8eSLuigi Rizzo 		/* Try to queue to LRO */
14002f345d8eSLuigi Rizzo 		if (IF_LRO_ENABLED(sc) &&
14012f345d8eSLuigi Rizzo 		    (cqe->u0.s.ip_cksum_pass) &&
14022f345d8eSLuigi Rizzo 		    (cqe->u0.s.l4_cksum_pass) &&
14032f345d8eSLuigi Rizzo 		    (!cqe->u0.s.ip_ver)       &&
14042f345d8eSLuigi Rizzo 		    (rq->lro.lro_cnt != 0)) {
14052f345d8eSLuigi Rizzo 
14062f345d8eSLuigi Rizzo 			if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
14072f345d8eSLuigi Rizzo 				rq->lro_pkts_queued ++;
14082f345d8eSLuigi Rizzo 				goto post_done;
14092f345d8eSLuigi Rizzo 			}
14102f345d8eSLuigi Rizzo 			/* If LRO posting fails then try to post to STACK */
14112f345d8eSLuigi Rizzo 		}
1412ad512958SBjoern A. Zeeb #endif
14132f345d8eSLuigi Rizzo 
14142f345d8eSLuigi Rizzo 		(*sc->ifp->if_input) (sc->ifp, m);
1415ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
14162f345d8eSLuigi Rizzo post_done:
1417ad512958SBjoern A. Zeeb #endif
14182f345d8eSLuigi Rizzo 		/* Update rx stats per queue */
14192f345d8eSLuigi Rizzo 		rq->rx_stats.rx_pkts++;
14202f345d8eSLuigi Rizzo 		rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
14212f345d8eSLuigi Rizzo 		rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
14222f345d8eSLuigi Rizzo 		if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
14232f345d8eSLuigi Rizzo 			rq->rx_stats.rx_mcast_pkts++;
14242f345d8eSLuigi Rizzo 		if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
14252f345d8eSLuigi Rizzo 			rq->rx_stats.rx_ucast_pkts++;
14262f345d8eSLuigi Rizzo 	}
14272f345d8eSLuigi Rizzo exit:
14282f345d8eSLuigi Rizzo 	return;
14292f345d8eSLuigi Rizzo }
14302f345d8eSLuigi Rizzo 
14312f345d8eSLuigi Rizzo 
14322f345d8eSLuigi Rizzo static void
14332f345d8eSLuigi Rizzo oce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
14342f345d8eSLuigi Rizzo {
14352f345d8eSLuigi Rizzo 	uint32_t out, i = 0;
14362f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
14372f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
14382f345d8eSLuigi Rizzo 	int num_frags = cqe->u0.s.num_fragments;
14392f345d8eSLuigi Rizzo 
14402f345d8eSLuigi Rizzo 	for (i = 0; i < num_frags; i++) {
14412f345d8eSLuigi Rizzo 		if (rq->packets_out == rq->packets_in) {
14422f345d8eSLuigi Rizzo 			device_printf(sc->dev,
14432f345d8eSLuigi Rizzo 				"RQ transmit descriptor missing\n");
14442f345d8eSLuigi Rizzo 		}
14452f345d8eSLuigi Rizzo 		out = rq->packets_out + 1;
14462f345d8eSLuigi Rizzo 		if (out == OCE_RQ_PACKET_ARRAY_SIZE)
14472f345d8eSLuigi Rizzo 			out = 0;
14482f345d8eSLuigi Rizzo 		pd = &rq->pckts[rq->packets_out];
14492f345d8eSLuigi Rizzo 		rq->packets_out = out;
14502f345d8eSLuigi Rizzo 
14512f345d8eSLuigi Rizzo 		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
14522f345d8eSLuigi Rizzo 		bus_dmamap_unload(rq->tag, pd->map);
14532f345d8eSLuigi Rizzo 		rq->pending--;
14542f345d8eSLuigi Rizzo 		m_freem(pd->mbuf);
14552f345d8eSLuigi Rizzo 	}
14562f345d8eSLuigi Rizzo 
14572f345d8eSLuigi Rizzo }
14582f345d8eSLuigi Rizzo 
14592f345d8eSLuigi Rizzo 
14602f345d8eSLuigi Rizzo static int
14612f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
14622f345d8eSLuigi Rizzo {
14632f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe_v1 *cqe_v1;
14642f345d8eSLuigi Rizzo 	int vtp = 0;
14652f345d8eSLuigi Rizzo 
14662f345d8eSLuigi Rizzo 	if (sc->be3_native) {
14672f345d8eSLuigi Rizzo 		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
14682f345d8eSLuigi Rizzo 		vtp =  cqe_v1->u0.s.vlan_tag_present;
14699bd3250aSLuigi Rizzo 	} else
14702f345d8eSLuigi Rizzo 		vtp = cqe->u0.s.vlan_tag_present;
14712f345d8eSLuigi Rizzo 
14722f345d8eSLuigi Rizzo 	return vtp;
14732f345d8eSLuigi Rizzo 
14742f345d8eSLuigi Rizzo }
14752f345d8eSLuigi Rizzo 
14762f345d8eSLuigi Rizzo 
14772f345d8eSLuigi Rizzo static int
14782f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
14792f345d8eSLuigi Rizzo {
14802f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe_v1 *cqe_v1;
14812f345d8eSLuigi Rizzo 	int port_id = 0;
14822f345d8eSLuigi Rizzo 
1483291a1934SXin LI 	if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) {
14842f345d8eSLuigi Rizzo 		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
14852f345d8eSLuigi Rizzo 		port_id =  cqe_v1->u0.s.port;
14862f345d8eSLuigi Rizzo 		if (sc->port_id != port_id)
14872f345d8eSLuigi Rizzo 			return 0;
14882f345d8eSLuigi Rizzo 	} else
14892f345d8eSLuigi Rizzo 		;/* For BE3 legacy and Lancer this is dummy */
14902f345d8eSLuigi Rizzo 
14912f345d8eSLuigi Rizzo 	return 1;
14922f345d8eSLuigi Rizzo 
14932f345d8eSLuigi Rizzo }
14942f345d8eSLuigi Rizzo 
1495ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
14962f345d8eSLuigi Rizzo static void
14972f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq)
14982f345d8eSLuigi Rizzo {
14992f345d8eSLuigi Rizzo 	struct lro_ctrl	*lro = &rq->lro;
15002f345d8eSLuigi Rizzo 	struct lro_entry *queued;
15012f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
15022f345d8eSLuigi Rizzo 
15032f345d8eSLuigi Rizzo 	if (!IF_LRO_ENABLED(sc))
15042f345d8eSLuigi Rizzo 		return;
15052f345d8eSLuigi Rizzo 
15062f345d8eSLuigi Rizzo 	while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
15072f345d8eSLuigi Rizzo 		SLIST_REMOVE_HEAD(&lro->lro_active, next);
15082f345d8eSLuigi Rizzo 		tcp_lro_flush(lro, queued);
15092f345d8eSLuigi Rizzo 	}
15102f345d8eSLuigi Rizzo 	rq->lro_pkts_queued = 0;
15112f345d8eSLuigi Rizzo 
15122f345d8eSLuigi Rizzo 	return;
15132f345d8eSLuigi Rizzo }
15142f345d8eSLuigi Rizzo 
15152f345d8eSLuigi Rizzo 
15162f345d8eSLuigi Rizzo static int
15172f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc)
15182f345d8eSLuigi Rizzo {
15192f345d8eSLuigi Rizzo 	struct lro_ctrl *lro = NULL;
15202f345d8eSLuigi Rizzo 	int i = 0, rc = 0;
15212f345d8eSLuigi Rizzo 
15222f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nrqs; i++) {
15232f345d8eSLuigi Rizzo 		lro = &sc->rq[i]->lro;
15242f345d8eSLuigi Rizzo 		rc = tcp_lro_init(lro);
15252f345d8eSLuigi Rizzo 		if (rc != 0) {
15262f345d8eSLuigi Rizzo 			device_printf(sc->dev, "LRO init failed\n");
15272f345d8eSLuigi Rizzo 			return rc;
15282f345d8eSLuigi Rizzo 		}
15292f345d8eSLuigi Rizzo 		lro->ifp = sc->ifp;
15302f345d8eSLuigi Rizzo 	}
15312f345d8eSLuigi Rizzo 
15322f345d8eSLuigi Rizzo 	return rc;
15332f345d8eSLuigi Rizzo }
15349bd3250aSLuigi Rizzo 
15352f345d8eSLuigi Rizzo 
15362f345d8eSLuigi Rizzo void
15372f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc)
15382f345d8eSLuigi Rizzo {
15392f345d8eSLuigi Rizzo 	struct lro_ctrl *lro = NULL;
15402f345d8eSLuigi Rizzo 	int i = 0;
15412f345d8eSLuigi Rizzo 
15422f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nrqs; i++) {
15432f345d8eSLuigi Rizzo 		lro = &sc->rq[i]->lro;
15442f345d8eSLuigi Rizzo 		if (lro)
15452f345d8eSLuigi Rizzo 			tcp_lro_free(lro);
15462f345d8eSLuigi Rizzo 	}
15472f345d8eSLuigi Rizzo }
1548cdaba892SXin LI #endif
15492f345d8eSLuigi Rizzo 
15502f345d8eSLuigi Rizzo int
15512f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count)
15522f345d8eSLuigi Rizzo {
15532f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
15542f345d8eSLuigi Rizzo 	int i, in, rc;
15552f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
15562f345d8eSLuigi Rizzo 	bus_dma_segment_t segs[6];
15572f345d8eSLuigi Rizzo 	int nsegs, added = 0;
15582f345d8eSLuigi Rizzo 	struct oce_nic_rqe *rqe;
15592f345d8eSLuigi Rizzo 	pd_rxulp_db_t rxdb_reg;
15602f345d8eSLuigi Rizzo 
1561cdaba892SXin LI 	bzero(&rxdb_reg, sizeof(pd_rxulp_db_t));
15622f345d8eSLuigi Rizzo 	for (i = 0; i < count; i++) {
15632f345d8eSLuigi Rizzo 		in = rq->packets_in + 1;
15642f345d8eSLuigi Rizzo 		if (in == OCE_RQ_PACKET_ARRAY_SIZE)
15652f345d8eSLuigi Rizzo 			in = 0;
15662f345d8eSLuigi Rizzo 		if (in == rq->packets_out)
15672f345d8eSLuigi Rizzo 			break;	/* no more room */
15682f345d8eSLuigi Rizzo 
15692f345d8eSLuigi Rizzo 		pd = &rq->pckts[rq->packets_in];
1570c6499eccSGleb Smirnoff 		pd->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
15712f345d8eSLuigi Rizzo 		if (pd->mbuf == NULL)
15722f345d8eSLuigi Rizzo 			break;
15732f345d8eSLuigi Rizzo 
15742f345d8eSLuigi Rizzo 		pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES;
15752f345d8eSLuigi Rizzo 		rc = bus_dmamap_load_mbuf_sg(rq->tag,
15762f345d8eSLuigi Rizzo 					     pd->map,
15772f345d8eSLuigi Rizzo 					     pd->mbuf,
15782f345d8eSLuigi Rizzo 					     segs, &nsegs, BUS_DMA_NOWAIT);
15792f345d8eSLuigi Rizzo 		if (rc) {
15802f345d8eSLuigi Rizzo 			m_free(pd->mbuf);
15812f345d8eSLuigi Rizzo 			break;
15822f345d8eSLuigi Rizzo 		}
15832f345d8eSLuigi Rizzo 
15842f345d8eSLuigi Rizzo 		if (nsegs != 1) {
15852f345d8eSLuigi Rizzo 			i--;
15862f345d8eSLuigi Rizzo 			continue;
15872f345d8eSLuigi Rizzo 		}
15882f345d8eSLuigi Rizzo 
15892f345d8eSLuigi Rizzo 		rq->packets_in = in;
15902f345d8eSLuigi Rizzo 		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
15912f345d8eSLuigi Rizzo 
15922f345d8eSLuigi Rizzo 		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
15932f345d8eSLuigi Rizzo 		rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
15942f345d8eSLuigi Rizzo 		rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
15952f345d8eSLuigi Rizzo 		DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
15962f345d8eSLuigi Rizzo 		RING_PUT(rq->ring, 1);
15972f345d8eSLuigi Rizzo 		added++;
15982f345d8eSLuigi Rizzo 		rq->pending++;
15992f345d8eSLuigi Rizzo 	}
16002f345d8eSLuigi Rizzo 	if (added != 0) {
16012f345d8eSLuigi Rizzo 		for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) {
16022f345d8eSLuigi Rizzo 			rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS;
16032f345d8eSLuigi Rizzo 			rxdb_reg.bits.qid = rq->rq_id;
16042f345d8eSLuigi Rizzo 			OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
16052f345d8eSLuigi Rizzo 			added -= OCE_MAX_RQ_POSTS;
16062f345d8eSLuigi Rizzo 		}
16072f345d8eSLuigi Rizzo 		if (added > 0) {
16082f345d8eSLuigi Rizzo 			rxdb_reg.bits.qid = rq->rq_id;
16092f345d8eSLuigi Rizzo 			rxdb_reg.bits.num_posted = added;
16102f345d8eSLuigi Rizzo 			OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
16112f345d8eSLuigi Rizzo 		}
16122f345d8eSLuigi Rizzo 	}
16132f345d8eSLuigi Rizzo 
16142f345d8eSLuigi Rizzo 	return 0;
16152f345d8eSLuigi Rizzo }
16162f345d8eSLuigi Rizzo 
16172f345d8eSLuigi Rizzo 
16182f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */
16192f345d8eSLuigi Rizzo uint16_t
16202f345d8eSLuigi Rizzo oce_rq_handler(void *arg)
16212f345d8eSLuigi Rizzo {
16222f345d8eSLuigi Rizzo 	struct oce_rq *rq = (struct oce_rq *)arg;
16232f345d8eSLuigi Rizzo 	struct oce_cq *cq = rq->cq;
16242f345d8eSLuigi Rizzo 	POCE_SOFTC sc = rq->parent;
16252f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe *cqe;
16262f345d8eSLuigi Rizzo 	int num_cqes = 0, rq_buffers_used = 0;
16272f345d8eSLuigi Rizzo 
16282f345d8eSLuigi Rizzo 
16292f345d8eSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
16302f345d8eSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
16312f345d8eSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
16322f345d8eSLuigi Rizzo 	while (cqe->u0.dw[2]) {
16332f345d8eSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
16342f345d8eSLuigi Rizzo 
16352f345d8eSLuigi Rizzo 		RING_GET(rq->ring, 1);
16362f345d8eSLuigi Rizzo 		if (cqe->u0.s.error == 0) {
16372f345d8eSLuigi Rizzo 			oce_rx(rq, cqe->u0.s.frag_index, cqe);
16382f345d8eSLuigi Rizzo 		} else {
16392f345d8eSLuigi Rizzo 			rq->rx_stats.rxcp_err++;
1640*c8dfaf38SGleb Smirnoff 			if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
16412f345d8eSLuigi Rizzo 			/* Post L3/L4 errors to stack.*/
16422f345d8eSLuigi Rizzo 			oce_rx(rq, cqe->u0.s.frag_index, cqe);
16432f345d8eSLuigi Rizzo 		}
16442f345d8eSLuigi Rizzo 		rq->rx_stats.rx_compl++;
16452f345d8eSLuigi Rizzo 		cqe->u0.dw[2] = 0;
16462f345d8eSLuigi Rizzo 
1647ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
16482f345d8eSLuigi Rizzo 		if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
16492f345d8eSLuigi Rizzo 			oce_rx_flush_lro(rq);
16502f345d8eSLuigi Rizzo 		}
1651ad512958SBjoern A. Zeeb #endif
16522f345d8eSLuigi Rizzo 
16532f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
16542f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
16552f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
16562f345d8eSLuigi Rizzo 		cqe =
16572f345d8eSLuigi Rizzo 		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
16582f345d8eSLuigi Rizzo 		num_cqes++;
16592f345d8eSLuigi Rizzo 		if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
16602f345d8eSLuigi Rizzo 			break;
16612f345d8eSLuigi Rizzo 	}
16629bd3250aSLuigi Rizzo 
1663ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
16642f345d8eSLuigi Rizzo 	if (IF_LRO_ENABLED(sc))
16652f345d8eSLuigi Rizzo 		oce_rx_flush_lro(rq);
1666ad512958SBjoern A. Zeeb #endif
16672f345d8eSLuigi Rizzo 
16682f345d8eSLuigi Rizzo 	if (num_cqes) {
16692f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
16702f345d8eSLuigi Rizzo 		rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending;
16712f345d8eSLuigi Rizzo 		if (rq_buffers_used > 1)
16722f345d8eSLuigi Rizzo 			oce_alloc_rx_bufs(rq, (rq_buffers_used - 1));
16732f345d8eSLuigi Rizzo 	}
16742f345d8eSLuigi Rizzo 
16752f345d8eSLuigi Rizzo 	return 0;
16762f345d8eSLuigi Rizzo 
16772f345d8eSLuigi Rizzo }
16782f345d8eSLuigi Rizzo 
16792f345d8eSLuigi Rizzo 
16802f345d8eSLuigi Rizzo 
16812f345d8eSLuigi Rizzo 
16822f345d8eSLuigi Rizzo /*****************************************************************************
16832f345d8eSLuigi Rizzo  *		   Helper function prototypes in this file 		     *
16842f345d8eSLuigi Rizzo  *****************************************************************************/
16852f345d8eSLuigi Rizzo 
16862f345d8eSLuigi Rizzo static int
16872f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc)
16882f345d8eSLuigi Rizzo {
16892f345d8eSLuigi Rizzo 
16902f345d8eSLuigi Rizzo 	sc->ifp = if_alloc(IFT_ETHER);
16912f345d8eSLuigi Rizzo 	if (!sc->ifp)
16922f345d8eSLuigi Rizzo 		return ENOMEM;
16932f345d8eSLuigi Rizzo 
16942f345d8eSLuigi Rizzo 	ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
16952f345d8eSLuigi Rizzo 	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
16962f345d8eSLuigi Rizzo 	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
16972f345d8eSLuigi Rizzo 
16982f345d8eSLuigi Rizzo 	sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
16992f345d8eSLuigi Rizzo 	sc->ifp->if_ioctl = oce_ioctl;
17002f345d8eSLuigi Rizzo 	sc->ifp->if_start = oce_start;
17012f345d8eSLuigi Rizzo 	sc->ifp->if_init = oce_init;
17022f345d8eSLuigi Rizzo 	sc->ifp->if_mtu = ETHERMTU;
17032f345d8eSLuigi Rizzo 	sc->ifp->if_softc = sc;
17042f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000
17052f345d8eSLuigi Rizzo 	sc->ifp->if_transmit = oce_multiq_start;
17062f345d8eSLuigi Rizzo 	sc->ifp->if_qflush = oce_multiq_flush;
17072f345d8eSLuigi Rizzo #endif
17082f345d8eSLuigi Rizzo 
17092f345d8eSLuigi Rizzo 	if_initname(sc->ifp,
17102f345d8eSLuigi Rizzo 		    device_get_name(sc->dev), device_get_unit(sc->dev));
17112f345d8eSLuigi Rizzo 
17122f345d8eSLuigi Rizzo 	sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1;
17132f345d8eSLuigi Rizzo 	IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen);
17142f345d8eSLuigi Rizzo 	IFQ_SET_READY(&sc->ifp->if_snd);
17152f345d8eSLuigi Rizzo 
17162f345d8eSLuigi Rizzo 	sc->ifp->if_hwassist = OCE_IF_HWASSIST;
17172f345d8eSLuigi Rizzo 	sc->ifp->if_hwassist |= CSUM_TSO;
17182f345d8eSLuigi Rizzo 	sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP);
17192f345d8eSLuigi Rizzo 
17202f345d8eSLuigi Rizzo 	sc->ifp->if_capabilities = OCE_IF_CAPABILITIES;
17212f345d8eSLuigi Rizzo 	sc->ifp->if_capabilities |= IFCAP_HWCSUM;
17222f345d8eSLuigi Rizzo 	sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
17239bd3250aSLuigi Rizzo 
1724ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
1725ad512958SBjoern A. Zeeb 	sc->ifp->if_capabilities |= IFCAP_TSO;
17262f345d8eSLuigi Rizzo 	sc->ifp->if_capabilities |= IFCAP_LRO;
17279bd3250aSLuigi Rizzo 	sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
1728ad512958SBjoern A. Zeeb #endif
17292f345d8eSLuigi Rizzo 
17302f345d8eSLuigi Rizzo 	sc->ifp->if_capenable = sc->ifp->if_capabilities;
1731b245f96cSGleb Smirnoff 	sc->ifp->if_baudrate = IF_Gbps(10);
17322f345d8eSLuigi Rizzo 
17335fbb6830SXin LI #if __FreeBSD_version >= 1000000
173472f31000SHans Petter Selasky 	sc->ifp->if_hw_tsomax = OCE_MAX_TSO_SIZE;
17355fbb6830SXin LI #endif
17365fbb6830SXin LI 
17372f345d8eSLuigi Rizzo 	ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
17382f345d8eSLuigi Rizzo 
17392f345d8eSLuigi Rizzo 	return 0;
17402f345d8eSLuigi Rizzo }
17412f345d8eSLuigi Rizzo 
17422f345d8eSLuigi Rizzo 
17432f345d8eSLuigi Rizzo static void
17442f345d8eSLuigi Rizzo oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
17452f345d8eSLuigi Rizzo {
17462f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
17472f345d8eSLuigi Rizzo 
17482f345d8eSLuigi Rizzo 	if (ifp->if_softc !=  arg)
17492f345d8eSLuigi Rizzo 		return;
17502f345d8eSLuigi Rizzo 	if ((vtag == 0) || (vtag > 4095))
17512f345d8eSLuigi Rizzo 		return;
17522f345d8eSLuigi Rizzo 
17532f345d8eSLuigi Rizzo 	sc->vlan_tag[vtag] = 1;
17542f345d8eSLuigi Rizzo 	sc->vlans_added++;
17555fbb6830SXin LI 	if (sc->vlans_added <= (sc->max_vlans + 1))
17562f345d8eSLuigi Rizzo 		oce_vid_config(sc);
17572f345d8eSLuigi Rizzo }
17582f345d8eSLuigi Rizzo 
17592f345d8eSLuigi Rizzo 
17602f345d8eSLuigi Rizzo static void
17612f345d8eSLuigi Rizzo oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
17622f345d8eSLuigi Rizzo {
17632f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
17642f345d8eSLuigi Rizzo 
17652f345d8eSLuigi Rizzo 	if (ifp->if_softc !=  arg)
17662f345d8eSLuigi Rizzo 		return;
17672f345d8eSLuigi Rizzo 	if ((vtag == 0) || (vtag > 4095))
17682f345d8eSLuigi Rizzo 		return;
17692f345d8eSLuigi Rizzo 
17702f345d8eSLuigi Rizzo 	sc->vlan_tag[vtag] = 0;
17712f345d8eSLuigi Rizzo 	sc->vlans_added--;
17722f345d8eSLuigi Rizzo 	oce_vid_config(sc);
17732f345d8eSLuigi Rizzo }
17742f345d8eSLuigi Rizzo 
17752f345d8eSLuigi Rizzo 
17762f345d8eSLuigi Rizzo /*
17772f345d8eSLuigi Rizzo  * A max of 64 vlans can be configured in BE. If the user configures
17782f345d8eSLuigi Rizzo  * more, place the card in vlan promiscuous mode.
17792f345d8eSLuigi Rizzo  */
17802f345d8eSLuigi Rizzo static int
17812f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc)
17822f345d8eSLuigi Rizzo {
17832f345d8eSLuigi Rizzo 	struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
17842f345d8eSLuigi Rizzo 	uint16_t ntags = 0, i;
17852f345d8eSLuigi Rizzo 	int status = 0;
17862f345d8eSLuigi Rizzo 
17872f345d8eSLuigi Rizzo 	if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
17882f345d8eSLuigi Rizzo 			(sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) {
17892f345d8eSLuigi Rizzo 		for (i = 0; i < MAX_VLANS; i++) {
17902f345d8eSLuigi Rizzo 			if (sc->vlan_tag[i]) {
17912f345d8eSLuigi Rizzo 				vtags[ntags].vtag = i;
17922f345d8eSLuigi Rizzo 				ntags++;
17932f345d8eSLuigi Rizzo 			}
17942f345d8eSLuigi Rizzo 		}
17952f345d8eSLuigi Rizzo 		if (ntags)
17962f345d8eSLuigi Rizzo 			status = oce_config_vlan(sc, (uint8_t) sc->if_id,
17972f345d8eSLuigi Rizzo 						vtags, ntags, 1, 0);
17982f345d8eSLuigi Rizzo 	} else
17992f345d8eSLuigi Rizzo 		status = oce_config_vlan(sc, (uint8_t) sc->if_id,
18002f345d8eSLuigi Rizzo 					 	NULL, 0, 1, 1);
18012f345d8eSLuigi Rizzo 	return status;
18022f345d8eSLuigi Rizzo }
18032f345d8eSLuigi Rizzo 
18042f345d8eSLuigi Rizzo 
18052f345d8eSLuigi Rizzo static void
18062f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc)
18072f345d8eSLuigi Rizzo {
18082f345d8eSLuigi Rizzo 	uint32_t old_pmac_id = sc->pmac_id;
18092f345d8eSLuigi Rizzo 	int status = 0;
18102f345d8eSLuigi Rizzo 
18112f345d8eSLuigi Rizzo 
18122f345d8eSLuigi Rizzo 	status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
18132f345d8eSLuigi Rizzo 			 sc->macaddr.size_of_struct);
18142f345d8eSLuigi Rizzo 	if (!status)
18152f345d8eSLuigi Rizzo 		return;
18162f345d8eSLuigi Rizzo 
18172f345d8eSLuigi Rizzo 	status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)),
18182f345d8eSLuigi Rizzo 					sc->if_id, &sc->pmac_id);
18192f345d8eSLuigi Rizzo 	if (!status) {
18202f345d8eSLuigi Rizzo 		status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
18212f345d8eSLuigi Rizzo 		bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
18222f345d8eSLuigi Rizzo 				 sc->macaddr.size_of_struct);
18232f345d8eSLuigi Rizzo 	}
18242f345d8eSLuigi Rizzo 	if (status)
18252f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Failed update macaddress\n");
18262f345d8eSLuigi Rizzo 
18272f345d8eSLuigi Rizzo }
18282f345d8eSLuigi Rizzo 
18292f345d8eSLuigi Rizzo 
18302f345d8eSLuigi Rizzo static int
18312f345d8eSLuigi Rizzo oce_handle_passthrough(struct ifnet *ifp, caddr_t data)
18322f345d8eSLuigi Rizzo {
18332f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
18342f345d8eSLuigi Rizzo 	struct ifreq *ifr = (struct ifreq *)data;
18352f345d8eSLuigi Rizzo 	int rc = ENXIO;
18362f345d8eSLuigi Rizzo 	char cookie[32] = {0};
18372f345d8eSLuigi Rizzo 	void *priv_data = (void *)ifr->ifr_data;
18382f345d8eSLuigi Rizzo 	void *ioctl_ptr;
18392f345d8eSLuigi Rizzo 	uint32_t req_size;
18402f345d8eSLuigi Rizzo 	struct mbx_hdr req;
18412f345d8eSLuigi Rizzo 	OCE_DMA_MEM dma_mem;
1842cdaba892SXin LI 	struct mbx_common_get_cntl_attr *fw_cmd;
18432f345d8eSLuigi Rizzo 
18442f345d8eSLuigi Rizzo 	if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
18452f345d8eSLuigi Rizzo 		return EFAULT;
18462f345d8eSLuigi Rizzo 
18472f345d8eSLuigi Rizzo 	if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
18482f345d8eSLuigi Rizzo 		return EINVAL;
18492f345d8eSLuigi Rizzo 
18502f345d8eSLuigi Rizzo 	ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
18512f345d8eSLuigi Rizzo 	if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
18522f345d8eSLuigi Rizzo 		return EFAULT;
18532f345d8eSLuigi Rizzo 
18542f345d8eSLuigi Rizzo 	req_size = le32toh(req.u0.req.request_length);
18552f345d8eSLuigi Rizzo 	if (req_size > 65536)
18562f345d8eSLuigi Rizzo 		return EINVAL;
18572f345d8eSLuigi Rizzo 
18582f345d8eSLuigi Rizzo 	req_size += sizeof(struct mbx_hdr);
18592f345d8eSLuigi Rizzo 	rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
18602f345d8eSLuigi Rizzo 	if (rc)
18612f345d8eSLuigi Rizzo 		return ENOMEM;
18622f345d8eSLuigi Rizzo 
18632f345d8eSLuigi Rizzo 	if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
18642f345d8eSLuigi Rizzo 		rc = EFAULT;
18652f345d8eSLuigi Rizzo 		goto dma_free;
18662f345d8eSLuigi Rizzo 	}
18672f345d8eSLuigi Rizzo 
18682f345d8eSLuigi Rizzo 	rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
18692f345d8eSLuigi Rizzo 	if (rc) {
18702f345d8eSLuigi Rizzo 		rc = EIO;
18712f345d8eSLuigi Rizzo 		goto dma_free;
18722f345d8eSLuigi Rizzo 	}
18732f345d8eSLuigi Rizzo 
18742f345d8eSLuigi Rizzo 	if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size))
18752f345d8eSLuigi Rizzo 		rc =  EFAULT;
18762f345d8eSLuigi Rizzo 
1877cdaba892SXin LI 	/*
1878cdaba892SXin LI 	   firmware is filling all the attributes for this ioctl except
1879cdaba892SXin LI 	   the driver version..so fill it
1880cdaba892SXin LI 	 */
1881cdaba892SXin LI 	if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) {
1882cdaba892SXin LI 		fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr;
1883cdaba892SXin LI 		strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str,
1884cdaba892SXin LI 			COMPONENT_REVISION, strlen(COMPONENT_REVISION));
1885cdaba892SXin LI 	}
1886cdaba892SXin LI 
18872f345d8eSLuigi Rizzo dma_free:
18882f345d8eSLuigi Rizzo 	oce_dma_free(sc, &dma_mem);
18892f345d8eSLuigi Rizzo 	return rc;
18902f345d8eSLuigi Rizzo 
18912f345d8eSLuigi Rizzo }
18922f345d8eSLuigi Rizzo 
1893cdaba892SXin LI static void
1894cdaba892SXin LI oce_eqd_set_periodic(POCE_SOFTC sc)
1895cdaba892SXin LI {
1896cdaba892SXin LI 	struct oce_set_eqd set_eqd[OCE_MAX_EQ];
1897cdaba892SXin LI 	struct oce_aic_obj *aic;
1898cdaba892SXin LI 	struct oce_eq *eqo;
1899cdaba892SXin LI 	uint64_t now = 0, delta;
1900cdaba892SXin LI 	int eqd, i, num = 0;
1901cdaba892SXin LI 	uint32_t ips = 0;
1902cdaba892SXin LI 	int tps;
1903cdaba892SXin LI 
1904cdaba892SXin LI 	for (i = 0 ; i < sc->neqs; i++) {
1905cdaba892SXin LI 		eqo = sc->eq[i];
1906cdaba892SXin LI 		aic = &sc->aic_obj[i];
1907cdaba892SXin LI 		/* When setting the static eq delay from the user space */
1908cdaba892SXin LI 		if (!aic->enable) {
1909cdaba892SXin LI 			eqd = aic->et_eqd;
1910cdaba892SXin LI 			goto modify_eqd;
1911cdaba892SXin LI 		}
1912cdaba892SXin LI 
1913cdaba892SXin LI 		now = ticks;
1914cdaba892SXin LI 
1915cdaba892SXin LI 		/* Over flow check */
1916cdaba892SXin LI 		if ((now < aic->ticks) || (eqo->intr < aic->intr_prev))
1917cdaba892SXin LI 			goto done;
1918cdaba892SXin LI 
1919cdaba892SXin LI 		delta = now - aic->ticks;
1920cdaba892SXin LI 		tps = delta/hz;
1921cdaba892SXin LI 
1922cdaba892SXin LI 		/* Interrupt rate based on elapsed ticks */
1923cdaba892SXin LI 		if(tps)
1924cdaba892SXin LI 			ips = (uint32_t)(eqo->intr - aic->intr_prev) / tps;
1925cdaba892SXin LI 
1926cdaba892SXin LI 		if (ips > INTR_RATE_HWM)
1927cdaba892SXin LI 			eqd = aic->cur_eqd + 20;
1928cdaba892SXin LI 		else if (ips < INTR_RATE_LWM)
1929cdaba892SXin LI 			eqd = aic->cur_eqd / 2;
1930cdaba892SXin LI 		else
1931cdaba892SXin LI 			goto done;
1932cdaba892SXin LI 
1933cdaba892SXin LI 		if (eqd < 10)
1934cdaba892SXin LI 			eqd = 0;
1935cdaba892SXin LI 
1936cdaba892SXin LI 		/* Make sure that the eq delay is in the known range */
1937cdaba892SXin LI 		eqd = min(eqd, aic->max_eqd);
1938cdaba892SXin LI 		eqd = max(eqd, aic->min_eqd);
1939cdaba892SXin LI 
1940cdaba892SXin LI modify_eqd:
1941cdaba892SXin LI 		if (eqd != aic->cur_eqd) {
1942cdaba892SXin LI 			set_eqd[num].delay_multiplier = (eqd * 65)/100;
1943cdaba892SXin LI 			set_eqd[num].eq_id = eqo->eq_id;
1944cdaba892SXin LI 			aic->cur_eqd = eqd;
1945cdaba892SXin LI 			num++;
1946cdaba892SXin LI 		}
1947cdaba892SXin LI done:
1948cdaba892SXin LI 		aic->intr_prev = eqo->intr;
1949cdaba892SXin LI 		aic->ticks = now;
1950cdaba892SXin LI 	}
1951cdaba892SXin LI 
1952cdaba892SXin LI 	/* Is there atleast one eq that needs to be modified? */
1953cdaba892SXin LI 	if(num)
1954cdaba892SXin LI 		oce_mbox_eqd_modify_periodic(sc, set_eqd, num);
1955cdaba892SXin LI }
19562f345d8eSLuigi Rizzo 
19575fbb6830SXin LI static void oce_detect_hw_error(POCE_SOFTC sc)
19585fbb6830SXin LI {
19595fbb6830SXin LI 
19605fbb6830SXin LI 	uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0;
19615fbb6830SXin LI 	uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
19625fbb6830SXin LI 	uint32_t i;
19635fbb6830SXin LI 
19645fbb6830SXin LI 	if (sc->hw_error)
19655fbb6830SXin LI 		return;
19665fbb6830SXin LI 
19675fbb6830SXin LI 	if (IS_XE201(sc)) {
19685fbb6830SXin LI 		sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET);
19695fbb6830SXin LI 		if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
19705fbb6830SXin LI 			sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET);
19715fbb6830SXin LI 			sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET);
19725fbb6830SXin LI 		}
19735fbb6830SXin LI 	} else {
19745fbb6830SXin LI 		ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW);
19755fbb6830SXin LI 		ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH);
19765fbb6830SXin LI 		ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK);
19775fbb6830SXin LI 		ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK);
19785fbb6830SXin LI 
19795fbb6830SXin LI 		ue_low = (ue_low & ~ue_low_mask);
19805fbb6830SXin LI 		ue_high = (ue_high & ~ue_high_mask);
19815fbb6830SXin LI 	}
19825fbb6830SXin LI 
19835fbb6830SXin LI 	/* On certain platforms BE hardware can indicate spurious UEs.
19845fbb6830SXin LI 	 * Allow the h/w to stop working completely in case of a real UE.
19855fbb6830SXin LI 	 * Hence not setting the hw_error for UE detection.
19865fbb6830SXin LI 	 */
19875fbb6830SXin LI 	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
19885fbb6830SXin LI 		sc->hw_error = TRUE;
19895fbb6830SXin LI 		device_printf(sc->dev, "Error detected in the card\n");
19905fbb6830SXin LI 	}
19915fbb6830SXin LI 
19925fbb6830SXin LI 	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
19935fbb6830SXin LI 		device_printf(sc->dev,
19945fbb6830SXin LI 				"ERR: sliport status 0x%x\n", sliport_status);
19955fbb6830SXin LI 		device_printf(sc->dev,
19965fbb6830SXin LI 				"ERR: sliport error1 0x%x\n", sliport_err1);
19975fbb6830SXin LI 		device_printf(sc->dev,
19985fbb6830SXin LI 				"ERR: sliport error2 0x%x\n", sliport_err2);
19995fbb6830SXin LI 	}
20005fbb6830SXin LI 
20015fbb6830SXin LI 	if (ue_low) {
20025fbb6830SXin LI 		for (i = 0; ue_low; ue_low >>= 1, i++) {
20035fbb6830SXin LI 			if (ue_low & 1)
20045fbb6830SXin LI 				device_printf(sc->dev, "UE: %s bit set\n",
20055fbb6830SXin LI 							ue_status_low_desc[i]);
20065fbb6830SXin LI 		}
20075fbb6830SXin LI 	}
20085fbb6830SXin LI 
20095fbb6830SXin LI 	if (ue_high) {
20105fbb6830SXin LI 		for (i = 0; ue_high; ue_high >>= 1, i++) {
20115fbb6830SXin LI 			if (ue_high & 1)
20125fbb6830SXin LI 				device_printf(sc->dev, "UE: %s bit set\n",
20135fbb6830SXin LI 							ue_status_hi_desc[i]);
20145fbb6830SXin LI 		}
20155fbb6830SXin LI 	}
20165fbb6830SXin LI 
20175fbb6830SXin LI }
20185fbb6830SXin LI 
20195fbb6830SXin LI 
20202f345d8eSLuigi Rizzo static void
20212f345d8eSLuigi Rizzo oce_local_timer(void *arg)
20222f345d8eSLuigi Rizzo {
20232f345d8eSLuigi Rizzo 	POCE_SOFTC sc = arg;
20242f345d8eSLuigi Rizzo 	int i = 0;
20252f345d8eSLuigi Rizzo 
20265fbb6830SXin LI 	oce_detect_hw_error(sc);
20272f345d8eSLuigi Rizzo 	oce_refresh_nic_stats(sc);
20282f345d8eSLuigi Rizzo 	oce_refresh_queue_stats(sc);
20292f345d8eSLuigi Rizzo 	oce_mac_addr_set(sc);
20302f345d8eSLuigi Rizzo 
20312f345d8eSLuigi Rizzo 	/* TX Watch Dog*/
20322f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nwqs; i++)
20332f345d8eSLuigi Rizzo 		oce_tx_restart(sc, sc->wq[i]);
20342f345d8eSLuigi Rizzo 
2035cdaba892SXin LI 	/* calculate and set the eq delay for optimal interrupt rate */
2036291a1934SXin LI 	if (IS_BE(sc) || IS_SH(sc))
2037cdaba892SXin LI 		oce_eqd_set_periodic(sc);
2038cdaba892SXin LI 
20392f345d8eSLuigi Rizzo 	callout_reset(&sc->timer, hz, oce_local_timer, sc);
20402f345d8eSLuigi Rizzo }
20412f345d8eSLuigi Rizzo 
20422f345d8eSLuigi Rizzo 
2043beb0f7e7SJosh Paetzel /* NOTE : This should only be called holding
2044beb0f7e7SJosh Paetzel  *        DEVICE_LOCK.
2045beb0f7e7SJosh Paetzel  */
20462f345d8eSLuigi Rizzo static void
20472f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc)
20482f345d8eSLuigi Rizzo {
20492f345d8eSLuigi Rizzo 	int i, mtime = 0;
20502f345d8eSLuigi Rizzo 	int wait_req = 0;
20512f345d8eSLuigi Rizzo 	struct oce_rq *rq;
20522f345d8eSLuigi Rizzo 	struct oce_wq *wq;
20532f345d8eSLuigi Rizzo 	struct oce_eq *eq;
20542f345d8eSLuigi Rizzo 
20552f345d8eSLuigi Rizzo 	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
20562f345d8eSLuigi Rizzo 
20572f345d8eSLuigi Rizzo 	/*Wait for max of 400ms for TX completions to be done */
20582f345d8eSLuigi Rizzo 	while (mtime < 400) {
20592f345d8eSLuigi Rizzo 		wait_req = 0;
20602f345d8eSLuigi Rizzo 		for_all_wq_queues(sc, wq, i) {
20612f345d8eSLuigi Rizzo 			if (wq->ring->num_used) {
20622f345d8eSLuigi Rizzo 				wait_req = 1;
20632f345d8eSLuigi Rizzo 				DELAY(1);
20642f345d8eSLuigi Rizzo 				break;
20652f345d8eSLuigi Rizzo 			}
20662f345d8eSLuigi Rizzo 		}
20672f345d8eSLuigi Rizzo 		mtime += 1;
20682f345d8eSLuigi Rizzo 		if (!wait_req)
20692f345d8eSLuigi Rizzo 			break;
20702f345d8eSLuigi Rizzo 	}
20712f345d8eSLuigi Rizzo 
20722f345d8eSLuigi Rizzo 	/* Stop intrs and finish any bottom halves pending */
20732f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
20742f345d8eSLuigi Rizzo 
2075cdaba892SXin LI 	/* Since taskqueue_drain takes a Gaint Lock, We should not acquire
2076beb0f7e7SJosh Paetzel 	   any other lock. So unlock device lock and require after
2077beb0f7e7SJosh Paetzel 	   completing taskqueue_drain.
2078beb0f7e7SJosh Paetzel 	*/
2079beb0f7e7SJosh Paetzel 	UNLOCK(&sc->dev_lock);
20802f345d8eSLuigi Rizzo 	for (i = 0; i < sc->intr_count; i++) {
20812f345d8eSLuigi Rizzo 		if (sc->intrs[i].tq != NULL) {
20822f345d8eSLuigi Rizzo 			taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
20832f345d8eSLuigi Rizzo 		}
20842f345d8eSLuigi Rizzo 	}
2085beb0f7e7SJosh Paetzel 	LOCK(&sc->dev_lock);
20862f345d8eSLuigi Rizzo 
20872f345d8eSLuigi Rizzo 	/* Delete RX queue in card with flush param */
20882f345d8eSLuigi Rizzo 	oce_stop_rx(sc);
20892f345d8eSLuigi Rizzo 
20902f345d8eSLuigi Rizzo 	/* Invalidate any pending cq and eq entries*/
20912f345d8eSLuigi Rizzo 	for_all_evnt_queues(sc, eq, i)
20922f345d8eSLuigi Rizzo 		oce_drain_eq(eq);
20932f345d8eSLuigi Rizzo 	for_all_rq_queues(sc, rq, i)
20942f345d8eSLuigi Rizzo 		oce_drain_rq_cq(rq);
20952f345d8eSLuigi Rizzo 	for_all_wq_queues(sc, wq, i)
20962f345d8eSLuigi Rizzo 		oce_drain_wq_cq(wq);
20972f345d8eSLuigi Rizzo 
20982f345d8eSLuigi Rizzo 	/* But still we need to get MCC aync events.
20992f345d8eSLuigi Rizzo 	   So enable intrs and also arm first EQ
21002f345d8eSLuigi Rizzo 	*/
21012f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
21022f345d8eSLuigi Rizzo 	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
21032f345d8eSLuigi Rizzo 
21042f345d8eSLuigi Rizzo 	DELAY(10);
21052f345d8eSLuigi Rizzo }
21062f345d8eSLuigi Rizzo 
21072f345d8eSLuigi Rizzo 
21082f345d8eSLuigi Rizzo static void
21092f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc)
21102f345d8eSLuigi Rizzo {
21112f345d8eSLuigi Rizzo 	struct oce_eq *eq;
21122f345d8eSLuigi Rizzo 	struct oce_rq *rq;
21132f345d8eSLuigi Rizzo 	struct oce_wq *wq;
21142f345d8eSLuigi Rizzo 	int i, rc = 0;
21152f345d8eSLuigi Rizzo 
21162f345d8eSLuigi Rizzo 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
21172f345d8eSLuigi Rizzo 
21182f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
21192f345d8eSLuigi Rizzo 
21202f345d8eSLuigi Rizzo 	oce_start_rx(sc);
21212f345d8eSLuigi Rizzo 
21222f345d8eSLuigi Rizzo 	for_all_rq_queues(sc, rq, i) {
21232f345d8eSLuigi Rizzo 		rc = oce_start_rq(rq);
21242f345d8eSLuigi Rizzo 		if (rc)
21252f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Unable to start RX\n");
21262f345d8eSLuigi Rizzo 	}
21272f345d8eSLuigi Rizzo 
21282f345d8eSLuigi Rizzo 	for_all_wq_queues(sc, wq, i) {
21292f345d8eSLuigi Rizzo 		rc = oce_start_wq(wq);
21302f345d8eSLuigi Rizzo 		if (rc)
21312f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Unable to start TX\n");
21322f345d8eSLuigi Rizzo 	}
21332f345d8eSLuigi Rizzo 
21342f345d8eSLuigi Rizzo 
21352f345d8eSLuigi Rizzo 	for_all_evnt_queues(sc, eq, i)
21362f345d8eSLuigi Rizzo 		oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
21372f345d8eSLuigi Rizzo 
21382f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
21392f345d8eSLuigi Rizzo 
21402f345d8eSLuigi Rizzo }
21412f345d8eSLuigi Rizzo 
21429bd3250aSLuigi Rizzo static void
21439bd3250aSLuigi Rizzo process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
21442f345d8eSLuigi Rizzo {
21459bd3250aSLuigi Rizzo 	/* Update Link status */
21462f345d8eSLuigi Rizzo 	if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
21472f345d8eSLuigi Rizzo 	     ASYNC_EVENT_LINK_UP) {
21482f345d8eSLuigi Rizzo 		sc->link_status = ASYNC_EVENT_LINK_UP;
21492f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_UP);
21502f345d8eSLuigi Rizzo 	} else {
21512f345d8eSLuigi Rizzo 		sc->link_status = ASYNC_EVENT_LINK_DOWN;
21522f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
21532f345d8eSLuigi Rizzo 	}
21549bd3250aSLuigi Rizzo }
21559bd3250aSLuigi Rizzo 
21569bd3250aSLuigi Rizzo 
21579bd3250aSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */
21589bd3250aSLuigi Rizzo uint16_t
21599bd3250aSLuigi Rizzo oce_mq_handler(void *arg)
21609bd3250aSLuigi Rizzo {
21619bd3250aSLuigi Rizzo 	struct oce_mq *mq = (struct oce_mq *)arg;
21629bd3250aSLuigi Rizzo 	POCE_SOFTC sc = mq->parent;
21639bd3250aSLuigi Rizzo 	struct oce_cq *cq = mq->cq;
21649bd3250aSLuigi Rizzo 	int num_cqes = 0, evt_type = 0, optype = 0;
21659bd3250aSLuigi Rizzo 	struct oce_mq_cqe *cqe;
21669bd3250aSLuigi Rizzo 	struct oce_async_cqe_link_state *acqe;
21679bd3250aSLuigi Rizzo 	struct oce_async_event_grp5_pvid_state *gcqe;
2168cdaba892SXin LI 	struct oce_async_event_qnq *dbgcqe;
21699bd3250aSLuigi Rizzo 
21709bd3250aSLuigi Rizzo 
21719bd3250aSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
21729bd3250aSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
21739bd3250aSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
21749bd3250aSLuigi Rizzo 
21759bd3250aSLuigi Rizzo 	while (cqe->u0.dw[3]) {
21769bd3250aSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
21779bd3250aSLuigi Rizzo 		if (cqe->u0.s.async_event) {
21789bd3250aSLuigi Rizzo 			evt_type = cqe->u0.s.event_type;
21799bd3250aSLuigi Rizzo 			optype = cqe->u0.s.async_type;
21809bd3250aSLuigi Rizzo 			if (evt_type  == ASYNC_EVENT_CODE_LINK_STATE) {
21819bd3250aSLuigi Rizzo 				/* Link status evt */
21829bd3250aSLuigi Rizzo 				acqe = (struct oce_async_cqe_link_state *)cqe;
21839bd3250aSLuigi Rizzo 				process_link_state(sc, acqe);
21849bd3250aSLuigi Rizzo 			} else if ((evt_type == ASYNC_EVENT_GRP5) &&
21859bd3250aSLuigi Rizzo 				   (optype == ASYNC_EVENT_PVID_STATE)) {
21869bd3250aSLuigi Rizzo 				/* GRP5 PVID */
21879bd3250aSLuigi Rizzo 				gcqe =
21889bd3250aSLuigi Rizzo 				(struct oce_async_event_grp5_pvid_state *)cqe;
21899bd3250aSLuigi Rizzo 				if (gcqe->enabled)
21909bd3250aSLuigi Rizzo 					sc->pvid = gcqe->tag & VLAN_VID_MASK;
21919bd3250aSLuigi Rizzo 				else
21929bd3250aSLuigi Rizzo 					sc->pvid = 0;
21939bd3250aSLuigi Rizzo 
21942f345d8eSLuigi Rizzo 			}
2195cdaba892SXin LI 			else if(evt_type == ASYNC_EVENT_CODE_DEBUG &&
2196cdaba892SXin LI 				optype == ASYNC_EVENT_DEBUG_QNQ) {
2197cdaba892SXin LI 				dbgcqe =
2198cdaba892SXin LI 				(struct oce_async_event_qnq *)cqe;
2199cdaba892SXin LI 				if(dbgcqe->valid)
2200cdaba892SXin LI 					sc->qnqid = dbgcqe->vlan_tag;
2201cdaba892SXin LI 				sc->qnq_debug_event = TRUE;
2202cdaba892SXin LI 			}
22032f345d8eSLuigi Rizzo 		}
22042f345d8eSLuigi Rizzo 		cqe->u0.dw[3] = 0;
22052f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
22062f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
22072f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
22082f345d8eSLuigi Rizzo 		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
22092f345d8eSLuigi Rizzo 		num_cqes++;
22102f345d8eSLuigi Rizzo 	}
22112f345d8eSLuigi Rizzo 
22122f345d8eSLuigi Rizzo 	if (num_cqes)
22132f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
22142f345d8eSLuigi Rizzo 
22152f345d8eSLuigi Rizzo 	return 0;
22162f345d8eSLuigi Rizzo }
22172f345d8eSLuigi Rizzo 
22182f345d8eSLuigi Rizzo 
22192f345d8eSLuigi Rizzo static void
22202f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc)
22212f345d8eSLuigi Rizzo {
22222f345d8eSLuigi Rizzo 	/* Check if it is FLEX machine. Is so dont use RSS */
22232f345d8eSLuigi Rizzo 	if ((sc->function_mode & FNM_FLEX10_MODE) ||
22249bd3250aSLuigi Rizzo 	    (sc->function_mode & FNM_UMC_MODE)    ||
22259bd3250aSLuigi Rizzo 	    (sc->function_mode & FNM_VNIC_MODE)	  ||
2226291a1934SXin LI 	    (!is_rss_enabled(sc))		  ||
2227a4f734b4SXin LI 	    IS_BE2(sc)) {
22282f345d8eSLuigi Rizzo 		sc->nrqs = 1;
22292f345d8eSLuigi Rizzo 		sc->nwqs = 1;
22305fbb6830SXin LI 	} else {
22315fbb6830SXin LI 		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
22325fbb6830SXin LI 		sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs);
22332f345d8eSLuigi Rizzo 	}
2234a4f734b4SXin LI 
2235a4f734b4SXin LI 	if (IS_BE2(sc) && is_rss_enabled(sc))
2236a4f734b4SXin LI 		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
22372f345d8eSLuigi Rizzo }
22382f345d8eSLuigi Rizzo 
22392f345d8eSLuigi Rizzo 
22402f345d8eSLuigi Rizzo static void
22412f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc)
22422f345d8eSLuigi Rizzo {
2243291a1934SXin LI 	if (is_rss_enabled(sc)) {
22442f345d8eSLuigi Rizzo 		sc->nrqs = sc->intr_count + 1;
22452f345d8eSLuigi Rizzo 		sc->nwqs = sc->intr_count;
22462f345d8eSLuigi Rizzo 	} else {
22472f345d8eSLuigi Rizzo 		sc->nrqs = 1;
22482f345d8eSLuigi Rizzo 		sc->nwqs = 1;
22492f345d8eSLuigi Rizzo 	}
2250a4f734b4SXin LI 
2251a4f734b4SXin LI 	if (IS_BE2(sc))
2252a4f734b4SXin LI 		sc->nwqs = 1;
22532f345d8eSLuigi Rizzo }
22542f345d8eSLuigi Rizzo 
2255cdaba892SXin LI static int
2256cdaba892SXin LI oce_check_ipv6_ext_hdr(struct mbuf *m)
2257cdaba892SXin LI {
2258cdaba892SXin LI 	struct ether_header *eh = mtod(m, struct ether_header *);
2259cdaba892SXin LI 	caddr_t m_datatemp = m->m_data;
2260cdaba892SXin LI 
2261cdaba892SXin LI 	if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2262cdaba892SXin LI 		m->m_data += sizeof(struct ether_header);
2263cdaba892SXin LI 		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2264cdaba892SXin LI 
2265cdaba892SXin LI 		if((ip6->ip6_nxt != IPPROTO_TCP) && \
2266cdaba892SXin LI 				(ip6->ip6_nxt != IPPROTO_UDP)){
2267cdaba892SXin LI 			struct ip6_ext *ip6e = NULL;
2268cdaba892SXin LI 			m->m_data += sizeof(struct ip6_hdr);
2269cdaba892SXin LI 
2270cdaba892SXin LI 			ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *);
2271cdaba892SXin LI 			if(ip6e->ip6e_len == 0xff) {
2272cdaba892SXin LI 				m->m_data = m_datatemp;
2273cdaba892SXin LI 				return TRUE;
2274cdaba892SXin LI 			}
2275cdaba892SXin LI 		}
2276cdaba892SXin LI 		m->m_data = m_datatemp;
2277cdaba892SXin LI 	}
2278cdaba892SXin LI 	return FALSE;
2279cdaba892SXin LI }
2280cdaba892SXin LI 
2281cdaba892SXin LI static int
2282cdaba892SXin LI is_be3_a1(POCE_SOFTC sc)
2283cdaba892SXin LI {
2284cdaba892SXin LI 	if((sc->flags & OCE_FLAGS_BE3)  && ((sc->asic_revision & 0xFF) < 2)) {
2285cdaba892SXin LI 		return TRUE;
2286cdaba892SXin LI 	}
2287cdaba892SXin LI 	return FALSE;
2288cdaba892SXin LI }
2289cdaba892SXin LI 
2290cdaba892SXin LI static struct mbuf *
2291cdaba892SXin LI oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete)
2292cdaba892SXin LI {
2293cdaba892SXin LI 	uint16_t vlan_tag = 0;
2294cdaba892SXin LI 
2295cdaba892SXin LI 	if(!M_WRITABLE(m))
2296cdaba892SXin LI 		return NULL;
2297cdaba892SXin LI 
2298cdaba892SXin LI 	/* Embed vlan tag in the packet if it is not part of it */
2299cdaba892SXin LI 	if(m->m_flags & M_VLANTAG) {
2300cdaba892SXin LI 		vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
2301cdaba892SXin LI 		m->m_flags &= ~M_VLANTAG;
2302cdaba892SXin LI 	}
2303cdaba892SXin LI 
2304cdaba892SXin LI 	/* if UMC, ignore vlan tag insertion and instead insert pvid */
2305cdaba892SXin LI 	if(sc->pvid) {
2306cdaba892SXin LI 		if(!vlan_tag)
2307cdaba892SXin LI 			vlan_tag = sc->pvid;
2308cdaba892SXin LI 		*complete = FALSE;
2309cdaba892SXin LI 	}
2310cdaba892SXin LI 
2311cdaba892SXin LI 	if(vlan_tag) {
2312cdaba892SXin LI 		m = ether_vlanencap(m, vlan_tag);
2313cdaba892SXin LI 	}
2314cdaba892SXin LI 
2315cdaba892SXin LI 	if(sc->qnqid) {
2316cdaba892SXin LI 		m = ether_vlanencap(m, sc->qnqid);
2317cdaba892SXin LI 		*complete = FALSE;
2318cdaba892SXin LI 	}
2319cdaba892SXin LI 	return m;
2320cdaba892SXin LI }
2321cdaba892SXin LI 
2322cdaba892SXin LI static int
2323cdaba892SXin LI oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m)
2324cdaba892SXin LI {
2325cdaba892SXin LI 	if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \
2326cdaba892SXin LI 			oce_check_ipv6_ext_hdr(m)) {
2327cdaba892SXin LI 		return TRUE;
2328cdaba892SXin LI 	}
2329cdaba892SXin LI 	return FALSE;
2330cdaba892SXin LI }
2331291a1934SXin LI 
2332291a1934SXin LI static void
2333291a1934SXin LI oce_get_config(POCE_SOFTC sc)
2334291a1934SXin LI {
2335291a1934SXin LI 	int rc = 0;
2336291a1934SXin LI 	uint32_t max_rss = 0;
2337291a1934SXin LI 
2338291a1934SXin LI 	if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native))
2339291a1934SXin LI 		max_rss = OCE_LEGACY_MODE_RSS;
2340291a1934SXin LI 	else
2341291a1934SXin LI 		max_rss = OCE_MAX_RSS;
2342291a1934SXin LI 
2343291a1934SXin LI 	if (!IS_BE(sc)) {
2344b41206d8SXin LI 		rc = oce_get_profile_config(sc, max_rss);
2345291a1934SXin LI 		if (rc) {
2346291a1934SXin LI 			sc->nwqs = OCE_MAX_WQ;
2347291a1934SXin LI 			sc->nrssqs = max_rss;
2348291a1934SXin LI 			sc->nrqs = sc->nrssqs + 1;
2349291a1934SXin LI 		}
2350291a1934SXin LI 	}
2351b41206d8SXin LI 	else { /* For BE3 don't rely on fw for determining the resources */
2352291a1934SXin LI 		sc->nrssqs = max_rss;
2353291a1934SXin LI 		sc->nrqs = sc->nrssqs + 1;
2354291a1934SXin LI 		sc->nwqs = OCE_MAX_WQ;
2355b41206d8SXin LI 		sc->max_vlans = MAX_VLANFILTER_SIZE;
2356291a1934SXin LI 	}
2357291a1934SXin LI }
2358