xref: /freebsd/sys/dev/oce/oce_if.c (revision aa3860851b9f6a6002d135b1cac7736e0995eedc)
12f345d8eSLuigi Rizzo /*-
27282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni  *
4291a1934SXin LI  * Copyright (C) 2013 Emulex
52f345d8eSLuigi Rizzo  * All rights reserved.
62f345d8eSLuigi Rizzo  *
72f345d8eSLuigi Rizzo  * Redistribution and use in source and binary forms, with or without
82f345d8eSLuigi Rizzo  * modification, are permitted provided that the following conditions are met:
92f345d8eSLuigi Rizzo  *
102f345d8eSLuigi Rizzo  * 1. Redistributions of source code must retain the above copyright notice,
112f345d8eSLuigi Rizzo  *    this list of conditions and the following disclaimer.
122f345d8eSLuigi Rizzo  *
132f345d8eSLuigi Rizzo  * 2. Redistributions in binary form must reproduce the above copyright
142f345d8eSLuigi Rizzo  *    notice, this list of conditions and the following disclaimer in the
152f345d8eSLuigi Rizzo  *    documentation and/or other materials provided with the distribution.
162f345d8eSLuigi Rizzo  *
172f345d8eSLuigi Rizzo  * 3. Neither the name of the Emulex Corporation nor the names of its
182f345d8eSLuigi Rizzo  *    contributors may be used to endorse or promote products derived from
192f345d8eSLuigi Rizzo  *    this software without specific prior written permission.
202f345d8eSLuigi Rizzo  *
212f345d8eSLuigi Rizzo  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
222f345d8eSLuigi Rizzo  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232f345d8eSLuigi Rizzo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242f345d8eSLuigi Rizzo  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
252f345d8eSLuigi Rizzo  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
262f345d8eSLuigi Rizzo  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
272f345d8eSLuigi Rizzo  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
282f345d8eSLuigi Rizzo  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
292f345d8eSLuigi Rizzo  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
302f345d8eSLuigi Rizzo  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
312f345d8eSLuigi Rizzo  * POSSIBILITY OF SUCH DAMAGE.
322f345d8eSLuigi Rizzo  *
332f345d8eSLuigi Rizzo  * Contact Information:
342f345d8eSLuigi Rizzo  * freebsd-drivers@emulex.com
352f345d8eSLuigi Rizzo  *
362f345d8eSLuigi Rizzo  * Emulex
372f345d8eSLuigi Rizzo  * 3333 Susan Street
382f345d8eSLuigi Rizzo  * Costa Mesa, CA 92626
392f345d8eSLuigi Rizzo  */
402f345d8eSLuigi Rizzo 
412f345d8eSLuigi Rizzo 
42ad512958SBjoern A. Zeeb #include "opt_inet6.h"
43ad512958SBjoern A. Zeeb #include "opt_inet.h"
44ad512958SBjoern A. Zeeb 
452f345d8eSLuigi Rizzo #include "oce_if.h"
46c2625e6eSJosh Paetzel #include "oce_user.h"
47c2625e6eSJosh Paetzel 
48c2625e6eSJosh Paetzel #define is_tso_pkt(m) (m->m_pkthdr.csum_flags & CSUM_TSO)
492f345d8eSLuigi Rizzo 
505fbb6830SXin LI /* UE Status Low CSR */
515fbb6830SXin LI static char *ue_status_low_desc[] = {
525fbb6830SXin LI         "CEV",
535fbb6830SXin LI         "CTX",
545fbb6830SXin LI         "DBUF",
555fbb6830SXin LI         "ERX",
565fbb6830SXin LI         "Host",
575fbb6830SXin LI         "MPU",
585fbb6830SXin LI         "NDMA",
595fbb6830SXin LI         "PTC ",
605fbb6830SXin LI         "RDMA ",
615fbb6830SXin LI         "RXF ",
625fbb6830SXin LI         "RXIPS ",
635fbb6830SXin LI         "RXULP0 ",
645fbb6830SXin LI         "RXULP1 ",
655fbb6830SXin LI         "RXULP2 ",
665fbb6830SXin LI         "TIM ",
675fbb6830SXin LI         "TPOST ",
685fbb6830SXin LI         "TPRE ",
695fbb6830SXin LI         "TXIPS ",
705fbb6830SXin LI         "TXULP0 ",
715fbb6830SXin LI         "TXULP1 ",
725fbb6830SXin LI         "UC ",
735fbb6830SXin LI         "WDMA ",
745fbb6830SXin LI         "TXULP2 ",
755fbb6830SXin LI         "HOST1 ",
765fbb6830SXin LI         "P0_OB_LINK ",
775fbb6830SXin LI         "P1_OB_LINK ",
785fbb6830SXin LI         "HOST_GPIO ",
795fbb6830SXin LI         "MBOX ",
805fbb6830SXin LI         "AXGMAC0",
815fbb6830SXin LI         "AXGMAC1",
825fbb6830SXin LI         "JTAG",
835fbb6830SXin LI         "MPU_INTPEND"
845fbb6830SXin LI };
855fbb6830SXin LI 
865fbb6830SXin LI /* UE Status High CSR */
875fbb6830SXin LI static char *ue_status_hi_desc[] = {
885fbb6830SXin LI         "LPCMEMHOST",
895fbb6830SXin LI         "MGMT_MAC",
905fbb6830SXin LI         "PCS0ONLINE",
915fbb6830SXin LI         "MPU_IRAM",
925fbb6830SXin LI         "PCS1ONLINE",
935fbb6830SXin LI         "PCTL0",
945fbb6830SXin LI         "PCTL1",
955fbb6830SXin LI         "PMEM",
965fbb6830SXin LI         "RR",
975fbb6830SXin LI         "TXPB",
985fbb6830SXin LI         "RXPP",
995fbb6830SXin LI         "XAUI",
1005fbb6830SXin LI         "TXP",
1015fbb6830SXin LI         "ARM",
1025fbb6830SXin LI         "IPC",
1035fbb6830SXin LI         "HOST2",
1045fbb6830SXin LI         "HOST3",
1055fbb6830SXin LI         "HOST4",
1065fbb6830SXin LI         "HOST5",
1075fbb6830SXin LI         "HOST6",
1085fbb6830SXin LI         "HOST7",
1095fbb6830SXin LI         "HOST8",
1105fbb6830SXin LI         "HOST9",
1115fbb6830SXin LI         "NETC",
1125fbb6830SXin LI         "Unknown",
1135fbb6830SXin LI         "Unknown",
1145fbb6830SXin LI         "Unknown",
1155fbb6830SXin LI         "Unknown",
1165fbb6830SXin LI         "Unknown",
1175fbb6830SXin LI         "Unknown",
1185fbb6830SXin LI         "Unknown",
1195fbb6830SXin LI         "Unknown"
1205fbb6830SXin LI };
1215fbb6830SXin LI 
122c2625e6eSJosh Paetzel struct oce_common_cqe_info{
123c2625e6eSJosh Paetzel         uint8_t vtp:1;
124c2625e6eSJosh Paetzel         uint8_t l4_cksum_pass:1;
125c2625e6eSJosh Paetzel         uint8_t ip_cksum_pass:1;
126c2625e6eSJosh Paetzel         uint8_t ipv6_frame:1;
127c2625e6eSJosh Paetzel         uint8_t qnq:1;
128c2625e6eSJosh Paetzel         uint8_t rsvd:3;
129c2625e6eSJosh Paetzel         uint8_t num_frags;
130c2625e6eSJosh Paetzel         uint16_t pkt_size;
131c2625e6eSJosh Paetzel         uint16_t vtag;
132c2625e6eSJosh Paetzel };
133c2625e6eSJosh Paetzel 
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);
13967fd4c9dSJustin Hibbits static int  oce_ioctl(if_t ifp, u_long command, caddr_t data);
1402f345d8eSLuigi Rizzo static void oce_init(void *xsc);
14167fd4c9dSJustin Hibbits static int  oce_multiq_start(if_t ifp, struct mbuf *m);
14267fd4c9dSJustin Hibbits static void oce_multiq_flush(if_t 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 */
15267fd4c9dSJustin Hibbits static void oce_media_status(if_t ifp, struct ifmediareq *req);
15367fd4c9dSJustin Hibbits static int  oce_media_change(if_t 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);
158c2625e6eSJosh Paetzel static void oce_process_tx_completion(struct oce_wq *wq);
15967fd4c9dSJustin Hibbits static int  oce_multiq_transmit(if_t 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);
165c2625e6eSJosh Paetzel static void oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe);
166c2625e6eSJosh Paetzel static void oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq);
167c2625e6eSJosh Paetzel static uint16_t oce_rq_handler_lro(void *arg);
168c2625e6eSJosh Paetzel static void oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2);
169c2625e6eSJosh Paetzel static void oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2);
170c2625e6eSJosh 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 */
173*aa386085SZhenlei Huang static void oce_attach_ifp(POCE_SOFTC sc);
17467fd4c9dSJustin Hibbits static void oce_add_vlan(void *arg, if_t ifp, uint16_t vtag);
17567fd4c9dSJustin Hibbits static void oce_del_vlan(void *arg, if_t 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);
17867fd4c9dSJustin Hibbits static int  oce_handle_passthrough(if_t 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);
189c2625e6eSJosh Paetzel static void oce_read_env_variables(POCE_SOFTC sc);
190c2625e6eSJosh Paetzel 
1919bd3250aSLuigi Rizzo /* IP specific */
1929bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
1939bd3250aSLuigi Rizzo static int  oce_init_lro(POCE_SOFTC sc);
1949bd3250aSLuigi Rizzo static struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp);
1959bd3250aSLuigi Rizzo #endif
1962f345d8eSLuigi Rizzo 
1972f345d8eSLuigi Rizzo static device_method_t oce_dispatch[] = {
1982f345d8eSLuigi Rizzo 	DEVMETHOD(device_probe, oce_probe),
1992f345d8eSLuigi Rizzo 	DEVMETHOD(device_attach, oce_attach),
2002f345d8eSLuigi Rizzo 	DEVMETHOD(device_detach, oce_detach),
2012f345d8eSLuigi Rizzo 	DEVMETHOD(device_shutdown, oce_shutdown),
20261bfd867SSofian Brabez 
20361bfd867SSofian Brabez 	DEVMETHOD_END
2042f345d8eSLuigi Rizzo };
2052f345d8eSLuigi Rizzo 
2062f345d8eSLuigi Rizzo static driver_t oce_driver = {
2072f345d8eSLuigi Rizzo 	"oce",
2082f345d8eSLuigi Rizzo 	oce_dispatch,
2092f345d8eSLuigi Rizzo 	sizeof(OCE_SOFTC)
2102f345d8eSLuigi Rizzo };
2112f345d8eSLuigi Rizzo 
2122f345d8eSLuigi Rizzo /* global vars */
2132f345d8eSLuigi Rizzo const char component_revision[32] = {"///" COMPONENT_REVISION "///"};
2142f345d8eSLuigi Rizzo 
2152f345d8eSLuigi Rizzo /* Module capabilites and parameters */
2162f345d8eSLuigi Rizzo uint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED;
2172f345d8eSLuigi Rizzo uint32_t oce_enable_rss = OCE_MODCAP_RSS;
218c2625e6eSJosh Paetzel uint32_t oce_rq_buf_size = 2048;
2192f345d8eSLuigi Rizzo 
2202f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled);
2212f345d8eSLuigi Rizzo TUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss);
2222f345d8eSLuigi Rizzo 
2232f345d8eSLuigi Rizzo /* Supported devices table */
2242f345d8eSLuigi Rizzo static uint32_t supportedDevices[] =  {
2252f345d8eSLuigi Rizzo 	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2,
2262f345d8eSLuigi Rizzo 	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3,
2272f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3,
2282f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201,
2292f345d8eSLuigi Rizzo 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF,
230291a1934SXin LI 	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH
2312f345d8eSLuigi Rizzo };
2322f345d8eSLuigi Rizzo 
2334e75e496SJohn Baldwin DRIVER_MODULE(oce, pci, oce_driver, 0, 0);
2340dc34160SWarner Losh MODULE_PNP_INFO("W32:vendor/device", pci, oce, supportedDevices,
2350dc34160SWarner Losh     nitems(supportedDevices));
2360dc34160SWarner Losh MODULE_DEPEND(oce, pci, 1, 1, 1);
2370dc34160SWarner Losh MODULE_DEPEND(oce, ether, 1, 1, 1);
2380dc34160SWarner Losh MODULE_VERSION(oce, 1);
2390dc34160SWarner Losh 
240c2625e6eSJosh Paetzel POCE_SOFTC softc_head = NULL;
241c2625e6eSJosh Paetzel POCE_SOFTC softc_tail = NULL;
2422f345d8eSLuigi Rizzo 
243c2625e6eSJosh Paetzel struct oce_rdma_if *oce_rdma_if = NULL;
2442f345d8eSLuigi Rizzo 
2452f345d8eSLuigi Rizzo /*****************************************************************************
2462f345d8eSLuigi Rizzo  *			Driver entry points functions                        *
2472f345d8eSLuigi Rizzo  *****************************************************************************/
2482f345d8eSLuigi Rizzo 
2492f345d8eSLuigi Rizzo static int
oce_probe(device_t dev)2502f345d8eSLuigi Rizzo oce_probe(device_t dev)
2512f345d8eSLuigi Rizzo {
2529bd3250aSLuigi Rizzo 	uint16_t vendor = 0;
2539bd3250aSLuigi Rizzo 	uint16_t device = 0;
2549bd3250aSLuigi Rizzo 	int i = 0;
2552f345d8eSLuigi Rizzo 	POCE_SOFTC sc;
2562f345d8eSLuigi Rizzo 
2572f345d8eSLuigi Rizzo 	sc = device_get_softc(dev);
2582f345d8eSLuigi Rizzo 	bzero(sc, sizeof(OCE_SOFTC));
2592f345d8eSLuigi Rizzo 	sc->dev = dev;
2602f345d8eSLuigi Rizzo 
2612f345d8eSLuigi Rizzo 	vendor = pci_get_vendor(dev);
2622f345d8eSLuigi Rizzo 	device = pci_get_device(dev);
2632f345d8eSLuigi Rizzo 
2649bd3250aSLuigi Rizzo 	for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) {
2652f345d8eSLuigi Rizzo 		if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) {
2662f345d8eSLuigi Rizzo 			if (device == (supportedDevices[i] & 0xffff)) {
267c704b87bSMark Johnston 				device_set_descf(dev,
268c704b87bSMark Johnston 				    "%s:%s", "Emulex CNA NIC function",
2692f345d8eSLuigi Rizzo 				    component_revision);
2702f345d8eSLuigi Rizzo 
2712f345d8eSLuigi Rizzo 				switch (device) {
2722f345d8eSLuigi Rizzo 				case PCI_PRODUCT_BE2:
2732f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_BE2;
2742f345d8eSLuigi Rizzo 					break;
2752f345d8eSLuigi Rizzo 				case PCI_PRODUCT_BE3:
2762f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_BE3;
2772f345d8eSLuigi Rizzo 					break;
2782f345d8eSLuigi Rizzo 				case PCI_PRODUCT_XE201:
2792f345d8eSLuigi Rizzo 				case PCI_PRODUCT_XE201_VF:
2802f345d8eSLuigi Rizzo 					sc->flags |= OCE_FLAGS_XE201;
2812f345d8eSLuigi Rizzo 					break;
282291a1934SXin LI 				case PCI_PRODUCT_SH:
283291a1934SXin LI 					sc->flags |= OCE_FLAGS_SH;
284291a1934SXin LI 					break;
2852f345d8eSLuigi Rizzo 				default:
2862f345d8eSLuigi Rizzo 					return ENXIO;
2872f345d8eSLuigi Rizzo 				}
2882f345d8eSLuigi Rizzo 				return BUS_PROBE_DEFAULT;
2892f345d8eSLuigi Rizzo 			}
2902f345d8eSLuigi Rizzo 		}
2912f345d8eSLuigi Rizzo 	}
2922f345d8eSLuigi Rizzo 
2932f345d8eSLuigi Rizzo 	return ENXIO;
2942f345d8eSLuigi Rizzo }
2952f345d8eSLuigi Rizzo 
2962f345d8eSLuigi Rizzo static int
oce_attach(device_t dev)2972f345d8eSLuigi Rizzo oce_attach(device_t dev)
2982f345d8eSLuigi Rizzo {
2992f345d8eSLuigi Rizzo 	POCE_SOFTC sc;
3002f345d8eSLuigi Rizzo 	int rc = 0;
3012f345d8eSLuigi Rizzo 
3022f345d8eSLuigi Rizzo 	sc = device_get_softc(dev);
3032f345d8eSLuigi Rizzo 
3042f345d8eSLuigi Rizzo 	rc = oce_hw_pci_alloc(sc);
3052f345d8eSLuigi Rizzo 	if (rc)
3062f345d8eSLuigi Rizzo 		return rc;
3072f345d8eSLuigi Rizzo 
3082f345d8eSLuigi Rizzo 	sc->tx_ring_size = OCE_TX_RING_SIZE;
3092f345d8eSLuigi Rizzo 	sc->rx_ring_size = OCE_RX_RING_SIZE;
310c2625e6eSJosh Paetzel 	/* receive fragment size should be multiple of 2K */
311c2625e6eSJosh Paetzel 	sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048);
3122f345d8eSLuigi Rizzo 	sc->flow_control = OCE_DEFAULT_FLOW_CONTROL;
3132f345d8eSLuigi Rizzo 	sc->promisc	 = OCE_DEFAULT_PROMISCUOUS;
3142f345d8eSLuigi Rizzo 
3152f345d8eSLuigi Rizzo 	LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock");
3162f345d8eSLuigi Rizzo 	LOCK_CREATE(&sc->dev_lock,  "Device_lock");
3172f345d8eSLuigi Rizzo 
3182f345d8eSLuigi Rizzo 	/* initialise the hardware */
3192f345d8eSLuigi Rizzo 	rc = oce_hw_init(sc);
3202f345d8eSLuigi Rizzo 	if (rc)
3212f345d8eSLuigi Rizzo 		goto pci_res_free;
3222f345d8eSLuigi Rizzo 
323c2625e6eSJosh Paetzel 	oce_read_env_variables(sc);
324c2625e6eSJosh Paetzel 
325291a1934SXin LI 	oce_get_config(sc);
326291a1934SXin LI 
3272f345d8eSLuigi Rizzo 	setup_max_queues_want(sc);
3282f345d8eSLuigi Rizzo 
3292f345d8eSLuigi Rizzo 	rc = oce_setup_intr(sc);
3302f345d8eSLuigi Rizzo 	if (rc)
3312f345d8eSLuigi Rizzo 		goto mbox_free;
3322f345d8eSLuigi Rizzo 
3332f345d8eSLuigi Rizzo 	rc = oce_queue_init_all(sc);
3342f345d8eSLuigi Rizzo 	if (rc)
3352f345d8eSLuigi Rizzo 		goto intr_free;
3362f345d8eSLuigi Rizzo 
337*aa386085SZhenlei Huang 	oce_attach_ifp(sc);
3382f345d8eSLuigi Rizzo 
339ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3402f345d8eSLuigi Rizzo 	rc = oce_init_lro(sc);
3412f345d8eSLuigi Rizzo 	if (rc)
3422f345d8eSLuigi Rizzo 		goto ifp_free;
343ad512958SBjoern A. Zeeb #endif
3442f345d8eSLuigi Rizzo 
3452f345d8eSLuigi Rizzo 	rc = oce_hw_start(sc);
3462f345d8eSLuigi Rizzo 	if (rc)
347db702c59SEitan Adler 		goto lro_free;
3482f345d8eSLuigi Rizzo 
3492f345d8eSLuigi Rizzo 	sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
3502f345d8eSLuigi Rizzo 				oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST);
3512f345d8eSLuigi Rizzo 	sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
3522f345d8eSLuigi Rizzo 				oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST);
3532f345d8eSLuigi Rizzo 
3542f345d8eSLuigi Rizzo 	rc = oce_stats_init(sc);
3552f345d8eSLuigi Rizzo 	if (rc)
3562f345d8eSLuigi Rizzo 		goto vlan_free;
3572f345d8eSLuigi Rizzo 
3582f345d8eSLuigi Rizzo 	oce_add_sysctls(sc);
3592f345d8eSLuigi Rizzo 
360c2625e6eSJosh Paetzel 	callout_init(&sc->timer, CALLOUT_MPSAFE);
3612f345d8eSLuigi Rizzo 	rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc);
3622f345d8eSLuigi Rizzo 	if (rc)
3632f345d8eSLuigi Rizzo 		goto stats_free;
3642f345d8eSLuigi Rizzo 
365c2625e6eSJosh Paetzel 	sc->next =NULL;
366c2625e6eSJosh Paetzel 	if (softc_tail != NULL) {
367c2625e6eSJosh Paetzel 	  softc_tail->next = sc;
368c2625e6eSJosh Paetzel 	} else {
369c2625e6eSJosh Paetzel 	  softc_head = sc;
370c2625e6eSJosh Paetzel 	}
371c2625e6eSJosh Paetzel 	softc_tail = sc;
372c2625e6eSJosh Paetzel 
37345913229SBrooks Davis 	gone_in_dev(dev, 15, "relatively uncommon 10GbE NIC");
37445913229SBrooks Davis 
3752f345d8eSLuigi Rizzo 	return 0;
3762f345d8eSLuigi Rizzo 
3772f345d8eSLuigi Rizzo stats_free:
3782f345d8eSLuigi Rizzo 	callout_drain(&sc->timer);
3792f345d8eSLuigi Rizzo 	oce_stats_free(sc);
3802f345d8eSLuigi Rizzo vlan_free:
3812f345d8eSLuigi Rizzo 	if (sc->vlan_attach)
3822f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
3832f345d8eSLuigi Rizzo 	if (sc->vlan_detach)
3842f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
3852f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
3862f345d8eSLuigi Rizzo lro_free:
387ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
3882f345d8eSLuigi Rizzo 	oce_free_lro(sc);
3892f345d8eSLuigi Rizzo ifp_free:
390ad512958SBjoern A. Zeeb #endif
3912f345d8eSLuigi Rizzo 	ether_ifdetach(sc->ifp);
3922f345d8eSLuigi Rizzo 	if_free(sc->ifp);
3932f345d8eSLuigi Rizzo 	oce_queue_release_all(sc);
3942f345d8eSLuigi Rizzo intr_free:
3952f345d8eSLuigi Rizzo 	oce_intr_free(sc);
3962f345d8eSLuigi Rizzo mbox_free:
3972f345d8eSLuigi Rizzo 	oce_dma_free(sc, &sc->bsmbx);
3982f345d8eSLuigi Rizzo pci_res_free:
3992f345d8eSLuigi Rizzo 	oce_hw_pci_free(sc);
4002f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->dev_lock);
4012f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->bmbx_lock);
4022f345d8eSLuigi Rizzo 	return rc;
4032f345d8eSLuigi Rizzo 
4042f345d8eSLuigi Rizzo }
4052f345d8eSLuigi Rizzo 
4062f345d8eSLuigi Rizzo static int
oce_detach(device_t dev)4072f345d8eSLuigi Rizzo oce_detach(device_t dev)
4082f345d8eSLuigi Rizzo {
4092f345d8eSLuigi Rizzo 	POCE_SOFTC sc = device_get_softc(dev);
410c2625e6eSJosh Paetzel 	POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL;
411c2625e6eSJosh Paetzel 
412c2625e6eSJosh Paetzel         poce_sc_tmp = softc_head;
413c2625e6eSJosh Paetzel         ppoce_sc_tmp1 = &softc_head;
414c2625e6eSJosh Paetzel         while (poce_sc_tmp != NULL) {
415c2625e6eSJosh Paetzel           if (poce_sc_tmp == sc) {
416c2625e6eSJosh Paetzel             *ppoce_sc_tmp1 = sc->next;
417c2625e6eSJosh Paetzel             if (sc->next == NULL) {
418c2625e6eSJosh Paetzel               softc_tail = poce_sc_tmp2;
419c2625e6eSJosh Paetzel             }
420c2625e6eSJosh Paetzel             break;
421c2625e6eSJosh Paetzel           }
422c2625e6eSJosh Paetzel           poce_sc_tmp2 = poce_sc_tmp;
423c2625e6eSJosh Paetzel           ppoce_sc_tmp1 = &poce_sc_tmp->next;
424c2625e6eSJosh Paetzel           poce_sc_tmp = poce_sc_tmp->next;
425c2625e6eSJosh Paetzel         }
4262f345d8eSLuigi Rizzo 
4272f345d8eSLuigi Rizzo 	LOCK(&sc->dev_lock);
4282f345d8eSLuigi Rizzo 	oce_if_deactivate(sc);
4292f345d8eSLuigi Rizzo 	UNLOCK(&sc->dev_lock);
4302f345d8eSLuigi Rizzo 
4312f345d8eSLuigi Rizzo 	callout_drain(&sc->timer);
4322f345d8eSLuigi Rizzo 
4332f345d8eSLuigi Rizzo 	if (sc->vlan_attach != NULL)
4342f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
4352f345d8eSLuigi Rizzo 	if (sc->vlan_detach != NULL)
4362f345d8eSLuigi Rizzo 		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
4372f345d8eSLuigi Rizzo 
4382f345d8eSLuigi Rizzo 	ether_ifdetach(sc->ifp);
4392f345d8eSLuigi Rizzo 
4402f345d8eSLuigi Rizzo 	if_free(sc->ifp);
4412f345d8eSLuigi Rizzo 
4422f345d8eSLuigi Rizzo 	oce_hw_shutdown(sc);
4432f345d8eSLuigi Rizzo 
4442f345d8eSLuigi Rizzo 	bus_generic_detach(dev);
4452f345d8eSLuigi Rizzo 
4462f345d8eSLuigi Rizzo 	return 0;
4472f345d8eSLuigi Rizzo }
4482f345d8eSLuigi Rizzo 
4492f345d8eSLuigi Rizzo static int
oce_shutdown(device_t dev)4502f345d8eSLuigi Rizzo oce_shutdown(device_t dev)
4512f345d8eSLuigi Rizzo {
4522f345d8eSLuigi Rizzo 	int rc;
4532f345d8eSLuigi Rizzo 
4542f345d8eSLuigi Rizzo 	rc = oce_detach(dev);
4552f345d8eSLuigi Rizzo 
4562f345d8eSLuigi Rizzo 	return rc;
4572f345d8eSLuigi Rizzo }
4582f345d8eSLuigi Rizzo 
4592f345d8eSLuigi Rizzo static int
oce_ioctl(if_t ifp,u_long command,caddr_t data)46067fd4c9dSJustin Hibbits oce_ioctl(if_t ifp, u_long command, caddr_t data)
4612f345d8eSLuigi Rizzo {
4622f345d8eSLuigi Rizzo 	struct ifreq *ifr = (struct ifreq *)data;
46367fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
464e0dd0fe3SXin LI 	struct ifi2creq i2c;
465e0dd0fe3SXin LI 	uint8_t	offset = 0;
4662f345d8eSLuigi Rizzo 	int rc = 0;
4672f345d8eSLuigi Rizzo 	uint32_t u;
4682f345d8eSLuigi Rizzo 
4692f345d8eSLuigi Rizzo 	switch (command) {
4702f345d8eSLuigi Rizzo 	case SIOCGIFMEDIA:
4712f345d8eSLuigi Rizzo 		rc = ifmedia_ioctl(ifp, ifr, &sc->media, command);
4722f345d8eSLuigi Rizzo 		break;
4732f345d8eSLuigi Rizzo 
4742f345d8eSLuigi Rizzo 	case SIOCSIFMTU:
4752f345d8eSLuigi Rizzo 		if (ifr->ifr_mtu > OCE_MAX_MTU)
4762f345d8eSLuigi Rizzo 			rc = EINVAL;
4772f345d8eSLuigi Rizzo 		else
47867fd4c9dSJustin Hibbits 			if_setmtu(ifp, ifr->ifr_mtu);
4792f345d8eSLuigi Rizzo 		break;
4802f345d8eSLuigi Rizzo 
4812f345d8eSLuigi Rizzo 	case SIOCSIFFLAGS:
48267fd4c9dSJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
48367fd4c9dSJustin Hibbits 			if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
48467fd4c9dSJustin Hibbits 				if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
4852f345d8eSLuigi Rizzo 				oce_init(sc);
4862f345d8eSLuigi Rizzo 			}
4872f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Interface Up\n");
4882f345d8eSLuigi Rizzo 		} else {
4892f345d8eSLuigi Rizzo 			LOCK(&sc->dev_lock);
4902f345d8eSLuigi Rizzo 
49167fd4c9dSJustin Hibbits 			if_setdrvflagbits(sc->ifp, 0,
49267fd4c9dSJustin Hibbits 			    IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
4932f345d8eSLuigi Rizzo 			oce_if_deactivate(sc);
4942f345d8eSLuigi Rizzo 
4952f345d8eSLuigi Rizzo 			UNLOCK(&sc->dev_lock);
4962f345d8eSLuigi Rizzo 
4972f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Interface Down\n");
4982f345d8eSLuigi Rizzo 		}
4992f345d8eSLuigi Rizzo 
50067fd4c9dSJustin Hibbits 		if ((if_getflags(ifp) & IFF_PROMISC) && !sc->promisc) {
5015fbb6830SXin LI 			if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1))))
5022f345d8eSLuigi Rizzo 				sc->promisc = TRUE;
50367fd4c9dSJustin Hibbits 		} else if (!(if_getflags(ifp) & IFF_PROMISC) && sc->promisc) {
5045fbb6830SXin LI 			if (!oce_rxf_set_promiscuous(sc, 0))
5052f345d8eSLuigi Rizzo 				sc->promisc = FALSE;
5062f345d8eSLuigi Rizzo 		}
5072f345d8eSLuigi Rizzo 
5082f345d8eSLuigi Rizzo 		break;
5092f345d8eSLuigi Rizzo 
5102f345d8eSLuigi Rizzo 	case SIOCADDMULTI:
5112f345d8eSLuigi Rizzo 	case SIOCDELMULTI:
5122f345d8eSLuigi Rizzo 		rc = oce_hw_update_multicast(sc);
5132f345d8eSLuigi Rizzo 		if (rc)
5142f345d8eSLuigi Rizzo 			device_printf(sc->dev,
5152f345d8eSLuigi Rizzo 				"Update multicast address failed\n");
5162f345d8eSLuigi Rizzo 		break;
5172f345d8eSLuigi Rizzo 
5182f345d8eSLuigi Rizzo 	case SIOCSIFCAP:
51967fd4c9dSJustin Hibbits 		u = ifr->ifr_reqcap ^ if_getcapenable(ifp);
5202f345d8eSLuigi Rizzo 
5212f345d8eSLuigi Rizzo 		if (u & IFCAP_TXCSUM) {
52267fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM);
52367fd4c9dSJustin Hibbits 			if_togglehwassist(ifp, (CSUM_TCP | CSUM_UDP | CSUM_IP));
5242f345d8eSLuigi Rizzo 
52567fd4c9dSJustin Hibbits 			if (IFCAP_TSO & if_getcapenable(ifp) &&
52667fd4c9dSJustin Hibbits 			    !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
527cbb9ccf7SRyan Moeller 				u &= ~IFCAP_TSO;
52867fd4c9dSJustin Hibbits 				if_setcapenablebit(ifp, 0, IFCAP_TSO);
52967fd4c9dSJustin Hibbits 				if_sethwassistbits(ifp, 0, CSUM_TSO);
5302f345d8eSLuigi Rizzo 				if_printf(ifp,
5312f345d8eSLuigi Rizzo 					 "TSO disabled due to -txcsum.\n");
5322f345d8eSLuigi Rizzo 			}
5332f345d8eSLuigi Rizzo 		}
5342f345d8eSLuigi Rizzo 
5352f345d8eSLuigi Rizzo 		if (u & IFCAP_RXCSUM)
53667fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_RXCSUM);
5372f345d8eSLuigi Rizzo 
5382f345d8eSLuigi Rizzo 		if (u & IFCAP_TSO4) {
53967fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO4);
5402f345d8eSLuigi Rizzo 
54167fd4c9dSJustin Hibbits 			if (IFCAP_TSO & if_getcapenable(ifp)) {
54267fd4c9dSJustin Hibbits 				if (IFCAP_TXCSUM & if_getcapenable(ifp))
54367fd4c9dSJustin Hibbits 					if_sethwassistbits(ifp, CSUM_TSO, 0);
5442f345d8eSLuigi Rizzo 				else {
54567fd4c9dSJustin Hibbits 					if_setcapenablebit(ifp, 0, IFCAP_TSO);
54667fd4c9dSJustin Hibbits 					if_sethwassistbits(ifp, 0, CSUM_TSO);
5472f345d8eSLuigi Rizzo 					if_printf(ifp,
5482f345d8eSLuigi Rizzo 					    "Enable txcsum first.\n");
5492f345d8eSLuigi Rizzo 					rc = EAGAIN;
5502f345d8eSLuigi Rizzo 				}
5512f345d8eSLuigi Rizzo 			} else
55267fd4c9dSJustin Hibbits 				if_sethwassistbits(ifp, 0, CSUM_TSO);
5532f345d8eSLuigi Rizzo 		}
5542f345d8eSLuigi Rizzo 
5552f345d8eSLuigi Rizzo 		if (u & IFCAP_VLAN_HWTAGGING)
55667fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
5572f345d8eSLuigi Rizzo 
5582f345d8eSLuigi Rizzo 		if (u & IFCAP_VLAN_HWFILTER) {
55967fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWFILTER);
5602f345d8eSLuigi Rizzo 			oce_vid_config(sc);
5612f345d8eSLuigi Rizzo 		}
562ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
563c2625e6eSJosh Paetzel 		if (u & IFCAP_LRO) {
56467fd4c9dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_LRO);
565c2625e6eSJosh Paetzel 			if(sc->enable_hwlro) {
56667fd4c9dSJustin Hibbits 				if(if_getcapenable(ifp) & IFCAP_LRO) {
567c2625e6eSJosh Paetzel 					rc = oce_mbox_nic_set_iface_lro_config(sc, 1);
568c2625e6eSJosh Paetzel 				}else {
569c2625e6eSJosh Paetzel 					rc = oce_mbox_nic_set_iface_lro_config(sc, 0);
570c2625e6eSJosh Paetzel 				}
571c2625e6eSJosh Paetzel 			}
572c2625e6eSJosh Paetzel 		}
573ad512958SBjoern A. Zeeb #endif
5742f345d8eSLuigi Rizzo 
5752f345d8eSLuigi Rizzo 		break;
5762f345d8eSLuigi Rizzo 
577e0dd0fe3SXin LI 	case SIOCGI2C:
578e0dd0fe3SXin LI 		rc = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
579e0dd0fe3SXin LI 		if (rc)
580e0dd0fe3SXin LI 			break;
581e0dd0fe3SXin LI 
5826e7ecc9aSMark Johnston 		if (i2c.dev_addr == PAGE_NUM_A0) {
5836e7ecc9aSMark Johnston 			offset = i2c.offset;
5846e7ecc9aSMark Johnston 		} else if (i2c.dev_addr == PAGE_NUM_A2) {
5856e7ecc9aSMark Johnston 			offset = TRANSCEIVER_A0_SIZE + i2c.offset;
5866e7ecc9aSMark Johnston 		} else {
587e0dd0fe3SXin LI 			rc = EINVAL;
588e0dd0fe3SXin LI 			break;
589e0dd0fe3SXin LI 		}
590e0dd0fe3SXin LI 
5916e7ecc9aSMark Johnston 		if (i2c.len > sizeof(i2c.data) ||
5926e7ecc9aSMark Johnston 		    i2c.len + offset > sizeof(sfp_vpd_dump_buffer)) {
593e0dd0fe3SXin LI 			rc = EINVAL;
594e0dd0fe3SXin LI 			break;
595e0dd0fe3SXin LI 		}
596e0dd0fe3SXin LI 
597e0dd0fe3SXin LI 		rc = oce_mbox_read_transrecv_data(sc, i2c.dev_addr);
598e0dd0fe3SXin LI 		if (rc) {
599e0dd0fe3SXin LI 			rc = -rc;
600e0dd0fe3SXin LI 			break;
601e0dd0fe3SXin LI 		}
602e0dd0fe3SXin LI 
603e0dd0fe3SXin LI 		memcpy(&i2c.data[0], &sfp_vpd_dump_buffer[offset], i2c.len);
604e0dd0fe3SXin LI 
605e0dd0fe3SXin LI 		rc = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c));
606e0dd0fe3SXin LI 		break;
607e0dd0fe3SXin LI 
6082f345d8eSLuigi Rizzo 	case SIOCGPRIVATE_0:
609c76ddeebSMark Johnston 		rc = priv_check(curthread, PRIV_DRIVER);
610c76ddeebSMark Johnston 		if (rc != 0)
611c76ddeebSMark Johnston 			break;
6122f345d8eSLuigi Rizzo 		rc = oce_handle_passthrough(ifp, data);
6132f345d8eSLuigi Rizzo 		break;
6142f345d8eSLuigi Rizzo 	default:
6152f345d8eSLuigi Rizzo 		rc = ether_ioctl(ifp, command, data);
6162f345d8eSLuigi Rizzo 		break;
6172f345d8eSLuigi Rizzo 	}
6182f345d8eSLuigi Rizzo 
6192f345d8eSLuigi Rizzo 	return rc;
6202f345d8eSLuigi Rizzo }
6212f345d8eSLuigi Rizzo 
6222f345d8eSLuigi Rizzo static void
oce_init(void * arg)6232f345d8eSLuigi Rizzo oce_init(void *arg)
6242f345d8eSLuigi Rizzo {
6252f345d8eSLuigi Rizzo 	POCE_SOFTC sc = arg;
6262f345d8eSLuigi Rizzo 
6272f345d8eSLuigi Rizzo 	LOCK(&sc->dev_lock);
6282f345d8eSLuigi Rizzo 
62967fd4c9dSJustin Hibbits 	if (if_getflags(sc->ifp) & IFF_UP) {
6302f345d8eSLuigi Rizzo 		oce_if_deactivate(sc);
6312f345d8eSLuigi Rizzo 		oce_if_activate(sc);
6322f345d8eSLuigi Rizzo 	}
6332f345d8eSLuigi Rizzo 
6342f345d8eSLuigi Rizzo 	UNLOCK(&sc->dev_lock);
6352f345d8eSLuigi Rizzo 
6362f345d8eSLuigi Rizzo }
6372f345d8eSLuigi Rizzo 
6382f345d8eSLuigi Rizzo static int
oce_multiq_start(if_t ifp,struct mbuf * m)63967fd4c9dSJustin Hibbits oce_multiq_start(if_t ifp, struct mbuf *m)
6402f345d8eSLuigi Rizzo {
64167fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
6422f345d8eSLuigi Rizzo 	struct oce_wq *wq = NULL;
6432f345d8eSLuigi Rizzo 	int queue_index = 0;
6442f345d8eSLuigi Rizzo 	int status = 0;
6452f345d8eSLuigi Rizzo 
646c2625e6eSJosh Paetzel 	if (!sc->link_status)
647c2625e6eSJosh Paetzel 		return ENXIO;
648c2625e6eSJosh Paetzel 
649c2529042SHans Petter Selasky 	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
6502f345d8eSLuigi Rizzo 		queue_index = m->m_pkthdr.flowid % sc->nwqs;
6512f345d8eSLuigi Rizzo 
6522f345d8eSLuigi Rizzo 	wq = sc->wq[queue_index];
6532f345d8eSLuigi Rizzo 
654291a1934SXin LI 	LOCK(&wq->tx_lock);
6552f345d8eSLuigi Rizzo 	status = oce_multiq_transmit(ifp, m, wq);
6562f345d8eSLuigi Rizzo 	UNLOCK(&wq->tx_lock);
657291a1934SXin LI 
6582f345d8eSLuigi Rizzo 	return status;
6592f345d8eSLuigi Rizzo 
6602f345d8eSLuigi Rizzo }
6612f345d8eSLuigi Rizzo 
6622f345d8eSLuigi Rizzo static void
oce_multiq_flush(if_t ifp)66367fd4c9dSJustin Hibbits oce_multiq_flush(if_t ifp)
6642f345d8eSLuigi Rizzo {
66567fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
6662f345d8eSLuigi Rizzo 	struct mbuf     *m;
6672f345d8eSLuigi Rizzo 	int i = 0;
6682f345d8eSLuigi Rizzo 
6692f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nwqs; i++) {
6702f345d8eSLuigi Rizzo 		while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
6712f345d8eSLuigi Rizzo 			m_freem(m);
6722f345d8eSLuigi Rizzo 	}
6732f345d8eSLuigi Rizzo 	if_qflush(ifp);
6742f345d8eSLuigi Rizzo }
6752f345d8eSLuigi Rizzo 
6762f345d8eSLuigi Rizzo /*****************************************************************************
6772f345d8eSLuigi Rizzo  *                   Driver interrupt routines functions                     *
6782f345d8eSLuigi Rizzo  *****************************************************************************/
6792f345d8eSLuigi Rizzo 
6802f345d8eSLuigi Rizzo static void
oce_intr(void * arg,int pending)6812f345d8eSLuigi Rizzo oce_intr(void *arg, int pending)
6822f345d8eSLuigi Rizzo {
6832f345d8eSLuigi Rizzo 
6842f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
6852f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ii->sc;
6862f345d8eSLuigi Rizzo 	struct oce_eq *eq = ii->eq;
6872f345d8eSLuigi Rizzo 	struct oce_eqe *eqe;
6882f345d8eSLuigi Rizzo 	struct oce_cq *cq = NULL;
6892f345d8eSLuigi Rizzo 	int i, num_eqes = 0;
6902f345d8eSLuigi Rizzo 
6912f345d8eSLuigi Rizzo 	bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
6922f345d8eSLuigi Rizzo 				 BUS_DMASYNC_POSTWRITE);
6932f345d8eSLuigi Rizzo 	do {
6942f345d8eSLuigi Rizzo 		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
6952f345d8eSLuigi Rizzo 		if (eqe->evnt == 0)
6962f345d8eSLuigi Rizzo 			break;
6972f345d8eSLuigi Rizzo 		eqe->evnt = 0;
6982f345d8eSLuigi Rizzo 		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
6992f345d8eSLuigi Rizzo 					BUS_DMASYNC_POSTWRITE);
7002f345d8eSLuigi Rizzo 		RING_GET(eq->ring, 1);
7012f345d8eSLuigi Rizzo 		num_eqes++;
7022f345d8eSLuigi Rizzo 
7032f345d8eSLuigi Rizzo 	} while (TRUE);
7042f345d8eSLuigi Rizzo 
7052f345d8eSLuigi Rizzo 	if (!num_eqes)
7062f345d8eSLuigi Rizzo 		goto eq_arm; /* Spurious */
7072f345d8eSLuigi Rizzo 
7082f345d8eSLuigi Rizzo  	/* Clear EQ entries, but dont arm */
7092f345d8eSLuigi Rizzo 	oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
7102f345d8eSLuigi Rizzo 
7112f345d8eSLuigi Rizzo 	/* Process TX, RX and MCC. But dont arm CQ*/
7122f345d8eSLuigi Rizzo 	for (i = 0; i < eq->cq_valid; i++) {
7132f345d8eSLuigi Rizzo 		cq = eq->cq[i];
7142f345d8eSLuigi Rizzo 		(*cq->cq_handler)(cq->cb_arg);
7152f345d8eSLuigi Rizzo 	}
7162f345d8eSLuigi Rizzo 
7172f345d8eSLuigi Rizzo 	/* Arm all cqs connected to this EQ */
7182f345d8eSLuigi Rizzo 	for (i = 0; i < eq->cq_valid; i++) {
7192f345d8eSLuigi Rizzo 		cq = eq->cq[i];
7202f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, 0, TRUE);
7212f345d8eSLuigi Rizzo 	}
7222f345d8eSLuigi Rizzo 
7232f345d8eSLuigi Rizzo eq_arm:
7242f345d8eSLuigi Rizzo 	oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
725cdaba892SXin LI 
7262f345d8eSLuigi Rizzo 	return;
7272f345d8eSLuigi Rizzo }
7282f345d8eSLuigi Rizzo 
7292f345d8eSLuigi Rizzo static int
oce_setup_intr(POCE_SOFTC sc)7302f345d8eSLuigi Rizzo oce_setup_intr(POCE_SOFTC sc)
7312f345d8eSLuigi Rizzo {
7322f345d8eSLuigi Rizzo 	int rc = 0, use_intx = 0;
7332f345d8eSLuigi Rizzo 	int vector = 0, req_vectors = 0;
734c2625e6eSJosh Paetzel 	int tot_req_vectors, tot_vectors;
7352f345d8eSLuigi Rizzo 
736291a1934SXin LI 	if (is_rss_enabled(sc))
7372f345d8eSLuigi Rizzo 		req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
7382f345d8eSLuigi Rizzo 	else
7392f345d8eSLuigi Rizzo 		req_vectors = 1;
7402f345d8eSLuigi Rizzo 
741c2625e6eSJosh Paetzel 	tot_req_vectors = req_vectors;
742c2625e6eSJosh Paetzel 	if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
743c2625e6eSJosh Paetzel 	  if (req_vectors > 1) {
744c2625e6eSJosh Paetzel 	    tot_req_vectors += OCE_RDMA_VECTORS;
745c2625e6eSJosh Paetzel 	    sc->roce_intr_count = OCE_RDMA_VECTORS;
746c2625e6eSJosh Paetzel 	  }
747c2625e6eSJosh Paetzel 	}
748c2625e6eSJosh Paetzel 
7492f345d8eSLuigi Rizzo         if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
7502f345d8eSLuigi Rizzo 		sc->intr_count = req_vectors;
751c2625e6eSJosh Paetzel                 tot_vectors = tot_req_vectors;
752c2625e6eSJosh Paetzel 		rc = pci_alloc_msix(sc->dev, &tot_vectors);
7532f345d8eSLuigi Rizzo 		if (rc != 0) {
7542f345d8eSLuigi Rizzo 			use_intx = 1;
7552f345d8eSLuigi Rizzo 			pci_release_msi(sc->dev);
756c2625e6eSJosh Paetzel 		} else {
757c2625e6eSJosh Paetzel 		  if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
758c2625e6eSJosh Paetzel 		    if (tot_vectors < tot_req_vectors) {
759c2625e6eSJosh Paetzel 		      if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) {
760c2625e6eSJosh Paetzel 			sc->roce_intr_count = (tot_vectors / 2);
761c2625e6eSJosh Paetzel 		      }
762c2625e6eSJosh Paetzel 		      sc->intr_count = tot_vectors - sc->roce_intr_count;
763c2625e6eSJosh Paetzel 		    }
764c2625e6eSJosh Paetzel 		  } else {
765c2625e6eSJosh Paetzel 		    sc->intr_count = tot_vectors;
766c2625e6eSJosh Paetzel 		  }
7672f345d8eSLuigi Rizzo     		  sc->flags |= OCE_FLAGS_USING_MSIX;
768c2625e6eSJosh Paetzel 		}
7692f345d8eSLuigi Rizzo 	} else
7702f345d8eSLuigi Rizzo 		use_intx = 1;
7712f345d8eSLuigi Rizzo 
7722f345d8eSLuigi Rizzo 	if (use_intx)
7732f345d8eSLuigi Rizzo 		sc->intr_count = 1;
7742f345d8eSLuigi Rizzo 
7752f345d8eSLuigi Rizzo 	/* Scale number of queues based on intr we got */
7762f345d8eSLuigi Rizzo 	update_queues_got(sc);
7772f345d8eSLuigi Rizzo 
7782f345d8eSLuigi Rizzo 	if (use_intx) {
7792f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Using legacy interrupt\n");
7802f345d8eSLuigi Rizzo 		rc = oce_alloc_intr(sc, vector, oce_intr);
7812f345d8eSLuigi Rizzo 		if (rc)
7822f345d8eSLuigi Rizzo 			goto error;
7832f345d8eSLuigi Rizzo 	} else {
7842f345d8eSLuigi Rizzo 		for (; vector < sc->intr_count; vector++) {
7852f345d8eSLuigi Rizzo 			rc = oce_alloc_intr(sc, vector, oce_intr);
7862f345d8eSLuigi Rizzo 			if (rc)
7872f345d8eSLuigi Rizzo 				goto error;
7882f345d8eSLuigi Rizzo 		}
7892f345d8eSLuigi Rizzo 	}
7902f345d8eSLuigi Rizzo 
7912f345d8eSLuigi Rizzo 	return 0;
7922f345d8eSLuigi Rizzo error:
7932f345d8eSLuigi Rizzo 	oce_intr_free(sc);
7942f345d8eSLuigi Rizzo 	return rc;
7952f345d8eSLuigi Rizzo }
7962f345d8eSLuigi Rizzo 
7972f345d8eSLuigi Rizzo static int
oce_fast_isr(void * arg)7982f345d8eSLuigi Rizzo oce_fast_isr(void *arg)
7992f345d8eSLuigi Rizzo {
8002f345d8eSLuigi Rizzo 	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
8012f345d8eSLuigi Rizzo 	POCE_SOFTC sc = ii->sc;
8022f345d8eSLuigi Rizzo 
8032f345d8eSLuigi Rizzo 	if (ii->eq == NULL)
8042f345d8eSLuigi Rizzo 		return FILTER_STRAY;
8052f345d8eSLuigi Rizzo 
8062f345d8eSLuigi Rizzo 	oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
8072f345d8eSLuigi Rizzo 
808cbc4d2dbSJohn Baldwin 	taskqueue_enqueue(ii->tq, &ii->task);
8092f345d8eSLuigi Rizzo 
810cdaba892SXin LI  	ii->eq->intr++;
811cdaba892SXin LI 
8122f345d8eSLuigi Rizzo 	return FILTER_HANDLED;
8132f345d8eSLuigi Rizzo }
8142f345d8eSLuigi Rizzo 
8152f345d8eSLuigi Rizzo static int
oce_alloc_intr(POCE_SOFTC sc,int vector,void (* isr)(void * arg,int pending))8162f345d8eSLuigi Rizzo oce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
8172f345d8eSLuigi Rizzo {
818ab7de25cSKyle Evans 	POCE_INTR_INFO ii;
8192f345d8eSLuigi Rizzo 	int rc = 0, rr;
8202f345d8eSLuigi Rizzo 
8212f345d8eSLuigi Rizzo 	if (vector >= OCE_MAX_EQ)
8222f345d8eSLuigi Rizzo 		return (EINVAL);
8232f345d8eSLuigi Rizzo 
824ab7de25cSKyle Evans 	ii = &sc->intrs[vector];
825ab7de25cSKyle Evans 
8262f345d8eSLuigi Rizzo 	/* Set the resource id for the interrupt.
8272f345d8eSLuigi Rizzo 	 * MSIx is vector + 1 for the resource id,
8282f345d8eSLuigi Rizzo 	 * INTx is 0 for the resource id.
8292f345d8eSLuigi Rizzo 	 */
8302f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_USING_MSIX)
8312f345d8eSLuigi Rizzo 		rr = vector + 1;
8322f345d8eSLuigi Rizzo 	else
8332f345d8eSLuigi Rizzo 		rr = 0;
8342f345d8eSLuigi Rizzo 	ii->intr_res = bus_alloc_resource_any(sc->dev,
8352f345d8eSLuigi Rizzo 					      SYS_RES_IRQ,
8362f345d8eSLuigi Rizzo 					      &rr, RF_ACTIVE|RF_SHAREABLE);
8372f345d8eSLuigi Rizzo 	ii->irq_rr = rr;
8382f345d8eSLuigi Rizzo 	if (ii->intr_res == NULL) {
8392f345d8eSLuigi Rizzo 		device_printf(sc->dev,
8402f345d8eSLuigi Rizzo 			  "Could not allocate interrupt\n");
8412f345d8eSLuigi Rizzo 		rc = ENXIO;
8422f345d8eSLuigi Rizzo 		return rc;
8432f345d8eSLuigi Rizzo 	}
8442f345d8eSLuigi Rizzo 
8452f345d8eSLuigi Rizzo 	TASK_INIT(&ii->task, 0, isr, ii);
8462f345d8eSLuigi Rizzo 	ii->vector = vector;
8472f345d8eSLuigi Rizzo 	sprintf(ii->task_name, "oce_task[%d]", ii->vector);
8482f345d8eSLuigi Rizzo 	ii->tq = taskqueue_create_fast(ii->task_name,
8492f345d8eSLuigi Rizzo 			M_NOWAIT,
8502f345d8eSLuigi Rizzo 			taskqueue_thread_enqueue,
8512f345d8eSLuigi Rizzo 			&ii->tq);
8522f345d8eSLuigi Rizzo 	taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
8532f345d8eSLuigi Rizzo 			device_get_nameunit(sc->dev));
8542f345d8eSLuigi Rizzo 
8552f345d8eSLuigi Rizzo 	ii->sc = sc;
8562f345d8eSLuigi Rizzo 	rc = bus_setup_intr(sc->dev,
8572f345d8eSLuigi Rizzo 			ii->intr_res,
8582f345d8eSLuigi Rizzo 			INTR_TYPE_NET,
8592f345d8eSLuigi Rizzo 			oce_fast_isr, NULL, ii, &ii->tag);
8602f345d8eSLuigi Rizzo 	return rc;
8612f345d8eSLuigi Rizzo 
8622f345d8eSLuigi Rizzo }
8632f345d8eSLuigi Rizzo 
8642f345d8eSLuigi Rizzo void
oce_intr_free(POCE_SOFTC sc)8652f345d8eSLuigi Rizzo oce_intr_free(POCE_SOFTC sc)
8662f345d8eSLuigi Rizzo {
8672f345d8eSLuigi Rizzo 	int i = 0;
8682f345d8eSLuigi Rizzo 
8692f345d8eSLuigi Rizzo 	for (i = 0; i < sc->intr_count; i++) {
8702f345d8eSLuigi Rizzo 
8712f345d8eSLuigi Rizzo 		if (sc->intrs[i].tag != NULL)
8722f345d8eSLuigi Rizzo 			bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
8732f345d8eSLuigi Rizzo 						sc->intrs[i].tag);
8742f345d8eSLuigi Rizzo 		if (sc->intrs[i].tq != NULL)
8752f345d8eSLuigi Rizzo 			taskqueue_free(sc->intrs[i].tq);
8762f345d8eSLuigi Rizzo 
8772f345d8eSLuigi Rizzo 		if (sc->intrs[i].intr_res != NULL)
8782f345d8eSLuigi Rizzo 			bus_release_resource(sc->dev, SYS_RES_IRQ,
8792f345d8eSLuigi Rizzo 						sc->intrs[i].irq_rr,
8802f345d8eSLuigi Rizzo 						sc->intrs[i].intr_res);
8812f345d8eSLuigi Rizzo 		sc->intrs[i].tag = NULL;
8822f345d8eSLuigi Rizzo 		sc->intrs[i].intr_res = NULL;
8832f345d8eSLuigi Rizzo 	}
8842f345d8eSLuigi Rizzo 
8852f345d8eSLuigi Rizzo 	if (sc->flags & OCE_FLAGS_USING_MSIX)
8862f345d8eSLuigi Rizzo 		pci_release_msi(sc->dev);
8872f345d8eSLuigi Rizzo 
8882f345d8eSLuigi Rizzo }
8892f345d8eSLuigi Rizzo 
8902f345d8eSLuigi Rizzo /******************************************************************************
8912f345d8eSLuigi Rizzo *			  Media callbacks functions 			      *
8922f345d8eSLuigi Rizzo ******************************************************************************/
8932f345d8eSLuigi Rizzo 
8942f345d8eSLuigi Rizzo static void
oce_media_status(if_t ifp,struct ifmediareq * req)89567fd4c9dSJustin Hibbits oce_media_status(if_t ifp, struct ifmediareq *req)
8962f345d8eSLuigi Rizzo {
89767fd4c9dSJustin Hibbits 	POCE_SOFTC sc = (POCE_SOFTC) if_getsoftc(ifp);
8982f345d8eSLuigi Rizzo 
8992f345d8eSLuigi Rizzo 	req->ifm_status = IFM_AVALID;
9002f345d8eSLuigi Rizzo 	req->ifm_active = IFM_ETHER;
9012f345d8eSLuigi Rizzo 
9022f345d8eSLuigi Rizzo 	if (sc->link_status == 1)
9032f345d8eSLuigi Rizzo 		req->ifm_status |= IFM_ACTIVE;
9042f345d8eSLuigi Rizzo 	else
9052f345d8eSLuigi Rizzo 		return;
9062f345d8eSLuigi Rizzo 
9072f345d8eSLuigi Rizzo 	switch (sc->link_speed) {
9082f345d8eSLuigi Rizzo 	case 1: /* 10 Mbps */
9092f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_10_T | IFM_FDX;
9102f345d8eSLuigi Rizzo 		sc->speed = 10;
9112f345d8eSLuigi Rizzo 		break;
9122f345d8eSLuigi Rizzo 	case 2: /* 100 Mbps */
9132f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_100_TX | IFM_FDX;
9142f345d8eSLuigi Rizzo 		sc->speed = 100;
9152f345d8eSLuigi Rizzo 		break;
9162f345d8eSLuigi Rizzo 	case 3: /* 1 Gbps */
9172f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_1000_T | IFM_FDX;
9182f345d8eSLuigi Rizzo 		sc->speed = 1000;
9192f345d8eSLuigi Rizzo 		break;
9202f345d8eSLuigi Rizzo 	case 4: /* 10 Gbps */
9212f345d8eSLuigi Rizzo 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
9222f345d8eSLuigi Rizzo 		sc->speed = 10000;
9232f345d8eSLuigi Rizzo 		break;
924a4f734b4SXin LI 	case 5: /* 20 Gbps */
925a4f734b4SXin LI 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
926a4f734b4SXin LI 		sc->speed = 20000;
927a4f734b4SXin LI 		break;
928a4f734b4SXin LI 	case 6: /* 25 Gbps */
929a4f734b4SXin LI 		req->ifm_active |= IFM_10G_SR | IFM_FDX;
930a4f734b4SXin LI 		sc->speed = 25000;
931a4f734b4SXin LI 		break;
932b41206d8SXin LI 	case 7: /* 40 Gbps */
933b41206d8SXin LI 		req->ifm_active |= IFM_40G_SR4 | IFM_FDX;
934b41206d8SXin LI 		sc->speed = 40000;
935b41206d8SXin LI 		break;
936a4f734b4SXin LI 	default:
937a4f734b4SXin LI 		sc->speed = 0;
938a4f734b4SXin LI 		break;
9392f345d8eSLuigi Rizzo 	}
9402f345d8eSLuigi Rizzo 
9412f345d8eSLuigi Rizzo 	return;
9422f345d8eSLuigi Rizzo }
9432f345d8eSLuigi Rizzo 
9442f345d8eSLuigi Rizzo int
oce_media_change(if_t ifp)94567fd4c9dSJustin Hibbits oce_media_change(if_t ifp)
9462f345d8eSLuigi Rizzo {
9472f345d8eSLuigi Rizzo 	return 0;
9482f345d8eSLuigi Rizzo }
9492f345d8eSLuigi Rizzo 
oce_is_pkt_dest_bmc(POCE_SOFTC sc,struct mbuf * m,boolean_t * os2bmc,struct mbuf ** m_new)950c2625e6eSJosh Paetzel static void oce_is_pkt_dest_bmc(POCE_SOFTC sc,
951c2625e6eSJosh Paetzel 				struct mbuf *m, boolean_t *os2bmc,
952c2625e6eSJosh Paetzel 				struct mbuf **m_new)
953c2625e6eSJosh Paetzel {
954c2625e6eSJosh Paetzel 	struct ether_header *eh = NULL;
955c2625e6eSJosh Paetzel 
956c2625e6eSJosh Paetzel 	eh = mtod(m, struct ether_header *);
957c2625e6eSJosh Paetzel 
958c2625e6eSJosh Paetzel 	if (!is_os2bmc_enabled(sc) || *os2bmc) {
959c2625e6eSJosh Paetzel 		*os2bmc = FALSE;
960c2625e6eSJosh Paetzel 		goto done;
961c2625e6eSJosh Paetzel 	}
962c2625e6eSJosh Paetzel 	if (!ETHER_IS_MULTICAST(eh->ether_dhost))
963c2625e6eSJosh Paetzel 		goto done;
964c2625e6eSJosh Paetzel 
965c2625e6eSJosh Paetzel 	if (is_mc_allowed_on_bmc(sc, eh) ||
966c2625e6eSJosh Paetzel 	    is_bc_allowed_on_bmc(sc, eh) ||
967c2625e6eSJosh Paetzel 	    is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) {
968c2625e6eSJosh Paetzel 		*os2bmc = TRUE;
969c2625e6eSJosh Paetzel 		goto done;
970c2625e6eSJosh Paetzel 	}
971c2625e6eSJosh Paetzel 
972c2625e6eSJosh Paetzel 	if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) {
973c2625e6eSJosh Paetzel 		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
974c2625e6eSJosh Paetzel 		uint8_t nexthdr = ip6->ip6_nxt;
975c2625e6eSJosh Paetzel 		if (nexthdr == IPPROTO_ICMPV6) {
976c2625e6eSJosh Paetzel 			struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1);
977c2625e6eSJosh Paetzel 			switch (icmp6->icmp6_type) {
978c2625e6eSJosh Paetzel 			case ND_ROUTER_ADVERT:
979c2625e6eSJosh Paetzel 				*os2bmc = is_ipv6_ra_filt_enabled(sc);
980c2625e6eSJosh Paetzel 				goto done;
981c2625e6eSJosh Paetzel 			case ND_NEIGHBOR_ADVERT:
982c2625e6eSJosh Paetzel 				*os2bmc = is_ipv6_na_filt_enabled(sc);
983c2625e6eSJosh Paetzel 				goto done;
984c2625e6eSJosh Paetzel 			default:
985c2625e6eSJosh Paetzel 				break;
986c2625e6eSJosh Paetzel 			}
987c2625e6eSJosh Paetzel 		}
988c2625e6eSJosh Paetzel 	}
989c2625e6eSJosh Paetzel 
990c2625e6eSJosh Paetzel 	if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) {
991c2625e6eSJosh Paetzel 		struct ip *ip = mtod(m, struct ip *);
992c2625e6eSJosh Paetzel 		int iphlen = ip->ip_hl << 2;
993c2625e6eSJosh Paetzel 		struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen);
994c2625e6eSJosh Paetzel 		switch (uh->uh_dport) {
995c2625e6eSJosh Paetzel 		case DHCP_CLIENT_PORT:
996c2625e6eSJosh Paetzel 			*os2bmc = is_dhcp_client_filt_enabled(sc);
997c2625e6eSJosh Paetzel 			goto done;
998c2625e6eSJosh Paetzel 		case DHCP_SERVER_PORT:
999c2625e6eSJosh Paetzel 			*os2bmc = is_dhcp_srvr_filt_enabled(sc);
1000c2625e6eSJosh Paetzel 			goto done;
1001c2625e6eSJosh Paetzel 		case NET_BIOS_PORT1:
1002c2625e6eSJosh Paetzel 		case NET_BIOS_PORT2:
1003c2625e6eSJosh Paetzel 			*os2bmc = is_nbios_filt_enabled(sc);
1004c2625e6eSJosh Paetzel 			goto done;
1005c2625e6eSJosh Paetzel 		case DHCPV6_RAS_PORT:
1006c2625e6eSJosh Paetzel 			*os2bmc = is_ipv6_ras_filt_enabled(sc);
1007c2625e6eSJosh Paetzel 			goto done;
1008c2625e6eSJosh Paetzel 		default:
1009c2625e6eSJosh Paetzel 			break;
1010c2625e6eSJosh Paetzel 		}
1011c2625e6eSJosh Paetzel 	}
1012c2625e6eSJosh Paetzel done:
1013c2625e6eSJosh Paetzel 	if (*os2bmc) {
1014c2625e6eSJosh Paetzel 		*m_new = m_dup(m, M_NOWAIT);
1015c2625e6eSJosh Paetzel 		if (!*m_new) {
1016c2625e6eSJosh Paetzel 			*os2bmc = FALSE;
1017c2625e6eSJosh Paetzel 			return;
1018c2625e6eSJosh Paetzel 		}
1019c2625e6eSJosh Paetzel 		*m_new = oce_insert_vlan_tag(sc, *m_new, NULL);
1020c2625e6eSJosh Paetzel 	}
1021c2625e6eSJosh Paetzel }
1022c2625e6eSJosh Paetzel 
10232f345d8eSLuigi Rizzo /*****************************************************************************
10242f345d8eSLuigi Rizzo  *			  Transmit routines functions			     *
10252f345d8eSLuigi Rizzo  *****************************************************************************/
10262f345d8eSLuigi Rizzo 
10272f345d8eSLuigi Rizzo static int
oce_tx(POCE_SOFTC sc,struct mbuf ** mpp,int wq_index)10282f345d8eSLuigi Rizzo oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
10292f345d8eSLuigi Rizzo {
10302f345d8eSLuigi Rizzo 	int rc = 0, i, retry_cnt = 0;
10312f345d8eSLuigi Rizzo 	bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
1032c2625e6eSJosh Paetzel 	struct mbuf *m, *m_temp, *m_new = NULL;
10332f345d8eSLuigi Rizzo 	struct oce_wq *wq = sc->wq[wq_index];
10342f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
10352f345d8eSLuigi Rizzo 	struct oce_nic_hdr_wqe *nichdr;
10362f345d8eSLuigi Rizzo 	struct oce_nic_frag_wqe *nicfrag;
1037c2625e6eSJosh Paetzel 	struct ether_header *eh = NULL;
10382f345d8eSLuigi Rizzo 	int num_wqes;
10392f345d8eSLuigi Rizzo 	uint32_t reg_value;
1040cdaba892SXin LI 	boolean_t complete = TRUE;
1041c2625e6eSJosh Paetzel 	boolean_t os2bmc = FALSE;
10422f345d8eSLuigi Rizzo 
10432f345d8eSLuigi Rizzo 	m = *mpp;
10442f345d8eSLuigi Rizzo 	if (!m)
10452f345d8eSLuigi Rizzo 		return EINVAL;
10462f345d8eSLuigi Rizzo 
10472f345d8eSLuigi Rizzo 	if (!(m->m_flags & M_PKTHDR)) {
10482f345d8eSLuigi Rizzo 		rc = ENXIO;
10492f345d8eSLuigi Rizzo 		goto free_ret;
10502f345d8eSLuigi Rizzo 	}
10512f345d8eSLuigi Rizzo 
1052c2625e6eSJosh Paetzel 	/* Don't allow non-TSO packets longer than MTU */
1053c2625e6eSJosh Paetzel 	if (!is_tso_pkt(m)) {
1054c2625e6eSJosh Paetzel 		eh = mtod(m, struct ether_header *);
1055c2625e6eSJosh Paetzel 		if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE))
1056c2625e6eSJosh Paetzel 			 goto free_ret;
1057c2625e6eSJosh Paetzel 	}
1058c2625e6eSJosh Paetzel 
1059cdaba892SXin LI 	if(oce_tx_asic_stall_verify(sc, m)) {
1060cdaba892SXin LI 		m = oce_insert_vlan_tag(sc, m, &complete);
1061cdaba892SXin LI 		if(!m) {
1062cdaba892SXin LI 			device_printf(sc->dev, "Insertion unsuccessful\n");
1063cdaba892SXin LI 			return 0;
1064cdaba892SXin LI 		}
1065cdaba892SXin LI 	}
1066cdaba892SXin LI 
1067c2625e6eSJosh Paetzel 	/* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less
1068c2625e6eSJosh Paetzel 	 * may cause a transmit stall on that port. So the work-around is to
1069c2625e6eSJosh Paetzel 	 * pad short packets (<= 32 bytes) to a 36-byte length.
1070c2625e6eSJosh Paetzel 	*/
1071c2625e6eSJosh Paetzel 	if(IS_SH(sc) || IS_XE201(sc) ) {
1072c2625e6eSJosh Paetzel 		if(m->m_pkthdr.len <= 32) {
1073c2625e6eSJosh Paetzel 			char buf[36];
1074c2625e6eSJosh Paetzel 			bzero((void *)buf, 36);
1075c2625e6eSJosh Paetzel 			m_append(m, (36 - m->m_pkthdr.len), buf);
1076c2625e6eSJosh Paetzel 		}
1077c2625e6eSJosh Paetzel 	}
1078c2625e6eSJosh Paetzel 
1079c2625e6eSJosh Paetzel tx_start:
10802f345d8eSLuigi Rizzo 	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
10812f345d8eSLuigi Rizzo 		/* consolidate packet buffers for TSO/LSO segment offload */
10829bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
10839bd3250aSLuigi Rizzo 		m = oce_tso_setup(sc, mpp);
1084ad512958SBjoern A. Zeeb #else
1085ad512958SBjoern A. Zeeb 		m = NULL;
1086ad512958SBjoern A. Zeeb #endif
10872f345d8eSLuigi Rizzo 		if (m == NULL) {
10882f345d8eSLuigi Rizzo 			rc = ENXIO;
10892f345d8eSLuigi Rizzo 			goto free_ret;
10902f345d8eSLuigi Rizzo 		}
10912f345d8eSLuigi Rizzo 	}
10922f345d8eSLuigi Rizzo 
1093291a1934SXin LI 	pd = &wq->pckts[wq->pkt_desc_head];
1094c2625e6eSJosh Paetzel 
10952f345d8eSLuigi Rizzo retry:
10962f345d8eSLuigi Rizzo 	rc = bus_dmamap_load_mbuf_sg(wq->tag,
10972f345d8eSLuigi Rizzo 				     pd->map,
10982f345d8eSLuigi Rizzo 				     m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
10992f345d8eSLuigi Rizzo 	if (rc == 0) {
11002f345d8eSLuigi Rizzo 		num_wqes = pd->nsegs + 1;
1101291a1934SXin LI 		if (IS_BE(sc) || IS_SH(sc)) {
11022f345d8eSLuigi Rizzo 			/*Dummy required only for BE3.*/
11032f345d8eSLuigi Rizzo 			if (num_wqes & 1)
11042f345d8eSLuigi Rizzo 				num_wqes++;
11052f345d8eSLuigi Rizzo 		}
11062f345d8eSLuigi Rizzo 		if (num_wqes >= RING_NUM_FREE(wq->ring)) {
11072f345d8eSLuigi Rizzo 			bus_dmamap_unload(wq->tag, pd->map);
11082f345d8eSLuigi Rizzo 			return EBUSY;
11092f345d8eSLuigi Rizzo 		}
1110291a1934SXin LI 		atomic_store_rel_int(&wq->pkt_desc_head,
1111291a1934SXin LI 				     (wq->pkt_desc_head + 1) % \
1112291a1934SXin LI 				      OCE_WQ_PACKET_ARRAY_SIZE);
11132f345d8eSLuigi Rizzo 		bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
11142f345d8eSLuigi Rizzo 		pd->mbuf = m;
11152f345d8eSLuigi Rizzo 
11162f345d8eSLuigi Rizzo 		nichdr =
11172f345d8eSLuigi Rizzo 		    RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
11182f345d8eSLuigi Rizzo 		nichdr->u0.dw[0] = 0;
11192f345d8eSLuigi Rizzo 		nichdr->u0.dw[1] = 0;
11202f345d8eSLuigi Rizzo 		nichdr->u0.dw[2] = 0;
11212f345d8eSLuigi Rizzo 		nichdr->u0.dw[3] = 0;
11222f345d8eSLuigi Rizzo 
1123cdaba892SXin LI 		nichdr->u0.s.complete = complete;
1124c2625e6eSJosh Paetzel 		nichdr->u0.s.mgmt = os2bmc;
11252f345d8eSLuigi Rizzo 		nichdr->u0.s.event = 1;
11262f345d8eSLuigi Rizzo 		nichdr->u0.s.crc = 1;
11272f345d8eSLuigi Rizzo 		nichdr->u0.s.forward = 0;
11282f345d8eSLuigi Rizzo 		nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
11292f345d8eSLuigi Rizzo 		nichdr->u0.s.udpcs =
11302f345d8eSLuigi Rizzo 			(m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
11312f345d8eSLuigi Rizzo 		nichdr->u0.s.tcpcs =
11322f345d8eSLuigi Rizzo 			(m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
11332f345d8eSLuigi Rizzo 		nichdr->u0.s.num_wqe = num_wqes;
11342f345d8eSLuigi Rizzo 		nichdr->u0.s.total_length = m->m_pkthdr.len;
11355fbb6830SXin LI 
11362f345d8eSLuigi Rizzo 		if (m->m_flags & M_VLANTAG) {
11372f345d8eSLuigi Rizzo 			nichdr->u0.s.vlan = 1; /*Vlan present*/
11382f345d8eSLuigi Rizzo 			nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
11392f345d8eSLuigi Rizzo 		}
11405fbb6830SXin LI 
11412f345d8eSLuigi Rizzo 		if (m->m_pkthdr.csum_flags & CSUM_TSO) {
11422f345d8eSLuigi Rizzo 			if (m->m_pkthdr.tso_segsz) {
11432f345d8eSLuigi Rizzo 				nichdr->u0.s.lso = 1;
11442f345d8eSLuigi Rizzo 				nichdr->u0.s.lso_mss  = m->m_pkthdr.tso_segsz;
11452f345d8eSLuigi Rizzo 			}
1146291a1934SXin LI 			if (!IS_BE(sc) || !IS_SH(sc))
11472f345d8eSLuigi Rizzo 				nichdr->u0.s.ipcs = 1;
11482f345d8eSLuigi Rizzo 		}
11492f345d8eSLuigi Rizzo 
11502f345d8eSLuigi Rizzo 		RING_PUT(wq->ring, 1);
1151291a1934SXin LI 		atomic_add_int(&wq->ring->num_used, 1);
11522f345d8eSLuigi Rizzo 
11532f345d8eSLuigi Rizzo 		for (i = 0; i < pd->nsegs; i++) {
11542f345d8eSLuigi Rizzo 			nicfrag =
11552f345d8eSLuigi Rizzo 			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
11562f345d8eSLuigi Rizzo 						      struct oce_nic_frag_wqe);
11572f345d8eSLuigi Rizzo 			nicfrag->u0.s.rsvd0 = 0;
11582f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
11592f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
11602f345d8eSLuigi Rizzo 			nicfrag->u0.s.frag_len = segs[i].ds_len;
11612f345d8eSLuigi Rizzo 			pd->wqe_idx = wq->ring->pidx;
11622f345d8eSLuigi Rizzo 			RING_PUT(wq->ring, 1);
1163291a1934SXin LI 			atomic_add_int(&wq->ring->num_used, 1);
11642f345d8eSLuigi Rizzo 		}
11652f345d8eSLuigi Rizzo 		if (num_wqes > (pd->nsegs + 1)) {
11662f345d8eSLuigi Rizzo 			nicfrag =
11672f345d8eSLuigi Rizzo 			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
11682f345d8eSLuigi Rizzo 						      struct oce_nic_frag_wqe);
11692f345d8eSLuigi Rizzo 			nicfrag->u0.dw[0] = 0;
11702f345d8eSLuigi Rizzo 			nicfrag->u0.dw[1] = 0;
11712f345d8eSLuigi Rizzo 			nicfrag->u0.dw[2] = 0;
11722f345d8eSLuigi Rizzo 			nicfrag->u0.dw[3] = 0;
11732f345d8eSLuigi Rizzo 			pd->wqe_idx = wq->ring->pidx;
11742f345d8eSLuigi Rizzo 			RING_PUT(wq->ring, 1);
1175291a1934SXin LI 			atomic_add_int(&wq->ring->num_used, 1);
11762f345d8eSLuigi Rizzo 			pd->nsegs++;
11772f345d8eSLuigi Rizzo 		}
11782f345d8eSLuigi Rizzo 
1179c8dfaf38SGleb Smirnoff 		if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
11802f345d8eSLuigi Rizzo 		wq->tx_stats.tx_reqs++;
11812f345d8eSLuigi Rizzo 		wq->tx_stats.tx_wrbs += num_wqes;
11822f345d8eSLuigi Rizzo 		wq->tx_stats.tx_bytes += m->m_pkthdr.len;
11832f345d8eSLuigi Rizzo 		wq->tx_stats.tx_pkts++;
11842f345d8eSLuigi Rizzo 
11852f345d8eSLuigi Rizzo 		bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
11862f345d8eSLuigi Rizzo 				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
11872f345d8eSLuigi Rizzo 		reg_value = (num_wqes << 16) | wq->wq_id;
1188c2625e6eSJosh Paetzel 
1189c2625e6eSJosh Paetzel 		/* if os2bmc is not enabled or if the pkt is already tagged as
1190c2625e6eSJosh Paetzel 		   bmc, do nothing
1191c2625e6eSJosh Paetzel 		 */
1192c2625e6eSJosh Paetzel 		oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new);
1193c2625e6eSJosh Paetzel 
1194b75a7728SConrad Meyer 		if_inc_counter(sc->ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len);
1195b75a7728SConrad Meyer 		if (m->m_flags & M_MCAST)
1196b75a7728SConrad Meyer 			if_inc_counter(sc->ifp, IFCOUNTER_OMCASTS, 1);
1197b75a7728SConrad Meyer 		ETHER_BPF_MTAP(sc->ifp, m);
1198b75a7728SConrad Meyer 
1199291a1934SXin LI 		OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value);
12002f345d8eSLuigi Rizzo 
12012f345d8eSLuigi Rizzo 	} else if (rc == EFBIG)	{
12022f345d8eSLuigi Rizzo 		if (retry_cnt == 0) {
1203c6499eccSGleb Smirnoff 			m_temp = m_defrag(m, M_NOWAIT);
12042f345d8eSLuigi Rizzo 			if (m_temp == NULL)
12052f345d8eSLuigi Rizzo 				goto free_ret;
12062f345d8eSLuigi Rizzo 			m = m_temp;
12072f345d8eSLuigi Rizzo 			*mpp = m_temp;
12082f345d8eSLuigi Rizzo 			retry_cnt = retry_cnt + 1;
12092f345d8eSLuigi Rizzo 			goto retry;
12102f345d8eSLuigi Rizzo 		} else
12112f345d8eSLuigi Rizzo 			goto free_ret;
12122f345d8eSLuigi Rizzo 	} else if (rc == ENOMEM)
12132f345d8eSLuigi Rizzo 		return rc;
12142f345d8eSLuigi Rizzo 	else
12152f345d8eSLuigi Rizzo 		goto free_ret;
12162f345d8eSLuigi Rizzo 
1217c2625e6eSJosh Paetzel 	if (os2bmc) {
1218c2625e6eSJosh Paetzel 		m = m_new;
1219c2625e6eSJosh Paetzel 		goto tx_start;
1220c2625e6eSJosh Paetzel 	}
1221c2625e6eSJosh Paetzel 
12222f345d8eSLuigi Rizzo 	return 0;
12232f345d8eSLuigi Rizzo 
12242f345d8eSLuigi Rizzo free_ret:
12252f345d8eSLuigi Rizzo 	m_freem(*mpp);
12262f345d8eSLuigi Rizzo 	*mpp = NULL;
12272f345d8eSLuigi Rizzo 	return rc;
12282f345d8eSLuigi Rizzo }
12292f345d8eSLuigi Rizzo 
12302f345d8eSLuigi Rizzo static void
oce_process_tx_completion(struct oce_wq * wq)1231c2625e6eSJosh Paetzel oce_process_tx_completion(struct oce_wq *wq)
12322f345d8eSLuigi Rizzo {
12332f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
12342f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
12352f345d8eSLuigi Rizzo 	struct mbuf *m;
12362f345d8eSLuigi Rizzo 
1237291a1934SXin LI 	pd = &wq->pckts[wq->pkt_desc_tail];
1238291a1934SXin LI 	atomic_store_rel_int(&wq->pkt_desc_tail,
1239291a1934SXin LI 			     (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE);
1240291a1934SXin LI 	atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1);
12412f345d8eSLuigi Rizzo 	bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
12422f345d8eSLuigi Rizzo 	bus_dmamap_unload(wq->tag, pd->map);
12432f345d8eSLuigi Rizzo 
12442f345d8eSLuigi Rizzo 	m = pd->mbuf;
12452f345d8eSLuigi Rizzo 	m_freem(m);
12462f345d8eSLuigi Rizzo 	pd->mbuf = NULL;
12472f345d8eSLuigi Rizzo 
124867fd4c9dSJustin Hibbits 	if (if_getdrvflags(sc->ifp) & IFF_DRV_OACTIVE) {
12492f345d8eSLuigi Rizzo 		if (wq->ring->num_used < (wq->ring->num_items / 2)) {
125067fd4c9dSJustin Hibbits 			if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_OACTIVE));
12512f345d8eSLuigi Rizzo 			oce_tx_restart(sc, wq);
12522f345d8eSLuigi Rizzo 		}
12532f345d8eSLuigi Rizzo 	}
12542f345d8eSLuigi Rizzo }
12552f345d8eSLuigi Rizzo 
12562f345d8eSLuigi Rizzo static void
oce_tx_restart(POCE_SOFTC sc,struct oce_wq * wq)12572f345d8eSLuigi Rizzo oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
12582f345d8eSLuigi Rizzo {
12592f345d8eSLuigi Rizzo 
126067fd4c9dSJustin Hibbits 	if ((if_getdrvflags(sc->ifp) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
12612f345d8eSLuigi Rizzo 		return;
12622f345d8eSLuigi Rizzo 
12632f345d8eSLuigi Rizzo 	if (!drbr_empty(sc->ifp, wq->br))
1264cbc4d2dbSJohn Baldwin 		taskqueue_enqueue(taskqueue_swi, &wq->txtask);
12652f345d8eSLuigi Rizzo 
12662f345d8eSLuigi Rizzo }
12672f345d8eSLuigi Rizzo 
1268ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
12692f345d8eSLuigi Rizzo static struct mbuf *
oce_tso_setup(POCE_SOFTC sc,struct mbuf ** mpp)12709bd3250aSLuigi Rizzo oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
12712f345d8eSLuigi Rizzo {
12722f345d8eSLuigi Rizzo 	struct mbuf *m;
1273ad512958SBjoern A. Zeeb #ifdef INET
12742f345d8eSLuigi Rizzo 	struct ip *ip;
1275ad512958SBjoern A. Zeeb #endif
1276ad512958SBjoern A. Zeeb #ifdef INET6
12772f345d8eSLuigi Rizzo 	struct ip6_hdr *ip6;
1278ad512958SBjoern A. Zeeb #endif
12792f345d8eSLuigi Rizzo 	struct ether_vlan_header *eh;
12802f345d8eSLuigi Rizzo 	struct tcphdr *th;
12812f345d8eSLuigi Rizzo 	uint16_t etype;
12829bd3250aSLuigi Rizzo 	int total_len = 0, ehdrlen = 0;
12832f345d8eSLuigi Rizzo 
12842f345d8eSLuigi Rizzo 	m = *mpp;
12852f345d8eSLuigi Rizzo 
12862f345d8eSLuigi Rizzo 	if (M_WRITABLE(m) == 0) {
1287c6499eccSGleb Smirnoff 		m = m_dup(*mpp, M_NOWAIT);
12882f345d8eSLuigi Rizzo 		if (!m)
12892f345d8eSLuigi Rizzo 			return NULL;
12902f345d8eSLuigi Rizzo 		m_freem(*mpp);
12912f345d8eSLuigi Rizzo 		*mpp = m;
12922f345d8eSLuigi Rizzo 	}
12932f345d8eSLuigi Rizzo 
12942f345d8eSLuigi Rizzo 	eh = mtod(m, struct ether_vlan_header *);
12952f345d8eSLuigi Rizzo 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
12962f345d8eSLuigi Rizzo 		etype = ntohs(eh->evl_proto);
12972f345d8eSLuigi Rizzo 		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
12982f345d8eSLuigi Rizzo 	} else {
12992f345d8eSLuigi Rizzo 		etype = ntohs(eh->evl_encap_proto);
13002f345d8eSLuigi Rizzo 		ehdrlen = ETHER_HDR_LEN;
13012f345d8eSLuigi Rizzo 	}
13022f345d8eSLuigi Rizzo 
13032f345d8eSLuigi Rizzo 	switch (etype) {
1304ad512958SBjoern A. Zeeb #ifdef INET
13052f345d8eSLuigi Rizzo 	case ETHERTYPE_IP:
13062f345d8eSLuigi Rizzo 		ip = (struct ip *)(m->m_data + ehdrlen);
13072f345d8eSLuigi Rizzo 		if (ip->ip_p != IPPROTO_TCP)
13082f345d8eSLuigi Rizzo 			return NULL;
13092f345d8eSLuigi Rizzo 		th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
13102f345d8eSLuigi Rizzo 
13112f345d8eSLuigi Rizzo 		total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
13122f345d8eSLuigi Rizzo 		break;
1313ad512958SBjoern A. Zeeb #endif
1314ad512958SBjoern A. Zeeb #ifdef INET6
13152f345d8eSLuigi Rizzo 	case ETHERTYPE_IPV6:
13162f345d8eSLuigi Rizzo 		ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
13172f345d8eSLuigi Rizzo 		if (ip6->ip6_nxt != IPPROTO_TCP)
13182f345d8eSLuigi Rizzo 			return NULL;
13192f345d8eSLuigi Rizzo 		th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
13202f345d8eSLuigi Rizzo 
13212f345d8eSLuigi Rizzo 		total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
13222f345d8eSLuigi Rizzo 		break;
1323ad512958SBjoern A. Zeeb #endif
13242f345d8eSLuigi Rizzo 	default:
13252f345d8eSLuigi Rizzo 		return NULL;
13262f345d8eSLuigi Rizzo 	}
13272f345d8eSLuigi Rizzo 
13282f345d8eSLuigi Rizzo 	m = m_pullup(m, total_len);
13292f345d8eSLuigi Rizzo 	*mpp = m;
13302f345d8eSLuigi Rizzo 	return m;
13312f345d8eSLuigi Rizzo }
1332ad512958SBjoern A. Zeeb #endif /* INET6 || INET */
13332f345d8eSLuigi Rizzo 
13342f345d8eSLuigi Rizzo void
oce_tx_task(void * arg,int npending)13352f345d8eSLuigi Rizzo oce_tx_task(void *arg, int npending)
13362f345d8eSLuigi Rizzo {
13372f345d8eSLuigi Rizzo 	struct oce_wq *wq = arg;
13382f345d8eSLuigi Rizzo 	POCE_SOFTC sc = wq->parent;
133967fd4c9dSJustin Hibbits 	if_t ifp = sc->ifp;
13402f345d8eSLuigi Rizzo 	int rc = 0;
13412f345d8eSLuigi Rizzo 
1342291a1934SXin LI 	LOCK(&wq->tx_lock);
13432f345d8eSLuigi Rizzo 	rc = oce_multiq_transmit(ifp, NULL, wq);
13442f345d8eSLuigi Rizzo 	if (rc) {
13452f345d8eSLuigi Rizzo 		device_printf(sc->dev,
13462f345d8eSLuigi Rizzo 				"TX[%d] restart failed\n", wq->queue_index);
13472f345d8eSLuigi Rizzo 	}
13482f345d8eSLuigi Rizzo 	UNLOCK(&wq->tx_lock);
13492f345d8eSLuigi Rizzo }
13502f345d8eSLuigi Rizzo 
13512f345d8eSLuigi Rizzo void
oce_start(if_t ifp)135267fd4c9dSJustin Hibbits oce_start(if_t ifp)
13532f345d8eSLuigi Rizzo {
135467fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
13552f345d8eSLuigi Rizzo 	struct mbuf *m;
13562f345d8eSLuigi Rizzo 	int rc = 0;
13579bd3250aSLuigi Rizzo 	int def_q = 0; /* Defualt tx queue is 0*/
13582f345d8eSLuigi Rizzo 
135967fd4c9dSJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
13602f345d8eSLuigi Rizzo 			IFF_DRV_RUNNING)
13612f345d8eSLuigi Rizzo 		return;
13622f345d8eSLuigi Rizzo 
1363cdaba892SXin LI 	if (!sc->link_status)
1364cdaba892SXin LI 		return;
1365cdaba892SXin LI 
1366b75a7728SConrad Meyer 	while (true) {
136767fd4c9dSJustin Hibbits 		m = if_dequeue(sc->ifp);
13682f345d8eSLuigi Rizzo 		if (m == NULL)
13692f345d8eSLuigi Rizzo 			break;
13709bd3250aSLuigi Rizzo 
13719bd3250aSLuigi Rizzo 		LOCK(&sc->wq[def_q]->tx_lock);
13729bd3250aSLuigi Rizzo 		rc = oce_tx(sc, &m, def_q);
13739bd3250aSLuigi Rizzo 		UNLOCK(&sc->wq[def_q]->tx_lock);
13742f345d8eSLuigi Rizzo 		if (rc) {
13752f345d8eSLuigi Rizzo 			if (m != NULL) {
13769bd3250aSLuigi Rizzo 				sc->wq[def_q]->tx_stats.tx_stops ++;
137767fd4c9dSJustin Hibbits 				if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
137867fd4c9dSJustin Hibbits 				if_sendq_prepend(ifp, m);
13792f345d8eSLuigi Rizzo 				m = NULL;
13802f345d8eSLuigi Rizzo 			}
13812f345d8eSLuigi Rizzo 			break;
13822f345d8eSLuigi Rizzo 		}
1383b75a7728SConrad Meyer 	}
13842f345d8eSLuigi Rizzo }
13852f345d8eSLuigi Rizzo 
13862f345d8eSLuigi Rizzo /* Handle the Completion Queue for transmit */
13872f345d8eSLuigi Rizzo uint16_t
oce_wq_handler(void * arg)13882f345d8eSLuigi Rizzo oce_wq_handler(void *arg)
13892f345d8eSLuigi Rizzo {
13902f345d8eSLuigi Rizzo 	struct oce_wq *wq = (struct oce_wq *)arg;
13912f345d8eSLuigi Rizzo 	POCE_SOFTC sc = wq->parent;
13922f345d8eSLuigi Rizzo 	struct oce_cq *cq = wq->cq;
13932f345d8eSLuigi Rizzo 	struct oce_nic_tx_cqe *cqe;
13942f345d8eSLuigi Rizzo 	int num_cqes = 0;
13952f345d8eSLuigi Rizzo 
1396c2625e6eSJosh Paetzel 	LOCK(&wq->tx_compl_lock);
13972f345d8eSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
13982f345d8eSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
13992f345d8eSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
14002f345d8eSLuigi Rizzo 	while (cqe->u0.dw[3]) {
14012f345d8eSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
14022f345d8eSLuigi Rizzo 
14032f345d8eSLuigi Rizzo 		wq->ring->cidx = cqe->u0.s.wqe_index + 1;
14042f345d8eSLuigi Rizzo 		if (wq->ring->cidx >= wq->ring->num_items)
14052f345d8eSLuigi Rizzo 			wq->ring->cidx -= wq->ring->num_items;
14062f345d8eSLuigi Rizzo 
1407c2625e6eSJosh Paetzel 		oce_process_tx_completion(wq);
14082f345d8eSLuigi Rizzo 		wq->tx_stats.tx_compl++;
14092f345d8eSLuigi Rizzo 		cqe->u0.dw[3] = 0;
14102f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
14112f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
14122f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
14132f345d8eSLuigi Rizzo 		cqe =
14142f345d8eSLuigi Rizzo 		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
14152f345d8eSLuigi Rizzo 		num_cqes++;
14162f345d8eSLuigi Rizzo 	}
14172f345d8eSLuigi Rizzo 
14182f345d8eSLuigi Rizzo 	if (num_cqes)
14192f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
14202f345d8eSLuigi Rizzo 
1421c2625e6eSJosh Paetzel 	UNLOCK(&wq->tx_compl_lock);
1422c2625e6eSJosh Paetzel 	return num_cqes;
14232f345d8eSLuigi Rizzo }
14242f345d8eSLuigi Rizzo 
14252f345d8eSLuigi Rizzo static int
oce_multiq_transmit(if_t ifp,struct mbuf * m,struct oce_wq * wq)142667fd4c9dSJustin Hibbits oce_multiq_transmit(if_t ifp, struct mbuf *m, struct oce_wq *wq)
14272f345d8eSLuigi Rizzo {
142867fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
14292f345d8eSLuigi Rizzo 	int status = 0, queue_index = 0;
14302f345d8eSLuigi Rizzo 	struct mbuf *next = NULL;
14312f345d8eSLuigi Rizzo 	struct buf_ring *br = NULL;
14322f345d8eSLuigi Rizzo 
14332f345d8eSLuigi Rizzo 	br  = wq->br;
14342f345d8eSLuigi Rizzo 	queue_index = wq->queue_index;
14352f345d8eSLuigi Rizzo 
143667fd4c9dSJustin Hibbits 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
14372f345d8eSLuigi Rizzo 		IFF_DRV_RUNNING) {
14382f345d8eSLuigi Rizzo 		if (m != NULL)
14392f345d8eSLuigi Rizzo 			status = drbr_enqueue(ifp, br, m);
14402f345d8eSLuigi Rizzo 		return status;
14412f345d8eSLuigi Rizzo 	}
14422f345d8eSLuigi Rizzo 
1443ded5ea6aSRandall Stewart 	if (m != NULL) {
14442f345d8eSLuigi Rizzo 		if ((status = drbr_enqueue(ifp, br, m)) != 0)
14452f345d8eSLuigi Rizzo 			return status;
1446ded5ea6aSRandall Stewart 	}
1447ded5ea6aSRandall Stewart 	while ((next = drbr_peek(ifp, br)) != NULL) {
14482f345d8eSLuigi Rizzo 		if (oce_tx(sc, &next, queue_index)) {
1449ded5ea6aSRandall Stewart 			if (next == NULL) {
1450ded5ea6aSRandall Stewart 				drbr_advance(ifp, br);
1451ded5ea6aSRandall Stewart 			} else {
1452ded5ea6aSRandall Stewart 				drbr_putback(ifp, br, next);
14532f345d8eSLuigi Rizzo 				wq->tx_stats.tx_stops ++;
145467fd4c9dSJustin Hibbits 				if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
14552f345d8eSLuigi Rizzo 			}
14562f345d8eSLuigi Rizzo 			break;
14572f345d8eSLuigi Rizzo 		}
1458ded5ea6aSRandall Stewart 		drbr_advance(ifp, br);
14592f345d8eSLuigi Rizzo 	}
14602f345d8eSLuigi Rizzo 
1461d398c863SLuigi Rizzo 	return 0;
14622f345d8eSLuigi Rizzo }
14632f345d8eSLuigi Rizzo 
14642f345d8eSLuigi Rizzo /*****************************************************************************
14652f345d8eSLuigi Rizzo  *			    Receive  routines functions 		     *
14662f345d8eSLuigi Rizzo  *****************************************************************************/
14672f345d8eSLuigi Rizzo 
14682f345d8eSLuigi Rizzo static void
oce_correct_header(struct mbuf * m,struct nic_hwlro_cqe_part1 * cqe1,struct nic_hwlro_cqe_part2 * cqe2)1469c2625e6eSJosh Paetzel oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2)
14702f345d8eSLuigi Rizzo {
1471c2625e6eSJosh Paetzel 	uint32_t *p;
1472c2625e6eSJosh Paetzel         struct ether_header *eh = NULL;
1473c2625e6eSJosh Paetzel         struct tcphdr *tcp_hdr = NULL;
1474c2625e6eSJosh Paetzel         struct ip *ip4_hdr = NULL;
1475c2625e6eSJosh Paetzel         struct ip6_hdr *ip6 = NULL;
1476c2625e6eSJosh Paetzel         uint32_t payload_len = 0;
1477c2625e6eSJosh Paetzel 
1478c2625e6eSJosh Paetzel         eh = mtod(m, struct ether_header *);
1479c2625e6eSJosh Paetzel         /* correct IP header */
1480c2625e6eSJosh Paetzel         if(!cqe2->ipv6_frame) {
1481c2625e6eSJosh Paetzel 		ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header));
1482c2625e6eSJosh Paetzel                 ip4_hdr->ip_ttl = cqe2->frame_lifespan;
1483c2625e6eSJosh Paetzel                 ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header));
1484c2625e6eSJosh Paetzel                 tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip));
1485c2625e6eSJosh Paetzel         }else {
1486c2625e6eSJosh Paetzel         	ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header));
1487c2625e6eSJosh Paetzel                 ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan;
1488c2625e6eSJosh Paetzel                 payload_len = cqe2->coalesced_size - sizeof(struct ether_header)
1489c2625e6eSJosh Paetzel                                                 - sizeof(struct ip6_hdr);
1490c2625e6eSJosh Paetzel                 ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len);
1491c2625e6eSJosh Paetzel                 tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr));
1492c2625e6eSJosh Paetzel         }
1493c2625e6eSJosh Paetzel 
1494c2625e6eSJosh Paetzel         /* correct tcp header */
1495c2625e6eSJosh Paetzel         tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num);
1496c2625e6eSJosh Paetzel         if(cqe2->push) {
1497c2625e6eSJosh Paetzel         	tcp_hdr->th_flags |= TH_PUSH;
1498c2625e6eSJosh Paetzel         }
1499c2625e6eSJosh Paetzel         tcp_hdr->th_win = htons(cqe2->tcp_window);
1500c2625e6eSJosh Paetzel         tcp_hdr->th_sum = 0xffff;
1501c2625e6eSJosh Paetzel         if(cqe2->ts_opt) {
1502c2625e6eSJosh Paetzel                 p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2);
1503c2625e6eSJosh Paetzel                 *p = cqe1->tcp_timestamp_val;
1504c2625e6eSJosh Paetzel                 *(p+1) = cqe1->tcp_timestamp_ecr;
1505c2625e6eSJosh Paetzel         }
1506c2625e6eSJosh Paetzel 
1507c2625e6eSJosh Paetzel 	return;
1508c2625e6eSJosh Paetzel }
1509c2625e6eSJosh Paetzel 
1510c2625e6eSJosh Paetzel static void
oce_rx_mbuf_chain(struct oce_rq * rq,struct oce_common_cqe_info * cqe_info,struct mbuf ** m)1511c2625e6eSJosh Paetzel oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m)
1512c2625e6eSJosh Paetzel {
1513764c812dSJosh Paetzel 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1514c2625e6eSJosh Paetzel         uint32_t i = 0, frag_len = 0;
1515c2625e6eSJosh Paetzel 	uint32_t len = cqe_info->pkt_size;
1516c2625e6eSJosh Paetzel         struct oce_packet_desc *pd;
1517c2625e6eSJosh Paetzel         struct mbuf *tail = NULL;
1518764c812dSJosh Paetzel 
1519c2625e6eSJosh Paetzel         for (i = 0; i < cqe_info->num_frags; i++) {
1520c2625e6eSJosh Paetzel                 if (rq->ring->cidx == rq->ring->pidx) {
152114410265SConrad Meyer                         device_printf(sc->dev,
1522c2625e6eSJosh Paetzel                                   "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n");
1523c2625e6eSJosh Paetzel                         return;
152414410265SConrad Meyer                 }
1525c2625e6eSJosh Paetzel                 pd = &rq->pckts[rq->ring->cidx];
152614410265SConrad Meyer 
152714410265SConrad Meyer                 bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
152814410265SConrad Meyer                 bus_dmamap_unload(rq->tag, pd->map);
1529c2625e6eSJosh Paetzel 		RING_GET(rq->ring, 1);
153014410265SConrad Meyer                 rq->pending--;
153114410265SConrad Meyer 
153214410265SConrad Meyer                 frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
153314410265SConrad Meyer                 pd->mbuf->m_len = frag_len;
153414410265SConrad Meyer 
153514410265SConrad Meyer                 if (tail != NULL) {
153614410265SConrad Meyer                         /* additional fragments */
153714410265SConrad Meyer                         pd->mbuf->m_flags &= ~M_PKTHDR;
153814410265SConrad Meyer                         tail->m_next = pd->mbuf;
1539c2625e6eSJosh Paetzel 			if(rq->islro)
1540c2625e6eSJosh Paetzel                         	tail->m_nextpkt = NULL;
154114410265SConrad Meyer                         tail = pd->mbuf;
154214410265SConrad Meyer                 } else {
154314410265SConrad Meyer                         /* first fragment, fill out much of the packet header */
154414410265SConrad Meyer                         pd->mbuf->m_pkthdr.len = len;
1545c2625e6eSJosh Paetzel 			if(rq->islro)
1546c2625e6eSJosh Paetzel                         	pd->mbuf->m_nextpkt = NULL;
154714410265SConrad Meyer                         pd->mbuf->m_pkthdr.csum_flags = 0;
154814410265SConrad Meyer                         if (IF_CSUM_ENABLED(sc)) {
1549c2625e6eSJosh Paetzel                                 if (cqe_info->l4_cksum_pass) {
1550c2625e6eSJosh Paetzel                                         if(!cqe_info->ipv6_frame) { /* IPV4 */
155114410265SConrad Meyer                                                 pd->mbuf->m_pkthdr.csum_flags |=
155214410265SConrad Meyer                                                         (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1553c2625e6eSJosh Paetzel                                         }else { /* IPV6 frame */
1554c2625e6eSJosh Paetzel 						if(rq->islro) {
1555c2625e6eSJosh Paetzel                                                 	pd->mbuf->m_pkthdr.csum_flags |=
1556c2625e6eSJosh Paetzel                                                         (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1557c2625e6eSJosh Paetzel 						}
1558c2625e6eSJosh Paetzel                                         }
155914410265SConrad Meyer                                         pd->mbuf->m_pkthdr.csum_data = 0xffff;
156014410265SConrad Meyer                                 }
1561c2625e6eSJosh Paetzel                                 if (cqe_info->ip_cksum_pass) {
156214410265SConrad Meyer                                         pd->mbuf->m_pkthdr.csum_flags |=
156314410265SConrad Meyer                                                (CSUM_IP_CHECKED|CSUM_IP_VALID);
156414410265SConrad Meyer                                 }
156514410265SConrad Meyer                         }
1566c2625e6eSJosh Paetzel                         *m = tail = pd->mbuf;
156714410265SConrad Meyer                }
156814410265SConrad Meyer                 pd->mbuf = NULL;
156914410265SConrad Meyer                 len -= frag_len;
157014410265SConrad Meyer         }
1571764c812dSJosh Paetzel 
1572c2625e6eSJosh Paetzel         return;
1573c2625e6eSJosh Paetzel }
1574c2625e6eSJosh Paetzel 
1575c2625e6eSJosh Paetzel static void
oce_rx_lro(struct oce_rq * rq,struct nic_hwlro_singleton_cqe * cqe,struct nic_hwlro_cqe_part2 * cqe2)1576c2625e6eSJosh Paetzel oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2)
1577c2625e6eSJosh Paetzel {
1578c2625e6eSJosh Paetzel         POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1579c2625e6eSJosh Paetzel         struct nic_hwlro_cqe_part1 *cqe1 = NULL;
1580c2625e6eSJosh Paetzel         struct mbuf *m = NULL;
1581c2625e6eSJosh Paetzel 	struct oce_common_cqe_info cq_info;
1582c2625e6eSJosh Paetzel 
1583c2625e6eSJosh Paetzel 	/* parse cqe */
1584c2625e6eSJosh Paetzel         if(cqe2 == NULL) {
1585c2625e6eSJosh Paetzel                 cq_info.pkt_size =  cqe->pkt_size;
1586c2625e6eSJosh Paetzel                 cq_info.vtag = cqe->vlan_tag;
1587c2625e6eSJosh Paetzel                 cq_info.l4_cksum_pass = cqe->l4_cksum_pass;
1588c2625e6eSJosh Paetzel                 cq_info.ip_cksum_pass = cqe->ip_cksum_pass;
1589c2625e6eSJosh Paetzel                 cq_info.ipv6_frame = cqe->ipv6_frame;
1590c2625e6eSJosh Paetzel                 cq_info.vtp = cqe->vtp;
1591c2625e6eSJosh Paetzel                 cq_info.qnq = cqe->qnq;
1592c2625e6eSJosh Paetzel         }else {
1593c2625e6eSJosh Paetzel                 cqe1 = (struct nic_hwlro_cqe_part1 *)cqe;
1594c2625e6eSJosh Paetzel                 cq_info.pkt_size =  cqe2->coalesced_size;
1595c2625e6eSJosh Paetzel                 cq_info.vtag = cqe2->vlan_tag;
1596c2625e6eSJosh Paetzel                 cq_info.l4_cksum_pass = cqe2->l4_cksum_pass;
1597c2625e6eSJosh Paetzel                 cq_info.ip_cksum_pass = cqe2->ip_cksum_pass;
1598c2625e6eSJosh Paetzel                 cq_info.ipv6_frame = cqe2->ipv6_frame;
1599c2625e6eSJosh Paetzel                 cq_info.vtp = cqe2->vtp;
1600c2625e6eSJosh Paetzel                 cq_info.qnq = cqe1->qnq;
1601c2625e6eSJosh Paetzel         }
1602c2625e6eSJosh Paetzel 
1603c2625e6eSJosh Paetzel 	cq_info.vtag = BSWAP_16(cq_info.vtag);
1604c2625e6eSJosh Paetzel 
1605c2625e6eSJosh Paetzel         cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size;
1606c2625e6eSJosh Paetzel         if(cq_info.pkt_size % rq->cfg.frag_size)
1607c2625e6eSJosh Paetzel                 cq_info.num_frags++;
1608c2625e6eSJosh Paetzel 
1609c2625e6eSJosh Paetzel 	oce_rx_mbuf_chain(rq, &cq_info, &m);
1610c2625e6eSJosh Paetzel 
1611764c812dSJosh Paetzel 	if (m) {
1612c2625e6eSJosh Paetzel 		if(cqe2) {
1613c2625e6eSJosh Paetzel 			//assert(cqe2->valid != 0);
1614c2625e6eSJosh Paetzel 
1615c2625e6eSJosh Paetzel 			//assert(cqe2->cqe_type != 2);
1616c2625e6eSJosh Paetzel 			oce_correct_header(m, cqe1, cqe2);
1617c2625e6eSJosh Paetzel 		}
1618c2625e6eSJosh Paetzel 
1619c2625e6eSJosh Paetzel 		m->m_pkthdr.rcvif = sc->ifp;
1620c2625e6eSJosh Paetzel 		if (rq->queue_index)
1621c2625e6eSJosh Paetzel 			m->m_pkthdr.flowid = (rq->queue_index - 1);
1622c2625e6eSJosh Paetzel 		else
1623c2625e6eSJosh Paetzel 			m->m_pkthdr.flowid = rq->queue_index;
1624c2625e6eSJosh Paetzel 		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1625a9208e98SWarner Losh 
1626c2625e6eSJosh Paetzel 		/* This deternies if vlan tag is Valid */
1627c2625e6eSJosh Paetzel 		if (cq_info.vtp) {
1628c2625e6eSJosh Paetzel 			if (sc->function_mode & FNM_FLEX10_MODE) {
1629c2625e6eSJosh Paetzel 				/* FLEX10. If QnQ is not set, neglect VLAN */
1630c2625e6eSJosh Paetzel 				if (cq_info.qnq) {
1631c2625e6eSJosh Paetzel 					m->m_pkthdr.ether_vtag = cq_info.vtag;
1632c2625e6eSJosh Paetzel 					m->m_flags |= M_VLANTAG;
1633c2625e6eSJosh Paetzel 				}
1634c2625e6eSJosh Paetzel 			} else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK))  {
1635c2625e6eSJosh Paetzel 				/* In UMC mode generally pvid will be striped by
1636c2625e6eSJosh Paetzel 				   hw. But in some cases we have seen it comes
1637c2625e6eSJosh Paetzel 				   with pvid. So if pvid == vlan, neglect vlan.
1638c2625e6eSJosh Paetzel 				 */
1639c2625e6eSJosh Paetzel 				m->m_pkthdr.ether_vtag = cq_info.vtag;
1640c2625e6eSJosh Paetzel 				m->m_flags |= M_VLANTAG;
1641c2625e6eSJosh Paetzel 			}
1642c2625e6eSJosh Paetzel 		}
1643c2625e6eSJosh Paetzel 		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1644c2625e6eSJosh Paetzel 
164567fd4c9dSJustin Hibbits 		if_input(sc->ifp, m);
1646c2625e6eSJosh Paetzel 
1647c2625e6eSJosh Paetzel 		/* Update rx stats per queue */
1648c2625e6eSJosh Paetzel 		rq->rx_stats.rx_pkts++;
1649c2625e6eSJosh Paetzel 		rq->rx_stats.rx_bytes += cq_info.pkt_size;
1650c2625e6eSJosh Paetzel 		rq->rx_stats.rx_frags += cq_info.num_frags;
1651c2625e6eSJosh Paetzel 		rq->rx_stats.rx_ucast_pkts++;
1652c2625e6eSJosh Paetzel 	}
1653c2625e6eSJosh Paetzel         return;
1654c2625e6eSJosh Paetzel }
1655c2625e6eSJosh Paetzel 
1656c2625e6eSJosh Paetzel static void
oce_rx(struct oce_rq * rq,struct oce_nic_rx_cqe * cqe)1657c2625e6eSJosh Paetzel oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
1658c2625e6eSJosh Paetzel {
1659c2625e6eSJosh Paetzel 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1660c2625e6eSJosh Paetzel 	int len;
1661c2625e6eSJosh Paetzel 	struct mbuf *m = NULL;
1662c2625e6eSJosh Paetzel 	struct oce_common_cqe_info cq_info;
1663c2625e6eSJosh Paetzel 	uint16_t vtag = 0;
1664c2625e6eSJosh Paetzel 
1665c2625e6eSJosh Paetzel 	/* Is it a flush compl that has no data */
1666c2625e6eSJosh Paetzel 	if(!cqe->u0.s.num_fragments)
1667c2625e6eSJosh Paetzel 		goto exit;
1668c2625e6eSJosh Paetzel 
1669c2625e6eSJosh Paetzel 	len = cqe->u0.s.pkt_size;
1670c2625e6eSJosh Paetzel 	if (!len) {
1671c2625e6eSJosh Paetzel 		/*partial DMA workaround for Lancer*/
1672c2625e6eSJosh Paetzel 		oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
167314410265SConrad Meyer 		goto exit;
167414410265SConrad Meyer 	}
167514410265SConrad Meyer 
1676c2625e6eSJosh Paetzel 	if (!oce_cqe_portid_valid(sc, cqe)) {
1677c2625e6eSJosh Paetzel 		oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
1678c2625e6eSJosh Paetzel 		goto exit;
1679c2625e6eSJosh Paetzel 	}
1680c2625e6eSJosh Paetzel 
1681c2625e6eSJosh Paetzel 	 /* Get vlan_tag value */
1682c2625e6eSJosh Paetzel 	if(IS_BE(sc) || IS_SH(sc))
1683c2625e6eSJosh Paetzel 		vtag = BSWAP_16(cqe->u0.s.vlan_tag);
1684c2625e6eSJosh Paetzel 	else
1685c2625e6eSJosh Paetzel 		vtag = cqe->u0.s.vlan_tag;
1686c2625e6eSJosh Paetzel 
1687c2625e6eSJosh Paetzel 	cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass;
1688c2625e6eSJosh Paetzel 	cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass;
1689c2625e6eSJosh Paetzel 	cq_info.ipv6_frame = cqe->u0.s.ip_ver;
1690c2625e6eSJosh Paetzel 	cq_info.num_frags = cqe->u0.s.num_fragments;
1691c2625e6eSJosh Paetzel 	cq_info.pkt_size = cqe->u0.s.pkt_size;
1692c2625e6eSJosh Paetzel 
1693c2625e6eSJosh Paetzel 	oce_rx_mbuf_chain(rq, &cq_info, &m);
1694c2625e6eSJosh Paetzel 
1695c2625e6eSJosh Paetzel 	if (m) {
16962f345d8eSLuigi Rizzo 		m->m_pkthdr.rcvif = sc->ifp;
1697291a1934SXin LI 		if (rq->queue_index)
1698291a1934SXin LI 			m->m_pkthdr.flowid = (rq->queue_index - 1);
1699291a1934SXin LI 		else
17002f345d8eSLuigi Rizzo 			m->m_pkthdr.flowid = rq->queue_index;
1701c2529042SHans Petter Selasky 		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1702a9208e98SWarner Losh 
17039bd3250aSLuigi Rizzo 		/* This deternies if vlan tag is Valid */
17042f345d8eSLuigi Rizzo 		if (oce_cqe_vtp_valid(sc, cqe)) {
17052f345d8eSLuigi Rizzo 			if (sc->function_mode & FNM_FLEX10_MODE) {
17069bd3250aSLuigi Rizzo 				/* FLEX10. If QnQ is not set, neglect VLAN */
17072f345d8eSLuigi Rizzo 				if (cqe->u0.s.qnq) {
17082f345d8eSLuigi Rizzo 					m->m_pkthdr.ether_vtag = vtag;
17092f345d8eSLuigi Rizzo 					m->m_flags |= M_VLANTAG;
17102f345d8eSLuigi Rizzo 				}
17119bd3250aSLuigi Rizzo 			} else if (sc->pvid != (vtag & VLAN_VID_MASK))  {
17129bd3250aSLuigi Rizzo 				/* In UMC mode generally pvid will be striped by
17139bd3250aSLuigi Rizzo 				   hw. But in some cases we have seen it comes
17149bd3250aSLuigi Rizzo 				   with pvid. So if pvid == vlan, neglect vlan.
17159bd3250aSLuigi Rizzo 				*/
17162f345d8eSLuigi Rizzo 				m->m_pkthdr.ether_vtag = vtag;
17172f345d8eSLuigi Rizzo 				m->m_flags |= M_VLANTAG;
17182f345d8eSLuigi Rizzo 			}
17192f345d8eSLuigi Rizzo 		}
17202f345d8eSLuigi Rizzo 
1721c8dfaf38SGleb Smirnoff 		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1722ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
17232f345d8eSLuigi Rizzo 		/* Try to queue to LRO */
17242f345d8eSLuigi Rizzo 		if (IF_LRO_ENABLED(sc) &&
17252f345d8eSLuigi Rizzo 		    (cqe->u0.s.ip_cksum_pass) &&
17262f345d8eSLuigi Rizzo 		    (cqe->u0.s.l4_cksum_pass) &&
17272f345d8eSLuigi Rizzo 		    (!cqe->u0.s.ip_ver)       &&
17282f345d8eSLuigi Rizzo 		    (rq->lro.lro_cnt != 0)) {
17292f345d8eSLuigi Rizzo 			if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
17302f345d8eSLuigi Rizzo 				rq->lro_pkts_queued ++;
17312f345d8eSLuigi Rizzo 				goto post_done;
17322f345d8eSLuigi Rizzo 			}
17332f345d8eSLuigi Rizzo 			/* If LRO posting fails then try to post to STACK */
17342f345d8eSLuigi Rizzo 		}
1735ad512958SBjoern A. Zeeb #endif
17362f345d8eSLuigi Rizzo 
173767fd4c9dSJustin Hibbits 		if_input(sc->ifp, m);
1738ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
17392f345d8eSLuigi Rizzo post_done:
1740ad512958SBjoern A. Zeeb #endif
17412f345d8eSLuigi Rizzo 		/* Update rx stats per queue */
17422f345d8eSLuigi Rizzo 		rq->rx_stats.rx_pkts++;
17432f345d8eSLuigi Rizzo 		rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
17442f345d8eSLuigi Rizzo 		rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
17452f345d8eSLuigi Rizzo 		if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
17462f345d8eSLuigi Rizzo 			rq->rx_stats.rx_mcast_pkts++;
17472f345d8eSLuigi Rizzo 		if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
17482f345d8eSLuigi Rizzo 			rq->rx_stats.rx_ucast_pkts++;
17492f345d8eSLuigi Rizzo 	}
17502f345d8eSLuigi Rizzo exit:
17512f345d8eSLuigi Rizzo 	return;
17522f345d8eSLuigi Rizzo }
17532f345d8eSLuigi Rizzo 
1754c2625e6eSJosh Paetzel void
oce_discard_rx_comp(struct oce_rq * rq,int num_frags)1755c2625e6eSJosh Paetzel oce_discard_rx_comp(struct oce_rq *rq, int num_frags)
17562f345d8eSLuigi Rizzo {
1757c2625e6eSJosh Paetzel 	uint32_t i = 0;
17582f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
17592f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
17602f345d8eSLuigi Rizzo 
17612f345d8eSLuigi Rizzo 	for (i = 0; i < num_frags; i++) {
1762c2625e6eSJosh Paetzel                 if (rq->ring->cidx == rq->ring->pidx) {
17632f345d8eSLuigi Rizzo                         device_printf(sc->dev,
1764c2625e6eSJosh Paetzel                                 "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n");
1765c2625e6eSJosh Paetzel                         return;
17662f345d8eSLuigi Rizzo                 }
1767c2625e6eSJosh Paetzel                 pd = &rq->pckts[rq->ring->cidx];
17682f345d8eSLuigi Rizzo                 bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
17692f345d8eSLuigi Rizzo                 bus_dmamap_unload(rq->tag, pd->map);
1770c2625e6eSJosh Paetzel                 if (pd->mbuf != NULL) {
17712f345d8eSLuigi Rizzo                         m_freem(pd->mbuf);
1772c2625e6eSJosh Paetzel                         pd->mbuf = NULL;
17732f345d8eSLuigi Rizzo                 }
17742f345d8eSLuigi Rizzo 
1775c2625e6eSJosh Paetzel 		RING_GET(rq->ring, 1);
1776c2625e6eSJosh Paetzel                 rq->pending--;
1777c2625e6eSJosh Paetzel 	}
17782f345d8eSLuigi Rizzo }
17792f345d8eSLuigi Rizzo 
17802f345d8eSLuigi Rizzo static int
oce_cqe_vtp_valid(POCE_SOFTC sc,struct oce_nic_rx_cqe * cqe)17812f345d8eSLuigi Rizzo oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
17822f345d8eSLuigi Rizzo {
17832f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe_v1 *cqe_v1;
17842f345d8eSLuigi Rizzo 	int vtp = 0;
17852f345d8eSLuigi Rizzo 
17862f345d8eSLuigi Rizzo 	if (sc->be3_native) {
17872f345d8eSLuigi Rizzo 		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
17882f345d8eSLuigi Rizzo 		vtp =  cqe_v1->u0.s.vlan_tag_present;
17899bd3250aSLuigi Rizzo 	} else
17902f345d8eSLuigi Rizzo 		vtp = cqe->u0.s.vlan_tag_present;
17912f345d8eSLuigi Rizzo 
17922f345d8eSLuigi Rizzo 	return vtp;
17932f345d8eSLuigi Rizzo 
17942f345d8eSLuigi Rizzo }
17952f345d8eSLuigi Rizzo 
17962f345d8eSLuigi Rizzo static int
oce_cqe_portid_valid(POCE_SOFTC sc,struct oce_nic_rx_cqe * cqe)17972f345d8eSLuigi Rizzo oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
17982f345d8eSLuigi Rizzo {
17992f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe_v1 *cqe_v1;
18002f345d8eSLuigi Rizzo 	int port_id = 0;
18012f345d8eSLuigi Rizzo 
1802291a1934SXin LI 	if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) {
18032f345d8eSLuigi Rizzo 		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
18042f345d8eSLuigi Rizzo 		port_id =  cqe_v1->u0.s.port;
18052f345d8eSLuigi Rizzo 		if (sc->port_id != port_id)
18062f345d8eSLuigi Rizzo 			return 0;
18072f345d8eSLuigi Rizzo 	} else
18082f345d8eSLuigi Rizzo 		;/* For BE3 legacy and Lancer this is dummy */
18092f345d8eSLuigi Rizzo 
18102f345d8eSLuigi Rizzo 	return 1;
18112f345d8eSLuigi Rizzo 
18122f345d8eSLuigi Rizzo }
18132f345d8eSLuigi Rizzo 
1814ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
1815c2625e6eSJosh Paetzel void
oce_rx_flush_lro(struct oce_rq * rq)18162f345d8eSLuigi Rizzo oce_rx_flush_lro(struct oce_rq *rq)
18172f345d8eSLuigi Rizzo {
18182f345d8eSLuigi Rizzo 	struct lro_ctrl	*lro = &rq->lro;
18192f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
18202f345d8eSLuigi Rizzo 
18212f345d8eSLuigi Rizzo 	if (!IF_LRO_ENABLED(sc))
18222f345d8eSLuigi Rizzo 		return;
18232f345d8eSLuigi Rizzo 
18246dd38b87SSepherosa Ziehau 	tcp_lro_flush_all(lro);
18252f345d8eSLuigi Rizzo 	rq->lro_pkts_queued = 0;
18262f345d8eSLuigi Rizzo 
18272f345d8eSLuigi Rizzo 	return;
18282f345d8eSLuigi Rizzo }
18292f345d8eSLuigi Rizzo 
18302f345d8eSLuigi Rizzo static int
oce_init_lro(POCE_SOFTC sc)18312f345d8eSLuigi Rizzo oce_init_lro(POCE_SOFTC sc)
18322f345d8eSLuigi Rizzo {
18332f345d8eSLuigi Rizzo 	struct lro_ctrl *lro = NULL;
18342f345d8eSLuigi Rizzo 	int i = 0, rc = 0;
18352f345d8eSLuigi Rizzo 
18362f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nrqs; i++) {
18372f345d8eSLuigi Rizzo 		lro = &sc->rq[i]->lro;
18382f345d8eSLuigi Rizzo 		rc = tcp_lro_init(lro);
18392f345d8eSLuigi Rizzo 		if (rc != 0) {
18402f345d8eSLuigi Rizzo 			device_printf(sc->dev, "LRO init failed\n");
18412f345d8eSLuigi Rizzo 			return rc;
18422f345d8eSLuigi Rizzo 		}
18432f345d8eSLuigi Rizzo 		lro->ifp = sc->ifp;
18442f345d8eSLuigi Rizzo 	}
18452f345d8eSLuigi Rizzo 
18462f345d8eSLuigi Rizzo 	return rc;
18472f345d8eSLuigi Rizzo }
18489bd3250aSLuigi Rizzo 
18492f345d8eSLuigi Rizzo void
oce_free_lro(POCE_SOFTC sc)18502f345d8eSLuigi Rizzo oce_free_lro(POCE_SOFTC sc)
18512f345d8eSLuigi Rizzo {
18522f345d8eSLuigi Rizzo 	struct lro_ctrl *lro = NULL;
18532f345d8eSLuigi Rizzo 	int i = 0;
18542f345d8eSLuigi Rizzo 
18552f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nrqs; i++) {
18562f345d8eSLuigi Rizzo 		lro = &sc->rq[i]->lro;
18572f345d8eSLuigi Rizzo 		if (lro)
18582f345d8eSLuigi Rizzo 			tcp_lro_free(lro);
18592f345d8eSLuigi Rizzo 	}
18602f345d8eSLuigi Rizzo }
1861cdaba892SXin LI #endif
18622f345d8eSLuigi Rizzo 
18632f345d8eSLuigi Rizzo int
oce_alloc_rx_bufs(struct oce_rq * rq,int count)18642f345d8eSLuigi Rizzo oce_alloc_rx_bufs(struct oce_rq *rq, int count)
18652f345d8eSLuigi Rizzo {
18662f345d8eSLuigi Rizzo 	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
186719c099a8SJohn Baldwin 	int i, rc;
18682f345d8eSLuigi Rizzo 	struct oce_packet_desc *pd;
18692f345d8eSLuigi Rizzo 	bus_dma_segment_t segs[6];
18702f345d8eSLuigi Rizzo 	int nsegs, added = 0;
18712f345d8eSLuigi Rizzo 	struct oce_nic_rqe *rqe;
18722f345d8eSLuigi Rizzo 	pd_rxulp_db_t rxdb_reg;
1873c2625e6eSJosh Paetzel 	uint32_t val = 0;
1874c2625e6eSJosh Paetzel 	uint32_t oce_max_rq_posts = 64;
18752f345d8eSLuigi Rizzo 
1876cdaba892SXin LI 	bzero(&rxdb_reg, sizeof(pd_rxulp_db_t));
18772f345d8eSLuigi Rizzo 	for (i = 0; i < count; i++) {
1878c2625e6eSJosh Paetzel 		pd = &rq->pckts[rq->ring->pidx];
1879c2625e6eSJosh Paetzel 		pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size);
1880c2625e6eSJosh Paetzel 		if (pd->mbuf == NULL) {
1881c2625e6eSJosh Paetzel 			device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size);
18822f345d8eSLuigi Rizzo 			break;
1883c2625e6eSJosh Paetzel 		}
1884c2625e6eSJosh Paetzel 		pd->mbuf->m_nextpkt = NULL;
18852f345d8eSLuigi Rizzo 
1886c2625e6eSJosh Paetzel 		pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size;
1887c2625e6eSJosh Paetzel 
18882f345d8eSLuigi Rizzo 		rc = bus_dmamap_load_mbuf_sg(rq->tag,
18892f345d8eSLuigi Rizzo 					     pd->map,
18902f345d8eSLuigi Rizzo 					     pd->mbuf,
18912f345d8eSLuigi Rizzo 					     segs, &nsegs, BUS_DMA_NOWAIT);
18922f345d8eSLuigi Rizzo 		if (rc) {
18932f345d8eSLuigi Rizzo 			m_free(pd->mbuf);
1894c2625e6eSJosh Paetzel 			device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc);
18952f345d8eSLuigi Rizzo 			break;
18962f345d8eSLuigi Rizzo 		}
18972f345d8eSLuigi Rizzo 
18982f345d8eSLuigi Rizzo 		if (nsegs != 1) {
18992f345d8eSLuigi Rizzo 			i--;
19002f345d8eSLuigi Rizzo 			continue;
19012f345d8eSLuigi Rizzo 		}
19022f345d8eSLuigi Rizzo 
19032f345d8eSLuigi Rizzo 		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
19042f345d8eSLuigi Rizzo 
19052f345d8eSLuigi Rizzo 		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
19062f345d8eSLuigi Rizzo 		rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
19072f345d8eSLuigi Rizzo 		rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
19082f345d8eSLuigi Rizzo 		DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
19092f345d8eSLuigi Rizzo 		RING_PUT(rq->ring, 1);
19102f345d8eSLuigi Rizzo 		added++;
19112f345d8eSLuigi Rizzo 		rq->pending++;
19122f345d8eSLuigi Rizzo 	}
1913c2625e6eSJosh Paetzel 	oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS;
19142f345d8eSLuigi Rizzo 	if (added != 0) {
1915c2625e6eSJosh Paetzel 		for (i = added / oce_max_rq_posts; i > 0; i--) {
1916c2625e6eSJosh Paetzel 			rxdb_reg.bits.num_posted = oce_max_rq_posts;
19172f345d8eSLuigi Rizzo 			rxdb_reg.bits.qid = rq->rq_id;
1918c2625e6eSJosh Paetzel 			if(rq->islro) {
1919c2625e6eSJosh Paetzel                                 val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1920c2625e6eSJosh Paetzel                                 val |= oce_max_rq_posts << 16;
1921c2625e6eSJosh Paetzel                                 OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
1922c2625e6eSJosh Paetzel 			}else {
19232f345d8eSLuigi Rizzo 				OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1924c2625e6eSJosh Paetzel 			}
1925c2625e6eSJosh Paetzel 			added -= oce_max_rq_posts;
19262f345d8eSLuigi Rizzo 		}
19272f345d8eSLuigi Rizzo 		if (added > 0) {
19282f345d8eSLuigi Rizzo 			rxdb_reg.bits.qid = rq->rq_id;
19292f345d8eSLuigi Rizzo 			rxdb_reg.bits.num_posted = added;
1930c2625e6eSJosh Paetzel 			if(rq->islro) {
1931c2625e6eSJosh Paetzel                                 val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1932c2625e6eSJosh Paetzel                                 val |= added << 16;
1933c2625e6eSJosh Paetzel                                 OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
1934c2625e6eSJosh Paetzel 			}else {
19352f345d8eSLuigi Rizzo 				OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
19362f345d8eSLuigi Rizzo 			}
19372f345d8eSLuigi Rizzo 		}
1938c2625e6eSJosh Paetzel 	}
19392f345d8eSLuigi Rizzo 
19402f345d8eSLuigi Rizzo 	return 0;
19412f345d8eSLuigi Rizzo }
19422f345d8eSLuigi Rizzo 
1943c2625e6eSJosh Paetzel static void
oce_check_rx_bufs(POCE_SOFTC sc,uint32_t num_cqes,struct oce_rq * rq)1944c2625e6eSJosh Paetzel oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq)
1945c2625e6eSJosh Paetzel {
1946c2625e6eSJosh Paetzel         if (num_cqes) {
1947c2625e6eSJosh Paetzel                 oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE);
1948c2625e6eSJosh Paetzel 		if(!sc->enable_hwlro) {
1949c2625e6eSJosh Paetzel 			if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1)
1950c2625e6eSJosh Paetzel 				oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1));
1951c2625e6eSJosh Paetzel 		}else {
1952c2625e6eSJosh Paetzel                 	if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64)
1953c2625e6eSJosh Paetzel                         	oce_alloc_rx_bufs(rq, 64);
1954c2625e6eSJosh Paetzel         	}
1955c2625e6eSJosh Paetzel 	}
1956c2625e6eSJosh Paetzel 
1957c2625e6eSJosh Paetzel         return;
1958c2625e6eSJosh Paetzel }
1959c2625e6eSJosh Paetzel 
1960c2625e6eSJosh Paetzel uint16_t
oce_rq_handler_lro(void * arg)1961c2625e6eSJosh Paetzel oce_rq_handler_lro(void *arg)
1962c2625e6eSJosh Paetzel {
1963c2625e6eSJosh Paetzel         struct oce_rq *rq = (struct oce_rq *)arg;
1964c2625e6eSJosh Paetzel         struct oce_cq *cq = rq->cq;
1965c2625e6eSJosh Paetzel         POCE_SOFTC sc = rq->parent;
1966c2625e6eSJosh Paetzel         struct nic_hwlro_singleton_cqe *cqe;
1967c2625e6eSJosh Paetzel         struct nic_hwlro_cqe_part2 *cqe2;
1968c2625e6eSJosh Paetzel         int num_cqes = 0;
1969c2625e6eSJosh Paetzel 
1970c2625e6eSJosh Paetzel 	LOCK(&rq->rx_lock);
1971c2625e6eSJosh Paetzel         bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1972c2625e6eSJosh Paetzel         cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
1973c2625e6eSJosh Paetzel         while (cqe->valid) {
1974c2625e6eSJosh Paetzel                 if(cqe->cqe_type == 0) { /* singleton cqe */
1975c2625e6eSJosh Paetzel 			/* we should not get singleton cqe after cqe1 on same rq */
1976c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart != NULL) {
1977c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got singleton cqe after cqe1 \n");
1978c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
1979c2625e6eSJosh Paetzel 			}
1980c2625e6eSJosh Paetzel                         if(cqe->error != 0) {
1981c2625e6eSJosh Paetzel                                 rq->rx_stats.rxcp_err++;
1982c2625e6eSJosh Paetzel 				if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
1983c2625e6eSJosh Paetzel                         }
1984c2625e6eSJosh Paetzel                         oce_rx_lro(rq, cqe, NULL);
1985c2625e6eSJosh Paetzel                         rq->rx_stats.rx_compl++;
1986c2625e6eSJosh Paetzel                         cqe->valid = 0;
1987c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
1988c2625e6eSJosh Paetzel                         num_cqes++;
1989c2625e6eSJosh Paetzel                         if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
1990c2625e6eSJosh Paetzel                                 break;
1991c2625e6eSJosh Paetzel                 }else if(cqe->cqe_type == 0x1) { /* first part */
1992c2625e6eSJosh Paetzel 			/* we should not get cqe1 after cqe1 on same rq */
1993c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart != NULL) {
1994c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got cqe1 after cqe1 \n");
1995c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
1996c2625e6eSJosh Paetzel 			}
1997c2625e6eSJosh Paetzel 			rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe;
1998c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
1999c2625e6eSJosh Paetzel                 }else if(cqe->cqe_type == 0x2) { /* second part */
2000c2625e6eSJosh Paetzel 			cqe2 = (struct nic_hwlro_cqe_part2 *)cqe;
2001c2625e6eSJosh Paetzel                         if(cqe2->error != 0) {
2002c2625e6eSJosh Paetzel                                 rq->rx_stats.rxcp_err++;
2003c2625e6eSJosh Paetzel 				if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
2004c2625e6eSJosh Paetzel                         }
2005c2625e6eSJosh Paetzel 			/* We should not get cqe2 without cqe1 */
2006c2625e6eSJosh Paetzel 			if(rq->cqe_firstpart == NULL) {
2007c2625e6eSJosh Paetzel 				device_printf(sc->dev, "Got cqe2 without cqe1 \n");
2008c2625e6eSJosh Paetzel 				goto exit_rq_handler_lro;
2009c2625e6eSJosh Paetzel 			}
2010c2625e6eSJosh Paetzel                         oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2);
2011c2625e6eSJosh Paetzel 
2012c2625e6eSJosh Paetzel                         rq->rx_stats.rx_compl++;
2013c2625e6eSJosh Paetzel                         rq->cqe_firstpart->valid = 0;
2014c2625e6eSJosh Paetzel                         cqe2->valid = 0;
2015c2625e6eSJosh Paetzel 			rq->cqe_firstpart = NULL;
2016c2625e6eSJosh Paetzel 
2017c2625e6eSJosh Paetzel                         RING_GET(cq->ring, 1);
2018c2625e6eSJosh Paetzel                         num_cqes += 2;
2019c2625e6eSJosh Paetzel                         if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
2020c2625e6eSJosh Paetzel                                 break;
2021c2625e6eSJosh Paetzel 		}
2022c2625e6eSJosh Paetzel 
2023c2625e6eSJosh Paetzel                 bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2024c2625e6eSJosh Paetzel                 cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
2025c2625e6eSJosh Paetzel         }
2026c2625e6eSJosh Paetzel 	oce_check_rx_bufs(sc, num_cqes, rq);
2027c2625e6eSJosh Paetzel exit_rq_handler_lro:
2028c2625e6eSJosh Paetzel 	UNLOCK(&rq->rx_lock);
2029c2625e6eSJosh Paetzel 	return 0;
2030c2625e6eSJosh Paetzel }
20312f345d8eSLuigi Rizzo 
20322f345d8eSLuigi Rizzo /* Handle the Completion Queue for receive */
20332f345d8eSLuigi Rizzo uint16_t
oce_rq_handler(void * arg)20342f345d8eSLuigi Rizzo oce_rq_handler(void *arg)
20352f345d8eSLuigi Rizzo {
2036e363f832SMichael Tuexen 	struct epoch_tracker et;
20372f345d8eSLuigi Rizzo 	struct oce_rq *rq = (struct oce_rq *)arg;
20382f345d8eSLuigi Rizzo 	struct oce_cq *cq = rq->cq;
20392f345d8eSLuigi Rizzo 	POCE_SOFTC sc = rq->parent;
20402f345d8eSLuigi Rizzo 	struct oce_nic_rx_cqe *cqe;
2041c2625e6eSJosh Paetzel 	int num_cqes = 0;
20422f345d8eSLuigi Rizzo 
2043e363f832SMichael Tuexen 	NET_EPOCH_ENTER(et);
2044c2625e6eSJosh Paetzel 	if(rq->islro) {
2045c2625e6eSJosh Paetzel 		oce_rq_handler_lro(arg);
2046e363f832SMichael Tuexen 		NET_EPOCH_EXIT(et);
2047c2625e6eSJosh Paetzel 		return 0;
2048c2625e6eSJosh Paetzel 	}
2049c2625e6eSJosh Paetzel 	LOCK(&rq->rx_lock);
20502f345d8eSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
20512f345d8eSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
20522f345d8eSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
20532f345d8eSLuigi Rizzo 	while (cqe->u0.dw[2]) {
20542f345d8eSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
20552f345d8eSLuigi Rizzo 
20562f345d8eSLuigi Rizzo 		if (cqe->u0.s.error == 0) {
2057c2625e6eSJosh Paetzel 			oce_rx(rq, cqe);
20582f345d8eSLuigi Rizzo 		} else {
20592f345d8eSLuigi Rizzo 			rq->rx_stats.rxcp_err++;
2060c8dfaf38SGleb Smirnoff 			if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
20612f345d8eSLuigi Rizzo 			/* Post L3/L4 errors to stack.*/
2062c2625e6eSJosh Paetzel 			oce_rx(rq, cqe);
20632f345d8eSLuigi Rizzo 		}
20642f345d8eSLuigi Rizzo 		rq->rx_stats.rx_compl++;
20652f345d8eSLuigi Rizzo 		cqe->u0.dw[2] = 0;
20662f345d8eSLuigi Rizzo 
2067ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
20682f345d8eSLuigi Rizzo 		if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
20692f345d8eSLuigi Rizzo 			oce_rx_flush_lro(rq);
20702f345d8eSLuigi Rizzo 		}
2071ad512958SBjoern A. Zeeb #endif
20722f345d8eSLuigi Rizzo 
20732f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
20742f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
20752f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
20762f345d8eSLuigi Rizzo 		cqe =
20772f345d8eSLuigi Rizzo 		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
20782f345d8eSLuigi Rizzo 		num_cqes++;
20792f345d8eSLuigi Rizzo 		if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
20802f345d8eSLuigi Rizzo 			break;
20812f345d8eSLuigi Rizzo 	}
20829bd3250aSLuigi Rizzo 
2083ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
20842f345d8eSLuigi Rizzo         if (IF_LRO_ENABLED(sc))
20852f345d8eSLuigi Rizzo                 oce_rx_flush_lro(rq);
2086ad512958SBjoern A. Zeeb #endif
20872f345d8eSLuigi Rizzo 
2088c2625e6eSJosh Paetzel 	oce_check_rx_bufs(sc, num_cqes, rq);
2089c2625e6eSJosh Paetzel 	UNLOCK(&rq->rx_lock);
2090e363f832SMichael Tuexen 	NET_EPOCH_EXIT(et);
20912f345d8eSLuigi Rizzo 	return 0;
20922f345d8eSLuigi Rizzo 
20932f345d8eSLuigi Rizzo }
20942f345d8eSLuigi Rizzo 
20952f345d8eSLuigi Rizzo /*****************************************************************************
20962f345d8eSLuigi Rizzo  *		   Helper function prototypes in this file 		     *
20972f345d8eSLuigi Rizzo  *****************************************************************************/
20982f345d8eSLuigi Rizzo 
2099*aa386085SZhenlei Huang static void
oce_attach_ifp(POCE_SOFTC sc)21002f345d8eSLuigi Rizzo oce_attach_ifp(POCE_SOFTC sc)
21012f345d8eSLuigi Rizzo {
21022f345d8eSLuigi Rizzo 
21032f345d8eSLuigi Rizzo 	sc->ifp = if_alloc(IFT_ETHER);
21042f345d8eSLuigi Rizzo 
21052f345d8eSLuigi Rizzo 	ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
21062f345d8eSLuigi Rizzo 	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
21072f345d8eSLuigi Rizzo 	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
21082f345d8eSLuigi Rizzo 
2109a6b55ee6SGleb Smirnoff 	if_setflags(sc->ifp, IFF_BROADCAST | IFF_MULTICAST);
211067fd4c9dSJustin Hibbits 	if_setioctlfn(sc->ifp, oce_ioctl);
211167fd4c9dSJustin Hibbits 	if_setstartfn(sc->ifp, oce_start);
211267fd4c9dSJustin Hibbits 	if_setinitfn(sc->ifp, oce_init);
211367fd4c9dSJustin Hibbits 	if_setmtu(sc->ifp, ETHERMTU);
211467fd4c9dSJustin Hibbits 	if_setsoftc(sc->ifp, sc);
211567fd4c9dSJustin Hibbits 	if_settransmitfn(sc->ifp, oce_multiq_start);
211667fd4c9dSJustin Hibbits 	if_setqflushfn(sc->ifp, oce_multiq_flush);
21172f345d8eSLuigi Rizzo 
21182f345d8eSLuigi Rizzo 	if_initname(sc->ifp,
21192f345d8eSLuigi Rizzo 		    device_get_name(sc->dev), device_get_unit(sc->dev));
21202f345d8eSLuigi Rizzo 
212167fd4c9dSJustin Hibbits 	if_setsendqlen(sc->ifp, OCE_MAX_TX_DESC - 1);
212267fd4c9dSJustin Hibbits 	if_setsendqready(sc->ifp);
21232f345d8eSLuigi Rizzo 
212467fd4c9dSJustin Hibbits 	if_sethwassist(sc->ifp, OCE_IF_HWASSIST);
212567fd4c9dSJustin Hibbits 	if_sethwassistbits(sc->ifp, CSUM_TSO, 0);
212667fd4c9dSJustin Hibbits 	if_sethwassistbits(sc->ifp, (CSUM_IP | CSUM_TCP | CSUM_UDP), 0);
21272f345d8eSLuigi Rizzo 
212867fd4c9dSJustin Hibbits 	if_setcapabilities(sc->ifp, OCE_IF_CAPABILITIES);
212967fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_HWCSUM, 0);
213067fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_VLAN_HWFILTER, 0);
21319bd3250aSLuigi Rizzo 
2132ad512958SBjoern A. Zeeb #if defined(INET6) || defined(INET)
213367fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_TSO, 0);
213467fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_LRO, 0);
213567fd4c9dSJustin Hibbits 	if_setcapabilitiesbit(sc->ifp, IFCAP_VLAN_HWTSO, 0);
2136ad512958SBjoern A. Zeeb #endif
21372f345d8eSLuigi Rizzo 
213867fd4c9dSJustin Hibbits 	if_setcapenable(sc->ifp, if_getcapabilities(sc->ifp));
213967fd4c9dSJustin Hibbits 	if_setbaudrate(sc->ifp, IF_Gbps(10));
21402f345d8eSLuigi Rizzo 
214167fd4c9dSJustin Hibbits 	if_sethwtsomax(sc->ifp, 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
214267fd4c9dSJustin Hibbits 	if_sethwtsomaxsegcount(sc->ifp, OCE_MAX_TX_ELEMENTS);
214367fd4c9dSJustin Hibbits 	if_sethwtsomaxsegsize(sc->ifp, 4096);
21445fbb6830SXin LI 
21452f345d8eSLuigi Rizzo 	ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
21462f345d8eSLuigi Rizzo }
21472f345d8eSLuigi Rizzo 
21482f345d8eSLuigi Rizzo static void
oce_add_vlan(void * arg,if_t ifp,uint16_t vtag)214967fd4c9dSJustin Hibbits oce_add_vlan(void *arg, if_t ifp, uint16_t vtag)
21502f345d8eSLuigi Rizzo {
215167fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
21522f345d8eSLuigi Rizzo 
215367fd4c9dSJustin Hibbits 	if (if_getsoftc(ifp) !=  arg)
21542f345d8eSLuigi Rizzo 		return;
21552f345d8eSLuigi Rizzo 	if ((vtag == 0) || (vtag > 4095))
21562f345d8eSLuigi Rizzo 		return;
21572f345d8eSLuigi Rizzo 
21582f345d8eSLuigi Rizzo 	sc->vlan_tag[vtag] = 1;
21592f345d8eSLuigi Rizzo 	sc->vlans_added++;
21605fbb6830SXin LI 	if (sc->vlans_added <= (sc->max_vlans + 1))
21612f345d8eSLuigi Rizzo 		oce_vid_config(sc);
21622f345d8eSLuigi Rizzo }
21632f345d8eSLuigi Rizzo 
21642f345d8eSLuigi Rizzo static void
oce_del_vlan(void * arg,if_t ifp,uint16_t vtag)216567fd4c9dSJustin Hibbits oce_del_vlan(void *arg, if_t ifp, uint16_t vtag)
21662f345d8eSLuigi Rizzo {
216767fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
21682f345d8eSLuigi Rizzo 
216967fd4c9dSJustin Hibbits 	if (if_getsoftc(ifp) !=  arg)
21702f345d8eSLuigi Rizzo 		return;
21712f345d8eSLuigi Rizzo 	if ((vtag == 0) || (vtag > 4095))
21722f345d8eSLuigi Rizzo 		return;
21732f345d8eSLuigi Rizzo 
21742f345d8eSLuigi Rizzo 	sc->vlan_tag[vtag] = 0;
21752f345d8eSLuigi Rizzo 	sc->vlans_added--;
21762f345d8eSLuigi Rizzo 	oce_vid_config(sc);
21772f345d8eSLuigi Rizzo }
21782f345d8eSLuigi Rizzo 
21792f345d8eSLuigi Rizzo /*
21802f345d8eSLuigi Rizzo  * A max of 64 vlans can be configured in BE. If the user configures
21812f345d8eSLuigi Rizzo  * more, place the card in vlan promiscuous mode.
21822f345d8eSLuigi Rizzo  */
21832f345d8eSLuigi Rizzo static int
oce_vid_config(POCE_SOFTC sc)21842f345d8eSLuigi Rizzo oce_vid_config(POCE_SOFTC sc)
21852f345d8eSLuigi Rizzo {
21862f345d8eSLuigi Rizzo 	struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
21872f345d8eSLuigi Rizzo 	uint16_t ntags = 0, i;
21882f345d8eSLuigi Rizzo 	int status = 0;
21892f345d8eSLuigi Rizzo 
21902f345d8eSLuigi Rizzo 	if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
219167fd4c9dSJustin Hibbits 			(if_getcapenable(sc->ifp) & IFCAP_VLAN_HWFILTER)) {
21922f345d8eSLuigi Rizzo 		for (i = 0; i < MAX_VLANS; i++) {
21932f345d8eSLuigi Rizzo 			if (sc->vlan_tag[i]) {
21942f345d8eSLuigi Rizzo 				vtags[ntags].vtag = i;
21952f345d8eSLuigi Rizzo 				ntags++;
21962f345d8eSLuigi Rizzo 			}
21972f345d8eSLuigi Rizzo 		}
21982f345d8eSLuigi Rizzo 		if (ntags)
21992f345d8eSLuigi Rizzo 			status = oce_config_vlan(sc, (uint8_t) sc->if_id,
22002f345d8eSLuigi Rizzo 						vtags, ntags, 1, 0);
22012f345d8eSLuigi Rizzo 	} else
22022f345d8eSLuigi Rizzo 		status = oce_config_vlan(sc, (uint8_t) sc->if_id,
22032f345d8eSLuigi Rizzo 					 	NULL, 0, 1, 1);
22042f345d8eSLuigi Rizzo 	return status;
22052f345d8eSLuigi Rizzo }
22062f345d8eSLuigi Rizzo 
22072f345d8eSLuigi Rizzo static void
oce_mac_addr_set(POCE_SOFTC sc)22082f345d8eSLuigi Rizzo oce_mac_addr_set(POCE_SOFTC sc)
22092f345d8eSLuigi Rizzo {
22102f345d8eSLuigi Rizzo 	uint32_t old_pmac_id = sc->pmac_id;
22112f345d8eSLuigi Rizzo 	int status = 0;
22122f345d8eSLuigi Rizzo 
221367fd4c9dSJustin Hibbits 	status = bcmp((if_getlladdr(sc->ifp)), sc->macaddr.mac_addr,
22142f345d8eSLuigi Rizzo 			 sc->macaddr.size_of_struct);
22152f345d8eSLuigi Rizzo 	if (!status)
22162f345d8eSLuigi Rizzo 		return;
22172f345d8eSLuigi Rizzo 
221867fd4c9dSJustin Hibbits 	status = oce_mbox_macaddr_add(sc, (uint8_t *)(if_getlladdr(sc->ifp)),
22192f345d8eSLuigi Rizzo 					sc->if_id, &sc->pmac_id);
22202f345d8eSLuigi Rizzo 	if (!status) {
22212f345d8eSLuigi Rizzo 		status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
222267fd4c9dSJustin Hibbits 		bcopy((if_getlladdr(sc->ifp)), sc->macaddr.mac_addr,
22232f345d8eSLuigi Rizzo 				 sc->macaddr.size_of_struct);
22242f345d8eSLuigi Rizzo 	}
22252f345d8eSLuigi Rizzo 	if (status)
22262f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Failed update macaddress\n");
22272f345d8eSLuigi Rizzo 
22282f345d8eSLuigi Rizzo }
22292f345d8eSLuigi Rizzo 
22302f345d8eSLuigi Rizzo static int
oce_handle_passthrough(if_t ifp,caddr_t data)223167fd4c9dSJustin Hibbits oce_handle_passthrough(if_t ifp, caddr_t data)
22322f345d8eSLuigi Rizzo {
223367fd4c9dSJustin Hibbits 	POCE_SOFTC sc = if_getsoftc(ifp);
22342f345d8eSLuigi Rizzo 	struct ifreq *ifr = (struct ifreq *)data;
22352f345d8eSLuigi Rizzo 	int rc = ENXIO;
22362f345d8eSLuigi Rizzo 	char cookie[32] = {0};
2237541d96aaSBrooks Davis 	void *priv_data = ifr_data_get_ptr(ifr);
22382f345d8eSLuigi Rizzo 	void *ioctl_ptr;
22392f345d8eSLuigi Rizzo 	uint32_t req_size;
22402f345d8eSLuigi Rizzo 	struct mbx_hdr req;
22412f345d8eSLuigi Rizzo 	OCE_DMA_MEM dma_mem;
22422f345d8eSLuigi Rizzo 
22432f345d8eSLuigi Rizzo 	if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
22442f345d8eSLuigi Rizzo 		return EFAULT;
22452f345d8eSLuigi Rizzo 
22462f345d8eSLuigi Rizzo 	if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
22472f345d8eSLuigi Rizzo 		return EINVAL;
22482f345d8eSLuigi Rizzo 
22492f345d8eSLuigi Rizzo 	ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
22502f345d8eSLuigi Rizzo 	if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
22512f345d8eSLuigi Rizzo 		return EFAULT;
22522f345d8eSLuigi Rizzo 
22532f345d8eSLuigi Rizzo 	req_size = le32toh(req.u0.req.request_length);
22542f345d8eSLuigi Rizzo 	if (req_size > 65536)
22552f345d8eSLuigi Rizzo 		return EINVAL;
22562f345d8eSLuigi Rizzo 
22572f345d8eSLuigi Rizzo 	req_size += sizeof(struct mbx_hdr);
22582f345d8eSLuigi Rizzo 	rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
22592f345d8eSLuigi Rizzo 	if (rc)
22602f345d8eSLuigi Rizzo 		return ENOMEM;
22612f345d8eSLuigi Rizzo 
22622f345d8eSLuigi Rizzo 	if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
22632f345d8eSLuigi Rizzo 		rc = EFAULT;
22642f345d8eSLuigi Rizzo 		goto dma_free;
22652f345d8eSLuigi Rizzo 	}
22662f345d8eSLuigi Rizzo 
22672f345d8eSLuigi Rizzo 	rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
22682f345d8eSLuigi Rizzo 	if (rc) {
22692f345d8eSLuigi Rizzo 		rc = EIO;
22702f345d8eSLuigi Rizzo 		goto dma_free;
22712f345d8eSLuigi Rizzo 	}
22722f345d8eSLuigi Rizzo 
2273758927a9SBrooks Davis 	if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size)) {
22742f345d8eSLuigi Rizzo 		rc =  EFAULT;
2275758927a9SBrooks Davis 		goto dma_free;
2276758927a9SBrooks Davis 	}
22772f345d8eSLuigi Rizzo 
2278cdaba892SXin LI 	/*
2279cdaba892SXin LI 	   firmware is filling all the attributes for this ioctl except
2280cdaba892SXin LI 	   the driver version..so fill it
2281cdaba892SXin LI 	 */
2282cdaba892SXin LI 	if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) {
2283758927a9SBrooks Davis 		struct mbx_common_get_cntl_attr *fw_cmd =
2284758927a9SBrooks Davis 		    (struct mbx_common_get_cntl_attr *)ioctl_ptr;
2285758927a9SBrooks Davis 		_Static_assert(sizeof(COMPONENT_REVISION) <=
2286758927a9SBrooks Davis 		     sizeof(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str),
2287758927a9SBrooks Davis 		     "driver version string too long");
2288758927a9SBrooks Davis 
2289758927a9SBrooks Davis 		rc = copyout(COMPONENT_REVISION,
2290758927a9SBrooks Davis 		    fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str,
2291758927a9SBrooks Davis 		    sizeof(COMPONENT_REVISION));
2292cdaba892SXin LI 	}
2293cdaba892SXin LI 
22942f345d8eSLuigi Rizzo dma_free:
22952f345d8eSLuigi Rizzo 	oce_dma_free(sc, &dma_mem);
22962f345d8eSLuigi Rizzo 	return rc;
22972f345d8eSLuigi Rizzo 
22982f345d8eSLuigi Rizzo }
22992f345d8eSLuigi Rizzo 
2300cdaba892SXin LI static void
oce_eqd_set_periodic(POCE_SOFTC sc)2301cdaba892SXin LI oce_eqd_set_periodic(POCE_SOFTC sc)
2302cdaba892SXin LI {
2303cdaba892SXin LI 	struct oce_set_eqd set_eqd[OCE_MAX_EQ];
2304cdaba892SXin LI 	struct oce_aic_obj *aic;
2305cdaba892SXin LI 	struct oce_eq *eqo;
2306cdaba892SXin LI 	uint64_t now = 0, delta;
2307cdaba892SXin LI 	int eqd, i, num = 0;
2308c2625e6eSJosh Paetzel 	uint32_t tx_reqs = 0, rxpkts = 0, pps;
2309c2625e6eSJosh Paetzel 	struct oce_wq *wq;
2310c2625e6eSJosh Paetzel 	struct oce_rq *rq;
2311c2625e6eSJosh Paetzel 
2312c2625e6eSJosh Paetzel 	#define ticks_to_msecs(t)       (1000 * (t) / hz)
2313cdaba892SXin LI 
2314cdaba892SXin LI 	for (i = 0 ; i < sc->neqs; i++) {
2315cdaba892SXin LI 		eqo = sc->eq[i];
2316cdaba892SXin LI 		aic = &sc->aic_obj[i];
2317cdaba892SXin LI 		/* When setting the static eq delay from the user space */
2318cdaba892SXin LI 		if (!aic->enable) {
2319c2625e6eSJosh Paetzel 			if (aic->ticks)
2320c2625e6eSJosh Paetzel 				aic->ticks = 0;
2321cdaba892SXin LI 			eqd = aic->et_eqd;
2322cdaba892SXin LI 			goto modify_eqd;
2323cdaba892SXin LI 		}
2324cdaba892SXin LI 
232535828280SAlexander Motin 		if (i == 0) {
232635828280SAlexander Motin 			rq = sc->rq[0];
2327c2625e6eSJosh Paetzel 			rxpkts = rq->rx_stats.rx_pkts;
232835828280SAlexander Motin 		} else
232935828280SAlexander Motin 			rxpkts = 0;
233035828280SAlexander Motin 		if (i + 1 < sc->nrqs) {
233135828280SAlexander Motin 			rq = sc->rq[i + 1];
233235828280SAlexander Motin 			rxpkts += rq->rx_stats.rx_pkts;
233335828280SAlexander Motin 		}
233435828280SAlexander Motin 		if (i < sc->nwqs) {
2335c2625e6eSJosh Paetzel 			wq = sc->wq[i];
2336c2625e6eSJosh Paetzel 			tx_reqs = wq->tx_stats.tx_reqs;
233735828280SAlexander Motin 		} else
233835828280SAlexander Motin 			tx_reqs = 0;
2339cdaba892SXin LI 		now = ticks;
2340cdaba892SXin LI 
2341c2625e6eSJosh Paetzel 		if (!aic->ticks || now < aic->ticks ||
2342c2625e6eSJosh Paetzel 		    rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) {
2343c2625e6eSJosh Paetzel 			aic->prev_rxpkts = rxpkts;
2344c2625e6eSJosh Paetzel 			aic->prev_txreqs = tx_reqs;
2345c2625e6eSJosh Paetzel 			aic->ticks = now;
2346c2625e6eSJosh Paetzel 			continue;
2347c2625e6eSJosh Paetzel 		}
2348cdaba892SXin LI 
2349c2625e6eSJosh Paetzel 		delta = ticks_to_msecs(now - aic->ticks);
2350cdaba892SXin LI 
2351c2625e6eSJosh Paetzel 		pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) +
2352c2625e6eSJosh Paetzel 		      (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta);
2353c2625e6eSJosh Paetzel 		eqd = (pps / 15000) << 2;
2354c2625e6eSJosh Paetzel 		if (eqd < 8)
2355cdaba892SXin LI 			eqd = 0;
2356cdaba892SXin LI 
2357cdaba892SXin LI 		/* Make sure that the eq delay is in the known range */
2358cdaba892SXin LI 		eqd = min(eqd, aic->max_eqd);
2359cdaba892SXin LI 		eqd = max(eqd, aic->min_eqd);
2360cdaba892SXin LI 
2361c2625e6eSJosh Paetzel 		aic->prev_rxpkts = rxpkts;
2362c2625e6eSJosh Paetzel 		aic->prev_txreqs = tx_reqs;
2363c2625e6eSJosh Paetzel 		aic->ticks = now;
2364c2625e6eSJosh Paetzel 
2365cdaba892SXin LI modify_eqd:
2366cdaba892SXin LI 		if (eqd != aic->cur_eqd) {
2367cdaba892SXin LI 			set_eqd[num].delay_multiplier = (eqd * 65)/100;
2368cdaba892SXin LI 			set_eqd[num].eq_id = eqo->eq_id;
2369cdaba892SXin LI 			aic->cur_eqd = eqd;
2370cdaba892SXin LI 			num++;
2371cdaba892SXin LI 		}
2372cdaba892SXin LI 	}
2373cdaba892SXin LI 
2374cdaba892SXin LI 	/* Is there atleast one eq that needs to be modified? */
2375c2625e6eSJosh Paetzel         for(i = 0; i < num; i += 8) {
2376c2625e6eSJosh Paetzel                 if((num - i) >=8 )
2377c2625e6eSJosh Paetzel                         oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8);
2378c2625e6eSJosh Paetzel                 else
2379c2625e6eSJosh Paetzel                         oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i));
2380c2625e6eSJosh Paetzel         }
2381c2625e6eSJosh Paetzel 
2382cdaba892SXin LI }
23832f345d8eSLuigi Rizzo 
oce_detect_hw_error(POCE_SOFTC sc)23845fbb6830SXin LI static void oce_detect_hw_error(POCE_SOFTC sc)
23855fbb6830SXin LI {
23865fbb6830SXin LI 
23875fbb6830SXin LI 	uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0;
23885fbb6830SXin LI 	uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
23895fbb6830SXin LI 	uint32_t i;
23905fbb6830SXin LI 
23915fbb6830SXin LI 	if (sc->hw_error)
23925fbb6830SXin LI 		return;
23935fbb6830SXin LI 
23945fbb6830SXin LI 	if (IS_XE201(sc)) {
23955fbb6830SXin LI 		sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET);
23965fbb6830SXin LI 		if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
23975fbb6830SXin LI 			sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET);
23985fbb6830SXin LI 			sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET);
23995fbb6830SXin LI 		}
24005fbb6830SXin LI 	} else {
24015fbb6830SXin LI 		ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW);
24025fbb6830SXin LI 		ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH);
24035fbb6830SXin LI 		ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK);
24045fbb6830SXin LI 		ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK);
24055fbb6830SXin LI 
24065fbb6830SXin LI 		ue_low = (ue_low & ~ue_low_mask);
24075fbb6830SXin LI 		ue_high = (ue_high & ~ue_high_mask);
24085fbb6830SXin LI 	}
24095fbb6830SXin LI 
24105fbb6830SXin LI 	/* On certain platforms BE hardware can indicate spurious UEs.
24115fbb6830SXin LI 	 * Allow the h/w to stop working completely in case of a real UE.
24125fbb6830SXin LI 	 * Hence not setting the hw_error for UE detection.
24135fbb6830SXin LI 	 */
24145fbb6830SXin LI 	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24155fbb6830SXin LI 		sc->hw_error = TRUE;
24165fbb6830SXin LI 		device_printf(sc->dev, "Error detected in the card\n");
24175fbb6830SXin LI 	}
24185fbb6830SXin LI 
24195fbb6830SXin LI 	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
24205fbb6830SXin LI 		device_printf(sc->dev,
24215fbb6830SXin LI 				"ERR: sliport status 0x%x\n", sliport_status);
24225fbb6830SXin LI 		device_printf(sc->dev,
24235fbb6830SXin LI 				"ERR: sliport error1 0x%x\n", sliport_err1);
24245fbb6830SXin LI 		device_printf(sc->dev,
24255fbb6830SXin LI 				"ERR: sliport error2 0x%x\n", sliport_err2);
24265fbb6830SXin LI 	}
24275fbb6830SXin LI 
24285fbb6830SXin LI 	if (ue_low) {
24295fbb6830SXin LI 		for (i = 0; ue_low; ue_low >>= 1, i++) {
24305fbb6830SXin LI 			if (ue_low & 1)
24315fbb6830SXin LI 				device_printf(sc->dev, "UE: %s bit set\n",
24325fbb6830SXin LI 							ue_status_low_desc[i]);
24335fbb6830SXin LI 		}
24345fbb6830SXin LI 	}
24355fbb6830SXin LI 
24365fbb6830SXin LI 	if (ue_high) {
24375fbb6830SXin LI 		for (i = 0; ue_high; ue_high >>= 1, i++) {
24385fbb6830SXin LI 			if (ue_high & 1)
24395fbb6830SXin LI 				device_printf(sc->dev, "UE: %s bit set\n",
24405fbb6830SXin LI 							ue_status_hi_desc[i]);
24415fbb6830SXin LI 		}
24425fbb6830SXin LI 	}
24435fbb6830SXin LI 
24445fbb6830SXin LI }
24455fbb6830SXin LI 
24462f345d8eSLuigi Rizzo static void
oce_local_timer(void * arg)24472f345d8eSLuigi Rizzo oce_local_timer(void *arg)
24482f345d8eSLuigi Rizzo {
24492f345d8eSLuigi Rizzo 	POCE_SOFTC sc = arg;
24502f345d8eSLuigi Rizzo 	int i = 0;
24512f345d8eSLuigi Rizzo 
24525fbb6830SXin LI 	oce_detect_hw_error(sc);
24532f345d8eSLuigi Rizzo 	oce_refresh_nic_stats(sc);
24542f345d8eSLuigi Rizzo 	oce_refresh_queue_stats(sc);
24552f345d8eSLuigi Rizzo 	oce_mac_addr_set(sc);
24562f345d8eSLuigi Rizzo 
24572f345d8eSLuigi Rizzo 	/* TX Watch Dog*/
24582f345d8eSLuigi Rizzo 	for (i = 0; i < sc->nwqs; i++)
24592f345d8eSLuigi Rizzo 		oce_tx_restart(sc, sc->wq[i]);
24602f345d8eSLuigi Rizzo 
2461cdaba892SXin LI 	/* calculate and set the eq delay for optimal interrupt rate */
2462291a1934SXin LI 	if (IS_BE(sc) || IS_SH(sc))
2463cdaba892SXin LI 		oce_eqd_set_periodic(sc);
2464cdaba892SXin LI 
24652f345d8eSLuigi Rizzo 	callout_reset(&sc->timer, hz, oce_local_timer, sc);
24662f345d8eSLuigi Rizzo }
24672f345d8eSLuigi Rizzo 
2468c2625e6eSJosh Paetzel static void
oce_tx_compl_clean(POCE_SOFTC sc)2469c2625e6eSJosh Paetzel oce_tx_compl_clean(POCE_SOFTC sc)
2470c2625e6eSJosh Paetzel {
2471c2625e6eSJosh Paetzel 	struct oce_wq *wq;
2472c2625e6eSJosh Paetzel 	int i = 0, timeo = 0, num_wqes = 0;
2473c2625e6eSJosh Paetzel 	int pending_txqs = sc->nwqs;
2474c2625e6eSJosh Paetzel 
2475c2625e6eSJosh Paetzel 	/* Stop polling for compls when HW has been silent for 10ms or
2476c2625e6eSJosh Paetzel 	 * hw_error or no outstanding completions expected
2477c2625e6eSJosh Paetzel 	 */
2478c2625e6eSJosh Paetzel 	do {
2479c2625e6eSJosh Paetzel 		pending_txqs = sc->nwqs;
2480c2625e6eSJosh Paetzel 
2481c2625e6eSJosh Paetzel 		for_all_wq_queues(sc, wq, i) {
2482c2625e6eSJosh Paetzel 			num_wqes = oce_wq_handler(wq);
2483c2625e6eSJosh Paetzel 
2484c2625e6eSJosh Paetzel 			if(num_wqes)
2485c2625e6eSJosh Paetzel 				timeo = 0;
2486c2625e6eSJosh Paetzel 
2487c2625e6eSJosh Paetzel 			if(!wq->ring->num_used)
2488c2625e6eSJosh Paetzel 				pending_txqs--;
2489c2625e6eSJosh Paetzel 		}
2490c2625e6eSJosh Paetzel 
2491c2625e6eSJosh Paetzel 		if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error)
2492c2625e6eSJosh Paetzel 			break;
2493c2625e6eSJosh Paetzel 
2494c2625e6eSJosh Paetzel 		DELAY(1000);
2495c2625e6eSJosh Paetzel 	} while (TRUE);
2496c2625e6eSJosh Paetzel 
2497c2625e6eSJosh Paetzel 	for_all_wq_queues(sc, wq, i) {
2498c2625e6eSJosh Paetzel 		while(wq->ring->num_used) {
2499c2625e6eSJosh Paetzel 			LOCK(&wq->tx_compl_lock);
2500c2625e6eSJosh Paetzel 			oce_process_tx_completion(wq);
2501c2625e6eSJosh Paetzel 			UNLOCK(&wq->tx_compl_lock);
2502c2625e6eSJosh Paetzel 		}
2503c2625e6eSJosh Paetzel 	}
2504c2625e6eSJosh Paetzel 
2505c2625e6eSJosh Paetzel }
25062f345d8eSLuigi Rizzo 
2507beb0f7e7SJosh Paetzel /* NOTE : This should only be called holding
2508beb0f7e7SJosh Paetzel  *        DEVICE_LOCK.
2509beb0f7e7SJosh Paetzel  */
25102f345d8eSLuigi Rizzo static void
oce_if_deactivate(POCE_SOFTC sc)25112f345d8eSLuigi Rizzo oce_if_deactivate(POCE_SOFTC sc)
25122f345d8eSLuigi Rizzo {
2513c2625e6eSJosh Paetzel 	int i;
25142f345d8eSLuigi Rizzo 	struct oce_rq *rq;
25152f345d8eSLuigi Rizzo 	struct oce_wq *wq;
25162f345d8eSLuigi Rizzo 	struct oce_eq *eq;
25172f345d8eSLuigi Rizzo 
251867fd4c9dSJustin Hibbits 	if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
25192f345d8eSLuigi Rizzo 
2520c2625e6eSJosh Paetzel 	oce_tx_compl_clean(sc);
25212f345d8eSLuigi Rizzo 
25222f345d8eSLuigi Rizzo 	/* Stop intrs and finish any bottom halves pending */
25232f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
25242f345d8eSLuigi Rizzo 
2525cdaba892SXin LI 	/* Since taskqueue_drain takes a Gaint Lock, We should not acquire
2526beb0f7e7SJosh Paetzel 	   any other lock. So unlock device lock and require after
2527beb0f7e7SJosh Paetzel 	   completing taskqueue_drain.
2528beb0f7e7SJosh Paetzel 	*/
2529beb0f7e7SJosh Paetzel 	UNLOCK(&sc->dev_lock);
25302f345d8eSLuigi Rizzo 	for (i = 0; i < sc->intr_count; i++) {
25312f345d8eSLuigi Rizzo 		if (sc->intrs[i].tq != NULL) {
25322f345d8eSLuigi Rizzo 			taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
25332f345d8eSLuigi Rizzo 		}
25342f345d8eSLuigi Rizzo 	}
2535beb0f7e7SJosh Paetzel 	LOCK(&sc->dev_lock);
25362f345d8eSLuigi Rizzo 
25372f345d8eSLuigi Rizzo 	/* Delete RX queue in card with flush param */
25382f345d8eSLuigi Rizzo 	oce_stop_rx(sc);
25392f345d8eSLuigi Rizzo 
25402f345d8eSLuigi Rizzo 	/* Invalidate any pending cq and eq entries*/
25412f345d8eSLuigi Rizzo 	for_all_evnt_queues(sc, eq, i)
25422f345d8eSLuigi Rizzo 		oce_drain_eq(eq);
25432f345d8eSLuigi Rizzo 	for_all_rq_queues(sc, rq, i)
25442f345d8eSLuigi Rizzo 		oce_drain_rq_cq(rq);
25452f345d8eSLuigi Rizzo 	for_all_wq_queues(sc, wq, i)
25462f345d8eSLuigi Rizzo 		oce_drain_wq_cq(wq);
25472f345d8eSLuigi Rizzo 
25482f345d8eSLuigi Rizzo 	/* But still we need to get MCC aync events.
25492f345d8eSLuigi Rizzo 	   So enable intrs and also arm first EQ
25502f345d8eSLuigi Rizzo 	*/
25512f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
25522f345d8eSLuigi Rizzo 	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
25532f345d8eSLuigi Rizzo 
25542f345d8eSLuigi Rizzo 	DELAY(10);
25552f345d8eSLuigi Rizzo }
25562f345d8eSLuigi Rizzo 
25572f345d8eSLuigi Rizzo static void
oce_if_activate(POCE_SOFTC sc)25582f345d8eSLuigi Rizzo oce_if_activate(POCE_SOFTC sc)
25592f345d8eSLuigi Rizzo {
25602f345d8eSLuigi Rizzo 	struct oce_eq *eq;
25612f345d8eSLuigi Rizzo 	struct oce_rq *rq;
25622f345d8eSLuigi Rizzo 	struct oce_wq *wq;
25632f345d8eSLuigi Rizzo 	int i, rc = 0;
25642f345d8eSLuigi Rizzo 
256567fd4c9dSJustin Hibbits 	if_setdrvflagbits(sc->ifp, IFF_DRV_RUNNING , 0);
25662f345d8eSLuigi Rizzo 
25672f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
25682f345d8eSLuigi Rizzo 
25692f345d8eSLuigi Rizzo 	oce_start_rx(sc);
25702f345d8eSLuigi Rizzo 
25712f345d8eSLuigi Rizzo 	for_all_rq_queues(sc, rq, i) {
25722f345d8eSLuigi Rizzo 		rc = oce_start_rq(rq);
25732f345d8eSLuigi Rizzo 		if (rc)
25742f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Unable to start RX\n");
25752f345d8eSLuigi Rizzo 	}
25762f345d8eSLuigi Rizzo 
25772f345d8eSLuigi Rizzo 	for_all_wq_queues(sc, wq, i) {
25782f345d8eSLuigi Rizzo 		rc = oce_start_wq(wq);
25792f345d8eSLuigi Rizzo 		if (rc)
25802f345d8eSLuigi Rizzo 			device_printf(sc->dev, "Unable to start TX\n");
25812f345d8eSLuigi Rizzo 	}
25822f345d8eSLuigi Rizzo 
25832f345d8eSLuigi Rizzo 	for_all_evnt_queues(sc, eq, i)
25842f345d8eSLuigi Rizzo 		oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
25852f345d8eSLuigi Rizzo 
25862f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
25872f345d8eSLuigi Rizzo 
25882f345d8eSLuigi Rizzo }
25892f345d8eSLuigi Rizzo 
25909bd3250aSLuigi Rizzo static void
process_link_state(POCE_SOFTC sc,struct oce_async_cqe_link_state * acqe)25919bd3250aSLuigi Rizzo process_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
25922f345d8eSLuigi Rizzo {
25939bd3250aSLuigi Rizzo 	/* Update Link status */
25942f345d8eSLuigi Rizzo 	if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
25952f345d8eSLuigi Rizzo 	     ASYNC_EVENT_LINK_UP) {
25962f345d8eSLuigi Rizzo 		sc->link_status = ASYNC_EVENT_LINK_UP;
25972f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_UP);
25982f345d8eSLuigi Rizzo 	} else {
25992f345d8eSLuigi Rizzo 		sc->link_status = ASYNC_EVENT_LINK_DOWN;
26002f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
26012f345d8eSLuigi Rizzo 	}
26029bd3250aSLuigi Rizzo }
26039bd3250aSLuigi Rizzo 
oce_async_grp5_osbmc_process(POCE_SOFTC sc,struct oce_async_evt_grp5_os2bmc * evt)2604c2625e6eSJosh Paetzel static void oce_async_grp5_osbmc_process(POCE_SOFTC sc,
2605c2625e6eSJosh Paetzel 					 struct oce_async_evt_grp5_os2bmc *evt)
2606c2625e6eSJosh Paetzel {
2607c2625e6eSJosh Paetzel 	DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc));
2608c2625e6eSJosh Paetzel 	if (evt->u.s.mgmt_enable)
2609c2625e6eSJosh Paetzel 		sc->flags |= OCE_FLAGS_OS2BMC;
2610c2625e6eSJosh Paetzel 	else
2611c2625e6eSJosh Paetzel 		return;
2612c2625e6eSJosh Paetzel 
2613c2625e6eSJosh Paetzel 	sc->bmc_filt_mask = evt->u.s.arp_filter;
2614c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1);
2615c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2);
2616c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3);
2617c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4);
2618c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5);
2619c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6);
2620c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7);
2621c2625e6eSJosh Paetzel 	sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8);
2622c2625e6eSJosh Paetzel }
2623c2625e6eSJosh Paetzel 
oce_process_grp5_events(POCE_SOFTC sc,struct oce_mq_cqe * cqe)2624c2625e6eSJosh Paetzel static void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe)
2625c2625e6eSJosh Paetzel {
2626c2625e6eSJosh Paetzel 	struct oce_async_event_grp5_pvid_state *gcqe;
2627c2625e6eSJosh Paetzel 	struct oce_async_evt_grp5_os2bmc *bmccqe;
2628c2625e6eSJosh Paetzel 
2629c2625e6eSJosh Paetzel 	switch (cqe->u0.s.async_type) {
2630c2625e6eSJosh Paetzel 	case ASYNC_EVENT_PVID_STATE:
2631c2625e6eSJosh Paetzel 		/* GRP5 PVID */
2632c2625e6eSJosh Paetzel 		gcqe = (struct oce_async_event_grp5_pvid_state *)cqe;
2633c2625e6eSJosh Paetzel 		if (gcqe->enabled)
2634c2625e6eSJosh Paetzel 			sc->pvid = gcqe->tag & VLAN_VID_MASK;
2635c2625e6eSJosh Paetzel 		else
2636c2625e6eSJosh Paetzel 			sc->pvid = 0;
2637c2625e6eSJosh Paetzel 		break;
2638c2625e6eSJosh Paetzel 	case ASYNC_EVENT_OS2BMC:
2639c2625e6eSJosh Paetzel 		bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe;
2640c2625e6eSJosh Paetzel 		oce_async_grp5_osbmc_process(sc, bmccqe);
2641c2625e6eSJosh Paetzel 		break;
2642c2625e6eSJosh Paetzel 	default:
2643c2625e6eSJosh Paetzel 		break;
2644c2625e6eSJosh Paetzel 	}
2645c2625e6eSJosh Paetzel }
2646c2625e6eSJosh Paetzel 
26479bd3250aSLuigi Rizzo /* Handle the Completion Queue for the Mailbox/Async notifications */
26489bd3250aSLuigi Rizzo uint16_t
oce_mq_handler(void * arg)26499bd3250aSLuigi Rizzo oce_mq_handler(void *arg)
26509bd3250aSLuigi Rizzo {
26519bd3250aSLuigi Rizzo 	struct oce_mq *mq = (struct oce_mq *)arg;
26529bd3250aSLuigi Rizzo 	POCE_SOFTC sc = mq->parent;
26539bd3250aSLuigi Rizzo 	struct oce_cq *cq = mq->cq;
26549bd3250aSLuigi Rizzo 	int num_cqes = 0, evt_type = 0, optype = 0;
26559bd3250aSLuigi Rizzo 	struct oce_mq_cqe *cqe;
26569bd3250aSLuigi Rizzo 	struct oce_async_cqe_link_state *acqe;
2657cdaba892SXin LI 	struct oce_async_event_qnq *dbgcqe;
26589bd3250aSLuigi Rizzo 
26599bd3250aSLuigi Rizzo 	bus_dmamap_sync(cq->ring->dma.tag,
26609bd3250aSLuigi Rizzo 			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
26619bd3250aSLuigi Rizzo 	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
26629bd3250aSLuigi Rizzo 
26639bd3250aSLuigi Rizzo 	while (cqe->u0.dw[3]) {
26649bd3250aSLuigi Rizzo 		DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
26659bd3250aSLuigi Rizzo 		if (cqe->u0.s.async_event) {
26669bd3250aSLuigi Rizzo 			evt_type = cqe->u0.s.event_type;
26679bd3250aSLuigi Rizzo 			optype = cqe->u0.s.async_type;
26689bd3250aSLuigi Rizzo 			if (evt_type  == ASYNC_EVENT_CODE_LINK_STATE) {
26699bd3250aSLuigi Rizzo 				/* Link status evt */
26709bd3250aSLuigi Rizzo 				acqe = (struct oce_async_cqe_link_state *)cqe;
26719bd3250aSLuigi Rizzo 				process_link_state(sc, acqe);
2672c2625e6eSJosh Paetzel 			} else if (evt_type == ASYNC_EVENT_GRP5) {
2673c2625e6eSJosh Paetzel 				oce_process_grp5_events(sc, cqe);
2674c2625e6eSJosh Paetzel 			} else if (evt_type == ASYNC_EVENT_CODE_DEBUG &&
2675cdaba892SXin LI 					optype == ASYNC_EVENT_DEBUG_QNQ) {
2676c2625e6eSJosh Paetzel 				dbgcqe =  (struct oce_async_event_qnq *)cqe;
2677cdaba892SXin LI 				if(dbgcqe->valid)
2678cdaba892SXin LI 					sc->qnqid = dbgcqe->vlan_tag;
2679cdaba892SXin LI 				sc->qnq_debug_event = TRUE;
2680cdaba892SXin LI 			}
26812f345d8eSLuigi Rizzo 		}
26822f345d8eSLuigi Rizzo 		cqe->u0.dw[3] = 0;
26832f345d8eSLuigi Rizzo 		RING_GET(cq->ring, 1);
26842f345d8eSLuigi Rizzo 		bus_dmamap_sync(cq->ring->dma.tag,
26852f345d8eSLuigi Rizzo 				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
26862f345d8eSLuigi Rizzo 		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
26872f345d8eSLuigi Rizzo 		num_cqes++;
26882f345d8eSLuigi Rizzo 	}
26892f345d8eSLuigi Rizzo 
26902f345d8eSLuigi Rizzo 	if (num_cqes)
26912f345d8eSLuigi Rizzo 		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
26922f345d8eSLuigi Rizzo 
26932f345d8eSLuigi Rizzo 	return 0;
26942f345d8eSLuigi Rizzo }
26952f345d8eSLuigi Rizzo 
26962f345d8eSLuigi Rizzo static void
setup_max_queues_want(POCE_SOFTC sc)26972f345d8eSLuigi Rizzo setup_max_queues_want(POCE_SOFTC sc)
26982f345d8eSLuigi Rizzo {
26992f345d8eSLuigi Rizzo 	/* Check if it is FLEX machine. Is so dont use RSS */
27002f345d8eSLuigi Rizzo 	if ((sc->function_mode & FNM_FLEX10_MODE) ||
27019bd3250aSLuigi Rizzo 	    (sc->function_mode & FNM_UMC_MODE)    ||
27029bd3250aSLuigi Rizzo 	    (sc->function_mode & FNM_VNIC_MODE)	  ||
2703291a1934SXin LI 	    (!is_rss_enabled(sc))		  ||
2704a4f734b4SXin LI 	    IS_BE2(sc)) {
27052f345d8eSLuigi Rizzo 		sc->nrqs = 1;
27062f345d8eSLuigi Rizzo 		sc->nwqs = 1;
27075fbb6830SXin LI 	} else {
27085fbb6830SXin LI 		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
27095fbb6830SXin LI 		sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs);
27102f345d8eSLuigi Rizzo 	}
2711a4f734b4SXin LI 
2712a4f734b4SXin LI 	if (IS_BE2(sc) && is_rss_enabled(sc))
2713a4f734b4SXin LI 		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
27142f345d8eSLuigi Rizzo }
27152f345d8eSLuigi Rizzo 
27162f345d8eSLuigi Rizzo static void
update_queues_got(POCE_SOFTC sc)27172f345d8eSLuigi Rizzo update_queues_got(POCE_SOFTC sc)
27182f345d8eSLuigi Rizzo {
2719291a1934SXin LI 	if (is_rss_enabled(sc)) {
27202f345d8eSLuigi Rizzo 		sc->nrqs = sc->intr_count + 1;
27212f345d8eSLuigi Rizzo 		sc->nwqs = sc->intr_count;
27222f345d8eSLuigi Rizzo 	} else {
27232f345d8eSLuigi Rizzo 		sc->nrqs = 1;
27242f345d8eSLuigi Rizzo 		sc->nwqs = 1;
27252f345d8eSLuigi Rizzo 	}
2726a4f734b4SXin LI 
2727a4f734b4SXin LI 	if (IS_BE2(sc))
2728a4f734b4SXin LI 		sc->nwqs = 1;
27292f345d8eSLuigi Rizzo }
27302f345d8eSLuigi Rizzo 
2731cdaba892SXin LI static int
oce_check_ipv6_ext_hdr(struct mbuf * m)2732cdaba892SXin LI oce_check_ipv6_ext_hdr(struct mbuf *m)
2733cdaba892SXin LI {
2734cdaba892SXin LI 	struct ether_header *eh = mtod(m, struct ether_header *);
2735cdaba892SXin LI 	caddr_t m_datatemp = m->m_data;
2736cdaba892SXin LI 
2737cdaba892SXin LI 	if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2738cdaba892SXin LI 		m->m_data += sizeof(struct ether_header);
2739cdaba892SXin LI 		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2740cdaba892SXin LI 
2741cdaba892SXin LI 		if((ip6->ip6_nxt != IPPROTO_TCP) && \
2742cdaba892SXin LI 				(ip6->ip6_nxt != IPPROTO_UDP)){
2743cdaba892SXin LI 			struct ip6_ext *ip6e = NULL;
2744cdaba892SXin LI 			m->m_data += sizeof(struct ip6_hdr);
2745cdaba892SXin LI 
2746cdaba892SXin LI 			ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *);
2747cdaba892SXin LI 			if(ip6e->ip6e_len == 0xff) {
2748cdaba892SXin LI 				m->m_data = m_datatemp;
2749cdaba892SXin LI 				return TRUE;
2750cdaba892SXin LI 			}
2751cdaba892SXin LI 		}
2752cdaba892SXin LI 		m->m_data = m_datatemp;
2753cdaba892SXin LI 	}
2754cdaba892SXin LI 	return FALSE;
2755cdaba892SXin LI }
2756cdaba892SXin LI 
2757cdaba892SXin LI static int
is_be3_a1(POCE_SOFTC sc)2758cdaba892SXin LI is_be3_a1(POCE_SOFTC sc)
2759cdaba892SXin LI {
2760cdaba892SXin LI 	if((sc->flags & OCE_FLAGS_BE3)  && ((sc->asic_revision & 0xFF) < 2)) {
2761cdaba892SXin LI 		return TRUE;
2762cdaba892SXin LI 	}
2763cdaba892SXin LI 	return FALSE;
2764cdaba892SXin LI }
2765cdaba892SXin LI 
2766cdaba892SXin LI static struct mbuf *
oce_insert_vlan_tag(POCE_SOFTC sc,struct mbuf * m,boolean_t * complete)2767cdaba892SXin LI oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete)
2768cdaba892SXin LI {
2769cdaba892SXin LI 	uint16_t vlan_tag = 0;
2770cdaba892SXin LI 
2771cdaba892SXin LI 	if(!M_WRITABLE(m))
2772cdaba892SXin LI 		return NULL;
2773cdaba892SXin LI 
2774cdaba892SXin LI 	/* Embed vlan tag in the packet if it is not part of it */
2775cdaba892SXin LI 	if(m->m_flags & M_VLANTAG) {
2776cdaba892SXin LI 		vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
2777cdaba892SXin LI 		m->m_flags &= ~M_VLANTAG;
2778cdaba892SXin LI 	}
2779cdaba892SXin LI 
2780cdaba892SXin LI 	/* if UMC, ignore vlan tag insertion and instead insert pvid */
2781cdaba892SXin LI 	if(sc->pvid) {
2782cdaba892SXin LI 		if(!vlan_tag)
2783cdaba892SXin LI 			vlan_tag = sc->pvid;
2784c2625e6eSJosh Paetzel 		if (complete)
2785cdaba892SXin LI 			*complete = FALSE;
2786cdaba892SXin LI 	}
2787cdaba892SXin LI 
2788cdaba892SXin LI 	if(vlan_tag) {
2789cdaba892SXin LI 		m = ether_vlanencap(m, vlan_tag);
2790cdaba892SXin LI 	}
2791cdaba892SXin LI 
2792cdaba892SXin LI 	if(sc->qnqid) {
2793cdaba892SXin LI 		m = ether_vlanencap(m, sc->qnqid);
2794c2625e6eSJosh Paetzel 
2795c2625e6eSJosh Paetzel 		if (complete)
2796cdaba892SXin LI 			*complete = FALSE;
2797cdaba892SXin LI 	}
2798cdaba892SXin LI 	return m;
2799cdaba892SXin LI }
2800cdaba892SXin LI 
2801cdaba892SXin LI static int
oce_tx_asic_stall_verify(POCE_SOFTC sc,struct mbuf * m)2802cdaba892SXin LI oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m)
2803cdaba892SXin LI {
2804cdaba892SXin LI 	if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \
2805cdaba892SXin LI 			oce_check_ipv6_ext_hdr(m)) {
2806cdaba892SXin LI 		return TRUE;
2807cdaba892SXin LI 	}
2808cdaba892SXin LI 	return FALSE;
2809cdaba892SXin LI }
2810291a1934SXin LI 
2811291a1934SXin LI static void
oce_get_config(POCE_SOFTC sc)2812291a1934SXin LI oce_get_config(POCE_SOFTC sc)
2813291a1934SXin LI {
2814291a1934SXin LI 	int rc = 0;
2815291a1934SXin LI 	uint32_t max_rss = 0;
2816291a1934SXin LI 
2817291a1934SXin LI 	if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native))
2818291a1934SXin LI 		max_rss = OCE_LEGACY_MODE_RSS;
2819291a1934SXin LI 	else
2820291a1934SXin LI 		max_rss = OCE_MAX_RSS;
2821291a1934SXin LI 
2822291a1934SXin LI 	if (!IS_BE(sc)) {
2823b41206d8SXin LI 		rc = oce_get_profile_config(sc, max_rss);
2824291a1934SXin LI 		if (rc) {
2825291a1934SXin LI 			sc->nwqs = OCE_MAX_WQ;
2826291a1934SXin LI 			sc->nrssqs = max_rss;
2827291a1934SXin LI 			sc->nrqs = sc->nrssqs + 1;
2828291a1934SXin LI 		}
2829291a1934SXin LI 	}
2830b41206d8SXin LI 	else { /* For BE3 don't rely on fw for determining the resources */
2831291a1934SXin LI 		sc->nrssqs = max_rss;
2832291a1934SXin LI 		sc->nrqs = sc->nrssqs + 1;
2833291a1934SXin LI 		sc->nwqs = OCE_MAX_WQ;
2834b41206d8SXin LI 		sc->max_vlans = MAX_VLANFILTER_SIZE;
2835291a1934SXin LI 	}
2836291a1934SXin LI }
2837c2625e6eSJosh Paetzel 
2838c2625e6eSJosh Paetzel static void
oce_rdma_close(void)2839c2625e6eSJosh Paetzel oce_rdma_close(void)
2840c2625e6eSJosh Paetzel {
2841c2625e6eSJosh Paetzel   if (oce_rdma_if != NULL) {
2842c2625e6eSJosh Paetzel     oce_rdma_if = NULL;
2843c2625e6eSJosh Paetzel   }
2844c2625e6eSJosh Paetzel }
2845c2625e6eSJosh Paetzel 
2846c2625e6eSJosh Paetzel static void
oce_get_mac_addr(POCE_SOFTC sc,uint8_t * macaddr)2847c2625e6eSJosh Paetzel oce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr)
2848c2625e6eSJosh Paetzel {
2849c2625e6eSJosh Paetzel   memcpy(macaddr, sc->macaddr.mac_addr, 6);
2850c2625e6eSJosh Paetzel }
2851c2625e6eSJosh Paetzel 
2852c2625e6eSJosh Paetzel int
oce_register_rdma(POCE_RDMA_INFO rdma_info,POCE_RDMA_IF rdma_if)2853c2625e6eSJosh Paetzel oce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if)
2854c2625e6eSJosh Paetzel {
2855c2625e6eSJosh Paetzel   POCE_SOFTC sc;
2856c2625e6eSJosh Paetzel   struct oce_dev_info di;
2857c2625e6eSJosh Paetzel   int i;
2858c2625e6eSJosh Paetzel 
2859c2625e6eSJosh Paetzel   if ((rdma_info == NULL) || (rdma_if == NULL)) {
2860c2625e6eSJosh Paetzel     return -EINVAL;
2861c2625e6eSJosh Paetzel   }
2862c2625e6eSJosh Paetzel 
2863c2625e6eSJosh Paetzel   if ((rdma_info->size != OCE_RDMA_INFO_SIZE) ||
2864c2625e6eSJosh Paetzel       (rdma_if->size != OCE_RDMA_IF_SIZE)) {
2865c2625e6eSJosh Paetzel     return -ENXIO;
2866c2625e6eSJosh Paetzel   }
2867c2625e6eSJosh Paetzel 
2868c2625e6eSJosh Paetzel   rdma_info->close = oce_rdma_close;
2869c2625e6eSJosh Paetzel   rdma_info->mbox_post = oce_mbox_post;
2870c2625e6eSJosh Paetzel   rdma_info->common_req_hdr_init = mbx_common_req_hdr_init;
2871c2625e6eSJosh Paetzel   rdma_info->get_mac_addr = oce_get_mac_addr;
2872c2625e6eSJosh Paetzel 
2873c2625e6eSJosh Paetzel   oce_rdma_if = rdma_if;
2874c2625e6eSJosh Paetzel 
2875c2625e6eSJosh Paetzel   sc = softc_head;
2876c2625e6eSJosh Paetzel   while (sc != NULL) {
2877c2625e6eSJosh Paetzel     if (oce_rdma_if->announce != NULL) {
2878c2625e6eSJosh Paetzel       memset(&di, 0, sizeof(di));
2879c2625e6eSJosh Paetzel       di.dev = sc->dev;
2880c2625e6eSJosh Paetzel       di.softc = sc;
2881c2625e6eSJosh Paetzel       di.ifp = sc->ifp;
2882c2625e6eSJosh Paetzel       di.db_bhandle = sc->db_bhandle;
2883c2625e6eSJosh Paetzel       di.db_btag = sc->db_btag;
2884c2625e6eSJosh Paetzel       di.db_page_size = 4096;
2885c2625e6eSJosh Paetzel       if (sc->flags & OCE_FLAGS_USING_MSIX) {
2886c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_MSIX;
2887c2625e6eSJosh Paetzel       } else if (sc->flags & OCE_FLAGS_USING_MSI) {
2888c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_MSI;
2889c2625e6eSJosh Paetzel       } else {
2890c2625e6eSJosh Paetzel         di.intr_mode = OCE_INTERRUPT_MODE_INTX;
2891c2625e6eSJosh Paetzel       }
2892c2625e6eSJosh Paetzel       di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk
2893c2625e6eSJosh Paetzel       if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) {
2894c2625e6eSJosh Paetzel         di.msix.num_vectors = sc->intr_count + sc->roce_intr_count;
2895c2625e6eSJosh Paetzel         di.msix.start_vector = sc->intr_count;
2896c2625e6eSJosh Paetzel         for (i=0; i<di.msix.num_vectors; i++) {
2897c2625e6eSJosh Paetzel           di.msix.vector_list[i] = sc->intrs[i].vector;
2898c2625e6eSJosh Paetzel         }
2899c2625e6eSJosh Paetzel       } else {
2900c2625e6eSJosh Paetzel       }
2901c2625e6eSJosh Paetzel       memcpy(di.mac_addr, sc->macaddr.mac_addr, 6);
2902c2625e6eSJosh Paetzel       di.vendor_id = pci_get_vendor(sc->dev);
2903c2625e6eSJosh Paetzel       di.dev_id = pci_get_device(sc->dev);
2904c2625e6eSJosh Paetzel 
2905c2625e6eSJosh Paetzel       if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
2906c2625e6eSJosh Paetzel           di.flags  |= OCE_RDMA_INFO_RDMA_SUPPORTED;
2907c2625e6eSJosh Paetzel       }
2908c2625e6eSJosh Paetzel 
2909c2625e6eSJosh Paetzel       rdma_if->announce(&di);
2910c2625e6eSJosh Paetzel       sc = sc->next;
2911c2625e6eSJosh Paetzel     }
2912c2625e6eSJosh Paetzel   }
2913c2625e6eSJosh Paetzel 
2914c2625e6eSJosh Paetzel   return 0;
2915c2625e6eSJosh Paetzel }
2916c2625e6eSJosh Paetzel 
2917c2625e6eSJosh Paetzel static void
oce_read_env_variables(POCE_SOFTC sc)2918c2625e6eSJosh Paetzel oce_read_env_variables( POCE_SOFTC sc )
2919c2625e6eSJosh Paetzel {
2920c2625e6eSJosh Paetzel 	char *value = NULL;
2921c2625e6eSJosh Paetzel 	int rc = 0;
2922c2625e6eSJosh Paetzel 
2923c2625e6eSJosh Paetzel         /* read if user wants to enable hwlro or swlro */
2924c2625e6eSJosh Paetzel         //value = getenv("oce_enable_hwlro");
2925c2625e6eSJosh Paetzel         if(value && IS_SH(sc)) {
2926c2625e6eSJosh Paetzel                 sc->enable_hwlro = strtol(value, NULL, 10);
2927c2625e6eSJosh Paetzel                 if(sc->enable_hwlro) {
2928c2625e6eSJosh Paetzel                         rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL);
2929c2625e6eSJosh Paetzel                         if(rc) {
2930c2625e6eSJosh Paetzel                                 device_printf(sc->dev, "no hardware lro support\n");
2931c2625e6eSJosh Paetzel                 		device_printf(sc->dev, "software lro enabled\n");
2932c2625e6eSJosh Paetzel                                 sc->enable_hwlro = 0;
2933c2625e6eSJosh Paetzel                         }else {
2934c2625e6eSJosh Paetzel                                 device_printf(sc->dev, "hardware lro enabled\n");
2935c2625e6eSJosh Paetzel 				oce_max_rsp_handled = 32;
2936c2625e6eSJosh Paetzel                         }
2937c2625e6eSJosh Paetzel                 }else {
2938c2625e6eSJosh Paetzel                         device_printf(sc->dev, "software lro enabled\n");
2939c2625e6eSJosh Paetzel                 }
2940c2625e6eSJosh Paetzel         }else {
2941c2625e6eSJosh Paetzel                 sc->enable_hwlro = 0;
2942c2625e6eSJosh Paetzel         }
2943c2625e6eSJosh Paetzel 
2944c2625e6eSJosh Paetzel         /* read mbuf size */
2945c2625e6eSJosh Paetzel         //value = getenv("oce_rq_buf_size");
2946c2625e6eSJosh Paetzel         if(value && IS_SH(sc)) {
2947c2625e6eSJosh Paetzel                 oce_rq_buf_size = strtol(value, NULL, 10);
2948c2625e6eSJosh Paetzel                 switch(oce_rq_buf_size) {
2949c2625e6eSJosh Paetzel                 case 2048:
2950c2625e6eSJosh Paetzel                 case 4096:
2951c2625e6eSJosh Paetzel                 case 9216:
2952c2625e6eSJosh Paetzel                 case 16384:
2953c2625e6eSJosh Paetzel                         break;
2954c2625e6eSJosh Paetzel 
2955c2625e6eSJosh Paetzel                 default:
2956c2625e6eSJosh Paetzel                         device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n");
2957c2625e6eSJosh Paetzel                         oce_rq_buf_size = 2048;
2958c2625e6eSJosh Paetzel                 }
2959c2625e6eSJosh Paetzel         }
2960c2625e6eSJosh Paetzel 
2961c2625e6eSJosh Paetzel 	return;
2962c2625e6eSJosh Paetzel }
2963