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