1231437Sluigi/*-
2252869Sdelphij * Copyright (C) 2013 Emulex
3231437Sluigi * All rights reserved.
4231437Sluigi *
5231437Sluigi * Redistribution and use in source and binary forms, with or without
6231437Sluigi * modification, are permitted provided that the following conditions are met:
7231437Sluigi *
8231437Sluigi * 1. Redistributions of source code must retain the above copyright notice,
9231437Sluigi *    this list of conditions and the following disclaimer.
10231437Sluigi *
11231437Sluigi * 2. Redistributions in binary form must reproduce the above copyright
12231437Sluigi *    notice, this list of conditions and the following disclaimer in the
13231437Sluigi *    documentation and/or other materials provided with the distribution.
14231437Sluigi *
15231437Sluigi * 3. Neither the name of the Emulex Corporation nor the names of its
16231437Sluigi *    contributors may be used to endorse or promote products derived from
17231437Sluigi *    this software without specific prior written permission.
18231437Sluigi *
19231437Sluigi * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20231437Sluigi * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21231437Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22231437Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23231437Sluigi * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24231437Sluigi * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25231437Sluigi * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26231437Sluigi * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27231437Sluigi * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28231437Sluigi * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29231437Sluigi * POSSIBILITY OF SUCH DAMAGE.
30231437Sluigi *
31231437Sluigi * Contact Information:
32231437Sluigi * freebsd-drivers@emulex.com
33231437Sluigi *
34231437Sluigi * Emulex
35231437Sluigi * 3333 Susan Street
36231437Sluigi * Costa Mesa, CA 92626
37231437Sluigi */
38231437Sluigi
39231437Sluigi/* $FreeBSD: stable/11/sys/dev/oce/oce_if.c 369531 2021-03-30 15:05:49Z freqlabs $ */
40231437Sluigi
41231511Sbz#include "opt_inet6.h"
42231511Sbz#include "opt_inet.h"
43231511Sbz
44231437Sluigi#include "oce_if.h"
45338938Sjpaetzel#include "oce_user.h"
46231437Sluigi
47338938Sjpaetzel#define is_tso_pkt(m) (m->m_pkthdr.csum_flags & CSUM_TSO)
48338938Sjpaetzel
49257007Sdelphij/* UE Status Low CSR */
50257007Sdelphijstatic char *ue_status_low_desc[] = {
51338938Sjpaetzel        "CEV",
52338938Sjpaetzel        "CTX",
53338938Sjpaetzel        "DBUF",
54338938Sjpaetzel        "ERX",
55338938Sjpaetzel        "Host",
56338938Sjpaetzel        "MPU",
57338938Sjpaetzel        "NDMA",
58338938Sjpaetzel        "PTC ",
59338938Sjpaetzel        "RDMA ",
60338938Sjpaetzel        "RXF ",
61338938Sjpaetzel        "RXIPS ",
62338938Sjpaetzel        "RXULP0 ",
63338938Sjpaetzel        "RXULP1 ",
64338938Sjpaetzel        "RXULP2 ",
65338938Sjpaetzel        "TIM ",
66338938Sjpaetzel        "TPOST ",
67338938Sjpaetzel        "TPRE ",
68338938Sjpaetzel        "TXIPS ",
69338938Sjpaetzel        "TXULP0 ",
70338938Sjpaetzel        "TXULP1 ",
71338938Sjpaetzel        "UC ",
72338938Sjpaetzel        "WDMA ",
73338938Sjpaetzel        "TXULP2 ",
74338938Sjpaetzel        "HOST1 ",
75338938Sjpaetzel        "P0_OB_LINK ",
76338938Sjpaetzel        "P1_OB_LINK ",
77338938Sjpaetzel        "HOST_GPIO ",
78338938Sjpaetzel        "MBOX ",
79338938Sjpaetzel        "AXGMAC0",
80338938Sjpaetzel        "AXGMAC1",
81338938Sjpaetzel        "JTAG",
82338938Sjpaetzel        "MPU_INTPEND"
83257007Sdelphij};
84231437Sluigi
85257007Sdelphij/* UE Status High CSR */
86257007Sdelphijstatic char *ue_status_hi_desc[] = {
87338938Sjpaetzel        "LPCMEMHOST",
88338938Sjpaetzel        "MGMT_MAC",
89338938Sjpaetzel        "PCS0ONLINE",
90338938Sjpaetzel        "MPU_IRAM",
91338938Sjpaetzel        "PCS1ONLINE",
92338938Sjpaetzel        "PCTL0",
93338938Sjpaetzel        "PCTL1",
94338938Sjpaetzel        "PMEM",
95338938Sjpaetzel        "RR",
96338938Sjpaetzel        "TXPB",
97338938Sjpaetzel        "RXPP",
98338938Sjpaetzel        "XAUI",
99338938Sjpaetzel        "TXP",
100338938Sjpaetzel        "ARM",
101338938Sjpaetzel        "IPC",
102338938Sjpaetzel        "HOST2",
103338938Sjpaetzel        "HOST3",
104338938Sjpaetzel        "HOST4",
105338938Sjpaetzel        "HOST5",
106338938Sjpaetzel        "HOST6",
107338938Sjpaetzel        "HOST7",
108338938Sjpaetzel        "HOST8",
109338938Sjpaetzel        "HOST9",
110338938Sjpaetzel        "NETC",
111338938Sjpaetzel        "Unknown",
112338938Sjpaetzel        "Unknown",
113338938Sjpaetzel        "Unknown",
114338938Sjpaetzel        "Unknown",
115338938Sjpaetzel        "Unknown",
116338938Sjpaetzel        "Unknown",
117338938Sjpaetzel        "Unknown",
118338938Sjpaetzel        "Unknown"
119257007Sdelphij};
120257007Sdelphij
121338938Sjpaetzelstruct oce_common_cqe_info{
122338938Sjpaetzel        uint8_t vtp:1;
123338938Sjpaetzel        uint8_t l4_cksum_pass:1;
124338938Sjpaetzel        uint8_t ip_cksum_pass:1;
125338938Sjpaetzel        uint8_t ipv6_frame:1;
126338938Sjpaetzel        uint8_t qnq:1;
127338938Sjpaetzel        uint8_t rsvd:3;
128338938Sjpaetzel        uint8_t num_frags;
129338938Sjpaetzel        uint16_t pkt_size;
130338938Sjpaetzel        uint16_t vtag;
131338938Sjpaetzel};
132257007Sdelphij
133338938Sjpaetzel
134231437Sluigi/* Driver entry points prototypes */
135231437Sluigistatic int  oce_probe(device_t dev);
136231437Sluigistatic int  oce_attach(device_t dev);
137231437Sluigistatic int  oce_detach(device_t dev);
138231437Sluigistatic int  oce_shutdown(device_t dev);
139231437Sluigistatic int  oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
140231437Sluigistatic void oce_init(void *xsc);
141231437Sluigistatic int  oce_multiq_start(struct ifnet *ifp, struct mbuf *m);
142231437Sluigistatic void oce_multiq_flush(struct ifnet *ifp);
143231437Sluigi
144231437Sluigi/* Driver interrupt routines protypes */
145231437Sluigistatic void oce_intr(void *arg, int pending);
146231437Sluigistatic int  oce_setup_intr(POCE_SOFTC sc);
147231437Sluigistatic int  oce_fast_isr(void *arg);
148231437Sluigistatic int  oce_alloc_intr(POCE_SOFTC sc, int vector,
149231437Sluigi			  void (*isr) (void *arg, int pending));
150231437Sluigi
151231437Sluigi/* Media callbacks prototypes */
152231437Sluigistatic void oce_media_status(struct ifnet *ifp, struct ifmediareq *req);
153231437Sluigistatic int  oce_media_change(struct ifnet *ifp);
154231437Sluigi
155231437Sluigi/* Transmit routines prototypes */
156231437Sluigistatic int  oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index);
157231437Sluigistatic void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq);
158338938Sjpaetzelstatic void oce_process_tx_completion(struct oce_wq *wq);
159231437Sluigistatic int  oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m,
160231437Sluigi				 struct oce_wq *wq);
161231437Sluigi
162231437Sluigi/* Receive routines prototypes */
163231437Sluigistatic int  oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
164231437Sluigistatic int  oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
165338938Sjpaetzelstatic void oce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe);
166338938Sjpaetzelstatic void oce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq);
167338938Sjpaetzelstatic uint16_t oce_rq_handler_lro(void *arg);
168338938Sjpaetzelstatic void oce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2);
169338938Sjpaetzelstatic void oce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2);
170338938Sjpaetzelstatic void oce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m);
171231437Sluigi
172231437Sluigi/* Helper function prototypes in this file */
173231437Sluigistatic int  oce_attach_ifp(POCE_SOFTC sc);
174231437Sluigistatic void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag);
175231437Sluigistatic void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag);
176231437Sluigistatic int  oce_vid_config(POCE_SOFTC sc);
177231437Sluigistatic void oce_mac_addr_set(POCE_SOFTC sc);
178231437Sluigistatic int  oce_handle_passthrough(struct ifnet *ifp, caddr_t data);
179231437Sluigistatic void oce_local_timer(void *arg);
180231437Sluigistatic void oce_if_deactivate(POCE_SOFTC sc);
181231437Sluigistatic void oce_if_activate(POCE_SOFTC sc);
182231437Sluigistatic void setup_max_queues_want(POCE_SOFTC sc);
183231437Sluigistatic void update_queues_got(POCE_SOFTC sc);
184231879Sluigistatic void process_link_state(POCE_SOFTC sc,
185231879Sluigi		 struct oce_async_cqe_link_state *acqe);
186247880Sdelphijstatic int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m);
187252869Sdelphijstatic void oce_get_config(POCE_SOFTC sc);
188247880Sdelphijstatic struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete);
189338938Sjpaetzelstatic void oce_read_env_variables(POCE_SOFTC sc);
190231437Sluigi
191338938Sjpaetzel
192231879Sluigi/* IP specific */
193231879Sluigi#if defined(INET6) || defined(INET)
194231879Sluigistatic int  oce_init_lro(POCE_SOFTC sc);
195231879Sluigistatic struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp);
196231879Sluigi#endif
197231879Sluigi
198231437Sluigistatic device_method_t oce_dispatch[] = {
199231437Sluigi	DEVMETHOD(device_probe, oce_probe),
200231437Sluigi	DEVMETHOD(device_attach, oce_attach),
201231437Sluigi	DEVMETHOD(device_detach, oce_detach),
202231437Sluigi	DEVMETHOD(device_shutdown, oce_shutdown),
203246128Ssbz
204246128Ssbz	DEVMETHOD_END
205231437Sluigi};
206231437Sluigi
207231437Sluigistatic driver_t oce_driver = {
208231437Sluigi	"oce",
209231437Sluigi	oce_dispatch,
210231437Sluigi	sizeof(OCE_SOFTC)
211231437Sluigi};
212231437Sluigistatic devclass_t oce_devclass;
213231437Sluigi
214231437Sluigi
215231437SluigiDRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0);
216231437SluigiMODULE_DEPEND(oce, pci, 1, 1, 1);
217231437SluigiMODULE_DEPEND(oce, ether, 1, 1, 1);
218231437SluigiMODULE_VERSION(oce, 1);
219231437Sluigi
220231437Sluigi
221231437Sluigi/* global vars */
222231437Sluigiconst char component_revision[32] = {"///" COMPONENT_REVISION "///"};
223231437Sluigi
224231437Sluigi/* Module capabilites and parameters */
225231437Sluigiuint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED;
226231437Sluigiuint32_t oce_enable_rss = OCE_MODCAP_RSS;
227338938Sjpaetzeluint32_t oce_rq_buf_size = 2048;
228231437Sluigi
229231437SluigiTUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled);
230231437SluigiTUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss);
231231437Sluigi
232231437Sluigi
233231437Sluigi/* Supported devices table */
234231437Sluigistatic uint32_t supportedDevices[] =  {
235231437Sluigi	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2,
236231437Sluigi	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3,
237231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3,
238231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201,
239231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF,
240252869Sdelphij	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH
241231437Sluigi};
242231437Sluigi
243338938SjpaetzelPOCE_SOFTC softc_head = NULL;
244338938SjpaetzelPOCE_SOFTC softc_tail = NULL;
245231437Sluigi
246338938Sjpaetzelstruct oce_rdma_if *oce_rdma_if = NULL;
247231437Sluigi
248231437Sluigi/*****************************************************************************
249231437Sluigi *			Driver entry points functions                        *
250231437Sluigi *****************************************************************************/
251231437Sluigi
252231437Sluigistatic int
253231437Sluigioce_probe(device_t dev)
254231437Sluigi{
255231879Sluigi	uint16_t vendor = 0;
256231879Sluigi	uint16_t device = 0;
257231879Sluigi	int i = 0;
258231879Sluigi	char str[256] = {0};
259231437Sluigi	POCE_SOFTC sc;
260231437Sluigi
261231437Sluigi	sc = device_get_softc(dev);
262231437Sluigi	bzero(sc, sizeof(OCE_SOFTC));
263231437Sluigi	sc->dev = dev;
264231437Sluigi
265231437Sluigi	vendor = pci_get_vendor(dev);
266231437Sluigi	device = pci_get_device(dev);
267231437Sluigi
268231879Sluigi	for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) {
269231437Sluigi		if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) {
270231437Sluigi			if (device == (supportedDevices[i] & 0xffff)) {
271231879Sluigi				sprintf(str, "%s:%s", "Emulex CNA NIC function",
272231437Sluigi					component_revision);
273231437Sluigi				device_set_desc_copy(dev, str);
274231437Sluigi
275231437Sluigi				switch (device) {
276231437Sluigi				case PCI_PRODUCT_BE2:
277231437Sluigi					sc->flags |= OCE_FLAGS_BE2;
278231437Sluigi					break;
279231437Sluigi				case PCI_PRODUCT_BE3:
280231437Sluigi					sc->flags |= OCE_FLAGS_BE3;
281231437Sluigi					break;
282231437Sluigi				case PCI_PRODUCT_XE201:
283231437Sluigi				case PCI_PRODUCT_XE201_VF:
284231437Sluigi					sc->flags |= OCE_FLAGS_XE201;
285231437Sluigi					break;
286252869Sdelphij				case PCI_PRODUCT_SH:
287252869Sdelphij					sc->flags |= OCE_FLAGS_SH;
288252869Sdelphij					break;
289231437Sluigi				default:
290231437Sluigi					return ENXIO;
291231437Sluigi				}
292231437Sluigi				return BUS_PROBE_DEFAULT;
293231437Sluigi			}
294231437Sluigi		}
295231437Sluigi	}
296231437Sluigi
297231437Sluigi	return ENXIO;
298231437Sluigi}
299231437Sluigi
300231437Sluigi
301231437Sluigistatic int
302231437Sluigioce_attach(device_t dev)
303231437Sluigi{
304231437Sluigi	POCE_SOFTC sc;
305231437Sluigi	int rc = 0;
306231437Sluigi
307231437Sluigi	sc = device_get_softc(dev);
308231437Sluigi
309231437Sluigi	rc = oce_hw_pci_alloc(sc);
310231437Sluigi	if (rc)
311231437Sluigi		return rc;
312231437Sluigi
313231437Sluigi	sc->tx_ring_size = OCE_TX_RING_SIZE;
314231437Sluigi	sc->rx_ring_size = OCE_RX_RING_SIZE;
315338938Sjpaetzel	/* receive fragment size should be multiple of 2K */
316338938Sjpaetzel	sc->rq_frag_size = ((oce_rq_buf_size / 2048) * 2048);
317231437Sluigi	sc->flow_control = OCE_DEFAULT_FLOW_CONTROL;
318231437Sluigi	sc->promisc	 = OCE_DEFAULT_PROMISCUOUS;
319231437Sluigi
320231437Sluigi	LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock");
321231437Sluigi	LOCK_CREATE(&sc->dev_lock,  "Device_lock");
322231437Sluigi
323231437Sluigi	/* initialise the hardware */
324231437Sluigi	rc = oce_hw_init(sc);
325231437Sluigi	if (rc)
326231437Sluigi		goto pci_res_free;
327231437Sluigi
328338938Sjpaetzel	oce_read_env_variables(sc);
329338938Sjpaetzel
330252869Sdelphij	oce_get_config(sc);
331252869Sdelphij
332231437Sluigi	setup_max_queues_want(sc);
333231437Sluigi
334231437Sluigi	rc = oce_setup_intr(sc);
335231437Sluigi	if (rc)
336231437Sluigi		goto mbox_free;
337231437Sluigi
338231437Sluigi	rc = oce_queue_init_all(sc);
339231437Sluigi	if (rc)
340231437Sluigi		goto intr_free;
341231437Sluigi
342231437Sluigi	rc = oce_attach_ifp(sc);
343231437Sluigi	if (rc)
344231437Sluigi		goto queues_free;
345231437Sluigi
346231511Sbz#if defined(INET6) || defined(INET)
347231437Sluigi	rc = oce_init_lro(sc);
348231437Sluigi	if (rc)
349231879Sluigi		goto ifp_free;
350231511Sbz#endif
351231437Sluigi
352231437Sluigi	rc = oce_hw_start(sc);
353231437Sluigi	if (rc)
354241844Seadler		goto lro_free;
355231437Sluigi
356231437Sluigi	sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
357231437Sluigi				oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST);
358231437Sluigi	sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
359231437Sluigi				oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST);
360231437Sluigi
361231437Sluigi	rc = oce_stats_init(sc);
362231437Sluigi	if (rc)
363231437Sluigi		goto vlan_free;
364231437Sluigi
365231437Sluigi	oce_add_sysctls(sc);
366231437Sluigi
367338938Sjpaetzel	callout_init(&sc->timer, CALLOUT_MPSAFE);
368231437Sluigi	rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc);
369231437Sluigi	if (rc)
370231437Sluigi		goto stats_free;
371231437Sluigi
372338938Sjpaetzel	sc->next =NULL;
373338938Sjpaetzel	if (softc_tail != NULL) {
374338938Sjpaetzel	  softc_tail->next = sc;
375338938Sjpaetzel	} else {
376338938Sjpaetzel	  softc_head = sc;
377338938Sjpaetzel	}
378338938Sjpaetzel	softc_tail = sc;
379338938Sjpaetzel
380231437Sluigi	return 0;
381231437Sluigi
382231437Sluigistats_free:
383231437Sluigi	callout_drain(&sc->timer);
384231437Sluigi	oce_stats_free(sc);
385231437Sluigivlan_free:
386231437Sluigi	if (sc->vlan_attach)
387231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
388231437Sluigi	if (sc->vlan_detach)
389231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
390231437Sluigi	oce_hw_intr_disable(sc);
391231437Sluigilro_free:
392231511Sbz#if defined(INET6) || defined(INET)
393231437Sluigi	oce_free_lro(sc);
394231437Sluigiifp_free:
395231511Sbz#endif
396231437Sluigi	ether_ifdetach(sc->ifp);
397231437Sluigi	if_free(sc->ifp);
398231437Sluigiqueues_free:
399231437Sluigi	oce_queue_release_all(sc);
400231437Sluigiintr_free:
401231437Sluigi	oce_intr_free(sc);
402231437Sluigimbox_free:
403231437Sluigi	oce_dma_free(sc, &sc->bsmbx);
404231437Sluigipci_res_free:
405231437Sluigi	oce_hw_pci_free(sc);
406231437Sluigi	LOCK_DESTROY(&sc->dev_lock);
407231437Sluigi	LOCK_DESTROY(&sc->bmbx_lock);
408231437Sluigi	return rc;
409231437Sluigi
410231437Sluigi}
411231437Sluigi
412231437Sluigi
413231437Sluigistatic int
414231437Sluigioce_detach(device_t dev)
415231437Sluigi{
416231437Sluigi	POCE_SOFTC sc = device_get_softc(dev);
417338938Sjpaetzel	POCE_SOFTC poce_sc_tmp, *ppoce_sc_tmp1, poce_sc_tmp2 = NULL;
418231437Sluigi
419338938Sjpaetzel        poce_sc_tmp = softc_head;
420338938Sjpaetzel        ppoce_sc_tmp1 = &softc_head;
421338938Sjpaetzel        while (poce_sc_tmp != NULL) {
422338938Sjpaetzel          if (poce_sc_tmp == sc) {
423338938Sjpaetzel            *ppoce_sc_tmp1 = sc->next;
424338938Sjpaetzel            if (sc->next == NULL) {
425338938Sjpaetzel              softc_tail = poce_sc_tmp2;
426338938Sjpaetzel            }
427338938Sjpaetzel            break;
428338938Sjpaetzel          }
429338938Sjpaetzel          poce_sc_tmp2 = poce_sc_tmp;
430338938Sjpaetzel          ppoce_sc_tmp1 = &poce_sc_tmp->next;
431338938Sjpaetzel          poce_sc_tmp = poce_sc_tmp->next;
432338938Sjpaetzel        }
433338938Sjpaetzel
434231437Sluigi	LOCK(&sc->dev_lock);
435231437Sluigi	oce_if_deactivate(sc);
436231437Sluigi	UNLOCK(&sc->dev_lock);
437231437Sluigi
438231437Sluigi	callout_drain(&sc->timer);
439231437Sluigi
440231437Sluigi	if (sc->vlan_attach != NULL)
441231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
442231437Sluigi	if (sc->vlan_detach != NULL)
443231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
444231437Sluigi
445231437Sluigi	ether_ifdetach(sc->ifp);
446231437Sluigi
447231437Sluigi	if_free(sc->ifp);
448231437Sluigi
449231437Sluigi	oce_hw_shutdown(sc);
450231437Sluigi
451231437Sluigi	bus_generic_detach(dev);
452231437Sluigi
453231437Sluigi	return 0;
454231437Sluigi}
455231437Sluigi
456231437Sluigi
457231437Sluigistatic int
458231437Sluigioce_shutdown(device_t dev)
459231437Sluigi{
460231437Sluigi	int rc;
461231437Sluigi
462231437Sluigi	rc = oce_detach(dev);
463231437Sluigi
464231437Sluigi	return rc;
465231437Sluigi}
466231437Sluigi
467231437Sluigi
468231437Sluigistatic int
469231437Sluigioce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
470231437Sluigi{
471231437Sluigi	struct ifreq *ifr = (struct ifreq *)data;
472231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
473343300Sdelphij	struct ifi2creq i2c;
474343300Sdelphij	uint8_t	offset = 0;
475231437Sluigi	int rc = 0;
476231437Sluigi	uint32_t u;
477231437Sluigi
478231437Sluigi	switch (command) {
479231437Sluigi
480231437Sluigi	case SIOCGIFMEDIA:
481231437Sluigi		rc = ifmedia_ioctl(ifp, ifr, &sc->media, command);
482231437Sluigi		break;
483231437Sluigi
484231437Sluigi	case SIOCSIFMTU:
485231437Sluigi		if (ifr->ifr_mtu > OCE_MAX_MTU)
486231437Sluigi			rc = EINVAL;
487231437Sluigi		else
488231437Sluigi			ifp->if_mtu = ifr->ifr_mtu;
489231437Sluigi		break;
490231437Sluigi
491231437Sluigi	case SIOCSIFFLAGS:
492231437Sluigi		if (ifp->if_flags & IFF_UP) {
493231437Sluigi			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
494231437Sluigi				sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
495231437Sluigi				oce_init(sc);
496231437Sluigi			}
497231437Sluigi			device_printf(sc->dev, "Interface Up\n");
498231437Sluigi		} else {
499231437Sluigi			LOCK(&sc->dev_lock);
500231437Sluigi
501231437Sluigi			sc->ifp->if_drv_flags &=
502231437Sluigi			    ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
503231437Sluigi			oce_if_deactivate(sc);
504231437Sluigi
505231437Sluigi			UNLOCK(&sc->dev_lock);
506231437Sluigi
507231437Sluigi			device_printf(sc->dev, "Interface Down\n");
508231437Sluigi		}
509231437Sluigi
510231437Sluigi		if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) {
511257007Sdelphij			if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1))))
512257007Sdelphij				sc->promisc = TRUE;
513231437Sluigi		} else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) {
514257007Sdelphij			if (!oce_rxf_set_promiscuous(sc, 0))
515257007Sdelphij				sc->promisc = FALSE;
516231437Sluigi		}
517231437Sluigi
518231437Sluigi		break;
519231437Sluigi
520231437Sluigi	case SIOCADDMULTI:
521231437Sluigi	case SIOCDELMULTI:
522231437Sluigi		rc = oce_hw_update_multicast(sc);
523231437Sluigi		if (rc)
524231437Sluigi			device_printf(sc->dev,
525231437Sluigi				"Update multicast address failed\n");
526231437Sluigi		break;
527231437Sluigi
528231437Sluigi	case SIOCSIFCAP:
529231437Sluigi		u = ifr->ifr_reqcap ^ ifp->if_capenable;
530231437Sluigi
531231437Sluigi		if (u & IFCAP_TXCSUM) {
532231437Sluigi			ifp->if_capenable ^= IFCAP_TXCSUM;
533231437Sluigi			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
534231437Sluigi
535231437Sluigi			if (IFCAP_TSO & ifp->if_capenable &&
536231437Sluigi			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
537362511Sfreqlabs				u &= ~IFCAP_TSO;
538231437Sluigi				ifp->if_capenable &= ~IFCAP_TSO;
539231437Sluigi				ifp->if_hwassist &= ~CSUM_TSO;
540231437Sluigi				if_printf(ifp,
541231437Sluigi					 "TSO disabled due to -txcsum.\n");
542231437Sluigi			}
543231437Sluigi		}
544231437Sluigi
545231437Sluigi		if (u & IFCAP_RXCSUM)
546231437Sluigi			ifp->if_capenable ^= IFCAP_RXCSUM;
547231437Sluigi
548231437Sluigi		if (u & IFCAP_TSO4) {
549231437Sluigi			ifp->if_capenable ^= IFCAP_TSO4;
550231437Sluigi
551231437Sluigi			if (IFCAP_TSO & ifp->if_capenable) {
552231437Sluigi				if (IFCAP_TXCSUM & ifp->if_capenable)
553231437Sluigi					ifp->if_hwassist |= CSUM_TSO;
554231437Sluigi				else {
555231437Sluigi					ifp->if_capenable &= ~IFCAP_TSO;
556231437Sluigi					ifp->if_hwassist &= ~CSUM_TSO;
557231437Sluigi					if_printf(ifp,
558231437Sluigi					    "Enable txcsum first.\n");
559231437Sluigi					rc = EAGAIN;
560231437Sluigi				}
561231437Sluigi			} else
562231437Sluigi				ifp->if_hwassist &= ~CSUM_TSO;
563231437Sluigi		}
564231437Sluigi
565231437Sluigi		if (u & IFCAP_VLAN_HWTAGGING)
566231437Sluigi			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
567231437Sluigi
568231437Sluigi		if (u & IFCAP_VLAN_HWFILTER) {
569231437Sluigi			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
570231437Sluigi			oce_vid_config(sc);
571231437Sluigi		}
572231511Sbz#if defined(INET6) || defined(INET)
573338938Sjpaetzel		if (u & IFCAP_LRO) {
574231437Sluigi			ifp->if_capenable ^= IFCAP_LRO;
575338938Sjpaetzel			if(sc->enable_hwlro) {
576338938Sjpaetzel				if(ifp->if_capenable & IFCAP_LRO) {
577338938Sjpaetzel					rc = oce_mbox_nic_set_iface_lro_config(sc, 1);
578338938Sjpaetzel				}else {
579338938Sjpaetzel					rc = oce_mbox_nic_set_iface_lro_config(sc, 0);
580338938Sjpaetzel				}
581338938Sjpaetzel			}
582338938Sjpaetzel		}
583231511Sbz#endif
584231437Sluigi
585231437Sluigi		break;
586231437Sluigi
587343300Sdelphij	case SIOCGI2C:
588343300Sdelphij		rc = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c));
589343300Sdelphij		if (rc)
590343300Sdelphij			break;
591343300Sdelphij
592343300Sdelphij		if (i2c.dev_addr != PAGE_NUM_A0 &&
593343300Sdelphij		    i2c.dev_addr != PAGE_NUM_A2) {
594343300Sdelphij			rc = EINVAL;
595343300Sdelphij			break;
596343300Sdelphij		}
597343300Sdelphij
598343300Sdelphij		if (i2c.len > sizeof(i2c.data)) {
599343300Sdelphij			rc = EINVAL;
600343300Sdelphij			break;
601343300Sdelphij		}
602343300Sdelphij
603343300Sdelphij		rc = oce_mbox_read_transrecv_data(sc, i2c.dev_addr);
604343300Sdelphij		if(rc) {
605343300Sdelphij			rc = -rc;
606343300Sdelphij			break;
607343300Sdelphij		}
608343300Sdelphij
609343300Sdelphij		if (i2c.dev_addr == PAGE_NUM_A0)
610343300Sdelphij			offset = i2c.offset;
611343300Sdelphij		else
612343300Sdelphij			offset = TRANSCEIVER_A0_SIZE + i2c.offset;
613343300Sdelphij
614343300Sdelphij		memcpy(&i2c.data[0], &sfp_vpd_dump_buffer[offset], i2c.len);
615343300Sdelphij
616343300Sdelphij		rc = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c));
617343300Sdelphij		break;
618343300Sdelphij
619231437Sluigi	case SIOCGPRIVATE_0:
620356090Smarkj		rc = priv_check(curthread, PRIV_DRIVER);
621356090Smarkj		if (rc != 0)
622356090Smarkj			break;
623231437Sluigi		rc = oce_handle_passthrough(ifp, data);
624231437Sluigi		break;
625231437Sluigi	default:
626231437Sluigi		rc = ether_ioctl(ifp, command, data);
627231437Sluigi		break;
628231437Sluigi	}
629231437Sluigi
630231437Sluigi	return rc;
631231437Sluigi}
632231437Sluigi
633231437Sluigi
634231437Sluigistatic void
635231437Sluigioce_init(void *arg)
636231437Sluigi{
637231437Sluigi	POCE_SOFTC sc = arg;
638231437Sluigi
639231437Sluigi	LOCK(&sc->dev_lock);
640231437Sluigi
641231437Sluigi	if (sc->ifp->if_flags & IFF_UP) {
642231437Sluigi		oce_if_deactivate(sc);
643231437Sluigi		oce_if_activate(sc);
644231437Sluigi	}
645231437Sluigi
646231437Sluigi	UNLOCK(&sc->dev_lock);
647231437Sluigi
648231437Sluigi}
649231437Sluigi
650231437Sluigi
651231437Sluigistatic int
652231437Sluigioce_multiq_start(struct ifnet *ifp, struct mbuf *m)
653231437Sluigi{
654231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
655231437Sluigi	struct oce_wq *wq = NULL;
656231437Sluigi	int queue_index = 0;
657231437Sluigi	int status = 0;
658247880Sdelphij
659338938Sjpaetzel	if (!sc->link_status)
660338938Sjpaetzel		return ENXIO;
661338938Sjpaetzel
662275358Shselasky	if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE)
663231437Sluigi		queue_index = m->m_pkthdr.flowid % sc->nwqs;
664252869Sdelphij
665231437Sluigi	wq = sc->wq[queue_index];
666231437Sluigi
667252869Sdelphij	LOCK(&wq->tx_lock);
668252869Sdelphij	status = oce_multiq_transmit(ifp, m, wq);
669252869Sdelphij	UNLOCK(&wq->tx_lock);
670252869Sdelphij
671231437Sluigi	return status;
672231437Sluigi
673231437Sluigi}
674231437Sluigi
675231437Sluigi
676231437Sluigistatic void
677231437Sluigioce_multiq_flush(struct ifnet *ifp)
678231437Sluigi{
679231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
680231437Sluigi	struct mbuf     *m;
681231437Sluigi	int i = 0;
682231437Sluigi
683231437Sluigi	for (i = 0; i < sc->nwqs; i++) {
684231437Sluigi		while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
685231437Sluigi			m_freem(m);
686231437Sluigi	}
687231437Sluigi	if_qflush(ifp);
688231437Sluigi}
689231437Sluigi
690231437Sluigi
691231437Sluigi
692231437Sluigi/*****************************************************************************
693231437Sluigi *                   Driver interrupt routines functions                     *
694231437Sluigi *****************************************************************************/
695231437Sluigi
696231437Sluigistatic void
697231437Sluigioce_intr(void *arg, int pending)
698231437Sluigi{
699231437Sluigi
700231437Sluigi	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
701231437Sluigi	POCE_SOFTC sc = ii->sc;
702231437Sluigi	struct oce_eq *eq = ii->eq;
703231437Sluigi	struct oce_eqe *eqe;
704231437Sluigi	struct oce_cq *cq = NULL;
705231437Sluigi	int i, num_eqes = 0;
706231437Sluigi
707231437Sluigi
708231437Sluigi	bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
709231437Sluigi				 BUS_DMASYNC_POSTWRITE);
710231437Sluigi	do {
711231437Sluigi		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
712231437Sluigi		if (eqe->evnt == 0)
713231437Sluigi			break;
714231437Sluigi		eqe->evnt = 0;
715231437Sluigi		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
716231437Sluigi					BUS_DMASYNC_POSTWRITE);
717231437Sluigi		RING_GET(eq->ring, 1);
718231437Sluigi		num_eqes++;
719231437Sluigi
720231437Sluigi	} while (TRUE);
721231437Sluigi
722231437Sluigi	if (!num_eqes)
723231437Sluigi		goto eq_arm; /* Spurious */
724231437Sluigi
725231437Sluigi 	/* Clear EQ entries, but dont arm */
726231437Sluigi	oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
727231437Sluigi
728231437Sluigi	/* Process TX, RX and MCC. But dont arm CQ*/
729231437Sluigi	for (i = 0; i < eq->cq_valid; i++) {
730231437Sluigi		cq = eq->cq[i];
731231437Sluigi		(*cq->cq_handler)(cq->cb_arg);
732231437Sluigi	}
733231437Sluigi
734231437Sluigi	/* Arm all cqs connected to this EQ */
735231437Sluigi	for (i = 0; i < eq->cq_valid; i++) {
736231437Sluigi		cq = eq->cq[i];
737231437Sluigi		oce_arm_cq(sc, cq->cq_id, 0, TRUE);
738231437Sluigi	}
739231437Sluigi
740231437Sluigieq_arm:
741231437Sluigi	oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
742247880Sdelphij
743231437Sluigi	return;
744231437Sluigi}
745231437Sluigi
746231437Sluigi
747231437Sluigistatic int
748231437Sluigioce_setup_intr(POCE_SOFTC sc)
749231437Sluigi{
750231437Sluigi	int rc = 0, use_intx = 0;
751231437Sluigi	int vector = 0, req_vectors = 0;
752338938Sjpaetzel	int tot_req_vectors, tot_vectors;
753231437Sluigi
754252869Sdelphij	if (is_rss_enabled(sc))
755231437Sluigi		req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
756231437Sluigi	else
757231437Sluigi		req_vectors = 1;
758231437Sluigi
759338938Sjpaetzel	tot_req_vectors = req_vectors;
760338938Sjpaetzel	if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
761338938Sjpaetzel	  if (req_vectors > 1) {
762338938Sjpaetzel	    tot_req_vectors += OCE_RDMA_VECTORS;
763338938Sjpaetzel	    sc->roce_intr_count = OCE_RDMA_VECTORS;
764338938Sjpaetzel	  }
765338938Sjpaetzel	}
766338938Sjpaetzel
767338938Sjpaetzel        if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
768231437Sluigi		sc->intr_count = req_vectors;
769338938Sjpaetzel                tot_vectors = tot_req_vectors;
770338938Sjpaetzel		rc = pci_alloc_msix(sc->dev, &tot_vectors);
771231437Sluigi		if (rc != 0) {
772231437Sluigi			use_intx = 1;
773231437Sluigi			pci_release_msi(sc->dev);
774338938Sjpaetzel		} else {
775338938Sjpaetzel		  if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
776338938Sjpaetzel		    if (tot_vectors < tot_req_vectors) {
777338938Sjpaetzel		      if (sc->intr_count < (2 * OCE_RDMA_VECTORS)) {
778338938Sjpaetzel			sc->roce_intr_count = (tot_vectors / 2);
779338938Sjpaetzel		      }
780338938Sjpaetzel		      sc->intr_count = tot_vectors - sc->roce_intr_count;
781338938Sjpaetzel		    }
782338938Sjpaetzel		  } else {
783338938Sjpaetzel		    sc->intr_count = tot_vectors;
784338938Sjpaetzel		  }
785338938Sjpaetzel    		  sc->flags |= OCE_FLAGS_USING_MSIX;
786338938Sjpaetzel		}
787231437Sluigi	} else
788231437Sluigi		use_intx = 1;
789231437Sluigi
790231437Sluigi	if (use_intx)
791231437Sluigi		sc->intr_count = 1;
792231437Sluigi
793231437Sluigi	/* Scale number of queues based on intr we got */
794231437Sluigi	update_queues_got(sc);
795231437Sluigi
796231437Sluigi	if (use_intx) {
797231437Sluigi		device_printf(sc->dev, "Using legacy interrupt\n");
798231437Sluigi		rc = oce_alloc_intr(sc, vector, oce_intr);
799231437Sluigi		if (rc)
800231437Sluigi			goto error;
801231437Sluigi	} else {
802231437Sluigi		for (; vector < sc->intr_count; vector++) {
803231437Sluigi			rc = oce_alloc_intr(sc, vector, oce_intr);
804231437Sluigi			if (rc)
805231437Sluigi				goto error;
806231437Sluigi		}
807231437Sluigi	}
808231437Sluigi
809231437Sluigi	return 0;
810231437Sluigierror:
811231437Sluigi	oce_intr_free(sc);
812231437Sluigi	return rc;
813231437Sluigi}
814231437Sluigi
815231437Sluigi
816231437Sluigistatic int
817231437Sluigioce_fast_isr(void *arg)
818231437Sluigi{
819231437Sluigi	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
820231437Sluigi	POCE_SOFTC sc = ii->sc;
821231437Sluigi
822231437Sluigi	if (ii->eq == NULL)
823231437Sluigi		return FILTER_STRAY;
824231437Sluigi
825231437Sluigi	oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
826231437Sluigi
827296272Sjhb	taskqueue_enqueue(ii->tq, &ii->task);
828231437Sluigi
829247880Sdelphij 	ii->eq->intr++;
830247880Sdelphij
831231437Sluigi	return FILTER_HANDLED;
832231437Sluigi}
833231437Sluigi
834231437Sluigi
835231437Sluigistatic int
836231437Sluigioce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
837231437Sluigi{
838351143Skevans	POCE_INTR_INFO ii;
839231437Sluigi	int rc = 0, rr;
840231437Sluigi
841231437Sluigi	if (vector >= OCE_MAX_EQ)
842231437Sluigi		return (EINVAL);
843231437Sluigi
844351143Skevans	ii = &sc->intrs[vector];
845351143Skevans
846231437Sluigi	/* Set the resource id for the interrupt.
847231437Sluigi	 * MSIx is vector + 1 for the resource id,
848231437Sluigi	 * INTx is 0 for the resource id.
849231437Sluigi	 */
850231437Sluigi	if (sc->flags & OCE_FLAGS_USING_MSIX)
851231437Sluigi		rr = vector + 1;
852231437Sluigi	else
853231437Sluigi		rr = 0;
854231437Sluigi	ii->intr_res = bus_alloc_resource_any(sc->dev,
855231437Sluigi					      SYS_RES_IRQ,
856231437Sluigi					      &rr, RF_ACTIVE|RF_SHAREABLE);
857231437Sluigi	ii->irq_rr = rr;
858231437Sluigi	if (ii->intr_res == NULL) {
859231437Sluigi		device_printf(sc->dev,
860231437Sluigi			  "Could not allocate interrupt\n");
861231437Sluigi		rc = ENXIO;
862231437Sluigi		return rc;
863231437Sluigi	}
864231437Sluigi
865231437Sluigi	TASK_INIT(&ii->task, 0, isr, ii);
866231437Sluigi	ii->vector = vector;
867231437Sluigi	sprintf(ii->task_name, "oce_task[%d]", ii->vector);
868231437Sluigi	ii->tq = taskqueue_create_fast(ii->task_name,
869231437Sluigi			M_NOWAIT,
870231437Sluigi			taskqueue_thread_enqueue,
871231437Sluigi			&ii->tq);
872231437Sluigi	taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
873231437Sluigi			device_get_nameunit(sc->dev));
874231437Sluigi
875231437Sluigi	ii->sc = sc;
876231437Sluigi	rc = bus_setup_intr(sc->dev,
877231437Sluigi			ii->intr_res,
878231437Sluigi			INTR_TYPE_NET,
879231437Sluigi			oce_fast_isr, NULL, ii, &ii->tag);
880231437Sluigi	return rc;
881231437Sluigi
882231437Sluigi}
883231437Sluigi
884231437Sluigi
885231437Sluigivoid
886231437Sluigioce_intr_free(POCE_SOFTC sc)
887231437Sluigi{
888231437Sluigi	int i = 0;
889231437Sluigi
890231437Sluigi	for (i = 0; i < sc->intr_count; i++) {
891231437Sluigi
892231437Sluigi		if (sc->intrs[i].tag != NULL)
893231437Sluigi			bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
894231437Sluigi						sc->intrs[i].tag);
895231437Sluigi		if (sc->intrs[i].tq != NULL)
896231437Sluigi			taskqueue_free(sc->intrs[i].tq);
897231437Sluigi
898231437Sluigi		if (sc->intrs[i].intr_res != NULL)
899231437Sluigi			bus_release_resource(sc->dev, SYS_RES_IRQ,
900231437Sluigi						sc->intrs[i].irq_rr,
901231437Sluigi						sc->intrs[i].intr_res);
902231437Sluigi		sc->intrs[i].tag = NULL;
903231437Sluigi		sc->intrs[i].intr_res = NULL;
904231437Sluigi	}
905231437Sluigi
906231437Sluigi	if (sc->flags & OCE_FLAGS_USING_MSIX)
907231437Sluigi		pci_release_msi(sc->dev);
908231437Sluigi
909231437Sluigi}
910231437Sluigi
911231437Sluigi
912231437Sluigi
913231437Sluigi/******************************************************************************
914231437Sluigi*			  Media callbacks functions 			      *
915231437Sluigi******************************************************************************/
916231437Sluigi
917231437Sluigistatic void
918231437Sluigioce_media_status(struct ifnet *ifp, struct ifmediareq *req)
919231437Sluigi{
920231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc;
921231437Sluigi
922231437Sluigi
923231437Sluigi	req->ifm_status = IFM_AVALID;
924231437Sluigi	req->ifm_active = IFM_ETHER;
925231437Sluigi
926231437Sluigi	if (sc->link_status == 1)
927231437Sluigi		req->ifm_status |= IFM_ACTIVE;
928231437Sluigi	else
929231437Sluigi		return;
930231437Sluigi
931231437Sluigi	switch (sc->link_speed) {
932231437Sluigi	case 1: /* 10 Mbps */
933231437Sluigi		req->ifm_active |= IFM_10_T | IFM_FDX;
934231437Sluigi		sc->speed = 10;
935231437Sluigi		break;
936231437Sluigi	case 2: /* 100 Mbps */
937231437Sluigi		req->ifm_active |= IFM_100_TX | IFM_FDX;
938231437Sluigi		sc->speed = 100;
939231437Sluigi		break;
940231437Sluigi	case 3: /* 1 Gbps */
941231437Sluigi		req->ifm_active |= IFM_1000_T | IFM_FDX;
942231437Sluigi		sc->speed = 1000;
943231437Sluigi		break;
944231437Sluigi	case 4: /* 10 Gbps */
945231437Sluigi		req->ifm_active |= IFM_10G_SR | IFM_FDX;
946231437Sluigi		sc->speed = 10000;
947231437Sluigi		break;
948267839Sdelphij	case 5: /* 20 Gbps */
949267839Sdelphij		req->ifm_active |= IFM_10G_SR | IFM_FDX;
950267839Sdelphij		sc->speed = 20000;
951267839Sdelphij		break;
952267839Sdelphij	case 6: /* 25 Gbps */
953267839Sdelphij		req->ifm_active |= IFM_10G_SR | IFM_FDX;
954267839Sdelphij		sc->speed = 25000;
955267839Sdelphij		break;
956258941Sdelphij	case 7: /* 40 Gbps */
957258941Sdelphij		req->ifm_active |= IFM_40G_SR4 | IFM_FDX;
958258941Sdelphij		sc->speed = 40000;
959258941Sdelphij		break;
960267839Sdelphij	default:
961267839Sdelphij		sc->speed = 0;
962267839Sdelphij		break;
963231437Sluigi	}
964231437Sluigi
965231437Sluigi	return;
966231437Sluigi}
967231437Sluigi
968231437Sluigi
969231437Sluigiint
970231437Sluigioce_media_change(struct ifnet *ifp)
971231437Sluigi{
972231437Sluigi	return 0;
973231437Sluigi}
974231437Sluigi
975231437Sluigi
976338938Sjpaetzelstatic void oce_is_pkt_dest_bmc(POCE_SOFTC sc,
977338938Sjpaetzel				struct mbuf *m, boolean_t *os2bmc,
978338938Sjpaetzel				struct mbuf **m_new)
979338938Sjpaetzel{
980338938Sjpaetzel	struct ether_header *eh = NULL;
981231437Sluigi
982338938Sjpaetzel	eh = mtod(m, struct ether_header *);
983231437Sluigi
984338938Sjpaetzel	if (!is_os2bmc_enabled(sc) || *os2bmc) {
985338938Sjpaetzel		*os2bmc = FALSE;
986338938Sjpaetzel		goto done;
987338938Sjpaetzel	}
988338938Sjpaetzel	if (!ETHER_IS_MULTICAST(eh->ether_dhost))
989338938Sjpaetzel		goto done;
990338938Sjpaetzel
991338938Sjpaetzel	if (is_mc_allowed_on_bmc(sc, eh) ||
992338938Sjpaetzel	    is_bc_allowed_on_bmc(sc, eh) ||
993338938Sjpaetzel	    is_arp_allowed_on_bmc(sc, ntohs(eh->ether_type))) {
994338938Sjpaetzel		*os2bmc = TRUE;
995338938Sjpaetzel		goto done;
996338938Sjpaetzel	}
997338938Sjpaetzel
998338938Sjpaetzel	if (mtod(m, struct ip *)->ip_p == IPPROTO_IPV6) {
999338938Sjpaetzel		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1000338938Sjpaetzel		uint8_t nexthdr = ip6->ip6_nxt;
1001338938Sjpaetzel		if (nexthdr == IPPROTO_ICMPV6) {
1002338938Sjpaetzel			struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)(ip6 + 1);
1003338938Sjpaetzel			switch (icmp6->icmp6_type) {
1004338938Sjpaetzel			case ND_ROUTER_ADVERT:
1005338938Sjpaetzel				*os2bmc = is_ipv6_ra_filt_enabled(sc);
1006338938Sjpaetzel				goto done;
1007338938Sjpaetzel			case ND_NEIGHBOR_ADVERT:
1008338938Sjpaetzel				*os2bmc = is_ipv6_na_filt_enabled(sc);
1009338938Sjpaetzel				goto done;
1010338938Sjpaetzel			default:
1011338938Sjpaetzel				break;
1012338938Sjpaetzel			}
1013338938Sjpaetzel		}
1014338938Sjpaetzel	}
1015338938Sjpaetzel
1016338938Sjpaetzel	if (mtod(m, struct ip *)->ip_p == IPPROTO_UDP) {
1017338938Sjpaetzel		struct ip *ip = mtod(m, struct ip *);
1018338938Sjpaetzel		int iphlen = ip->ip_hl << 2;
1019338938Sjpaetzel		struct udphdr *uh = (struct udphdr *)((caddr_t)ip + iphlen);
1020338938Sjpaetzel		switch (uh->uh_dport) {
1021338938Sjpaetzel		case DHCP_CLIENT_PORT:
1022338938Sjpaetzel			*os2bmc = is_dhcp_client_filt_enabled(sc);
1023338938Sjpaetzel			goto done;
1024338938Sjpaetzel		case DHCP_SERVER_PORT:
1025338938Sjpaetzel			*os2bmc = is_dhcp_srvr_filt_enabled(sc);
1026338938Sjpaetzel			goto done;
1027338938Sjpaetzel		case NET_BIOS_PORT1:
1028338938Sjpaetzel		case NET_BIOS_PORT2:
1029338938Sjpaetzel			*os2bmc = is_nbios_filt_enabled(sc);
1030338938Sjpaetzel			goto done;
1031338938Sjpaetzel		case DHCPV6_RAS_PORT:
1032338938Sjpaetzel			*os2bmc = is_ipv6_ras_filt_enabled(sc);
1033338938Sjpaetzel			goto done;
1034338938Sjpaetzel		default:
1035338938Sjpaetzel			break;
1036338938Sjpaetzel		}
1037338938Sjpaetzel	}
1038338938Sjpaetzeldone:
1039338938Sjpaetzel	if (*os2bmc) {
1040338938Sjpaetzel		*m_new = m_dup(m, M_NOWAIT);
1041338938Sjpaetzel		if (!*m_new) {
1042338938Sjpaetzel			*os2bmc = FALSE;
1043338938Sjpaetzel			return;
1044338938Sjpaetzel		}
1045338938Sjpaetzel		*m_new = oce_insert_vlan_tag(sc, *m_new, NULL);
1046338938Sjpaetzel	}
1047338938Sjpaetzel}
1048338938Sjpaetzel
1049338938Sjpaetzel
1050338938Sjpaetzel
1051231437Sluigi/*****************************************************************************
1052231437Sluigi *			  Transmit routines functions			     *
1053231437Sluigi *****************************************************************************/
1054231437Sluigi
1055231437Sluigistatic int
1056231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
1057231437Sluigi{
1058231437Sluigi	int rc = 0, i, retry_cnt = 0;
1059231437Sluigi	bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
1060338938Sjpaetzel	struct mbuf *m, *m_temp, *m_new = NULL;
1061231437Sluigi	struct oce_wq *wq = sc->wq[wq_index];
1062231437Sluigi	struct oce_packet_desc *pd;
1063231437Sluigi	struct oce_nic_hdr_wqe *nichdr;
1064231437Sluigi	struct oce_nic_frag_wqe *nicfrag;
1065338938Sjpaetzel	struct ether_header *eh = NULL;
1066231437Sluigi	int num_wqes;
1067231437Sluigi	uint32_t reg_value;
1068247880Sdelphij	boolean_t complete = TRUE;
1069338938Sjpaetzel	boolean_t os2bmc = FALSE;
1070231437Sluigi
1071231437Sluigi	m = *mpp;
1072231437Sluigi	if (!m)
1073231437Sluigi		return EINVAL;
1074231437Sluigi
1075231437Sluigi	if (!(m->m_flags & M_PKTHDR)) {
1076231437Sluigi		rc = ENXIO;
1077231437Sluigi		goto free_ret;
1078231437Sluigi	}
1079231437Sluigi
1080338938Sjpaetzel	/* Don't allow non-TSO packets longer than MTU */
1081338938Sjpaetzel	if (!is_tso_pkt(m)) {
1082338938Sjpaetzel		eh = mtod(m, struct ether_header *);
1083338938Sjpaetzel		if(m->m_pkthdr.len > ETHER_MAX_FRAME(sc->ifp, eh->ether_type, FALSE))
1084338938Sjpaetzel			 goto free_ret;
1085338938Sjpaetzel	}
1086338938Sjpaetzel
1087247880Sdelphij	if(oce_tx_asic_stall_verify(sc, m)) {
1088247880Sdelphij		m = oce_insert_vlan_tag(sc, m, &complete);
1089247880Sdelphij		if(!m) {
1090247880Sdelphij			device_printf(sc->dev, "Insertion unsuccessful\n");
1091247880Sdelphij			return 0;
1092247880Sdelphij		}
1093247880Sdelphij
1094247880Sdelphij	}
1095247880Sdelphij
1096338938Sjpaetzel	/* Lancer, SH ASIC has a bug wherein Packets that are 32 bytes or less
1097338938Sjpaetzel	 * may cause a transmit stall on that port. So the work-around is to
1098338938Sjpaetzel	 * pad short packets (<= 32 bytes) to a 36-byte length.
1099338938Sjpaetzel	*/
1100338938Sjpaetzel	if(IS_SH(sc) || IS_XE201(sc) ) {
1101338938Sjpaetzel		if(m->m_pkthdr.len <= 32) {
1102338938Sjpaetzel			char buf[36];
1103338938Sjpaetzel			bzero((void *)buf, 36);
1104338938Sjpaetzel			m_append(m, (36 - m->m_pkthdr.len), buf);
1105338938Sjpaetzel		}
1106338938Sjpaetzel	}
1107338938Sjpaetzel
1108338938Sjpaetzeltx_start:
1109231437Sluigi	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
1110231879Sluigi		/* consolidate packet buffers for TSO/LSO segment offload */
1111231511Sbz#if defined(INET6) || defined(INET)
1112231879Sluigi		m = oce_tso_setup(sc, mpp);
1113231511Sbz#else
1114231511Sbz		m = NULL;
1115231511Sbz#endif
1116231437Sluigi		if (m == NULL) {
1117231437Sluigi			rc = ENXIO;
1118231437Sluigi			goto free_ret;
1119231437Sluigi		}
1120231437Sluigi	}
1121231437Sluigi
1122338938Sjpaetzel
1123252869Sdelphij	pd = &wq->pckts[wq->pkt_desc_head];
1124338938Sjpaetzel
1125231437Sluigiretry:
1126231437Sluigi	rc = bus_dmamap_load_mbuf_sg(wq->tag,
1127231437Sluigi				     pd->map,
1128231437Sluigi				     m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
1129231437Sluigi	if (rc == 0) {
1130231437Sluigi		num_wqes = pd->nsegs + 1;
1131252869Sdelphij		if (IS_BE(sc) || IS_SH(sc)) {
1132231437Sluigi			/*Dummy required only for BE3.*/
1133231437Sluigi			if (num_wqes & 1)
1134231437Sluigi				num_wqes++;
1135231437Sluigi		}
1136231437Sluigi		if (num_wqes >= RING_NUM_FREE(wq->ring)) {
1137231437Sluigi			bus_dmamap_unload(wq->tag, pd->map);
1138231437Sluigi			return EBUSY;
1139231437Sluigi		}
1140252869Sdelphij		atomic_store_rel_int(&wq->pkt_desc_head,
1141252869Sdelphij				     (wq->pkt_desc_head + 1) % \
1142252869Sdelphij				      OCE_WQ_PACKET_ARRAY_SIZE);
1143231437Sluigi		bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
1144231437Sluigi		pd->mbuf = m;
1145231437Sluigi
1146231437Sluigi		nichdr =
1147231437Sluigi		    RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
1148231437Sluigi		nichdr->u0.dw[0] = 0;
1149231437Sluigi		nichdr->u0.dw[1] = 0;
1150231437Sluigi		nichdr->u0.dw[2] = 0;
1151231437Sluigi		nichdr->u0.dw[3] = 0;
1152231437Sluigi
1153247880Sdelphij		nichdr->u0.s.complete = complete;
1154338938Sjpaetzel		nichdr->u0.s.mgmt = os2bmc;
1155231437Sluigi		nichdr->u0.s.event = 1;
1156231437Sluigi		nichdr->u0.s.crc = 1;
1157231437Sluigi		nichdr->u0.s.forward = 0;
1158231437Sluigi		nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
1159231437Sluigi		nichdr->u0.s.udpcs =
1160247880Sdelphij			(m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
1161231437Sluigi		nichdr->u0.s.tcpcs =
1162247880Sdelphij			(m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
1163231437Sluigi		nichdr->u0.s.num_wqe = num_wqes;
1164231437Sluigi		nichdr->u0.s.total_length = m->m_pkthdr.len;
1165257007Sdelphij
1166231437Sluigi		if (m->m_flags & M_VLANTAG) {
1167231437Sluigi			nichdr->u0.s.vlan = 1; /*Vlan present*/
1168231437Sluigi			nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
1169231437Sluigi		}
1170257007Sdelphij
1171231437Sluigi		if (m->m_pkthdr.csum_flags & CSUM_TSO) {
1172231437Sluigi			if (m->m_pkthdr.tso_segsz) {
1173231437Sluigi				nichdr->u0.s.lso = 1;
1174231437Sluigi				nichdr->u0.s.lso_mss  = m->m_pkthdr.tso_segsz;
1175231437Sluigi			}
1176252869Sdelphij			if (!IS_BE(sc) || !IS_SH(sc))
1177231437Sluigi				nichdr->u0.s.ipcs = 1;
1178231437Sluigi		}
1179231437Sluigi
1180231437Sluigi		RING_PUT(wq->ring, 1);
1181252869Sdelphij		atomic_add_int(&wq->ring->num_used, 1);
1182231437Sluigi
1183231437Sluigi		for (i = 0; i < pd->nsegs; i++) {
1184231437Sluigi			nicfrag =
1185231437Sluigi			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
1186231437Sluigi						      struct oce_nic_frag_wqe);
1187231437Sluigi			nicfrag->u0.s.rsvd0 = 0;
1188231437Sluigi			nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
1189231437Sluigi			nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
1190231437Sluigi			nicfrag->u0.s.frag_len = segs[i].ds_len;
1191231437Sluigi			pd->wqe_idx = wq->ring->pidx;
1192231437Sluigi			RING_PUT(wq->ring, 1);
1193252869Sdelphij			atomic_add_int(&wq->ring->num_used, 1);
1194231437Sluigi		}
1195231437Sluigi		if (num_wqes > (pd->nsegs + 1)) {
1196231437Sluigi			nicfrag =
1197231437Sluigi			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
1198231437Sluigi						      struct oce_nic_frag_wqe);
1199231437Sluigi			nicfrag->u0.dw[0] = 0;
1200231437Sluigi			nicfrag->u0.dw[1] = 0;
1201231437Sluigi			nicfrag->u0.dw[2] = 0;
1202231437Sluigi			nicfrag->u0.dw[3] = 0;
1203231437Sluigi			pd->wqe_idx = wq->ring->pidx;
1204231437Sluigi			RING_PUT(wq->ring, 1);
1205252869Sdelphij			atomic_add_int(&wq->ring->num_used, 1);
1206231437Sluigi			pd->nsegs++;
1207231437Sluigi		}
1208231437Sluigi
1209271849Sglebius		if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
1210231437Sluigi		wq->tx_stats.tx_reqs++;
1211231437Sluigi		wq->tx_stats.tx_wrbs += num_wqes;
1212231437Sluigi		wq->tx_stats.tx_bytes += m->m_pkthdr.len;
1213231437Sluigi		wq->tx_stats.tx_pkts++;
1214247880Sdelphij
1215231437Sluigi		bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
1216231437Sluigi				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1217231437Sluigi		reg_value = (num_wqes << 16) | wq->wq_id;
1218338938Sjpaetzel
1219338938Sjpaetzel		/* if os2bmc is not enabled or if the pkt is already tagged as
1220338938Sjpaetzel		   bmc, do nothing
1221338938Sjpaetzel		 */
1222338938Sjpaetzel		oce_is_pkt_dest_bmc(sc, m, &os2bmc, &m_new);
1223338938Sjpaetzel
1224252869Sdelphij		OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value);
1225231437Sluigi
1226231437Sluigi	} else if (rc == EFBIG)	{
1227231437Sluigi		if (retry_cnt == 0) {
1228243857Sglebius			m_temp = m_defrag(m, M_NOWAIT);
1229231437Sluigi			if (m_temp == NULL)
1230231437Sluigi				goto free_ret;
1231231437Sluigi			m = m_temp;
1232231437Sluigi			*mpp = m_temp;
1233231437Sluigi			retry_cnt = retry_cnt + 1;
1234231437Sluigi			goto retry;
1235231437Sluigi		} else
1236231437Sluigi			goto free_ret;
1237231437Sluigi	} else if (rc == ENOMEM)
1238231437Sluigi		return rc;
1239231437Sluigi	else
1240231437Sluigi		goto free_ret;
1241338938Sjpaetzel
1242338938Sjpaetzel	if (os2bmc) {
1243338938Sjpaetzel		m = m_new;
1244338938Sjpaetzel		goto tx_start;
1245338938Sjpaetzel	}
1246252869Sdelphij
1247231437Sluigi	return 0;
1248231437Sluigi
1249231437Sluigifree_ret:
1250231437Sluigi	m_freem(*mpp);
1251231437Sluigi	*mpp = NULL;
1252231437Sluigi	return rc;
1253231437Sluigi}
1254231437Sluigi
1255231437Sluigi
1256231437Sluigistatic void
1257338938Sjpaetzeloce_process_tx_completion(struct oce_wq *wq)
1258231437Sluigi{
1259231437Sluigi	struct oce_packet_desc *pd;
1260231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
1261231437Sluigi	struct mbuf *m;
1262231437Sluigi
1263252869Sdelphij	pd = &wq->pckts[wq->pkt_desc_tail];
1264252869Sdelphij	atomic_store_rel_int(&wq->pkt_desc_tail,
1265252869Sdelphij			     (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE);
1266252869Sdelphij	atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1);
1267231437Sluigi	bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1268231437Sluigi	bus_dmamap_unload(wq->tag, pd->map);
1269231437Sluigi
1270231437Sluigi	m = pd->mbuf;
1271231437Sluigi	m_freem(m);
1272231437Sluigi	pd->mbuf = NULL;
1273231437Sluigi
1274252869Sdelphij
1275231437Sluigi	if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1276231437Sluigi		if (wq->ring->num_used < (wq->ring->num_items / 2)) {
1277231437Sluigi			sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
1278231437Sluigi			oce_tx_restart(sc, wq);
1279231437Sluigi		}
1280231437Sluigi	}
1281231437Sluigi}
1282231437Sluigi
1283231437Sluigi
1284231437Sluigistatic void
1285231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
1286231437Sluigi{
1287231437Sluigi
1288231437Sluigi	if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
1289231437Sluigi		return;
1290231437Sluigi
1291231437Sluigi#if __FreeBSD_version >= 800000
1292231437Sluigi	if (!drbr_empty(sc->ifp, wq->br))
1293231437Sluigi#else
1294231437Sluigi	if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd))
1295231437Sluigi#endif
1296296272Sjhb		taskqueue_enqueue(taskqueue_swi, &wq->txtask);
1297231437Sluigi
1298231437Sluigi}
1299231437Sluigi
1300231879Sluigi
1301231511Sbz#if defined(INET6) || defined(INET)
1302231437Sluigistatic struct mbuf *
1303231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
1304231437Sluigi{
1305231437Sluigi	struct mbuf *m;
1306231511Sbz#ifdef INET
1307231437Sluigi	struct ip *ip;
1308231511Sbz#endif
1309231511Sbz#ifdef INET6
1310231437Sluigi	struct ip6_hdr *ip6;
1311231511Sbz#endif
1312231437Sluigi	struct ether_vlan_header *eh;
1313231437Sluigi	struct tcphdr *th;
1314231437Sluigi	uint16_t etype;
1315231879Sluigi	int total_len = 0, ehdrlen = 0;
1316231437Sluigi
1317231437Sluigi	m = *mpp;
1318231437Sluigi
1319231437Sluigi	if (M_WRITABLE(m) == 0) {
1320243857Sglebius		m = m_dup(*mpp, M_NOWAIT);
1321231437Sluigi		if (!m)
1322231437Sluigi			return NULL;
1323231437Sluigi		m_freem(*mpp);
1324231437Sluigi		*mpp = m;
1325231437Sluigi	}
1326231437Sluigi
1327231437Sluigi	eh = mtod(m, struct ether_vlan_header *);
1328231437Sluigi	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
1329231437Sluigi		etype = ntohs(eh->evl_proto);
1330231437Sluigi		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1331231437Sluigi	} else {
1332231437Sluigi		etype = ntohs(eh->evl_encap_proto);
1333231437Sluigi		ehdrlen = ETHER_HDR_LEN;
1334231437Sluigi	}
1335231437Sluigi
1336231437Sluigi	switch (etype) {
1337231511Sbz#ifdef INET
1338231437Sluigi	case ETHERTYPE_IP:
1339231437Sluigi		ip = (struct ip *)(m->m_data + ehdrlen);
1340231437Sluigi		if (ip->ip_p != IPPROTO_TCP)
1341231437Sluigi			return NULL;
1342231437Sluigi		th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
1343231437Sluigi
1344231437Sluigi		total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
1345231437Sluigi		break;
1346231511Sbz#endif
1347231511Sbz#ifdef INET6
1348231437Sluigi	case ETHERTYPE_IPV6:
1349231437Sluigi		ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
1350231437Sluigi		if (ip6->ip6_nxt != IPPROTO_TCP)
1351231437Sluigi			return NULL;
1352231437Sluigi		th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
1353231437Sluigi
1354231437Sluigi		total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
1355231437Sluigi		break;
1356231511Sbz#endif
1357231437Sluigi	default:
1358231437Sluigi		return NULL;
1359231437Sluigi	}
1360231437Sluigi
1361231437Sluigi	m = m_pullup(m, total_len);
1362231437Sluigi	if (!m)
1363231437Sluigi		return NULL;
1364231437Sluigi	*mpp = m;
1365231437Sluigi	return m;
1366231437Sluigi
1367231437Sluigi}
1368231511Sbz#endif /* INET6 || INET */
1369231437Sluigi
1370231437Sluigivoid
1371231437Sluigioce_tx_task(void *arg, int npending)
1372231437Sluigi{
1373231437Sluigi	struct oce_wq *wq = arg;
1374231437Sluigi	POCE_SOFTC sc = wq->parent;
1375231437Sluigi	struct ifnet *ifp = sc->ifp;
1376231437Sluigi	int rc = 0;
1377252869Sdelphij
1378231437Sluigi#if __FreeBSD_version >= 800000
1379252869Sdelphij	LOCK(&wq->tx_lock);
1380252869Sdelphij	rc = oce_multiq_transmit(ifp, NULL, wq);
1381252869Sdelphij	if (rc) {
1382252869Sdelphij		device_printf(sc->dev,
1383252869Sdelphij				"TX[%d] restart failed\n", wq->queue_index);
1384231437Sluigi	}
1385252869Sdelphij	UNLOCK(&wq->tx_lock);
1386231437Sluigi#else
1387231437Sluigi	oce_start(ifp);
1388231437Sluigi#endif
1389231437Sluigi
1390231437Sluigi}
1391231437Sluigi
1392231437Sluigi
1393231437Sluigivoid
1394231437Sluigioce_start(struct ifnet *ifp)
1395231437Sluigi{
1396231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1397231437Sluigi	struct mbuf *m;
1398231437Sluigi	int rc = 0;
1399231879Sluigi	int def_q = 0; /* Defualt tx queue is 0*/
1400231437Sluigi
1401231437Sluigi	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1402231437Sluigi			IFF_DRV_RUNNING)
1403231437Sluigi		return;
1404247880Sdelphij
1405247880Sdelphij	if (!sc->link_status)
1406247880Sdelphij		return;
1407231437Sluigi
1408231437Sluigi	do {
1409231437Sluigi		IF_DEQUEUE(&sc->ifp->if_snd, m);
1410231437Sluigi		if (m == NULL)
1411231437Sluigi			break;
1412231879Sluigi
1413231879Sluigi		LOCK(&sc->wq[def_q]->tx_lock);
1414231879Sluigi		rc = oce_tx(sc, &m, def_q);
1415231879Sluigi		UNLOCK(&sc->wq[def_q]->tx_lock);
1416231437Sluigi		if (rc) {
1417231437Sluigi			if (m != NULL) {
1418231879Sluigi				sc->wq[def_q]->tx_stats.tx_stops ++;
1419231437Sluigi				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1420231437Sluigi				IFQ_DRV_PREPEND(&ifp->if_snd, m);
1421231437Sluigi				m = NULL;
1422231437Sluigi			}
1423231437Sluigi			break;
1424231437Sluigi		}
1425231437Sluigi		if (m != NULL)
1426231437Sluigi			ETHER_BPF_MTAP(ifp, m);
1427231437Sluigi
1428231879Sluigi	} while (TRUE);
1429231437Sluigi
1430231437Sluigi	return;
1431231437Sluigi}
1432231437Sluigi
1433231437Sluigi
1434231437Sluigi/* Handle the Completion Queue for transmit */
1435231437Sluigiuint16_t
1436231437Sluigioce_wq_handler(void *arg)
1437231437Sluigi{
1438231437Sluigi	struct oce_wq *wq = (struct oce_wq *)arg;
1439231437Sluigi	POCE_SOFTC sc = wq->parent;
1440231437Sluigi	struct oce_cq *cq = wq->cq;
1441231437Sluigi	struct oce_nic_tx_cqe *cqe;
1442231437Sluigi	int num_cqes = 0;
1443231437Sluigi
1444338938Sjpaetzel	LOCK(&wq->tx_compl_lock);
1445231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
1446231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1447231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1448231437Sluigi	while (cqe->u0.dw[3]) {
1449231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
1450231437Sluigi
1451231437Sluigi		wq->ring->cidx = cqe->u0.s.wqe_index + 1;
1452231437Sluigi		if (wq->ring->cidx >= wq->ring->num_items)
1453231437Sluigi			wq->ring->cidx -= wq->ring->num_items;
1454231437Sluigi
1455338938Sjpaetzel		oce_process_tx_completion(wq);
1456231437Sluigi		wq->tx_stats.tx_compl++;
1457231437Sluigi		cqe->u0.dw[3] = 0;
1458231437Sluigi		RING_GET(cq->ring, 1);
1459231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
1460231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1461231437Sluigi		cqe =
1462231437Sluigi		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1463231437Sluigi		num_cqes++;
1464231437Sluigi	}
1465231437Sluigi
1466231437Sluigi	if (num_cqes)
1467231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1468338938Sjpaetzel
1469338938Sjpaetzel	UNLOCK(&wq->tx_compl_lock);
1470338938Sjpaetzel	return num_cqes;
1471231437Sluigi}
1472231437Sluigi
1473231437Sluigi
1474231437Sluigistatic int
1475231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq)
1476231437Sluigi{
1477231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1478231437Sluigi	int status = 0, queue_index = 0;
1479231437Sluigi	struct mbuf *next = NULL;
1480231437Sluigi	struct buf_ring *br = NULL;
1481231437Sluigi
1482231437Sluigi	br  = wq->br;
1483231437Sluigi	queue_index = wq->queue_index;
1484231437Sluigi
1485231437Sluigi	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1486231437Sluigi		IFF_DRV_RUNNING) {
1487231437Sluigi		if (m != NULL)
1488231437Sluigi			status = drbr_enqueue(ifp, br, m);
1489231437Sluigi		return status;
1490231437Sluigi	}
1491231437Sluigi
1492257007Sdelphij	if (m != NULL) {
1493231437Sluigi		if ((status = drbr_enqueue(ifp, br, m)) != 0)
1494231437Sluigi			return status;
1495246482Srrs	}
1496246482Srrs	while ((next = drbr_peek(ifp, br)) != NULL) {
1497231437Sluigi		if (oce_tx(sc, &next, queue_index)) {
1498246482Srrs			if (next == NULL) {
1499246482Srrs				drbr_advance(ifp, br);
1500246482Srrs			} else {
1501246482Srrs				drbr_putback(ifp, br, next);
1502231437Sluigi				wq->tx_stats.tx_stops ++;
1503231437Sluigi				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1504231437Sluigi			}
1505231437Sluigi			break;
1506231437Sluigi		}
1507246482Srrs		drbr_advance(ifp, br);
1508271849Sglebius		if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len);
1509241037Sglebius		if (next->m_flags & M_MCAST)
1510271849Sglebius			if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
1511231437Sluigi		ETHER_BPF_MTAP(ifp, next);
1512231437Sluigi	}
1513231437Sluigi
1514268156Sluigi	return 0;
1515231437Sluigi}
1516231437Sluigi
1517231437Sluigi
1518231437Sluigi
1519231437Sluigi
1520231437Sluigi/*****************************************************************************
1521231437Sluigi *			    Receive  routines functions 		     *
1522231437Sluigi *****************************************************************************/
1523231437Sluigi
1524231437Sluigistatic void
1525338938Sjpaetzeloce_correct_header(struct mbuf *m, struct nic_hwlro_cqe_part1 *cqe1, struct nic_hwlro_cqe_part2 *cqe2)
1526231437Sluigi{
1527338938Sjpaetzel	uint32_t *p;
1528338938Sjpaetzel        struct ether_header *eh = NULL;
1529338938Sjpaetzel        struct tcphdr *tcp_hdr = NULL;
1530338938Sjpaetzel        struct ip *ip4_hdr = NULL;
1531338938Sjpaetzel        struct ip6_hdr *ip6 = NULL;
1532338938Sjpaetzel        uint32_t payload_len = 0;
1533338938Sjpaetzel
1534338938Sjpaetzel        eh = mtod(m, struct ether_header *);
1535338938Sjpaetzel        /* correct IP header */
1536338938Sjpaetzel        if(!cqe2->ipv6_frame) {
1537338938Sjpaetzel		ip4_hdr = (struct ip *)((char*)eh + sizeof(struct ether_header));
1538338938Sjpaetzel                ip4_hdr->ip_ttl = cqe2->frame_lifespan;
1539338938Sjpaetzel                ip4_hdr->ip_len = htons(cqe2->coalesced_size - sizeof(struct ether_header));
1540338938Sjpaetzel                tcp_hdr = (struct tcphdr *)((char*)ip4_hdr + sizeof(struct ip));
1541338938Sjpaetzel        }else {
1542338938Sjpaetzel        	ip6 = (struct ip6_hdr *)((char*)eh + sizeof(struct ether_header));
1543338938Sjpaetzel                ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = cqe2->frame_lifespan;
1544338938Sjpaetzel                payload_len = cqe2->coalesced_size - sizeof(struct ether_header)
1545338938Sjpaetzel                                                - sizeof(struct ip6_hdr);
1546338938Sjpaetzel                ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(payload_len);
1547338938Sjpaetzel                tcp_hdr = (struct tcphdr *)((char*)ip6 + sizeof(struct ip6_hdr));
1548338938Sjpaetzel        }
1549338938Sjpaetzel
1550338938Sjpaetzel        /* correct tcp header */
1551338938Sjpaetzel        tcp_hdr->th_ack = htonl(cqe2->tcp_ack_num);
1552338938Sjpaetzel        if(cqe2->push) {
1553338938Sjpaetzel        	tcp_hdr->th_flags |= TH_PUSH;
1554338938Sjpaetzel        }
1555338938Sjpaetzel        tcp_hdr->th_win = htons(cqe2->tcp_window);
1556338938Sjpaetzel        tcp_hdr->th_sum = 0xffff;
1557338938Sjpaetzel        if(cqe2->ts_opt) {
1558338938Sjpaetzel                p = (uint32_t *)((char*)tcp_hdr + sizeof(struct tcphdr) + 2);
1559338938Sjpaetzel                *p = cqe1->tcp_timestamp_val;
1560338938Sjpaetzel                *(p+1) = cqe1->tcp_timestamp_ecr;
1561338938Sjpaetzel        }
1562338938Sjpaetzel
1563338938Sjpaetzel	return;
1564338938Sjpaetzel}
1565338938Sjpaetzel
1566338938Sjpaetzelstatic void
1567338938Sjpaetzeloce_rx_mbuf_chain(struct oce_rq *rq, struct oce_common_cqe_info *cqe_info, struct mbuf **m)
1568338938Sjpaetzel{
1569231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1570338938Sjpaetzel        uint32_t i = 0, frag_len = 0;
1571338938Sjpaetzel	uint32_t len = cqe_info->pkt_size;
1572338938Sjpaetzel        struct oce_packet_desc *pd;
1573338938Sjpaetzel        struct mbuf *tail = NULL;
1574231437Sluigi
1575338938Sjpaetzel        for (i = 0; i < cqe_info->num_frags; i++) {
1576338938Sjpaetzel                if (rq->ring->cidx == rq->ring->pidx) {
1577338938Sjpaetzel                        device_printf(sc->dev,
1578338938Sjpaetzel                                  "oce_rx_mbuf_chain: Invalid RX completion - Queue is empty\n");
1579338938Sjpaetzel                        return;
1580338938Sjpaetzel                }
1581338938Sjpaetzel                pd = &rq->pckts[rq->ring->cidx];
1582338938Sjpaetzel
1583338938Sjpaetzel                bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1584338938Sjpaetzel                bus_dmamap_unload(rq->tag, pd->map);
1585338938Sjpaetzel		RING_GET(rq->ring, 1);
1586338938Sjpaetzel                rq->pending--;
1587338938Sjpaetzel
1588338938Sjpaetzel                frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
1589338938Sjpaetzel                pd->mbuf->m_len = frag_len;
1590338938Sjpaetzel
1591338938Sjpaetzel                if (tail != NULL) {
1592338938Sjpaetzel                        /* additional fragments */
1593338938Sjpaetzel                        pd->mbuf->m_flags &= ~M_PKTHDR;
1594338938Sjpaetzel                        tail->m_next = pd->mbuf;
1595338938Sjpaetzel			if(rq->islro)
1596338938Sjpaetzel                        	tail->m_nextpkt = NULL;
1597338938Sjpaetzel                        tail = pd->mbuf;
1598338938Sjpaetzel                } else {
1599338938Sjpaetzel                        /* first fragment, fill out much of the packet header */
1600338938Sjpaetzel                        pd->mbuf->m_pkthdr.len = len;
1601338938Sjpaetzel			if(rq->islro)
1602338938Sjpaetzel                        	pd->mbuf->m_nextpkt = NULL;
1603338938Sjpaetzel                        pd->mbuf->m_pkthdr.csum_flags = 0;
1604338938Sjpaetzel                        if (IF_CSUM_ENABLED(sc)) {
1605338938Sjpaetzel                                if (cqe_info->l4_cksum_pass) {
1606338938Sjpaetzel                                        if(!cqe_info->ipv6_frame) { /* IPV4 */
1607338938Sjpaetzel                                                pd->mbuf->m_pkthdr.csum_flags |=
1608338938Sjpaetzel                                                        (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1609338938Sjpaetzel                                        }else { /* IPV6 frame */
1610338938Sjpaetzel						if(rq->islro) {
1611338938Sjpaetzel                                                	pd->mbuf->m_pkthdr.csum_flags |=
1612338938Sjpaetzel                                                        (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1613338938Sjpaetzel						}
1614338938Sjpaetzel                                        }
1615338938Sjpaetzel                                        pd->mbuf->m_pkthdr.csum_data = 0xffff;
1616338938Sjpaetzel                                }
1617338938Sjpaetzel                                if (cqe_info->ip_cksum_pass) {
1618338938Sjpaetzel                                        pd->mbuf->m_pkthdr.csum_flags |=
1619338938Sjpaetzel                                               (CSUM_IP_CHECKED|CSUM_IP_VALID);
1620338938Sjpaetzel                                }
1621338938Sjpaetzel                        }
1622338938Sjpaetzel                        *m = tail = pd->mbuf;
1623338938Sjpaetzel               }
1624338938Sjpaetzel                pd->mbuf = NULL;
1625338938Sjpaetzel                len -= frag_len;
1626338938Sjpaetzel        }
1627338938Sjpaetzel
1628338938Sjpaetzel        return;
1629338938Sjpaetzel}
1630338938Sjpaetzel
1631338938Sjpaetzelstatic void
1632338938Sjpaetzeloce_rx_lro(struct oce_rq *rq, struct nic_hwlro_singleton_cqe *cqe, struct nic_hwlro_cqe_part2 *cqe2)
1633338938Sjpaetzel{
1634338938Sjpaetzel        POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1635338938Sjpaetzel        struct nic_hwlro_cqe_part1 *cqe1 = NULL;
1636338938Sjpaetzel        struct mbuf *m = NULL;
1637338938Sjpaetzel	struct oce_common_cqe_info cq_info;
1638338938Sjpaetzel
1639338938Sjpaetzel	/* parse cqe */
1640338938Sjpaetzel        if(cqe2 == NULL) {
1641338938Sjpaetzel                cq_info.pkt_size =  cqe->pkt_size;
1642338938Sjpaetzel                cq_info.vtag = cqe->vlan_tag;
1643338938Sjpaetzel                cq_info.l4_cksum_pass = cqe->l4_cksum_pass;
1644338938Sjpaetzel                cq_info.ip_cksum_pass = cqe->ip_cksum_pass;
1645338938Sjpaetzel                cq_info.ipv6_frame = cqe->ipv6_frame;
1646338938Sjpaetzel                cq_info.vtp = cqe->vtp;
1647338938Sjpaetzel                cq_info.qnq = cqe->qnq;
1648338938Sjpaetzel        }else {
1649338938Sjpaetzel                cqe1 = (struct nic_hwlro_cqe_part1 *)cqe;
1650338938Sjpaetzel                cq_info.pkt_size =  cqe2->coalesced_size;
1651338938Sjpaetzel                cq_info.vtag = cqe2->vlan_tag;
1652338938Sjpaetzel                cq_info.l4_cksum_pass = cqe2->l4_cksum_pass;
1653338938Sjpaetzel                cq_info.ip_cksum_pass = cqe2->ip_cksum_pass;
1654338938Sjpaetzel                cq_info.ipv6_frame = cqe2->ipv6_frame;
1655338938Sjpaetzel                cq_info.vtp = cqe2->vtp;
1656338938Sjpaetzel                cq_info.qnq = cqe1->qnq;
1657338938Sjpaetzel        }
1658338938Sjpaetzel
1659338938Sjpaetzel	cq_info.vtag = BSWAP_16(cq_info.vtag);
1660338938Sjpaetzel
1661338938Sjpaetzel        cq_info.num_frags = cq_info.pkt_size / rq->cfg.frag_size;
1662338938Sjpaetzel        if(cq_info.pkt_size % rq->cfg.frag_size)
1663338938Sjpaetzel                cq_info.num_frags++;
1664338938Sjpaetzel
1665338938Sjpaetzel	oce_rx_mbuf_chain(rq, &cq_info, &m);
1666338938Sjpaetzel
1667338938Sjpaetzel	if (m) {
1668338938Sjpaetzel		if(cqe2) {
1669338938Sjpaetzel			//assert(cqe2->valid != 0);
1670338938Sjpaetzel
1671338938Sjpaetzel			//assert(cqe2->cqe_type != 2);
1672338938Sjpaetzel			oce_correct_header(m, cqe1, cqe2);
1673338938Sjpaetzel		}
1674338938Sjpaetzel
1675338938Sjpaetzel		m->m_pkthdr.rcvif = sc->ifp;
1676338938Sjpaetzel#if __FreeBSD_version >= 800000
1677338938Sjpaetzel		if (rq->queue_index)
1678338938Sjpaetzel			m->m_pkthdr.flowid = (rq->queue_index - 1);
1679338938Sjpaetzel		else
1680338938Sjpaetzel			m->m_pkthdr.flowid = rq->queue_index;
1681338938Sjpaetzel		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1682338938Sjpaetzel#endif
1683338938Sjpaetzel		/* This deternies if vlan tag is Valid */
1684338938Sjpaetzel		if (cq_info.vtp) {
1685338938Sjpaetzel			if (sc->function_mode & FNM_FLEX10_MODE) {
1686338938Sjpaetzel				/* FLEX10. If QnQ is not set, neglect VLAN */
1687338938Sjpaetzel				if (cq_info.qnq) {
1688338938Sjpaetzel					m->m_pkthdr.ether_vtag = cq_info.vtag;
1689338938Sjpaetzel					m->m_flags |= M_VLANTAG;
1690338938Sjpaetzel				}
1691338938Sjpaetzel			} else if (sc->pvid != (cq_info.vtag & VLAN_VID_MASK))  {
1692338938Sjpaetzel				/* In UMC mode generally pvid will be striped by
1693338938Sjpaetzel				   hw. But in some cases we have seen it comes
1694338938Sjpaetzel				   with pvid. So if pvid == vlan, neglect vlan.
1695338938Sjpaetzel				 */
1696338938Sjpaetzel				m->m_pkthdr.ether_vtag = cq_info.vtag;
1697338938Sjpaetzel				m->m_flags |= M_VLANTAG;
1698338938Sjpaetzel			}
1699338938Sjpaetzel		}
1700338938Sjpaetzel		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1701338938Sjpaetzel
1702338938Sjpaetzel		(*sc->ifp->if_input) (sc->ifp, m);
1703338938Sjpaetzel
1704338938Sjpaetzel		/* Update rx stats per queue */
1705338938Sjpaetzel		rq->rx_stats.rx_pkts++;
1706338938Sjpaetzel		rq->rx_stats.rx_bytes += cq_info.pkt_size;
1707338938Sjpaetzel		rq->rx_stats.rx_frags += cq_info.num_frags;
1708338938Sjpaetzel		rq->rx_stats.rx_ucast_pkts++;
1709338938Sjpaetzel	}
1710338938Sjpaetzel        return;
1711338938Sjpaetzel}
1712338938Sjpaetzel
1713338938Sjpaetzelstatic void
1714338938Sjpaetzeloce_rx(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
1715338938Sjpaetzel{
1716338938Sjpaetzel	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1717338938Sjpaetzel	int len;
1718338938Sjpaetzel	struct mbuf *m = NULL;
1719338938Sjpaetzel	struct oce_common_cqe_info cq_info;
1720338938Sjpaetzel	uint16_t vtag = 0;
1721338938Sjpaetzel
1722338938Sjpaetzel	/* Is it a flush compl that has no data */
1723338938Sjpaetzel	if(!cqe->u0.s.num_fragments)
1724338938Sjpaetzel		goto exit;
1725338938Sjpaetzel
1726231437Sluigi	len = cqe->u0.s.pkt_size;
1727231437Sluigi	if (!len) {
1728231437Sluigi		/*partial DMA workaround for Lancer*/
1729338938Sjpaetzel		oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
1730231437Sluigi		goto exit;
1731231437Sluigi	}
1732231437Sluigi
1733338938Sjpaetzel	if (!oce_cqe_portid_valid(sc, cqe)) {
1734338938Sjpaetzel		oce_discard_rx_comp(rq, cqe->u0.s.num_fragments);
1735338938Sjpaetzel		goto exit;
1736338938Sjpaetzel	}
1737338938Sjpaetzel
1738231879Sluigi	 /* Get vlan_tag value */
1739252869Sdelphij	if(IS_BE(sc) || IS_SH(sc))
1740231879Sluigi		vtag = BSWAP_16(cqe->u0.s.vlan_tag);
1741231879Sluigi	else
1742231879Sluigi		vtag = cqe->u0.s.vlan_tag;
1743338938Sjpaetzel
1744338938Sjpaetzel	cq_info.l4_cksum_pass = cqe->u0.s.l4_cksum_pass;
1745338938Sjpaetzel	cq_info.ip_cksum_pass = cqe->u0.s.ip_cksum_pass;
1746338938Sjpaetzel	cq_info.ipv6_frame = cqe->u0.s.ip_ver;
1747338938Sjpaetzel	cq_info.num_frags = cqe->u0.s.num_fragments;
1748338938Sjpaetzel	cq_info.pkt_size = cqe->u0.s.pkt_size;
1749231879Sluigi
1750338938Sjpaetzel	oce_rx_mbuf_chain(rq, &cq_info, &m);
1751231879Sluigi
1752231437Sluigi	if (m) {
1753231437Sluigi		m->m_pkthdr.rcvif = sc->ifp;
1754231437Sluigi#if __FreeBSD_version >= 800000
1755252869Sdelphij		if (rq->queue_index)
1756252869Sdelphij			m->m_pkthdr.flowid = (rq->queue_index - 1);
1757252869Sdelphij		else
1758252869Sdelphij			m->m_pkthdr.flowid = rq->queue_index;
1759275358Shselasky		M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE);
1760231437Sluigi#endif
1761231879Sluigi		/* This deternies if vlan tag is Valid */
1762231437Sluigi		if (oce_cqe_vtp_valid(sc, cqe)) {
1763231437Sluigi			if (sc->function_mode & FNM_FLEX10_MODE) {
1764231879Sluigi				/* FLEX10. If QnQ is not set, neglect VLAN */
1765231437Sluigi				if (cqe->u0.s.qnq) {
1766231879Sluigi					m->m_pkthdr.ether_vtag = vtag;
1767231437Sluigi					m->m_flags |= M_VLANTAG;
1768231437Sluigi				}
1769231879Sluigi			} else if (sc->pvid != (vtag & VLAN_VID_MASK))  {
1770231879Sluigi				/* In UMC mode generally pvid will be striped by
1771231879Sluigi				   hw. But in some cases we have seen it comes
1772231879Sluigi				   with pvid. So if pvid == vlan, neglect vlan.
1773231879Sluigi				*/
1774231879Sluigi				m->m_pkthdr.ether_vtag = vtag;
1775231437Sluigi				m->m_flags |= M_VLANTAG;
1776231437Sluigi			}
1777231437Sluigi		}
1778231437Sluigi
1779271849Sglebius		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
1780231511Sbz#if defined(INET6) || defined(INET)
1781231437Sluigi		/* Try to queue to LRO */
1782231437Sluigi		if (IF_LRO_ENABLED(sc) &&
1783231437Sluigi		    (cqe->u0.s.ip_cksum_pass) &&
1784231437Sluigi		    (cqe->u0.s.l4_cksum_pass) &&
1785231437Sluigi		    (!cqe->u0.s.ip_ver)       &&
1786231437Sluigi		    (rq->lro.lro_cnt != 0)) {
1787231437Sluigi
1788231437Sluigi			if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
1789231437Sluigi				rq->lro_pkts_queued ++;
1790231437Sluigi				goto post_done;
1791231437Sluigi			}
1792231437Sluigi			/* If LRO posting fails then try to post to STACK */
1793231437Sluigi		}
1794231511Sbz#endif
1795231437Sluigi
1796231437Sluigi		(*sc->ifp->if_input) (sc->ifp, m);
1797231511Sbz#if defined(INET6) || defined(INET)
1798231437Sluigipost_done:
1799231511Sbz#endif
1800231437Sluigi		/* Update rx stats per queue */
1801231437Sluigi		rq->rx_stats.rx_pkts++;
1802231437Sluigi		rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
1803231437Sluigi		rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
1804231437Sluigi		if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
1805231437Sluigi			rq->rx_stats.rx_mcast_pkts++;
1806231437Sluigi		if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
1807231437Sluigi			rq->rx_stats.rx_ucast_pkts++;
1808231437Sluigi	}
1809231437Sluigiexit:
1810231437Sluigi	return;
1811231437Sluigi}
1812231437Sluigi
1813231437Sluigi
1814338938Sjpaetzelvoid
1815338938Sjpaetzeloce_discard_rx_comp(struct oce_rq *rq, int num_frags)
1816231437Sluigi{
1817338938Sjpaetzel	uint32_t i = 0;
1818231437Sluigi	struct oce_packet_desc *pd;
1819231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1820231437Sluigi
1821231437Sluigi	for (i = 0; i < num_frags; i++) {
1822338938Sjpaetzel                if (rq->ring->cidx == rq->ring->pidx) {
1823338938Sjpaetzel                        device_printf(sc->dev,
1824338938Sjpaetzel                                "oce_discard_rx_comp: Invalid RX completion - Queue is empty\n");
1825338938Sjpaetzel                        return;
1826338938Sjpaetzel                }
1827338938Sjpaetzel                pd = &rq->pckts[rq->ring->cidx];
1828338938Sjpaetzel                bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1829338938Sjpaetzel                bus_dmamap_unload(rq->tag, pd->map);
1830338938Sjpaetzel                if (pd->mbuf != NULL) {
1831338938Sjpaetzel                        m_freem(pd->mbuf);
1832338938Sjpaetzel                        pd->mbuf = NULL;
1833338938Sjpaetzel                }
1834231437Sluigi
1835338938Sjpaetzel		RING_GET(rq->ring, 1);
1836338938Sjpaetzel                rq->pending--;
1837231437Sluigi	}
1838231437Sluigi}
1839231437Sluigi
1840231437Sluigi
1841231437Sluigistatic int
1842231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
1843231437Sluigi{
1844231437Sluigi	struct oce_nic_rx_cqe_v1 *cqe_v1;
1845231437Sluigi	int vtp = 0;
1846231437Sluigi
1847231437Sluigi	if (sc->be3_native) {
1848231437Sluigi		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1849231437Sluigi		vtp =  cqe_v1->u0.s.vlan_tag_present;
1850231879Sluigi	} else
1851231437Sluigi		vtp = cqe->u0.s.vlan_tag_present;
1852231437Sluigi
1853231437Sluigi	return vtp;
1854231437Sluigi
1855231437Sluigi}
1856231437Sluigi
1857231437Sluigi
1858231437Sluigistatic int
1859231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
1860231437Sluigi{
1861231437Sluigi	struct oce_nic_rx_cqe_v1 *cqe_v1;
1862231437Sluigi	int port_id = 0;
1863231437Sluigi
1864252869Sdelphij	if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) {
1865231437Sluigi		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1866231437Sluigi		port_id =  cqe_v1->u0.s.port;
1867231437Sluigi		if (sc->port_id != port_id)
1868231437Sluigi			return 0;
1869231437Sluigi	} else
1870231437Sluigi		;/* For BE3 legacy and Lancer this is dummy */
1871231437Sluigi
1872231437Sluigi	return 1;
1873231437Sluigi
1874231437Sluigi}
1875231437Sluigi
1876231511Sbz#if defined(INET6) || defined(INET)
1877338938Sjpaetzelvoid
1878231437Sluigioce_rx_flush_lro(struct oce_rq *rq)
1879231437Sluigi{
1880231437Sluigi	struct lro_ctrl	*lro = &rq->lro;
1881231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1882231437Sluigi
1883231437Sluigi	if (!IF_LRO_ENABLED(sc))
1884231437Sluigi		return;
1885231437Sluigi
1886297482Ssephe	tcp_lro_flush_all(lro);
1887231437Sluigi	rq->lro_pkts_queued = 0;
1888231437Sluigi
1889231437Sluigi	return;
1890231437Sluigi}
1891231437Sluigi
1892231437Sluigi
1893231437Sluigistatic int
1894231437Sluigioce_init_lro(POCE_SOFTC sc)
1895231437Sluigi{
1896231437Sluigi	struct lro_ctrl *lro = NULL;
1897231437Sluigi	int i = 0, rc = 0;
1898231437Sluigi
1899231437Sluigi	for (i = 0; i < sc->nrqs; i++) {
1900231437Sluigi		lro = &sc->rq[i]->lro;
1901231437Sluigi		rc = tcp_lro_init(lro);
1902231437Sluigi		if (rc != 0) {
1903231437Sluigi			device_printf(sc->dev, "LRO init failed\n");
1904231437Sluigi			return rc;
1905231437Sluigi		}
1906231437Sluigi		lro->ifp = sc->ifp;
1907231437Sluigi	}
1908231437Sluigi
1909231437Sluigi	return rc;
1910231437Sluigi}
1911231437Sluigi
1912231879Sluigi
1913231437Sluigivoid
1914231437Sluigioce_free_lro(POCE_SOFTC sc)
1915231437Sluigi{
1916231437Sluigi	struct lro_ctrl *lro = NULL;
1917231437Sluigi	int i = 0;
1918231437Sluigi
1919231437Sluigi	for (i = 0; i < sc->nrqs; i++) {
1920231437Sluigi		lro = &sc->rq[i]->lro;
1921231437Sluigi		if (lro)
1922231437Sluigi			tcp_lro_free(lro);
1923231437Sluigi	}
1924231437Sluigi}
1925247880Sdelphij#endif
1926231437Sluigi
1927231437Sluigiint
1928231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count)
1929231437Sluigi{
1930231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1931231437Sluigi	int i, in, rc;
1932231437Sluigi	struct oce_packet_desc *pd;
1933231437Sluigi	bus_dma_segment_t segs[6];
1934231437Sluigi	int nsegs, added = 0;
1935231437Sluigi	struct oce_nic_rqe *rqe;
1936231437Sluigi	pd_rxulp_db_t rxdb_reg;
1937338938Sjpaetzel	uint32_t val = 0;
1938338938Sjpaetzel	uint32_t oce_max_rq_posts = 64;
1939231437Sluigi
1940247880Sdelphij	bzero(&rxdb_reg, sizeof(pd_rxulp_db_t));
1941231437Sluigi	for (i = 0; i < count; i++) {
1942338938Sjpaetzel		in = (rq->ring->pidx + 1) % OCE_RQ_PACKET_ARRAY_SIZE;
1943231437Sluigi
1944338938Sjpaetzel		pd = &rq->pckts[rq->ring->pidx];
1945338938Sjpaetzel		pd->mbuf = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, oce_rq_buf_size);
1946338938Sjpaetzel		if (pd->mbuf == NULL) {
1947338938Sjpaetzel			device_printf(sc->dev, "mbuf allocation failed, size = %d\n",oce_rq_buf_size);
1948231437Sluigi			break;
1949338938Sjpaetzel		}
1950338938Sjpaetzel		pd->mbuf->m_nextpkt = NULL;
1951231437Sluigi
1952338938Sjpaetzel		pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = rq->cfg.frag_size;
1953338938Sjpaetzel
1954231437Sluigi		rc = bus_dmamap_load_mbuf_sg(rq->tag,
1955231437Sluigi					     pd->map,
1956231437Sluigi					     pd->mbuf,
1957231437Sluigi					     segs, &nsegs, BUS_DMA_NOWAIT);
1958231437Sluigi		if (rc) {
1959231437Sluigi			m_free(pd->mbuf);
1960338938Sjpaetzel			device_printf(sc->dev, "bus_dmamap_load_mbuf_sg failed rc = %d\n", rc);
1961231437Sluigi			break;
1962231437Sluigi		}
1963231437Sluigi
1964231437Sluigi		if (nsegs != 1) {
1965231437Sluigi			i--;
1966231437Sluigi			continue;
1967231437Sluigi		}
1968231437Sluigi
1969231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
1970231437Sluigi
1971231437Sluigi		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
1972231437Sluigi		rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
1973231437Sluigi		rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
1974231437Sluigi		DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
1975231437Sluigi		RING_PUT(rq->ring, 1);
1976231437Sluigi		added++;
1977231437Sluigi		rq->pending++;
1978231437Sluigi	}
1979338938Sjpaetzel	oce_max_rq_posts = sc->enable_hwlro ? OCE_HWLRO_MAX_RQ_POSTS : OCE_MAX_RQ_POSTS;
1980231437Sluigi	if (added != 0) {
1981338938Sjpaetzel		for (i = added / oce_max_rq_posts; i > 0; i--) {
1982338938Sjpaetzel			rxdb_reg.bits.num_posted = oce_max_rq_posts;
1983231437Sluigi			rxdb_reg.bits.qid = rq->rq_id;
1984338938Sjpaetzel			if(rq->islro) {
1985338938Sjpaetzel                                val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1986338938Sjpaetzel                                val |= oce_max_rq_posts << 16;
1987338938Sjpaetzel                                OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
1988338938Sjpaetzel			}else {
1989338938Sjpaetzel				OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1990338938Sjpaetzel			}
1991338938Sjpaetzel			added -= oce_max_rq_posts;
1992231437Sluigi		}
1993231437Sluigi		if (added > 0) {
1994231437Sluigi			rxdb_reg.bits.qid = rq->rq_id;
1995231437Sluigi			rxdb_reg.bits.num_posted = added;
1996338938Sjpaetzel			if(rq->islro) {
1997338938Sjpaetzel                                val |= rq->rq_id & DB_LRO_RQ_ID_MASK;
1998338938Sjpaetzel                                val |= added << 16;
1999338938Sjpaetzel                                OCE_WRITE_REG32(sc, db, DB_OFFSET, val);
2000338938Sjpaetzel			}else {
2001338938Sjpaetzel				OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
2002338938Sjpaetzel			}
2003231437Sluigi		}
2004231437Sluigi	}
2005231437Sluigi
2006231437Sluigi	return 0;
2007231437Sluigi}
2008231437Sluigi
2009338938Sjpaetzelstatic void
2010338938Sjpaetzeloce_check_rx_bufs(POCE_SOFTC sc, uint32_t num_cqes, struct oce_rq *rq)
2011338938Sjpaetzel{
2012338938Sjpaetzel        if (num_cqes) {
2013338938Sjpaetzel                oce_arm_cq(sc, rq->cq->cq_id, num_cqes, FALSE);
2014338938Sjpaetzel		if(!sc->enable_hwlro) {
2015338938Sjpaetzel			if((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) > 1)
2016338938Sjpaetzel				oce_alloc_rx_bufs(rq, ((OCE_RQ_PACKET_ARRAY_SIZE - rq->pending) - 1));
2017338938Sjpaetzel		}else {
2018338938Sjpaetzel                	if ((OCE_RQ_PACKET_ARRAY_SIZE -1 - rq->pending) > 64)
2019338938Sjpaetzel                        	oce_alloc_rx_bufs(rq, 64);
2020338938Sjpaetzel        	}
2021338938Sjpaetzel	}
2022231437Sluigi
2023338938Sjpaetzel        return;
2024338938Sjpaetzel}
2025338938Sjpaetzel
2026338938Sjpaetzeluint16_t
2027338938Sjpaetzeloce_rq_handler_lro(void *arg)
2028338938Sjpaetzel{
2029338938Sjpaetzel        struct oce_rq *rq = (struct oce_rq *)arg;
2030338938Sjpaetzel        struct oce_cq *cq = rq->cq;
2031338938Sjpaetzel        POCE_SOFTC sc = rq->parent;
2032338938Sjpaetzel        struct nic_hwlro_singleton_cqe *cqe;
2033338938Sjpaetzel        struct nic_hwlro_cqe_part2 *cqe2;
2034338938Sjpaetzel        int num_cqes = 0;
2035338938Sjpaetzel
2036338938Sjpaetzel	LOCK(&rq->rx_lock);
2037338938Sjpaetzel        bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2038338938Sjpaetzel        cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
2039338938Sjpaetzel        while (cqe->valid) {
2040338938Sjpaetzel                if(cqe->cqe_type == 0) { /* singleton cqe */
2041338938Sjpaetzel			/* we should not get singleton cqe after cqe1 on same rq */
2042338938Sjpaetzel			if(rq->cqe_firstpart != NULL) {
2043338938Sjpaetzel				device_printf(sc->dev, "Got singleton cqe after cqe1 \n");
2044338938Sjpaetzel				goto exit_rq_handler_lro;
2045338938Sjpaetzel			}
2046338938Sjpaetzel                        if(cqe->error != 0) {
2047338938Sjpaetzel                                rq->rx_stats.rxcp_err++;
2048338938Sjpaetzel				if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
2049338938Sjpaetzel                        }
2050338938Sjpaetzel                        oce_rx_lro(rq, cqe, NULL);
2051338938Sjpaetzel                        rq->rx_stats.rx_compl++;
2052338938Sjpaetzel                        cqe->valid = 0;
2053338938Sjpaetzel                        RING_GET(cq->ring, 1);
2054338938Sjpaetzel                        num_cqes++;
2055338938Sjpaetzel                        if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
2056338938Sjpaetzel                                break;
2057338938Sjpaetzel                }else if(cqe->cqe_type == 0x1) { /* first part */
2058338938Sjpaetzel			/* we should not get cqe1 after cqe1 on same rq */
2059338938Sjpaetzel			if(rq->cqe_firstpart != NULL) {
2060338938Sjpaetzel				device_printf(sc->dev, "Got cqe1 after cqe1 \n");
2061338938Sjpaetzel				goto exit_rq_handler_lro;
2062338938Sjpaetzel			}
2063338938Sjpaetzel			rq->cqe_firstpart = (struct nic_hwlro_cqe_part1 *)cqe;
2064338938Sjpaetzel                        RING_GET(cq->ring, 1);
2065338938Sjpaetzel                }else if(cqe->cqe_type == 0x2) { /* second part */
2066338938Sjpaetzel			cqe2 = (struct nic_hwlro_cqe_part2 *)cqe;
2067338938Sjpaetzel                        if(cqe2->error != 0) {
2068338938Sjpaetzel                                rq->rx_stats.rxcp_err++;
2069338938Sjpaetzel				if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
2070338938Sjpaetzel                        }
2071338938Sjpaetzel			/* We should not get cqe2 without cqe1 */
2072338938Sjpaetzel			if(rq->cqe_firstpart == NULL) {
2073338938Sjpaetzel				device_printf(sc->dev, "Got cqe2 without cqe1 \n");
2074338938Sjpaetzel				goto exit_rq_handler_lro;
2075338938Sjpaetzel			}
2076338938Sjpaetzel                        oce_rx_lro(rq, (struct nic_hwlro_singleton_cqe *)rq->cqe_firstpart, cqe2);
2077338938Sjpaetzel
2078338938Sjpaetzel                        rq->rx_stats.rx_compl++;
2079338938Sjpaetzel                        rq->cqe_firstpart->valid = 0;
2080338938Sjpaetzel                        cqe2->valid = 0;
2081338938Sjpaetzel			rq->cqe_firstpart = NULL;
2082338938Sjpaetzel
2083338938Sjpaetzel                        RING_GET(cq->ring, 1);
2084338938Sjpaetzel                        num_cqes += 2;
2085338938Sjpaetzel                        if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
2086338938Sjpaetzel                                break;
2087338938Sjpaetzel		}
2088338938Sjpaetzel
2089338938Sjpaetzel                bus_dmamap_sync(cq->ring->dma.tag,cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2090338938Sjpaetzel                cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct nic_hwlro_singleton_cqe);
2091338938Sjpaetzel        }
2092338938Sjpaetzel	oce_check_rx_bufs(sc, num_cqes, rq);
2093338938Sjpaetzelexit_rq_handler_lro:
2094338938Sjpaetzel	UNLOCK(&rq->rx_lock);
2095338938Sjpaetzel	return 0;
2096338938Sjpaetzel}
2097338938Sjpaetzel
2098231437Sluigi/* Handle the Completion Queue for receive */
2099231437Sluigiuint16_t
2100231437Sluigioce_rq_handler(void *arg)
2101231437Sluigi{
2102231437Sluigi	struct oce_rq *rq = (struct oce_rq *)arg;
2103231437Sluigi	struct oce_cq *cq = rq->cq;
2104231437Sluigi	POCE_SOFTC sc = rq->parent;
2105231437Sluigi	struct oce_nic_rx_cqe *cqe;
2106338938Sjpaetzel	int num_cqes = 0;
2107231437Sluigi
2108338938Sjpaetzel	if(rq->islro) {
2109338938Sjpaetzel		oce_rq_handler_lro(arg);
2110338938Sjpaetzel		return 0;
2111338938Sjpaetzel	}
2112338938Sjpaetzel	LOCK(&rq->rx_lock);
2113231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
2114231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2115231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
2116231437Sluigi	while (cqe->u0.dw[2]) {
2117231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
2118231437Sluigi
2119231437Sluigi		if (cqe->u0.s.error == 0) {
2120338938Sjpaetzel			oce_rx(rq, cqe);
2121231437Sluigi		} else {
2122231437Sluigi			rq->rx_stats.rxcp_err++;
2123271849Sglebius			if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
2124247880Sdelphij			/* Post L3/L4 errors to stack.*/
2125338938Sjpaetzel			oce_rx(rq, cqe);
2126231437Sluigi		}
2127231437Sluigi		rq->rx_stats.rx_compl++;
2128231437Sluigi		cqe->u0.dw[2] = 0;
2129231437Sluigi
2130231511Sbz#if defined(INET6) || defined(INET)
2131231437Sluigi		if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
2132231437Sluigi			oce_rx_flush_lro(rq);
2133231437Sluigi		}
2134231511Sbz#endif
2135231437Sluigi
2136231437Sluigi		RING_GET(cq->ring, 1);
2137231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
2138231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2139231437Sluigi		cqe =
2140231437Sluigi		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
2141231437Sluigi		num_cqes++;
2142231437Sluigi		if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
2143231437Sluigi			break;
2144231437Sluigi	}
2145231879Sluigi
2146231511Sbz#if defined(INET6) || defined(INET)
2147338938Sjpaetzel        if (IF_LRO_ENABLED(sc))
2148338938Sjpaetzel                oce_rx_flush_lro(rq);
2149231511Sbz#endif
2150231437Sluigi
2151338938Sjpaetzel	oce_check_rx_bufs(sc, num_cqes, rq);
2152338938Sjpaetzel	UNLOCK(&rq->rx_lock);
2153231437Sluigi	return 0;
2154231437Sluigi
2155231437Sluigi}
2156231437Sluigi
2157231437Sluigi
2158231437Sluigi
2159231437Sluigi
2160231437Sluigi/*****************************************************************************
2161231437Sluigi *		   Helper function prototypes in this file 		     *
2162231437Sluigi *****************************************************************************/
2163231437Sluigi
2164231437Sluigistatic int
2165231437Sluigioce_attach_ifp(POCE_SOFTC sc)
2166231437Sluigi{
2167231437Sluigi
2168231437Sluigi	sc->ifp = if_alloc(IFT_ETHER);
2169231437Sluigi	if (!sc->ifp)
2170231437Sluigi		return ENOMEM;
2171231437Sluigi
2172231437Sluigi	ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
2173231437Sluigi	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
2174231437Sluigi	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
2175231437Sluigi
2176231437Sluigi	sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
2177231437Sluigi	sc->ifp->if_ioctl = oce_ioctl;
2178231437Sluigi	sc->ifp->if_start = oce_start;
2179231437Sluigi	sc->ifp->if_init = oce_init;
2180231437Sluigi	sc->ifp->if_mtu = ETHERMTU;
2181231437Sluigi	sc->ifp->if_softc = sc;
2182231437Sluigi#if __FreeBSD_version >= 800000
2183231437Sluigi	sc->ifp->if_transmit = oce_multiq_start;
2184231437Sluigi	sc->ifp->if_qflush = oce_multiq_flush;
2185231437Sluigi#endif
2186231437Sluigi
2187231437Sluigi	if_initname(sc->ifp,
2188231437Sluigi		    device_get_name(sc->dev), device_get_unit(sc->dev));
2189231437Sluigi
2190231437Sluigi	sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1;
2191231437Sluigi	IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen);
2192231437Sluigi	IFQ_SET_READY(&sc->ifp->if_snd);
2193231437Sluigi
2194231437Sluigi	sc->ifp->if_hwassist = OCE_IF_HWASSIST;
2195231437Sluigi	sc->ifp->if_hwassist |= CSUM_TSO;
2196231437Sluigi	sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP);
2197231437Sluigi
2198231437Sluigi	sc->ifp->if_capabilities = OCE_IF_CAPABILITIES;
2199231437Sluigi	sc->ifp->if_capabilities |= IFCAP_HWCSUM;
2200231437Sluigi	sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
2201231879Sluigi
2202231511Sbz#if defined(INET6) || defined(INET)
2203231511Sbz	sc->ifp->if_capabilities |= IFCAP_TSO;
2204231437Sluigi	sc->ifp->if_capabilities |= IFCAP_LRO;
2205231879Sluigi	sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
2206231511Sbz#endif
2207231437Sluigi
2208231437Sluigi	sc->ifp->if_capenable = sc->ifp->if_capabilities;
2209263102Sglebius	sc->ifp->if_baudrate = IF_Gbps(10);
2210231437Sluigi
2211257007Sdelphij#if __FreeBSD_version >= 1000000
2212271946Shselasky	sc->ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
2213271946Shselasky	sc->ifp->if_hw_tsomaxsegcount = OCE_MAX_TX_ELEMENTS;
2214271946Shselasky	sc->ifp->if_hw_tsomaxsegsize = 4096;
2215257007Sdelphij#endif
2216257007Sdelphij
2217231437Sluigi	ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
2218231437Sluigi
2219231437Sluigi	return 0;
2220231437Sluigi}
2221231437Sluigi
2222231437Sluigi
2223231437Sluigistatic void
2224231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
2225231437Sluigi{
2226231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
2227231437Sluigi
2228231437Sluigi	if (ifp->if_softc !=  arg)
2229231437Sluigi		return;
2230231437Sluigi	if ((vtag == 0) || (vtag > 4095))
2231231437Sluigi		return;
2232231437Sluigi
2233231437Sluigi	sc->vlan_tag[vtag] = 1;
2234231437Sluigi	sc->vlans_added++;
2235257007Sdelphij	if (sc->vlans_added <= (sc->max_vlans + 1))
2236257007Sdelphij		oce_vid_config(sc);
2237231437Sluigi}
2238231437Sluigi
2239231437Sluigi
2240231437Sluigistatic void
2241231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
2242231437Sluigi{
2243231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
2244231437Sluigi
2245231437Sluigi	if (ifp->if_softc !=  arg)
2246231437Sluigi		return;
2247231437Sluigi	if ((vtag == 0) || (vtag > 4095))
2248231437Sluigi		return;
2249231437Sluigi
2250231437Sluigi	sc->vlan_tag[vtag] = 0;
2251231437Sluigi	sc->vlans_added--;
2252231437Sluigi	oce_vid_config(sc);
2253231437Sluigi}
2254231437Sluigi
2255231437Sluigi
2256231437Sluigi/*
2257231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures
2258231437Sluigi * more, place the card in vlan promiscuous mode.
2259231437Sluigi */
2260231437Sluigistatic int
2261231437Sluigioce_vid_config(POCE_SOFTC sc)
2262231437Sluigi{
2263231437Sluigi	struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
2264231437Sluigi	uint16_t ntags = 0, i;
2265231437Sluigi	int status = 0;
2266231437Sluigi
2267231437Sluigi	if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
2268231437Sluigi			(sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) {
2269231437Sluigi		for (i = 0; i < MAX_VLANS; i++) {
2270231437Sluigi			if (sc->vlan_tag[i]) {
2271231437Sluigi				vtags[ntags].vtag = i;
2272231437Sluigi				ntags++;
2273231437Sluigi			}
2274231437Sluigi		}
2275231437Sluigi		if (ntags)
2276231437Sluigi			status = oce_config_vlan(sc, (uint8_t) sc->if_id,
2277231437Sluigi						vtags, ntags, 1, 0);
2278231437Sluigi	} else
2279231437Sluigi		status = oce_config_vlan(sc, (uint8_t) sc->if_id,
2280231437Sluigi					 	NULL, 0, 1, 1);
2281231437Sluigi	return status;
2282231437Sluigi}
2283231437Sluigi
2284231437Sluigi
2285231437Sluigistatic void
2286231437Sluigioce_mac_addr_set(POCE_SOFTC sc)
2287231437Sluigi{
2288231437Sluigi	uint32_t old_pmac_id = sc->pmac_id;
2289231437Sluigi	int status = 0;
2290231437Sluigi
2291231437Sluigi
2292231437Sluigi	status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
2293231437Sluigi			 sc->macaddr.size_of_struct);
2294231437Sluigi	if (!status)
2295231437Sluigi		return;
2296231437Sluigi
2297231437Sluigi	status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)),
2298231437Sluigi					sc->if_id, &sc->pmac_id);
2299231437Sluigi	if (!status) {
2300231437Sluigi		status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
2301231437Sluigi		bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
2302231437Sluigi				 sc->macaddr.size_of_struct);
2303231437Sluigi	}
2304231437Sluigi	if (status)
2305231437Sluigi		device_printf(sc->dev, "Failed update macaddress\n");
2306231437Sluigi
2307231437Sluigi}
2308231437Sluigi
2309231437Sluigi
2310231437Sluigistatic int
2311231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data)
2312231437Sluigi{
2313231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
2314231437Sluigi	struct ifreq *ifr = (struct ifreq *)data;
2315231437Sluigi	int rc = ENXIO;
2316231437Sluigi	char cookie[32] = {0};
2317332288Sbrooks	void *priv_data = ifr_data_get_ptr(ifr);
2318231437Sluigi	void *ioctl_ptr;
2319231437Sluigi	uint32_t req_size;
2320231437Sluigi	struct mbx_hdr req;
2321231437Sluigi	OCE_DMA_MEM dma_mem;
2322247880Sdelphij	struct mbx_common_get_cntl_attr *fw_cmd;
2323231437Sluigi
2324231437Sluigi	if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
2325231437Sluigi		return EFAULT;
2326247880Sdelphij
2327231437Sluigi	if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
2328231437Sluigi		return EINVAL;
2329247880Sdelphij
2330231437Sluigi	ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
2331231437Sluigi	if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
2332231437Sluigi		return EFAULT;
2333247880Sdelphij
2334231437Sluigi	req_size = le32toh(req.u0.req.request_length);
2335231437Sluigi	if (req_size > 65536)
2336231437Sluigi		return EINVAL;
2337231437Sluigi
2338231437Sluigi	req_size += sizeof(struct mbx_hdr);
2339231437Sluigi	rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
2340231437Sluigi	if (rc)
2341231437Sluigi		return ENOMEM;
2342231437Sluigi
2343231437Sluigi	if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
2344231437Sluigi		rc = EFAULT;
2345231437Sluigi		goto dma_free;
2346231437Sluigi	}
2347231437Sluigi
2348231437Sluigi	rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
2349231437Sluigi	if (rc) {
2350231437Sluigi		rc = EIO;
2351231437Sluigi		goto dma_free;
2352231437Sluigi	}
2353231437Sluigi
2354231437Sluigi	if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size))
2355231437Sluigi		rc =  EFAULT;
2356231437Sluigi
2357247880Sdelphij	/*
2358247880Sdelphij	   firmware is filling all the attributes for this ioctl except
2359247880Sdelphij	   the driver version..so fill it
2360247880Sdelphij	 */
2361247880Sdelphij	if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) {
2362247880Sdelphij		fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr;
2363247880Sdelphij		strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str,
2364247880Sdelphij			COMPONENT_REVISION, strlen(COMPONENT_REVISION));
2365247880Sdelphij	}
2366247880Sdelphij
2367231437Sluigidma_free:
2368231437Sluigi	oce_dma_free(sc, &dma_mem);
2369231437Sluigi	return rc;
2370231437Sluigi
2371231437Sluigi}
2372231437Sluigi
2373247880Sdelphijstatic void
2374247880Sdelphijoce_eqd_set_periodic(POCE_SOFTC sc)
2375247880Sdelphij{
2376247880Sdelphij	struct oce_set_eqd set_eqd[OCE_MAX_EQ];
2377247880Sdelphij	struct oce_aic_obj *aic;
2378247880Sdelphij	struct oce_eq *eqo;
2379247880Sdelphij	uint64_t now = 0, delta;
2380247880Sdelphij	int eqd, i, num = 0;
2381338938Sjpaetzel	uint32_t tx_reqs = 0, rxpkts = 0, pps;
2382338938Sjpaetzel	struct oce_wq *wq;
2383338938Sjpaetzel	struct oce_rq *rq;
2384231437Sluigi
2385338938Sjpaetzel	#define ticks_to_msecs(t)       (1000 * (t) / hz)
2386338938Sjpaetzel
2387247880Sdelphij	for (i = 0 ; i < sc->neqs; i++) {
2388247880Sdelphij		eqo = sc->eq[i];
2389247880Sdelphij		aic = &sc->aic_obj[i];
2390247880Sdelphij		/* When setting the static eq delay from the user space */
2391247880Sdelphij		if (!aic->enable) {
2392338938Sjpaetzel			if (aic->ticks)
2393338938Sjpaetzel				aic->ticks = 0;
2394247880Sdelphij			eqd = aic->et_eqd;
2395247880Sdelphij			goto modify_eqd;
2396247880Sdelphij		}
2397247880Sdelphij
2398369531Sfreqlabs		if (i == 0) {
2399369531Sfreqlabs			rq = sc->rq[0];
2400369531Sfreqlabs			rxpkts = rq->rx_stats.rx_pkts;
2401369531Sfreqlabs		} else
2402369531Sfreqlabs			rxpkts = 0;
2403369531Sfreqlabs		if (i + 1 < sc->nrqs) {
2404369531Sfreqlabs			rq = sc->rq[i + 1];
2405369531Sfreqlabs			rxpkts += rq->rx_stats.rx_pkts;
2406369531Sfreqlabs		}
2407369531Sfreqlabs		if (i < sc->nwqs) {
2408369531Sfreqlabs			wq = sc->wq[i];
2409369531Sfreqlabs			tx_reqs = wq->tx_stats.tx_reqs;
2410369531Sfreqlabs		} else
2411369531Sfreqlabs			tx_reqs = 0;
2412247880Sdelphij		now = ticks;
2413247880Sdelphij
2414338938Sjpaetzel		if (!aic->ticks || now < aic->ticks ||
2415338938Sjpaetzel		    rxpkts < aic->prev_rxpkts || tx_reqs < aic->prev_txreqs) {
2416338938Sjpaetzel			aic->prev_rxpkts = rxpkts;
2417338938Sjpaetzel			aic->prev_txreqs = tx_reqs;
2418338938Sjpaetzel			aic->ticks = now;
2419338938Sjpaetzel			continue;
2420338938Sjpaetzel		}
2421247880Sdelphij
2422338938Sjpaetzel		delta = ticks_to_msecs(now - aic->ticks);
2423247880Sdelphij
2424338938Sjpaetzel		pps = (((uint32_t)(rxpkts - aic->prev_rxpkts) * 1000) / delta) +
2425338938Sjpaetzel		      (((uint32_t)(tx_reqs - aic->prev_txreqs) * 1000) / delta);
2426338938Sjpaetzel		eqd = (pps / 15000) << 2;
2427338938Sjpaetzel		if (eqd < 8)
2428247880Sdelphij			eqd = 0;
2429247880Sdelphij
2430247880Sdelphij		/* Make sure that the eq delay is in the known range */
2431247880Sdelphij		eqd = min(eqd, aic->max_eqd);
2432247880Sdelphij		eqd = max(eqd, aic->min_eqd);
2433247880Sdelphij
2434338938Sjpaetzel		aic->prev_rxpkts = rxpkts;
2435338938Sjpaetzel		aic->prev_txreqs = tx_reqs;
2436338938Sjpaetzel		aic->ticks = now;
2437338938Sjpaetzel
2438247880Sdelphijmodify_eqd:
2439247880Sdelphij		if (eqd != aic->cur_eqd) {
2440247880Sdelphij			set_eqd[num].delay_multiplier = (eqd * 65)/100;
2441247880Sdelphij			set_eqd[num].eq_id = eqo->eq_id;
2442247880Sdelphij			aic->cur_eqd = eqd;
2443247880Sdelphij			num++;
2444247880Sdelphij		}
2445247880Sdelphij	}
2446247880Sdelphij
2447247880Sdelphij	/* Is there atleast one eq that needs to be modified? */
2448338938Sjpaetzel        for(i = 0; i < num; i += 8) {
2449338938Sjpaetzel                if((num - i) >=8 )
2450338938Sjpaetzel                        oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], 8);
2451338938Sjpaetzel                else
2452338938Sjpaetzel                        oce_mbox_eqd_modify_periodic(sc, &set_eqd[i], (num - i));
2453338938Sjpaetzel        }
2454338938Sjpaetzel
2455247880Sdelphij}
2456247880Sdelphij
2457257007Sdelphijstatic void oce_detect_hw_error(POCE_SOFTC sc)
2458257007Sdelphij{
2459257007Sdelphij
2460257007Sdelphij	uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0;
2461257007Sdelphij	uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
2462257007Sdelphij	uint32_t i;
2463257007Sdelphij
2464257007Sdelphij	if (sc->hw_error)
2465257007Sdelphij		return;
2466257007Sdelphij
2467257007Sdelphij	if (IS_XE201(sc)) {
2468257007Sdelphij		sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET);
2469257007Sdelphij		if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
2470257007Sdelphij			sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET);
2471257007Sdelphij			sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET);
2472257007Sdelphij		}
2473257007Sdelphij	} else {
2474257007Sdelphij		ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW);
2475257007Sdelphij		ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH);
2476257007Sdelphij		ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK);
2477257007Sdelphij		ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK);
2478257007Sdelphij
2479257007Sdelphij		ue_low = (ue_low & ~ue_low_mask);
2480257007Sdelphij		ue_high = (ue_high & ~ue_high_mask);
2481257007Sdelphij	}
2482257007Sdelphij
2483257007Sdelphij	/* On certain platforms BE hardware can indicate spurious UEs.
2484257007Sdelphij	 * Allow the h/w to stop working completely in case of a real UE.
2485257007Sdelphij	 * Hence not setting the hw_error for UE detection.
2486257007Sdelphij	 */
2487257007Sdelphij	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
2488257007Sdelphij		sc->hw_error = TRUE;
2489257007Sdelphij		device_printf(sc->dev, "Error detected in the card\n");
2490257007Sdelphij	}
2491257007Sdelphij
2492257007Sdelphij	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
2493257007Sdelphij		device_printf(sc->dev,
2494257007Sdelphij				"ERR: sliport status 0x%x\n", sliport_status);
2495257007Sdelphij		device_printf(sc->dev,
2496257007Sdelphij				"ERR: sliport error1 0x%x\n", sliport_err1);
2497257007Sdelphij		device_printf(sc->dev,
2498257007Sdelphij				"ERR: sliport error2 0x%x\n", sliport_err2);
2499257007Sdelphij	}
2500257007Sdelphij
2501257007Sdelphij	if (ue_low) {
2502257007Sdelphij		for (i = 0; ue_low; ue_low >>= 1, i++) {
2503257007Sdelphij			if (ue_low & 1)
2504257007Sdelphij				device_printf(sc->dev, "UE: %s bit set\n",
2505257007Sdelphij							ue_status_low_desc[i]);
2506257007Sdelphij		}
2507257007Sdelphij	}
2508257007Sdelphij
2509257007Sdelphij	if (ue_high) {
2510257007Sdelphij		for (i = 0; ue_high; ue_high >>= 1, i++) {
2511257007Sdelphij			if (ue_high & 1)
2512257007Sdelphij				device_printf(sc->dev, "UE: %s bit set\n",
2513257007Sdelphij							ue_status_hi_desc[i]);
2514257007Sdelphij		}
2515257007Sdelphij	}
2516257007Sdelphij
2517257007Sdelphij}
2518257007Sdelphij
2519257007Sdelphij
2520231437Sluigistatic void
2521231437Sluigioce_local_timer(void *arg)
2522231437Sluigi{
2523231437Sluigi	POCE_SOFTC sc = arg;
2524231437Sluigi	int i = 0;
2525231437Sluigi
2526257007Sdelphij	oce_detect_hw_error(sc);
2527231437Sluigi	oce_refresh_nic_stats(sc);
2528231437Sluigi	oce_refresh_queue_stats(sc);
2529231437Sluigi	oce_mac_addr_set(sc);
2530231437Sluigi
2531231437Sluigi	/* TX Watch Dog*/
2532231437Sluigi	for (i = 0; i < sc->nwqs; i++)
2533231437Sluigi		oce_tx_restart(sc, sc->wq[i]);
2534231437Sluigi
2535247880Sdelphij	/* calculate and set the eq delay for optimal interrupt rate */
2536252869Sdelphij	if (IS_BE(sc) || IS_SH(sc))
2537247880Sdelphij		oce_eqd_set_periodic(sc);
2538247880Sdelphij
2539231437Sluigi	callout_reset(&sc->timer, hz, oce_local_timer, sc);
2540231437Sluigi}
2541231437Sluigi
2542338938Sjpaetzelstatic void
2543338938Sjpaetzeloce_tx_compl_clean(POCE_SOFTC sc)
2544338938Sjpaetzel{
2545338938Sjpaetzel	struct oce_wq *wq;
2546338938Sjpaetzel	int i = 0, timeo = 0, num_wqes = 0;
2547338938Sjpaetzel	int pending_txqs = sc->nwqs;
2548231437Sluigi
2549338938Sjpaetzel	/* Stop polling for compls when HW has been silent for 10ms or
2550338938Sjpaetzel	 * hw_error or no outstanding completions expected
2551338938Sjpaetzel	 */
2552338938Sjpaetzel	do {
2553338938Sjpaetzel		pending_txqs = sc->nwqs;
2554338938Sjpaetzel
2555338938Sjpaetzel		for_all_wq_queues(sc, wq, i) {
2556338938Sjpaetzel			num_wqes = oce_wq_handler(wq);
2557338938Sjpaetzel
2558338938Sjpaetzel			if(num_wqes)
2559338938Sjpaetzel				timeo = 0;
2560338938Sjpaetzel
2561338938Sjpaetzel			if(!wq->ring->num_used)
2562338938Sjpaetzel				pending_txqs--;
2563338938Sjpaetzel		}
2564338938Sjpaetzel
2565338938Sjpaetzel		if (pending_txqs == 0 || ++timeo > 10 || sc->hw_error)
2566338938Sjpaetzel			break;
2567338938Sjpaetzel
2568338938Sjpaetzel		DELAY(1000);
2569338938Sjpaetzel	} while (TRUE);
2570338938Sjpaetzel
2571338938Sjpaetzel	for_all_wq_queues(sc, wq, i) {
2572338938Sjpaetzel		while(wq->ring->num_used) {
2573338938Sjpaetzel			LOCK(&wq->tx_compl_lock);
2574338938Sjpaetzel			oce_process_tx_completion(wq);
2575338938Sjpaetzel			UNLOCK(&wq->tx_compl_lock);
2576338938Sjpaetzel		}
2577338938Sjpaetzel	}
2578338938Sjpaetzel
2579338938Sjpaetzel}
2580338938Sjpaetzel
2581246799Sjpaetzel/* NOTE : This should only be called holding
2582246799Sjpaetzel *        DEVICE_LOCK.
2583257007Sdelphij */
2584231437Sluigistatic void
2585231437Sluigioce_if_deactivate(POCE_SOFTC sc)
2586231437Sluigi{
2587338938Sjpaetzel	int i;
2588231437Sluigi	struct oce_rq *rq;
2589231437Sluigi	struct oce_wq *wq;
2590231437Sluigi	struct oce_eq *eq;
2591231437Sluigi
2592231437Sluigi	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2593231437Sluigi
2594338938Sjpaetzel	oce_tx_compl_clean(sc);
2595231437Sluigi
2596231437Sluigi	/* Stop intrs and finish any bottom halves pending */
2597231437Sluigi	oce_hw_intr_disable(sc);
2598231437Sluigi
2599247880Sdelphij	/* Since taskqueue_drain takes a Gaint Lock, We should not acquire
2600247880Sdelphij	   any other lock. So unlock device lock and require after
2601247880Sdelphij	   completing taskqueue_drain.
2602247880Sdelphij	*/
2603247880Sdelphij	UNLOCK(&sc->dev_lock);
2604231437Sluigi	for (i = 0; i < sc->intr_count; i++) {
2605231437Sluigi		if (sc->intrs[i].tq != NULL) {
2606231437Sluigi			taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
2607231437Sluigi		}
2608231437Sluigi	}
2609247880Sdelphij	LOCK(&sc->dev_lock);
2610231437Sluigi
2611231437Sluigi	/* Delete RX queue in card with flush param */
2612231437Sluigi	oce_stop_rx(sc);
2613231437Sluigi
2614231437Sluigi	/* Invalidate any pending cq and eq entries*/
2615231437Sluigi	for_all_evnt_queues(sc, eq, i)
2616231437Sluigi		oce_drain_eq(eq);
2617231437Sluigi	for_all_rq_queues(sc, rq, i)
2618231437Sluigi		oce_drain_rq_cq(rq);
2619231437Sluigi	for_all_wq_queues(sc, wq, i)
2620231437Sluigi		oce_drain_wq_cq(wq);
2621231437Sluigi
2622231437Sluigi	/* But still we need to get MCC aync events.
2623231437Sluigi	   So enable intrs and also arm first EQ
2624247880Sdelphij	*/
2625231437Sluigi	oce_hw_intr_enable(sc);
2626231437Sluigi	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
2627231437Sluigi
2628231437Sluigi	DELAY(10);
2629231437Sluigi}
2630231437Sluigi
2631231437Sluigi
2632231437Sluigistatic void
2633231437Sluigioce_if_activate(POCE_SOFTC sc)
2634231437Sluigi{
2635231437Sluigi	struct oce_eq *eq;
2636231437Sluigi	struct oce_rq *rq;
2637231437Sluigi	struct oce_wq *wq;
2638231437Sluigi	int i, rc = 0;
2639231437Sluigi
2640231437Sluigi	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
2641231437Sluigi
2642231437Sluigi	oce_hw_intr_disable(sc);
2643231437Sluigi
2644231437Sluigi	oce_start_rx(sc);
2645231437Sluigi
2646231437Sluigi	for_all_rq_queues(sc, rq, i) {
2647231437Sluigi		rc = oce_start_rq(rq);
2648231437Sluigi		if (rc)
2649231437Sluigi			device_printf(sc->dev, "Unable to start RX\n");
2650231437Sluigi	}
2651231437Sluigi
2652231437Sluigi	for_all_wq_queues(sc, wq, i) {
2653231437Sluigi		rc = oce_start_wq(wq);
2654231437Sluigi		if (rc)
2655231437Sluigi			device_printf(sc->dev, "Unable to start TX\n");
2656231437Sluigi	}
2657231437Sluigi
2658231437Sluigi
2659231437Sluigi	for_all_evnt_queues(sc, eq, i)
2660231437Sluigi		oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
2661231437Sluigi
2662231437Sluigi	oce_hw_intr_enable(sc);
2663231437Sluigi
2664231437Sluigi}
2665231437Sluigi
2666231879Sluigistatic void
2667231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
2668231879Sluigi{
2669231879Sluigi	/* Update Link status */
2670231879Sluigi	if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
2671231879Sluigi	     ASYNC_EVENT_LINK_UP) {
2672231879Sluigi		sc->link_status = ASYNC_EVENT_LINK_UP;
2673231879Sluigi		if_link_state_change(sc->ifp, LINK_STATE_UP);
2674231879Sluigi	} else {
2675231879Sluigi		sc->link_status = ASYNC_EVENT_LINK_DOWN;
2676231879Sluigi		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
2677231879Sluigi	}
2678231879Sluigi}
2679231879Sluigi
2680231879Sluigi
2681338938Sjpaetzelstatic void oce_async_grp5_osbmc_process(POCE_SOFTC sc,
2682338938Sjpaetzel					 struct oce_async_evt_grp5_os2bmc *evt)
2683338938Sjpaetzel{
2684338938Sjpaetzel	DW_SWAP(evt, sizeof(struct oce_async_evt_grp5_os2bmc));
2685338938Sjpaetzel	if (evt->u.s.mgmt_enable)
2686338938Sjpaetzel		sc->flags |= OCE_FLAGS_OS2BMC;
2687338938Sjpaetzel	else
2688338938Sjpaetzel		return;
2689338938Sjpaetzel
2690338938Sjpaetzel	sc->bmc_filt_mask = evt->u.s.arp_filter;
2691338938Sjpaetzel	sc->bmc_filt_mask |= (evt->u.s.dhcp_client_filt << 1);
2692338938Sjpaetzel	sc->bmc_filt_mask |= (evt->u.s.dhcp_server_filt << 2);
2693338938Sjpaetzel	sc->bmc_filt_mask |= (evt->u.s.net_bios_filt << 3);
2694338938Sjpaetzel	sc->bmc_filt_mask |= (evt->u.s.bcast_filt << 4);
2695338938Sjpaetzel	sc->bmc_filt_mask |= (evt->u.s.ipv6_nbr_filt << 5);
2696338938Sjpaetzel	sc->bmc_filt_mask |= (evt->u.s.ipv6_ra_filt << 6);
2697338938Sjpaetzel	sc->bmc_filt_mask |= (evt->u.s.ipv6_ras_filt << 7);
2698338938Sjpaetzel	sc->bmc_filt_mask |= (evt->u.s.mcast_filt << 8);
2699338938Sjpaetzel}
2700338938Sjpaetzel
2701338938Sjpaetzel
2702338938Sjpaetzelstatic void oce_process_grp5_events(POCE_SOFTC sc, struct oce_mq_cqe *cqe)
2703338938Sjpaetzel{
2704338938Sjpaetzel	struct oce_async_event_grp5_pvid_state *gcqe;
2705338938Sjpaetzel	struct oce_async_evt_grp5_os2bmc *bmccqe;
2706338938Sjpaetzel
2707338938Sjpaetzel	switch (cqe->u0.s.async_type) {
2708338938Sjpaetzel	case ASYNC_EVENT_PVID_STATE:
2709338938Sjpaetzel		/* GRP5 PVID */
2710338938Sjpaetzel		gcqe = (struct oce_async_event_grp5_pvid_state *)cqe;
2711338938Sjpaetzel		if (gcqe->enabled)
2712338938Sjpaetzel			sc->pvid = gcqe->tag & VLAN_VID_MASK;
2713338938Sjpaetzel		else
2714338938Sjpaetzel			sc->pvid = 0;
2715338938Sjpaetzel		break;
2716338938Sjpaetzel	case ASYNC_EVENT_OS2BMC:
2717338938Sjpaetzel		bmccqe = (struct oce_async_evt_grp5_os2bmc *)cqe;
2718338938Sjpaetzel		oce_async_grp5_osbmc_process(sc, bmccqe);
2719338938Sjpaetzel		break;
2720338938Sjpaetzel	default:
2721338938Sjpaetzel		break;
2722338938Sjpaetzel	}
2723338938Sjpaetzel}
2724338938Sjpaetzel
2725231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */
2726231437Sluigiuint16_t
2727231437Sluigioce_mq_handler(void *arg)
2728231437Sluigi{
2729231437Sluigi	struct oce_mq *mq = (struct oce_mq *)arg;
2730231437Sluigi	POCE_SOFTC sc = mq->parent;
2731231437Sluigi	struct oce_cq *cq = mq->cq;
2732231879Sluigi	int num_cqes = 0, evt_type = 0, optype = 0;
2733231437Sluigi	struct oce_mq_cqe *cqe;
2734231437Sluigi	struct oce_async_cqe_link_state *acqe;
2735247880Sdelphij	struct oce_async_event_qnq *dbgcqe;
2736231437Sluigi
2737231879Sluigi
2738231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
2739231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2740231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
2741231879Sluigi
2742231437Sluigi	while (cqe->u0.dw[3]) {
2743231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
2744231437Sluigi		if (cqe->u0.s.async_event) {
2745231879Sluigi			evt_type = cqe->u0.s.event_type;
2746231879Sluigi			optype = cqe->u0.s.async_type;
2747231879Sluigi			if (evt_type  == ASYNC_EVENT_CODE_LINK_STATE) {
2748231879Sluigi				/* Link status evt */
2749231879Sluigi				acqe = (struct oce_async_cqe_link_state *)cqe;
2750231879Sluigi				process_link_state(sc, acqe);
2751338938Sjpaetzel			} else if (evt_type == ASYNC_EVENT_GRP5) {
2752338938Sjpaetzel				oce_process_grp5_events(sc, cqe);
2753338938Sjpaetzel			} else if (evt_type == ASYNC_EVENT_CODE_DEBUG &&
2754338938Sjpaetzel					optype == ASYNC_EVENT_DEBUG_QNQ) {
2755338938Sjpaetzel				dbgcqe =  (struct oce_async_event_qnq *)cqe;
2756247880Sdelphij				if(dbgcqe->valid)
2757247880Sdelphij					sc->qnqid = dbgcqe->vlan_tag;
2758247880Sdelphij				sc->qnq_debug_event = TRUE;
2759247880Sdelphij			}
2760231437Sluigi		}
2761231437Sluigi		cqe->u0.dw[3] = 0;
2762231437Sluigi		RING_GET(cq->ring, 1);
2763231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
2764231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2765231437Sluigi		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
2766231437Sluigi		num_cqes++;
2767231437Sluigi	}
2768231437Sluigi
2769231437Sluigi	if (num_cqes)
2770231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
2771231437Sluigi
2772231437Sluigi	return 0;
2773231437Sluigi}
2774231437Sluigi
2775231437Sluigi
2776231437Sluigistatic void
2777231437Sluigisetup_max_queues_want(POCE_SOFTC sc)
2778231437Sluigi{
2779231437Sluigi	/* Check if it is FLEX machine. Is so dont use RSS */
2780231437Sluigi	if ((sc->function_mode & FNM_FLEX10_MODE) ||
2781231879Sluigi	    (sc->function_mode & FNM_UMC_MODE)    ||
2782231879Sluigi	    (sc->function_mode & FNM_VNIC_MODE)	  ||
2783252869Sdelphij	    (!is_rss_enabled(sc))		  ||
2784267839Sdelphij	    IS_BE2(sc)) {
2785231437Sluigi		sc->nrqs = 1;
2786231437Sluigi		sc->nwqs = 1;
2787257007Sdelphij	} else {
2788257007Sdelphij		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
2789257007Sdelphij		sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs);
2790231437Sluigi	}
2791267839Sdelphij
2792267839Sdelphij	if (IS_BE2(sc) && is_rss_enabled(sc))
2793267839Sdelphij		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
2794231437Sluigi}
2795231437Sluigi
2796231437Sluigi
2797231437Sluigistatic void
2798231437Sluigiupdate_queues_got(POCE_SOFTC sc)
2799231437Sluigi{
2800252869Sdelphij	if (is_rss_enabled(sc)) {
2801231437Sluigi		sc->nrqs = sc->intr_count + 1;
2802231437Sluigi		sc->nwqs = sc->intr_count;
2803231437Sluigi	} else {
2804231437Sluigi		sc->nrqs = 1;
2805231437Sluigi		sc->nwqs = 1;
2806231437Sluigi	}
2807267839Sdelphij
2808267839Sdelphij	if (IS_BE2(sc))
2809267839Sdelphij		sc->nwqs = 1;
2810231437Sluigi}
2811231437Sluigi
2812247880Sdelphijstatic int
2813247880Sdelphijoce_check_ipv6_ext_hdr(struct mbuf *m)
2814247880Sdelphij{
2815247880Sdelphij	struct ether_header *eh = mtod(m, struct ether_header *);
2816247880Sdelphij	caddr_t m_datatemp = m->m_data;
2817247880Sdelphij
2818247880Sdelphij	if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2819247880Sdelphij		m->m_data += sizeof(struct ether_header);
2820247880Sdelphij		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2821247880Sdelphij
2822247880Sdelphij		if((ip6->ip6_nxt != IPPROTO_TCP) && \
2823247880Sdelphij				(ip6->ip6_nxt != IPPROTO_UDP)){
2824247880Sdelphij			struct ip6_ext *ip6e = NULL;
2825247880Sdelphij			m->m_data += sizeof(struct ip6_hdr);
2826247880Sdelphij
2827247880Sdelphij			ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *);
2828247880Sdelphij			if(ip6e->ip6e_len == 0xff) {
2829247880Sdelphij				m->m_data = m_datatemp;
2830247880Sdelphij				return TRUE;
2831247880Sdelphij			}
2832247880Sdelphij		}
2833247880Sdelphij		m->m_data = m_datatemp;
2834247880Sdelphij	}
2835247880Sdelphij	return FALSE;
2836247880Sdelphij}
2837247880Sdelphij
2838247880Sdelphijstatic int
2839247880Sdelphijis_be3_a1(POCE_SOFTC sc)
2840247880Sdelphij{
2841247880Sdelphij	if((sc->flags & OCE_FLAGS_BE3)  && ((sc->asic_revision & 0xFF) < 2)) {
2842247880Sdelphij		return TRUE;
2843247880Sdelphij	}
2844247880Sdelphij	return FALSE;
2845247880Sdelphij}
2846247880Sdelphij
2847247880Sdelphijstatic struct mbuf *
2848247880Sdelphijoce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete)
2849247880Sdelphij{
2850247880Sdelphij	uint16_t vlan_tag = 0;
2851247880Sdelphij
2852247880Sdelphij	if(!M_WRITABLE(m))
2853247880Sdelphij		return NULL;
2854247880Sdelphij
2855247880Sdelphij	/* Embed vlan tag in the packet if it is not part of it */
2856247880Sdelphij	if(m->m_flags & M_VLANTAG) {
2857247880Sdelphij		vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
2858247880Sdelphij		m->m_flags &= ~M_VLANTAG;
2859247880Sdelphij	}
2860247880Sdelphij
2861247880Sdelphij	/* if UMC, ignore vlan tag insertion and instead insert pvid */
2862247880Sdelphij	if(sc->pvid) {
2863247880Sdelphij		if(!vlan_tag)
2864247880Sdelphij			vlan_tag = sc->pvid;
2865338938Sjpaetzel		if (complete)
2866338938Sjpaetzel			*complete = FALSE;
2867247880Sdelphij	}
2868247880Sdelphij
2869247880Sdelphij	if(vlan_tag) {
2870247880Sdelphij		m = ether_vlanencap(m, vlan_tag);
2871247880Sdelphij	}
2872247880Sdelphij
2873247880Sdelphij	if(sc->qnqid) {
2874247880Sdelphij		m = ether_vlanencap(m, sc->qnqid);
2875338938Sjpaetzel
2876338938Sjpaetzel		if (complete)
2877338938Sjpaetzel			*complete = FALSE;
2878247880Sdelphij	}
2879247880Sdelphij	return m;
2880247880Sdelphij}
2881247880Sdelphij
2882247880Sdelphijstatic int
2883247880Sdelphijoce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m)
2884247880Sdelphij{
2885247880Sdelphij	if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \
2886247880Sdelphij			oce_check_ipv6_ext_hdr(m)) {
2887247880Sdelphij		return TRUE;
2888247880Sdelphij	}
2889247880Sdelphij	return FALSE;
2890247880Sdelphij}
2891252869Sdelphij
2892252869Sdelphijstatic void
2893252869Sdelphijoce_get_config(POCE_SOFTC sc)
2894252869Sdelphij{
2895252869Sdelphij	int rc = 0;
2896252869Sdelphij	uint32_t max_rss = 0;
2897252869Sdelphij
2898252869Sdelphij	if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native))
2899252869Sdelphij		max_rss = OCE_LEGACY_MODE_RSS;
2900252869Sdelphij	else
2901252869Sdelphij		max_rss = OCE_MAX_RSS;
2902252869Sdelphij
2903252869Sdelphij	if (!IS_BE(sc)) {
2904258941Sdelphij		rc = oce_get_profile_config(sc, max_rss);
2905252869Sdelphij		if (rc) {
2906252869Sdelphij			sc->nwqs = OCE_MAX_WQ;
2907252869Sdelphij			sc->nrssqs = max_rss;
2908252869Sdelphij			sc->nrqs = sc->nrssqs + 1;
2909252869Sdelphij		}
2910252869Sdelphij	}
2911258941Sdelphij	else { /* For BE3 don't rely on fw for determining the resources */
2912252869Sdelphij		sc->nrssqs = max_rss;
2913252869Sdelphij		sc->nrqs = sc->nrssqs + 1;
2914258941Sdelphij		sc->nwqs = OCE_MAX_WQ;
2915258941Sdelphij		sc->max_vlans = MAX_VLANFILTER_SIZE;
2916252869Sdelphij	}
2917252869Sdelphij}
2918338938Sjpaetzel
2919338938Sjpaetzelstatic void
2920338938Sjpaetzeloce_rdma_close(void)
2921338938Sjpaetzel{
2922338938Sjpaetzel  if (oce_rdma_if != NULL) {
2923338938Sjpaetzel    oce_rdma_if = NULL;
2924338938Sjpaetzel  }
2925338938Sjpaetzel}
2926338938Sjpaetzel
2927338938Sjpaetzelstatic void
2928338938Sjpaetzeloce_get_mac_addr(POCE_SOFTC sc, uint8_t *macaddr)
2929338938Sjpaetzel{
2930338938Sjpaetzel  memcpy(macaddr, sc->macaddr.mac_addr, 6);
2931338938Sjpaetzel}
2932338938Sjpaetzel
2933338938Sjpaetzelint
2934338938Sjpaetzeloce_register_rdma(POCE_RDMA_INFO rdma_info, POCE_RDMA_IF rdma_if)
2935338938Sjpaetzel{
2936338938Sjpaetzel  POCE_SOFTC sc;
2937338938Sjpaetzel  struct oce_dev_info di;
2938338938Sjpaetzel  int i;
2939338938Sjpaetzel
2940338938Sjpaetzel  if ((rdma_info == NULL) || (rdma_if == NULL)) {
2941338938Sjpaetzel    return -EINVAL;
2942338938Sjpaetzel  }
2943338938Sjpaetzel
2944338938Sjpaetzel  if ((rdma_info->size != OCE_RDMA_INFO_SIZE) ||
2945338938Sjpaetzel      (rdma_if->size != OCE_RDMA_IF_SIZE)) {
2946338938Sjpaetzel    return -ENXIO;
2947338938Sjpaetzel  }
2948338938Sjpaetzel
2949338938Sjpaetzel  rdma_info->close = oce_rdma_close;
2950338938Sjpaetzel  rdma_info->mbox_post = oce_mbox_post;
2951338938Sjpaetzel  rdma_info->common_req_hdr_init = mbx_common_req_hdr_init;
2952338938Sjpaetzel  rdma_info->get_mac_addr = oce_get_mac_addr;
2953338938Sjpaetzel
2954338938Sjpaetzel  oce_rdma_if = rdma_if;
2955338938Sjpaetzel
2956338938Sjpaetzel  sc = softc_head;
2957338938Sjpaetzel  while (sc != NULL) {
2958338938Sjpaetzel    if (oce_rdma_if->announce != NULL) {
2959338938Sjpaetzel      memset(&di, 0, sizeof(di));
2960338938Sjpaetzel      di.dev = sc->dev;
2961338938Sjpaetzel      di.softc = sc;
2962338938Sjpaetzel      di.ifp = sc->ifp;
2963338938Sjpaetzel      di.db_bhandle = sc->db_bhandle;
2964338938Sjpaetzel      di.db_btag = sc->db_btag;
2965338938Sjpaetzel      di.db_page_size = 4096;
2966338938Sjpaetzel      if (sc->flags & OCE_FLAGS_USING_MSIX) {
2967338938Sjpaetzel        di.intr_mode = OCE_INTERRUPT_MODE_MSIX;
2968338938Sjpaetzel      } else if (sc->flags & OCE_FLAGS_USING_MSI) {
2969338938Sjpaetzel        di.intr_mode = OCE_INTERRUPT_MODE_MSI;
2970338938Sjpaetzel      } else {
2971338938Sjpaetzel        di.intr_mode = OCE_INTERRUPT_MODE_INTX;
2972338938Sjpaetzel      }
2973338938Sjpaetzel      di.dev_family = OCE_GEN2_FAMILY; // fixme: must detect skyhawk
2974338938Sjpaetzel      if (di.intr_mode != OCE_INTERRUPT_MODE_INTX) {
2975338938Sjpaetzel        di.msix.num_vectors = sc->intr_count + sc->roce_intr_count;
2976338938Sjpaetzel        di.msix.start_vector = sc->intr_count;
2977338938Sjpaetzel        for (i=0; i<di.msix.num_vectors; i++) {
2978338938Sjpaetzel          di.msix.vector_list[i] = sc->intrs[i].vector;
2979338938Sjpaetzel        }
2980338938Sjpaetzel      } else {
2981338938Sjpaetzel      }
2982338938Sjpaetzel      memcpy(di.mac_addr, sc->macaddr.mac_addr, 6);
2983338938Sjpaetzel      di.vendor_id = pci_get_vendor(sc->dev);
2984338938Sjpaetzel      di.dev_id = pci_get_device(sc->dev);
2985338938Sjpaetzel
2986338938Sjpaetzel      if (sc->rdma_flags & OCE_RDMA_FLAG_SUPPORTED) {
2987338938Sjpaetzel          di.flags  |= OCE_RDMA_INFO_RDMA_SUPPORTED;
2988338938Sjpaetzel      }
2989338938Sjpaetzel
2990338938Sjpaetzel      rdma_if->announce(&di);
2991338938Sjpaetzel      sc = sc->next;
2992338938Sjpaetzel    }
2993338938Sjpaetzel  }
2994338938Sjpaetzel
2995338938Sjpaetzel  return 0;
2996338938Sjpaetzel}
2997338938Sjpaetzel
2998338938Sjpaetzelstatic void
2999338938Sjpaetzeloce_read_env_variables( POCE_SOFTC sc )
3000338938Sjpaetzel{
3001338938Sjpaetzel	char *value = NULL;
3002338938Sjpaetzel	int rc = 0;
3003338938Sjpaetzel
3004338938Sjpaetzel        /* read if user wants to enable hwlro or swlro */
3005338938Sjpaetzel        //value = getenv("oce_enable_hwlro");
3006338938Sjpaetzel        if(value && IS_SH(sc)) {
3007338938Sjpaetzel                sc->enable_hwlro = strtol(value, NULL, 10);
3008338938Sjpaetzel                if(sc->enable_hwlro) {
3009338938Sjpaetzel                        rc = oce_mbox_nic_query_lro_capabilities(sc, NULL, NULL);
3010338938Sjpaetzel                        if(rc) {
3011338938Sjpaetzel                                device_printf(sc->dev, "no hardware lro support\n");
3012338938Sjpaetzel                		device_printf(sc->dev, "software lro enabled\n");
3013338938Sjpaetzel                                sc->enable_hwlro = 0;
3014338938Sjpaetzel                        }else {
3015338938Sjpaetzel                                device_printf(sc->dev, "hardware lro enabled\n");
3016338938Sjpaetzel				oce_max_rsp_handled = 32;
3017338938Sjpaetzel                        }
3018338938Sjpaetzel                }else {
3019338938Sjpaetzel                        device_printf(sc->dev, "software lro enabled\n");
3020338938Sjpaetzel                }
3021338938Sjpaetzel        }else {
3022338938Sjpaetzel                sc->enable_hwlro = 0;
3023338938Sjpaetzel        }
3024338938Sjpaetzel
3025338938Sjpaetzel        /* read mbuf size */
3026338938Sjpaetzel        //value = getenv("oce_rq_buf_size");
3027338938Sjpaetzel        if(value && IS_SH(sc)) {
3028338938Sjpaetzel                oce_rq_buf_size = strtol(value, NULL, 10);
3029338938Sjpaetzel                switch(oce_rq_buf_size) {
3030338938Sjpaetzel                case 2048:
3031338938Sjpaetzel                case 4096:
3032338938Sjpaetzel                case 9216:
3033338938Sjpaetzel                case 16384:
3034338938Sjpaetzel                        break;
3035338938Sjpaetzel
3036338938Sjpaetzel                default:
3037338938Sjpaetzel                        device_printf(sc->dev, " Supported oce_rq_buf_size values are 2K, 4K, 9K, 16K \n");
3038338938Sjpaetzel                        oce_rq_buf_size = 2048;
3039338938Sjpaetzel                }
3040338938Sjpaetzel        }
3041338938Sjpaetzel
3042338938Sjpaetzel	return;
3043338938Sjpaetzel}
3044