xref: /freebsd/sys/dev/oce/oce_if.c (revision ab7de25c25a5d7daa96828b9e535c7c848af913d)
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 /* global vars */
2182f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"};
2192f345d8eSLuigi Rizzo 
2202f345d8eSLuigi Rizzo /* Module capabilites and parameters */
2212f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED;
2222f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS;
223c2625e6eSJosh Paetzel uint32_t oce_rq_buf_size = 2048;
2242f345d8eSLuigi Rizzo 
2252f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled);
2262f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss);
2272f345d8eSLuigi Rizzo 
2282f345d8eSLuigi Rizzo 
2292f345d8eSLuigi Rizzo /* Supported devices table */
2302f345d8eSLuigi Rizzo static uint32_t supportedDevices[] =  {
2312f345d8eSLuigi Rizzo 	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2,
2322f345d8eSLuigi Rizzo 	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3,
2332f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3,
2342f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201,
2352f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF,
236291a1934SXin LI 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH
2372f345d8eSLuigi Rizzo };
2382f345d8eSLuigi Rizzo 
2390dc34160SWarner Losh 
2400dc34160SWarner Losh DRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0);
2410dc34160SWarner Losh MODULE_PNP_INFO("W32:vendor/device", pci, oce, supportedDevices,
2420dc34160SWarner Losh     nitems(supportedDevices));
2430dc34160SWarner Losh MODULE_DEPEND(oce, pci, 1, 1, 1);
2440dc34160SWarner Losh MODULE_DEPEND(oce, ether, 1, 1, 1);
2450dc34160SWarner Losh MODULE_VERSION(oce, 1);
2460dc34160SWarner Losh 
2470dc34160SWarner Losh 
248c2625e6eSJosh Paetzel POCE_SOFTC softc_head = NULL;
249c2625e6eSJosh Paetzel POCE_SOFTC softc_tail = NULL;
2502f345d8eSLuigi Rizzo 
251c2625e6eSJosh Paetzel struct oce_rdma_if *oce_rdma_if = NULL;
2522f345d8eSLuigi Rizzo 
2532f345d8eSLuigi Rizzo /*****************************************************************************
2542f345d8eSLuigi Rizzo  *			Driver entry points functions                        *
2552f345d8eSLuigi Rizzo  *****************************************************************************/
2562f345d8eSLuigi Rizzo 
2572f345d8eSLuigi Rizzo static int
2582f345d8eSLuigi Rizzo oce_probe(device_t dev)
2592f345d8eSLuigi Rizzo {
2609bd3250aSLuigi Rizzo 	uint16_t vendor = 0;
2619bd3250aSLuigi Rizzo 	uint16_t device = 0;
2629bd3250aSLuigi Rizzo 	int i = 0;
2639bd3250aSLuigi Rizzo 	char str[256] = {0};
2642f345d8eSLuigi Rizzo 	POCE_SOFTC sc;
2652f345d8eSLuigi Rizzo 
2662f345d8eSLuigi Rizzo 	sc = device_get_softc(dev);
2672f345d8eSLuigi Rizzo 	bzero(sc, sizeof(OCE_SOFTC));
2682f345d8eSLuigi Rizzo 	sc->dev = dev;
2692f345d8eSLuigi Rizzo 
2702f345d8eSLuigi Rizzo 	vendor = pci_get_vendor(dev);
2712f345d8eSLuigi Rizzo 	device = pci_get_device(dev);
2722f345d8eSLuigi Rizzo 
2739bd3250aSLuigi Rizzo 	for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) {
2742f345d8eSLuigi Rizzo 		if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) {
2752f345d8eSLuigi Rizzo 			if (device == (supportedDevices[i] & 0xffff)) {
2769bd3250aSLuigi Rizzo 				sprintf(str, "%s:%s", "Emulex CNA NIC function",
2772f345d8eSLuigi Rizzo 					component_revision);
2782f345d8eSLuigi Rizzo 				device_set_desc_copy(dev, str);
2792f345d8eSLuigi Rizzo 
2802f345d8eSLuigi Rizzo 				switch (device) {
2812f345d8eSLuigi Rizzo 				case PCI_PRODUCT_BE2:
2822f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_BE2;
2832f345d8eSLuigi Rizzo 					break;
2842f345d8eSLuigi Rizzo 				case PCI_PRODUCT_BE3:
2852f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_BE3;
2862f345d8eSLuigi Rizzo 					break;
2872f345d8eSLuigi Rizzo 				case PCI_PRODUCT_XE201:
2882f345d8eSLuigi Rizzo 				case PCI_PRODUCT_XE201_VF:
2892f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_XE201;
2902f345d8eSLuigi Rizzo 					break;
291291a1934SXin LI 				case PCI_PRODUCT_SH:
292291a1934SXin LI 					sc->flags |= OCE_FLAGS_SH;
293291a1934SXin LI 					break;
2942f345d8eSLuigi Rizzo 				default:
2952f345d8eSLuigi Rizzo 					return ENXIO;
2962f345d8eSLuigi Rizzo 				}
2972f345d8eSLuigi Rizzo 				return BUS_PROBE_DEFAULT;
2982f345d8eSLuigi Rizzo 			}
2992f345d8eSLuigi Rizzo 		}
3002f345d8eSLuigi Rizzo 	}
3012f345d8eSLuigi Rizzo 
3022f345d8eSLuigi Rizzo 	return ENXIO;
3032f345d8eSLuigi Rizzo }
3042f345d8eSLuigi Rizzo 
3052f345d8eSLuigi Rizzo 
3062f345d8eSLuigi Rizzo static int
3072f345d8eSLuigi Rizzo oce_attach(device_t dev)
3082f345d8eSLuigi Rizzo {
3092f345d8eSLuigi Rizzo 	POCE_SOFTC sc;
3102f345d8eSLuigi Rizzo 	int rc = 0;
3112f345d8eSLuigi Rizzo 
3122f345d8eSLuigi Rizzo 	sc = device_get_softc(dev);
3132f345d8eSLuigi Rizzo 
3142f345d8eSLuigi Rizzo 	rc = oce_hw_pci_alloc(sc);
3152f345d8eSLuigi Rizzo 	if (rc)
3162f345d8eSLuigi Rizzo 		return rc;
3172f345d8eSLuigi Rizzo 
3182f345d8eSLuigi Rizzo 	sc->tx_ring_size = OCE_TX_RING_SIZE;
3192f345d8eSLuigi Rizzo 	sc->rx_ring_size = OCE_RX_RING_SIZE;
320c2625e6eSJosh Paetzel 	/* receive fragment size should be multiple of 2K */
321c2625e6eSJosh Paetzel 	sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048);
3222f345d8eSLuigi Rizzo 	sc->flow_control = OCE_DEFAULT_FLOW_CONTROL;
3232f345d8eSLuigi Rizzo 	sc->promisc	 = OCE_DEFAULT_PROMISCUOUS;
3242f345d8eSLuigi Rizzo 
3252f345d8eSLuigi Rizzo 	LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock");
3262f345d8eSLuigi Rizzo 	LOCK_CREATE(&sc->dev_lock,  "Device_lock");
3272f345d8eSLuigi Rizzo 
3282f345d8eSLuigi Rizzo 	/* initialise the hardware */
3292f345d8eSLuigi Rizzo 	rc = oce_hw_init(sc);
3302f345d8eSLuigi Rizzo 	if (rc)
3312f345d8eSLuigi Rizzo 		goto pci_res_free;
3322f345d8eSLuigi Rizzo 
333c2625e6eSJosh Paetzel 	oce_read_env_variables(sc);
334c2625e6eSJosh Paetzel 
335291a1934SXin LI 	oce_get_config(sc);
336291a1934SXin LI 
3372f345d8eSLuigi Rizzo 	setup_max_queues_want(sc);
3382f345d8eSLuigi Rizzo 
3392f345d8eSLuigi Rizzo 	rc = oce_setup_intr(sc);
3402f345d8eSLuigi Rizzo 	if (rc)
3412f345d8eSLuigi Rizzo 		goto mbox_free;
3422f345d8eSLuigi Rizzo 
3432f345d8eSLuigi Rizzo 	rc = oce_queue_init_all(sc);
3442f345d8eSLuigi Rizzo 	if (rc)
3452f345d8eSLuigi Rizzo 		goto intr_free;
3462f345d8eSLuigi Rizzo 
3472f345d8eSLuigi Rizzo 	rc = oce_attach_ifp(sc);
3482f345d8eSLuigi Rizzo 	if (rc)
3492f345d8eSLuigi Rizzo 		goto queues_free;
3502f345d8eSLuigi Rizzo 
351ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3522f345d8eSLuigi Rizzo 	rc = oce_init_lro(sc);
3532f345d8eSLuigi Rizzo 	if (rc)
3542f345d8eSLuigi Rizzo 		goto ifp_free;
355ad512958SBjoern A. Zeeb #endif
3562f345d8eSLuigi Rizzo 
3572f345d8eSLuigi Rizzo 	rc = oce_hw_start(sc);
3582f345d8eSLuigi Rizzo 	if (rc)
359db702c59SEitan Adler 		goto lro_free;
3602f345d8eSLuigi Rizzo 
3612f345d8eSLuigi Rizzo 	sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
3622f345d8eSLuigi Rizzo 				oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST);
3632f345d8eSLuigi Rizzo 	sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
3642f345d8eSLuigi Rizzo 				oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST);
3652f345d8eSLuigi Rizzo 
3662f345d8eSLuigi Rizzo 	rc = oce_stats_init(sc);
3672f345d8eSLuigi Rizzo 	if (rc)
3682f345d8eSLuigi Rizzo 		goto vlan_free;
3692f345d8eSLuigi Rizzo 
3702f345d8eSLuigi Rizzo 	oce_add_sysctls(sc);
3712f345d8eSLuigi Rizzo 
372c2625e6eSJosh Paetzel 	callout_init(&sc->timer, CALLOUT_MPSAFE);
3732f345d8eSLuigi Rizzo 	rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc);
3742f345d8eSLuigi Rizzo 	if (rc)
3752f345d8eSLuigi Rizzo 		goto stats_free;
3762f345d8eSLuigi Rizzo 
377c2625e6eSJosh Paetzel 	sc->next =NULL;
378c2625e6eSJosh Paetzel 	if (softc_tail != NULL) {
379c2625e6eSJosh Paetzel 	  softc_tail->next = sc;
380c2625e6eSJosh Paetzel 	} else {
381c2625e6eSJosh Paetzel 	  softc_head = sc;
382c2625e6eSJosh Paetzel 	}
383c2625e6eSJosh Paetzel 	softc_tail = sc;
384c2625e6eSJosh Paetzel 
3852f345d8eSLuigi Rizzo 	return 0;
3862f345d8eSLuigi Rizzo 
3872f345d8eSLuigi Rizzo stats_free:
3882f345d8eSLuigi Rizzo 	callout_drain(&sc->timer);
3892f345d8eSLuigi Rizzo 	oce_stats_free(sc);
3902f345d8eSLuigi Rizzo vlan_free:
3912f345d8eSLuigi Rizzo 	if (sc->vlan_attach)
3922f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
3932f345d8eSLuigi Rizzo 	if (sc->vlan_detach)
3942f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
3952f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
3962f345d8eSLuigi Rizzo lro_free:
397ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3982f345d8eSLuigi Rizzo 	oce_free_lro(sc);
3992f345d8eSLuigi Rizzo ifp_free:
400ad512958SBjoern A. Zeeb #endif
4012f345d8eSLuigi Rizzo 	ether_ifdetach(sc->ifp);
4022f345d8eSLuigi Rizzo 	if_free(sc->ifp);
4032f345d8eSLuigi Rizzo queues_free:
4042f345d8eSLuigi Rizzo 	oce_queue_release_all(sc);
4052f345d8eSLuigi Rizzo intr_free:
4062f345d8eSLuigi Rizzo 	oce_intr_free(sc);
4072f345d8eSLuigi Rizzo mbox_free:
4082f345d8eSLuigi Rizzo 	oce_dma_free(sc, &sc->bsmbx);
4092f345d8eSLuigi Rizzo pci_res_free:
4102f345d8eSLuigi Rizzo 	oce_hw_pci_free(sc);
4112f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->dev_lock);
4122f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->bmbx_lock);
4132f345d8eSLuigi Rizzo 	return rc;
4142f345d8eSLuigi Rizzo 
4152f345d8eSLuigi Rizzo }
4162f345d8eSLuigi Rizzo 
4172f345d8eSLuigi Rizzo 
4182f345d8eSLuigi Rizzo static int
4192f345d8eSLuigi Rizzo oce_detach(device_t dev)
4202f345d8eSLuigi Rizzo {
4212f345d8eSLuigi Rizzo 	POCE_SOFTC sc = device_get_softc(dev);
422c2625e6eSJosh Paetzel 	POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL;
423c2625e6eSJosh Paetzel 
424c2625e6eSJosh Paetzel         poce_sc_tmp = softc_head;
425c2625e6eSJosh Paetzel         ppoce_sc_tmp1 = &softc_head;
426c2625e6eSJosh Paetzel         while (poce_sc_tmp != NULL) {
427c2625e6eSJosh Paetzel           if (poce_sc_tmp == sc) {
428c2625e6eSJosh Paetzel             *ppoce_sc_tmp1 = sc->next;
429c2625e6eSJosh Paetzel             if (sc->next == NULL) {
430c2625e6eSJosh Paetzel               softc_tail = poce_sc_tmp2;
431c2625e6eSJosh Paetzel             }
432c2625e6eSJosh Paetzel             break;
433c2625e6eSJosh Paetzel           }
434c2625e6eSJosh Paetzel           poce_sc_tmp2 = poce_sc_tmp;
435c2625e6eSJosh Paetzel           ppoce_sc_tmp1 = &poce_sc_tmp->next;
436c2625e6eSJosh Paetzel           poce_sc_tmp = poce_sc_tmp->next;
437c2625e6eSJosh Paetzel         }
4382f345d8eSLuigi Rizzo 
4392f345d8eSLuigi Rizzo 	LOCK(&sc->dev_lock);
4402f345d8eSLuigi Rizzo 	oce_if_deactivate(sc);
4412f345d8eSLuigi Rizzo 	UNLOCK(&sc->dev_lock);
4422f345d8eSLuigi Rizzo 
4432f345d8eSLuigi Rizzo 	callout_drain(&sc->timer);
4442f345d8eSLuigi Rizzo 
4452f345d8eSLuigi Rizzo 	if (sc->vlan_attach != NULL)
4462f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
4472f345d8eSLuigi Rizzo 	if (sc->vlan_detach != NULL)
4482f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
4492f345d8eSLuigi Rizzo 
4502f345d8eSLuigi Rizzo 	ether_ifdetach(sc->ifp);
4512f345d8eSLuigi Rizzo 
4522f345d8eSLuigi Rizzo 	if_free(sc->ifp);
4532f345d8eSLuigi Rizzo 
4542f345d8eSLuigi Rizzo 	oce_hw_shutdown(sc);
4552f345d8eSLuigi Rizzo 
4562f345d8eSLuigi Rizzo 	bus_generic_detach(dev);
4572f345d8eSLuigi Rizzo 
4582f345d8eSLuigi Rizzo 	return 0;
4592f345d8eSLuigi Rizzo }
4602f345d8eSLuigi Rizzo 
4612f345d8eSLuigi Rizzo 
4622f345d8eSLuigi Rizzo static int
4632f345d8eSLuigi Rizzo oce_shutdown(device_t dev)
4642f345d8eSLuigi Rizzo {
4652f345d8eSLuigi Rizzo 	int rc;
4662f345d8eSLuigi Rizzo 
4672f345d8eSLuigi Rizzo 	rc = oce_detach(dev);
4682f345d8eSLuigi Rizzo 
4692f345d8eSLuigi Rizzo 	return rc;
4702f345d8eSLuigi Rizzo }
4712f345d8eSLuigi Rizzo 
4722f345d8eSLuigi Rizzo 
4732f345d8eSLuigi Rizzo static int
4742f345d8eSLuigi Rizzo oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
4752f345d8eSLuigi Rizzo {
4762f345d8eSLuigi Rizzo 	struct ifreq *ifr = (struct ifreq *)data;
4772f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
478e0dd0fe3SXin LI 	struct ifi2creq i2c;
479e0dd0fe3SXin LI 	uint8_t	offset = 0;
4802f345d8eSLuigi Rizzo 	int rc = 0;
4812f345d8eSLuigi Rizzo 	uint32_t u;
4822f345d8eSLuigi Rizzo 
4832f345d8eSLuigi Rizzo 	switch (command) {
4842f345d8eSLuigi Rizzo 
4852f345d8eSLuigi Rizzo 	case SIOCGIFMEDIA:
4862f345d8eSLuigi Rizzo 		rc = ifmedia_ioctl(ifp, ifr, &sc->media, command);
4872f345d8eSLuigi Rizzo 		break;
4882f345d8eSLuigi Rizzo 
4892f345d8eSLuigi Rizzo 	case SIOCSIFMTU:
4902f345d8eSLuigi Rizzo 		if (ifr->ifr_mtu > OCE_MAX_MTU)
4912f345d8eSLuigi Rizzo 			rc = EINVAL;
4922f345d8eSLuigi Rizzo 		else
4932f345d8eSLuigi Rizzo 			ifp->if_mtu = ifr->ifr_mtu;
4942f345d8eSLuigi Rizzo 		break;
4952f345d8eSLuigi Rizzo 
4962f345d8eSLuigi Rizzo 	case SIOCSIFFLAGS:
4972f345d8eSLuigi Rizzo 		if (ifp->if_flags & IFF_UP) {
4982f345d8eSLuigi Rizzo 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
4992f345d8eSLuigi Rizzo 				sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
5002f345d8eSLuigi Rizzo 				oce_init(sc);
5012f345d8eSLuigi Rizzo 			}
5022f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Interface Up\n");
5032f345d8eSLuigi Rizzo 		} else {
5042f345d8eSLuigi Rizzo 			LOCK(&sc->dev_lock);
5052f345d8eSLuigi Rizzo 
5062f345d8eSLuigi Rizzo 			sc->ifp->if_drv_flags &=
5072f345d8eSLuigi Rizzo 			    ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
5082f345d8eSLuigi Rizzo 			oce_if_deactivate(sc);
5092f345d8eSLuigi Rizzo 
5102f345d8eSLuigi Rizzo 			UNLOCK(&sc->dev_lock);
5112f345d8eSLuigi Rizzo 
5122f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Interface Down\n");
5132f345d8eSLuigi Rizzo 		}
5142f345d8eSLuigi Rizzo 
5152f345d8eSLuigi Rizzo 		if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) {
5165fbb6830SXin LI 			if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1))))
5172f345d8eSLuigi Rizzo 				sc->promisc = TRUE;
5182f345d8eSLuigi Rizzo 		} else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) {
5195fbb6830SXin LI 			if (!oce_rxf_set_promiscuous(sc, 0))
5202f345d8eSLuigi Rizzo 				sc->promisc = FALSE;
5212f345d8eSLuigi Rizzo 		}
5222f345d8eSLuigi Rizzo 
5232f345d8eSLuigi Rizzo 		break;
5242f345d8eSLuigi Rizzo 
5252f345d8eSLuigi Rizzo 	case SIOCADDMULTI:
5262f345d8eSLuigi Rizzo 	case SIOCDELMULTI:
5272f345d8eSLuigi Rizzo 		rc = oce_hw_update_multicast(sc);
5282f345d8eSLuigi Rizzo 		if (rc)
5292f345d8eSLuigi Rizzo 			device_printf(sc->dev,
5302f345d8eSLuigi Rizzo 				"Update multicast address failed\n");
5312f345d8eSLuigi Rizzo 		break;
5322f345d8eSLuigi Rizzo 
5332f345d8eSLuigi Rizzo 	case SIOCSIFCAP:
5342f345d8eSLuigi Rizzo 		u = ifr->ifr_reqcap ^ ifp->if_capenable;
5352f345d8eSLuigi Rizzo 
5362f345d8eSLuigi Rizzo 		if (u & IFCAP_TXCSUM) {
5372f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_TXCSUM;
5382f345d8eSLuigi Rizzo 			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
5392f345d8eSLuigi Rizzo 
5402f345d8eSLuigi Rizzo 			if (IFCAP_TSO & ifp->if_capenable &&
5412f345d8eSLuigi Rizzo 			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
5422f345d8eSLuigi Rizzo 				ifp->if_capenable &= ~IFCAP_TSO;
5432f345d8eSLuigi Rizzo 				ifp->if_hwassist &= ~CSUM_TSO;
5442f345d8eSLuigi Rizzo 				if_printf(ifp,
5452f345d8eSLuigi Rizzo 					 "TSO disabled due to -txcsum.\n");
5462f345d8eSLuigi Rizzo 			}
5472f345d8eSLuigi Rizzo 		}
5482f345d8eSLuigi Rizzo 
5492f345d8eSLuigi Rizzo 		if (u & IFCAP_RXCSUM)
5502f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_RXCSUM;
5512f345d8eSLuigi Rizzo 
5522f345d8eSLuigi Rizzo 		if (u & IFCAP_TSO4) {
5532f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_TSO4;
5542f345d8eSLuigi Rizzo 
5552f345d8eSLuigi Rizzo 			if (IFCAP_TSO & ifp->if_capenable) {
5562f345d8eSLuigi Rizzo 				if (IFCAP_TXCSUM & ifp->if_capenable)
5572f345d8eSLuigi Rizzo 					ifp->if_hwassist |= CSUM_TSO;
5582f345d8eSLuigi Rizzo 				else {
5592f345d8eSLuigi Rizzo 					ifp->if_capenable &= ~IFCAP_TSO;
5602f345d8eSLuigi Rizzo 					ifp->if_hwassist &= ~CSUM_TSO;
5612f345d8eSLuigi Rizzo 					if_printf(ifp,
5622f345d8eSLuigi Rizzo 					    "Enable txcsum first.\n");
5632f345d8eSLuigi Rizzo 					rc = EAGAIN;
5642f345d8eSLuigi Rizzo 				}
5652f345d8eSLuigi Rizzo 			} else
5662f345d8eSLuigi Rizzo 				ifp->if_hwassist &= ~CSUM_TSO;
5672f345d8eSLuigi Rizzo 		}
5682f345d8eSLuigi Rizzo 
5692f345d8eSLuigi Rizzo 		if (u & IFCAP_VLAN_HWTAGGING)
5702f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
5712f345d8eSLuigi Rizzo 
5722f345d8eSLuigi Rizzo 		if (u & IFCAP_VLAN_HWFILTER) {
5732f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
5742f345d8eSLuigi Rizzo 			oce_vid_config(sc);
5752f345d8eSLuigi Rizzo 		}
576ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
577c2625e6eSJosh Paetzel 		if (u & IFCAP_LRO) {
5782f345d8eSLuigi Rizzo 			ifp->if_capenable ^= IFCAP_LRO;
579c2625e6eSJosh Paetzel 			if(sc->enable_hwlro) {
580c2625e6eSJosh Paetzel 				if(ifp->if_capenable & IFCAP_LRO) {
581c2625e6eSJosh Paetzel 					rc = oce_mbox_nic_set_iface_lro_config(sc, 1);
582c2625e6eSJosh Paetzel 				}else {
583c2625e6eSJosh Paetzel 					rc = oce_mbox_nic_set_iface_lro_config(sc, 0);
584c2625e6eSJosh Paetzel 				}
585c2625e6eSJosh Paetzel 			}
586c2625e6eSJosh Paetzel 		}
587ad512958SBjoern A. Zeeb #endif
5882f345d8eSLuigi Rizzo 
5892f345d8eSLuigi Rizzo 		break;
5902f345d8eSLuigi Rizzo 
591e0dd0fe3SXin LI 	case SIOCGI2C:
592e0dd0fe3SXin LI 		rc = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
593e0dd0fe3SXin LI 		if (rc)
594e0dd0fe3SXin LI 			break;
595e0dd0fe3SXin LI 
596e0dd0fe3SXin LI 		if (i2c.dev_addr != PAGE_NUM_A0 &&
597e0dd0fe3SXin LI 		    i2c.dev_addr != PAGE_NUM_A2) {
598e0dd0fe3SXin LI 			rc = EINVAL;
599e0dd0fe3SXin LI 			break;
600e0dd0fe3SXin LI 		}
601e0dd0fe3SXin LI 
602e0dd0fe3SXin LI 		if (i2c.len > sizeof(i2c.data)) {
603e0dd0fe3SXin LI 			rc = EINVAL;
604e0dd0fe3SXin LI 			break;
605e0dd0fe3SXin LI 		}
606e0dd0fe3SXin LI 
607e0dd0fe3SXin LI 		rc = oce_mbox_read_transrecv_data(sc, i2c.dev_addr);
608e0dd0fe3SXin LI 		if(rc) {
609e0dd0fe3SXin LI 			rc = -rc;
610e0dd0fe3SXin LI 			break;
611e0dd0fe3SXin LI 		}
612e0dd0fe3SXin LI 
613e0dd0fe3SXin LI 		if (i2c.dev_addr == PAGE_NUM_A0)
614e0dd0fe3SXin LI 			offset = i2c.offset;
615e0dd0fe3SXin LI 		else
616e0dd0fe3SXin LI 			offset = TRANSCEIVER_A0_SIZE + i2c.offset;
617e0dd0fe3SXin LI 
618e0dd0fe3SXin LI 		memcpy(&i2c.data[0], &sfp_vpd_dump_buffer[offset], i2c.len);
619e0dd0fe3SXin LI 
620e0dd0fe3SXin LI 		rc = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c));
621e0dd0fe3SXin LI 		break;
622e0dd0fe3SXin LI 
6232f345d8eSLuigi Rizzo 	case SIOCGPRIVATE_0:
6242f345d8eSLuigi Rizzo 		rc = oce_handle_passthrough(ifp, data);
6252f345d8eSLuigi Rizzo 		break;
6262f345d8eSLuigi Rizzo 	default:
6272f345d8eSLuigi Rizzo 		rc = ether_ioctl(ifp, command, data);
6282f345d8eSLuigi Rizzo 		break;
6292f345d8eSLuigi Rizzo 	}
6302f345d8eSLuigi Rizzo 
6312f345d8eSLuigi Rizzo 	return rc;
6322f345d8eSLuigi Rizzo }
6332f345d8eSLuigi Rizzo 
6342f345d8eSLuigi Rizzo 
6352f345d8eSLuigi Rizzo static void
6362f345d8eSLuigi Rizzo oce_init(void *arg)
6372f345d8eSLuigi Rizzo {
6382f345d8eSLuigi Rizzo 	POCE_SOFTC sc = arg;
6392f345d8eSLuigi Rizzo 
6402f345d8eSLuigi Rizzo 	LOCK(&sc->dev_lock);
6412f345d8eSLuigi Rizzo 
6422f345d8eSLuigi Rizzo 	if (sc->ifp->if_flags & IFF_UP) {
6432f345d8eSLuigi Rizzo 		oce_if_deactivate(sc);
6442f345d8eSLuigi Rizzo 		oce_if_activate(sc);
6452f345d8eSLuigi Rizzo 	}
6462f345d8eSLuigi Rizzo 
6472f345d8eSLuigi Rizzo 	UNLOCK(&sc->dev_lock);
6482f345d8eSLuigi Rizzo 
6492f345d8eSLuigi Rizzo }
6502f345d8eSLuigi Rizzo 
6512f345d8eSLuigi Rizzo 
6522f345d8eSLuigi Rizzo static int
6532f345d8eSLuigi Rizzo oce_multiq_start(struct ifnet *ifp, struct mbuf *m)
6542f345d8eSLuigi Rizzo {
6552f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
6562f345d8eSLuigi Rizzo 	struct oce_wq *wq = NULL;
6572f345d8eSLuigi Rizzo 	int queue_index = 0;
6582f345d8eSLuigi Rizzo 	int status = 0;
6592f345d8eSLuigi Rizzo 
660c2625e6eSJosh Paetzel 	if (!sc->link_status)
661c2625e6eSJosh Paetzel 		return ENXIO;
662c2625e6eSJosh Paetzel 
663c2529042SHans Petter Selasky 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
6642f345d8eSLuigi Rizzo 		queue_index = m->m_pkthdr.flowid % sc->nwqs;
6652f345d8eSLuigi Rizzo 
6662f345d8eSLuigi Rizzo 	wq = sc->wq[queue_index];
6672f345d8eSLuigi Rizzo 
668291a1934SXin LI 	LOCK(&wq->tx_lock);
6692f345d8eSLuigi Rizzo 	status = oce_multiq_transmit(ifp, m, wq);
6702f345d8eSLuigi Rizzo 	UNLOCK(&wq->tx_lock);
671291a1934SXin LI 
6722f345d8eSLuigi Rizzo 	return status;
6732f345d8eSLuigi Rizzo 
6742f345d8eSLuigi Rizzo }
6752f345d8eSLuigi Rizzo 
6762f345d8eSLuigi Rizzo 
6772f345d8eSLuigi Rizzo static void
6782f345d8eSLuigi Rizzo oce_multiq_flush(struct ifnet *ifp)
6792f345d8eSLuigi Rizzo {
6802f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
6812f345d8eSLuigi Rizzo 	struct mbuf     *m;
6822f345d8eSLuigi Rizzo 	int i = 0;
6832f345d8eSLuigi Rizzo 
6842f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nwqs; i++) {
6852f345d8eSLuigi Rizzo 		while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
6862f345d8eSLuigi Rizzo 			m_freem(m);
6872f345d8eSLuigi Rizzo 	}
6882f345d8eSLuigi Rizzo 	if_qflush(ifp);
6892f345d8eSLuigi Rizzo }
6902f345d8eSLuigi Rizzo 
6912f345d8eSLuigi Rizzo 
6922f345d8eSLuigi Rizzo 
6932f345d8eSLuigi Rizzo /*****************************************************************************
6942f345d8eSLuigi Rizzo  *                   Driver interrupt routines functions                     *
6952f345d8eSLuigi Rizzo  *****************************************************************************/
6962f345d8eSLuigi Rizzo 
6972f345d8eSLuigi Rizzo static void
6982f345d8eSLuigi Rizzo oce_intr(void *arg, int pending)
6992f345d8eSLuigi Rizzo {
7002f345d8eSLuigi Rizzo 
7012f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
7022f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ii->sc;
7032f345d8eSLuigi Rizzo 	struct oce_eq *eq = ii->eq;
7042f345d8eSLuigi Rizzo 	struct oce_eqe *eqe;
7052f345d8eSLuigi Rizzo 	struct oce_cq *cq = NULL;
7062f345d8eSLuigi Rizzo 	int i, num_eqes = 0;
7072f345d8eSLuigi Rizzo 
7082f345d8eSLuigi Rizzo 
7092f345d8eSLuigi Rizzo 	bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
7102f345d8eSLuigi Rizzo 				 BUS_DMASYNC_POSTWRITE);
7112f345d8eSLuigi Rizzo 	do {
7122f345d8eSLuigi Rizzo 		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
7132f345d8eSLuigi Rizzo 		if (eqe->evnt == 0)
7142f345d8eSLuigi Rizzo 			break;
7152f345d8eSLuigi Rizzo 		eqe->evnt = 0;
7162f345d8eSLuigi Rizzo 		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
7172f345d8eSLuigi Rizzo 					BUS_DMASYNC_POSTWRITE);
7182f345d8eSLuigi Rizzo 		RING_GET(eq->ring, 1);
7192f345d8eSLuigi Rizzo 		num_eqes++;
7202f345d8eSLuigi Rizzo 
7212f345d8eSLuigi Rizzo 	} while (TRUE);
7222f345d8eSLuigi Rizzo 
7232f345d8eSLuigi Rizzo 	if (!num_eqes)
7242f345d8eSLuigi Rizzo 		goto eq_arm; /* Spurious */
7252f345d8eSLuigi Rizzo 
7262f345d8eSLuigi Rizzo  	/* Clear EQ entries, but dont arm */
7272f345d8eSLuigi Rizzo 	oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
7282f345d8eSLuigi Rizzo 
7292f345d8eSLuigi Rizzo 	/* Process TX, RX and MCC. But dont arm CQ*/
7302f345d8eSLuigi Rizzo 	for (i = 0; i < eq->cq_valid; i++) {
7312f345d8eSLuigi Rizzo 		cq = eq->cq[i];
7322f345d8eSLuigi Rizzo 		(*cq->cq_handler)(cq->cb_arg);
7332f345d8eSLuigi Rizzo 	}
7342f345d8eSLuigi Rizzo 
7352f345d8eSLuigi Rizzo 	/* Arm all cqs connected to this EQ */
7362f345d8eSLuigi Rizzo 	for (i = 0; i < eq->cq_valid; i++) {
7372f345d8eSLuigi Rizzo 		cq = eq->cq[i];
7382f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, 0, TRUE);
7392f345d8eSLuigi Rizzo 	}
7402f345d8eSLuigi Rizzo 
7412f345d8eSLuigi Rizzo eq_arm:
7422f345d8eSLuigi Rizzo 	oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
743cdaba892SXin LI 
7442f345d8eSLuigi Rizzo 	return;
7452f345d8eSLuigi Rizzo }
7462f345d8eSLuigi Rizzo 
7472f345d8eSLuigi Rizzo 
7482f345d8eSLuigi Rizzo static int
7492f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc)
7502f345d8eSLuigi Rizzo {
7512f345d8eSLuigi Rizzo 	int rc = 0, use_intx = 0;
7522f345d8eSLuigi Rizzo 	int vector = 0, req_vectors = 0;
753c2625e6eSJosh Paetzel 	int tot_req_vectors, tot_vectors;
7542f345d8eSLuigi Rizzo 
755291a1934SXin LI 	if (is_rss_enabled(sc))
7562f345d8eSLuigi Rizzo 		req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
7572f345d8eSLuigi Rizzo 	else
7582f345d8eSLuigi Rizzo 		req_vectors = 1;
7592f345d8eSLuigi Rizzo 
760c2625e6eSJosh Paetzel 	tot_req_vectors = req_vectors;
761c2625e6eSJosh Paetzel 	if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
762c2625e6eSJosh Paetzel 	  if (req_vectors > 1) {
763c2625e6eSJosh Paetzel 	    tot_req_vectors += OCE_RDMA_VECTORS;
764c2625e6eSJosh Paetzel 	    sc->roce_intr_count = OCE_RDMA_VECTORS;
765c2625e6eSJosh Paetzel 	  }
766c2625e6eSJosh Paetzel 	}
767c2625e6eSJosh Paetzel 
7682f345d8eSLuigi Rizzo         if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
7692f345d8eSLuigi Rizzo 		sc->intr_count = req_vectors;
770c2625e6eSJosh Paetzel                 tot_vectors = tot_req_vectors;
771c2625e6eSJosh Paetzel 		rc = pci_alloc_msix(sc->dev, &tot_vectors);
7722f345d8eSLuigi Rizzo 		if (rc != 0) {
7732f345d8eSLuigi Rizzo 			use_intx = 1;
7742f345d8eSLuigi Rizzo 			pci_release_msi(sc->dev);
775c2625e6eSJosh Paetzel 		} else {
776c2625e6eSJosh Paetzel 		  if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
777c2625e6eSJosh Paetzel 		    if (tot_vectors < tot_req_vectors) {
778c2625e6eSJosh Paetzel 		      if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) {
779c2625e6eSJosh Paetzel 			sc->roce_intr_count = (tot_vectors / 2);
780c2625e6eSJosh Paetzel 		      }
781c2625e6eSJosh Paetzel 		      sc->intr_count = tot_vectors - sc->roce_intr_count;
782c2625e6eSJosh Paetzel 		    }
783c2625e6eSJosh Paetzel 		  } else {
784c2625e6eSJosh Paetzel 		    sc->intr_count = tot_vectors;
785c2625e6eSJosh Paetzel 		  }
7862f345d8eSLuigi Rizzo     		  sc->flags |= OCE_FLAGS_USING_MSIX;
787c2625e6eSJosh Paetzel 		}
7882f345d8eSLuigi Rizzo 	} else
7892f345d8eSLuigi Rizzo 		use_intx = 1;
7902f345d8eSLuigi Rizzo 
7912f345d8eSLuigi Rizzo 	if (use_intx)
7922f345d8eSLuigi Rizzo 		sc->intr_count = 1;
7932f345d8eSLuigi Rizzo 
7942f345d8eSLuigi Rizzo 	/* Scale number of queues based on intr we got */
7952f345d8eSLuigi Rizzo 	update_queues_got(sc);
7962f345d8eSLuigi Rizzo 
7972f345d8eSLuigi Rizzo 	if (use_intx) {
7982f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Using legacy interrupt\n");
7992f345d8eSLuigi Rizzo 		rc = oce_alloc_intr(sc, vector, oce_intr);
8002f345d8eSLuigi Rizzo 		if (rc)
8012f345d8eSLuigi Rizzo 			goto error;
8022f345d8eSLuigi Rizzo 	} else {
8032f345d8eSLuigi Rizzo 		for (; vector < sc->intr_count; vector++) {
8042f345d8eSLuigi Rizzo 			rc = oce_alloc_intr(sc, vector, oce_intr);
8052f345d8eSLuigi Rizzo 			if (rc)
8062f345d8eSLuigi Rizzo 				goto error;
8072f345d8eSLuigi Rizzo 		}
8082f345d8eSLuigi Rizzo 	}
8092f345d8eSLuigi Rizzo 
8102f345d8eSLuigi Rizzo 	return 0;
8112f345d8eSLuigi Rizzo error:
8122f345d8eSLuigi Rizzo 	oce_intr_free(sc);
8132f345d8eSLuigi Rizzo 	return rc;
8142f345d8eSLuigi Rizzo }
8152f345d8eSLuigi Rizzo 
8162f345d8eSLuigi Rizzo 
8172f345d8eSLuigi Rizzo static int
8182f345d8eSLuigi Rizzo oce_fast_isr(void *arg)
8192f345d8eSLuigi Rizzo {
8202f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
8212f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ii->sc;
8222f345d8eSLuigi Rizzo 
8232f345d8eSLuigi Rizzo 	if (ii->eq == NULL)
8242f345d8eSLuigi Rizzo 		return FILTER_STRAY;
8252f345d8eSLuigi Rizzo 
8262f345d8eSLuigi Rizzo 	oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
8272f345d8eSLuigi Rizzo 
828cbc4d2dbSJohn Baldwin 	taskqueue_enqueue(ii->tq, &ii->task);
8292f345d8eSLuigi Rizzo 
830cdaba892SXin LI  	ii->eq->intr++;
831cdaba892SXin LI 
8322f345d8eSLuigi Rizzo 	return FILTER_HANDLED;
8332f345d8eSLuigi Rizzo }
8342f345d8eSLuigi Rizzo 
8352f345d8eSLuigi Rizzo 
8362f345d8eSLuigi Rizzo static int
8372f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
8382f345d8eSLuigi Rizzo {
839*ab7de25cSKyle Evans 	POCE_INTR_INFO ii;
8402f345d8eSLuigi Rizzo 	int rc = 0, rr;
8412f345d8eSLuigi Rizzo 
8422f345d8eSLuigi Rizzo 	if (vector >= OCE_MAX_EQ)
8432f345d8eSLuigi Rizzo 		return (EINVAL);
8442f345d8eSLuigi Rizzo 
845*ab7de25cSKyle Evans 	ii = &sc->intrs[vector];
846*ab7de25cSKyle Evans 
8472f345d8eSLuigi Rizzo 	/* Set the resource id for the interrupt.
8482f345d8eSLuigi Rizzo 	 * MSIx is vector + 1 for the resource id,
8492f345d8eSLuigi Rizzo 	 * INTx is 0 for the resource id.
8502f345d8eSLuigi Rizzo 	 */
8512f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_USING_MSIX)
8522f345d8eSLuigi Rizzo 		rr = vector + 1;
8532f345d8eSLuigi Rizzo 	else
8542f345d8eSLuigi Rizzo 		rr = 0;
8552f345d8eSLuigi Rizzo 	ii->intr_res = bus_alloc_resource_any(sc->dev,
8562f345d8eSLuigi Rizzo 					      SYS_RES_IRQ,
8572f345d8eSLuigi Rizzo 					      &rr, RF_ACTIVE|RF_SHAREABLE);
8582f345d8eSLuigi Rizzo 	ii->irq_rr = rr;
8592f345d8eSLuigi Rizzo 	if (ii->intr_res == NULL) {
8602f345d8eSLuigi Rizzo 		device_printf(sc->dev,
8612f345d8eSLuigi Rizzo 			  "Could not allocate interrupt\n");
8622f345d8eSLuigi Rizzo 		rc = ENXIO;
8632f345d8eSLuigi Rizzo 		return rc;
8642f345d8eSLuigi Rizzo 	}
8652f345d8eSLuigi Rizzo 
8662f345d8eSLuigi Rizzo 	TASK_INIT(&ii->task, 0, isr, ii);
8672f345d8eSLuigi Rizzo 	ii->vector = vector;
8682f345d8eSLuigi Rizzo 	sprintf(ii->task_name, "oce_task[%d]", ii->vector);
8692f345d8eSLuigi Rizzo 	ii->tq = taskqueue_create_fast(ii->task_name,
8702f345d8eSLuigi Rizzo 			M_NOWAIT,
8712f345d8eSLuigi Rizzo 			taskqueue_thread_enqueue,
8722f345d8eSLuigi Rizzo 			&ii->tq);
8732f345d8eSLuigi Rizzo 	taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
8742f345d8eSLuigi Rizzo 			device_get_nameunit(sc->dev));
8752f345d8eSLuigi Rizzo 
8762f345d8eSLuigi Rizzo 	ii->sc = sc;
8772f345d8eSLuigi Rizzo 	rc = bus_setup_intr(sc->dev,
8782f345d8eSLuigi Rizzo 			ii->intr_res,
8792f345d8eSLuigi Rizzo 			INTR_TYPE_NET,
8802f345d8eSLuigi Rizzo 			oce_fast_isr, NULL, ii, &ii->tag);
8812f345d8eSLuigi Rizzo 	return rc;
8822f345d8eSLuigi Rizzo 
8832f345d8eSLuigi Rizzo }
8842f345d8eSLuigi Rizzo 
8852f345d8eSLuigi Rizzo 
8862f345d8eSLuigi Rizzo void
8872f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc)
8882f345d8eSLuigi Rizzo {
8892f345d8eSLuigi Rizzo 	int i = 0;
8902f345d8eSLuigi Rizzo 
8912f345d8eSLuigi Rizzo 	for (i = 0; i < sc->intr_count; i++) {
8922f345d8eSLuigi Rizzo 
8932f345d8eSLuigi Rizzo 		if (sc->intrs[i].tag != NULL)
8942f345d8eSLuigi Rizzo 			bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
8952f345d8eSLuigi Rizzo 						sc->intrs[i].tag);
8962f345d8eSLuigi Rizzo 		if (sc->intrs[i].tq != NULL)
8972f345d8eSLuigi Rizzo 			taskqueue_free(sc->intrs[i].tq);
8982f345d8eSLuigi Rizzo 
8992f345d8eSLuigi Rizzo 		if (sc->intrs[i].intr_res != NULL)
9002f345d8eSLuigi Rizzo 			bus_release_resource(sc->dev, SYS_RES_IRQ,
9012f345d8eSLuigi Rizzo 						sc->intrs[i].irq_rr,
9022f345d8eSLuigi Rizzo 						sc->intrs[i].intr_res);
9032f345d8eSLuigi Rizzo 		sc->intrs[i].tag = NULL;
9042f345d8eSLuigi Rizzo 		sc->intrs[i].intr_res = NULL;
9052f345d8eSLuigi Rizzo 	}
9062f345d8eSLuigi Rizzo 
9072f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_USING_MSIX)
9082f345d8eSLuigi Rizzo 		pci_release_msi(sc->dev);
9092f345d8eSLuigi Rizzo 
9102f345d8eSLuigi Rizzo }
9112f345d8eSLuigi Rizzo 
9122f345d8eSLuigi Rizzo 
9132f345d8eSLuigi Rizzo 
9142f345d8eSLuigi Rizzo /******************************************************************************
9152f345d8eSLuigi Rizzo *			  Media callbacks functions 			      *
9162f345d8eSLuigi Rizzo ******************************************************************************/
9172f345d8eSLuigi Rizzo 
9182f345d8eSLuigi Rizzo static void
9192f345d8eSLuigi Rizzo oce_media_status(struct ifnet *ifp, struct ifmediareq *req)
9202f345d8eSLuigi Rizzo {
9212f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc;
9222f345d8eSLuigi Rizzo 
9232f345d8eSLuigi Rizzo 
9242f345d8eSLuigi Rizzo 	req->ifm_status = IFM_AVALID;
9252f345d8eSLuigi Rizzo 	req->ifm_active = IFM_ETHER;
9262f345d8eSLuigi Rizzo 
9272f345d8eSLuigi Rizzo 	if (sc->link_status == 1)
9282f345d8eSLuigi Rizzo 		req->ifm_status |= IFM_ACTIVE;
9292f345d8eSLuigi Rizzo 	else
9302f345d8eSLuigi Rizzo 		return;
9312f345d8eSLuigi Rizzo 
9322f345d8eSLuigi Rizzo 	switch (sc->link_speed) {
9332f345d8eSLuigi Rizzo 	case 1: /* 10 Mbps */
9342f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_10_T | IFM_FDX;
9352f345d8eSLuigi Rizzo 		sc->speed = 10;
9362f345d8eSLuigi Rizzo 		break;
9372f345d8eSLuigi Rizzo 	case 2: /* 100 Mbps */
9382f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_100_TX | IFM_FDX;
9392f345d8eSLuigi Rizzo 		sc->speed = 100;
9402f345d8eSLuigi Rizzo 		break;
9412f345d8eSLuigi Rizzo 	case 3: /* 1 Gbps */
9422f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_1000_T | IFM_FDX;
9432f345d8eSLuigi Rizzo 		sc->speed = 1000;
9442f345d8eSLuigi Rizzo 		break;
9452f345d8eSLuigi Rizzo 	case 4: /* 10 Gbps */
9462f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
9472f345d8eSLuigi Rizzo 		sc->speed = 10000;
9482f345d8eSLuigi Rizzo 		break;
949a4f734b4SXin LI 	case 5: /* 20 Gbps */
950a4f734b4SXin LI 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
951a4f734b4SXin LI 		sc->speed = 20000;
952a4f734b4SXin LI 		break;
953a4f734b4SXin LI 	case 6: /* 25 Gbps */
954a4f734b4SXin LI 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
955a4f734b4SXin LI 		sc->speed = 25000;
956a4f734b4SXin LI 		break;
957b41206d8SXin LI 	case 7: /* 40 Gbps */
958b41206d8SXin LI 		req->ifm_active |= IFM_40G_SR4 | IFM_FDX;
959b41206d8SXin LI 		sc->speed = 40000;
960b41206d8SXin LI 		break;
961a4f734b4SXin LI 	default:
962a4f734b4SXin LI 		sc->speed = 0;
963a4f734b4SXin LI 		break;
9642f345d8eSLuigi Rizzo 	}
9652f345d8eSLuigi Rizzo 
9662f345d8eSLuigi Rizzo 	return;
9672f345d8eSLuigi Rizzo }
9682f345d8eSLuigi Rizzo 
9692f345d8eSLuigi Rizzo 
9702f345d8eSLuigi Rizzo int
9712f345d8eSLuigi Rizzo oce_media_change(struct ifnet *ifp)
9722f345d8eSLuigi Rizzo {
9732f345d8eSLuigi Rizzo 	return 0;
9742f345d8eSLuigi Rizzo }
9752f345d8eSLuigi Rizzo 
9762f345d8eSLuigi Rizzo 
977c2625e6eSJosh Paetzel static void oce_is_pkt_dest_bmc(POCE_SOFTC sc,
978c2625e6eSJosh Paetzel 				struct mbuf *m, boolean_t *os2bmc,
979c2625e6eSJosh Paetzel 				struct mbuf **m_new)
980c2625e6eSJosh Paetzel {
981c2625e6eSJosh Paetzel 	struct ether_header *eh = NULL;
982c2625e6eSJosh Paetzel 
983c2625e6eSJosh Paetzel 	eh = mtod(m, struct ether_header *);
984c2625e6eSJosh Paetzel 
985c2625e6eSJosh Paetzel 	if (!is_os2bmc_enabled(sc) || *os2bmc) {
986c2625e6eSJosh Paetzel 		*os2bmc = FALSE;
987c2625e6eSJosh Paetzel 		goto done;
988c2625e6eSJosh Paetzel 	}
989c2625e6eSJosh Paetzel 	if (!ETHER_IS_MULTICAST(eh->ether_dhost))
990c2625e6eSJosh Paetzel 		goto done;
991c2625e6eSJosh Paetzel 
992c2625e6eSJosh Paetzel 	if (is_mc_allowed_on_bmc(sc, eh) ||
993c2625e6eSJosh Paetzel 	    is_bc_allowed_on_bmc(sc, eh) ||
994c2625e6eSJosh Paetzel 	    is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) {
995c2625e6eSJosh Paetzel 		*os2bmc = TRUE;
996c2625e6eSJosh Paetzel 		goto done;
997c2625e6eSJosh Paetzel 	}
998c2625e6eSJosh Paetzel 
999c2625e6eSJosh Paetzel 	if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) {
1000c2625e6eSJosh Paetzel 		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1001c2625e6eSJosh Paetzel 		uint8_t nexthdr = ip6->ip6_nxt;
1002c2625e6eSJosh Paetzel 		if (nexthdr == IPPROTO_ICMPV6) {
1003c2625e6eSJosh Paetzel 			struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1);
1004c2625e6eSJosh Paetzel 			switch (icmp6->icmp6_type) {
1005c2625e6eSJosh Paetzel 			case ND_ROUTER_ADVERT:
1006c2625e6eSJosh Paetzel 				*os2bmc = is_ipv6_ra_filt_enabled(sc);
1007c2625e6eSJosh Paetzel 				goto done;
1008c2625e6eSJosh Paetzel 			case ND_NEIGHBOR_ADVERT:
1009c2625e6eSJosh Paetzel 				*os2bmc = is_ipv6_na_filt_enabled(sc);
1010c2625e6eSJosh Paetzel 				goto done;
1011c2625e6eSJosh Paetzel 			default:
1012c2625e6eSJosh Paetzel 				break;
1013c2625e6eSJosh Paetzel 			}
1014c2625e6eSJosh Paetzel 		}
1015c2625e6eSJosh Paetzel 	}
1016c2625e6eSJosh Paetzel 
1017c2625e6eSJosh Paetzel 	if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) {
1018c2625e6eSJosh Paetzel 		struct ip *ip = mtod(m, struct ip *);
1019c2625e6eSJosh Paetzel 		int iphlen = ip->ip_hl << 2;
1020c2625e6eSJosh Paetzel 		struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen);
1021c2625e6eSJosh Paetzel 		switch (uh->uh_dport) {
1022c2625e6eSJosh Paetzel 		case DHCP_CLIENT_PORT:
1023c2625e6eSJosh Paetzel 			*os2bmc = is_dhcp_client_filt_enabled(sc);
1024c2625e6eSJosh Paetzel 			goto done;
1025c2625e6eSJosh Paetzel 		case DHCP_SERVER_PORT:
1026c2625e6eSJosh Paetzel 			*os2bmc = is_dhcp_srvr_filt_enabled(sc);
1027c2625e6eSJosh Paetzel 			goto done;
1028c2625e6eSJosh Paetzel 		case NET_BIOS_PORT1:
1029c2625e6eSJosh Paetzel 		case NET_BIOS_PORT2:
1030c2625e6eSJosh Paetzel 			*os2bmc = is_nbios_filt_enabled(sc);
1031c2625e6eSJosh Paetzel 			goto done;
1032c2625e6eSJosh Paetzel 		case DHCPV6_RAS_PORT:
1033c2625e6eSJosh Paetzel 			*os2bmc = is_ipv6_ras_filt_enabled(sc);
1034c2625e6eSJosh Paetzel 			goto done;
1035c2625e6eSJosh Paetzel 		default:
1036c2625e6eSJosh Paetzel 			break;
1037c2625e6eSJosh Paetzel 		}
1038c2625e6eSJosh Paetzel 	}
1039c2625e6eSJosh Paetzel done:
1040c2625e6eSJosh Paetzel 	if (*os2bmc) {
1041c2625e6eSJosh Paetzel 		*m_new = m_dup(m, M_NOWAIT);
1042c2625e6eSJosh Paetzel 		if (!*m_new) {
1043c2625e6eSJosh Paetzel 			*os2bmc = FALSE;
1044c2625e6eSJosh Paetzel 			return;
1045c2625e6eSJosh Paetzel 		}
1046c2625e6eSJosh Paetzel 		*m_new = oce_insert_vlan_tag(sc, *m_new, NULL);
1047c2625e6eSJosh Paetzel 	}
1048c2625e6eSJosh Paetzel }
1049c2625e6eSJosh Paetzel 
10502f345d8eSLuigi Rizzo 
10512f345d8eSLuigi Rizzo 
10522f345d8eSLuigi Rizzo /*****************************************************************************
10532f345d8eSLuigi Rizzo  *			  Transmit routines functions			     *
10542f345d8eSLuigi Rizzo  *****************************************************************************/
10552f345d8eSLuigi Rizzo 
10562f345d8eSLuigi Rizzo static int
10572f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
10582f345d8eSLuigi Rizzo {
10592f345d8eSLuigi Rizzo 	int rc = 0, i, retry_cnt = 0;
10602f345d8eSLuigi Rizzo 	bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
1061c2625e6eSJosh Paetzel 	struct mbuf *m, *m_temp, *m_new = NULL;
10622f345d8eSLuigi Rizzo 	struct oce_wq *wq = sc->wq[wq_index];
10632f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
10642f345d8eSLuigi Rizzo 	struct oce_nic_hdr_wqe *nichdr;
10652f345d8eSLuigi Rizzo 	struct oce_nic_frag_wqe *nicfrag;
1066c2625e6eSJosh Paetzel 	struct ether_header *eh = NULL;
10672f345d8eSLuigi Rizzo 	int num_wqes;
10682f345d8eSLuigi Rizzo 	uint32_t reg_value;
1069cdaba892SXin LI 	boolean_t complete = TRUE;
1070c2625e6eSJosh Paetzel 	boolean_t os2bmc = FALSE;
10712f345d8eSLuigi Rizzo 
10722f345d8eSLuigi Rizzo 	m = *mpp;
10732f345d8eSLuigi Rizzo 	if (!m)
10742f345d8eSLuigi Rizzo 		return EINVAL;
10752f345d8eSLuigi Rizzo 
10762f345d8eSLuigi Rizzo 	if (!(m->m_flags & M_PKTHDR)) {
10772f345d8eSLuigi Rizzo 		rc = ENXIO;
10782f345d8eSLuigi Rizzo 		goto free_ret;
10792f345d8eSLuigi Rizzo 	}
10802f345d8eSLuigi Rizzo 
1081c2625e6eSJosh Paetzel 	/* Don't allow non-TSO packets longer than MTU */
1082c2625e6eSJosh Paetzel 	if (!is_tso_pkt(m)) {
1083c2625e6eSJosh Paetzel 		eh = mtod(m, struct ether_header *);
1084c2625e6eSJosh Paetzel 		if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE))
1085c2625e6eSJosh Paetzel 			 goto free_ret;
1086c2625e6eSJosh Paetzel 	}
1087c2625e6eSJosh Paetzel 
1088cdaba892SXin LI 	if(oce_tx_asic_stall_verify(sc, m)) {
1089cdaba892SXin LI 		m = oce_insert_vlan_tag(sc, m, &complete);
1090cdaba892SXin LI 		if(!m) {
1091cdaba892SXin LI 			device_printf(sc->dev, "Insertion unsuccessful\n");
1092cdaba892SXin LI 			return 0;
1093cdaba892SXin LI 		}
1094cdaba892SXin LI 
1095cdaba892SXin LI 	}
1096cdaba892SXin LI 
1097c2625e6eSJosh Paetzel 	/* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less
1098c2625e6eSJosh Paetzel 	 * may cause a transmit stall on that port. So the work-around is to
1099c2625e6eSJosh Paetzel 	 * pad short packets (<= 32 bytes) to a 36-byte length.
1100c2625e6eSJosh Paetzel 	*/
1101c2625e6eSJosh Paetzel 	if(IS_SH(sc) || IS_XE201(sc) ) {
1102c2625e6eSJosh Paetzel 		if(m->m_pkthdr.len <= 32) {
1103c2625e6eSJosh Paetzel 			char buf[36];
1104c2625e6eSJosh Paetzel 			bzero((void *)buf, 36);
1105c2625e6eSJosh Paetzel 			m_append(m, (36 - m->m_pkthdr.len), buf);
1106c2625e6eSJosh Paetzel 		}
1107c2625e6eSJosh Paetzel 	}
1108c2625e6eSJosh Paetzel 
1109c2625e6eSJosh Paetzel tx_start:
11102f345d8eSLuigi Rizzo 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
11112f345d8eSLuigi Rizzo 		/* consolidate packet buffers for TSO/LSO segment offload */
11129bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
11139bd3250aSLuigi Rizzo 		m = oce_tso_setup(sc, mpp);
1114ad512958SBjoern A. Zeeb #else
1115ad512958SBjoern A. Zeeb 		m = NULL;
1116ad512958SBjoern A. Zeeb #endif
11172f345d8eSLuigi Rizzo 		if (m == NULL) {
11182f345d8eSLuigi Rizzo 			rc = ENXIO;
11192f345d8eSLuigi Rizzo 			goto free_ret;
11202f345d8eSLuigi Rizzo 		}
11212f345d8eSLuigi Rizzo 	}
11222f345d8eSLuigi Rizzo 
1123c2625e6eSJosh Paetzel 
1124291a1934SXin LI 	pd = &wq->pckts[wq->pkt_desc_head];
1125c2625e6eSJosh Paetzel 
11262f345d8eSLuigi Rizzo retry:
11272f345d8eSLuigi Rizzo 	rc = bus_dmamap_load_mbuf_sg(wq->tag,
11282f345d8eSLuigi Rizzo 				     pd->map,
11292f345d8eSLuigi Rizzo 				     m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
11302f345d8eSLuigi Rizzo 	if (rc == 0) {
11312f345d8eSLuigi Rizzo 		num_wqes = pd->nsegs + 1;
1132291a1934SXin LI 		if (IS_BE(sc) || IS_SH(sc)) {
11332f345d8eSLuigi Rizzo 			/*Dummy required only for BE3.*/
11342f345d8eSLuigi Rizzo 			if (num_wqes & 1)
11352f345d8eSLuigi Rizzo 				num_wqes++;
11362f345d8eSLuigi Rizzo 		}
11372f345d8eSLuigi Rizzo 		if (num_wqes >= RING_NUM_FREE(wq->ring)) {
11382f345d8eSLuigi Rizzo 			bus_dmamap_unload(wq->tag, pd->map);
11392f345d8eSLuigi Rizzo 			return EBUSY;
11402f345d8eSLuigi Rizzo 		}
1141291a1934SXin LI 		atomic_store_rel_int(&wq->pkt_desc_head,
1142291a1934SXin LI 				     (wq->pkt_desc_head + 1) % \
1143291a1934SXin LI 				      OCE_WQ_PACKET_ARRAY_SIZE);
11442f345d8eSLuigi Rizzo 		bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
11452f345d8eSLuigi Rizzo 		pd->mbuf = m;
11462f345d8eSLuigi Rizzo 
11472f345d8eSLuigi Rizzo 		nichdr =
11482f345d8eSLuigi Rizzo 		    RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
11492f345d8eSLuigi Rizzo 		nichdr->u0.dw[0] = 0;
11502f345d8eSLuigi Rizzo 		nichdr->u0.dw[1] = 0;
11512f345d8eSLuigi Rizzo 		nichdr->u0.dw[2] = 0;
11522f345d8eSLuigi Rizzo 		nichdr->u0.dw[3] = 0;
11532f345d8eSLuigi Rizzo 
1154cdaba892SXin LI 		nichdr->u0.s.complete = complete;
1155c2625e6eSJosh Paetzel 		nichdr->u0.s.mgmt = os2bmc;
11562f345d8eSLuigi Rizzo 		nichdr->u0.s.event = 1;
11572f345d8eSLuigi Rizzo 		nichdr->u0.s.crc = 1;
11582f345d8eSLuigi Rizzo 		nichdr->u0.s.forward = 0;
11592f345d8eSLuigi Rizzo 		nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
11602f345d8eSLuigi Rizzo 		nichdr->u0.s.udpcs =
11612f345d8eSLuigi Rizzo 			(m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
11622f345d8eSLuigi Rizzo 		nichdr->u0.s.tcpcs =
11632f345d8eSLuigi Rizzo 			(m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
11642f345d8eSLuigi Rizzo 		nichdr->u0.s.num_wqe = num_wqes;
11652f345d8eSLuigi Rizzo 		nichdr->u0.s.total_length = m->m_pkthdr.len;
11665fbb6830SXin LI 
11672f345d8eSLuigi Rizzo 		if (m->m_flags & M_VLANTAG) {
11682f345d8eSLuigi Rizzo 			nichdr->u0.s.vlan = 1; /*Vlan present*/
11692f345d8eSLuigi Rizzo 			nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
11702f345d8eSLuigi Rizzo 		}
11715fbb6830SXin LI 
11722f345d8eSLuigi Rizzo 		if (m->m_pkthdr.csum_flags & CSUM_TSO) {
11732f345d8eSLuigi Rizzo 			if (m->m_pkthdr.tso_segsz) {
11742f345d8eSLuigi Rizzo 				nichdr->u0.s.lso = 1;
11752f345d8eSLuigi Rizzo 				nichdr->u0.s.lso_mss  = m->m_pkthdr.tso_segsz;
11762f345d8eSLuigi Rizzo 			}
1177291a1934SXin LI 			if (!IS_BE(sc) || !IS_SH(sc))
11782f345d8eSLuigi Rizzo 				nichdr->u0.s.ipcs = 1;
11792f345d8eSLuigi Rizzo 		}
11802f345d8eSLuigi Rizzo 
11812f345d8eSLuigi Rizzo 		RING_PUT(wq->ring, 1);
1182291a1934SXin LI 		atomic_add_int(&wq->ring->num_used, 1);
11832f345d8eSLuigi Rizzo 
11842f345d8eSLuigi Rizzo 		for (i = 0; i < pd->nsegs; i++) {
11852f345d8eSLuigi Rizzo 			nicfrag =
11862f345d8eSLuigi Rizzo 			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
11872f345d8eSLuigi Rizzo 						      struct oce_nic_frag_wqe);
11882f345d8eSLuigi Rizzo 			nicfrag->u0.s.rsvd0 = 0;
11892f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
11902f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
11912f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_len = segs[i].ds_len;
11922f345d8eSLuigi Rizzo 			pd->wqe_idx = wq->ring->pidx;
11932f345d8eSLuigi Rizzo 			RING_PUT(wq->ring, 1);
1194291a1934SXin LI 			atomic_add_int(&wq->ring->num_used, 1);
11952f345d8eSLuigi Rizzo 		}
11962f345d8eSLuigi Rizzo 		if (num_wqes > (pd->nsegs + 1)) {
11972f345d8eSLuigi Rizzo 			nicfrag =
11982f345d8eSLuigi Rizzo 			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
11992f345d8eSLuigi Rizzo 						      struct oce_nic_frag_wqe);
12002f345d8eSLuigi Rizzo 			nicfrag->u0.dw[0] = 0;
12012f345d8eSLuigi Rizzo 			nicfrag->u0.dw[1] = 0;
12022f345d8eSLuigi Rizzo 			nicfrag->u0.dw[2] = 0;
12032f345d8eSLuigi Rizzo 			nicfrag->u0.dw[3] = 0;
12042f345d8eSLuigi Rizzo 			pd->wqe_idx = wq->ring->pidx;
12052f345d8eSLuigi Rizzo 			RING_PUT(wq->ring, 1);
1206291a1934SXin LI 			atomic_add_int(&wq->ring->num_used, 1);
12072f345d8eSLuigi Rizzo 			pd->nsegs++;
12082f345d8eSLuigi Rizzo 		}
12092f345d8eSLuigi Rizzo 
1210c8dfaf38SGleb Smirnoff 		if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
12112f345d8eSLuigi Rizzo 		wq->tx_stats.tx_reqs++;
12122f345d8eSLuigi Rizzo 		wq->tx_stats.tx_wrbs += num_wqes;
12132f345d8eSLuigi Rizzo 		wq->tx_stats.tx_bytes += m->m_pkthdr.len;
12142f345d8eSLuigi Rizzo 		wq->tx_stats.tx_pkts++;
12152f345d8eSLuigi Rizzo 
12162f345d8eSLuigi Rizzo 		bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
12172f345d8eSLuigi Rizzo 				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
12182f345d8eSLuigi Rizzo 		reg_value = (num_wqes << 16) | wq->wq_id;
1219c2625e6eSJosh Paetzel 
1220c2625e6eSJosh Paetzel 		/* if os2bmc is not enabled or if the pkt is already tagged as
1221c2625e6eSJosh Paetzel 		   bmc, do nothing
1222c2625e6eSJosh Paetzel 		 */
1223c2625e6eSJosh Paetzel 		oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new);
1224c2625e6eSJosh Paetzel 
1225291a1934SXin LI 		OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value);
12262f345d8eSLuigi Rizzo 
12272f345d8eSLuigi Rizzo 	} else if (rc == EFBIG)	{
12282f345d8eSLuigi Rizzo 		if (retry_cnt == 0) {
1229c6499eccSGleb Smirnoff 			m_temp = m_defrag(m, M_NOWAIT);
12302f345d8eSLuigi Rizzo 			if (m_temp == NULL)
12312f345d8eSLuigi Rizzo 				goto free_ret;
12322f345d8eSLuigi Rizzo 			m = m_temp;
12332f345d8eSLuigi Rizzo 			*mpp = m_temp;
12342f345d8eSLuigi Rizzo 			retry_cnt = retry_cnt + 1;
12352f345d8eSLuigi Rizzo 			goto retry;
12362f345d8eSLuigi Rizzo 		} else
12372f345d8eSLuigi Rizzo 			goto free_ret;
12382f345d8eSLuigi Rizzo 	} else if (rc == ENOMEM)
12392f345d8eSLuigi Rizzo 		return rc;
12402f345d8eSLuigi Rizzo 	else
12412f345d8eSLuigi Rizzo 		goto free_ret;
12422f345d8eSLuigi Rizzo 
1243c2625e6eSJosh Paetzel 	if (os2bmc) {
1244c2625e6eSJosh Paetzel 		m = m_new;
1245c2625e6eSJosh Paetzel 		goto tx_start;
1246c2625e6eSJosh Paetzel 	}
1247c2625e6eSJosh Paetzel 
12482f345d8eSLuigi Rizzo 	return 0;
12492f345d8eSLuigi Rizzo 
12502f345d8eSLuigi Rizzo free_ret:
12512f345d8eSLuigi Rizzo 	m_freem(*mpp);
12522f345d8eSLuigi Rizzo 	*mpp = NULL;
12532f345d8eSLuigi Rizzo 	return rc;
12542f345d8eSLuigi Rizzo }
12552f345d8eSLuigi Rizzo 
12562f345d8eSLuigi Rizzo 
12572f345d8eSLuigi Rizzo static void
1258c2625e6eSJosh Paetzel oce_process_tx_completion(struct oce_wq *wq)
12592f345d8eSLuigi Rizzo {
12602f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
12612f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
12622f345d8eSLuigi Rizzo 	struct mbuf *m;
12632f345d8eSLuigi Rizzo 
1264291a1934SXin LI 	pd = &wq->pckts[wq->pkt_desc_tail];
1265291a1934SXin LI 	atomic_store_rel_int(&wq->pkt_desc_tail,
1266291a1934SXin LI 			     (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE);
1267291a1934SXin LI 	atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1);
12682f345d8eSLuigi Rizzo 	bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
12692f345d8eSLuigi Rizzo 	bus_dmamap_unload(wq->tag, pd->map);
12702f345d8eSLuigi Rizzo 
12712f345d8eSLuigi Rizzo 	m = pd->mbuf;
12722f345d8eSLuigi Rizzo 	m_freem(m);
12732f345d8eSLuigi Rizzo 	pd->mbuf = NULL;
12742f345d8eSLuigi Rizzo 
1275291a1934SXin LI 
12762f345d8eSLuigi Rizzo 	if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) {
12772f345d8eSLuigi Rizzo 		if (wq->ring->num_used < (wq->ring->num_items / 2)) {
12782f345d8eSLuigi Rizzo 			sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
12792f345d8eSLuigi Rizzo 			oce_tx_restart(sc, wq);
12802f345d8eSLuigi Rizzo 		}
12812f345d8eSLuigi Rizzo 	}
12822f345d8eSLuigi Rizzo }
12832f345d8eSLuigi Rizzo 
12842f345d8eSLuigi Rizzo 
12852f345d8eSLuigi Rizzo static void
12862f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
12872f345d8eSLuigi Rizzo {
12882f345d8eSLuigi Rizzo 
12892f345d8eSLuigi Rizzo 	if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
12902f345d8eSLuigi Rizzo 		return;
12912f345d8eSLuigi Rizzo 
12922f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000
12932f345d8eSLuigi Rizzo 	if (!drbr_empty(sc->ifp, wq->br))
12942f345d8eSLuigi Rizzo #else
12952f345d8eSLuigi Rizzo 	if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd))
12962f345d8eSLuigi Rizzo #endif
1297cbc4d2dbSJohn Baldwin 		taskqueue_enqueue(taskqueue_swi, &wq->txtask);
12982f345d8eSLuigi Rizzo 
12992f345d8eSLuigi Rizzo }
13002f345d8eSLuigi Rizzo 
13019bd3250aSLuigi Rizzo 
1302ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
13032f345d8eSLuigi Rizzo static struct mbuf *
13049bd3250aSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
13052f345d8eSLuigi Rizzo {
13062f345d8eSLuigi Rizzo 	struct mbuf *m;
1307ad512958SBjoern A. Zeeb #ifdef INET
13082f345d8eSLuigi Rizzo 	struct ip *ip;
1309ad512958SBjoern A. Zeeb #endif
1310ad512958SBjoern A. Zeeb #ifdef INET6
13112f345d8eSLuigi Rizzo 	struct ip6_hdr *ip6;
1312ad512958SBjoern A. Zeeb #endif
13132f345d8eSLuigi Rizzo 	struct ether_vlan_header *eh;
13142f345d8eSLuigi Rizzo 	struct tcphdr *th;
13152f345d8eSLuigi Rizzo 	uint16_t etype;
13169bd3250aSLuigi Rizzo 	int total_len = 0, ehdrlen = 0;
13172f345d8eSLuigi Rizzo 
13182f345d8eSLuigi Rizzo 	m = *mpp;
13192f345d8eSLuigi Rizzo 
13202f345d8eSLuigi Rizzo 	if (M_WRITABLE(m) == 0) {
1321c6499eccSGleb Smirnoff 		m = m_dup(*mpp, M_NOWAIT);
13222f345d8eSLuigi Rizzo 		if (!m)
13232f345d8eSLuigi Rizzo 			return NULL;
13242f345d8eSLuigi Rizzo 		m_freem(*mpp);
13252f345d8eSLuigi Rizzo 		*mpp = m;
13262f345d8eSLuigi Rizzo 	}
13272f345d8eSLuigi Rizzo 
13282f345d8eSLuigi Rizzo 	eh = mtod(m, struct ether_vlan_header *);
13292f345d8eSLuigi Rizzo 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
13302f345d8eSLuigi Rizzo 		etype = ntohs(eh->evl_proto);
13312f345d8eSLuigi Rizzo 		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
13322f345d8eSLuigi Rizzo 	} else {
13332f345d8eSLuigi Rizzo 		etype = ntohs(eh->evl_encap_proto);
13342f345d8eSLuigi Rizzo 		ehdrlen = ETHER_HDR_LEN;
13352f345d8eSLuigi Rizzo 	}
13362f345d8eSLuigi Rizzo 
13372f345d8eSLuigi Rizzo 	switch (etype) {
1338ad512958SBjoern A. Zeeb #ifdef INET
13392f345d8eSLuigi Rizzo 	case ETHERTYPE_IP:
13402f345d8eSLuigi Rizzo 		ip = (struct ip *)(m->m_data + ehdrlen);
13412f345d8eSLuigi Rizzo 		if (ip->ip_p != IPPROTO_TCP)
13422f345d8eSLuigi Rizzo 			return NULL;
13432f345d8eSLuigi Rizzo 		th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
13442f345d8eSLuigi Rizzo 
13452f345d8eSLuigi Rizzo 		total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
13462f345d8eSLuigi Rizzo 		break;
1347ad512958SBjoern A. Zeeb #endif
1348ad512958SBjoern A. Zeeb #ifdef INET6
13492f345d8eSLuigi Rizzo 	case ETHERTYPE_IPV6:
13502f345d8eSLuigi Rizzo 		ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
13512f345d8eSLuigi Rizzo 		if (ip6->ip6_nxt != IPPROTO_TCP)
13522f345d8eSLuigi Rizzo 			return NULL;
13532f345d8eSLuigi Rizzo 		th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
13542f345d8eSLuigi Rizzo 
13552f345d8eSLuigi Rizzo 		total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
13562f345d8eSLuigi Rizzo 		break;
1357ad512958SBjoern A. Zeeb #endif
13582f345d8eSLuigi Rizzo 	default:
13592f345d8eSLuigi Rizzo 		return NULL;
13602f345d8eSLuigi Rizzo 	}
13612f345d8eSLuigi Rizzo 
13622f345d8eSLuigi Rizzo 	m = m_pullup(m, total_len);
13632f345d8eSLuigi Rizzo 	if (!m)
13642f345d8eSLuigi Rizzo 		return NULL;
13652f345d8eSLuigi Rizzo 	*mpp = m;
13662f345d8eSLuigi Rizzo 	return m;
13672f345d8eSLuigi Rizzo 
13682f345d8eSLuigi Rizzo }
1369ad512958SBjoern A. Zeeb #endif /* INET6 || INET */
13702f345d8eSLuigi Rizzo 
13712f345d8eSLuigi Rizzo void
13722f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending)
13732f345d8eSLuigi Rizzo {
13742f345d8eSLuigi Rizzo 	struct oce_wq *wq = arg;
13752f345d8eSLuigi Rizzo 	POCE_SOFTC sc = wq->parent;
13762f345d8eSLuigi Rizzo 	struct ifnet *ifp = sc->ifp;
13772f345d8eSLuigi Rizzo 	int rc = 0;
13782f345d8eSLuigi Rizzo 
13792f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000
1380291a1934SXin LI 	LOCK(&wq->tx_lock);
13812f345d8eSLuigi Rizzo 	rc = oce_multiq_transmit(ifp, NULL, wq);
13822f345d8eSLuigi Rizzo 	if (rc) {
13832f345d8eSLuigi Rizzo 		device_printf(sc->dev,
13842f345d8eSLuigi Rizzo 				"TX[%d] restart failed\n", wq->queue_index);
13852f345d8eSLuigi Rizzo 	}
13862f345d8eSLuigi Rizzo 	UNLOCK(&wq->tx_lock);
13872f345d8eSLuigi Rizzo #else
13882f345d8eSLuigi Rizzo 	oce_start(ifp);
13892f345d8eSLuigi Rizzo #endif
13902f345d8eSLuigi Rizzo 
13912f345d8eSLuigi Rizzo }
13922f345d8eSLuigi Rizzo 
13932f345d8eSLuigi Rizzo 
13942f345d8eSLuigi Rizzo void
13952f345d8eSLuigi Rizzo oce_start(struct ifnet *ifp)
13962f345d8eSLuigi Rizzo {
13972f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
13982f345d8eSLuigi Rizzo 	struct mbuf *m;
13992f345d8eSLuigi Rizzo 	int rc = 0;
14009bd3250aSLuigi Rizzo 	int def_q = 0; /* Defualt tx queue is 0*/
14012f345d8eSLuigi Rizzo 
14022f345d8eSLuigi Rizzo 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
14032f345d8eSLuigi Rizzo 			IFF_DRV_RUNNING)
14042f345d8eSLuigi Rizzo 		return;
14052f345d8eSLuigi Rizzo 
1406cdaba892SXin LI 	if (!sc->link_status)
1407cdaba892SXin LI 		return;
1408cdaba892SXin LI 
14092f345d8eSLuigi Rizzo 	do {
14102f345d8eSLuigi Rizzo 		IF_DEQUEUE(&sc->ifp->if_snd, m);
14112f345d8eSLuigi Rizzo 		if (m == NULL)
14122f345d8eSLuigi Rizzo 			break;
14139bd3250aSLuigi Rizzo 
14149bd3250aSLuigi Rizzo 		LOCK(&sc->wq[def_q]->tx_lock);
14159bd3250aSLuigi Rizzo 		rc = oce_tx(sc, &m, def_q);
14169bd3250aSLuigi Rizzo 		UNLOCK(&sc->wq[def_q]->tx_lock);
14172f345d8eSLuigi Rizzo 		if (rc) {
14182f345d8eSLuigi Rizzo 			if (m != NULL) {
14199bd3250aSLuigi Rizzo 				sc->wq[def_q]->tx_stats.tx_stops ++;
14202f345d8eSLuigi Rizzo 				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
14212f345d8eSLuigi Rizzo 				IFQ_DRV_PREPEND(&ifp->if_snd, m);
14222f345d8eSLuigi Rizzo 				m = NULL;
14232f345d8eSLuigi Rizzo 			}
14242f345d8eSLuigi Rizzo 			break;
14252f345d8eSLuigi Rizzo 		}
14262f345d8eSLuigi Rizzo 		if (m != NULL)
14272f345d8eSLuigi Rizzo 			ETHER_BPF_MTAP(ifp, m);
14282f345d8eSLuigi Rizzo 
14299bd3250aSLuigi Rizzo 	} while (TRUE);
14302f345d8eSLuigi Rizzo 
14312f345d8eSLuigi Rizzo 	return;
14322f345d8eSLuigi Rizzo }
14332f345d8eSLuigi Rizzo 
14342f345d8eSLuigi Rizzo 
14352f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */
14362f345d8eSLuigi Rizzo uint16_t
14372f345d8eSLuigi Rizzo oce_wq_handler(void *arg)
14382f345d8eSLuigi Rizzo {
14392f345d8eSLuigi Rizzo 	struct oce_wq *wq = (struct oce_wq *)arg;
14402f345d8eSLuigi Rizzo 	POCE_SOFTC sc = wq->parent;
14412f345d8eSLuigi Rizzo 	struct oce_cq *cq = wq->cq;
14422f345d8eSLuigi Rizzo 	struct oce_nic_tx_cqe *cqe;
14432f345d8eSLuigi Rizzo 	int num_cqes = 0;
14442f345d8eSLuigi Rizzo 
1445c2625e6eSJosh Paetzel 	LOCK(&wq->tx_compl_lock);
14462f345d8eSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
14472f345d8eSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
14482f345d8eSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
14492f345d8eSLuigi Rizzo 	while (cqe->u0.dw[3]) {
14502f345d8eSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
14512f345d8eSLuigi Rizzo 
14522f345d8eSLuigi Rizzo 		wq->ring->cidx = cqe->u0.s.wqe_index + 1;
14532f345d8eSLuigi Rizzo 		if (wq->ring->cidx >= wq->ring->num_items)
14542f345d8eSLuigi Rizzo 			wq->ring->cidx -= wq->ring->num_items;
14552f345d8eSLuigi Rizzo 
1456c2625e6eSJosh Paetzel 		oce_process_tx_completion(wq);
14572f345d8eSLuigi Rizzo 		wq->tx_stats.tx_compl++;
14582f345d8eSLuigi Rizzo 		cqe->u0.dw[3] = 0;
14592f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
14602f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
14612f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
14622f345d8eSLuigi Rizzo 		cqe =
14632f345d8eSLuigi Rizzo 		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
14642f345d8eSLuigi Rizzo 		num_cqes++;
14652f345d8eSLuigi Rizzo 	}
14662f345d8eSLuigi Rizzo 
14672f345d8eSLuigi Rizzo 	if (num_cqes)
14682f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
14692f345d8eSLuigi Rizzo 
1470c2625e6eSJosh Paetzel 	UNLOCK(&wq->tx_compl_lock);
1471c2625e6eSJosh Paetzel 	return num_cqes;
14722f345d8eSLuigi Rizzo }
14732f345d8eSLuigi Rizzo 
14742f345d8eSLuigi Rizzo 
14752f345d8eSLuigi Rizzo static int
14762f345d8eSLuigi Rizzo oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq)
14772f345d8eSLuigi Rizzo {
14782f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
14792f345d8eSLuigi Rizzo 	int status = 0, queue_index = 0;
14802f345d8eSLuigi Rizzo 	struct mbuf *next = NULL;
14812f345d8eSLuigi Rizzo 	struct buf_ring *br = NULL;
14822f345d8eSLuigi Rizzo 
14832f345d8eSLuigi Rizzo 	br  = wq->br;
14842f345d8eSLuigi Rizzo 	queue_index = wq->queue_index;
14852f345d8eSLuigi Rizzo 
14862f345d8eSLuigi Rizzo 	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
14872f345d8eSLuigi Rizzo 		IFF_DRV_RUNNING) {
14882f345d8eSLuigi Rizzo 		if (m != NULL)
14892f345d8eSLuigi Rizzo 			status = drbr_enqueue(ifp, br, m);
14902f345d8eSLuigi Rizzo 		return status;
14912f345d8eSLuigi Rizzo 	}
14922f345d8eSLuigi Rizzo 
1493ded5ea6aSRandall Stewart 	if (m != NULL) {
14942f345d8eSLuigi Rizzo 		if ((status = drbr_enqueue(ifp, br, m)) != 0)
14952f345d8eSLuigi Rizzo 			return status;
1496ded5ea6aSRandall Stewart 	}
1497ded5ea6aSRandall Stewart 	while ((next = drbr_peek(ifp, br)) != NULL) {
14982f345d8eSLuigi Rizzo 		if (oce_tx(sc, &next, queue_index)) {
1499ded5ea6aSRandall Stewart 			if (next == NULL) {
1500ded5ea6aSRandall Stewart 				drbr_advance(ifp, br);
1501ded5ea6aSRandall Stewart 			} else {
1502ded5ea6aSRandall Stewart 				drbr_putback(ifp, br, next);
15032f345d8eSLuigi Rizzo 				wq->tx_stats.tx_stops ++;
15042f345d8eSLuigi Rizzo 				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
15052f345d8eSLuigi Rizzo 			}
15062f345d8eSLuigi Rizzo 			break;
15072f345d8eSLuigi Rizzo 		}
1508ded5ea6aSRandall Stewart 		drbr_advance(ifp, br);
1509c8dfaf38SGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len);
1510063efed2SGleb Smirnoff 		if (next->m_flags & M_MCAST)
1511c8dfaf38SGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
15122f345d8eSLuigi Rizzo 		ETHER_BPF_MTAP(ifp, next);
15132f345d8eSLuigi Rizzo 	}
15142f345d8eSLuigi Rizzo 
1515d398c863SLuigi Rizzo 	return 0;
15162f345d8eSLuigi Rizzo }
15172f345d8eSLuigi Rizzo 
15182f345d8eSLuigi Rizzo 
15192f345d8eSLuigi Rizzo 
15202f345d8eSLuigi Rizzo 
15212f345d8eSLuigi Rizzo /*****************************************************************************
15222f345d8eSLuigi Rizzo  *			    Receive  routines functions 		     *
15232f345d8eSLuigi Rizzo  *****************************************************************************/
15242f345d8eSLuigi Rizzo 
15252f345d8eSLuigi Rizzo static void
1526c2625e6eSJosh Paetzel oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2)
15272f345d8eSLuigi Rizzo {
1528c2625e6eSJosh Paetzel 	uint32_t *p;
1529c2625e6eSJosh Paetzel         struct ether_header *eh = NULL;
1530c2625e6eSJosh Paetzel         struct tcphdr *tcp_hdr = NULL;
1531c2625e6eSJosh Paetzel         struct ip *ip4_hdr = NULL;
1532c2625e6eSJosh Paetzel         struct ip6_hdr *ip6 = NULL;
1533c2625e6eSJosh Paetzel         uint32_t payload_len = 0;
1534c2625e6eSJosh Paetzel 
1535c2625e6eSJosh Paetzel         eh = mtod(m, struct ether_header *);
1536c2625e6eSJosh Paetzel         /* correct IP header */
1537c2625e6eSJosh Paetzel         if(!cqe2->ipv6_frame) {
1538c2625e6eSJosh Paetzel 		ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header));
1539c2625e6eSJosh Paetzel                 ip4_hdr->ip_ttl = cqe2->frame_lifespan;
1540c2625e6eSJosh Paetzel                 ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header));
1541c2625e6eSJosh Paetzel                 tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip));
1542c2625e6eSJosh Paetzel         }else {
1543c2625e6eSJosh Paetzel         	ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header));
1544c2625e6eSJosh Paetzel                 ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan;
1545c2625e6eSJosh Paetzel                 payload_len = cqe2->coalesced_size - sizeof(struct ether_header)
1546c2625e6eSJosh Paetzel                                                 - sizeof(struct ip6_hdr);
1547c2625e6eSJosh Paetzel                 ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len);
1548c2625e6eSJosh Paetzel                 tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr));
1549c2625e6eSJosh Paetzel         }
1550c2625e6eSJosh Paetzel 
1551c2625e6eSJosh Paetzel         /* correct tcp header */
1552c2625e6eSJosh Paetzel         tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num);
1553c2625e6eSJosh Paetzel         if(cqe2->push) {
1554c2625e6eSJosh Paetzel         	tcp_hdr->th_flags |= TH_PUSH;
1555c2625e6eSJosh Paetzel         }
1556c2625e6eSJosh Paetzel         tcp_hdr->th_win = htons(cqe2->tcp_window);
1557c2625e6eSJosh Paetzel         tcp_hdr->th_sum = 0xffff;
1558c2625e6eSJosh Paetzel         if(cqe2->ts_opt) {
1559c2625e6eSJosh Paetzel                 p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2);
1560c2625e6eSJosh Paetzel                 *p = cqe1->tcp_timestamp_val;
1561c2625e6eSJosh Paetzel                 *(p+1) = cqe1->tcp_timestamp_ecr;
1562c2625e6eSJosh Paetzel         }
1563c2625e6eSJosh Paetzel 
1564c2625e6eSJosh Paetzel 	return;
1565c2625e6eSJosh Paetzel }
1566c2625e6eSJosh Paetzel 
1567c2625e6eSJosh Paetzel static void
1568c2625e6eSJosh Paetzel oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m)
1569c2625e6eSJosh Paetzel {
1570764c812dSJosh Paetzel 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1571c2625e6eSJosh Paetzel         uint32_t i = 0, frag_len = 0;
1572c2625e6eSJosh Paetzel 	uint32_t len = cqe_info->pkt_size;
1573c2625e6eSJosh Paetzel         struct oce_packet_desc *pd;
1574c2625e6eSJosh Paetzel         struct mbuf *tail = NULL;
1575764c812dSJosh Paetzel 
1576c2625e6eSJosh Paetzel         for (i = 0; i < cqe_info->num_frags; i++) {
1577c2625e6eSJosh Paetzel                 if (rq->ring->cidx == rq->ring->pidx) {
157814410265SConrad Meyer                         device_printf(sc->dev,
1579c2625e6eSJosh Paetzel                                   "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n");
1580c2625e6eSJosh Paetzel                         return;
158114410265SConrad Meyer                 }
1582c2625e6eSJosh Paetzel                 pd = &rq->pckts[rq->ring->cidx];
158314410265SConrad Meyer 
158414410265SConrad Meyer                 bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
158514410265SConrad Meyer                 bus_dmamap_unload(rq->tag, pd->map);
1586c2625e6eSJosh Paetzel 		RING_GET(rq->ring, 1);
158714410265SConrad Meyer                 rq->pending--;
158814410265SConrad Meyer 
158914410265SConrad Meyer                 frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
159014410265SConrad Meyer                 pd->mbuf->m_len = frag_len;
159114410265SConrad Meyer 
159214410265SConrad Meyer                 if (tail != NULL) {
159314410265SConrad Meyer                         /* additional fragments */
159414410265SConrad Meyer                         pd->mbuf->m_flags &= ~M_PKTHDR;
159514410265SConrad Meyer                         tail->m_next = pd->mbuf;
1596c2625e6eSJosh Paetzel 			if(rq->islro)
1597c2625e6eSJosh Paetzel                         	tail->m_nextpkt = NULL;
159814410265SConrad Meyer                         tail = pd->mbuf;
159914410265SConrad Meyer                 } else {
160014410265SConrad Meyer                         /* first fragment, fill out much of the packet header */
160114410265SConrad Meyer                         pd->mbuf->m_pkthdr.len = len;
1602c2625e6eSJosh Paetzel 			if(rq->islro)
1603c2625e6eSJosh Paetzel                         	pd->mbuf->m_nextpkt = NULL;
160414410265SConrad Meyer                         pd->mbuf->m_pkthdr.csum_flags = 0;
160514410265SConrad Meyer                         if (IF_CSUM_ENABLED(sc)) {
1606c2625e6eSJosh Paetzel                                 if (cqe_info->l4_cksum_pass) {
1607c2625e6eSJosh Paetzel                                         if(!cqe_info->ipv6_frame) { /* IPV4 */
160814410265SConrad Meyer                                                 pd->mbuf->m_pkthdr.csum_flags |=
160914410265SConrad Meyer                                                         (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1610c2625e6eSJosh Paetzel                                         }else { /* IPV6 frame */
1611c2625e6eSJosh Paetzel 						if(rq->islro) {
1612c2625e6eSJosh Paetzel                                                 	pd->mbuf->m_pkthdr.csum_flags |=
1613c2625e6eSJosh Paetzel                                                         (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1614c2625e6eSJosh Paetzel 						}
1615c2625e6eSJosh Paetzel                                         }
161614410265SConrad Meyer                                         pd->mbuf->m_pkthdr.csum_data = 0xffff;
161714410265SConrad Meyer                                 }
1618c2625e6eSJosh Paetzel                                 if (cqe_info->ip_cksum_pass) {
161914410265SConrad Meyer                                         pd->mbuf->m_pkthdr.csum_flags |=
162014410265SConrad Meyer                                                (CSUM_IP_CHECKED|CSUM_IP_VALID);
162114410265SConrad Meyer                                 }
162214410265SConrad Meyer                         }
1623c2625e6eSJosh Paetzel                         *m = tail = pd->mbuf;
162414410265SConrad Meyer                }
162514410265SConrad Meyer                 pd->mbuf = NULL;
162614410265SConrad Meyer                 len -= frag_len;
162714410265SConrad Meyer         }
1628764c812dSJosh Paetzel 
1629c2625e6eSJosh Paetzel         return;
1630c2625e6eSJosh Paetzel }
1631c2625e6eSJosh Paetzel 
1632c2625e6eSJosh Paetzel static void
1633c2625e6eSJosh Paetzel oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2)
1634c2625e6eSJosh Paetzel {
1635c2625e6eSJosh Paetzel         POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1636c2625e6eSJosh Paetzel         struct nic_hwlro_cqe_part1 *cqe1 = NULL;
1637c2625e6eSJosh Paetzel         struct mbuf *m = NULL;
1638c2625e6eSJosh Paetzel 	struct oce_common_cqe_info cq_info;
1639c2625e6eSJosh Paetzel 
1640c2625e6eSJosh Paetzel 	/* parse cqe */
1641c2625e6eSJosh Paetzel         if(cqe2 == NULL) {
1642c2625e6eSJosh Paetzel                 cq_info.pkt_size =  cqe->pkt_size;
1643c2625e6eSJosh Paetzel                 cq_info.vtag = cqe->vlan_tag;
1644c2625e6eSJosh Paetzel                 cq_info.l4_cksum_pass = cqe->l4_cksum_pass;
1645c2625e6eSJosh Paetzel                 cq_info.ip_cksum_pass = cqe->ip_cksum_pass;
1646c2625e6eSJosh Paetzel                 cq_info.ipv6_frame = cqe->ipv6_frame;
1647c2625e6eSJosh Paetzel                 cq_info.vtp = cqe->vtp;
1648c2625e6eSJosh Paetzel                 cq_info.qnq = cqe->qnq;
1649c2625e6eSJosh Paetzel         }else {
1650c2625e6eSJosh Paetzel                 cqe1 = (struct nic_hwlro_cqe_part1 *)cqe;
1651c2625e6eSJosh Paetzel                 cq_info.pkt_size =  cqe2->coalesced_size;
1652c2625e6eSJosh Paetzel                 cq_info.vtag = cqe2->vlan_tag;
1653c2625e6eSJosh Paetzel                 cq_info.l4_cksum_pass = cqe2->l4_cksum_pass;
1654c2625e6eSJosh Paetzel                 cq_info.ip_cksum_pass = cqe2->ip_cksum_pass;
1655c2625e6eSJosh Paetzel                 cq_info.ipv6_frame = cqe2->ipv6_frame;
1656c2625e6eSJosh Paetzel                 cq_info.vtp = cqe2->vtp;
1657c2625e6eSJosh Paetzel                 cq_info.qnq = cqe1->qnq;
1658c2625e6eSJosh Paetzel         }
1659c2625e6eSJosh Paetzel 
1660c2625e6eSJosh Paetzel 	cq_info.vtag = BSWAP_16(cq_info.vtag);
1661c2625e6eSJosh Paetzel 
1662c2625e6eSJosh Paetzel         cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size;
1663c2625e6eSJosh Paetzel         if(cq_info.pkt_size % rq->cfg.frag_size)
1664c2625e6eSJosh Paetzel                 cq_info.num_frags++;
1665c2625e6eSJosh Paetzel 
1666c2625e6eSJosh Paetzel 	oce_rx_mbuf_chain(rq, &cq_info, &m);
1667c2625e6eSJosh Paetzel 
1668764c812dSJosh Paetzel 	if (m) {
1669c2625e6eSJosh Paetzel 		if(cqe2) {
1670c2625e6eSJosh Paetzel 			//assert(cqe2->valid != 0);
1671c2625e6eSJosh Paetzel 
1672c2625e6eSJosh Paetzel 			//assert(cqe2->cqe_type != 2);
1673c2625e6eSJosh Paetzel 			oce_correct_header(m, cqe1, cqe2);
1674c2625e6eSJosh Paetzel 		}
1675c2625e6eSJosh Paetzel 
1676c2625e6eSJosh Paetzel 		m->m_pkthdr.rcvif = sc->ifp;
1677c2625e6eSJosh Paetzel #if __FreeBSD_version >= 800000
1678c2625e6eSJosh Paetzel 		if (rq->queue_index)
1679c2625e6eSJosh Paetzel 			m->m_pkthdr.flowid = (rq->queue_index - 1);
1680c2625e6eSJosh Paetzel 		else
1681c2625e6eSJosh Paetzel 			m->m_pkthdr.flowid = rq->queue_index;
1682c2625e6eSJosh Paetzel 		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1683c2625e6eSJosh Paetzel #endif
1684c2625e6eSJosh Paetzel 		/* This deternies if vlan tag is Valid */
1685c2625e6eSJosh Paetzel 		if (cq_info.vtp) {
1686c2625e6eSJosh Paetzel 			if (sc->function_mode & FNM_FLEX10_MODE) {
1687c2625e6eSJosh Paetzel 				/* FLEX10. If QnQ is not set, neglect VLAN */
1688c2625e6eSJosh Paetzel 				if (cq_info.qnq) {
1689c2625e6eSJosh Paetzel 					m->m_pkthdr.ether_vtag = cq_info.vtag;
1690c2625e6eSJosh Paetzel 					m->m_flags |= M_VLANTAG;
1691c2625e6eSJosh Paetzel 				}
1692c2625e6eSJosh Paetzel 			} else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK))  {
1693c2625e6eSJosh Paetzel 				/* In UMC mode generally pvid will be striped by
1694c2625e6eSJosh Paetzel 				   hw. But in some cases we have seen it comes
1695c2625e6eSJosh Paetzel 				   with pvid. So if pvid == vlan, neglect vlan.
1696c2625e6eSJosh Paetzel 				 */
1697c2625e6eSJosh Paetzel 				m->m_pkthdr.ether_vtag = cq_info.vtag;
1698c2625e6eSJosh Paetzel 				m->m_flags |= M_VLANTAG;
1699c2625e6eSJosh Paetzel 			}
1700c2625e6eSJosh Paetzel 		}
1701c2625e6eSJosh Paetzel 		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1702c2625e6eSJosh Paetzel 
1703c2625e6eSJosh Paetzel 		(*sc->ifp->if_input) (sc->ifp, m);
1704c2625e6eSJosh Paetzel 
1705c2625e6eSJosh Paetzel 		/* Update rx stats per queue */
1706c2625e6eSJosh Paetzel 		rq->rx_stats.rx_pkts++;
1707c2625e6eSJosh Paetzel 		rq->rx_stats.rx_bytes += cq_info.pkt_size;
1708c2625e6eSJosh Paetzel 		rq->rx_stats.rx_frags += cq_info.num_frags;
1709c2625e6eSJosh Paetzel 		rq->rx_stats.rx_ucast_pkts++;
1710c2625e6eSJosh Paetzel 	}
1711c2625e6eSJosh Paetzel         return;
1712c2625e6eSJosh Paetzel }
1713c2625e6eSJosh Paetzel 
1714c2625e6eSJosh Paetzel static void
1715c2625e6eSJosh Paetzel oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
1716c2625e6eSJosh Paetzel {
1717c2625e6eSJosh Paetzel 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1718c2625e6eSJosh Paetzel 	int len;
1719c2625e6eSJosh Paetzel 	struct mbuf *m = NULL;
1720c2625e6eSJosh Paetzel 	struct oce_common_cqe_info cq_info;
1721c2625e6eSJosh Paetzel 	uint16_t vtag = 0;
1722c2625e6eSJosh Paetzel 
1723c2625e6eSJosh Paetzel 	/* Is it a flush compl that has no data */
1724c2625e6eSJosh Paetzel 	if(!cqe->u0.s.num_fragments)
1725c2625e6eSJosh Paetzel 		goto exit;
1726c2625e6eSJosh Paetzel 
1727c2625e6eSJosh Paetzel 	len = cqe->u0.s.pkt_size;
1728c2625e6eSJosh Paetzel 	if (!len) {
1729c2625e6eSJosh Paetzel 		/*partial DMA workaround for Lancer*/
1730c2625e6eSJosh Paetzel 		oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
173114410265SConrad Meyer 		goto exit;
173214410265SConrad Meyer 	}
173314410265SConrad Meyer 
1734c2625e6eSJosh Paetzel 	if (!oce_cqe_portid_valid(sc, cqe)) {
1735c2625e6eSJosh Paetzel 		oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
1736c2625e6eSJosh Paetzel 		goto exit;
1737c2625e6eSJosh Paetzel 	}
1738c2625e6eSJosh Paetzel 
1739c2625e6eSJosh Paetzel 	 /* Get vlan_tag value */
1740c2625e6eSJosh Paetzel 	if(IS_BE(sc) || IS_SH(sc))
1741c2625e6eSJosh Paetzel 		vtag = BSWAP_16(cqe->u0.s.vlan_tag);
1742c2625e6eSJosh Paetzel 	else
1743c2625e6eSJosh Paetzel 		vtag = cqe->u0.s.vlan_tag;
1744c2625e6eSJosh Paetzel 
1745c2625e6eSJosh Paetzel 	cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass;
1746c2625e6eSJosh Paetzel 	cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass;
1747c2625e6eSJosh Paetzel 	cq_info.ipv6_frame = cqe->u0.s.ip_ver;
1748c2625e6eSJosh Paetzel 	cq_info.num_frags = cqe->u0.s.num_fragments;
1749c2625e6eSJosh Paetzel 	cq_info.pkt_size = cqe->u0.s.pkt_size;
1750c2625e6eSJosh Paetzel 
1751c2625e6eSJosh Paetzel 	oce_rx_mbuf_chain(rq, &cq_info, &m);
1752c2625e6eSJosh Paetzel 
1753c2625e6eSJosh Paetzel 	if (m) {
17542f345d8eSLuigi Rizzo 		m->m_pkthdr.rcvif = sc->ifp;
17552f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000
1756291a1934SXin LI 		if (rq->queue_index)
1757291a1934SXin LI 			m->m_pkthdr.flowid = (rq->queue_index - 1);
1758291a1934SXin LI 		else
17592f345d8eSLuigi Rizzo 			m->m_pkthdr.flowid = rq->queue_index;
1760c2529042SHans Petter Selasky 		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
17612f345d8eSLuigi Rizzo #endif
17629bd3250aSLuigi Rizzo 		/* This deternies if vlan tag is Valid */
17632f345d8eSLuigi Rizzo 		if (oce_cqe_vtp_valid(sc, cqe)) {
17642f345d8eSLuigi Rizzo 			if (sc->function_mode & FNM_FLEX10_MODE) {
17659bd3250aSLuigi Rizzo 				/* FLEX10. If QnQ is not set, neglect VLAN */
17662f345d8eSLuigi Rizzo 				if (cqe->u0.s.qnq) {
17672f345d8eSLuigi Rizzo 					m->m_pkthdr.ether_vtag = vtag;
17682f345d8eSLuigi Rizzo 					m->m_flags |= M_VLANTAG;
17692f345d8eSLuigi Rizzo 				}
17709bd3250aSLuigi Rizzo 			} else if (sc->pvid != (vtag & VLAN_VID_MASK))  {
17719bd3250aSLuigi Rizzo 				/* In UMC mode generally pvid will be striped by
17729bd3250aSLuigi Rizzo 				   hw. But in some cases we have seen it comes
17739bd3250aSLuigi Rizzo 				   with pvid. So if pvid == vlan, neglect vlan.
17749bd3250aSLuigi Rizzo 				*/
17752f345d8eSLuigi Rizzo 				m->m_pkthdr.ether_vtag = vtag;
17762f345d8eSLuigi Rizzo 				m->m_flags |= M_VLANTAG;
17772f345d8eSLuigi Rizzo 			}
17782f345d8eSLuigi Rizzo 		}
17792f345d8eSLuigi Rizzo 
1780c8dfaf38SGleb Smirnoff 		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1781ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
17822f345d8eSLuigi Rizzo 		/* Try to queue to LRO */
17832f345d8eSLuigi Rizzo 		if (IF_LRO_ENABLED(sc) &&
17842f345d8eSLuigi Rizzo 		    (cqe->u0.s.ip_cksum_pass) &&
17852f345d8eSLuigi Rizzo 		    (cqe->u0.s.l4_cksum_pass) &&
17862f345d8eSLuigi Rizzo 		    (!cqe->u0.s.ip_ver)       &&
17872f345d8eSLuigi Rizzo 		    (rq->lro.lro_cnt != 0)) {
17882f345d8eSLuigi Rizzo 
17892f345d8eSLuigi Rizzo 			if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
17902f345d8eSLuigi Rizzo 				rq->lro_pkts_queued ++;
17912f345d8eSLuigi Rizzo 				goto post_done;
17922f345d8eSLuigi Rizzo 			}
17932f345d8eSLuigi Rizzo 			/* If LRO posting fails then try to post to STACK */
17942f345d8eSLuigi Rizzo 		}
1795ad512958SBjoern A. Zeeb #endif
17962f345d8eSLuigi Rizzo 
17972f345d8eSLuigi Rizzo 		(*sc->ifp->if_input) (sc->ifp, m);
1798ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
17992f345d8eSLuigi Rizzo post_done:
1800ad512958SBjoern A. Zeeb #endif
18012f345d8eSLuigi Rizzo 		/* Update rx stats per queue */
18022f345d8eSLuigi Rizzo 		rq->rx_stats.rx_pkts++;
18032f345d8eSLuigi Rizzo 		rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
18042f345d8eSLuigi Rizzo 		rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
18052f345d8eSLuigi Rizzo 		if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
18062f345d8eSLuigi Rizzo 			rq->rx_stats.rx_mcast_pkts++;
18072f345d8eSLuigi Rizzo 		if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
18082f345d8eSLuigi Rizzo 			rq->rx_stats.rx_ucast_pkts++;
18092f345d8eSLuigi Rizzo 	}
18102f345d8eSLuigi Rizzo exit:
18112f345d8eSLuigi Rizzo 	return;
18122f345d8eSLuigi Rizzo }
18132f345d8eSLuigi Rizzo 
18142f345d8eSLuigi Rizzo 
1815c2625e6eSJosh Paetzel void
1816c2625e6eSJosh Paetzel oce_discard_rx_comp(struct oce_rq *rq, int num_frags)
18172f345d8eSLuigi Rizzo {
1818c2625e6eSJosh Paetzel 	uint32_t i = 0;
18192f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
18202f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
18212f345d8eSLuigi Rizzo 
18222f345d8eSLuigi Rizzo 	for (i = 0; i < num_frags; i++) {
1823c2625e6eSJosh Paetzel                 if (rq->ring->cidx == rq->ring->pidx) {
18242f345d8eSLuigi Rizzo                         device_printf(sc->dev,
1825c2625e6eSJosh Paetzel                                 "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n");
1826c2625e6eSJosh Paetzel                         return;
18272f345d8eSLuigi Rizzo                 }
1828c2625e6eSJosh Paetzel                 pd = &rq->pckts[rq->ring->cidx];
18292f345d8eSLuigi Rizzo                 bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
18302f345d8eSLuigi Rizzo                 bus_dmamap_unload(rq->tag, pd->map);
1831c2625e6eSJosh Paetzel                 if (pd->mbuf != NULL) {
18322f345d8eSLuigi Rizzo                         m_freem(pd->mbuf);
1833c2625e6eSJosh Paetzel                         pd->mbuf = NULL;
18342f345d8eSLuigi Rizzo                 }
18352f345d8eSLuigi Rizzo 
1836c2625e6eSJosh Paetzel 		RING_GET(rq->ring, 1);
1837c2625e6eSJosh Paetzel                 rq->pending--;
1838c2625e6eSJosh Paetzel 	}
18392f345d8eSLuigi Rizzo }
18402f345d8eSLuigi Rizzo 
18412f345d8eSLuigi Rizzo 
18422f345d8eSLuigi Rizzo static int
18432f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
18442f345d8eSLuigi Rizzo {
18452f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe_v1 *cqe_v1;
18462f345d8eSLuigi Rizzo 	int vtp = 0;
18472f345d8eSLuigi Rizzo 
18482f345d8eSLuigi Rizzo 	if (sc->be3_native) {
18492f345d8eSLuigi Rizzo 		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
18502f345d8eSLuigi Rizzo 		vtp =  cqe_v1->u0.s.vlan_tag_present;
18519bd3250aSLuigi Rizzo 	} else
18522f345d8eSLuigi Rizzo 		vtp = cqe->u0.s.vlan_tag_present;
18532f345d8eSLuigi Rizzo 
18542f345d8eSLuigi Rizzo 	return vtp;
18552f345d8eSLuigi Rizzo 
18562f345d8eSLuigi Rizzo }
18572f345d8eSLuigi Rizzo 
18582f345d8eSLuigi Rizzo 
18592f345d8eSLuigi Rizzo static int
18602f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
18612f345d8eSLuigi Rizzo {
18622f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe_v1 *cqe_v1;
18632f345d8eSLuigi Rizzo 	int port_id = 0;
18642f345d8eSLuigi Rizzo 
1865291a1934SXin LI 	if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) {
18662f345d8eSLuigi Rizzo 		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
18672f345d8eSLuigi Rizzo 		port_id =  cqe_v1->u0.s.port;
18682f345d8eSLuigi Rizzo 		if (sc->port_id != port_id)
18692f345d8eSLuigi Rizzo 			return 0;
18702f345d8eSLuigi Rizzo 	} else
18712f345d8eSLuigi Rizzo 		;/* For BE3 legacy and Lancer this is dummy */
18722f345d8eSLuigi Rizzo 
18732f345d8eSLuigi Rizzo 	return 1;
18742f345d8eSLuigi Rizzo 
18752f345d8eSLuigi Rizzo }
18762f345d8eSLuigi Rizzo 
1877ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
1878c2625e6eSJosh Paetzel void
18792f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq)
18802f345d8eSLuigi Rizzo {
18812f345d8eSLuigi Rizzo 	struct lro_ctrl	*lro = &rq->lro;
18822f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
18832f345d8eSLuigi Rizzo 
18842f345d8eSLuigi Rizzo 	if (!IF_LRO_ENABLED(sc))
18852f345d8eSLuigi Rizzo 		return;
18862f345d8eSLuigi Rizzo 
18876dd38b87SSepherosa Ziehau 	tcp_lro_flush_all(lro);
18882f345d8eSLuigi Rizzo 	rq->lro_pkts_queued = 0;
18892f345d8eSLuigi Rizzo 
18902f345d8eSLuigi Rizzo 	return;
18912f345d8eSLuigi Rizzo }
18922f345d8eSLuigi Rizzo 
18932f345d8eSLuigi Rizzo 
18942f345d8eSLuigi Rizzo static int
18952f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc)
18962f345d8eSLuigi Rizzo {
18972f345d8eSLuigi Rizzo 	struct lro_ctrl *lro = NULL;
18982f345d8eSLuigi Rizzo 	int i = 0, rc = 0;
18992f345d8eSLuigi Rizzo 
19002f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nrqs; i++) {
19012f345d8eSLuigi Rizzo 		lro = &sc->rq[i]->lro;
19022f345d8eSLuigi Rizzo 		rc = tcp_lro_init(lro);
19032f345d8eSLuigi Rizzo 		if (rc != 0) {
19042f345d8eSLuigi Rizzo 			device_printf(sc->dev, "LRO init failed\n");
19052f345d8eSLuigi Rizzo 			return rc;
19062f345d8eSLuigi Rizzo 		}
19072f345d8eSLuigi Rizzo 		lro->ifp = sc->ifp;
19082f345d8eSLuigi Rizzo 	}
19092f345d8eSLuigi Rizzo 
19102f345d8eSLuigi Rizzo 	return rc;
19112f345d8eSLuigi Rizzo }
19129bd3250aSLuigi Rizzo 
19132f345d8eSLuigi Rizzo 
19142f345d8eSLuigi Rizzo void
19152f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc)
19162f345d8eSLuigi Rizzo {
19172f345d8eSLuigi Rizzo 	struct lro_ctrl *lro = NULL;
19182f345d8eSLuigi Rizzo 	int i = 0;
19192f345d8eSLuigi Rizzo 
19202f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nrqs; i++) {
19212f345d8eSLuigi Rizzo 		lro = &sc->rq[i]->lro;
19222f345d8eSLuigi Rizzo 		if (lro)
19232f345d8eSLuigi Rizzo 			tcp_lro_free(lro);
19242f345d8eSLuigi Rizzo 	}
19252f345d8eSLuigi Rizzo }
1926cdaba892SXin LI #endif
19272f345d8eSLuigi Rizzo 
19282f345d8eSLuigi Rizzo int
19292f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count)
19302f345d8eSLuigi Rizzo {
19312f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
19322f345d8eSLuigi Rizzo 	int i, in, rc;
19332f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
19342f345d8eSLuigi Rizzo 	bus_dma_segment_t segs[6];
19352f345d8eSLuigi Rizzo 	int nsegs, added = 0;
19362f345d8eSLuigi Rizzo 	struct oce_nic_rqe *rqe;
19372f345d8eSLuigi Rizzo 	pd_rxulp_db_t rxdb_reg;
1938c2625e6eSJosh Paetzel 	uint32_t val = 0;
1939c2625e6eSJosh Paetzel 	uint32_t oce_max_rq_posts = 64;
19402f345d8eSLuigi Rizzo 
1941cdaba892SXin LI 	bzero(&rxdb_reg, sizeof(pd_rxulp_db_t));
19422f345d8eSLuigi Rizzo 	for (i = 0; i < count; i++) {
1943c2625e6eSJosh Paetzel 		in = (rq->ring->pidx + 1) % OCE_RQ_PACKET_ARRAY_SIZE;
19442f345d8eSLuigi Rizzo 
1945c2625e6eSJosh Paetzel 		pd = &rq->pckts[rq->ring->pidx];
1946c2625e6eSJosh Paetzel 		pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size);
1947c2625e6eSJosh Paetzel 		if (pd->mbuf == NULL) {
1948c2625e6eSJosh Paetzel 			device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size);
19492f345d8eSLuigi Rizzo 			break;
1950c2625e6eSJosh Paetzel 		}
1951c2625e6eSJosh Paetzel 		pd->mbuf->m_nextpkt = NULL;
19522f345d8eSLuigi Rizzo 
1953c2625e6eSJosh Paetzel 		pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size;
1954c2625e6eSJosh Paetzel 
19552f345d8eSLuigi Rizzo 		rc = bus_dmamap_load_mbuf_sg(rq->tag,
19562f345d8eSLuigi Rizzo 					     pd->map,
19572f345d8eSLuigi Rizzo 					     pd->mbuf,
19582f345d8eSLuigi Rizzo 					     segs, &nsegs, BUS_DMA_NOWAIT);
19592f345d8eSLuigi Rizzo 		if (rc) {
19602f345d8eSLuigi Rizzo 			m_free(pd->mbuf);
1961c2625e6eSJosh Paetzel 			device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc);
19622f345d8eSLuigi Rizzo 			break;
19632f345d8eSLuigi Rizzo 		}
19642f345d8eSLuigi Rizzo 
19652f345d8eSLuigi Rizzo 		if (nsegs != 1) {
19662f345d8eSLuigi Rizzo 			i--;
19672f345d8eSLuigi Rizzo 			continue;
19682f345d8eSLuigi Rizzo 		}
19692f345d8eSLuigi Rizzo 
19702f345d8eSLuigi Rizzo 		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
19712f345d8eSLuigi Rizzo 
19722f345d8eSLuigi Rizzo 		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
19732f345d8eSLuigi Rizzo 		rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
19742f345d8eSLuigi Rizzo 		rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
19752f345d8eSLuigi Rizzo 		DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
19762f345d8eSLuigi Rizzo 		RING_PUT(rq->ring, 1);
19772f345d8eSLuigi Rizzo 		added++;
19782f345d8eSLuigi Rizzo 		rq->pending++;
19792f345d8eSLuigi Rizzo 	}
1980c2625e6eSJosh Paetzel 	oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS;
19812f345d8eSLuigi Rizzo 	if (added != 0) {
1982c2625e6eSJosh Paetzel 		for (i = added / oce_max_rq_posts; i > 0; i--) {
1983c2625e6eSJosh Paetzel 			rxdb_reg.bits.num_posted = oce_max_rq_posts;
19842f345d8eSLuigi Rizzo 			rxdb_reg.bits.qid = rq->rq_id;
1985c2625e6eSJosh Paetzel 			if(rq->islro) {
1986c2625e6eSJosh Paetzel                                 val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1987c2625e6eSJosh Paetzel                                 val |= oce_max_rq_posts << 16;
1988c2625e6eSJosh Paetzel                                 OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
1989c2625e6eSJosh Paetzel 			}else {
19902f345d8eSLuigi Rizzo 				OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1991c2625e6eSJosh Paetzel 			}
1992c2625e6eSJosh Paetzel 			added -= oce_max_rq_posts;
19932f345d8eSLuigi Rizzo 		}
19942f345d8eSLuigi Rizzo 		if (added > 0) {
19952f345d8eSLuigi Rizzo 			rxdb_reg.bits.qid = rq->rq_id;
19962f345d8eSLuigi Rizzo 			rxdb_reg.bits.num_posted = added;
1997c2625e6eSJosh Paetzel 			if(rq->islro) {
1998c2625e6eSJosh Paetzel                                 val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1999c2625e6eSJosh Paetzel                                 val |= added << 16;
2000c2625e6eSJosh Paetzel                                 OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
2001c2625e6eSJosh Paetzel 			}else {
20022f345d8eSLuigi Rizzo 				OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
20032f345d8eSLuigi Rizzo 			}
20042f345d8eSLuigi Rizzo 		}
2005c2625e6eSJosh Paetzel 	}
20062f345d8eSLuigi Rizzo 
20072f345d8eSLuigi Rizzo 	return 0;
20082f345d8eSLuigi Rizzo }
20092f345d8eSLuigi Rizzo 
2010c2625e6eSJosh Paetzel static void
2011c2625e6eSJosh Paetzel oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq)
2012c2625e6eSJosh Paetzel {
2013c2625e6eSJosh Paetzel         if (num_cqes) {
2014c2625e6eSJosh Paetzel                 oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE);
2015c2625e6eSJosh Paetzel 		if(!sc->enable_hwlro) {
2016c2625e6eSJosh Paetzel 			if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1)
2017c2625e6eSJosh Paetzel 				oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1));
2018c2625e6eSJosh Paetzel 		}else {
2019c2625e6eSJosh Paetzel                 	if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64)
2020c2625e6eSJosh Paetzel                         	oce_alloc_rx_bufs(rq, 64);
2021c2625e6eSJosh Paetzel         	}
2022c2625e6eSJosh Paetzel 	}
2023c2625e6eSJosh Paetzel 
2024c2625e6eSJosh Paetzel         return;
2025c2625e6eSJosh Paetzel }
2026c2625e6eSJosh Paetzel 
2027c2625e6eSJosh Paetzel uint16_t
2028c2625e6eSJosh Paetzel oce_rq_handler_lro(void *arg)
2029c2625e6eSJosh Paetzel {
2030c2625e6eSJosh Paetzel         struct oce_rq *rq = (struct oce_rq *)arg;
2031c2625e6eSJosh Paetzel         struct oce_cq *cq = rq->cq;
2032c2625e6eSJosh Paetzel         POCE_SOFTC sc = rq->parent;
2033c2625e6eSJosh Paetzel         struct nic_hwlro_singleton_cqe *cqe;
2034c2625e6eSJosh Paetzel         struct nic_hwlro_cqe_part2 *cqe2;
2035c2625e6eSJosh Paetzel         int num_cqes = 0;
2036c2625e6eSJosh Paetzel 
2037c2625e6eSJosh Paetzel 	LOCK(&rq->rx_lock);
2038c2625e6eSJosh Paetzel         bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2039c2625e6eSJosh Paetzel         cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
2040c2625e6eSJosh Paetzel         while (cqe->valid) {
2041c2625e6eSJosh Paetzel                 if(cqe->cqe_type == 0) { /* singleton cqe */
2042c2625e6eSJosh Paetzel 			/* we should not get singleton cqe after cqe1 on same rq */
2043c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart != NULL) {
2044c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got singleton cqe after cqe1 \n");
2045c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
2046c2625e6eSJosh Paetzel 			}
2047c2625e6eSJosh Paetzel                         if(cqe->error != 0) {
2048c2625e6eSJosh Paetzel                                 rq->rx_stats.rxcp_err++;
2049c2625e6eSJosh Paetzel 				if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
2050c2625e6eSJosh Paetzel                         }
2051c2625e6eSJosh Paetzel                         oce_rx_lro(rq, cqe, NULL);
2052c2625e6eSJosh Paetzel                         rq->rx_stats.rx_compl++;
2053c2625e6eSJosh Paetzel                         cqe->valid = 0;
2054c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
2055c2625e6eSJosh Paetzel                         num_cqes++;
2056c2625e6eSJosh Paetzel                         if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
2057c2625e6eSJosh Paetzel                                 break;
2058c2625e6eSJosh Paetzel                 }else if(cqe->cqe_type == 0x1) { /* first part */
2059c2625e6eSJosh Paetzel 			/* we should not get cqe1 after cqe1 on same rq */
2060c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart != NULL) {
2061c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got cqe1 after cqe1 \n");
2062c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
2063c2625e6eSJosh Paetzel 			}
2064c2625e6eSJosh Paetzel 			rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe;
2065c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
2066c2625e6eSJosh Paetzel                 }else if(cqe->cqe_type == 0x2) { /* second part */
2067c2625e6eSJosh Paetzel 			cqe2 = (struct nic_hwlro_cqe_part2 *)cqe;
2068c2625e6eSJosh Paetzel                         if(cqe2->error != 0) {
2069c2625e6eSJosh Paetzel                                 rq->rx_stats.rxcp_err++;
2070c2625e6eSJosh Paetzel 				if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
2071c2625e6eSJosh Paetzel                         }
2072c2625e6eSJosh Paetzel 			/* We should not get cqe2 without cqe1 */
2073c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart == NULL) {
2074c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got cqe2 without cqe1 \n");
2075c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
2076c2625e6eSJosh Paetzel 			}
2077c2625e6eSJosh Paetzel                         oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2);
2078c2625e6eSJosh Paetzel 
2079c2625e6eSJosh Paetzel                         rq->rx_stats.rx_compl++;
2080c2625e6eSJosh Paetzel                         rq->cqe_firstpart->valid = 0;
2081c2625e6eSJosh Paetzel                         cqe2->valid = 0;
2082c2625e6eSJosh Paetzel 			rq->cqe_firstpart = NULL;
2083c2625e6eSJosh Paetzel 
2084c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
2085c2625e6eSJosh Paetzel                         num_cqes += 2;
2086c2625e6eSJosh Paetzel                         if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
2087c2625e6eSJosh Paetzel                                 break;
2088c2625e6eSJosh Paetzel 		}
2089c2625e6eSJosh Paetzel 
2090c2625e6eSJosh Paetzel                 bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2091c2625e6eSJosh Paetzel                 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
2092c2625e6eSJosh Paetzel         }
2093c2625e6eSJosh Paetzel 	oce_check_rx_bufs(sc, num_cqes, rq);
2094c2625e6eSJosh Paetzel exit_rq_handler_lro:
2095c2625e6eSJosh Paetzel 	UNLOCK(&rq->rx_lock);
2096c2625e6eSJosh Paetzel 	return 0;
2097c2625e6eSJosh Paetzel }
20982f345d8eSLuigi Rizzo 
20992f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */
21002f345d8eSLuigi Rizzo uint16_t
21012f345d8eSLuigi Rizzo oce_rq_handler(void *arg)
21022f345d8eSLuigi Rizzo {
21032f345d8eSLuigi Rizzo 	struct oce_rq *rq = (struct oce_rq *)arg;
21042f345d8eSLuigi Rizzo 	struct oce_cq *cq = rq->cq;
21052f345d8eSLuigi Rizzo 	POCE_SOFTC sc = rq->parent;
21062f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe *cqe;
2107c2625e6eSJosh Paetzel 	int num_cqes = 0;
21082f345d8eSLuigi Rizzo 
2109c2625e6eSJosh Paetzel 	if(rq->islro) {
2110c2625e6eSJosh Paetzel 		oce_rq_handler_lro(arg);
2111c2625e6eSJosh Paetzel 		return 0;
2112c2625e6eSJosh Paetzel 	}
2113c2625e6eSJosh Paetzel 	LOCK(&rq->rx_lock);
21142f345d8eSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
21152f345d8eSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
21162f345d8eSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
21172f345d8eSLuigi Rizzo 	while (cqe->u0.dw[2]) {
21182f345d8eSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
21192f345d8eSLuigi Rizzo 
21202f345d8eSLuigi Rizzo 		if (cqe->u0.s.error == 0) {
2121c2625e6eSJosh Paetzel 			oce_rx(rq, cqe);
21222f345d8eSLuigi Rizzo 		} else {
21232f345d8eSLuigi Rizzo 			rq->rx_stats.rxcp_err++;
2124c8dfaf38SGleb Smirnoff 			if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
21252f345d8eSLuigi Rizzo 			/* Post L3/L4 errors to stack.*/
2126c2625e6eSJosh Paetzel 			oce_rx(rq, cqe);
21272f345d8eSLuigi Rizzo 		}
21282f345d8eSLuigi Rizzo 		rq->rx_stats.rx_compl++;
21292f345d8eSLuigi Rizzo 		cqe->u0.dw[2] = 0;
21302f345d8eSLuigi Rizzo 
2131ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
21322f345d8eSLuigi Rizzo 		if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
21332f345d8eSLuigi Rizzo 			oce_rx_flush_lro(rq);
21342f345d8eSLuigi Rizzo 		}
2135ad512958SBjoern A. Zeeb #endif
21362f345d8eSLuigi Rizzo 
21372f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
21382f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
21392f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
21402f345d8eSLuigi Rizzo 		cqe =
21412f345d8eSLuigi Rizzo 		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
21422f345d8eSLuigi Rizzo 		num_cqes++;
21432f345d8eSLuigi Rizzo 		if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
21442f345d8eSLuigi Rizzo 			break;
21452f345d8eSLuigi Rizzo 	}
21469bd3250aSLuigi Rizzo 
2147ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
21482f345d8eSLuigi Rizzo         if (IF_LRO_ENABLED(sc))
21492f345d8eSLuigi Rizzo                 oce_rx_flush_lro(rq);
2150ad512958SBjoern A. Zeeb #endif
21512f345d8eSLuigi Rizzo 
2152c2625e6eSJosh Paetzel 	oce_check_rx_bufs(sc, num_cqes, rq);
2153c2625e6eSJosh Paetzel 	UNLOCK(&rq->rx_lock);
21542f345d8eSLuigi Rizzo 	return 0;
21552f345d8eSLuigi Rizzo 
21562f345d8eSLuigi Rizzo }
21572f345d8eSLuigi Rizzo 
21582f345d8eSLuigi Rizzo 
21592f345d8eSLuigi Rizzo 
21602f345d8eSLuigi Rizzo 
21612f345d8eSLuigi Rizzo /*****************************************************************************
21622f345d8eSLuigi Rizzo  *		   Helper function prototypes in this file 		     *
21632f345d8eSLuigi Rizzo  *****************************************************************************/
21642f345d8eSLuigi Rizzo 
21652f345d8eSLuigi Rizzo static int
21662f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc)
21672f345d8eSLuigi Rizzo {
21682f345d8eSLuigi Rizzo 
21692f345d8eSLuigi Rizzo 	sc->ifp = if_alloc(IFT_ETHER);
21702f345d8eSLuigi Rizzo 	if (!sc->ifp)
21712f345d8eSLuigi Rizzo 		return ENOMEM;
21722f345d8eSLuigi Rizzo 
21732f345d8eSLuigi Rizzo 	ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
21742f345d8eSLuigi Rizzo 	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
21752f345d8eSLuigi Rizzo 	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
21762f345d8eSLuigi Rizzo 
21772f345d8eSLuigi Rizzo 	sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
21782f345d8eSLuigi Rizzo 	sc->ifp->if_ioctl = oce_ioctl;
21792f345d8eSLuigi Rizzo 	sc->ifp->if_start = oce_start;
21802f345d8eSLuigi Rizzo 	sc->ifp->if_init = oce_init;
21812f345d8eSLuigi Rizzo 	sc->ifp->if_mtu = ETHERMTU;
21822f345d8eSLuigi Rizzo 	sc->ifp->if_softc = sc;
21832f345d8eSLuigi Rizzo #if __FreeBSD_version >= 800000
21842f345d8eSLuigi Rizzo 	sc->ifp->if_transmit = oce_multiq_start;
21852f345d8eSLuigi Rizzo 	sc->ifp->if_qflush = oce_multiq_flush;
21862f345d8eSLuigi Rizzo #endif
21872f345d8eSLuigi Rizzo 
21882f345d8eSLuigi Rizzo 	if_initname(sc->ifp,
21892f345d8eSLuigi Rizzo 		    device_get_name(sc->dev), device_get_unit(sc->dev));
21902f345d8eSLuigi Rizzo 
21912f345d8eSLuigi Rizzo 	sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1;
21922f345d8eSLuigi Rizzo 	IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen);
21932f345d8eSLuigi Rizzo 	IFQ_SET_READY(&sc->ifp->if_snd);
21942f345d8eSLuigi Rizzo 
21952f345d8eSLuigi Rizzo 	sc->ifp->if_hwassist = OCE_IF_HWASSIST;
21962f345d8eSLuigi Rizzo 	sc->ifp->if_hwassist |= CSUM_TSO;
21972f345d8eSLuigi Rizzo 	sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP);
21982f345d8eSLuigi Rizzo 
21992f345d8eSLuigi Rizzo 	sc->ifp->if_capabilities = OCE_IF_CAPABILITIES;
22002f345d8eSLuigi Rizzo 	sc->ifp->if_capabilities |= IFCAP_HWCSUM;
22012f345d8eSLuigi Rizzo 	sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
22029bd3250aSLuigi Rizzo 
2203ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
2204ad512958SBjoern A. Zeeb 	sc->ifp->if_capabilities |= IFCAP_TSO;
22052f345d8eSLuigi Rizzo 	sc->ifp->if_capabilities |= IFCAP_LRO;
22069bd3250aSLuigi Rizzo 	sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
2207ad512958SBjoern A. Zeeb #endif
22082f345d8eSLuigi Rizzo 
22092f345d8eSLuigi Rizzo 	sc->ifp->if_capenable = sc->ifp->if_capabilities;
2210b245f96cSGleb Smirnoff 	sc->ifp->if_baudrate = IF_Gbps(10);
22112f345d8eSLuigi Rizzo 
22125fbb6830SXin LI #if __FreeBSD_version >= 1000000
22139fd573c3SHans Petter Selasky 	sc->ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
22149fd573c3SHans Petter Selasky 	sc->ifp->if_hw_tsomaxsegcount = OCE_MAX_TX_ELEMENTS;
22159fd573c3SHans Petter Selasky 	sc->ifp->if_hw_tsomaxsegsize = 4096;
22165fbb6830SXin LI #endif
22175fbb6830SXin LI 
22182f345d8eSLuigi Rizzo 	ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
22192f345d8eSLuigi Rizzo 
22202f345d8eSLuigi Rizzo 	return 0;
22212f345d8eSLuigi Rizzo }
22222f345d8eSLuigi Rizzo 
22232f345d8eSLuigi Rizzo 
22242f345d8eSLuigi Rizzo static void
22252f345d8eSLuigi Rizzo oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
22262f345d8eSLuigi Rizzo {
22272f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
22282f345d8eSLuigi Rizzo 
22292f345d8eSLuigi Rizzo 	if (ifp->if_softc !=  arg)
22302f345d8eSLuigi Rizzo 		return;
22312f345d8eSLuigi Rizzo 	if ((vtag == 0) || (vtag > 4095))
22322f345d8eSLuigi Rizzo 		return;
22332f345d8eSLuigi Rizzo 
22342f345d8eSLuigi Rizzo 	sc->vlan_tag[vtag] = 1;
22352f345d8eSLuigi Rizzo 	sc->vlans_added++;
22365fbb6830SXin LI 	if (sc->vlans_added <= (sc->max_vlans + 1))
22372f345d8eSLuigi Rizzo 		oce_vid_config(sc);
22382f345d8eSLuigi Rizzo }
22392f345d8eSLuigi Rizzo 
22402f345d8eSLuigi Rizzo 
22412f345d8eSLuigi Rizzo static void
22422f345d8eSLuigi Rizzo oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
22432f345d8eSLuigi Rizzo {
22442f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
22452f345d8eSLuigi Rizzo 
22462f345d8eSLuigi Rizzo 	if (ifp->if_softc !=  arg)
22472f345d8eSLuigi Rizzo 		return;
22482f345d8eSLuigi Rizzo 	if ((vtag == 0) || (vtag > 4095))
22492f345d8eSLuigi Rizzo 		return;
22502f345d8eSLuigi Rizzo 
22512f345d8eSLuigi Rizzo 	sc->vlan_tag[vtag] = 0;
22522f345d8eSLuigi Rizzo 	sc->vlans_added--;
22532f345d8eSLuigi Rizzo 	oce_vid_config(sc);
22542f345d8eSLuigi Rizzo }
22552f345d8eSLuigi Rizzo 
22562f345d8eSLuigi Rizzo 
22572f345d8eSLuigi Rizzo /*
22582f345d8eSLuigi Rizzo  * A max of 64 vlans can be configured in BE. If the user configures
22592f345d8eSLuigi Rizzo  * more, place the card in vlan promiscuous mode.
22602f345d8eSLuigi Rizzo  */
22612f345d8eSLuigi Rizzo static int
22622f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc)
22632f345d8eSLuigi Rizzo {
22642f345d8eSLuigi Rizzo 	struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
22652f345d8eSLuigi Rizzo 	uint16_t ntags = 0, i;
22662f345d8eSLuigi Rizzo 	int status = 0;
22672f345d8eSLuigi Rizzo 
22682f345d8eSLuigi Rizzo 	if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
22692f345d8eSLuigi Rizzo 			(sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) {
22702f345d8eSLuigi Rizzo 		for (i = 0; i < MAX_VLANS; i++) {
22712f345d8eSLuigi Rizzo 			if (sc->vlan_tag[i]) {
22722f345d8eSLuigi Rizzo 				vtags[ntags].vtag = i;
22732f345d8eSLuigi Rizzo 				ntags++;
22742f345d8eSLuigi Rizzo 			}
22752f345d8eSLuigi Rizzo 		}
22762f345d8eSLuigi Rizzo 		if (ntags)
22772f345d8eSLuigi Rizzo 			status = oce_config_vlan(sc, (uint8_t) sc->if_id,
22782f345d8eSLuigi Rizzo 						vtags, ntags, 1, 0);
22792f345d8eSLuigi Rizzo 	} else
22802f345d8eSLuigi Rizzo 		status = oce_config_vlan(sc, (uint8_t) sc->if_id,
22812f345d8eSLuigi Rizzo 					 	NULL, 0, 1, 1);
22822f345d8eSLuigi Rizzo 	return status;
22832f345d8eSLuigi Rizzo }
22842f345d8eSLuigi Rizzo 
22852f345d8eSLuigi Rizzo 
22862f345d8eSLuigi Rizzo static void
22872f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc)
22882f345d8eSLuigi Rizzo {
22892f345d8eSLuigi Rizzo 	uint32_t old_pmac_id = sc->pmac_id;
22902f345d8eSLuigi Rizzo 	int status = 0;
22912f345d8eSLuigi Rizzo 
22922f345d8eSLuigi Rizzo 
22932f345d8eSLuigi Rizzo 	status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
22942f345d8eSLuigi Rizzo 			 sc->macaddr.size_of_struct);
22952f345d8eSLuigi Rizzo 	if (!status)
22962f345d8eSLuigi Rizzo 		return;
22972f345d8eSLuigi Rizzo 
22982f345d8eSLuigi Rizzo 	status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)),
22992f345d8eSLuigi Rizzo 					sc->if_id, &sc->pmac_id);
23002f345d8eSLuigi Rizzo 	if (!status) {
23012f345d8eSLuigi Rizzo 		status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
23022f345d8eSLuigi Rizzo 		bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
23032f345d8eSLuigi Rizzo 				 sc->macaddr.size_of_struct);
23042f345d8eSLuigi Rizzo 	}
23052f345d8eSLuigi Rizzo 	if (status)
23062f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Failed update macaddress\n");
23072f345d8eSLuigi Rizzo 
23082f345d8eSLuigi Rizzo }
23092f345d8eSLuigi Rizzo 
23102f345d8eSLuigi Rizzo 
23112f345d8eSLuigi Rizzo static int
23122f345d8eSLuigi Rizzo oce_handle_passthrough(struct ifnet *ifp, caddr_t data)
23132f345d8eSLuigi Rizzo {
23142f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ifp->if_softc;
23152f345d8eSLuigi Rizzo 	struct ifreq *ifr = (struct ifreq *)data;
23162f345d8eSLuigi Rizzo 	int rc = ENXIO;
23172f345d8eSLuigi Rizzo 	char cookie[32] = {0};
2318541d96aaSBrooks Davis 	void *priv_data = ifr_data_get_ptr(ifr);
23192f345d8eSLuigi Rizzo 	void *ioctl_ptr;
23202f345d8eSLuigi Rizzo 	uint32_t req_size;
23212f345d8eSLuigi Rizzo 	struct mbx_hdr req;
23222f345d8eSLuigi Rizzo 	OCE_DMA_MEM dma_mem;
2323cdaba892SXin LI 	struct mbx_common_get_cntl_attr *fw_cmd;
23242f345d8eSLuigi Rizzo 
23252f345d8eSLuigi Rizzo 	if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
23262f345d8eSLuigi Rizzo 		return EFAULT;
23272f345d8eSLuigi Rizzo 
23282f345d8eSLuigi Rizzo 	if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
23292f345d8eSLuigi Rizzo 		return EINVAL;
23302f345d8eSLuigi Rizzo 
23312f345d8eSLuigi Rizzo 	ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
23322f345d8eSLuigi Rizzo 	if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
23332f345d8eSLuigi Rizzo 		return EFAULT;
23342f345d8eSLuigi Rizzo 
23352f345d8eSLuigi Rizzo 	req_size = le32toh(req.u0.req.request_length);
23362f345d8eSLuigi Rizzo 	if (req_size > 65536)
23372f345d8eSLuigi Rizzo 		return EINVAL;
23382f345d8eSLuigi Rizzo 
23392f345d8eSLuigi Rizzo 	req_size += sizeof(struct mbx_hdr);
23402f345d8eSLuigi Rizzo 	rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
23412f345d8eSLuigi Rizzo 	if (rc)
23422f345d8eSLuigi Rizzo 		return ENOMEM;
23432f345d8eSLuigi Rizzo 
23442f345d8eSLuigi Rizzo 	if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
23452f345d8eSLuigi Rizzo 		rc = EFAULT;
23462f345d8eSLuigi Rizzo 		goto dma_free;
23472f345d8eSLuigi Rizzo 	}
23482f345d8eSLuigi Rizzo 
23492f345d8eSLuigi Rizzo 	rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
23502f345d8eSLuigi Rizzo 	if (rc) {
23512f345d8eSLuigi Rizzo 		rc = EIO;
23522f345d8eSLuigi Rizzo 		goto dma_free;
23532f345d8eSLuigi Rizzo 	}
23542f345d8eSLuigi Rizzo 
23552f345d8eSLuigi Rizzo 	if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size))
23562f345d8eSLuigi Rizzo 		rc =  EFAULT;
23572f345d8eSLuigi Rizzo 
2358cdaba892SXin LI 	/*
2359cdaba892SXin LI 	   firmware is filling all the attributes for this ioctl except
2360cdaba892SXin LI 	   the driver version..so fill it
2361cdaba892SXin LI 	 */
2362cdaba892SXin LI 	if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) {
2363cdaba892SXin LI 		fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr;
2364cdaba892SXin LI 		strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str,
2365cdaba892SXin LI 			COMPONENT_REVISION, strlen(COMPONENT_REVISION));
2366cdaba892SXin LI 	}
2367cdaba892SXin LI 
23682f345d8eSLuigi Rizzo dma_free:
23692f345d8eSLuigi Rizzo 	oce_dma_free(sc, &dma_mem);
23702f345d8eSLuigi Rizzo 	return rc;
23712f345d8eSLuigi Rizzo 
23722f345d8eSLuigi Rizzo }
23732f345d8eSLuigi Rizzo 
2374cdaba892SXin LI static void
2375cdaba892SXin LI oce_eqd_set_periodic(POCE_SOFTC sc)
2376cdaba892SXin LI {
2377cdaba892SXin LI 	struct oce_set_eqd set_eqd[OCE_MAX_EQ];
2378cdaba892SXin LI 	struct oce_aic_obj *aic;
2379cdaba892SXin LI 	struct oce_eq *eqo;
2380cdaba892SXin LI 	uint64_t now = 0, delta;
2381cdaba892SXin LI 	int eqd, i, num = 0;
2382c2625e6eSJosh Paetzel 	uint32_t tx_reqs = 0, rxpkts = 0, pps;
2383c2625e6eSJosh Paetzel 	struct oce_wq *wq;
2384c2625e6eSJosh Paetzel 	struct oce_rq *rq;
2385c2625e6eSJosh Paetzel 
2386c2625e6eSJosh Paetzel 	#define ticks_to_msecs(t)       (1000 * (t) / hz)
2387cdaba892SXin LI 
2388cdaba892SXin LI 	for (i = 0 ; i < sc->neqs; i++) {
2389cdaba892SXin LI 		eqo = sc->eq[i];
2390cdaba892SXin LI 		aic = &sc->aic_obj[i];
2391cdaba892SXin LI 		/* When setting the static eq delay from the user space */
2392cdaba892SXin LI 		if (!aic->enable) {
2393c2625e6eSJosh Paetzel 			if (aic->ticks)
2394c2625e6eSJosh Paetzel 				aic->ticks = 0;
2395cdaba892SXin LI 			eqd = aic->et_eqd;
2396cdaba892SXin LI 			goto modify_eqd;
2397cdaba892SXin LI 		}
2398cdaba892SXin LI 
239935828280SAlexander Motin 		if (i == 0) {
240035828280SAlexander Motin 			rq = sc->rq[0];
2401c2625e6eSJosh Paetzel 			rxpkts = rq->rx_stats.rx_pkts;
240235828280SAlexander Motin 		} else
240335828280SAlexander Motin 			rxpkts = 0;
240435828280SAlexander Motin 		if (i + 1 < sc->nrqs) {
240535828280SAlexander Motin 			rq = sc->rq[i + 1];
240635828280SAlexander Motin 			rxpkts += rq->rx_stats.rx_pkts;
240735828280SAlexander Motin 		}
240835828280SAlexander Motin 		if (i < sc->nwqs) {
2409c2625e6eSJosh Paetzel 			wq = sc->wq[i];
2410c2625e6eSJosh Paetzel 			tx_reqs = wq->tx_stats.tx_reqs;
241135828280SAlexander Motin 		} else
241235828280SAlexander Motin 			tx_reqs = 0;
2413cdaba892SXin LI 		now = ticks;
2414cdaba892SXin LI 
2415c2625e6eSJosh Paetzel 		if (!aic->ticks || now < aic->ticks ||
2416c2625e6eSJosh Paetzel 		    rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) {
2417c2625e6eSJosh Paetzel 			aic->prev_rxpkts = rxpkts;
2418c2625e6eSJosh Paetzel 			aic->prev_txreqs = tx_reqs;
2419c2625e6eSJosh Paetzel 			aic->ticks = now;
2420c2625e6eSJosh Paetzel 			continue;
2421c2625e6eSJosh Paetzel 		}
2422cdaba892SXin LI 
2423c2625e6eSJosh Paetzel 		delta = ticks_to_msecs(now - aic->ticks);
2424cdaba892SXin LI 
2425c2625e6eSJosh Paetzel 		pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) +
2426c2625e6eSJosh Paetzel 		      (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta);
2427c2625e6eSJosh Paetzel 		eqd = (pps / 15000) << 2;
2428c2625e6eSJosh Paetzel 		if (eqd < 8)
2429cdaba892SXin LI 			eqd = 0;
2430cdaba892SXin LI 
2431cdaba892SXin LI 		/* Make sure that the eq delay is in the known range */
2432cdaba892SXin LI 		eqd = min(eqd, aic->max_eqd);
2433cdaba892SXin LI 		eqd = max(eqd, aic->min_eqd);
2434cdaba892SXin LI 
2435c2625e6eSJosh Paetzel 		aic->prev_rxpkts = rxpkts;
2436c2625e6eSJosh Paetzel 		aic->prev_txreqs = tx_reqs;
2437c2625e6eSJosh Paetzel 		aic->ticks = now;
2438c2625e6eSJosh Paetzel 
2439cdaba892SXin LI modify_eqd:
2440cdaba892SXin LI 		if (eqd != aic->cur_eqd) {
2441cdaba892SXin LI 			set_eqd[num].delay_multiplier = (eqd * 65)/100;
2442cdaba892SXin LI 			set_eqd[num].eq_id = eqo->eq_id;
2443cdaba892SXin LI 			aic->cur_eqd = eqd;
2444cdaba892SXin LI 			num++;
2445cdaba892SXin LI 		}
2446cdaba892SXin LI 	}
2447cdaba892SXin LI 
2448cdaba892SXin LI 	/* Is there atleast one eq that needs to be modified? */
2449c2625e6eSJosh Paetzel         for(i = 0; i < num; i += 8) {
2450c2625e6eSJosh Paetzel                 if((num - i) >=8 )
2451c2625e6eSJosh Paetzel                         oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8);
2452c2625e6eSJosh Paetzel                 else
2453c2625e6eSJosh Paetzel                         oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i));
2454c2625e6eSJosh Paetzel         }
2455c2625e6eSJosh Paetzel 
2456cdaba892SXin LI }
24572f345d8eSLuigi Rizzo 
24585fbb6830SXin LI static void oce_detect_hw_error(POCE_SOFTC sc)
24595fbb6830SXin LI {
24605fbb6830SXin LI 
24615fbb6830SXin LI 	uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0;
24625fbb6830SXin LI 	uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
24635fbb6830SXin LI 	uint32_t i;
24645fbb6830SXin LI 
24655fbb6830SXin LI 	if (sc->hw_error)
24665fbb6830SXin LI 		return;
24675fbb6830SXin LI 
24685fbb6830SXin LI 	if (IS_XE201(sc)) {
24695fbb6830SXin LI 		sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET);
24705fbb6830SXin LI 		if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24715fbb6830SXin LI 			sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET);
24725fbb6830SXin LI 			sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET);
24735fbb6830SXin LI 		}
24745fbb6830SXin LI 	} else {
24755fbb6830SXin LI 		ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW);
24765fbb6830SXin LI 		ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH);
24775fbb6830SXin LI 		ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK);
24785fbb6830SXin LI 		ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK);
24795fbb6830SXin LI 
24805fbb6830SXin LI 		ue_low = (ue_low & ~ue_low_mask);
24815fbb6830SXin LI 		ue_high = (ue_high & ~ue_high_mask);
24825fbb6830SXin LI 	}
24835fbb6830SXin LI 
24845fbb6830SXin LI 	/* On certain platforms BE hardware can indicate spurious UEs.
24855fbb6830SXin LI 	 * Allow the h/w to stop working completely in case of a real UE.
24865fbb6830SXin LI 	 * Hence not setting the hw_error for UE detection.
24875fbb6830SXin LI 	 */
24885fbb6830SXin LI 	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24895fbb6830SXin LI 		sc->hw_error = TRUE;
24905fbb6830SXin LI 		device_printf(sc->dev, "Error detected in the card\n");
24915fbb6830SXin LI 	}
24925fbb6830SXin LI 
24935fbb6830SXin LI 	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24945fbb6830SXin LI 		device_printf(sc->dev,
24955fbb6830SXin LI 				"ERR: sliport status 0x%x\n", sliport_status);
24965fbb6830SXin LI 		device_printf(sc->dev,
24975fbb6830SXin LI 				"ERR: sliport error1 0x%x\n", sliport_err1);
24985fbb6830SXin LI 		device_printf(sc->dev,
24995fbb6830SXin LI 				"ERR: sliport error2 0x%x\n", sliport_err2);
25005fbb6830SXin LI 	}
25015fbb6830SXin LI 
25025fbb6830SXin LI 	if (ue_low) {
25035fbb6830SXin LI 		for (i = 0; ue_low; ue_low >>= 1, i++) {
25045fbb6830SXin LI 			if (ue_low & 1)
25055fbb6830SXin LI 				device_printf(sc->dev, "UE: %s bit set\n",
25065fbb6830SXin LI 							ue_status_low_desc[i]);
25075fbb6830SXin LI 		}
25085fbb6830SXin LI 	}
25095fbb6830SXin LI 
25105fbb6830SXin LI 	if (ue_high) {
25115fbb6830SXin LI 		for (i = 0; ue_high; ue_high >>= 1, i++) {
25125fbb6830SXin LI 			if (ue_high & 1)
25135fbb6830SXin LI 				device_printf(sc->dev, "UE: %s bit set\n",
25145fbb6830SXin LI 							ue_status_hi_desc[i]);
25155fbb6830SXin LI 		}
25165fbb6830SXin LI 	}
25175fbb6830SXin LI 
25185fbb6830SXin LI }
25195fbb6830SXin LI 
25205fbb6830SXin LI 
25212f345d8eSLuigi Rizzo static void
25222f345d8eSLuigi Rizzo oce_local_timer(void *arg)
25232f345d8eSLuigi Rizzo {
25242f345d8eSLuigi Rizzo 	POCE_SOFTC sc = arg;
25252f345d8eSLuigi Rizzo 	int i = 0;
25262f345d8eSLuigi Rizzo 
25275fbb6830SXin LI 	oce_detect_hw_error(sc);
25282f345d8eSLuigi Rizzo 	oce_refresh_nic_stats(sc);
25292f345d8eSLuigi Rizzo 	oce_refresh_queue_stats(sc);
25302f345d8eSLuigi Rizzo 	oce_mac_addr_set(sc);
25312f345d8eSLuigi Rizzo 
25322f345d8eSLuigi Rizzo 	/* TX Watch Dog*/
25332f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nwqs; i++)
25342f345d8eSLuigi Rizzo 		oce_tx_restart(sc, sc->wq[i]);
25352f345d8eSLuigi Rizzo 
2536cdaba892SXin LI 	/* calculate and set the eq delay for optimal interrupt rate */
2537291a1934SXin LI 	if (IS_BE(sc) || IS_SH(sc))
2538cdaba892SXin LI 		oce_eqd_set_periodic(sc);
2539cdaba892SXin LI 
25402f345d8eSLuigi Rizzo 	callout_reset(&sc->timer, hz, oce_local_timer, sc);
25412f345d8eSLuigi Rizzo }
25422f345d8eSLuigi Rizzo 
2543c2625e6eSJosh Paetzel static void
2544c2625e6eSJosh Paetzel oce_tx_compl_clean(POCE_SOFTC sc)
2545c2625e6eSJosh Paetzel {
2546c2625e6eSJosh Paetzel 	struct oce_wq *wq;
2547c2625e6eSJosh Paetzel 	int i = 0, timeo = 0, num_wqes = 0;
2548c2625e6eSJosh Paetzel 	int pending_txqs = sc->nwqs;
2549c2625e6eSJosh Paetzel 
2550c2625e6eSJosh Paetzel 	/* Stop polling for compls when HW has been silent for 10ms or
2551c2625e6eSJosh Paetzel 	 * hw_error or no outstanding completions expected
2552c2625e6eSJosh Paetzel 	 */
2553c2625e6eSJosh Paetzel 	do {
2554c2625e6eSJosh Paetzel 		pending_txqs = sc->nwqs;
2555c2625e6eSJosh Paetzel 
2556c2625e6eSJosh Paetzel 		for_all_wq_queues(sc, wq, i) {
2557c2625e6eSJosh Paetzel 			num_wqes = oce_wq_handler(wq);
2558c2625e6eSJosh Paetzel 
2559c2625e6eSJosh Paetzel 			if(num_wqes)
2560c2625e6eSJosh Paetzel 				timeo = 0;
2561c2625e6eSJosh Paetzel 
2562c2625e6eSJosh Paetzel 			if(!wq->ring->num_used)
2563c2625e6eSJosh Paetzel 				pending_txqs--;
2564c2625e6eSJosh Paetzel 		}
2565c2625e6eSJosh Paetzel 
2566c2625e6eSJosh Paetzel 		if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error)
2567c2625e6eSJosh Paetzel 			break;
2568c2625e6eSJosh Paetzel 
2569c2625e6eSJosh Paetzel 		DELAY(1000);
2570c2625e6eSJosh Paetzel 	} while (TRUE);
2571c2625e6eSJosh Paetzel 
2572c2625e6eSJosh Paetzel 	for_all_wq_queues(sc, wq, i) {
2573c2625e6eSJosh Paetzel 		while(wq->ring->num_used) {
2574c2625e6eSJosh Paetzel 			LOCK(&wq->tx_compl_lock);
2575c2625e6eSJosh Paetzel 			oce_process_tx_completion(wq);
2576c2625e6eSJosh Paetzel 			UNLOCK(&wq->tx_compl_lock);
2577c2625e6eSJosh Paetzel 		}
2578c2625e6eSJosh Paetzel 	}
2579c2625e6eSJosh Paetzel 
2580c2625e6eSJosh Paetzel }
25812f345d8eSLuigi Rizzo 
2582beb0f7e7SJosh Paetzel /* NOTE : This should only be called holding
2583beb0f7e7SJosh Paetzel  *        DEVICE_LOCK.
2584beb0f7e7SJosh Paetzel  */
25852f345d8eSLuigi Rizzo static void
25862f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc)
25872f345d8eSLuigi Rizzo {
2588c2625e6eSJosh Paetzel 	int i;
25892f345d8eSLuigi Rizzo 	struct oce_rq *rq;
25902f345d8eSLuigi Rizzo 	struct oce_wq *wq;
25912f345d8eSLuigi Rizzo 	struct oce_eq *eq;
25922f345d8eSLuigi Rizzo 
25932f345d8eSLuigi Rizzo 	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
25942f345d8eSLuigi Rizzo 
2595c2625e6eSJosh Paetzel 	oce_tx_compl_clean(sc);
25962f345d8eSLuigi Rizzo 
25972f345d8eSLuigi Rizzo 	/* Stop intrs and finish any bottom halves pending */
25982f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
25992f345d8eSLuigi Rizzo 
2600cdaba892SXin LI 	/* Since taskqueue_drain takes a Gaint Lock, We should not acquire
2601beb0f7e7SJosh Paetzel 	   any other lock. So unlock device lock and require after
2602beb0f7e7SJosh Paetzel 	   completing taskqueue_drain.
2603beb0f7e7SJosh Paetzel 	*/
2604beb0f7e7SJosh Paetzel 	UNLOCK(&sc->dev_lock);
26052f345d8eSLuigi Rizzo 	for (i = 0; i < sc->intr_count; i++) {
26062f345d8eSLuigi Rizzo 		if (sc->intrs[i].tq != NULL) {
26072f345d8eSLuigi Rizzo 			taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
26082f345d8eSLuigi Rizzo 		}
26092f345d8eSLuigi Rizzo 	}
2610beb0f7e7SJosh Paetzel 	LOCK(&sc->dev_lock);
26112f345d8eSLuigi Rizzo 
26122f345d8eSLuigi Rizzo 	/* Delete RX queue in card with flush param */
26132f345d8eSLuigi Rizzo 	oce_stop_rx(sc);
26142f345d8eSLuigi Rizzo 
26152f345d8eSLuigi Rizzo 	/* Invalidate any pending cq and eq entries*/
26162f345d8eSLuigi Rizzo 	for_all_evnt_queues(sc, eq, i)
26172f345d8eSLuigi Rizzo 		oce_drain_eq(eq);
26182f345d8eSLuigi Rizzo 	for_all_rq_queues(sc, rq, i)
26192f345d8eSLuigi Rizzo 		oce_drain_rq_cq(rq);
26202f345d8eSLuigi Rizzo 	for_all_wq_queues(sc, wq, i)
26212f345d8eSLuigi Rizzo 		oce_drain_wq_cq(wq);
26222f345d8eSLuigi Rizzo 
26232f345d8eSLuigi Rizzo 	/* But still we need to get MCC aync events.
26242f345d8eSLuigi Rizzo 	   So enable intrs and also arm first EQ
26252f345d8eSLuigi Rizzo 	*/
26262f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
26272f345d8eSLuigi Rizzo 	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
26282f345d8eSLuigi Rizzo 
26292f345d8eSLuigi Rizzo 	DELAY(10);
26302f345d8eSLuigi Rizzo }
26312f345d8eSLuigi Rizzo 
26322f345d8eSLuigi Rizzo 
26332f345d8eSLuigi Rizzo static void
26342f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc)
26352f345d8eSLuigi Rizzo {
26362f345d8eSLuigi Rizzo 	struct oce_eq *eq;
26372f345d8eSLuigi Rizzo 	struct oce_rq *rq;
26382f345d8eSLuigi Rizzo 	struct oce_wq *wq;
26392f345d8eSLuigi Rizzo 	int i, rc = 0;
26402f345d8eSLuigi Rizzo 
26412f345d8eSLuigi Rizzo 	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
26422f345d8eSLuigi Rizzo 
26432f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
26442f345d8eSLuigi Rizzo 
26452f345d8eSLuigi Rizzo 	oce_start_rx(sc);
26462f345d8eSLuigi Rizzo 
26472f345d8eSLuigi Rizzo 	for_all_rq_queues(sc, rq, i) {
26482f345d8eSLuigi Rizzo 		rc = oce_start_rq(rq);
26492f345d8eSLuigi Rizzo 		if (rc)
26502f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Unable to start RX\n");
26512f345d8eSLuigi Rizzo 	}
26522f345d8eSLuigi Rizzo 
26532f345d8eSLuigi Rizzo 	for_all_wq_queues(sc, wq, i) {
26542f345d8eSLuigi Rizzo 		rc = oce_start_wq(wq);
26552f345d8eSLuigi Rizzo 		if (rc)
26562f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Unable to start TX\n");
26572f345d8eSLuigi Rizzo 	}
26582f345d8eSLuigi Rizzo 
26592f345d8eSLuigi Rizzo 
26602f345d8eSLuigi Rizzo 	for_all_evnt_queues(sc, eq, i)
26612f345d8eSLuigi Rizzo 		oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
26622f345d8eSLuigi Rizzo 
26632f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
26642f345d8eSLuigi Rizzo 
26652f345d8eSLuigi Rizzo }
26662f345d8eSLuigi Rizzo 
26679bd3250aSLuigi Rizzo static void
26689bd3250aSLuigi Rizzo process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
26692f345d8eSLuigi Rizzo {
26709bd3250aSLuigi Rizzo 	/* Update Link status */
26712f345d8eSLuigi Rizzo 	if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
26722f345d8eSLuigi Rizzo 	     ASYNC_EVENT_LINK_UP) {
26732f345d8eSLuigi Rizzo 		sc->link_status = ASYNC_EVENT_LINK_UP;
26742f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_UP);
26752f345d8eSLuigi Rizzo 	} else {
26762f345d8eSLuigi Rizzo 		sc->link_status = ASYNC_EVENT_LINK_DOWN;
26772f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
26782f345d8eSLuigi Rizzo 	}
26799bd3250aSLuigi Rizzo }
26809bd3250aSLuigi Rizzo 
26819bd3250aSLuigi Rizzo 
2682c2625e6eSJosh Paetzel static void oce_async_grp5_osbmc_process(POCE_SOFTC sc,
2683c2625e6eSJosh Paetzel 					 struct oce_async_evt_grp5_os2bmc *evt)
2684c2625e6eSJosh Paetzel {
2685c2625e6eSJosh Paetzel 	DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc));
2686c2625e6eSJosh Paetzel 	if (evt->u.s.mgmt_enable)
2687c2625e6eSJosh Paetzel 		sc->flags |= OCE_FLAGS_OS2BMC;
2688c2625e6eSJosh Paetzel 	else
2689c2625e6eSJosh Paetzel 		return;
2690c2625e6eSJosh Paetzel 
2691c2625e6eSJosh Paetzel 	sc->bmc_filt_mask = evt->u.s.arp_filter;
2692c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1);
2693c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2);
2694c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3);
2695c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4);
2696c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5);
2697c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6);
2698c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7);
2699c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8);
2700c2625e6eSJosh Paetzel }
2701c2625e6eSJosh Paetzel 
2702c2625e6eSJosh Paetzel 
2703c2625e6eSJosh Paetzel static void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe)
2704c2625e6eSJosh Paetzel {
2705c2625e6eSJosh Paetzel 	struct oce_async_event_grp5_pvid_state *gcqe;
2706c2625e6eSJosh Paetzel 	struct oce_async_evt_grp5_os2bmc *bmccqe;
2707c2625e6eSJosh Paetzel 
2708c2625e6eSJosh Paetzel 	switch (cqe->u0.s.async_type) {
2709c2625e6eSJosh Paetzel 	case ASYNC_EVENT_PVID_STATE:
2710c2625e6eSJosh Paetzel 		/* GRP5 PVID */
2711c2625e6eSJosh Paetzel 		gcqe = (struct oce_async_event_grp5_pvid_state *)cqe;
2712c2625e6eSJosh Paetzel 		if (gcqe->enabled)
2713c2625e6eSJosh Paetzel 			sc->pvid = gcqe->tag & VLAN_VID_MASK;
2714c2625e6eSJosh Paetzel 		else
2715c2625e6eSJosh Paetzel 			sc->pvid = 0;
2716c2625e6eSJosh Paetzel 		break;
2717c2625e6eSJosh Paetzel 	case ASYNC_EVENT_OS2BMC:
2718c2625e6eSJosh Paetzel 		bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe;
2719c2625e6eSJosh Paetzel 		oce_async_grp5_osbmc_process(sc, bmccqe);
2720c2625e6eSJosh Paetzel 		break;
2721c2625e6eSJosh Paetzel 	default:
2722c2625e6eSJosh Paetzel 		break;
2723c2625e6eSJosh Paetzel 	}
2724c2625e6eSJosh Paetzel }
2725c2625e6eSJosh Paetzel 
27269bd3250aSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */
27279bd3250aSLuigi Rizzo uint16_t
27289bd3250aSLuigi Rizzo oce_mq_handler(void *arg)
27299bd3250aSLuigi Rizzo {
27309bd3250aSLuigi Rizzo 	struct oce_mq *mq = (struct oce_mq *)arg;
27319bd3250aSLuigi Rizzo 	POCE_SOFTC sc = mq->parent;
27329bd3250aSLuigi Rizzo 	struct oce_cq *cq = mq->cq;
27339bd3250aSLuigi Rizzo 	int num_cqes = 0, evt_type = 0, optype = 0;
27349bd3250aSLuigi Rizzo 	struct oce_mq_cqe *cqe;
27359bd3250aSLuigi Rizzo 	struct oce_async_cqe_link_state *acqe;
2736cdaba892SXin LI 	struct oce_async_event_qnq *dbgcqe;
27379bd3250aSLuigi Rizzo 
27389bd3250aSLuigi Rizzo 
27399bd3250aSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
27409bd3250aSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
27419bd3250aSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
27429bd3250aSLuigi Rizzo 
27439bd3250aSLuigi Rizzo 	while (cqe->u0.dw[3]) {
27449bd3250aSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
27459bd3250aSLuigi Rizzo 		if (cqe->u0.s.async_event) {
27469bd3250aSLuigi Rizzo 			evt_type = cqe->u0.s.event_type;
27479bd3250aSLuigi Rizzo 			optype = cqe->u0.s.async_type;
27489bd3250aSLuigi Rizzo 			if (evt_type  == ASYNC_EVENT_CODE_LINK_STATE) {
27499bd3250aSLuigi Rizzo 				/* Link status evt */
27509bd3250aSLuigi Rizzo 				acqe = (struct oce_async_cqe_link_state *)cqe;
27519bd3250aSLuigi Rizzo 				process_link_state(sc, acqe);
2752c2625e6eSJosh Paetzel 			} else if (evt_type == ASYNC_EVENT_GRP5) {
2753c2625e6eSJosh Paetzel 				oce_process_grp5_events(sc, cqe);
2754c2625e6eSJosh Paetzel 			} else if (evt_type == ASYNC_EVENT_CODE_DEBUG &&
2755cdaba892SXin LI 					optype == ASYNC_EVENT_DEBUG_QNQ) {
2756c2625e6eSJosh Paetzel 				dbgcqe =  (struct oce_async_event_qnq *)cqe;
2757cdaba892SXin LI 				if(dbgcqe->valid)
2758cdaba892SXin LI 					sc->qnqid = dbgcqe->vlan_tag;
2759cdaba892SXin LI 				sc->qnq_debug_event = TRUE;
2760cdaba892SXin LI 			}
27612f345d8eSLuigi Rizzo 		}
27622f345d8eSLuigi Rizzo 		cqe->u0.dw[3] = 0;
27632f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
27642f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
27652f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
27662f345d8eSLuigi Rizzo 		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
27672f345d8eSLuigi Rizzo 		num_cqes++;
27682f345d8eSLuigi Rizzo 	}
27692f345d8eSLuigi Rizzo 
27702f345d8eSLuigi Rizzo 	if (num_cqes)
27712f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
27722f345d8eSLuigi Rizzo 
27732f345d8eSLuigi Rizzo 	return 0;
27742f345d8eSLuigi Rizzo }
27752f345d8eSLuigi Rizzo 
27762f345d8eSLuigi Rizzo 
27772f345d8eSLuigi Rizzo static void
27782f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc)
27792f345d8eSLuigi Rizzo {
27802f345d8eSLuigi Rizzo 	/* Check if it is FLEX machine. Is so dont use RSS */
27812f345d8eSLuigi Rizzo 	if ((sc->function_mode & FNM_FLEX10_MODE) ||
27829bd3250aSLuigi Rizzo 	    (sc->function_mode & FNM_UMC_MODE)    ||
27839bd3250aSLuigi Rizzo 	    (sc->function_mode & FNM_VNIC_MODE)	  ||
2784291a1934SXin LI 	    (!is_rss_enabled(sc))		  ||
2785a4f734b4SXin LI 	    IS_BE2(sc)) {
27862f345d8eSLuigi Rizzo 		sc->nrqs = 1;
27872f345d8eSLuigi Rizzo 		sc->nwqs = 1;
27885fbb6830SXin LI 	} else {
27895fbb6830SXin LI 		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
27905fbb6830SXin LI 		sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs);
27912f345d8eSLuigi Rizzo 	}
2792a4f734b4SXin LI 
2793a4f734b4SXin LI 	if (IS_BE2(sc) && is_rss_enabled(sc))
2794a4f734b4SXin LI 		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
27952f345d8eSLuigi Rizzo }
27962f345d8eSLuigi Rizzo 
27972f345d8eSLuigi Rizzo 
27982f345d8eSLuigi Rizzo static void
27992f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc)
28002f345d8eSLuigi Rizzo {
2801291a1934SXin LI 	if (is_rss_enabled(sc)) {
28022f345d8eSLuigi Rizzo 		sc->nrqs = sc->intr_count + 1;
28032f345d8eSLuigi Rizzo 		sc->nwqs = sc->intr_count;
28042f345d8eSLuigi Rizzo 	} else {
28052f345d8eSLuigi Rizzo 		sc->nrqs = 1;
28062f345d8eSLuigi Rizzo 		sc->nwqs = 1;
28072f345d8eSLuigi Rizzo 	}
2808a4f734b4SXin LI 
2809a4f734b4SXin LI 	if (IS_BE2(sc))
2810a4f734b4SXin LI 		sc->nwqs = 1;
28112f345d8eSLuigi Rizzo }
28122f345d8eSLuigi Rizzo 
2813cdaba892SXin LI static int
2814cdaba892SXin LI oce_check_ipv6_ext_hdr(struct mbuf *m)
2815cdaba892SXin LI {
2816cdaba892SXin LI 	struct ether_header *eh = mtod(m, struct ether_header *);
2817cdaba892SXin LI 	caddr_t m_datatemp = m->m_data;
2818cdaba892SXin LI 
2819cdaba892SXin LI 	if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2820cdaba892SXin LI 		m->m_data += sizeof(struct ether_header);
2821cdaba892SXin LI 		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2822cdaba892SXin LI 
2823cdaba892SXin LI 		if((ip6->ip6_nxt != IPPROTO_TCP) && \
2824cdaba892SXin LI 				(ip6->ip6_nxt != IPPROTO_UDP)){
2825cdaba892SXin LI 			struct ip6_ext *ip6e = NULL;
2826cdaba892SXin LI 			m->m_data += sizeof(struct ip6_hdr);
2827cdaba892SXin LI 
2828cdaba892SXin LI 			ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *);
2829cdaba892SXin LI 			if(ip6e->ip6e_len == 0xff) {
2830cdaba892SXin LI 				m->m_data = m_datatemp;
2831cdaba892SXin LI 				return TRUE;
2832cdaba892SXin LI 			}
2833cdaba892SXin LI 		}
2834cdaba892SXin LI 		m->m_data = m_datatemp;
2835cdaba892SXin LI 	}
2836cdaba892SXin LI 	return FALSE;
2837cdaba892SXin LI }
2838cdaba892SXin LI 
2839cdaba892SXin LI static int
2840cdaba892SXin LI is_be3_a1(POCE_SOFTC sc)
2841cdaba892SXin LI {
2842cdaba892SXin LI 	if((sc->flags & OCE_FLAGS_BE3)  && ((sc->asic_revision & 0xFF) < 2)) {
2843cdaba892SXin LI 		return TRUE;
2844cdaba892SXin LI 	}
2845cdaba892SXin LI 	return FALSE;
2846cdaba892SXin LI }
2847cdaba892SXin LI 
2848cdaba892SXin LI static struct mbuf *
2849cdaba892SXin LI oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete)
2850cdaba892SXin LI {
2851cdaba892SXin LI 	uint16_t vlan_tag = 0;
2852cdaba892SXin LI 
2853cdaba892SXin LI 	if(!M_WRITABLE(m))
2854cdaba892SXin LI 		return NULL;
2855cdaba892SXin LI 
2856cdaba892SXin LI 	/* Embed vlan tag in the packet if it is not part of it */
2857cdaba892SXin LI 	if(m->m_flags & M_VLANTAG) {
2858cdaba892SXin LI 		vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
2859cdaba892SXin LI 		m->m_flags &= ~M_VLANTAG;
2860cdaba892SXin LI 	}
2861cdaba892SXin LI 
2862cdaba892SXin LI 	/* if UMC, ignore vlan tag insertion and instead insert pvid */
2863cdaba892SXin LI 	if(sc->pvid) {
2864cdaba892SXin LI 		if(!vlan_tag)
2865cdaba892SXin LI 			vlan_tag = sc->pvid;
2866c2625e6eSJosh Paetzel 		if (complete)
2867cdaba892SXin LI 			*complete = FALSE;
2868cdaba892SXin LI 	}
2869cdaba892SXin LI 
2870cdaba892SXin LI 	if(vlan_tag) {
2871cdaba892SXin LI 		m = ether_vlanencap(m, vlan_tag);
2872cdaba892SXin LI 	}
2873cdaba892SXin LI 
2874cdaba892SXin LI 	if(sc->qnqid) {
2875cdaba892SXin LI 		m = ether_vlanencap(m, sc->qnqid);
2876c2625e6eSJosh Paetzel 
2877c2625e6eSJosh Paetzel 		if (complete)
2878cdaba892SXin LI 			*complete = FALSE;
2879cdaba892SXin LI 	}
2880cdaba892SXin LI 	return m;
2881cdaba892SXin LI }
2882cdaba892SXin LI 
2883cdaba892SXin LI static int
2884cdaba892SXin LI oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m)
2885cdaba892SXin LI {
2886cdaba892SXin LI 	if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \
2887cdaba892SXin LI 			oce_check_ipv6_ext_hdr(m)) {
2888cdaba892SXin LI 		return TRUE;
2889cdaba892SXin LI 	}
2890cdaba892SXin LI 	return FALSE;
2891cdaba892SXin LI }
2892291a1934SXin LI 
2893291a1934SXin LI static void
2894291a1934SXin LI oce_get_config(POCE_SOFTC sc)
2895291a1934SXin LI {
2896291a1934SXin LI 	int rc = 0;
2897291a1934SXin LI 	uint32_t max_rss = 0;
2898291a1934SXin LI 
2899291a1934SXin LI 	if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native))
2900291a1934SXin LI 		max_rss = OCE_LEGACY_MODE_RSS;
2901291a1934SXin LI 	else
2902291a1934SXin LI 		max_rss = OCE_MAX_RSS;
2903291a1934SXin LI 
2904291a1934SXin LI 	if (!IS_BE(sc)) {
2905b41206d8SXin LI 		rc = oce_get_profile_config(sc, max_rss);
2906291a1934SXin LI 		if (rc) {
2907291a1934SXin LI 			sc->nwqs = OCE_MAX_WQ;
2908291a1934SXin LI 			sc->nrssqs = max_rss;
2909291a1934SXin LI 			sc->nrqs = sc->nrssqs + 1;
2910291a1934SXin LI 		}
2911291a1934SXin LI 	}
2912b41206d8SXin LI 	else { /* For BE3 don't rely on fw for determining the resources */
2913291a1934SXin LI 		sc->nrssqs = max_rss;
2914291a1934SXin LI 		sc->nrqs = sc->nrssqs + 1;
2915291a1934SXin LI 		sc->nwqs = OCE_MAX_WQ;
2916b41206d8SXin LI 		sc->max_vlans = MAX_VLANFILTER_SIZE;
2917291a1934SXin LI 	}
2918291a1934SXin LI }
2919c2625e6eSJosh Paetzel 
2920c2625e6eSJosh Paetzel static void
2921c2625e6eSJosh Paetzel oce_rdma_close(void)
2922c2625e6eSJosh Paetzel {
2923c2625e6eSJosh Paetzel   if (oce_rdma_if != NULL) {
2924c2625e6eSJosh Paetzel     oce_rdma_if = NULL;
2925c2625e6eSJosh Paetzel   }
2926c2625e6eSJosh Paetzel }
2927c2625e6eSJosh Paetzel 
2928c2625e6eSJosh Paetzel static void
2929c2625e6eSJosh Paetzel oce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr)
2930c2625e6eSJosh Paetzel {
2931c2625e6eSJosh Paetzel   memcpy(macaddr, sc->macaddr.mac_addr, 6);
2932c2625e6eSJosh Paetzel }
2933c2625e6eSJosh Paetzel 
2934c2625e6eSJosh Paetzel int
2935c2625e6eSJosh Paetzel oce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if)
2936c2625e6eSJosh Paetzel {
2937c2625e6eSJosh Paetzel   POCE_SOFTC sc;
2938c2625e6eSJosh Paetzel   struct oce_dev_info di;
2939c2625e6eSJosh Paetzel   int i;
2940c2625e6eSJosh Paetzel 
2941c2625e6eSJosh Paetzel   if ((rdma_info == NULL) || (rdma_if == NULL)) {
2942c2625e6eSJosh Paetzel     return -EINVAL;
2943c2625e6eSJosh Paetzel   }
2944c2625e6eSJosh Paetzel 
2945c2625e6eSJosh Paetzel   if ((rdma_info->size != OCE_RDMA_INFO_SIZE) ||
2946c2625e6eSJosh Paetzel       (rdma_if->size != OCE_RDMA_IF_SIZE)) {
2947c2625e6eSJosh Paetzel     return -ENXIO;
2948c2625e6eSJosh Paetzel   }
2949c2625e6eSJosh Paetzel 
2950c2625e6eSJosh Paetzel   rdma_info->close = oce_rdma_close;
2951c2625e6eSJosh Paetzel   rdma_info->mbox_post = oce_mbox_post;
2952c2625e6eSJosh Paetzel   rdma_info->common_req_hdr_init = mbx_common_req_hdr_init;
2953c2625e6eSJosh Paetzel   rdma_info->get_mac_addr = oce_get_mac_addr;
2954c2625e6eSJosh Paetzel 
2955c2625e6eSJosh Paetzel   oce_rdma_if = rdma_if;
2956c2625e6eSJosh Paetzel 
2957c2625e6eSJosh Paetzel   sc = softc_head;
2958c2625e6eSJosh Paetzel   while (sc != NULL) {
2959c2625e6eSJosh Paetzel     if (oce_rdma_if->announce != NULL) {
2960c2625e6eSJosh Paetzel       memset(&di, 0, sizeof(di));
2961c2625e6eSJosh Paetzel       di.dev = sc->dev;
2962c2625e6eSJosh Paetzel       di.softc = sc;
2963c2625e6eSJosh Paetzel       di.ifp = sc->ifp;
2964c2625e6eSJosh Paetzel       di.db_bhandle = sc->db_bhandle;
2965c2625e6eSJosh Paetzel       di.db_btag = sc->db_btag;
2966c2625e6eSJosh Paetzel       di.db_page_size = 4096;
2967c2625e6eSJosh Paetzel       if (sc->flags & OCE_FLAGS_USING_MSIX) {
2968c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_MSIX;
2969c2625e6eSJosh Paetzel       } else if (sc->flags & OCE_FLAGS_USING_MSI) {
2970c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_MSI;
2971c2625e6eSJosh Paetzel       } else {
2972c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_INTX;
2973c2625e6eSJosh Paetzel       }
2974c2625e6eSJosh Paetzel       di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk
2975c2625e6eSJosh Paetzel       if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) {
2976c2625e6eSJosh Paetzel         di.msix.num_vectors = sc->intr_count + sc->roce_intr_count;
2977c2625e6eSJosh Paetzel         di.msix.start_vector = sc->intr_count;
2978c2625e6eSJosh Paetzel         for (i=0; i<di.msix.num_vectors; i++) {
2979c2625e6eSJosh Paetzel           di.msix.vector_list[i] = sc->intrs[i].vector;
2980c2625e6eSJosh Paetzel         }
2981c2625e6eSJosh Paetzel       } else {
2982c2625e6eSJosh Paetzel       }
2983c2625e6eSJosh Paetzel       memcpy(di.mac_addr, sc->macaddr.mac_addr, 6);
2984c2625e6eSJosh Paetzel       di.vendor_id = pci_get_vendor(sc->dev);
2985c2625e6eSJosh Paetzel       di.dev_id = pci_get_device(sc->dev);
2986c2625e6eSJosh Paetzel 
2987c2625e6eSJosh Paetzel       if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
2988c2625e6eSJosh Paetzel           di.flags  |= OCE_RDMA_INFO_RDMA_SUPPORTED;
2989c2625e6eSJosh Paetzel       }
2990c2625e6eSJosh Paetzel 
2991c2625e6eSJosh Paetzel       rdma_if->announce(&di);
2992c2625e6eSJosh Paetzel       sc = sc->next;
2993c2625e6eSJosh Paetzel     }
2994c2625e6eSJosh Paetzel   }
2995c2625e6eSJosh Paetzel 
2996c2625e6eSJosh Paetzel   return 0;
2997c2625e6eSJosh Paetzel }
2998c2625e6eSJosh Paetzel 
2999c2625e6eSJosh Paetzel static void
3000c2625e6eSJosh Paetzel oce_read_env_variables( POCE_SOFTC sc )
3001c2625e6eSJosh Paetzel {
3002c2625e6eSJosh Paetzel 	char *value = NULL;
3003c2625e6eSJosh Paetzel 	int rc = 0;
3004c2625e6eSJosh Paetzel 
3005c2625e6eSJosh Paetzel         /* read if user wants to enable hwlro or swlro */
3006c2625e6eSJosh Paetzel         //value = getenv("oce_enable_hwlro");
3007c2625e6eSJosh Paetzel         if(value && IS_SH(sc)) {
3008c2625e6eSJosh Paetzel                 sc->enable_hwlro = strtol(value, NULL, 10);
3009c2625e6eSJosh Paetzel                 if(sc->enable_hwlro) {
3010c2625e6eSJosh Paetzel                         rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL);
3011c2625e6eSJosh Paetzel                         if(rc) {
3012c2625e6eSJosh Paetzel                                 device_printf(sc->dev, "no hardware lro support\n");
3013c2625e6eSJosh Paetzel                 		device_printf(sc->dev, "software lro enabled\n");
3014c2625e6eSJosh Paetzel                                 sc->enable_hwlro = 0;
3015c2625e6eSJosh Paetzel                         }else {
3016c2625e6eSJosh Paetzel                                 device_printf(sc->dev, "hardware lro enabled\n");
3017c2625e6eSJosh Paetzel 				oce_max_rsp_handled = 32;
3018c2625e6eSJosh Paetzel                         }
3019c2625e6eSJosh Paetzel                 }else {
3020c2625e6eSJosh Paetzel                         device_printf(sc->dev, "software lro enabled\n");
3021c2625e6eSJosh Paetzel                 }
3022c2625e6eSJosh Paetzel         }else {
3023c2625e6eSJosh Paetzel                 sc->enable_hwlro = 0;
3024c2625e6eSJosh Paetzel         }
3025c2625e6eSJosh Paetzel 
3026c2625e6eSJosh Paetzel         /* read mbuf size */
3027c2625e6eSJosh Paetzel         //value = getenv("oce_rq_buf_size");
3028c2625e6eSJosh Paetzel         if(value && IS_SH(sc)) {
3029c2625e6eSJosh Paetzel                 oce_rq_buf_size = strtol(value, NULL, 10);
3030c2625e6eSJosh Paetzel                 switch(oce_rq_buf_size) {
3031c2625e6eSJosh Paetzel                 case 2048:
3032c2625e6eSJosh Paetzel                 case 4096:
3033c2625e6eSJosh Paetzel                 case 9216:
3034c2625e6eSJosh Paetzel                 case 16384:
3035c2625e6eSJosh Paetzel                         break;
3036c2625e6eSJosh Paetzel 
3037c2625e6eSJosh Paetzel                 default:
3038c2625e6eSJosh Paetzel                         device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n");
3039c2625e6eSJosh Paetzel                         oce_rq_buf_size = 2048;
3040c2625e6eSJosh Paetzel                 }
3041c2625e6eSJosh Paetzel         }
3042c2625e6eSJosh Paetzel 
3043c2625e6eSJosh Paetzel 	return;
3044c2625e6eSJosh Paetzel }
3045