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