xref: /freebsd/sys/dev/oce/oce_if.c (revision 4591322980a37d6ee38a3ed70569366e16ca71f6)
12f345d8eSLuigi Rizzo /*-
27282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni  *
4291a1934SXin LI  * Copyright (C) 2013 Emulex
52f345d8eSLuigi Rizzo  * All rights reserved.
62f345d8eSLuigi Rizzo  *
72f345d8eSLuigi Rizzo  * Redistribution and use in source and binary forms, with or without
82f345d8eSLuigi Rizzo  * modification, are permitted provided that the following conditions are met:
92f345d8eSLuigi Rizzo  *
102f345d8eSLuigi Rizzo  * 1. Redistributions of source code must retain the above copyright notice,
112f345d8eSLuigi Rizzo  *    this list of conditions and the following disclaimer.
122f345d8eSLuigi Rizzo  *
132f345d8eSLuigi Rizzo  * 2. Redistributions in binary form must reproduce the above copyright
142f345d8eSLuigi Rizzo  *    notice, this list of conditions and the following disclaimer in the
152f345d8eSLuigi Rizzo  *    documentation and/or other materials provided with the distribution.
162f345d8eSLuigi Rizzo  *
172f345d8eSLuigi Rizzo  * 3. Neither the name of the Emulex Corporation nor the names of its
182f345d8eSLuigi Rizzo  *    contributors may be used to endorse or promote products derived from
192f345d8eSLuigi Rizzo  *    this software without specific prior written permission.
202f345d8eSLuigi Rizzo  *
212f345d8eSLuigi Rizzo  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
222f345d8eSLuigi Rizzo  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232f345d8eSLuigi Rizzo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242f345d8eSLuigi Rizzo  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
252f345d8eSLuigi Rizzo  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
262f345d8eSLuigi Rizzo  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
272f345d8eSLuigi Rizzo  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
282f345d8eSLuigi Rizzo  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
292f345d8eSLuigi Rizzo  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
302f345d8eSLuigi Rizzo  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
312f345d8eSLuigi Rizzo  * POSSIBILITY OF SUCH DAMAGE.
322f345d8eSLuigi Rizzo  *
332f345d8eSLuigi Rizzo  * Contact Information:
342f345d8eSLuigi Rizzo  * freebsd-drivers@emulex.com
352f345d8eSLuigi Rizzo  *
362f345d8eSLuigi Rizzo  * Emulex
372f345d8eSLuigi Rizzo  * 3333 Susan Street
382f345d8eSLuigi Rizzo  * Costa Mesa, CA 92626
392f345d8eSLuigi Rizzo  */
402f345d8eSLuigi Rizzo 
412f345d8eSLuigi Rizzo /* $FreeBSD$ */
422f345d8eSLuigi Rizzo 
43ad512958SBjoern A. Zeeb #include "opt_inet6.h"
44ad512958SBjoern A. Zeeb #include "opt_inet.h"
45ad512958SBjoern A. Zeeb 
462f345d8eSLuigi Rizzo #include "oce_if.h"
47c2625e6eSJosh Paetzel #include "oce_user.h"
48c2625e6eSJosh Paetzel 
49c2625e6eSJosh Paetzel #define is_tso_pkt(m) (m->m_pkthdr.csum_flags & CSUM_TSO)
502f345d8eSLuigi Rizzo 
515fbb6830SXin LI /* UE Status Low CSR */
525fbb6830SXin LI static char *ue_status_low_desc[] = {
535fbb6830SXin LI         "CEV",
545fbb6830SXin LI         "CTX",
555fbb6830SXin LI         "DBUF",
565fbb6830SXin LI         "ERX",
575fbb6830SXin LI         "Host",
585fbb6830SXin LI         "MPU",
595fbb6830SXin LI         "NDMA",
605fbb6830SXin LI         "PTC ",
615fbb6830SXin LI         "RDMA ",
625fbb6830SXin LI         "RXF ",
635fbb6830SXin LI         "RXIPS ",
645fbb6830SXin LI         "RXULP0 ",
655fbb6830SXin LI         "RXULP1 ",
665fbb6830SXin LI         "RXULP2 ",
675fbb6830SXin LI         "TIM ",
685fbb6830SXin LI         "TPOST ",
695fbb6830SXin LI         "TPRE ",
705fbb6830SXin LI         "TXIPS ",
715fbb6830SXin LI         "TXULP0 ",
725fbb6830SXin LI         "TXULP1 ",
735fbb6830SXin LI         "UC ",
745fbb6830SXin LI         "WDMA ",
755fbb6830SXin LI         "TXULP2 ",
765fbb6830SXin LI         "HOST1 ",
775fbb6830SXin LI         "P0_OB_LINK ",
785fbb6830SXin LI         "P1_OB_LINK ",
795fbb6830SXin LI         "HOST_GPIO ",
805fbb6830SXin LI         "MBOX ",
815fbb6830SXin LI         "AXGMAC0",
825fbb6830SXin LI         "AXGMAC1",
835fbb6830SXin LI         "JTAG",
845fbb6830SXin LI         "MPU_INTPEND"
855fbb6830SXin LI };
865fbb6830SXin LI 
875fbb6830SXin LI /* UE Status High CSR */
885fbb6830SXin LI static char *ue_status_hi_desc[] = {
895fbb6830SXin LI         "LPCMEMHOST",
905fbb6830SXin LI         "MGMT_MAC",
915fbb6830SXin LI         "PCS0ONLINE",
925fbb6830SXin LI         "MPU_IRAM",
935fbb6830SXin LI         "PCS1ONLINE",
945fbb6830SXin LI         "PCTL0",
955fbb6830SXin LI         "PCTL1",
965fbb6830SXin LI         "PMEM",
975fbb6830SXin LI         "RR",
985fbb6830SXin LI         "TXPB",
995fbb6830SXin LI         "RXPP",
1005fbb6830SXin LI         "XAUI",
1015fbb6830SXin LI         "TXP",
1025fbb6830SXin LI         "ARM",
1035fbb6830SXin LI         "IPC",
1045fbb6830SXin LI         "HOST2",
1055fbb6830SXin LI         "HOST3",
1065fbb6830SXin LI         "HOST4",
1075fbb6830SXin LI         "HOST5",
1085fbb6830SXin LI         "HOST6",
1095fbb6830SXin LI         "HOST7",
1105fbb6830SXin LI         "HOST8",
1115fbb6830SXin LI         "HOST9",
1125fbb6830SXin LI         "NETC",
1135fbb6830SXin LI         "Unknown",
1145fbb6830SXin LI         "Unknown",
1155fbb6830SXin LI         "Unknown",
1165fbb6830SXin LI         "Unknown",
1175fbb6830SXin LI         "Unknown",
1185fbb6830SXin LI         "Unknown",
1195fbb6830SXin LI         "Unknown",
1205fbb6830SXin LI         "Unknown"
1215fbb6830SXin LI };
1225fbb6830SXin LI 
123c2625e6eSJosh Paetzel struct oce_common_cqe_info{
124c2625e6eSJosh Paetzel         uint8_t vtp:1;
125c2625e6eSJosh Paetzel         uint8_t l4_cksum_pass:1;
126c2625e6eSJosh Paetzel         uint8_t ip_cksum_pass:1;
127c2625e6eSJosh Paetzel         uint8_t ipv6_frame:1;
128c2625e6eSJosh Paetzel         uint8_t qnq:1;
129c2625e6eSJosh Paetzel         uint8_t rsvd:3;
130c2625e6eSJosh Paetzel         uint8_t num_frags;
131c2625e6eSJosh Paetzel         uint16_t pkt_size;
132c2625e6eSJosh Paetzel         uint16_t vtag;
133c2625e6eSJosh Paetzel };
134c2625e6eSJosh Paetzel 
1352f345d8eSLuigi Rizzo /* Driver entry points prototypes */
1362f345d8eSLuigi Rizzo static int  oce_probe(device_t dev);
1372f345d8eSLuigi Rizzo static int  oce_attach(device_t dev);
1382f345d8eSLuigi Rizzo static int  oce_detach(device_t dev);
1392f345d8eSLuigi Rizzo static int  oce_shutdown(device_t dev);
14067fd4c9dSJustin Hibbits static int  oce_ioctl(if_t ifp, u_long command, caddr_t data);
1412f345d8eSLuigi Rizzo static void oce_init(void *xsc);
14267fd4c9dSJustin Hibbits static int  oce_multiq_start(if_t ifp, struct mbuf *m);
14367fd4c9dSJustin Hibbits static void oce_multiq_flush(if_t ifp);
1442f345d8eSLuigi Rizzo 
1452f345d8eSLuigi Rizzo /* Driver interrupt routines protypes */
1462f345d8eSLuigi Rizzo static void oce_intr(void *arg, int pending);
1472f345d8eSLuigi Rizzo static int  oce_setup_intr(POCE_SOFTC sc);
1482f345d8eSLuigi Rizzo static int  oce_fast_isr(void *arg);
1492f345d8eSLuigi Rizzo static int  oce_alloc_intr(POCE_SOFTC sc, int vector,
1502f345d8eSLuigi Rizzo 			  void (*isr) (void *arg, int pending));
1512f345d8eSLuigi Rizzo 
1522f345d8eSLuigi Rizzo /* Media callbacks prototypes */
15367fd4c9dSJustin Hibbits static void oce_media_status(if_t ifp, struct ifmediareq *req);
15467fd4c9dSJustin Hibbits static int  oce_media_change(if_t ifp);
1552f345d8eSLuigi Rizzo 
1562f345d8eSLuigi Rizzo /* Transmit routines prototypes */
1572f345d8eSLuigi Rizzo static int  oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index);
1582f345d8eSLuigi Rizzo static void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq);
159c2625e6eSJosh Paetzel static void oce_process_tx_completion(struct oce_wq *wq);
16067fd4c9dSJustin Hibbits static int  oce_multiq_transmit(if_t ifp, struct mbuf *m,
1612f345d8eSLuigi Rizzo 				 struct oce_wq *wq);
1622f345d8eSLuigi Rizzo 
1632f345d8eSLuigi Rizzo /* Receive routines prototypes */
1642f345d8eSLuigi Rizzo static int  oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
1652f345d8eSLuigi Rizzo static int  oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
166c2625e6eSJosh Paetzel static void oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe);
167c2625e6eSJosh Paetzel static void oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq);
168c2625e6eSJosh Paetzel static uint16_t oce_rq_handler_lro(void *arg);
169c2625e6eSJosh Paetzel static void oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2);
170c2625e6eSJosh Paetzel static void oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2);
171c2625e6eSJosh Paetzel static void oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m);
1722f345d8eSLuigi Rizzo 
1732f345d8eSLuigi Rizzo /* Helper function prototypes in this file */
1742f345d8eSLuigi Rizzo static int  oce_attach_ifp(POCE_SOFTC sc);
17567fd4c9dSJustin Hibbits static void oce_add_vlan(void *arg, if_t ifp, uint16_t vtag);
17667fd4c9dSJustin Hibbits static void oce_del_vlan(void *arg, if_t ifp, uint16_t vtag);
1772f345d8eSLuigi Rizzo static int  oce_vid_config(POCE_SOFTC sc);
1782f345d8eSLuigi Rizzo static void oce_mac_addr_set(POCE_SOFTC sc);
17967fd4c9dSJustin Hibbits static int  oce_handle_passthrough(if_t ifp, caddr_t data);
1802f345d8eSLuigi Rizzo static void oce_local_timer(void *arg);
1812f345d8eSLuigi Rizzo static void oce_if_deactivate(POCE_SOFTC sc);
1822f345d8eSLuigi Rizzo static void oce_if_activate(POCE_SOFTC sc);
1832f345d8eSLuigi Rizzo static void setup_max_queues_want(POCE_SOFTC sc);
1842f345d8eSLuigi Rizzo static void update_queues_got(POCE_SOFTC sc);
1859bd3250aSLuigi Rizzo static void process_link_state(POCE_SOFTC sc,
1869bd3250aSLuigi Rizzo 		 struct oce_async_cqe_link_state *acqe);
187cdaba892SXin LI static int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m);
188291a1934SXin LI static void oce_get_config(POCE_SOFTC sc);
189cdaba892SXin LI static struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete);
190c2625e6eSJosh Paetzel static void oce_read_env_variables(POCE_SOFTC sc);
191c2625e6eSJosh Paetzel 
1929bd3250aSLuigi Rizzo /* IP specific */
1939bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
1949bd3250aSLuigi Rizzo static int  oce_init_lro(POCE_SOFTC sc);
1959bd3250aSLuigi Rizzo static struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp);
1969bd3250aSLuigi Rizzo #endif
1972f345d8eSLuigi Rizzo 
1982f345d8eSLuigi Rizzo static device_method_t oce_dispatch[] = {
1992f345d8eSLuigi Rizzo 	DEVMETHOD(device_probe, oce_probe),
2002f345d8eSLuigi Rizzo 	DEVMETHOD(device_attach, oce_attach),
2012f345d8eSLuigi Rizzo 	DEVMETHOD(device_detach, oce_detach),
2022f345d8eSLuigi Rizzo 	DEVMETHOD(device_shutdown, oce_shutdown),
20361bfd867SSofian Brabez 
20461bfd867SSofian Brabez 	DEVMETHOD_END
2052f345d8eSLuigi Rizzo };
2062f345d8eSLuigi Rizzo 
2072f345d8eSLuigi Rizzo static driver_t oce_driver = {
2082f345d8eSLuigi Rizzo 	"oce",
2092f345d8eSLuigi Rizzo 	oce_dispatch,
2102f345d8eSLuigi Rizzo 	sizeof(OCE_SOFTC)
2112f345d8eSLuigi Rizzo };
2122f345d8eSLuigi Rizzo 
2132f345d8eSLuigi Rizzo /* global vars */
2142f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"};
2152f345d8eSLuigi Rizzo 
2162f345d8eSLuigi Rizzo /* Module capabilites and parameters */
2172f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED;
2182f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS;
219c2625e6eSJosh Paetzel uint32_t oce_rq_buf_size = 2048;
2202f345d8eSLuigi Rizzo 
2212f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled);
2222f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss);
2232f345d8eSLuigi Rizzo 
2242f345d8eSLuigi Rizzo /* Supported devices table */
2252f345d8eSLuigi Rizzo static uint32_t supportedDevices[] =  {
2262f345d8eSLuigi Rizzo 	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2,
2272f345d8eSLuigi Rizzo 	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3,
2282f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3,
2292f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201,
2302f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF,
231291a1934SXin LI 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH
2322f345d8eSLuigi Rizzo };
2332f345d8eSLuigi Rizzo 
2344e75e496SJohn Baldwin DRIVER_MODULE(oce, pci, oce_driver, 0, 0);
2350dc34160SWarner Losh MODULE_PNP_INFO("W32:vendor/device", pci, oce, supportedDevices,
2360dc34160SWarner Losh     nitems(supportedDevices));
2370dc34160SWarner Losh MODULE_DEPEND(oce, pci, 1, 1, 1);
2380dc34160SWarner Losh MODULE_DEPEND(oce, ether, 1, 1, 1);
2390dc34160SWarner Losh MODULE_VERSION(oce, 1);
2400dc34160SWarner Losh 
241c2625e6eSJosh Paetzel POCE_SOFTC softc_head = NULL;
242c2625e6eSJosh Paetzel POCE_SOFTC softc_tail = NULL;
2432f345d8eSLuigi Rizzo 
244c2625e6eSJosh Paetzel struct oce_rdma_if *oce_rdma_if = NULL;
2452f345d8eSLuigi Rizzo 
2462f345d8eSLuigi Rizzo /*****************************************************************************
2472f345d8eSLuigi Rizzo  *			Driver entry points functions                        *
2482f345d8eSLuigi Rizzo  *****************************************************************************/
2492f345d8eSLuigi Rizzo 
2502f345d8eSLuigi Rizzo static int
2512f345d8eSLuigi Rizzo oce_probe(device_t dev)
2522f345d8eSLuigi Rizzo {
2539bd3250aSLuigi Rizzo 	uint16_t vendor = 0;
2549bd3250aSLuigi Rizzo 	uint16_t device = 0;
2559bd3250aSLuigi Rizzo 	int i = 0;
2569bd3250aSLuigi Rizzo 	char str[256] = {0};
2572f345d8eSLuigi Rizzo 	POCE_SOFTC sc;
2582f345d8eSLuigi Rizzo 
2592f345d8eSLuigi Rizzo 	sc = device_get_softc(dev);
2602f345d8eSLuigi Rizzo 	bzero(sc, sizeof(OCE_SOFTC));
2612f345d8eSLuigi Rizzo 	sc->dev = dev;
2622f345d8eSLuigi Rizzo 
2632f345d8eSLuigi Rizzo 	vendor = pci_get_vendor(dev);
2642f345d8eSLuigi Rizzo 	device = pci_get_device(dev);
2652f345d8eSLuigi Rizzo 
2669bd3250aSLuigi Rizzo 	for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) {
2672f345d8eSLuigi Rizzo 		if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) {
2682f345d8eSLuigi Rizzo 			if (device == (supportedDevices[i] & 0xffff)) {
2699bd3250aSLuigi Rizzo 				sprintf(str, "%s:%s", "Emulex CNA NIC function",
2702f345d8eSLuigi Rizzo 					component_revision);
2712f345d8eSLuigi Rizzo 				device_set_desc_copy(dev, str);
2722f345d8eSLuigi Rizzo 
2732f345d8eSLuigi Rizzo 				switch (device) {
2742f345d8eSLuigi Rizzo 				case PCI_PRODUCT_BE2:
2752f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_BE2;
2762f345d8eSLuigi Rizzo 					break;
2772f345d8eSLuigi Rizzo 				case PCI_PRODUCT_BE3:
2782f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_BE3;
2792f345d8eSLuigi Rizzo 					break;
2802f345d8eSLuigi Rizzo 				case PCI_PRODUCT_XE201:
2812f345d8eSLuigi Rizzo 				case PCI_PRODUCT_XE201_VF:
2822f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_XE201;
2832f345d8eSLuigi Rizzo 					break;
284291a1934SXin LI 				case PCI_PRODUCT_SH:
285291a1934SXin LI 					sc->flags |= OCE_FLAGS_SH;
286291a1934SXin LI 					break;
2872f345d8eSLuigi Rizzo 				default:
2882f345d8eSLuigi Rizzo 					return ENXIO;
2892f345d8eSLuigi Rizzo 				}
2902f345d8eSLuigi Rizzo 				return BUS_PROBE_DEFAULT;
2912f345d8eSLuigi Rizzo 			}
2922f345d8eSLuigi Rizzo 		}
2932f345d8eSLuigi Rizzo 	}
2942f345d8eSLuigi Rizzo 
2952f345d8eSLuigi Rizzo 	return ENXIO;
2962f345d8eSLuigi Rizzo }
2972f345d8eSLuigi Rizzo 
2982f345d8eSLuigi Rizzo static int
2992f345d8eSLuigi Rizzo oce_attach(device_t dev)
3002f345d8eSLuigi Rizzo {
3012f345d8eSLuigi Rizzo 	POCE_SOFTC sc;
3022f345d8eSLuigi Rizzo 	int rc = 0;
3032f345d8eSLuigi Rizzo 
3042f345d8eSLuigi Rizzo 	sc = device_get_softc(dev);
3052f345d8eSLuigi Rizzo 
3062f345d8eSLuigi Rizzo 	rc = oce_hw_pci_alloc(sc);
3072f345d8eSLuigi Rizzo 	if (rc)
3082f345d8eSLuigi Rizzo 		return rc;
3092f345d8eSLuigi Rizzo 
3102f345d8eSLuigi Rizzo 	sc->tx_ring_size = OCE_TX_RING_SIZE;
3112f345d8eSLuigi Rizzo 	sc->rx_ring_size = OCE_RX_RING_SIZE;
312c2625e6eSJosh Paetzel 	/* receive fragment size should be multiple of 2K */
313c2625e6eSJosh Paetzel 	sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048);
3142f345d8eSLuigi Rizzo 	sc->flow_control = OCE_DEFAULT_FLOW_CONTROL;
3152f345d8eSLuigi Rizzo 	sc->promisc	 = OCE_DEFAULT_PROMISCUOUS;
3162f345d8eSLuigi Rizzo 
3172f345d8eSLuigi Rizzo 	LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock");
3182f345d8eSLuigi Rizzo 	LOCK_CREATE(&sc->dev_lock,  "Device_lock");
3192f345d8eSLuigi Rizzo 
3202f345d8eSLuigi Rizzo 	/* initialise the hardware */
3212f345d8eSLuigi Rizzo 	rc = oce_hw_init(sc);
3222f345d8eSLuigi Rizzo 	if (rc)
3232f345d8eSLuigi Rizzo 		goto pci_res_free;
3242f345d8eSLuigi Rizzo 
325c2625e6eSJosh Paetzel 	oce_read_env_variables(sc);
326c2625e6eSJosh Paetzel 
327291a1934SXin LI 	oce_get_config(sc);
328291a1934SXin LI 
3292f345d8eSLuigi Rizzo 	setup_max_queues_want(sc);
3302f345d8eSLuigi Rizzo 
3312f345d8eSLuigi Rizzo 	rc = oce_setup_intr(sc);
3322f345d8eSLuigi Rizzo 	if (rc)
3332f345d8eSLuigi Rizzo 		goto mbox_free;
3342f345d8eSLuigi Rizzo 
3352f345d8eSLuigi Rizzo 	rc = oce_queue_init_all(sc);
3362f345d8eSLuigi Rizzo 	if (rc)
3372f345d8eSLuigi Rizzo 		goto intr_free;
3382f345d8eSLuigi Rizzo 
3392f345d8eSLuigi Rizzo 	rc = oce_attach_ifp(sc);
3402f345d8eSLuigi Rizzo 	if (rc)
3412f345d8eSLuigi Rizzo 		goto queues_free;
3422f345d8eSLuigi Rizzo 
343ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3442f345d8eSLuigi Rizzo 	rc = oce_init_lro(sc);
3452f345d8eSLuigi Rizzo 	if (rc)
3462f345d8eSLuigi Rizzo 		goto ifp_free;
347ad512958SBjoern A. Zeeb #endif
3482f345d8eSLuigi Rizzo 
3492f345d8eSLuigi Rizzo 	rc = oce_hw_start(sc);
3502f345d8eSLuigi Rizzo 	if (rc)
351db702c59SEitan Adler 		goto lro_free;
3522f345d8eSLuigi Rizzo 
3532f345d8eSLuigi Rizzo 	sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
3542f345d8eSLuigi Rizzo 				oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST);
3552f345d8eSLuigi Rizzo 	sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
3562f345d8eSLuigi Rizzo 				oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST);
3572f345d8eSLuigi Rizzo 
3582f345d8eSLuigi Rizzo 	rc = oce_stats_init(sc);
3592f345d8eSLuigi Rizzo 	if (rc)
3602f345d8eSLuigi Rizzo 		goto vlan_free;
3612f345d8eSLuigi Rizzo 
3622f345d8eSLuigi Rizzo 	oce_add_sysctls(sc);
3632f345d8eSLuigi Rizzo 
364c2625e6eSJosh Paetzel 	callout_init(&sc->timer, CALLOUT_MPSAFE);
3652f345d8eSLuigi Rizzo 	rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc);
3662f345d8eSLuigi Rizzo 	if (rc)
3672f345d8eSLuigi Rizzo 		goto stats_free;
3682f345d8eSLuigi Rizzo 
369c2625e6eSJosh Paetzel 	sc->next =NULL;
370c2625e6eSJosh Paetzel 	if (softc_tail != NULL) {
371c2625e6eSJosh Paetzel 	  softc_tail->next = sc;
372c2625e6eSJosh Paetzel 	} else {
373c2625e6eSJosh Paetzel 	  softc_head = sc;
374c2625e6eSJosh Paetzel 	}
375c2625e6eSJosh Paetzel 	softc_tail = sc;
376c2625e6eSJosh Paetzel 
377*45913229SBrooks Davis 	gone_in_dev(dev, 15, "relatively uncommon 10GbE NIC");
378*45913229SBrooks Davis 
3792f345d8eSLuigi Rizzo 	return 0;
3802f345d8eSLuigi Rizzo 
3812f345d8eSLuigi Rizzo stats_free:
3822f345d8eSLuigi Rizzo 	callout_drain(&sc->timer);
3832f345d8eSLuigi Rizzo 	oce_stats_free(sc);
3842f345d8eSLuigi Rizzo vlan_free:
3852f345d8eSLuigi Rizzo 	if (sc->vlan_attach)
3862f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
3872f345d8eSLuigi Rizzo 	if (sc->vlan_detach)
3882f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
3892f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
3902f345d8eSLuigi Rizzo lro_free:
391ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3922f345d8eSLuigi Rizzo 	oce_free_lro(sc);
3932f345d8eSLuigi Rizzo ifp_free:
394ad512958SBjoern A. Zeeb #endif
3952f345d8eSLuigi Rizzo 	ether_ifdetach(sc->ifp);
3962f345d8eSLuigi Rizzo 	if_free(sc->ifp);
3972f345d8eSLuigi Rizzo queues_free:
3982f345d8eSLuigi Rizzo 	oce_queue_release_all(sc);
3992f345d8eSLuigi Rizzo intr_free:
4002f345d8eSLuigi Rizzo 	oce_intr_free(sc);
4012f345d8eSLuigi Rizzo mbox_free:
4022f345d8eSLuigi Rizzo 	oce_dma_free(sc, &sc->bsmbx);
4032f345d8eSLuigi Rizzo pci_res_free:
4042f345d8eSLuigi Rizzo 	oce_hw_pci_free(sc);
4052f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->dev_lock);
4062f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->bmbx_lock);
4072f345d8eSLuigi Rizzo 	return rc;
4082f345d8eSLuigi Rizzo 
4092f345d8eSLuigi Rizzo }
4102f345d8eSLuigi Rizzo 
4112f345d8eSLuigi Rizzo static int
4122f345d8eSLuigi Rizzo oce_detach(device_t dev)
4132f345d8eSLuigi Rizzo {
4142f345d8eSLuigi Rizzo 	POCE_SOFTC sc = device_get_softc(dev);
415c2625e6eSJosh Paetzel 	POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL;
416c2625e6eSJosh Paetzel 
417c2625e6eSJosh Paetzel         poce_sc_tmp = softc_head;
418c2625e6eSJosh Paetzel         ppoce_sc_tmp1 = &softc_head;
419c2625e6eSJosh Paetzel         while (poce_sc_tmp != NULL) {
420c2625e6eSJosh Paetzel           if (poce_sc_tmp == sc) {
421c2625e6eSJosh Paetzel             *ppoce_sc_tmp1 = sc->next;
422c2625e6eSJosh Paetzel             if (sc->next == NULL) {
423c2625e6eSJosh Paetzel               softc_tail = poce_sc_tmp2;
424c2625e6eSJosh Paetzel             }
425c2625e6eSJosh Paetzel             break;
426c2625e6eSJosh Paetzel           }
427c2625e6eSJosh Paetzel           poce_sc_tmp2 = poce_sc_tmp;
428c2625e6eSJosh Paetzel           ppoce_sc_tmp1 = &poce_sc_tmp->next;
429c2625e6eSJosh Paetzel           poce_sc_tmp = poce_sc_tmp->next;
430c2625e6eSJosh Paetzel         }
4312f345d8eSLuigi Rizzo 
4322f345d8eSLuigi Rizzo 	LOCK(&sc->dev_lock);
4332f345d8eSLuigi Rizzo 	oce_if_deactivate(sc);
4342f345d8eSLuigi Rizzo 	UNLOCK(&sc->dev_lock);
4352f345d8eSLuigi Rizzo 
4362f345d8eSLuigi Rizzo 	callout_drain(&sc->timer);
4372f345d8eSLuigi Rizzo 
4382f345d8eSLuigi Rizzo 	if (sc->vlan_attach != NULL)
4392f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
4402f345d8eSLuigi Rizzo 	if (sc->vlan_detach != NULL)
4412f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
4422f345d8eSLuigi Rizzo 
4432f345d8eSLuigi Rizzo 	ether_ifdetach(sc->ifp);
4442f345d8eSLuigi Rizzo 
4452f345d8eSLuigi Rizzo 	if_free(sc->ifp);
4462f345d8eSLuigi Rizzo 
4472f345d8eSLuigi Rizzo 	oce_hw_shutdown(sc);
4482f345d8eSLuigi Rizzo 
4492f345d8eSLuigi Rizzo 	bus_generic_detach(dev);
4502f345d8eSLuigi Rizzo 
4512f345d8eSLuigi Rizzo 	return 0;
4522f345d8eSLuigi Rizzo }
4532f345d8eSLuigi Rizzo 
4542f345d8eSLuigi Rizzo static int
4552f345d8eSLuigi Rizzo oce_shutdown(device_t dev)
4562f345d8eSLuigi Rizzo {
4572f345d8eSLuigi Rizzo 	int rc;
4582f345d8eSLuigi Rizzo 
4592f345d8eSLuigi Rizzo 	rc = oce_detach(dev);
4602f345d8eSLuigi Rizzo 
4612f345d8eSLuigi Rizzo 	return rc;
4622f345d8eSLuigi Rizzo }
4632f345d8eSLuigi Rizzo 
4642f345d8eSLuigi Rizzo static int
46567fd4c9dSJustin Hibbits oce_ioctl(if_t ifp, u_long command, caddr_t data)
4662f345d8eSLuigi Rizzo {
4672f345d8eSLuigi Rizzo 	struct ifreq *ifr = (struct ifreq *)data;
46867fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
469e0dd0fe3SXin LI 	struct ifi2creq i2c;
470e0dd0fe3SXin LI 	uint8_t	offset = 0;
4712f345d8eSLuigi Rizzo 	int rc = 0;
4722f345d8eSLuigi Rizzo 	uint32_t u;
4732f345d8eSLuigi Rizzo 
4742f345d8eSLuigi Rizzo 	switch (command) {
4752f345d8eSLuigi Rizzo 	case SIOCGIFMEDIA:
4762f345d8eSLuigi Rizzo 		rc = ifmedia_ioctl(ifp, ifr, &sc->media, command);
4772f345d8eSLuigi Rizzo 		break;
4782f345d8eSLuigi Rizzo 
4792f345d8eSLuigi Rizzo 	case SIOCSIFMTU:
4802f345d8eSLuigi Rizzo 		if (ifr->ifr_mtu > OCE_MAX_MTU)
4812f345d8eSLuigi Rizzo 			rc = EINVAL;
4822f345d8eSLuigi Rizzo 		else
48367fd4c9dSJustin Hibbits 			if_setmtu(ifp, ifr->ifr_mtu);
4842f345d8eSLuigi Rizzo 		break;
4852f345d8eSLuigi Rizzo 
4862f345d8eSLuigi Rizzo 	case SIOCSIFFLAGS:
48767fd4c9dSJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
48867fd4c9dSJustin Hibbits 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
48967fd4c9dSJustin Hibbits 				if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
4902f345d8eSLuigi Rizzo 				oce_init(sc);
4912f345d8eSLuigi Rizzo 			}
4922f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Interface Up\n");
4932f345d8eSLuigi Rizzo 		} else {
4942f345d8eSLuigi Rizzo 			LOCK(&sc->dev_lock);
4952f345d8eSLuigi Rizzo 
49667fd4c9dSJustin Hibbits 			if_setdrvflagbits(sc->ifp, 0,
49767fd4c9dSJustin Hibbits 			    IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
4982f345d8eSLuigi Rizzo 			oce_if_deactivate(sc);
4992f345d8eSLuigi Rizzo 
5002f345d8eSLuigi Rizzo 			UNLOCK(&sc->dev_lock);
5012f345d8eSLuigi Rizzo 
5022f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Interface Down\n");
5032f345d8eSLuigi Rizzo 		}
5042f345d8eSLuigi Rizzo 
50567fd4c9dSJustin Hibbits 		if ((if_getflags(ifp) & IFF_PROMISC) && !sc->promisc) {
5065fbb6830SXin LI 			if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1))))
5072f345d8eSLuigi Rizzo 				sc->promisc = TRUE;
50867fd4c9dSJustin Hibbits 		} else if (!(if_getflags(ifp) & IFF_PROMISC) && sc->promisc) {
5095fbb6830SXin LI 			if (!oce_rxf_set_promiscuous(sc, 0))
5102f345d8eSLuigi Rizzo 				sc->promisc = FALSE;
5112f345d8eSLuigi Rizzo 		}
5122f345d8eSLuigi Rizzo 
5132f345d8eSLuigi Rizzo 		break;
5142f345d8eSLuigi Rizzo 
5152f345d8eSLuigi Rizzo 	case SIOCADDMULTI:
5162f345d8eSLuigi Rizzo 	case SIOCDELMULTI:
5172f345d8eSLuigi Rizzo 		rc = oce_hw_update_multicast(sc);
5182f345d8eSLuigi Rizzo 		if (rc)
5192f345d8eSLuigi Rizzo 			device_printf(sc->dev,
5202f345d8eSLuigi Rizzo 				"Update multicast address failed\n");
5212f345d8eSLuigi Rizzo 		break;
5222f345d8eSLuigi Rizzo 
5232f345d8eSLuigi Rizzo 	case SIOCSIFCAP:
52467fd4c9dSJustin Hibbits 		u = ifr->ifr_reqcap ^ if_getcapenable(ifp);
5252f345d8eSLuigi Rizzo 
5262f345d8eSLuigi Rizzo 		if (u & IFCAP_TXCSUM) {
52767fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM);
52867fd4c9dSJustin Hibbits 			if_togglehwassist(ifp, (CSUM_TCP | CSUM_UDP | CSUM_IP));
5292f345d8eSLuigi Rizzo 
53067fd4c9dSJustin Hibbits 			if (IFCAP_TSO & if_getcapenable(ifp) &&
53167fd4c9dSJustin Hibbits 			    !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
532cbb9ccf7SRyan Moeller 				u &= ~IFCAP_TSO;
53367fd4c9dSJustin Hibbits 				if_setcapenablebit(ifp, 0, IFCAP_TSO);
53467fd4c9dSJustin Hibbits 				if_sethwassistbits(ifp, 0, CSUM_TSO);
5352f345d8eSLuigi Rizzo 				if_printf(ifp,
5362f345d8eSLuigi Rizzo 					 "TSO disabled due to -txcsum.\n");
5372f345d8eSLuigi Rizzo 			}
5382f345d8eSLuigi Rizzo 		}
5392f345d8eSLuigi Rizzo 
5402f345d8eSLuigi Rizzo 		if (u & IFCAP_RXCSUM)
54167fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_RXCSUM);
5422f345d8eSLuigi Rizzo 
5432f345d8eSLuigi Rizzo 		if (u & IFCAP_TSO4) {
54467fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO4);
5452f345d8eSLuigi Rizzo 
54667fd4c9dSJustin Hibbits 			if (IFCAP_TSO & if_getcapenable(ifp)) {
54767fd4c9dSJustin Hibbits 				if (IFCAP_TXCSUM & if_getcapenable(ifp))
54867fd4c9dSJustin Hibbits 					if_sethwassistbits(ifp, CSUM_TSO, 0);
5492f345d8eSLuigi Rizzo 				else {
55067fd4c9dSJustin Hibbits 					if_setcapenablebit(ifp, 0, IFCAP_TSO);
55167fd4c9dSJustin Hibbits 					if_sethwassistbits(ifp, 0, CSUM_TSO);
5522f345d8eSLuigi Rizzo 					if_printf(ifp,
5532f345d8eSLuigi Rizzo 					    "Enable txcsum first.\n");
5542f345d8eSLuigi Rizzo 					rc = EAGAIN;
5552f345d8eSLuigi Rizzo 				}
5562f345d8eSLuigi Rizzo 			} else
55767fd4c9dSJustin Hibbits 				if_sethwassistbits(ifp, 0, CSUM_TSO);
5582f345d8eSLuigi Rizzo 		}
5592f345d8eSLuigi Rizzo 
5602f345d8eSLuigi Rizzo 		if (u & IFCAP_VLAN_HWTAGGING)
56167fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
5622f345d8eSLuigi Rizzo 
5632f345d8eSLuigi Rizzo 		if (u & IFCAP_VLAN_HWFILTER) {
56467fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWFILTER);
5652f345d8eSLuigi Rizzo 			oce_vid_config(sc);
5662f345d8eSLuigi Rizzo 		}
567ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
568c2625e6eSJosh Paetzel 		if (u & IFCAP_LRO) {
56967fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_LRO);
570c2625e6eSJosh Paetzel 			if(sc->enable_hwlro) {
57167fd4c9dSJustin Hibbits 				if(if_getcapenable(ifp) & IFCAP_LRO) {
572c2625e6eSJosh Paetzel 					rc = oce_mbox_nic_set_iface_lro_config(sc, 1);
573c2625e6eSJosh Paetzel 				}else {
574c2625e6eSJosh Paetzel 					rc = oce_mbox_nic_set_iface_lro_config(sc, 0);
575c2625e6eSJosh Paetzel 				}
576c2625e6eSJosh Paetzel 			}
577c2625e6eSJosh Paetzel 		}
578ad512958SBjoern A. Zeeb #endif
5792f345d8eSLuigi Rizzo 
5802f345d8eSLuigi Rizzo 		break;
5812f345d8eSLuigi Rizzo 
582e0dd0fe3SXin LI 	case SIOCGI2C:
583e0dd0fe3SXin LI 		rc = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
584e0dd0fe3SXin LI 		if (rc)
585e0dd0fe3SXin LI 			break;
586e0dd0fe3SXin LI 
5876e7ecc9aSMark Johnston 		if (i2c.dev_addr == PAGE_NUM_A0) {
5886e7ecc9aSMark Johnston 			offset = i2c.offset;
5896e7ecc9aSMark Johnston 		} else if (i2c.dev_addr == PAGE_NUM_A2) {
5906e7ecc9aSMark Johnston 			offset = TRANSCEIVER_A0_SIZE + i2c.offset;
5916e7ecc9aSMark Johnston 		} else {
592e0dd0fe3SXin LI 			rc = EINVAL;
593e0dd0fe3SXin LI 			break;
594e0dd0fe3SXin LI 		}
595e0dd0fe3SXin LI 
5966e7ecc9aSMark Johnston 		if (i2c.len > sizeof(i2c.data) ||
5976e7ecc9aSMark Johnston 		    i2c.len + offset > sizeof(sfp_vpd_dump_buffer)) {
598e0dd0fe3SXin LI 			rc = EINVAL;
599e0dd0fe3SXin LI 			break;
600e0dd0fe3SXin LI 		}
601e0dd0fe3SXin LI 
602e0dd0fe3SXin LI 		rc = oce_mbox_read_transrecv_data(sc, i2c.dev_addr);
603e0dd0fe3SXin LI 		if (rc) {
604e0dd0fe3SXin LI 			rc = -rc;
605e0dd0fe3SXin LI 			break;
606e0dd0fe3SXin LI 		}
607e0dd0fe3SXin LI 
608e0dd0fe3SXin LI 		memcpy(&i2c.data[0], &sfp_vpd_dump_buffer[offset], i2c.len);
609e0dd0fe3SXin LI 
610e0dd0fe3SXin LI 		rc = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c));
611e0dd0fe3SXin LI 		break;
612e0dd0fe3SXin LI 
6132f345d8eSLuigi Rizzo 	case SIOCGPRIVATE_0:
614c76ddeebSMark Johnston 		rc = priv_check(curthread, PRIV_DRIVER);
615c76ddeebSMark Johnston 		if (rc != 0)
616c76ddeebSMark Johnston 			break;
6172f345d8eSLuigi Rizzo 		rc = oce_handle_passthrough(ifp, data);
6182f345d8eSLuigi Rizzo 		break;
6192f345d8eSLuigi Rizzo 	default:
6202f345d8eSLuigi Rizzo 		rc = ether_ioctl(ifp, command, data);
6212f345d8eSLuigi Rizzo 		break;
6222f345d8eSLuigi Rizzo 	}
6232f345d8eSLuigi Rizzo 
6242f345d8eSLuigi Rizzo 	return rc;
6252f345d8eSLuigi Rizzo }
6262f345d8eSLuigi Rizzo 
6272f345d8eSLuigi Rizzo static void
6282f345d8eSLuigi Rizzo oce_init(void *arg)
6292f345d8eSLuigi Rizzo {
6302f345d8eSLuigi Rizzo 	POCE_SOFTC sc = arg;
6312f345d8eSLuigi Rizzo 
6322f345d8eSLuigi Rizzo 	LOCK(&sc->dev_lock);
6332f345d8eSLuigi Rizzo 
63467fd4c9dSJustin Hibbits 	if (if_getflags(sc->ifp) & IFF_UP) {
6352f345d8eSLuigi Rizzo 		oce_if_deactivate(sc);
6362f345d8eSLuigi Rizzo 		oce_if_activate(sc);
6372f345d8eSLuigi Rizzo 	}
6382f345d8eSLuigi Rizzo 
6392f345d8eSLuigi Rizzo 	UNLOCK(&sc->dev_lock);
6402f345d8eSLuigi Rizzo 
6412f345d8eSLuigi Rizzo }
6422f345d8eSLuigi Rizzo 
6432f345d8eSLuigi Rizzo static int
64467fd4c9dSJustin Hibbits oce_multiq_start(if_t ifp, struct mbuf *m)
6452f345d8eSLuigi Rizzo {
64667fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
6472f345d8eSLuigi Rizzo 	struct oce_wq *wq = NULL;
6482f345d8eSLuigi Rizzo 	int queue_index = 0;
6492f345d8eSLuigi Rizzo 	int status = 0;
6502f345d8eSLuigi Rizzo 
651c2625e6eSJosh Paetzel 	if (!sc->link_status)
652c2625e6eSJosh Paetzel 		return ENXIO;
653c2625e6eSJosh Paetzel 
654c2529042SHans Petter Selasky 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
6552f345d8eSLuigi Rizzo 		queue_index = m->m_pkthdr.flowid % sc->nwqs;
6562f345d8eSLuigi Rizzo 
6572f345d8eSLuigi Rizzo 	wq = sc->wq[queue_index];
6582f345d8eSLuigi Rizzo 
659291a1934SXin LI 	LOCK(&wq->tx_lock);
6602f345d8eSLuigi Rizzo 	status = oce_multiq_transmit(ifp, m, wq);
6612f345d8eSLuigi Rizzo 	UNLOCK(&wq->tx_lock);
662291a1934SXin LI 
6632f345d8eSLuigi Rizzo 	return status;
6642f345d8eSLuigi Rizzo 
6652f345d8eSLuigi Rizzo }
6662f345d8eSLuigi Rizzo 
6672f345d8eSLuigi Rizzo static void
66867fd4c9dSJustin Hibbits oce_multiq_flush(if_t ifp)
6692f345d8eSLuigi Rizzo {
67067fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
6712f345d8eSLuigi Rizzo 	struct mbuf     *m;
6722f345d8eSLuigi Rizzo 	int i = 0;
6732f345d8eSLuigi Rizzo 
6742f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nwqs; i++) {
6752f345d8eSLuigi Rizzo 		while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
6762f345d8eSLuigi Rizzo 			m_freem(m);
6772f345d8eSLuigi Rizzo 	}
6782f345d8eSLuigi Rizzo 	if_qflush(ifp);
6792f345d8eSLuigi Rizzo }
6802f345d8eSLuigi Rizzo 
6812f345d8eSLuigi Rizzo /*****************************************************************************
6822f345d8eSLuigi Rizzo  *                   Driver interrupt routines functions                     *
6832f345d8eSLuigi Rizzo  *****************************************************************************/
6842f345d8eSLuigi Rizzo 
6852f345d8eSLuigi Rizzo static void
6862f345d8eSLuigi Rizzo oce_intr(void *arg, int pending)
6872f345d8eSLuigi Rizzo {
6882f345d8eSLuigi Rizzo 
6892f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
6902f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ii->sc;
6912f345d8eSLuigi Rizzo 	struct oce_eq *eq = ii->eq;
6922f345d8eSLuigi Rizzo 	struct oce_eqe *eqe;
6932f345d8eSLuigi Rizzo 	struct oce_cq *cq = NULL;
6942f345d8eSLuigi Rizzo 	int i, num_eqes = 0;
6952f345d8eSLuigi Rizzo 
6962f345d8eSLuigi Rizzo 	bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
6972f345d8eSLuigi Rizzo 				 BUS_DMASYNC_POSTWRITE);
6982f345d8eSLuigi Rizzo 	do {
6992f345d8eSLuigi Rizzo 		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
7002f345d8eSLuigi Rizzo 		if (eqe->evnt == 0)
7012f345d8eSLuigi Rizzo 			break;
7022f345d8eSLuigi Rizzo 		eqe->evnt = 0;
7032f345d8eSLuigi Rizzo 		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
7042f345d8eSLuigi Rizzo 					BUS_DMASYNC_POSTWRITE);
7052f345d8eSLuigi Rizzo 		RING_GET(eq->ring, 1);
7062f345d8eSLuigi Rizzo 		num_eqes++;
7072f345d8eSLuigi Rizzo 
7082f345d8eSLuigi Rizzo 	} while (TRUE);
7092f345d8eSLuigi Rizzo 
7102f345d8eSLuigi Rizzo 	if (!num_eqes)
7112f345d8eSLuigi Rizzo 		goto eq_arm; /* Spurious */
7122f345d8eSLuigi Rizzo 
7132f345d8eSLuigi Rizzo  	/* Clear EQ entries, but dont arm */
7142f345d8eSLuigi Rizzo 	oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
7152f345d8eSLuigi Rizzo 
7162f345d8eSLuigi Rizzo 	/* Process TX, RX and MCC. But dont arm CQ*/
7172f345d8eSLuigi Rizzo 	for (i = 0; i < eq->cq_valid; i++) {
7182f345d8eSLuigi Rizzo 		cq = eq->cq[i];
7192f345d8eSLuigi Rizzo 		(*cq->cq_handler)(cq->cb_arg);
7202f345d8eSLuigi Rizzo 	}
7212f345d8eSLuigi Rizzo 
7222f345d8eSLuigi Rizzo 	/* Arm all cqs connected to this EQ */
7232f345d8eSLuigi Rizzo 	for (i = 0; i < eq->cq_valid; i++) {
7242f345d8eSLuigi Rizzo 		cq = eq->cq[i];
7252f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, 0, TRUE);
7262f345d8eSLuigi Rizzo 	}
7272f345d8eSLuigi Rizzo 
7282f345d8eSLuigi Rizzo eq_arm:
7292f345d8eSLuigi Rizzo 	oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
730cdaba892SXin LI 
7312f345d8eSLuigi Rizzo 	return;
7322f345d8eSLuigi Rizzo }
7332f345d8eSLuigi Rizzo 
7342f345d8eSLuigi Rizzo static int
7352f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc)
7362f345d8eSLuigi Rizzo {
7372f345d8eSLuigi Rizzo 	int rc = 0, use_intx = 0;
7382f345d8eSLuigi Rizzo 	int vector = 0, req_vectors = 0;
739c2625e6eSJosh Paetzel 	int tot_req_vectors, tot_vectors;
7402f345d8eSLuigi Rizzo 
741291a1934SXin LI 	if (is_rss_enabled(sc))
7422f345d8eSLuigi Rizzo 		req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
7432f345d8eSLuigi Rizzo 	else
7442f345d8eSLuigi Rizzo 		req_vectors = 1;
7452f345d8eSLuigi Rizzo 
746c2625e6eSJosh Paetzel 	tot_req_vectors = req_vectors;
747c2625e6eSJosh Paetzel 	if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
748c2625e6eSJosh Paetzel 	  if (req_vectors > 1) {
749c2625e6eSJosh Paetzel 	    tot_req_vectors += OCE_RDMA_VECTORS;
750c2625e6eSJosh Paetzel 	    sc->roce_intr_count = OCE_RDMA_VECTORS;
751c2625e6eSJosh Paetzel 	  }
752c2625e6eSJosh Paetzel 	}
753c2625e6eSJosh Paetzel 
7542f345d8eSLuigi Rizzo         if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
7552f345d8eSLuigi Rizzo 		sc->intr_count = req_vectors;
756c2625e6eSJosh Paetzel                 tot_vectors = tot_req_vectors;
757c2625e6eSJosh Paetzel 		rc = pci_alloc_msix(sc->dev, &tot_vectors);
7582f345d8eSLuigi Rizzo 		if (rc != 0) {
7592f345d8eSLuigi Rizzo 			use_intx = 1;
7602f345d8eSLuigi Rizzo 			pci_release_msi(sc->dev);
761c2625e6eSJosh Paetzel 		} else {
762c2625e6eSJosh Paetzel 		  if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
763c2625e6eSJosh Paetzel 		    if (tot_vectors < tot_req_vectors) {
764c2625e6eSJosh Paetzel 		      if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) {
765c2625e6eSJosh Paetzel 			sc->roce_intr_count = (tot_vectors / 2);
766c2625e6eSJosh Paetzel 		      }
767c2625e6eSJosh Paetzel 		      sc->intr_count = tot_vectors - sc->roce_intr_count;
768c2625e6eSJosh Paetzel 		    }
769c2625e6eSJosh Paetzel 		  } else {
770c2625e6eSJosh Paetzel 		    sc->intr_count = tot_vectors;
771c2625e6eSJosh Paetzel 		  }
7722f345d8eSLuigi Rizzo     		  sc->flags |= OCE_FLAGS_USING_MSIX;
773c2625e6eSJosh Paetzel 		}
7742f345d8eSLuigi Rizzo 	} else
7752f345d8eSLuigi Rizzo 		use_intx = 1;
7762f345d8eSLuigi Rizzo 
7772f345d8eSLuigi Rizzo 	if (use_intx)
7782f345d8eSLuigi Rizzo 		sc->intr_count = 1;
7792f345d8eSLuigi Rizzo 
7802f345d8eSLuigi Rizzo 	/* Scale number of queues based on intr we got */
7812f345d8eSLuigi Rizzo 	update_queues_got(sc);
7822f345d8eSLuigi Rizzo 
7832f345d8eSLuigi Rizzo 	if (use_intx) {
7842f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Using legacy interrupt\n");
7852f345d8eSLuigi Rizzo 		rc = oce_alloc_intr(sc, vector, oce_intr);
7862f345d8eSLuigi Rizzo 		if (rc)
7872f345d8eSLuigi Rizzo 			goto error;
7882f345d8eSLuigi Rizzo 	} else {
7892f345d8eSLuigi Rizzo 		for (; vector < sc->intr_count; vector++) {
7902f345d8eSLuigi Rizzo 			rc = oce_alloc_intr(sc, vector, oce_intr);
7912f345d8eSLuigi Rizzo 			if (rc)
7922f345d8eSLuigi Rizzo 				goto error;
7932f345d8eSLuigi Rizzo 		}
7942f345d8eSLuigi Rizzo 	}
7952f345d8eSLuigi Rizzo 
7962f345d8eSLuigi Rizzo 	return 0;
7972f345d8eSLuigi Rizzo error:
7982f345d8eSLuigi Rizzo 	oce_intr_free(sc);
7992f345d8eSLuigi Rizzo 	return rc;
8002f345d8eSLuigi Rizzo }
8012f345d8eSLuigi Rizzo 
8022f345d8eSLuigi Rizzo static int
8032f345d8eSLuigi Rizzo oce_fast_isr(void *arg)
8042f345d8eSLuigi Rizzo {
8052f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
8062f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ii->sc;
8072f345d8eSLuigi Rizzo 
8082f345d8eSLuigi Rizzo 	if (ii->eq == NULL)
8092f345d8eSLuigi Rizzo 		return FILTER_STRAY;
8102f345d8eSLuigi Rizzo 
8112f345d8eSLuigi Rizzo 	oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
8122f345d8eSLuigi Rizzo 
813cbc4d2dbSJohn Baldwin 	taskqueue_enqueue(ii->tq, &ii->task);
8142f345d8eSLuigi Rizzo 
815cdaba892SXin LI  	ii->eq->intr++;
816cdaba892SXin LI 
8172f345d8eSLuigi Rizzo 	return FILTER_HANDLED;
8182f345d8eSLuigi Rizzo }
8192f345d8eSLuigi Rizzo 
8202f345d8eSLuigi Rizzo static int
8212f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
8222f345d8eSLuigi Rizzo {
823ab7de25cSKyle Evans 	POCE_INTR_INFO ii;
8242f345d8eSLuigi Rizzo 	int rc = 0, rr;
8252f345d8eSLuigi Rizzo 
8262f345d8eSLuigi Rizzo 	if (vector >= OCE_MAX_EQ)
8272f345d8eSLuigi Rizzo 		return (EINVAL);
8282f345d8eSLuigi Rizzo 
829ab7de25cSKyle Evans 	ii = &sc->intrs[vector];
830ab7de25cSKyle Evans 
8312f345d8eSLuigi Rizzo 	/* Set the resource id for the interrupt.
8322f345d8eSLuigi Rizzo 	 * MSIx is vector + 1 for the resource id,
8332f345d8eSLuigi Rizzo 	 * INTx is 0 for the resource id.
8342f345d8eSLuigi Rizzo 	 */
8352f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_USING_MSIX)
8362f345d8eSLuigi Rizzo 		rr = vector + 1;
8372f345d8eSLuigi Rizzo 	else
8382f345d8eSLuigi Rizzo 		rr = 0;
8392f345d8eSLuigi Rizzo 	ii->intr_res = bus_alloc_resource_any(sc->dev,
8402f345d8eSLuigi Rizzo 					      SYS_RES_IRQ,
8412f345d8eSLuigi Rizzo 					      &rr, RF_ACTIVE|RF_SHAREABLE);
8422f345d8eSLuigi Rizzo 	ii->irq_rr = rr;
8432f345d8eSLuigi Rizzo 	if (ii->intr_res == NULL) {
8442f345d8eSLuigi Rizzo 		device_printf(sc->dev,
8452f345d8eSLuigi Rizzo 			  "Could not allocate interrupt\n");
8462f345d8eSLuigi Rizzo 		rc = ENXIO;
8472f345d8eSLuigi Rizzo 		return rc;
8482f345d8eSLuigi Rizzo 	}
8492f345d8eSLuigi Rizzo 
8502f345d8eSLuigi Rizzo 	TASK_INIT(&ii->task, 0, isr, ii);
8512f345d8eSLuigi Rizzo 	ii->vector = vector;
8522f345d8eSLuigi Rizzo 	sprintf(ii->task_name, "oce_task[%d]", ii->vector);
8532f345d8eSLuigi Rizzo 	ii->tq = taskqueue_create_fast(ii->task_name,
8542f345d8eSLuigi Rizzo 			M_NOWAIT,
8552f345d8eSLuigi Rizzo 			taskqueue_thread_enqueue,
8562f345d8eSLuigi Rizzo 			&ii->tq);
8572f345d8eSLuigi Rizzo 	taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
8582f345d8eSLuigi Rizzo 			device_get_nameunit(sc->dev));
8592f345d8eSLuigi Rizzo 
8602f345d8eSLuigi Rizzo 	ii->sc = sc;
8612f345d8eSLuigi Rizzo 	rc = bus_setup_intr(sc->dev,
8622f345d8eSLuigi Rizzo 			ii->intr_res,
8632f345d8eSLuigi Rizzo 			INTR_TYPE_NET,
8642f345d8eSLuigi Rizzo 			oce_fast_isr, NULL, ii, &ii->tag);
8652f345d8eSLuigi Rizzo 	return rc;
8662f345d8eSLuigi Rizzo 
8672f345d8eSLuigi Rizzo }
8682f345d8eSLuigi Rizzo 
8692f345d8eSLuigi Rizzo void
8702f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc)
8712f345d8eSLuigi Rizzo {
8722f345d8eSLuigi Rizzo 	int i = 0;
8732f345d8eSLuigi Rizzo 
8742f345d8eSLuigi Rizzo 	for (i = 0; i < sc->intr_count; i++) {
8752f345d8eSLuigi Rizzo 
8762f345d8eSLuigi Rizzo 		if (sc->intrs[i].tag != NULL)
8772f345d8eSLuigi Rizzo 			bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
8782f345d8eSLuigi Rizzo 						sc->intrs[i].tag);
8792f345d8eSLuigi Rizzo 		if (sc->intrs[i].tq != NULL)
8802f345d8eSLuigi Rizzo 			taskqueue_free(sc->intrs[i].tq);
8812f345d8eSLuigi Rizzo 
8822f345d8eSLuigi Rizzo 		if (sc->intrs[i].intr_res != NULL)
8832f345d8eSLuigi Rizzo 			bus_release_resource(sc->dev, SYS_RES_IRQ,
8842f345d8eSLuigi Rizzo 						sc->intrs[i].irq_rr,
8852f345d8eSLuigi Rizzo 						sc->intrs[i].intr_res);
8862f345d8eSLuigi Rizzo 		sc->intrs[i].tag = NULL;
8872f345d8eSLuigi Rizzo 		sc->intrs[i].intr_res = NULL;
8882f345d8eSLuigi Rizzo 	}
8892f345d8eSLuigi Rizzo 
8902f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_USING_MSIX)
8912f345d8eSLuigi Rizzo 		pci_release_msi(sc->dev);
8922f345d8eSLuigi Rizzo 
8932f345d8eSLuigi Rizzo }
8942f345d8eSLuigi Rizzo 
8952f345d8eSLuigi Rizzo /******************************************************************************
8962f345d8eSLuigi Rizzo *			  Media callbacks functions 			      *
8972f345d8eSLuigi Rizzo ******************************************************************************/
8982f345d8eSLuigi Rizzo 
8992f345d8eSLuigi Rizzo static void
90067fd4c9dSJustin Hibbits oce_media_status(if_t ifp, struct ifmediareq *req)
9012f345d8eSLuigi Rizzo {
90267fd4c9dSJustin Hibbits 	POCE_SOFTC sc = (POCE_SOFTC) if_getsoftc(ifp);
9032f345d8eSLuigi Rizzo 
9042f345d8eSLuigi Rizzo 	req->ifm_status = IFM_AVALID;
9052f345d8eSLuigi Rizzo 	req->ifm_active = IFM_ETHER;
9062f345d8eSLuigi Rizzo 
9072f345d8eSLuigi Rizzo 	if (sc->link_status == 1)
9082f345d8eSLuigi Rizzo 		req->ifm_status |= IFM_ACTIVE;
9092f345d8eSLuigi Rizzo 	else
9102f345d8eSLuigi Rizzo 		return;
9112f345d8eSLuigi Rizzo 
9122f345d8eSLuigi Rizzo 	switch (sc->link_speed) {
9132f345d8eSLuigi Rizzo 	case 1: /* 10 Mbps */
9142f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_10_T | IFM_FDX;
9152f345d8eSLuigi Rizzo 		sc->speed = 10;
9162f345d8eSLuigi Rizzo 		break;
9172f345d8eSLuigi Rizzo 	case 2: /* 100 Mbps */
9182f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_100_TX | IFM_FDX;
9192f345d8eSLuigi Rizzo 		sc->speed = 100;
9202f345d8eSLuigi Rizzo 		break;
9212f345d8eSLuigi Rizzo 	case 3: /* 1 Gbps */
9222f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_1000_T | IFM_FDX;
9232f345d8eSLuigi Rizzo 		sc->speed = 1000;
9242f345d8eSLuigi Rizzo 		break;
9252f345d8eSLuigi Rizzo 	case 4: /* 10 Gbps */
9262f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
9272f345d8eSLuigi Rizzo 		sc->speed = 10000;
9282f345d8eSLuigi Rizzo 		break;
929a4f734b4SXin LI 	case 5: /* 20 Gbps */
930a4f734b4SXin LI 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
931a4f734b4SXin LI 		sc->speed = 20000;
932a4f734b4SXin LI 		break;
933a4f734b4SXin LI 	case 6: /* 25 Gbps */
934a4f734b4SXin LI 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
935a4f734b4SXin LI 		sc->speed = 25000;
936a4f734b4SXin LI 		break;
937b41206d8SXin LI 	case 7: /* 40 Gbps */
938b41206d8SXin LI 		req->ifm_active |= IFM_40G_SR4 | IFM_FDX;
939b41206d8SXin LI 		sc->speed = 40000;
940b41206d8SXin LI 		break;
941a4f734b4SXin LI 	default:
942a4f734b4SXin LI 		sc->speed = 0;
943a4f734b4SXin LI 		break;
9442f345d8eSLuigi Rizzo 	}
9452f345d8eSLuigi Rizzo 
9462f345d8eSLuigi Rizzo 	return;
9472f345d8eSLuigi Rizzo }
9482f345d8eSLuigi Rizzo 
9492f345d8eSLuigi Rizzo int
95067fd4c9dSJustin Hibbits oce_media_change(if_t ifp)
9512f345d8eSLuigi Rizzo {
9522f345d8eSLuigi Rizzo 	return 0;
9532f345d8eSLuigi Rizzo }
9542f345d8eSLuigi Rizzo 
955c2625e6eSJosh Paetzel static void oce_is_pkt_dest_bmc(POCE_SOFTC sc,
956c2625e6eSJosh Paetzel 				struct mbuf *m, boolean_t *os2bmc,
957c2625e6eSJosh Paetzel 				struct mbuf **m_new)
958c2625e6eSJosh Paetzel {
959c2625e6eSJosh Paetzel 	struct ether_header *eh = NULL;
960c2625e6eSJosh Paetzel 
961c2625e6eSJosh Paetzel 	eh = mtod(m, struct ether_header *);
962c2625e6eSJosh Paetzel 
963c2625e6eSJosh Paetzel 	if (!is_os2bmc_enabled(sc) || *os2bmc) {
964c2625e6eSJosh Paetzel 		*os2bmc = FALSE;
965c2625e6eSJosh Paetzel 		goto done;
966c2625e6eSJosh Paetzel 	}
967c2625e6eSJosh Paetzel 	if (!ETHER_IS_MULTICAST(eh->ether_dhost))
968c2625e6eSJosh Paetzel 		goto done;
969c2625e6eSJosh Paetzel 
970c2625e6eSJosh Paetzel 	if (is_mc_allowed_on_bmc(sc, eh) ||
971c2625e6eSJosh Paetzel 	    is_bc_allowed_on_bmc(sc, eh) ||
972c2625e6eSJosh Paetzel 	    is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) {
973c2625e6eSJosh Paetzel 		*os2bmc = TRUE;
974c2625e6eSJosh Paetzel 		goto done;
975c2625e6eSJosh Paetzel 	}
976c2625e6eSJosh Paetzel 
977c2625e6eSJosh Paetzel 	if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) {
978c2625e6eSJosh Paetzel 		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
979c2625e6eSJosh Paetzel 		uint8_t nexthdr = ip6->ip6_nxt;
980c2625e6eSJosh Paetzel 		if (nexthdr == IPPROTO_ICMPV6) {
981c2625e6eSJosh Paetzel 			struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1);
982c2625e6eSJosh Paetzel 			switch (icmp6->icmp6_type) {
983c2625e6eSJosh Paetzel 			case ND_ROUTER_ADVERT:
984c2625e6eSJosh Paetzel 				*os2bmc = is_ipv6_ra_filt_enabled(sc);
985c2625e6eSJosh Paetzel 				goto done;
986c2625e6eSJosh Paetzel 			case ND_NEIGHBOR_ADVERT:
987c2625e6eSJosh Paetzel 				*os2bmc = is_ipv6_na_filt_enabled(sc);
988c2625e6eSJosh Paetzel 				goto done;
989c2625e6eSJosh Paetzel 			default:
990c2625e6eSJosh Paetzel 				break;
991c2625e6eSJosh Paetzel 			}
992c2625e6eSJosh Paetzel 		}
993c2625e6eSJosh Paetzel 	}
994c2625e6eSJosh Paetzel 
995c2625e6eSJosh Paetzel 	if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) {
996c2625e6eSJosh Paetzel 		struct ip *ip = mtod(m, struct ip *);
997c2625e6eSJosh Paetzel 		int iphlen = ip->ip_hl << 2;
998c2625e6eSJosh Paetzel 		struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen);
999c2625e6eSJosh Paetzel 		switch (uh->uh_dport) {
1000c2625e6eSJosh Paetzel 		case DHCP_CLIENT_PORT:
1001c2625e6eSJosh Paetzel 			*os2bmc = is_dhcp_client_filt_enabled(sc);
1002c2625e6eSJosh Paetzel 			goto done;
1003c2625e6eSJosh Paetzel 		case DHCP_SERVER_PORT:
1004c2625e6eSJosh Paetzel 			*os2bmc = is_dhcp_srvr_filt_enabled(sc);
1005c2625e6eSJosh Paetzel 			goto done;
1006c2625e6eSJosh Paetzel 		case NET_BIOS_PORT1:
1007c2625e6eSJosh Paetzel 		case NET_BIOS_PORT2:
1008c2625e6eSJosh Paetzel 			*os2bmc = is_nbios_filt_enabled(sc);
1009c2625e6eSJosh Paetzel 			goto done;
1010c2625e6eSJosh Paetzel 		case DHCPV6_RAS_PORT:
1011c2625e6eSJosh Paetzel 			*os2bmc = is_ipv6_ras_filt_enabled(sc);
1012c2625e6eSJosh Paetzel 			goto done;
1013c2625e6eSJosh Paetzel 		default:
1014c2625e6eSJosh Paetzel 			break;
1015c2625e6eSJosh Paetzel 		}
1016c2625e6eSJosh Paetzel 	}
1017c2625e6eSJosh Paetzel done:
1018c2625e6eSJosh Paetzel 	if (*os2bmc) {
1019c2625e6eSJosh Paetzel 		*m_new = m_dup(m, M_NOWAIT);
1020c2625e6eSJosh Paetzel 		if (!*m_new) {
1021c2625e6eSJosh Paetzel 			*os2bmc = FALSE;
1022c2625e6eSJosh Paetzel 			return;
1023c2625e6eSJosh Paetzel 		}
1024c2625e6eSJosh Paetzel 		*m_new = oce_insert_vlan_tag(sc, *m_new, NULL);
1025c2625e6eSJosh Paetzel 	}
1026c2625e6eSJosh Paetzel }
1027c2625e6eSJosh Paetzel 
10282f345d8eSLuigi Rizzo /*****************************************************************************
10292f345d8eSLuigi Rizzo  *			  Transmit routines functions			     *
10302f345d8eSLuigi Rizzo  *****************************************************************************/
10312f345d8eSLuigi Rizzo 
10322f345d8eSLuigi Rizzo static int
10332f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
10342f345d8eSLuigi Rizzo {
10352f345d8eSLuigi Rizzo 	int rc = 0, i, retry_cnt = 0;
10362f345d8eSLuigi Rizzo 	bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
1037c2625e6eSJosh Paetzel 	struct mbuf *m, *m_temp, *m_new = NULL;
10382f345d8eSLuigi Rizzo 	struct oce_wq *wq = sc->wq[wq_index];
10392f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
10402f345d8eSLuigi Rizzo 	struct oce_nic_hdr_wqe *nichdr;
10412f345d8eSLuigi Rizzo 	struct oce_nic_frag_wqe *nicfrag;
1042c2625e6eSJosh Paetzel 	struct ether_header *eh = NULL;
10432f345d8eSLuigi Rizzo 	int num_wqes;
10442f345d8eSLuigi Rizzo 	uint32_t reg_value;
1045cdaba892SXin LI 	boolean_t complete = TRUE;
1046c2625e6eSJosh Paetzel 	boolean_t os2bmc = FALSE;
10472f345d8eSLuigi Rizzo 
10482f345d8eSLuigi Rizzo 	m = *mpp;
10492f345d8eSLuigi Rizzo 	if (!m)
10502f345d8eSLuigi Rizzo 		return EINVAL;
10512f345d8eSLuigi Rizzo 
10522f345d8eSLuigi Rizzo 	if (!(m->m_flags & M_PKTHDR)) {
10532f345d8eSLuigi Rizzo 		rc = ENXIO;
10542f345d8eSLuigi Rizzo 		goto free_ret;
10552f345d8eSLuigi Rizzo 	}
10562f345d8eSLuigi Rizzo 
1057c2625e6eSJosh Paetzel 	/* Don't allow non-TSO packets longer than MTU */
1058c2625e6eSJosh Paetzel 	if (!is_tso_pkt(m)) {
1059c2625e6eSJosh Paetzel 		eh = mtod(m, struct ether_header *);
1060c2625e6eSJosh Paetzel 		if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE))
1061c2625e6eSJosh Paetzel 			 goto free_ret;
1062c2625e6eSJosh Paetzel 	}
1063c2625e6eSJosh Paetzel 
1064cdaba892SXin LI 	if(oce_tx_asic_stall_verify(sc, m)) {
1065cdaba892SXin LI 		m = oce_insert_vlan_tag(sc, m, &complete);
1066cdaba892SXin LI 		if(!m) {
1067cdaba892SXin LI 			device_printf(sc->dev, "Insertion unsuccessful\n");
1068cdaba892SXin LI 			return 0;
1069cdaba892SXin LI 		}
1070cdaba892SXin LI 	}
1071cdaba892SXin LI 
1072c2625e6eSJosh Paetzel 	/* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less
1073c2625e6eSJosh Paetzel 	 * may cause a transmit stall on that port. So the work-around is to
1074c2625e6eSJosh Paetzel 	 * pad short packets (<= 32 bytes) to a 36-byte length.
1075c2625e6eSJosh Paetzel 	*/
1076c2625e6eSJosh Paetzel 	if(IS_SH(sc) || IS_XE201(sc) ) {
1077c2625e6eSJosh Paetzel 		if(m->m_pkthdr.len <= 32) {
1078c2625e6eSJosh Paetzel 			char buf[36];
1079c2625e6eSJosh Paetzel 			bzero((void *)buf, 36);
1080c2625e6eSJosh Paetzel 			m_append(m, (36 - m->m_pkthdr.len), buf);
1081c2625e6eSJosh Paetzel 		}
1082c2625e6eSJosh Paetzel 	}
1083c2625e6eSJosh Paetzel 
1084c2625e6eSJosh Paetzel tx_start:
10852f345d8eSLuigi Rizzo 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
10862f345d8eSLuigi Rizzo 		/* consolidate packet buffers for TSO/LSO segment offload */
10879bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
10889bd3250aSLuigi Rizzo 		m = oce_tso_setup(sc, mpp);
1089ad512958SBjoern A. Zeeb #else
1090ad512958SBjoern A. Zeeb 		m = NULL;
1091ad512958SBjoern A. Zeeb #endif
10922f345d8eSLuigi Rizzo 		if (m == NULL) {
10932f345d8eSLuigi Rizzo 			rc = ENXIO;
10942f345d8eSLuigi Rizzo 			goto free_ret;
10952f345d8eSLuigi Rizzo 		}
10962f345d8eSLuigi Rizzo 	}
10972f345d8eSLuigi Rizzo 
1098291a1934SXin LI 	pd = &wq->pckts[wq->pkt_desc_head];
1099c2625e6eSJosh Paetzel 
11002f345d8eSLuigi Rizzo retry:
11012f345d8eSLuigi Rizzo 	rc = bus_dmamap_load_mbuf_sg(wq->tag,
11022f345d8eSLuigi Rizzo 				     pd->map,
11032f345d8eSLuigi Rizzo 				     m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
11042f345d8eSLuigi Rizzo 	if (rc == 0) {
11052f345d8eSLuigi Rizzo 		num_wqes = pd->nsegs + 1;
1106291a1934SXin LI 		if (IS_BE(sc) || IS_SH(sc)) {
11072f345d8eSLuigi Rizzo 			/*Dummy required only for BE3.*/
11082f345d8eSLuigi Rizzo 			if (num_wqes & 1)
11092f345d8eSLuigi Rizzo 				num_wqes++;
11102f345d8eSLuigi Rizzo 		}
11112f345d8eSLuigi Rizzo 		if (num_wqes >= RING_NUM_FREE(wq->ring)) {
11122f345d8eSLuigi Rizzo 			bus_dmamap_unload(wq->tag, pd->map);
11132f345d8eSLuigi Rizzo 			return EBUSY;
11142f345d8eSLuigi Rizzo 		}
1115291a1934SXin LI 		atomic_store_rel_int(&wq->pkt_desc_head,
1116291a1934SXin LI 				     (wq->pkt_desc_head + 1) % \
1117291a1934SXin LI 				      OCE_WQ_PACKET_ARRAY_SIZE);
11182f345d8eSLuigi Rizzo 		bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
11192f345d8eSLuigi Rizzo 		pd->mbuf = m;
11202f345d8eSLuigi Rizzo 
11212f345d8eSLuigi Rizzo 		nichdr =
11222f345d8eSLuigi Rizzo 		    RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
11232f345d8eSLuigi Rizzo 		nichdr->u0.dw[0] = 0;
11242f345d8eSLuigi Rizzo 		nichdr->u0.dw[1] = 0;
11252f345d8eSLuigi Rizzo 		nichdr->u0.dw[2] = 0;
11262f345d8eSLuigi Rizzo 		nichdr->u0.dw[3] = 0;
11272f345d8eSLuigi Rizzo 
1128cdaba892SXin LI 		nichdr->u0.s.complete = complete;
1129c2625e6eSJosh Paetzel 		nichdr->u0.s.mgmt = os2bmc;
11302f345d8eSLuigi Rizzo 		nichdr->u0.s.event = 1;
11312f345d8eSLuigi Rizzo 		nichdr->u0.s.crc = 1;
11322f345d8eSLuigi Rizzo 		nichdr->u0.s.forward = 0;
11332f345d8eSLuigi Rizzo 		nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
11342f345d8eSLuigi Rizzo 		nichdr->u0.s.udpcs =
11352f345d8eSLuigi Rizzo 			(m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
11362f345d8eSLuigi Rizzo 		nichdr->u0.s.tcpcs =
11372f345d8eSLuigi Rizzo 			(m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
11382f345d8eSLuigi Rizzo 		nichdr->u0.s.num_wqe = num_wqes;
11392f345d8eSLuigi Rizzo 		nichdr->u0.s.total_length = m->m_pkthdr.len;
11405fbb6830SXin LI 
11412f345d8eSLuigi Rizzo 		if (m->m_flags & M_VLANTAG) {
11422f345d8eSLuigi Rizzo 			nichdr->u0.s.vlan = 1; /*Vlan present*/
11432f345d8eSLuigi Rizzo 			nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
11442f345d8eSLuigi Rizzo 		}
11455fbb6830SXin LI 
11462f345d8eSLuigi Rizzo 		if (m->m_pkthdr.csum_flags & CSUM_TSO) {
11472f345d8eSLuigi Rizzo 			if (m->m_pkthdr.tso_segsz) {
11482f345d8eSLuigi Rizzo 				nichdr->u0.s.lso = 1;
11492f345d8eSLuigi Rizzo 				nichdr->u0.s.lso_mss  = m->m_pkthdr.tso_segsz;
11502f345d8eSLuigi Rizzo 			}
1151291a1934SXin LI 			if (!IS_BE(sc) || !IS_SH(sc))
11522f345d8eSLuigi Rizzo 				nichdr->u0.s.ipcs = 1;
11532f345d8eSLuigi Rizzo 		}
11542f345d8eSLuigi Rizzo 
11552f345d8eSLuigi Rizzo 		RING_PUT(wq->ring, 1);
1156291a1934SXin LI 		atomic_add_int(&wq->ring->num_used, 1);
11572f345d8eSLuigi Rizzo 
11582f345d8eSLuigi Rizzo 		for (i = 0; i < pd->nsegs; i++) {
11592f345d8eSLuigi Rizzo 			nicfrag =
11602f345d8eSLuigi Rizzo 			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
11612f345d8eSLuigi Rizzo 						      struct oce_nic_frag_wqe);
11622f345d8eSLuigi Rizzo 			nicfrag->u0.s.rsvd0 = 0;
11632f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
11642f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
11652f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_len = segs[i].ds_len;
11662f345d8eSLuigi Rizzo 			pd->wqe_idx = wq->ring->pidx;
11672f345d8eSLuigi Rizzo 			RING_PUT(wq->ring, 1);
1168291a1934SXin LI 			atomic_add_int(&wq->ring->num_used, 1);
11692f345d8eSLuigi Rizzo 		}
11702f345d8eSLuigi Rizzo 		if (num_wqes > (pd->nsegs + 1)) {
11712f345d8eSLuigi Rizzo 			nicfrag =
11722f345d8eSLuigi Rizzo 			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
11732f345d8eSLuigi Rizzo 						      struct oce_nic_frag_wqe);
11742f345d8eSLuigi Rizzo 			nicfrag->u0.dw[0] = 0;
11752f345d8eSLuigi Rizzo 			nicfrag->u0.dw[1] = 0;
11762f345d8eSLuigi Rizzo 			nicfrag->u0.dw[2] = 0;
11772f345d8eSLuigi Rizzo 			nicfrag->u0.dw[3] = 0;
11782f345d8eSLuigi Rizzo 			pd->wqe_idx = wq->ring->pidx;
11792f345d8eSLuigi Rizzo 			RING_PUT(wq->ring, 1);
1180291a1934SXin LI 			atomic_add_int(&wq->ring->num_used, 1);
11812f345d8eSLuigi Rizzo 			pd->nsegs++;
11822f345d8eSLuigi Rizzo 		}
11832f345d8eSLuigi Rizzo 
1184c8dfaf38SGleb Smirnoff 		if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
11852f345d8eSLuigi Rizzo 		wq->tx_stats.tx_reqs++;
11862f345d8eSLuigi Rizzo 		wq->tx_stats.tx_wrbs += num_wqes;
11872f345d8eSLuigi Rizzo 		wq->tx_stats.tx_bytes += m->m_pkthdr.len;
11882f345d8eSLuigi Rizzo 		wq->tx_stats.tx_pkts++;
11892f345d8eSLuigi Rizzo 
11902f345d8eSLuigi Rizzo 		bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
11912f345d8eSLuigi Rizzo 				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11922f345d8eSLuigi Rizzo 		reg_value = (num_wqes << 16) | wq->wq_id;
1193c2625e6eSJosh Paetzel 
1194c2625e6eSJosh Paetzel 		/* if os2bmc is not enabled or if the pkt is already tagged as
1195c2625e6eSJosh Paetzel 		   bmc, do nothing
1196c2625e6eSJosh Paetzel 		 */
1197c2625e6eSJosh Paetzel 		oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new);
1198c2625e6eSJosh Paetzel 
1199b75a7728SConrad Meyer 		if_inc_counter(sc->ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
1200b75a7728SConrad Meyer 		if (m->m_flags & M_MCAST)
1201b75a7728SConrad Meyer 			if_inc_counter(sc->ifp, IFCOUNTER_OMCASTS, 1);
1202b75a7728SConrad Meyer 		ETHER_BPF_MTAP(sc->ifp, m);
1203b75a7728SConrad Meyer 
1204291a1934SXin LI 		OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value);
12052f345d8eSLuigi Rizzo 
12062f345d8eSLuigi Rizzo 	} else if (rc == EFBIG)	{
12072f345d8eSLuigi Rizzo 		if (retry_cnt == 0) {
1208c6499eccSGleb Smirnoff 			m_temp = m_defrag(m, M_NOWAIT);
12092f345d8eSLuigi Rizzo 			if (m_temp == NULL)
12102f345d8eSLuigi Rizzo 				goto free_ret;
12112f345d8eSLuigi Rizzo 			m = m_temp;
12122f345d8eSLuigi Rizzo 			*mpp = m_temp;
12132f345d8eSLuigi Rizzo 			retry_cnt = retry_cnt + 1;
12142f345d8eSLuigi Rizzo 			goto retry;
12152f345d8eSLuigi Rizzo 		} else
12162f345d8eSLuigi Rizzo 			goto free_ret;
12172f345d8eSLuigi Rizzo 	} else if (rc == ENOMEM)
12182f345d8eSLuigi Rizzo 		return rc;
12192f345d8eSLuigi Rizzo 	else
12202f345d8eSLuigi Rizzo 		goto free_ret;
12212f345d8eSLuigi Rizzo 
1222c2625e6eSJosh Paetzel 	if (os2bmc) {
1223c2625e6eSJosh Paetzel 		m = m_new;
1224c2625e6eSJosh Paetzel 		goto tx_start;
1225c2625e6eSJosh Paetzel 	}
1226c2625e6eSJosh Paetzel 
12272f345d8eSLuigi Rizzo 	return 0;
12282f345d8eSLuigi Rizzo 
12292f345d8eSLuigi Rizzo free_ret:
12302f345d8eSLuigi Rizzo 	m_freem(*mpp);
12312f345d8eSLuigi Rizzo 	*mpp = NULL;
12322f345d8eSLuigi Rizzo 	return rc;
12332f345d8eSLuigi Rizzo }
12342f345d8eSLuigi Rizzo 
12352f345d8eSLuigi Rizzo static void
1236c2625e6eSJosh Paetzel oce_process_tx_completion(struct oce_wq *wq)
12372f345d8eSLuigi Rizzo {
12382f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
12392f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
12402f345d8eSLuigi Rizzo 	struct mbuf *m;
12412f345d8eSLuigi Rizzo 
1242291a1934SXin LI 	pd = &wq->pckts[wq->pkt_desc_tail];
1243291a1934SXin LI 	atomic_store_rel_int(&wq->pkt_desc_tail,
1244291a1934SXin LI 			     (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE);
1245291a1934SXin LI 	atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1);
12462f345d8eSLuigi Rizzo 	bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
12472f345d8eSLuigi Rizzo 	bus_dmamap_unload(wq->tag, pd->map);
12482f345d8eSLuigi Rizzo 
12492f345d8eSLuigi Rizzo 	m = pd->mbuf;
12502f345d8eSLuigi Rizzo 	m_freem(m);
12512f345d8eSLuigi Rizzo 	pd->mbuf = NULL;
12522f345d8eSLuigi Rizzo 
125367fd4c9dSJustin Hibbits 	if (if_getdrvflags(sc->ifp) & IFF_DRV_OACTIVE) {
12542f345d8eSLuigi Rizzo 		if (wq->ring->num_used < (wq->ring->num_items / 2)) {
125567fd4c9dSJustin Hibbits 			if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_OACTIVE));
12562f345d8eSLuigi Rizzo 			oce_tx_restart(sc, wq);
12572f345d8eSLuigi Rizzo 		}
12582f345d8eSLuigi Rizzo 	}
12592f345d8eSLuigi Rizzo }
12602f345d8eSLuigi Rizzo 
12612f345d8eSLuigi Rizzo static void
12622f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
12632f345d8eSLuigi Rizzo {
12642f345d8eSLuigi Rizzo 
126567fd4c9dSJustin Hibbits 	if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
12662f345d8eSLuigi Rizzo 		return;
12672f345d8eSLuigi Rizzo 
12682f345d8eSLuigi Rizzo 	if (!drbr_empty(sc->ifp, wq->br))
1269cbc4d2dbSJohn Baldwin 		taskqueue_enqueue(taskqueue_swi, &wq->txtask);
12702f345d8eSLuigi Rizzo 
12712f345d8eSLuigi Rizzo }
12722f345d8eSLuigi Rizzo 
1273ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
12742f345d8eSLuigi Rizzo static struct mbuf *
12759bd3250aSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
12762f345d8eSLuigi Rizzo {
12772f345d8eSLuigi Rizzo 	struct mbuf *m;
1278ad512958SBjoern A. Zeeb #ifdef INET
12792f345d8eSLuigi Rizzo 	struct ip *ip;
1280ad512958SBjoern A. Zeeb #endif
1281ad512958SBjoern A. Zeeb #ifdef INET6
12822f345d8eSLuigi Rizzo 	struct ip6_hdr *ip6;
1283ad512958SBjoern A. Zeeb #endif
12842f345d8eSLuigi Rizzo 	struct ether_vlan_header *eh;
12852f345d8eSLuigi Rizzo 	struct tcphdr *th;
12862f345d8eSLuigi Rizzo 	uint16_t etype;
12879bd3250aSLuigi Rizzo 	int total_len = 0, ehdrlen = 0;
12882f345d8eSLuigi Rizzo 
12892f345d8eSLuigi Rizzo 	m = *mpp;
12902f345d8eSLuigi Rizzo 
12912f345d8eSLuigi Rizzo 	if (M_WRITABLE(m) == 0) {
1292c6499eccSGleb Smirnoff 		m = m_dup(*mpp, M_NOWAIT);
12932f345d8eSLuigi Rizzo 		if (!m)
12942f345d8eSLuigi Rizzo 			return NULL;
12952f345d8eSLuigi Rizzo 		m_freem(*mpp);
12962f345d8eSLuigi Rizzo 		*mpp = m;
12972f345d8eSLuigi Rizzo 	}
12982f345d8eSLuigi Rizzo 
12992f345d8eSLuigi Rizzo 	eh = mtod(m, struct ether_vlan_header *);
13002f345d8eSLuigi Rizzo 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
13012f345d8eSLuigi Rizzo 		etype = ntohs(eh->evl_proto);
13022f345d8eSLuigi Rizzo 		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
13032f345d8eSLuigi Rizzo 	} else {
13042f345d8eSLuigi Rizzo 		etype = ntohs(eh->evl_encap_proto);
13052f345d8eSLuigi Rizzo 		ehdrlen = ETHER_HDR_LEN;
13062f345d8eSLuigi Rizzo 	}
13072f345d8eSLuigi Rizzo 
13082f345d8eSLuigi Rizzo 	switch (etype) {
1309ad512958SBjoern A. Zeeb #ifdef INET
13102f345d8eSLuigi Rizzo 	case ETHERTYPE_IP:
13112f345d8eSLuigi Rizzo 		ip = (struct ip *)(m->m_data + ehdrlen);
13122f345d8eSLuigi Rizzo 		if (ip->ip_p != IPPROTO_TCP)
13132f345d8eSLuigi Rizzo 			return NULL;
13142f345d8eSLuigi Rizzo 		th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
13152f345d8eSLuigi Rizzo 
13162f345d8eSLuigi Rizzo 		total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
13172f345d8eSLuigi Rizzo 		break;
1318ad512958SBjoern A. Zeeb #endif
1319ad512958SBjoern A. Zeeb #ifdef INET6
13202f345d8eSLuigi Rizzo 	case ETHERTYPE_IPV6:
13212f345d8eSLuigi Rizzo 		ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
13222f345d8eSLuigi Rizzo 		if (ip6->ip6_nxt != IPPROTO_TCP)
13232f345d8eSLuigi Rizzo 			return NULL;
13242f345d8eSLuigi Rizzo 		th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
13252f345d8eSLuigi Rizzo 
13262f345d8eSLuigi Rizzo 		total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
13272f345d8eSLuigi Rizzo 		break;
1328ad512958SBjoern A. Zeeb #endif
13292f345d8eSLuigi Rizzo 	default:
13302f345d8eSLuigi Rizzo 		return NULL;
13312f345d8eSLuigi Rizzo 	}
13322f345d8eSLuigi Rizzo 
13332f345d8eSLuigi Rizzo 	m = m_pullup(m, total_len);
13342f345d8eSLuigi Rizzo 	*mpp = m;
13352f345d8eSLuigi Rizzo 	return m;
13362f345d8eSLuigi Rizzo }
1337ad512958SBjoern A. Zeeb #endif /* INET6 || INET */
13382f345d8eSLuigi Rizzo 
13392f345d8eSLuigi Rizzo void
13402f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending)
13412f345d8eSLuigi Rizzo {
13422f345d8eSLuigi Rizzo 	struct oce_wq *wq = arg;
13432f345d8eSLuigi Rizzo 	POCE_SOFTC sc = wq->parent;
134467fd4c9dSJustin Hibbits 	if_t ifp = sc->ifp;
13452f345d8eSLuigi Rizzo 	int rc = 0;
13462f345d8eSLuigi Rizzo 
1347291a1934SXin LI 	LOCK(&wq->tx_lock);
13482f345d8eSLuigi Rizzo 	rc = oce_multiq_transmit(ifp, NULL, wq);
13492f345d8eSLuigi Rizzo 	if (rc) {
13502f345d8eSLuigi Rizzo 		device_printf(sc->dev,
13512f345d8eSLuigi Rizzo 				"TX[%d] restart failed\n", wq->queue_index);
13522f345d8eSLuigi Rizzo 	}
13532f345d8eSLuigi Rizzo 	UNLOCK(&wq->tx_lock);
13542f345d8eSLuigi Rizzo }
13552f345d8eSLuigi Rizzo 
13562f345d8eSLuigi Rizzo void
135767fd4c9dSJustin Hibbits oce_start(if_t ifp)
13582f345d8eSLuigi Rizzo {
135967fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
13602f345d8eSLuigi Rizzo 	struct mbuf *m;
13612f345d8eSLuigi Rizzo 	int rc = 0;
13629bd3250aSLuigi Rizzo 	int def_q = 0; /* Defualt tx queue is 0*/
13632f345d8eSLuigi Rizzo 
136467fd4c9dSJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
13652f345d8eSLuigi Rizzo 			IFF_DRV_RUNNING)
13662f345d8eSLuigi Rizzo 		return;
13672f345d8eSLuigi Rizzo 
1368cdaba892SXin LI 	if (!sc->link_status)
1369cdaba892SXin LI 		return;
1370cdaba892SXin LI 
1371b75a7728SConrad Meyer 	while (true) {
137267fd4c9dSJustin Hibbits 		m = if_dequeue(sc->ifp);
13732f345d8eSLuigi Rizzo 		if (m == NULL)
13742f345d8eSLuigi Rizzo 			break;
13759bd3250aSLuigi Rizzo 
13769bd3250aSLuigi Rizzo 		LOCK(&sc->wq[def_q]->tx_lock);
13779bd3250aSLuigi Rizzo 		rc = oce_tx(sc, &m, def_q);
13789bd3250aSLuigi Rizzo 		UNLOCK(&sc->wq[def_q]->tx_lock);
13792f345d8eSLuigi Rizzo 		if (rc) {
13802f345d8eSLuigi Rizzo 			if (m != NULL) {
13819bd3250aSLuigi Rizzo 				sc->wq[def_q]->tx_stats.tx_stops ++;
138267fd4c9dSJustin Hibbits 				if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
138367fd4c9dSJustin Hibbits 				if_sendq_prepend(ifp, m);
13842f345d8eSLuigi Rizzo 				m = NULL;
13852f345d8eSLuigi Rizzo 			}
13862f345d8eSLuigi Rizzo 			break;
13872f345d8eSLuigi Rizzo 		}
1388b75a7728SConrad Meyer 	}
13892f345d8eSLuigi Rizzo }
13902f345d8eSLuigi Rizzo 
13912f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */
13922f345d8eSLuigi Rizzo uint16_t
13932f345d8eSLuigi Rizzo oce_wq_handler(void *arg)
13942f345d8eSLuigi Rizzo {
13952f345d8eSLuigi Rizzo 	struct oce_wq *wq = (struct oce_wq *)arg;
13962f345d8eSLuigi Rizzo 	POCE_SOFTC sc = wq->parent;
13972f345d8eSLuigi Rizzo 	struct oce_cq *cq = wq->cq;
13982f345d8eSLuigi Rizzo 	struct oce_nic_tx_cqe *cqe;
13992f345d8eSLuigi Rizzo 	int num_cqes = 0;
14002f345d8eSLuigi Rizzo 
1401c2625e6eSJosh Paetzel 	LOCK(&wq->tx_compl_lock);
14022f345d8eSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
14032f345d8eSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
14042f345d8eSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
14052f345d8eSLuigi Rizzo 	while (cqe->u0.dw[3]) {
14062f345d8eSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
14072f345d8eSLuigi Rizzo 
14082f345d8eSLuigi Rizzo 		wq->ring->cidx = cqe->u0.s.wqe_index + 1;
14092f345d8eSLuigi Rizzo 		if (wq->ring->cidx >= wq->ring->num_items)
14102f345d8eSLuigi Rizzo 			wq->ring->cidx -= wq->ring->num_items;
14112f345d8eSLuigi Rizzo 
1412c2625e6eSJosh Paetzel 		oce_process_tx_completion(wq);
14132f345d8eSLuigi Rizzo 		wq->tx_stats.tx_compl++;
14142f345d8eSLuigi Rizzo 		cqe->u0.dw[3] = 0;
14152f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
14162f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
14172f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
14182f345d8eSLuigi Rizzo 		cqe =
14192f345d8eSLuigi Rizzo 		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
14202f345d8eSLuigi Rizzo 		num_cqes++;
14212f345d8eSLuigi Rizzo 	}
14222f345d8eSLuigi Rizzo 
14232f345d8eSLuigi Rizzo 	if (num_cqes)
14242f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
14252f345d8eSLuigi Rizzo 
1426c2625e6eSJosh Paetzel 	UNLOCK(&wq->tx_compl_lock);
1427c2625e6eSJosh Paetzel 	return num_cqes;
14282f345d8eSLuigi Rizzo }
14292f345d8eSLuigi Rizzo 
14302f345d8eSLuigi Rizzo static int
143167fd4c9dSJustin Hibbits oce_multiq_transmit(if_t ifp, struct mbuf *m, struct oce_wq *wq)
14322f345d8eSLuigi Rizzo {
143367fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
14342f345d8eSLuigi Rizzo 	int status = 0, queue_index = 0;
14352f345d8eSLuigi Rizzo 	struct mbuf *next = NULL;
14362f345d8eSLuigi Rizzo 	struct buf_ring *br = NULL;
14372f345d8eSLuigi Rizzo 
14382f345d8eSLuigi Rizzo 	br  = wq->br;
14392f345d8eSLuigi Rizzo 	queue_index = wq->queue_index;
14402f345d8eSLuigi Rizzo 
144167fd4c9dSJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
14422f345d8eSLuigi Rizzo 		IFF_DRV_RUNNING) {
14432f345d8eSLuigi Rizzo 		if (m != NULL)
14442f345d8eSLuigi Rizzo 			status = drbr_enqueue(ifp, br, m);
14452f345d8eSLuigi Rizzo 		return status;
14462f345d8eSLuigi Rizzo 	}
14472f345d8eSLuigi Rizzo 
1448ded5ea6aSRandall Stewart 	if (m != NULL) {
14492f345d8eSLuigi Rizzo 		if ((status = drbr_enqueue(ifp, br, m)) != 0)
14502f345d8eSLuigi Rizzo 			return status;
1451ded5ea6aSRandall Stewart 	}
1452ded5ea6aSRandall Stewart 	while ((next = drbr_peek(ifp, br)) != NULL) {
14532f345d8eSLuigi Rizzo 		if (oce_tx(sc, &next, queue_index)) {
1454ded5ea6aSRandall Stewart 			if (next == NULL) {
1455ded5ea6aSRandall Stewart 				drbr_advance(ifp, br);
1456ded5ea6aSRandall Stewart 			} else {
1457ded5ea6aSRandall Stewart 				drbr_putback(ifp, br, next);
14582f345d8eSLuigi Rizzo 				wq->tx_stats.tx_stops ++;
145967fd4c9dSJustin Hibbits 				if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
14602f345d8eSLuigi Rizzo 			}
14612f345d8eSLuigi Rizzo 			break;
14622f345d8eSLuigi Rizzo 		}
1463ded5ea6aSRandall Stewart 		drbr_advance(ifp, br);
14642f345d8eSLuigi Rizzo 	}
14652f345d8eSLuigi Rizzo 
1466d398c863SLuigi Rizzo 	return 0;
14672f345d8eSLuigi Rizzo }
14682f345d8eSLuigi Rizzo 
14692f345d8eSLuigi Rizzo /*****************************************************************************
14702f345d8eSLuigi Rizzo  *			    Receive  routines functions 		     *
14712f345d8eSLuigi Rizzo  *****************************************************************************/
14722f345d8eSLuigi Rizzo 
14732f345d8eSLuigi Rizzo static void
1474c2625e6eSJosh Paetzel oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2)
14752f345d8eSLuigi Rizzo {
1476c2625e6eSJosh Paetzel 	uint32_t *p;
1477c2625e6eSJosh Paetzel         struct ether_header *eh = NULL;
1478c2625e6eSJosh Paetzel         struct tcphdr *tcp_hdr = NULL;
1479c2625e6eSJosh Paetzel         struct ip *ip4_hdr = NULL;
1480c2625e6eSJosh Paetzel         struct ip6_hdr *ip6 = NULL;
1481c2625e6eSJosh Paetzel         uint32_t payload_len = 0;
1482c2625e6eSJosh Paetzel 
1483c2625e6eSJosh Paetzel         eh = mtod(m, struct ether_header *);
1484c2625e6eSJosh Paetzel         /* correct IP header */
1485c2625e6eSJosh Paetzel         if(!cqe2->ipv6_frame) {
1486c2625e6eSJosh Paetzel 		ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header));
1487c2625e6eSJosh Paetzel                 ip4_hdr->ip_ttl = cqe2->frame_lifespan;
1488c2625e6eSJosh Paetzel                 ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header));
1489c2625e6eSJosh Paetzel                 tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip));
1490c2625e6eSJosh Paetzel         }else {
1491c2625e6eSJosh Paetzel         	ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header));
1492c2625e6eSJosh Paetzel                 ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan;
1493c2625e6eSJosh Paetzel                 payload_len = cqe2->coalesced_size - sizeof(struct ether_header)
1494c2625e6eSJosh Paetzel                                                 - sizeof(struct ip6_hdr);
1495c2625e6eSJosh Paetzel                 ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len);
1496c2625e6eSJosh Paetzel                 tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr));
1497c2625e6eSJosh Paetzel         }
1498c2625e6eSJosh Paetzel 
1499c2625e6eSJosh Paetzel         /* correct tcp header */
1500c2625e6eSJosh Paetzel         tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num);
1501c2625e6eSJosh Paetzel         if(cqe2->push) {
1502c2625e6eSJosh Paetzel         	tcp_hdr->th_flags |= TH_PUSH;
1503c2625e6eSJosh Paetzel         }
1504c2625e6eSJosh Paetzel         tcp_hdr->th_win = htons(cqe2->tcp_window);
1505c2625e6eSJosh Paetzel         tcp_hdr->th_sum = 0xffff;
1506c2625e6eSJosh Paetzel         if(cqe2->ts_opt) {
1507c2625e6eSJosh Paetzel                 p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2);
1508c2625e6eSJosh Paetzel                 *p = cqe1->tcp_timestamp_val;
1509c2625e6eSJosh Paetzel                 *(p+1) = cqe1->tcp_timestamp_ecr;
1510c2625e6eSJosh Paetzel         }
1511c2625e6eSJosh Paetzel 
1512c2625e6eSJosh Paetzel 	return;
1513c2625e6eSJosh Paetzel }
1514c2625e6eSJosh Paetzel 
1515c2625e6eSJosh Paetzel static void
1516c2625e6eSJosh Paetzel oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m)
1517c2625e6eSJosh Paetzel {
1518764c812dSJosh Paetzel 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1519c2625e6eSJosh Paetzel         uint32_t i = 0, frag_len = 0;
1520c2625e6eSJosh Paetzel 	uint32_t len = cqe_info->pkt_size;
1521c2625e6eSJosh Paetzel         struct oce_packet_desc *pd;
1522c2625e6eSJosh Paetzel         struct mbuf *tail = NULL;
1523764c812dSJosh Paetzel 
1524c2625e6eSJosh Paetzel         for (i = 0; i < cqe_info->num_frags; i++) {
1525c2625e6eSJosh Paetzel                 if (rq->ring->cidx == rq->ring->pidx) {
152614410265SConrad Meyer                         device_printf(sc->dev,
1527c2625e6eSJosh Paetzel                                   "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n");
1528c2625e6eSJosh Paetzel                         return;
152914410265SConrad Meyer                 }
1530c2625e6eSJosh Paetzel                 pd = &rq->pckts[rq->ring->cidx];
153114410265SConrad Meyer 
153214410265SConrad Meyer                 bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
153314410265SConrad Meyer                 bus_dmamap_unload(rq->tag, pd->map);
1534c2625e6eSJosh Paetzel 		RING_GET(rq->ring, 1);
153514410265SConrad Meyer                 rq->pending--;
153614410265SConrad Meyer 
153714410265SConrad Meyer                 frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
153814410265SConrad Meyer                 pd->mbuf->m_len = frag_len;
153914410265SConrad Meyer 
154014410265SConrad Meyer                 if (tail != NULL) {
154114410265SConrad Meyer                         /* additional fragments */
154214410265SConrad Meyer                         pd->mbuf->m_flags &= ~M_PKTHDR;
154314410265SConrad Meyer                         tail->m_next = pd->mbuf;
1544c2625e6eSJosh Paetzel 			if(rq->islro)
1545c2625e6eSJosh Paetzel                         	tail->m_nextpkt = NULL;
154614410265SConrad Meyer                         tail = pd->mbuf;
154714410265SConrad Meyer                 } else {
154814410265SConrad Meyer                         /* first fragment, fill out much of the packet header */
154914410265SConrad Meyer                         pd->mbuf->m_pkthdr.len = len;
1550c2625e6eSJosh Paetzel 			if(rq->islro)
1551c2625e6eSJosh Paetzel                         	pd->mbuf->m_nextpkt = NULL;
155214410265SConrad Meyer                         pd->mbuf->m_pkthdr.csum_flags = 0;
155314410265SConrad Meyer                         if (IF_CSUM_ENABLED(sc)) {
1554c2625e6eSJosh Paetzel                                 if (cqe_info->l4_cksum_pass) {
1555c2625e6eSJosh Paetzel                                         if(!cqe_info->ipv6_frame) { /* IPV4 */
155614410265SConrad Meyer                                                 pd->mbuf->m_pkthdr.csum_flags |=
155714410265SConrad Meyer                                                         (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1558c2625e6eSJosh Paetzel                                         }else { /* IPV6 frame */
1559c2625e6eSJosh Paetzel 						if(rq->islro) {
1560c2625e6eSJosh Paetzel                                                 	pd->mbuf->m_pkthdr.csum_flags |=
1561c2625e6eSJosh Paetzel                                                         (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1562c2625e6eSJosh Paetzel 						}
1563c2625e6eSJosh Paetzel                                         }
156414410265SConrad Meyer                                         pd->mbuf->m_pkthdr.csum_data = 0xffff;
156514410265SConrad Meyer                                 }
1566c2625e6eSJosh Paetzel                                 if (cqe_info->ip_cksum_pass) {
156714410265SConrad Meyer                                         pd->mbuf->m_pkthdr.csum_flags |=
156814410265SConrad Meyer                                                (CSUM_IP_CHECKED|CSUM_IP_VALID);
156914410265SConrad Meyer                                 }
157014410265SConrad Meyer                         }
1571c2625e6eSJosh Paetzel                         *m = tail = pd->mbuf;
157214410265SConrad Meyer                }
157314410265SConrad Meyer                 pd->mbuf = NULL;
157414410265SConrad Meyer                 len -= frag_len;
157514410265SConrad Meyer         }
1576764c812dSJosh Paetzel 
1577c2625e6eSJosh Paetzel         return;
1578c2625e6eSJosh Paetzel }
1579c2625e6eSJosh Paetzel 
1580c2625e6eSJosh Paetzel static void
1581c2625e6eSJosh Paetzel oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2)
1582c2625e6eSJosh Paetzel {
1583c2625e6eSJosh Paetzel         POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1584c2625e6eSJosh Paetzel         struct nic_hwlro_cqe_part1 *cqe1 = NULL;
1585c2625e6eSJosh Paetzel         struct mbuf *m = NULL;
1586c2625e6eSJosh Paetzel 	struct oce_common_cqe_info cq_info;
1587c2625e6eSJosh Paetzel 
1588c2625e6eSJosh Paetzel 	/* parse cqe */
1589c2625e6eSJosh Paetzel         if(cqe2 == NULL) {
1590c2625e6eSJosh Paetzel                 cq_info.pkt_size =  cqe->pkt_size;
1591c2625e6eSJosh Paetzel                 cq_info.vtag = cqe->vlan_tag;
1592c2625e6eSJosh Paetzel                 cq_info.l4_cksum_pass = cqe->l4_cksum_pass;
1593c2625e6eSJosh Paetzel                 cq_info.ip_cksum_pass = cqe->ip_cksum_pass;
1594c2625e6eSJosh Paetzel                 cq_info.ipv6_frame = cqe->ipv6_frame;
1595c2625e6eSJosh Paetzel                 cq_info.vtp = cqe->vtp;
1596c2625e6eSJosh Paetzel                 cq_info.qnq = cqe->qnq;
1597c2625e6eSJosh Paetzel         }else {
1598c2625e6eSJosh Paetzel                 cqe1 = (struct nic_hwlro_cqe_part1 *)cqe;
1599c2625e6eSJosh Paetzel                 cq_info.pkt_size =  cqe2->coalesced_size;
1600c2625e6eSJosh Paetzel                 cq_info.vtag = cqe2->vlan_tag;
1601c2625e6eSJosh Paetzel                 cq_info.l4_cksum_pass = cqe2->l4_cksum_pass;
1602c2625e6eSJosh Paetzel                 cq_info.ip_cksum_pass = cqe2->ip_cksum_pass;
1603c2625e6eSJosh Paetzel                 cq_info.ipv6_frame = cqe2->ipv6_frame;
1604c2625e6eSJosh Paetzel                 cq_info.vtp = cqe2->vtp;
1605c2625e6eSJosh Paetzel                 cq_info.qnq = cqe1->qnq;
1606c2625e6eSJosh Paetzel         }
1607c2625e6eSJosh Paetzel 
1608c2625e6eSJosh Paetzel 	cq_info.vtag = BSWAP_16(cq_info.vtag);
1609c2625e6eSJosh Paetzel 
1610c2625e6eSJosh Paetzel         cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size;
1611c2625e6eSJosh Paetzel         if(cq_info.pkt_size % rq->cfg.frag_size)
1612c2625e6eSJosh Paetzel                 cq_info.num_frags++;
1613c2625e6eSJosh Paetzel 
1614c2625e6eSJosh Paetzel 	oce_rx_mbuf_chain(rq, &cq_info, &m);
1615c2625e6eSJosh Paetzel 
1616764c812dSJosh Paetzel 	if (m) {
1617c2625e6eSJosh Paetzel 		if(cqe2) {
1618c2625e6eSJosh Paetzel 			//assert(cqe2->valid != 0);
1619c2625e6eSJosh Paetzel 
1620c2625e6eSJosh Paetzel 			//assert(cqe2->cqe_type != 2);
1621c2625e6eSJosh Paetzel 			oce_correct_header(m, cqe1, cqe2);
1622c2625e6eSJosh Paetzel 		}
1623c2625e6eSJosh Paetzel 
1624c2625e6eSJosh Paetzel 		m->m_pkthdr.rcvif = sc->ifp;
1625c2625e6eSJosh Paetzel 		if (rq->queue_index)
1626c2625e6eSJosh Paetzel 			m->m_pkthdr.flowid = (rq->queue_index - 1);
1627c2625e6eSJosh Paetzel 		else
1628c2625e6eSJosh Paetzel 			m->m_pkthdr.flowid = rq->queue_index;
1629c2625e6eSJosh Paetzel 		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1630a9208e98SWarner Losh 
1631c2625e6eSJosh Paetzel 		/* This deternies if vlan tag is Valid */
1632c2625e6eSJosh Paetzel 		if (cq_info.vtp) {
1633c2625e6eSJosh Paetzel 			if (sc->function_mode & FNM_FLEX10_MODE) {
1634c2625e6eSJosh Paetzel 				/* FLEX10. If QnQ is not set, neglect VLAN */
1635c2625e6eSJosh Paetzel 				if (cq_info.qnq) {
1636c2625e6eSJosh Paetzel 					m->m_pkthdr.ether_vtag = cq_info.vtag;
1637c2625e6eSJosh Paetzel 					m->m_flags |= M_VLANTAG;
1638c2625e6eSJosh Paetzel 				}
1639c2625e6eSJosh Paetzel 			} else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK))  {
1640c2625e6eSJosh Paetzel 				/* In UMC mode generally pvid will be striped by
1641c2625e6eSJosh Paetzel 				   hw. But in some cases we have seen it comes
1642c2625e6eSJosh Paetzel 				   with pvid. So if pvid == vlan, neglect vlan.
1643c2625e6eSJosh Paetzel 				 */
1644c2625e6eSJosh Paetzel 				m->m_pkthdr.ether_vtag = cq_info.vtag;
1645c2625e6eSJosh Paetzel 				m->m_flags |= M_VLANTAG;
1646c2625e6eSJosh Paetzel 			}
1647c2625e6eSJosh Paetzel 		}
1648c2625e6eSJosh Paetzel 		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1649c2625e6eSJosh Paetzel 
165067fd4c9dSJustin Hibbits 		if_input(sc->ifp, m);
1651c2625e6eSJosh Paetzel 
1652c2625e6eSJosh Paetzel 		/* Update rx stats per queue */
1653c2625e6eSJosh Paetzel 		rq->rx_stats.rx_pkts++;
1654c2625e6eSJosh Paetzel 		rq->rx_stats.rx_bytes += cq_info.pkt_size;
1655c2625e6eSJosh Paetzel 		rq->rx_stats.rx_frags += cq_info.num_frags;
1656c2625e6eSJosh Paetzel 		rq->rx_stats.rx_ucast_pkts++;
1657c2625e6eSJosh Paetzel 	}
1658c2625e6eSJosh Paetzel         return;
1659c2625e6eSJosh Paetzel }
1660c2625e6eSJosh Paetzel 
1661c2625e6eSJosh Paetzel static void
1662c2625e6eSJosh Paetzel oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
1663c2625e6eSJosh Paetzel {
1664c2625e6eSJosh Paetzel 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1665c2625e6eSJosh Paetzel 	int len;
1666c2625e6eSJosh Paetzel 	struct mbuf *m = NULL;
1667c2625e6eSJosh Paetzel 	struct oce_common_cqe_info cq_info;
1668c2625e6eSJosh Paetzel 	uint16_t vtag = 0;
1669c2625e6eSJosh Paetzel 
1670c2625e6eSJosh Paetzel 	/* Is it a flush compl that has no data */
1671c2625e6eSJosh Paetzel 	if(!cqe->u0.s.num_fragments)
1672c2625e6eSJosh Paetzel 		goto exit;
1673c2625e6eSJosh Paetzel 
1674c2625e6eSJosh Paetzel 	len = cqe->u0.s.pkt_size;
1675c2625e6eSJosh Paetzel 	if (!len) {
1676c2625e6eSJosh Paetzel 		/*partial DMA workaround for Lancer*/
1677c2625e6eSJosh Paetzel 		oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
167814410265SConrad Meyer 		goto exit;
167914410265SConrad Meyer 	}
168014410265SConrad Meyer 
1681c2625e6eSJosh Paetzel 	if (!oce_cqe_portid_valid(sc, cqe)) {
1682c2625e6eSJosh Paetzel 		oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
1683c2625e6eSJosh Paetzel 		goto exit;
1684c2625e6eSJosh Paetzel 	}
1685c2625e6eSJosh Paetzel 
1686c2625e6eSJosh Paetzel 	 /* Get vlan_tag value */
1687c2625e6eSJosh Paetzel 	if(IS_BE(sc) || IS_SH(sc))
1688c2625e6eSJosh Paetzel 		vtag = BSWAP_16(cqe->u0.s.vlan_tag);
1689c2625e6eSJosh Paetzel 	else
1690c2625e6eSJosh Paetzel 		vtag = cqe->u0.s.vlan_tag;
1691c2625e6eSJosh Paetzel 
1692c2625e6eSJosh Paetzel 	cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass;
1693c2625e6eSJosh Paetzel 	cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass;
1694c2625e6eSJosh Paetzel 	cq_info.ipv6_frame = cqe->u0.s.ip_ver;
1695c2625e6eSJosh Paetzel 	cq_info.num_frags = cqe->u0.s.num_fragments;
1696c2625e6eSJosh Paetzel 	cq_info.pkt_size = cqe->u0.s.pkt_size;
1697c2625e6eSJosh Paetzel 
1698c2625e6eSJosh Paetzel 	oce_rx_mbuf_chain(rq, &cq_info, &m);
1699c2625e6eSJosh Paetzel 
1700c2625e6eSJosh Paetzel 	if (m) {
17012f345d8eSLuigi Rizzo 		m->m_pkthdr.rcvif = sc->ifp;
1702291a1934SXin LI 		if (rq->queue_index)
1703291a1934SXin LI 			m->m_pkthdr.flowid = (rq->queue_index - 1);
1704291a1934SXin LI 		else
17052f345d8eSLuigi Rizzo 			m->m_pkthdr.flowid = rq->queue_index;
1706c2529042SHans Petter Selasky 		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1707a9208e98SWarner Losh 
17089bd3250aSLuigi Rizzo 		/* This deternies if vlan tag is Valid */
17092f345d8eSLuigi Rizzo 		if (oce_cqe_vtp_valid(sc, cqe)) {
17102f345d8eSLuigi Rizzo 			if (sc->function_mode & FNM_FLEX10_MODE) {
17119bd3250aSLuigi Rizzo 				/* FLEX10. If QnQ is not set, neglect VLAN */
17122f345d8eSLuigi Rizzo 				if (cqe->u0.s.qnq) {
17132f345d8eSLuigi Rizzo 					m->m_pkthdr.ether_vtag = vtag;
17142f345d8eSLuigi Rizzo 					m->m_flags |= M_VLANTAG;
17152f345d8eSLuigi Rizzo 				}
17169bd3250aSLuigi Rizzo 			} else if (sc->pvid != (vtag & VLAN_VID_MASK))  {
17179bd3250aSLuigi Rizzo 				/* In UMC mode generally pvid will be striped by
17189bd3250aSLuigi Rizzo 				   hw. But in some cases we have seen it comes
17199bd3250aSLuigi Rizzo 				   with pvid. So if pvid == vlan, neglect vlan.
17209bd3250aSLuigi Rizzo 				*/
17212f345d8eSLuigi Rizzo 				m->m_pkthdr.ether_vtag = vtag;
17222f345d8eSLuigi Rizzo 				m->m_flags |= M_VLANTAG;
17232f345d8eSLuigi Rizzo 			}
17242f345d8eSLuigi Rizzo 		}
17252f345d8eSLuigi Rizzo 
1726c8dfaf38SGleb Smirnoff 		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1727ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
17282f345d8eSLuigi Rizzo 		/* Try to queue to LRO */
17292f345d8eSLuigi Rizzo 		if (IF_LRO_ENABLED(sc) &&
17302f345d8eSLuigi Rizzo 		    (cqe->u0.s.ip_cksum_pass) &&
17312f345d8eSLuigi Rizzo 		    (cqe->u0.s.l4_cksum_pass) &&
17322f345d8eSLuigi Rizzo 		    (!cqe->u0.s.ip_ver)       &&
17332f345d8eSLuigi Rizzo 		    (rq->lro.lro_cnt != 0)) {
17342f345d8eSLuigi Rizzo 			if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
17352f345d8eSLuigi Rizzo 				rq->lro_pkts_queued ++;
17362f345d8eSLuigi Rizzo 				goto post_done;
17372f345d8eSLuigi Rizzo 			}
17382f345d8eSLuigi Rizzo 			/* If LRO posting fails then try to post to STACK */
17392f345d8eSLuigi Rizzo 		}
1740ad512958SBjoern A. Zeeb #endif
17412f345d8eSLuigi Rizzo 
174267fd4c9dSJustin Hibbits 		if_input(sc->ifp, m);
1743ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
17442f345d8eSLuigi Rizzo post_done:
1745ad512958SBjoern A. Zeeb #endif
17462f345d8eSLuigi Rizzo 		/* Update rx stats per queue */
17472f345d8eSLuigi Rizzo 		rq->rx_stats.rx_pkts++;
17482f345d8eSLuigi Rizzo 		rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
17492f345d8eSLuigi Rizzo 		rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
17502f345d8eSLuigi Rizzo 		if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
17512f345d8eSLuigi Rizzo 			rq->rx_stats.rx_mcast_pkts++;
17522f345d8eSLuigi Rizzo 		if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
17532f345d8eSLuigi Rizzo 			rq->rx_stats.rx_ucast_pkts++;
17542f345d8eSLuigi Rizzo 	}
17552f345d8eSLuigi Rizzo exit:
17562f345d8eSLuigi Rizzo 	return;
17572f345d8eSLuigi Rizzo }
17582f345d8eSLuigi Rizzo 
1759c2625e6eSJosh Paetzel void
1760c2625e6eSJosh Paetzel oce_discard_rx_comp(struct oce_rq *rq, int num_frags)
17612f345d8eSLuigi Rizzo {
1762c2625e6eSJosh Paetzel 	uint32_t i = 0;
17632f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
17642f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
17652f345d8eSLuigi Rizzo 
17662f345d8eSLuigi Rizzo 	for (i = 0; i < num_frags; i++) {
1767c2625e6eSJosh Paetzel                 if (rq->ring->cidx == rq->ring->pidx) {
17682f345d8eSLuigi Rizzo                         device_printf(sc->dev,
1769c2625e6eSJosh Paetzel                                 "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n");
1770c2625e6eSJosh Paetzel                         return;
17712f345d8eSLuigi Rizzo                 }
1772c2625e6eSJosh Paetzel                 pd = &rq->pckts[rq->ring->cidx];
17732f345d8eSLuigi Rizzo                 bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
17742f345d8eSLuigi Rizzo                 bus_dmamap_unload(rq->tag, pd->map);
1775c2625e6eSJosh Paetzel                 if (pd->mbuf != NULL) {
17762f345d8eSLuigi Rizzo                         m_freem(pd->mbuf);
1777c2625e6eSJosh Paetzel                         pd->mbuf = NULL;
17782f345d8eSLuigi Rizzo                 }
17792f345d8eSLuigi Rizzo 
1780c2625e6eSJosh Paetzel 		RING_GET(rq->ring, 1);
1781c2625e6eSJosh Paetzel                 rq->pending--;
1782c2625e6eSJosh Paetzel 	}
17832f345d8eSLuigi Rizzo }
17842f345d8eSLuigi Rizzo 
17852f345d8eSLuigi Rizzo static int
17862f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
17872f345d8eSLuigi Rizzo {
17882f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe_v1 *cqe_v1;
17892f345d8eSLuigi Rizzo 	int vtp = 0;
17902f345d8eSLuigi Rizzo 
17912f345d8eSLuigi Rizzo 	if (sc->be3_native) {
17922f345d8eSLuigi Rizzo 		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
17932f345d8eSLuigi Rizzo 		vtp =  cqe_v1->u0.s.vlan_tag_present;
17949bd3250aSLuigi Rizzo 	} else
17952f345d8eSLuigi Rizzo 		vtp = cqe->u0.s.vlan_tag_present;
17962f345d8eSLuigi Rizzo 
17972f345d8eSLuigi Rizzo 	return vtp;
17982f345d8eSLuigi Rizzo 
17992f345d8eSLuigi Rizzo }
18002f345d8eSLuigi Rizzo 
18012f345d8eSLuigi Rizzo static int
18022f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
18032f345d8eSLuigi Rizzo {
18042f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe_v1 *cqe_v1;
18052f345d8eSLuigi Rizzo 	int port_id = 0;
18062f345d8eSLuigi Rizzo 
1807291a1934SXin LI 	if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) {
18082f345d8eSLuigi Rizzo 		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
18092f345d8eSLuigi Rizzo 		port_id =  cqe_v1->u0.s.port;
18102f345d8eSLuigi Rizzo 		if (sc->port_id != port_id)
18112f345d8eSLuigi Rizzo 			return 0;
18122f345d8eSLuigi Rizzo 	} else
18132f345d8eSLuigi Rizzo 		;/* For BE3 legacy and Lancer this is dummy */
18142f345d8eSLuigi Rizzo 
18152f345d8eSLuigi Rizzo 	return 1;
18162f345d8eSLuigi Rizzo 
18172f345d8eSLuigi Rizzo }
18182f345d8eSLuigi Rizzo 
1819ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
1820c2625e6eSJosh Paetzel void
18212f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq)
18222f345d8eSLuigi Rizzo {
18232f345d8eSLuigi Rizzo 	struct lro_ctrl	*lro = &rq->lro;
18242f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
18252f345d8eSLuigi Rizzo 
18262f345d8eSLuigi Rizzo 	if (!IF_LRO_ENABLED(sc))
18272f345d8eSLuigi Rizzo 		return;
18282f345d8eSLuigi Rizzo 
18296dd38b87SSepherosa Ziehau 	tcp_lro_flush_all(lro);
18302f345d8eSLuigi Rizzo 	rq->lro_pkts_queued = 0;
18312f345d8eSLuigi Rizzo 
18322f345d8eSLuigi Rizzo 	return;
18332f345d8eSLuigi Rizzo }
18342f345d8eSLuigi Rizzo 
18352f345d8eSLuigi Rizzo static int
18362f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc)
18372f345d8eSLuigi Rizzo {
18382f345d8eSLuigi Rizzo 	struct lro_ctrl *lro = NULL;
18392f345d8eSLuigi Rizzo 	int i = 0, rc = 0;
18402f345d8eSLuigi Rizzo 
18412f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nrqs; i++) {
18422f345d8eSLuigi Rizzo 		lro = &sc->rq[i]->lro;
18432f345d8eSLuigi Rizzo 		rc = tcp_lro_init(lro);
18442f345d8eSLuigi Rizzo 		if (rc != 0) {
18452f345d8eSLuigi Rizzo 			device_printf(sc->dev, "LRO init failed\n");
18462f345d8eSLuigi Rizzo 			return rc;
18472f345d8eSLuigi Rizzo 		}
18482f345d8eSLuigi Rizzo 		lro->ifp = sc->ifp;
18492f345d8eSLuigi Rizzo 	}
18502f345d8eSLuigi Rizzo 
18512f345d8eSLuigi Rizzo 	return rc;
18522f345d8eSLuigi Rizzo }
18539bd3250aSLuigi Rizzo 
18542f345d8eSLuigi Rizzo void
18552f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc)
18562f345d8eSLuigi Rizzo {
18572f345d8eSLuigi Rizzo 	struct lro_ctrl *lro = NULL;
18582f345d8eSLuigi Rizzo 	int i = 0;
18592f345d8eSLuigi Rizzo 
18602f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nrqs; i++) {
18612f345d8eSLuigi Rizzo 		lro = &sc->rq[i]->lro;
18622f345d8eSLuigi Rizzo 		if (lro)
18632f345d8eSLuigi Rizzo 			tcp_lro_free(lro);
18642f345d8eSLuigi Rizzo 	}
18652f345d8eSLuigi Rizzo }
1866cdaba892SXin LI #endif
18672f345d8eSLuigi Rizzo 
18682f345d8eSLuigi Rizzo int
18692f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count)
18702f345d8eSLuigi Rizzo {
18712f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
187219c099a8SJohn Baldwin 	int i, rc;
18732f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
18742f345d8eSLuigi Rizzo 	bus_dma_segment_t segs[6];
18752f345d8eSLuigi Rizzo 	int nsegs, added = 0;
18762f345d8eSLuigi Rizzo 	struct oce_nic_rqe *rqe;
18772f345d8eSLuigi Rizzo 	pd_rxulp_db_t rxdb_reg;
1878c2625e6eSJosh Paetzel 	uint32_t val = 0;
1879c2625e6eSJosh Paetzel 	uint32_t oce_max_rq_posts = 64;
18802f345d8eSLuigi Rizzo 
1881cdaba892SXin LI 	bzero(&rxdb_reg, sizeof(pd_rxulp_db_t));
18822f345d8eSLuigi Rizzo 	for (i = 0; i < count; i++) {
1883c2625e6eSJosh Paetzel 		pd = &rq->pckts[rq->ring->pidx];
1884c2625e6eSJosh Paetzel 		pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size);
1885c2625e6eSJosh Paetzel 		if (pd->mbuf == NULL) {
1886c2625e6eSJosh Paetzel 			device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size);
18872f345d8eSLuigi Rizzo 			break;
1888c2625e6eSJosh Paetzel 		}
1889c2625e6eSJosh Paetzel 		pd->mbuf->m_nextpkt = NULL;
18902f345d8eSLuigi Rizzo 
1891c2625e6eSJosh Paetzel 		pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size;
1892c2625e6eSJosh Paetzel 
18932f345d8eSLuigi Rizzo 		rc = bus_dmamap_load_mbuf_sg(rq->tag,
18942f345d8eSLuigi Rizzo 					     pd->map,
18952f345d8eSLuigi Rizzo 					     pd->mbuf,
18962f345d8eSLuigi Rizzo 					     segs, &nsegs, BUS_DMA_NOWAIT);
18972f345d8eSLuigi Rizzo 		if (rc) {
18982f345d8eSLuigi Rizzo 			m_free(pd->mbuf);
1899c2625e6eSJosh Paetzel 			device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc);
19002f345d8eSLuigi Rizzo 			break;
19012f345d8eSLuigi Rizzo 		}
19022f345d8eSLuigi Rizzo 
19032f345d8eSLuigi Rizzo 		if (nsegs != 1) {
19042f345d8eSLuigi Rizzo 			i--;
19052f345d8eSLuigi Rizzo 			continue;
19062f345d8eSLuigi Rizzo 		}
19072f345d8eSLuigi Rizzo 
19082f345d8eSLuigi Rizzo 		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
19092f345d8eSLuigi Rizzo 
19102f345d8eSLuigi Rizzo 		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
19112f345d8eSLuigi Rizzo 		rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
19122f345d8eSLuigi Rizzo 		rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
19132f345d8eSLuigi Rizzo 		DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
19142f345d8eSLuigi Rizzo 		RING_PUT(rq->ring, 1);
19152f345d8eSLuigi Rizzo 		added++;
19162f345d8eSLuigi Rizzo 		rq->pending++;
19172f345d8eSLuigi Rizzo 	}
1918c2625e6eSJosh Paetzel 	oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS;
19192f345d8eSLuigi Rizzo 	if (added != 0) {
1920c2625e6eSJosh Paetzel 		for (i = added / oce_max_rq_posts; i > 0; i--) {
1921c2625e6eSJosh Paetzel 			rxdb_reg.bits.num_posted = oce_max_rq_posts;
19222f345d8eSLuigi Rizzo 			rxdb_reg.bits.qid = rq->rq_id;
1923c2625e6eSJosh Paetzel 			if(rq->islro) {
1924c2625e6eSJosh Paetzel                                 val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1925c2625e6eSJosh Paetzel                                 val |= oce_max_rq_posts << 16;
1926c2625e6eSJosh Paetzel                                 OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
1927c2625e6eSJosh Paetzel 			}else {
19282f345d8eSLuigi Rizzo 				OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1929c2625e6eSJosh Paetzel 			}
1930c2625e6eSJosh Paetzel 			added -= oce_max_rq_posts;
19312f345d8eSLuigi Rizzo 		}
19322f345d8eSLuigi Rizzo 		if (added > 0) {
19332f345d8eSLuigi Rizzo 			rxdb_reg.bits.qid = rq->rq_id;
19342f345d8eSLuigi Rizzo 			rxdb_reg.bits.num_posted = added;
1935c2625e6eSJosh Paetzel 			if(rq->islro) {
1936c2625e6eSJosh Paetzel                                 val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1937c2625e6eSJosh Paetzel                                 val |= added << 16;
1938c2625e6eSJosh Paetzel                                 OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
1939c2625e6eSJosh Paetzel 			}else {
19402f345d8eSLuigi Rizzo 				OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
19412f345d8eSLuigi Rizzo 			}
19422f345d8eSLuigi Rizzo 		}
1943c2625e6eSJosh Paetzel 	}
19442f345d8eSLuigi Rizzo 
19452f345d8eSLuigi Rizzo 	return 0;
19462f345d8eSLuigi Rizzo }
19472f345d8eSLuigi Rizzo 
1948c2625e6eSJosh Paetzel static void
1949c2625e6eSJosh Paetzel oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq)
1950c2625e6eSJosh Paetzel {
1951c2625e6eSJosh Paetzel         if (num_cqes) {
1952c2625e6eSJosh Paetzel                 oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE);
1953c2625e6eSJosh Paetzel 		if(!sc->enable_hwlro) {
1954c2625e6eSJosh Paetzel 			if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1)
1955c2625e6eSJosh Paetzel 				oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1));
1956c2625e6eSJosh Paetzel 		}else {
1957c2625e6eSJosh Paetzel                 	if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64)
1958c2625e6eSJosh Paetzel                         	oce_alloc_rx_bufs(rq, 64);
1959c2625e6eSJosh Paetzel         	}
1960c2625e6eSJosh Paetzel 	}
1961c2625e6eSJosh Paetzel 
1962c2625e6eSJosh Paetzel         return;
1963c2625e6eSJosh Paetzel }
1964c2625e6eSJosh Paetzel 
1965c2625e6eSJosh Paetzel uint16_t
1966c2625e6eSJosh Paetzel oce_rq_handler_lro(void *arg)
1967c2625e6eSJosh Paetzel {
1968c2625e6eSJosh Paetzel         struct oce_rq *rq = (struct oce_rq *)arg;
1969c2625e6eSJosh Paetzel         struct oce_cq *cq = rq->cq;
1970c2625e6eSJosh Paetzel         POCE_SOFTC sc = rq->parent;
1971c2625e6eSJosh Paetzel         struct nic_hwlro_singleton_cqe *cqe;
1972c2625e6eSJosh Paetzel         struct nic_hwlro_cqe_part2 *cqe2;
1973c2625e6eSJosh Paetzel         int num_cqes = 0;
1974c2625e6eSJosh Paetzel 
1975c2625e6eSJosh Paetzel 	LOCK(&rq->rx_lock);
1976c2625e6eSJosh Paetzel         bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1977c2625e6eSJosh Paetzel         cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
1978c2625e6eSJosh Paetzel         while (cqe->valid) {
1979c2625e6eSJosh Paetzel                 if(cqe->cqe_type == 0) { /* singleton cqe */
1980c2625e6eSJosh Paetzel 			/* we should not get singleton cqe after cqe1 on same rq */
1981c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart != NULL) {
1982c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got singleton cqe after cqe1 \n");
1983c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
1984c2625e6eSJosh Paetzel 			}
1985c2625e6eSJosh Paetzel                         if(cqe->error != 0) {
1986c2625e6eSJosh Paetzel                                 rq->rx_stats.rxcp_err++;
1987c2625e6eSJosh Paetzel 				if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
1988c2625e6eSJosh Paetzel                         }
1989c2625e6eSJosh Paetzel                         oce_rx_lro(rq, cqe, NULL);
1990c2625e6eSJosh Paetzel                         rq->rx_stats.rx_compl++;
1991c2625e6eSJosh Paetzel                         cqe->valid = 0;
1992c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
1993c2625e6eSJosh Paetzel                         num_cqes++;
1994c2625e6eSJosh Paetzel                         if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
1995c2625e6eSJosh Paetzel                                 break;
1996c2625e6eSJosh Paetzel                 }else if(cqe->cqe_type == 0x1) { /* first part */
1997c2625e6eSJosh Paetzel 			/* we should not get cqe1 after cqe1 on same rq */
1998c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart != NULL) {
1999c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got cqe1 after cqe1 \n");
2000c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
2001c2625e6eSJosh Paetzel 			}
2002c2625e6eSJosh Paetzel 			rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe;
2003c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
2004c2625e6eSJosh Paetzel                 }else if(cqe->cqe_type == 0x2) { /* second part */
2005c2625e6eSJosh Paetzel 			cqe2 = (struct nic_hwlro_cqe_part2 *)cqe;
2006c2625e6eSJosh Paetzel                         if(cqe2->error != 0) {
2007c2625e6eSJosh Paetzel                                 rq->rx_stats.rxcp_err++;
2008c2625e6eSJosh Paetzel 				if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
2009c2625e6eSJosh Paetzel                         }
2010c2625e6eSJosh Paetzel 			/* We should not get cqe2 without cqe1 */
2011c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart == NULL) {
2012c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got cqe2 without cqe1 \n");
2013c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
2014c2625e6eSJosh Paetzel 			}
2015c2625e6eSJosh Paetzel                         oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2);
2016c2625e6eSJosh Paetzel 
2017c2625e6eSJosh Paetzel                         rq->rx_stats.rx_compl++;
2018c2625e6eSJosh Paetzel                         rq->cqe_firstpart->valid = 0;
2019c2625e6eSJosh Paetzel                         cqe2->valid = 0;
2020c2625e6eSJosh Paetzel 			rq->cqe_firstpart = NULL;
2021c2625e6eSJosh Paetzel 
2022c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
2023c2625e6eSJosh Paetzel                         num_cqes += 2;
2024c2625e6eSJosh Paetzel                         if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
2025c2625e6eSJosh Paetzel                                 break;
2026c2625e6eSJosh Paetzel 		}
2027c2625e6eSJosh Paetzel 
2028c2625e6eSJosh Paetzel                 bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2029c2625e6eSJosh Paetzel                 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
2030c2625e6eSJosh Paetzel         }
2031c2625e6eSJosh Paetzel 	oce_check_rx_bufs(sc, num_cqes, rq);
2032c2625e6eSJosh Paetzel exit_rq_handler_lro:
2033c2625e6eSJosh Paetzel 	UNLOCK(&rq->rx_lock);
2034c2625e6eSJosh Paetzel 	return 0;
2035c2625e6eSJosh Paetzel }
20362f345d8eSLuigi Rizzo 
20372f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */
20382f345d8eSLuigi Rizzo uint16_t
20392f345d8eSLuigi Rizzo oce_rq_handler(void *arg)
20402f345d8eSLuigi Rizzo {
2041e363f832SMichael Tuexen 	struct epoch_tracker et;
20422f345d8eSLuigi Rizzo 	struct oce_rq *rq = (struct oce_rq *)arg;
20432f345d8eSLuigi Rizzo 	struct oce_cq *cq = rq->cq;
20442f345d8eSLuigi Rizzo 	POCE_SOFTC sc = rq->parent;
20452f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe *cqe;
2046c2625e6eSJosh Paetzel 	int num_cqes = 0;
20472f345d8eSLuigi Rizzo 
2048e363f832SMichael Tuexen 	NET_EPOCH_ENTER(et);
2049c2625e6eSJosh Paetzel 	if(rq->islro) {
2050c2625e6eSJosh Paetzel 		oce_rq_handler_lro(arg);
2051e363f832SMichael Tuexen 		NET_EPOCH_EXIT(et);
2052c2625e6eSJosh Paetzel 		return 0;
2053c2625e6eSJosh Paetzel 	}
2054c2625e6eSJosh Paetzel 	LOCK(&rq->rx_lock);
20552f345d8eSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
20562f345d8eSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
20572f345d8eSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
20582f345d8eSLuigi Rizzo 	while (cqe->u0.dw[2]) {
20592f345d8eSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
20602f345d8eSLuigi Rizzo 
20612f345d8eSLuigi Rizzo 		if (cqe->u0.s.error == 0) {
2062c2625e6eSJosh Paetzel 			oce_rx(rq, cqe);
20632f345d8eSLuigi Rizzo 		} else {
20642f345d8eSLuigi Rizzo 			rq->rx_stats.rxcp_err++;
2065c8dfaf38SGleb Smirnoff 			if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
20662f345d8eSLuigi Rizzo 			/* Post L3/L4 errors to stack.*/
2067c2625e6eSJosh Paetzel 			oce_rx(rq, cqe);
20682f345d8eSLuigi Rizzo 		}
20692f345d8eSLuigi Rizzo 		rq->rx_stats.rx_compl++;
20702f345d8eSLuigi Rizzo 		cqe->u0.dw[2] = 0;
20712f345d8eSLuigi Rizzo 
2072ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
20732f345d8eSLuigi Rizzo 		if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
20742f345d8eSLuigi Rizzo 			oce_rx_flush_lro(rq);
20752f345d8eSLuigi Rizzo 		}
2076ad512958SBjoern A. Zeeb #endif
20772f345d8eSLuigi Rizzo 
20782f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
20792f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
20802f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
20812f345d8eSLuigi Rizzo 		cqe =
20822f345d8eSLuigi Rizzo 		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
20832f345d8eSLuigi Rizzo 		num_cqes++;
20842f345d8eSLuigi Rizzo 		if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
20852f345d8eSLuigi Rizzo 			break;
20862f345d8eSLuigi Rizzo 	}
20879bd3250aSLuigi Rizzo 
2088ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
20892f345d8eSLuigi Rizzo         if (IF_LRO_ENABLED(sc))
20902f345d8eSLuigi Rizzo                 oce_rx_flush_lro(rq);
2091ad512958SBjoern A. Zeeb #endif
20922f345d8eSLuigi Rizzo 
2093c2625e6eSJosh Paetzel 	oce_check_rx_bufs(sc, num_cqes, rq);
2094c2625e6eSJosh Paetzel 	UNLOCK(&rq->rx_lock);
2095e363f832SMichael Tuexen 	NET_EPOCH_EXIT(et);
20962f345d8eSLuigi Rizzo 	return 0;
20972f345d8eSLuigi Rizzo 
20982f345d8eSLuigi Rizzo }
20992f345d8eSLuigi Rizzo 
21002f345d8eSLuigi Rizzo /*****************************************************************************
21012f345d8eSLuigi Rizzo  *		   Helper function prototypes in this file 		     *
21022f345d8eSLuigi Rizzo  *****************************************************************************/
21032f345d8eSLuigi Rizzo 
21042f345d8eSLuigi Rizzo static int
21052f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc)
21062f345d8eSLuigi Rizzo {
21072f345d8eSLuigi Rizzo 
21082f345d8eSLuigi Rizzo 	sc->ifp = if_alloc(IFT_ETHER);
21092f345d8eSLuigi Rizzo 	if (!sc->ifp)
21102f345d8eSLuigi Rizzo 		return ENOMEM;
21112f345d8eSLuigi Rizzo 
21122f345d8eSLuigi Rizzo 	ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
21132f345d8eSLuigi Rizzo 	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
21142f345d8eSLuigi Rizzo 	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
21152f345d8eSLuigi Rizzo 
2116a6b55ee6SGleb Smirnoff 	if_setflags(sc->ifp, IFF_BROADCAST | IFF_MULTICAST);
211767fd4c9dSJustin Hibbits 	if_setioctlfn(sc->ifp, oce_ioctl);
211867fd4c9dSJustin Hibbits 	if_setstartfn(sc->ifp, oce_start);
211967fd4c9dSJustin Hibbits 	if_setinitfn(sc->ifp, oce_init);
212067fd4c9dSJustin Hibbits 	if_setmtu(sc->ifp, ETHERMTU);
212167fd4c9dSJustin Hibbits 	if_setsoftc(sc->ifp, sc);
212267fd4c9dSJustin Hibbits 	if_settransmitfn(sc->ifp, oce_multiq_start);
212367fd4c9dSJustin Hibbits 	if_setqflushfn(sc->ifp, oce_multiq_flush);
21242f345d8eSLuigi Rizzo 
21252f345d8eSLuigi Rizzo 	if_initname(sc->ifp,
21262f345d8eSLuigi Rizzo 		    device_get_name(sc->dev), device_get_unit(sc->dev));
21272f345d8eSLuigi Rizzo 
212867fd4c9dSJustin Hibbits 	if_setsendqlen(sc->ifp, OCE_MAX_TX_DESC - 1);
212967fd4c9dSJustin Hibbits 	if_setsendqready(sc->ifp);
21302f345d8eSLuigi Rizzo 
213167fd4c9dSJustin Hibbits 	if_sethwassist(sc->ifp, OCE_IF_HWASSIST);
213267fd4c9dSJustin Hibbits 	if_sethwassistbits(sc->ifp, CSUM_TSO, 0);
213367fd4c9dSJustin Hibbits 	if_sethwassistbits(sc->ifp, (CSUM_IP | CSUM_TCP | CSUM_UDP), 0);
21342f345d8eSLuigi Rizzo 
213567fd4c9dSJustin Hibbits 	if_setcapabilities(sc->ifp, OCE_IF_CAPABILITIES);
213667fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_HWCSUM, 0);
213767fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_VLAN_HWFILTER, 0);
21389bd3250aSLuigi Rizzo 
2139ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
214067fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_TSO, 0);
214167fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_LRO, 0);
214267fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_VLAN_HWTSO, 0);
2143ad512958SBjoern A. Zeeb #endif
21442f345d8eSLuigi Rizzo 
214567fd4c9dSJustin Hibbits 	if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp));
214667fd4c9dSJustin Hibbits 	if_setbaudrate(sc->ifp, IF_Gbps(10));
21472f345d8eSLuigi Rizzo 
214867fd4c9dSJustin Hibbits 	if_sethwtsomax(sc->ifp, 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
214967fd4c9dSJustin Hibbits 	if_sethwtsomaxsegcount(sc->ifp, OCE_MAX_TX_ELEMENTS);
215067fd4c9dSJustin Hibbits 	if_sethwtsomaxsegsize(sc->ifp, 4096);
21515fbb6830SXin LI 
21522f345d8eSLuigi Rizzo 	ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
21532f345d8eSLuigi Rizzo 
21542f345d8eSLuigi Rizzo 	return 0;
21552f345d8eSLuigi Rizzo }
21562f345d8eSLuigi Rizzo 
21572f345d8eSLuigi Rizzo static void
215867fd4c9dSJustin Hibbits oce_add_vlan(void *arg, if_t ifp, uint16_t vtag)
21592f345d8eSLuigi Rizzo {
216067fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
21612f345d8eSLuigi Rizzo 
216267fd4c9dSJustin Hibbits 	if (if_getsoftc(ifp) !=  arg)
21632f345d8eSLuigi Rizzo 		return;
21642f345d8eSLuigi Rizzo 	if ((vtag == 0) || (vtag > 4095))
21652f345d8eSLuigi Rizzo 		return;
21662f345d8eSLuigi Rizzo 
21672f345d8eSLuigi Rizzo 	sc->vlan_tag[vtag] = 1;
21682f345d8eSLuigi Rizzo 	sc->vlans_added++;
21695fbb6830SXin LI 	if (sc->vlans_added <= (sc->max_vlans + 1))
21702f345d8eSLuigi Rizzo 		oce_vid_config(sc);
21712f345d8eSLuigi Rizzo }
21722f345d8eSLuigi Rizzo 
21732f345d8eSLuigi Rizzo static void
217467fd4c9dSJustin Hibbits oce_del_vlan(void *arg, if_t ifp, uint16_t vtag)
21752f345d8eSLuigi Rizzo {
217667fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
21772f345d8eSLuigi Rizzo 
217867fd4c9dSJustin Hibbits 	if (if_getsoftc(ifp) !=  arg)
21792f345d8eSLuigi Rizzo 		return;
21802f345d8eSLuigi Rizzo 	if ((vtag == 0) || (vtag > 4095))
21812f345d8eSLuigi Rizzo 		return;
21822f345d8eSLuigi Rizzo 
21832f345d8eSLuigi Rizzo 	sc->vlan_tag[vtag] = 0;
21842f345d8eSLuigi Rizzo 	sc->vlans_added--;
21852f345d8eSLuigi Rizzo 	oce_vid_config(sc);
21862f345d8eSLuigi Rizzo }
21872f345d8eSLuigi Rizzo 
21882f345d8eSLuigi Rizzo /*
21892f345d8eSLuigi Rizzo  * A max of 64 vlans can be configured in BE. If the user configures
21902f345d8eSLuigi Rizzo  * more, place the card in vlan promiscuous mode.
21912f345d8eSLuigi Rizzo  */
21922f345d8eSLuigi Rizzo static int
21932f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc)
21942f345d8eSLuigi Rizzo {
21952f345d8eSLuigi Rizzo 	struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
21962f345d8eSLuigi Rizzo 	uint16_t ntags = 0, i;
21972f345d8eSLuigi Rizzo 	int status = 0;
21982f345d8eSLuigi Rizzo 
21992f345d8eSLuigi Rizzo 	if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
220067fd4c9dSJustin Hibbits 			(if_getcapenable(sc->ifp) & IFCAP_VLAN_HWFILTER)) {
22012f345d8eSLuigi Rizzo 		for (i = 0; i < MAX_VLANS; i++) {
22022f345d8eSLuigi Rizzo 			if (sc->vlan_tag[i]) {
22032f345d8eSLuigi Rizzo 				vtags[ntags].vtag = i;
22042f345d8eSLuigi Rizzo 				ntags++;
22052f345d8eSLuigi Rizzo 			}
22062f345d8eSLuigi Rizzo 		}
22072f345d8eSLuigi Rizzo 		if (ntags)
22082f345d8eSLuigi Rizzo 			status = oce_config_vlan(sc, (uint8_t) sc->if_id,
22092f345d8eSLuigi Rizzo 						vtags, ntags, 1, 0);
22102f345d8eSLuigi Rizzo 	} else
22112f345d8eSLuigi Rizzo 		status = oce_config_vlan(sc, (uint8_t) sc->if_id,
22122f345d8eSLuigi Rizzo 					 	NULL, 0, 1, 1);
22132f345d8eSLuigi Rizzo 	return status;
22142f345d8eSLuigi Rizzo }
22152f345d8eSLuigi Rizzo 
22162f345d8eSLuigi Rizzo static void
22172f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc)
22182f345d8eSLuigi Rizzo {
22192f345d8eSLuigi Rizzo 	uint32_t old_pmac_id = sc->pmac_id;
22202f345d8eSLuigi Rizzo 	int status = 0;
22212f345d8eSLuigi Rizzo 
222267fd4c9dSJustin Hibbits 	status = bcmp((if_getlladdr(sc->ifp)), sc->macaddr.mac_addr,
22232f345d8eSLuigi Rizzo 			 sc->macaddr.size_of_struct);
22242f345d8eSLuigi Rizzo 	if (!status)
22252f345d8eSLuigi Rizzo 		return;
22262f345d8eSLuigi Rizzo 
222767fd4c9dSJustin Hibbits 	status = oce_mbox_macaddr_add(sc, (uint8_t *)(if_getlladdr(sc->ifp)),
22282f345d8eSLuigi Rizzo 					sc->if_id, &sc->pmac_id);
22292f345d8eSLuigi Rizzo 	if (!status) {
22302f345d8eSLuigi Rizzo 		status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
223167fd4c9dSJustin Hibbits 		bcopy((if_getlladdr(sc->ifp)), sc->macaddr.mac_addr,
22322f345d8eSLuigi Rizzo 				 sc->macaddr.size_of_struct);
22332f345d8eSLuigi Rizzo 	}
22342f345d8eSLuigi Rizzo 	if (status)
22352f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Failed update macaddress\n");
22362f345d8eSLuigi Rizzo 
22372f345d8eSLuigi Rizzo }
22382f345d8eSLuigi Rizzo 
22392f345d8eSLuigi Rizzo static int
224067fd4c9dSJustin Hibbits oce_handle_passthrough(if_t ifp, caddr_t data)
22412f345d8eSLuigi Rizzo {
224267fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
22432f345d8eSLuigi Rizzo 	struct ifreq *ifr = (struct ifreq *)data;
22442f345d8eSLuigi Rizzo 	int rc = ENXIO;
22452f345d8eSLuigi Rizzo 	char cookie[32] = {0};
2246541d96aaSBrooks Davis 	void *priv_data = ifr_data_get_ptr(ifr);
22472f345d8eSLuigi Rizzo 	void *ioctl_ptr;
22482f345d8eSLuigi Rizzo 	uint32_t req_size;
22492f345d8eSLuigi Rizzo 	struct mbx_hdr req;
22502f345d8eSLuigi Rizzo 	OCE_DMA_MEM dma_mem;
22512f345d8eSLuigi Rizzo 
22522f345d8eSLuigi Rizzo 	if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
22532f345d8eSLuigi Rizzo 		return EFAULT;
22542f345d8eSLuigi Rizzo 
22552f345d8eSLuigi Rizzo 	if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
22562f345d8eSLuigi Rizzo 		return EINVAL;
22572f345d8eSLuigi Rizzo 
22582f345d8eSLuigi Rizzo 	ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
22592f345d8eSLuigi Rizzo 	if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
22602f345d8eSLuigi Rizzo 		return EFAULT;
22612f345d8eSLuigi Rizzo 
22622f345d8eSLuigi Rizzo 	req_size = le32toh(req.u0.req.request_length);
22632f345d8eSLuigi Rizzo 	if (req_size > 65536)
22642f345d8eSLuigi Rizzo 		return EINVAL;
22652f345d8eSLuigi Rizzo 
22662f345d8eSLuigi Rizzo 	req_size += sizeof(struct mbx_hdr);
22672f345d8eSLuigi Rizzo 	rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
22682f345d8eSLuigi Rizzo 	if (rc)
22692f345d8eSLuigi Rizzo 		return ENOMEM;
22702f345d8eSLuigi Rizzo 
22712f345d8eSLuigi Rizzo 	if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
22722f345d8eSLuigi Rizzo 		rc = EFAULT;
22732f345d8eSLuigi Rizzo 		goto dma_free;
22742f345d8eSLuigi Rizzo 	}
22752f345d8eSLuigi Rizzo 
22762f345d8eSLuigi Rizzo 	rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
22772f345d8eSLuigi Rizzo 	if (rc) {
22782f345d8eSLuigi Rizzo 		rc = EIO;
22792f345d8eSLuigi Rizzo 		goto dma_free;
22802f345d8eSLuigi Rizzo 	}
22812f345d8eSLuigi Rizzo 
2282758927a9SBrooks Davis 	if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) {
22832f345d8eSLuigi Rizzo 		rc =  EFAULT;
2284758927a9SBrooks Davis 		goto dma_free;
2285758927a9SBrooks Davis 	}
22862f345d8eSLuigi Rizzo 
2287cdaba892SXin LI 	/*
2288cdaba892SXin LI 	   firmware is filling all the attributes for this ioctl except
2289cdaba892SXin LI 	   the driver version..so fill it
2290cdaba892SXin LI 	 */
2291cdaba892SXin LI 	if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) {
2292758927a9SBrooks Davis 		struct mbx_common_get_cntl_attr *fw_cmd =
2293758927a9SBrooks Davis 		    (struct mbx_common_get_cntl_attr *)ioctl_ptr;
2294758927a9SBrooks Davis 		_Static_assert(sizeof(COMPONENT_REVISION) <=
2295758927a9SBrooks Davis 		     sizeof(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str),
2296758927a9SBrooks Davis 		     "driver version string too long");
2297758927a9SBrooks Davis 
2298758927a9SBrooks Davis 		rc = copyout(COMPONENT_REVISION,
2299758927a9SBrooks Davis 		    fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str,
2300758927a9SBrooks Davis 		    sizeof(COMPONENT_REVISION));
2301cdaba892SXin LI 	}
2302cdaba892SXin LI 
23032f345d8eSLuigi Rizzo dma_free:
23042f345d8eSLuigi Rizzo 	oce_dma_free(sc, &dma_mem);
23052f345d8eSLuigi Rizzo 	return rc;
23062f345d8eSLuigi Rizzo 
23072f345d8eSLuigi Rizzo }
23082f345d8eSLuigi Rizzo 
2309cdaba892SXin LI static void
2310cdaba892SXin LI oce_eqd_set_periodic(POCE_SOFTC sc)
2311cdaba892SXin LI {
2312cdaba892SXin LI 	struct oce_set_eqd set_eqd[OCE_MAX_EQ];
2313cdaba892SXin LI 	struct oce_aic_obj *aic;
2314cdaba892SXin LI 	struct oce_eq *eqo;
2315cdaba892SXin LI 	uint64_t now = 0, delta;
2316cdaba892SXin LI 	int eqd, i, num = 0;
2317c2625e6eSJosh Paetzel 	uint32_t tx_reqs = 0, rxpkts = 0, pps;
2318c2625e6eSJosh Paetzel 	struct oce_wq *wq;
2319c2625e6eSJosh Paetzel 	struct oce_rq *rq;
2320c2625e6eSJosh Paetzel 
2321c2625e6eSJosh Paetzel 	#define ticks_to_msecs(t)       (1000 * (t) / hz)
2322cdaba892SXin LI 
2323cdaba892SXin LI 	for (i = 0 ; i < sc->neqs; i++) {
2324cdaba892SXin LI 		eqo = sc->eq[i];
2325cdaba892SXin LI 		aic = &sc->aic_obj[i];
2326cdaba892SXin LI 		/* When setting the static eq delay from the user space */
2327cdaba892SXin LI 		if (!aic->enable) {
2328c2625e6eSJosh Paetzel 			if (aic->ticks)
2329c2625e6eSJosh Paetzel 				aic->ticks = 0;
2330cdaba892SXin LI 			eqd = aic->et_eqd;
2331cdaba892SXin LI 			goto modify_eqd;
2332cdaba892SXin LI 		}
2333cdaba892SXin LI 
233435828280SAlexander Motin 		if (i == 0) {
233535828280SAlexander Motin 			rq = sc->rq[0];
2336c2625e6eSJosh Paetzel 			rxpkts = rq->rx_stats.rx_pkts;
233735828280SAlexander Motin 		} else
233835828280SAlexander Motin 			rxpkts = 0;
233935828280SAlexander Motin 		if (i + 1 < sc->nrqs) {
234035828280SAlexander Motin 			rq = sc->rq[i + 1];
234135828280SAlexander Motin 			rxpkts += rq->rx_stats.rx_pkts;
234235828280SAlexander Motin 		}
234335828280SAlexander Motin 		if (i < sc->nwqs) {
2344c2625e6eSJosh Paetzel 			wq = sc->wq[i];
2345c2625e6eSJosh Paetzel 			tx_reqs = wq->tx_stats.tx_reqs;
234635828280SAlexander Motin 		} else
234735828280SAlexander Motin 			tx_reqs = 0;
2348cdaba892SXin LI 		now = ticks;
2349cdaba892SXin LI 
2350c2625e6eSJosh Paetzel 		if (!aic->ticks || now < aic->ticks ||
2351c2625e6eSJosh Paetzel 		    rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) {
2352c2625e6eSJosh Paetzel 			aic->prev_rxpkts = rxpkts;
2353c2625e6eSJosh Paetzel 			aic->prev_txreqs = tx_reqs;
2354c2625e6eSJosh Paetzel 			aic->ticks = now;
2355c2625e6eSJosh Paetzel 			continue;
2356c2625e6eSJosh Paetzel 		}
2357cdaba892SXin LI 
2358c2625e6eSJosh Paetzel 		delta = ticks_to_msecs(now - aic->ticks);
2359cdaba892SXin LI 
2360c2625e6eSJosh Paetzel 		pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) +
2361c2625e6eSJosh Paetzel 		      (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta);
2362c2625e6eSJosh Paetzel 		eqd = (pps / 15000) << 2;
2363c2625e6eSJosh Paetzel 		if (eqd < 8)
2364cdaba892SXin LI 			eqd = 0;
2365cdaba892SXin LI 
2366cdaba892SXin LI 		/* Make sure that the eq delay is in the known range */
2367cdaba892SXin LI 		eqd = min(eqd, aic->max_eqd);
2368cdaba892SXin LI 		eqd = max(eqd, aic->min_eqd);
2369cdaba892SXin LI 
2370c2625e6eSJosh Paetzel 		aic->prev_rxpkts = rxpkts;
2371c2625e6eSJosh Paetzel 		aic->prev_txreqs = tx_reqs;
2372c2625e6eSJosh Paetzel 		aic->ticks = now;
2373c2625e6eSJosh Paetzel 
2374cdaba892SXin LI modify_eqd:
2375cdaba892SXin LI 		if (eqd != aic->cur_eqd) {
2376cdaba892SXin LI 			set_eqd[num].delay_multiplier = (eqd * 65)/100;
2377cdaba892SXin LI 			set_eqd[num].eq_id = eqo->eq_id;
2378cdaba892SXin LI 			aic->cur_eqd = eqd;
2379cdaba892SXin LI 			num++;
2380cdaba892SXin LI 		}
2381cdaba892SXin LI 	}
2382cdaba892SXin LI 
2383cdaba892SXin LI 	/* Is there atleast one eq that needs to be modified? */
2384c2625e6eSJosh Paetzel         for(i = 0; i < num; i += 8) {
2385c2625e6eSJosh Paetzel                 if((num - i) >=8 )
2386c2625e6eSJosh Paetzel                         oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8);
2387c2625e6eSJosh Paetzel                 else
2388c2625e6eSJosh Paetzel                         oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i));
2389c2625e6eSJosh Paetzel         }
2390c2625e6eSJosh Paetzel 
2391cdaba892SXin LI }
23922f345d8eSLuigi Rizzo 
23935fbb6830SXin LI static void oce_detect_hw_error(POCE_SOFTC sc)
23945fbb6830SXin LI {
23955fbb6830SXin LI 
23965fbb6830SXin LI 	uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0;
23975fbb6830SXin LI 	uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
23985fbb6830SXin LI 	uint32_t i;
23995fbb6830SXin LI 
24005fbb6830SXin LI 	if (sc->hw_error)
24015fbb6830SXin LI 		return;
24025fbb6830SXin LI 
24035fbb6830SXin LI 	if (IS_XE201(sc)) {
24045fbb6830SXin LI 		sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET);
24055fbb6830SXin LI 		if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24065fbb6830SXin LI 			sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET);
24075fbb6830SXin LI 			sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET);
24085fbb6830SXin LI 		}
24095fbb6830SXin LI 	} else {
24105fbb6830SXin LI 		ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW);
24115fbb6830SXin LI 		ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH);
24125fbb6830SXin LI 		ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK);
24135fbb6830SXin LI 		ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK);
24145fbb6830SXin LI 
24155fbb6830SXin LI 		ue_low = (ue_low & ~ue_low_mask);
24165fbb6830SXin LI 		ue_high = (ue_high & ~ue_high_mask);
24175fbb6830SXin LI 	}
24185fbb6830SXin LI 
24195fbb6830SXin LI 	/* On certain platforms BE hardware can indicate spurious UEs.
24205fbb6830SXin LI 	 * Allow the h/w to stop working completely in case of a real UE.
24215fbb6830SXin LI 	 * Hence not setting the hw_error for UE detection.
24225fbb6830SXin LI 	 */
24235fbb6830SXin LI 	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24245fbb6830SXin LI 		sc->hw_error = TRUE;
24255fbb6830SXin LI 		device_printf(sc->dev, "Error detected in the card\n");
24265fbb6830SXin LI 	}
24275fbb6830SXin LI 
24285fbb6830SXin LI 	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24295fbb6830SXin LI 		device_printf(sc->dev,
24305fbb6830SXin LI 				"ERR: sliport status 0x%x\n", sliport_status);
24315fbb6830SXin LI 		device_printf(sc->dev,
24325fbb6830SXin LI 				"ERR: sliport error1 0x%x\n", sliport_err1);
24335fbb6830SXin LI 		device_printf(sc->dev,
24345fbb6830SXin LI 				"ERR: sliport error2 0x%x\n", sliport_err2);
24355fbb6830SXin LI 	}
24365fbb6830SXin LI 
24375fbb6830SXin LI 	if (ue_low) {
24385fbb6830SXin LI 		for (i = 0; ue_low; ue_low >>= 1, i++) {
24395fbb6830SXin LI 			if (ue_low & 1)
24405fbb6830SXin LI 				device_printf(sc->dev, "UE: %s bit set\n",
24415fbb6830SXin LI 							ue_status_low_desc[i]);
24425fbb6830SXin LI 		}
24435fbb6830SXin LI 	}
24445fbb6830SXin LI 
24455fbb6830SXin LI 	if (ue_high) {
24465fbb6830SXin LI 		for (i = 0; ue_high; ue_high >>= 1, i++) {
24475fbb6830SXin LI 			if (ue_high & 1)
24485fbb6830SXin LI 				device_printf(sc->dev, "UE: %s bit set\n",
24495fbb6830SXin LI 							ue_status_hi_desc[i]);
24505fbb6830SXin LI 		}
24515fbb6830SXin LI 	}
24525fbb6830SXin LI 
24535fbb6830SXin LI }
24545fbb6830SXin LI 
24552f345d8eSLuigi Rizzo static void
24562f345d8eSLuigi Rizzo oce_local_timer(void *arg)
24572f345d8eSLuigi Rizzo {
24582f345d8eSLuigi Rizzo 	POCE_SOFTC sc = arg;
24592f345d8eSLuigi Rizzo 	int i = 0;
24602f345d8eSLuigi Rizzo 
24615fbb6830SXin LI 	oce_detect_hw_error(sc);
24622f345d8eSLuigi Rizzo 	oce_refresh_nic_stats(sc);
24632f345d8eSLuigi Rizzo 	oce_refresh_queue_stats(sc);
24642f345d8eSLuigi Rizzo 	oce_mac_addr_set(sc);
24652f345d8eSLuigi Rizzo 
24662f345d8eSLuigi Rizzo 	/* TX Watch Dog*/
24672f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nwqs; i++)
24682f345d8eSLuigi Rizzo 		oce_tx_restart(sc, sc->wq[i]);
24692f345d8eSLuigi Rizzo 
2470cdaba892SXin LI 	/* calculate and set the eq delay for optimal interrupt rate */
2471291a1934SXin LI 	if (IS_BE(sc) || IS_SH(sc))
2472cdaba892SXin LI 		oce_eqd_set_periodic(sc);
2473cdaba892SXin LI 
24742f345d8eSLuigi Rizzo 	callout_reset(&sc->timer, hz, oce_local_timer, sc);
24752f345d8eSLuigi Rizzo }
24762f345d8eSLuigi Rizzo 
2477c2625e6eSJosh Paetzel static void
2478c2625e6eSJosh Paetzel oce_tx_compl_clean(POCE_SOFTC sc)
2479c2625e6eSJosh Paetzel {
2480c2625e6eSJosh Paetzel 	struct oce_wq *wq;
2481c2625e6eSJosh Paetzel 	int i = 0, timeo = 0, num_wqes = 0;
2482c2625e6eSJosh Paetzel 	int pending_txqs = sc->nwqs;
2483c2625e6eSJosh Paetzel 
2484c2625e6eSJosh Paetzel 	/* Stop polling for compls when HW has been silent for 10ms or
2485c2625e6eSJosh Paetzel 	 * hw_error or no outstanding completions expected
2486c2625e6eSJosh Paetzel 	 */
2487c2625e6eSJosh Paetzel 	do {
2488c2625e6eSJosh Paetzel 		pending_txqs = sc->nwqs;
2489c2625e6eSJosh Paetzel 
2490c2625e6eSJosh Paetzel 		for_all_wq_queues(sc, wq, i) {
2491c2625e6eSJosh Paetzel 			num_wqes = oce_wq_handler(wq);
2492c2625e6eSJosh Paetzel 
2493c2625e6eSJosh Paetzel 			if(num_wqes)
2494c2625e6eSJosh Paetzel 				timeo = 0;
2495c2625e6eSJosh Paetzel 
2496c2625e6eSJosh Paetzel 			if(!wq->ring->num_used)
2497c2625e6eSJosh Paetzel 				pending_txqs--;
2498c2625e6eSJosh Paetzel 		}
2499c2625e6eSJosh Paetzel 
2500c2625e6eSJosh Paetzel 		if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error)
2501c2625e6eSJosh Paetzel 			break;
2502c2625e6eSJosh Paetzel 
2503c2625e6eSJosh Paetzel 		DELAY(1000);
2504c2625e6eSJosh Paetzel 	} while (TRUE);
2505c2625e6eSJosh Paetzel 
2506c2625e6eSJosh Paetzel 	for_all_wq_queues(sc, wq, i) {
2507c2625e6eSJosh Paetzel 		while(wq->ring->num_used) {
2508c2625e6eSJosh Paetzel 			LOCK(&wq->tx_compl_lock);
2509c2625e6eSJosh Paetzel 			oce_process_tx_completion(wq);
2510c2625e6eSJosh Paetzel 			UNLOCK(&wq->tx_compl_lock);
2511c2625e6eSJosh Paetzel 		}
2512c2625e6eSJosh Paetzel 	}
2513c2625e6eSJosh Paetzel 
2514c2625e6eSJosh Paetzel }
25152f345d8eSLuigi Rizzo 
2516beb0f7e7SJosh Paetzel /* NOTE : This should only be called holding
2517beb0f7e7SJosh Paetzel  *        DEVICE_LOCK.
2518beb0f7e7SJosh Paetzel  */
25192f345d8eSLuigi Rizzo static void
25202f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc)
25212f345d8eSLuigi Rizzo {
2522c2625e6eSJosh Paetzel 	int i;
25232f345d8eSLuigi Rizzo 	struct oce_rq *rq;
25242f345d8eSLuigi Rizzo 	struct oce_wq *wq;
25252f345d8eSLuigi Rizzo 	struct oce_eq *eq;
25262f345d8eSLuigi Rizzo 
252767fd4c9dSJustin Hibbits 	if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
25282f345d8eSLuigi Rizzo 
2529c2625e6eSJosh Paetzel 	oce_tx_compl_clean(sc);
25302f345d8eSLuigi Rizzo 
25312f345d8eSLuigi Rizzo 	/* Stop intrs and finish any bottom halves pending */
25322f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
25332f345d8eSLuigi Rizzo 
2534cdaba892SXin LI 	/* Since taskqueue_drain takes a Gaint Lock, We should not acquire
2535beb0f7e7SJosh Paetzel 	   any other lock. So unlock device lock and require after
2536beb0f7e7SJosh Paetzel 	   completing taskqueue_drain.
2537beb0f7e7SJosh Paetzel 	*/
2538beb0f7e7SJosh Paetzel 	UNLOCK(&sc->dev_lock);
25392f345d8eSLuigi Rizzo 	for (i = 0; i < sc->intr_count; i++) {
25402f345d8eSLuigi Rizzo 		if (sc->intrs[i].tq != NULL) {
25412f345d8eSLuigi Rizzo 			taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
25422f345d8eSLuigi Rizzo 		}
25432f345d8eSLuigi Rizzo 	}
2544beb0f7e7SJosh Paetzel 	LOCK(&sc->dev_lock);
25452f345d8eSLuigi Rizzo 
25462f345d8eSLuigi Rizzo 	/* Delete RX queue in card with flush param */
25472f345d8eSLuigi Rizzo 	oce_stop_rx(sc);
25482f345d8eSLuigi Rizzo 
25492f345d8eSLuigi Rizzo 	/* Invalidate any pending cq and eq entries*/
25502f345d8eSLuigi Rizzo 	for_all_evnt_queues(sc, eq, i)
25512f345d8eSLuigi Rizzo 		oce_drain_eq(eq);
25522f345d8eSLuigi Rizzo 	for_all_rq_queues(sc, rq, i)
25532f345d8eSLuigi Rizzo 		oce_drain_rq_cq(rq);
25542f345d8eSLuigi Rizzo 	for_all_wq_queues(sc, wq, i)
25552f345d8eSLuigi Rizzo 		oce_drain_wq_cq(wq);
25562f345d8eSLuigi Rizzo 
25572f345d8eSLuigi Rizzo 	/* But still we need to get MCC aync events.
25582f345d8eSLuigi Rizzo 	   So enable intrs and also arm first EQ
25592f345d8eSLuigi Rizzo 	*/
25602f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
25612f345d8eSLuigi Rizzo 	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
25622f345d8eSLuigi Rizzo 
25632f345d8eSLuigi Rizzo 	DELAY(10);
25642f345d8eSLuigi Rizzo }
25652f345d8eSLuigi Rizzo 
25662f345d8eSLuigi Rizzo static void
25672f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc)
25682f345d8eSLuigi Rizzo {
25692f345d8eSLuigi Rizzo 	struct oce_eq *eq;
25702f345d8eSLuigi Rizzo 	struct oce_rq *rq;
25712f345d8eSLuigi Rizzo 	struct oce_wq *wq;
25722f345d8eSLuigi Rizzo 	int i, rc = 0;
25732f345d8eSLuigi Rizzo 
257467fd4c9dSJustin Hibbits 	if_setdrvflagbits(sc->ifp, IFF_DRV_RUNNING , 0);
25752f345d8eSLuigi Rizzo 
25762f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
25772f345d8eSLuigi Rizzo 
25782f345d8eSLuigi Rizzo 	oce_start_rx(sc);
25792f345d8eSLuigi Rizzo 
25802f345d8eSLuigi Rizzo 	for_all_rq_queues(sc, rq, i) {
25812f345d8eSLuigi Rizzo 		rc = oce_start_rq(rq);
25822f345d8eSLuigi Rizzo 		if (rc)
25832f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Unable to start RX\n");
25842f345d8eSLuigi Rizzo 	}
25852f345d8eSLuigi Rizzo 
25862f345d8eSLuigi Rizzo 	for_all_wq_queues(sc, wq, i) {
25872f345d8eSLuigi Rizzo 		rc = oce_start_wq(wq);
25882f345d8eSLuigi Rizzo 		if (rc)
25892f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Unable to start TX\n");
25902f345d8eSLuigi Rizzo 	}
25912f345d8eSLuigi Rizzo 
25922f345d8eSLuigi Rizzo 	for_all_evnt_queues(sc, eq, i)
25932f345d8eSLuigi Rizzo 		oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
25942f345d8eSLuigi Rizzo 
25952f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
25962f345d8eSLuigi Rizzo 
25972f345d8eSLuigi Rizzo }
25982f345d8eSLuigi Rizzo 
25999bd3250aSLuigi Rizzo static void
26009bd3250aSLuigi Rizzo process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
26012f345d8eSLuigi Rizzo {
26029bd3250aSLuigi Rizzo 	/* Update Link status */
26032f345d8eSLuigi Rizzo 	if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
26042f345d8eSLuigi Rizzo 	     ASYNC_EVENT_LINK_UP) {
26052f345d8eSLuigi Rizzo 		sc->link_status = ASYNC_EVENT_LINK_UP;
26062f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_UP);
26072f345d8eSLuigi Rizzo 	} else {
26082f345d8eSLuigi Rizzo 		sc->link_status = ASYNC_EVENT_LINK_DOWN;
26092f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
26102f345d8eSLuigi Rizzo 	}
26119bd3250aSLuigi Rizzo }
26129bd3250aSLuigi Rizzo 
2613c2625e6eSJosh Paetzel static void oce_async_grp5_osbmc_process(POCE_SOFTC sc,
2614c2625e6eSJosh Paetzel 					 struct oce_async_evt_grp5_os2bmc *evt)
2615c2625e6eSJosh Paetzel {
2616c2625e6eSJosh Paetzel 	DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc));
2617c2625e6eSJosh Paetzel 	if (evt->u.s.mgmt_enable)
2618c2625e6eSJosh Paetzel 		sc->flags |= OCE_FLAGS_OS2BMC;
2619c2625e6eSJosh Paetzel 	else
2620c2625e6eSJosh Paetzel 		return;
2621c2625e6eSJosh Paetzel 
2622c2625e6eSJosh Paetzel 	sc->bmc_filt_mask = evt->u.s.arp_filter;
2623c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1);
2624c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2);
2625c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3);
2626c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4);
2627c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5);
2628c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6);
2629c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7);
2630c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8);
2631c2625e6eSJosh Paetzel }
2632c2625e6eSJosh Paetzel 
2633c2625e6eSJosh Paetzel static void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe)
2634c2625e6eSJosh Paetzel {
2635c2625e6eSJosh Paetzel 	struct oce_async_event_grp5_pvid_state *gcqe;
2636c2625e6eSJosh Paetzel 	struct oce_async_evt_grp5_os2bmc *bmccqe;
2637c2625e6eSJosh Paetzel 
2638c2625e6eSJosh Paetzel 	switch (cqe->u0.s.async_type) {
2639c2625e6eSJosh Paetzel 	case ASYNC_EVENT_PVID_STATE:
2640c2625e6eSJosh Paetzel 		/* GRP5 PVID */
2641c2625e6eSJosh Paetzel 		gcqe = (struct oce_async_event_grp5_pvid_state *)cqe;
2642c2625e6eSJosh Paetzel 		if (gcqe->enabled)
2643c2625e6eSJosh Paetzel 			sc->pvid = gcqe->tag & VLAN_VID_MASK;
2644c2625e6eSJosh Paetzel 		else
2645c2625e6eSJosh Paetzel 			sc->pvid = 0;
2646c2625e6eSJosh Paetzel 		break;
2647c2625e6eSJosh Paetzel 	case ASYNC_EVENT_OS2BMC:
2648c2625e6eSJosh Paetzel 		bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe;
2649c2625e6eSJosh Paetzel 		oce_async_grp5_osbmc_process(sc, bmccqe);
2650c2625e6eSJosh Paetzel 		break;
2651c2625e6eSJosh Paetzel 	default:
2652c2625e6eSJosh Paetzel 		break;
2653c2625e6eSJosh Paetzel 	}
2654c2625e6eSJosh Paetzel }
2655c2625e6eSJosh Paetzel 
26569bd3250aSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */
26579bd3250aSLuigi Rizzo uint16_t
26589bd3250aSLuigi Rizzo oce_mq_handler(void *arg)
26599bd3250aSLuigi Rizzo {
26609bd3250aSLuigi Rizzo 	struct oce_mq *mq = (struct oce_mq *)arg;
26619bd3250aSLuigi Rizzo 	POCE_SOFTC sc = mq->parent;
26629bd3250aSLuigi Rizzo 	struct oce_cq *cq = mq->cq;
26639bd3250aSLuigi Rizzo 	int num_cqes = 0, evt_type = 0, optype = 0;
26649bd3250aSLuigi Rizzo 	struct oce_mq_cqe *cqe;
26659bd3250aSLuigi Rizzo 	struct oce_async_cqe_link_state *acqe;
2666cdaba892SXin LI 	struct oce_async_event_qnq *dbgcqe;
26679bd3250aSLuigi Rizzo 
26689bd3250aSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
26699bd3250aSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
26709bd3250aSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
26719bd3250aSLuigi Rizzo 
26729bd3250aSLuigi Rizzo 	while (cqe->u0.dw[3]) {
26739bd3250aSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
26749bd3250aSLuigi Rizzo 		if (cqe->u0.s.async_event) {
26759bd3250aSLuigi Rizzo 			evt_type = cqe->u0.s.event_type;
26769bd3250aSLuigi Rizzo 			optype = cqe->u0.s.async_type;
26779bd3250aSLuigi Rizzo 			if (evt_type  == ASYNC_EVENT_CODE_LINK_STATE) {
26789bd3250aSLuigi Rizzo 				/* Link status evt */
26799bd3250aSLuigi Rizzo 				acqe = (struct oce_async_cqe_link_state *)cqe;
26809bd3250aSLuigi Rizzo 				process_link_state(sc, acqe);
2681c2625e6eSJosh Paetzel 			} else if (evt_type == ASYNC_EVENT_GRP5) {
2682c2625e6eSJosh Paetzel 				oce_process_grp5_events(sc, cqe);
2683c2625e6eSJosh Paetzel 			} else if (evt_type == ASYNC_EVENT_CODE_DEBUG &&
2684cdaba892SXin LI 					optype == ASYNC_EVENT_DEBUG_QNQ) {
2685c2625e6eSJosh Paetzel 				dbgcqe =  (struct oce_async_event_qnq *)cqe;
2686cdaba892SXin LI 				if(dbgcqe->valid)
2687cdaba892SXin LI 					sc->qnqid = dbgcqe->vlan_tag;
2688cdaba892SXin LI 				sc->qnq_debug_event = TRUE;
2689cdaba892SXin LI 			}
26902f345d8eSLuigi Rizzo 		}
26912f345d8eSLuigi Rizzo 		cqe->u0.dw[3] = 0;
26922f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
26932f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
26942f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
26952f345d8eSLuigi Rizzo 		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
26962f345d8eSLuigi Rizzo 		num_cqes++;
26972f345d8eSLuigi Rizzo 	}
26982f345d8eSLuigi Rizzo 
26992f345d8eSLuigi Rizzo 	if (num_cqes)
27002f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
27012f345d8eSLuigi Rizzo 
27022f345d8eSLuigi Rizzo 	return 0;
27032f345d8eSLuigi Rizzo }
27042f345d8eSLuigi Rizzo 
27052f345d8eSLuigi Rizzo static void
27062f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc)
27072f345d8eSLuigi Rizzo {
27082f345d8eSLuigi Rizzo 	/* Check if it is FLEX machine. Is so dont use RSS */
27092f345d8eSLuigi Rizzo 	if ((sc->function_mode & FNM_FLEX10_MODE) ||
27109bd3250aSLuigi Rizzo 	    (sc->function_mode & FNM_UMC_MODE)    ||
27119bd3250aSLuigi Rizzo 	    (sc->function_mode & FNM_VNIC_MODE)	  ||
2712291a1934SXin LI 	    (!is_rss_enabled(sc))		  ||
2713a4f734b4SXin LI 	    IS_BE2(sc)) {
27142f345d8eSLuigi Rizzo 		sc->nrqs = 1;
27152f345d8eSLuigi Rizzo 		sc->nwqs = 1;
27165fbb6830SXin LI 	} else {
27175fbb6830SXin LI 		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
27185fbb6830SXin LI 		sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs);
27192f345d8eSLuigi Rizzo 	}
2720a4f734b4SXin LI 
2721a4f734b4SXin LI 	if (IS_BE2(sc) && is_rss_enabled(sc))
2722a4f734b4SXin LI 		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
27232f345d8eSLuigi Rizzo }
27242f345d8eSLuigi Rizzo 
27252f345d8eSLuigi Rizzo static void
27262f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc)
27272f345d8eSLuigi Rizzo {
2728291a1934SXin LI 	if (is_rss_enabled(sc)) {
27292f345d8eSLuigi Rizzo 		sc->nrqs = sc->intr_count + 1;
27302f345d8eSLuigi Rizzo 		sc->nwqs = sc->intr_count;
27312f345d8eSLuigi Rizzo 	} else {
27322f345d8eSLuigi Rizzo 		sc->nrqs = 1;
27332f345d8eSLuigi Rizzo 		sc->nwqs = 1;
27342f345d8eSLuigi Rizzo 	}
2735a4f734b4SXin LI 
2736a4f734b4SXin LI 	if (IS_BE2(sc))
2737a4f734b4SXin LI 		sc->nwqs = 1;
27382f345d8eSLuigi Rizzo }
27392f345d8eSLuigi Rizzo 
2740cdaba892SXin LI static int
2741cdaba892SXin LI oce_check_ipv6_ext_hdr(struct mbuf *m)
2742cdaba892SXin LI {
2743cdaba892SXin LI 	struct ether_header *eh = mtod(m, struct ether_header *);
2744cdaba892SXin LI 	caddr_t m_datatemp = m->m_data;
2745cdaba892SXin LI 
2746cdaba892SXin LI 	if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2747cdaba892SXin LI 		m->m_data += sizeof(struct ether_header);
2748cdaba892SXin LI 		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2749cdaba892SXin LI 
2750cdaba892SXin LI 		if((ip6->ip6_nxt != IPPROTO_TCP) && \
2751cdaba892SXin LI 				(ip6->ip6_nxt != IPPROTO_UDP)){
2752cdaba892SXin LI 			struct ip6_ext *ip6e = NULL;
2753cdaba892SXin LI 			m->m_data += sizeof(struct ip6_hdr);
2754cdaba892SXin LI 
2755cdaba892SXin LI 			ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *);
2756cdaba892SXin LI 			if(ip6e->ip6e_len == 0xff) {
2757cdaba892SXin LI 				m->m_data = m_datatemp;
2758cdaba892SXin LI 				return TRUE;
2759cdaba892SXin LI 			}
2760cdaba892SXin LI 		}
2761cdaba892SXin LI 		m->m_data = m_datatemp;
2762cdaba892SXin LI 	}
2763cdaba892SXin LI 	return FALSE;
2764cdaba892SXin LI }
2765cdaba892SXin LI 
2766cdaba892SXin LI static int
2767cdaba892SXin LI is_be3_a1(POCE_SOFTC sc)
2768cdaba892SXin LI {
2769cdaba892SXin LI 	if((sc->flags & OCE_FLAGS_BE3)  && ((sc->asic_revision & 0xFF) < 2)) {
2770cdaba892SXin LI 		return TRUE;
2771cdaba892SXin LI 	}
2772cdaba892SXin LI 	return FALSE;
2773cdaba892SXin LI }
2774cdaba892SXin LI 
2775cdaba892SXin LI static struct mbuf *
2776cdaba892SXin LI oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete)
2777cdaba892SXin LI {
2778cdaba892SXin LI 	uint16_t vlan_tag = 0;
2779cdaba892SXin LI 
2780cdaba892SXin LI 	if(!M_WRITABLE(m))
2781cdaba892SXin LI 		return NULL;
2782cdaba892SXin LI 
2783cdaba892SXin LI 	/* Embed vlan tag in the packet if it is not part of it */
2784cdaba892SXin LI 	if(m->m_flags & M_VLANTAG) {
2785cdaba892SXin LI 		vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
2786cdaba892SXin LI 		m->m_flags &= ~M_VLANTAG;
2787cdaba892SXin LI 	}
2788cdaba892SXin LI 
2789cdaba892SXin LI 	/* if UMC, ignore vlan tag insertion and instead insert pvid */
2790cdaba892SXin LI 	if(sc->pvid) {
2791cdaba892SXin LI 		if(!vlan_tag)
2792cdaba892SXin LI 			vlan_tag = sc->pvid;
2793c2625e6eSJosh Paetzel 		if (complete)
2794cdaba892SXin LI 			*complete = FALSE;
2795cdaba892SXin LI 	}
2796cdaba892SXin LI 
2797cdaba892SXin LI 	if(vlan_tag) {
2798cdaba892SXin LI 		m = ether_vlanencap(m, vlan_tag);
2799cdaba892SXin LI 	}
2800cdaba892SXin LI 
2801cdaba892SXin LI 	if(sc->qnqid) {
2802cdaba892SXin LI 		m = ether_vlanencap(m, sc->qnqid);
2803c2625e6eSJosh Paetzel 
2804c2625e6eSJosh Paetzel 		if (complete)
2805cdaba892SXin LI 			*complete = FALSE;
2806cdaba892SXin LI 	}
2807cdaba892SXin LI 	return m;
2808cdaba892SXin LI }
2809cdaba892SXin LI 
2810cdaba892SXin LI static int
2811cdaba892SXin LI oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m)
2812cdaba892SXin LI {
2813cdaba892SXin LI 	if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \
2814cdaba892SXin LI 			oce_check_ipv6_ext_hdr(m)) {
2815cdaba892SXin LI 		return TRUE;
2816cdaba892SXin LI 	}
2817cdaba892SXin LI 	return FALSE;
2818cdaba892SXin LI }
2819291a1934SXin LI 
2820291a1934SXin LI static void
2821291a1934SXin LI oce_get_config(POCE_SOFTC sc)
2822291a1934SXin LI {
2823291a1934SXin LI 	int rc = 0;
2824291a1934SXin LI 	uint32_t max_rss = 0;
2825291a1934SXin LI 
2826291a1934SXin LI 	if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native))
2827291a1934SXin LI 		max_rss = OCE_LEGACY_MODE_RSS;
2828291a1934SXin LI 	else
2829291a1934SXin LI 		max_rss = OCE_MAX_RSS;
2830291a1934SXin LI 
2831291a1934SXin LI 	if (!IS_BE(sc)) {
2832b41206d8SXin LI 		rc = oce_get_profile_config(sc, max_rss);
2833291a1934SXin LI 		if (rc) {
2834291a1934SXin LI 			sc->nwqs = OCE_MAX_WQ;
2835291a1934SXin LI 			sc->nrssqs = max_rss;
2836291a1934SXin LI 			sc->nrqs = sc->nrssqs + 1;
2837291a1934SXin LI 		}
2838291a1934SXin LI 	}
2839b41206d8SXin LI 	else { /* For BE3 don't rely on fw for determining the resources */
2840291a1934SXin LI 		sc->nrssqs = max_rss;
2841291a1934SXin LI 		sc->nrqs = sc->nrssqs + 1;
2842291a1934SXin LI 		sc->nwqs = OCE_MAX_WQ;
2843b41206d8SXin LI 		sc->max_vlans = MAX_VLANFILTER_SIZE;
2844291a1934SXin LI 	}
2845291a1934SXin LI }
2846c2625e6eSJosh Paetzel 
2847c2625e6eSJosh Paetzel static void
2848c2625e6eSJosh Paetzel oce_rdma_close(void)
2849c2625e6eSJosh Paetzel {
2850c2625e6eSJosh Paetzel   if (oce_rdma_if != NULL) {
2851c2625e6eSJosh Paetzel     oce_rdma_if = NULL;
2852c2625e6eSJosh Paetzel   }
2853c2625e6eSJosh Paetzel }
2854c2625e6eSJosh Paetzel 
2855c2625e6eSJosh Paetzel static void
2856c2625e6eSJosh Paetzel oce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr)
2857c2625e6eSJosh Paetzel {
2858c2625e6eSJosh Paetzel   memcpy(macaddr, sc->macaddr.mac_addr, 6);
2859c2625e6eSJosh Paetzel }
2860c2625e6eSJosh Paetzel 
2861c2625e6eSJosh Paetzel int
2862c2625e6eSJosh Paetzel oce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if)
2863c2625e6eSJosh Paetzel {
2864c2625e6eSJosh Paetzel   POCE_SOFTC sc;
2865c2625e6eSJosh Paetzel   struct oce_dev_info di;
2866c2625e6eSJosh Paetzel   int i;
2867c2625e6eSJosh Paetzel 
2868c2625e6eSJosh Paetzel   if ((rdma_info == NULL) || (rdma_if == NULL)) {
2869c2625e6eSJosh Paetzel     return -EINVAL;
2870c2625e6eSJosh Paetzel   }
2871c2625e6eSJosh Paetzel 
2872c2625e6eSJosh Paetzel   if ((rdma_info->size != OCE_RDMA_INFO_SIZE) ||
2873c2625e6eSJosh Paetzel       (rdma_if->size != OCE_RDMA_IF_SIZE)) {
2874c2625e6eSJosh Paetzel     return -ENXIO;
2875c2625e6eSJosh Paetzel   }
2876c2625e6eSJosh Paetzel 
2877c2625e6eSJosh Paetzel   rdma_info->close = oce_rdma_close;
2878c2625e6eSJosh Paetzel   rdma_info->mbox_post = oce_mbox_post;
2879c2625e6eSJosh Paetzel   rdma_info->common_req_hdr_init = mbx_common_req_hdr_init;
2880c2625e6eSJosh Paetzel   rdma_info->get_mac_addr = oce_get_mac_addr;
2881c2625e6eSJosh Paetzel 
2882c2625e6eSJosh Paetzel   oce_rdma_if = rdma_if;
2883c2625e6eSJosh Paetzel 
2884c2625e6eSJosh Paetzel   sc = softc_head;
2885c2625e6eSJosh Paetzel   while (sc != NULL) {
2886c2625e6eSJosh Paetzel     if (oce_rdma_if->announce != NULL) {
2887c2625e6eSJosh Paetzel       memset(&di, 0, sizeof(di));
2888c2625e6eSJosh Paetzel       di.dev = sc->dev;
2889c2625e6eSJosh Paetzel       di.softc = sc;
2890c2625e6eSJosh Paetzel       di.ifp = sc->ifp;
2891c2625e6eSJosh Paetzel       di.db_bhandle = sc->db_bhandle;
2892c2625e6eSJosh Paetzel       di.db_btag = sc->db_btag;
2893c2625e6eSJosh Paetzel       di.db_page_size = 4096;
2894c2625e6eSJosh Paetzel       if (sc->flags & OCE_FLAGS_USING_MSIX) {
2895c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_MSIX;
2896c2625e6eSJosh Paetzel       } else if (sc->flags & OCE_FLAGS_USING_MSI) {
2897c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_MSI;
2898c2625e6eSJosh Paetzel       } else {
2899c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_INTX;
2900c2625e6eSJosh Paetzel       }
2901c2625e6eSJosh Paetzel       di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk
2902c2625e6eSJosh Paetzel       if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) {
2903c2625e6eSJosh Paetzel         di.msix.num_vectors = sc->intr_count + sc->roce_intr_count;
2904c2625e6eSJosh Paetzel         di.msix.start_vector = sc->intr_count;
2905c2625e6eSJosh Paetzel         for (i=0; i<di.msix.num_vectors; i++) {
2906c2625e6eSJosh Paetzel           di.msix.vector_list[i] = sc->intrs[i].vector;
2907c2625e6eSJosh Paetzel         }
2908c2625e6eSJosh Paetzel       } else {
2909c2625e6eSJosh Paetzel       }
2910c2625e6eSJosh Paetzel       memcpy(di.mac_addr, sc->macaddr.mac_addr, 6);
2911c2625e6eSJosh Paetzel       di.vendor_id = pci_get_vendor(sc->dev);
2912c2625e6eSJosh Paetzel       di.dev_id = pci_get_device(sc->dev);
2913c2625e6eSJosh Paetzel 
2914c2625e6eSJosh Paetzel       if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
2915c2625e6eSJosh Paetzel           di.flags  |= OCE_RDMA_INFO_RDMA_SUPPORTED;
2916c2625e6eSJosh Paetzel       }
2917c2625e6eSJosh Paetzel 
2918c2625e6eSJosh Paetzel       rdma_if->announce(&di);
2919c2625e6eSJosh Paetzel       sc = sc->next;
2920c2625e6eSJosh Paetzel     }
2921c2625e6eSJosh Paetzel   }
2922c2625e6eSJosh Paetzel 
2923c2625e6eSJosh Paetzel   return 0;
2924c2625e6eSJosh Paetzel }
2925c2625e6eSJosh Paetzel 
2926c2625e6eSJosh Paetzel static void
2927c2625e6eSJosh Paetzel oce_read_env_variables( POCE_SOFTC sc )
2928c2625e6eSJosh Paetzel {
2929c2625e6eSJosh Paetzel 	char *value = NULL;
2930c2625e6eSJosh Paetzel 	int rc = 0;
2931c2625e6eSJosh Paetzel 
2932c2625e6eSJosh Paetzel         /* read if user wants to enable hwlro or swlro */
2933c2625e6eSJosh Paetzel         //value = getenv("oce_enable_hwlro");
2934c2625e6eSJosh Paetzel         if(value && IS_SH(sc)) {
2935c2625e6eSJosh Paetzel                 sc->enable_hwlro = strtol(value, NULL, 10);
2936c2625e6eSJosh Paetzel                 if(sc->enable_hwlro) {
2937c2625e6eSJosh Paetzel                         rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL);
2938c2625e6eSJosh Paetzel                         if(rc) {
2939c2625e6eSJosh Paetzel                                 device_printf(sc->dev, "no hardware lro support\n");
2940c2625e6eSJosh Paetzel                 		device_printf(sc->dev, "software lro enabled\n");
2941c2625e6eSJosh Paetzel                                 sc->enable_hwlro = 0;
2942c2625e6eSJosh Paetzel                         }else {
2943c2625e6eSJosh Paetzel                                 device_printf(sc->dev, "hardware lro enabled\n");
2944c2625e6eSJosh Paetzel 				oce_max_rsp_handled = 32;
2945c2625e6eSJosh Paetzel                         }
2946c2625e6eSJosh Paetzel                 }else {
2947c2625e6eSJosh Paetzel                         device_printf(sc->dev, "software lro enabled\n");
2948c2625e6eSJosh Paetzel                 }
2949c2625e6eSJosh Paetzel         }else {
2950c2625e6eSJosh Paetzel                 sc->enable_hwlro = 0;
2951c2625e6eSJosh Paetzel         }
2952c2625e6eSJosh Paetzel 
2953c2625e6eSJosh Paetzel         /* read mbuf size */
2954c2625e6eSJosh Paetzel         //value = getenv("oce_rq_buf_size");
2955c2625e6eSJosh Paetzel         if(value && IS_SH(sc)) {
2956c2625e6eSJosh Paetzel                 oce_rq_buf_size = strtol(value, NULL, 10);
2957c2625e6eSJosh Paetzel                 switch(oce_rq_buf_size) {
2958c2625e6eSJosh Paetzel                 case 2048:
2959c2625e6eSJosh Paetzel                 case 4096:
2960c2625e6eSJosh Paetzel                 case 9216:
2961c2625e6eSJosh Paetzel                 case 16384:
2962c2625e6eSJosh Paetzel                         break;
2963c2625e6eSJosh Paetzel 
2964c2625e6eSJosh Paetzel                 default:
2965c2625e6eSJosh Paetzel                         device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n");
2966c2625e6eSJosh Paetzel                         oce_rq_buf_size = 2048;
2967c2625e6eSJosh Paetzel                 }
2968c2625e6eSJosh Paetzel         }
2969c2625e6eSJosh Paetzel 
2970c2625e6eSJosh Paetzel 	return;
2971c2625e6eSJosh Paetzel }
2972