oce_if.c revision 231879
1231437Sluigi/*-
2231437Sluigi * Copyright (C) 2012 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: head/sys/dev/oce/oce_if.c 231879 2012-02-17 13:55:17Z luigi $ */
40231437Sluigi
41231511Sbz#include "opt_inet6.h"
42231511Sbz#include "opt_inet.h"
43231511Sbz
44231437Sluigi#include "oce_if.h"
45231437Sluigi
46231437Sluigi
47231437Sluigi/* Driver entry points prototypes */
48231437Sluigistatic int  oce_probe(device_t dev);
49231437Sluigistatic int  oce_attach(device_t dev);
50231437Sluigistatic int  oce_detach(device_t dev);
51231437Sluigistatic int  oce_shutdown(device_t dev);
52231437Sluigistatic int  oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
53231437Sluigistatic void oce_init(void *xsc);
54231437Sluigistatic int  oce_multiq_start(struct ifnet *ifp, struct mbuf *m);
55231437Sluigistatic void oce_multiq_flush(struct ifnet *ifp);
56231437Sluigi
57231437Sluigi/* Driver interrupt routines protypes */
58231437Sluigistatic void oce_intr(void *arg, int pending);
59231437Sluigistatic int  oce_setup_intr(POCE_SOFTC sc);
60231437Sluigistatic int  oce_fast_isr(void *arg);
61231437Sluigistatic int  oce_alloc_intr(POCE_SOFTC sc, int vector,
62231437Sluigi			  void (*isr) (void *arg, int pending));
63231437Sluigi
64231437Sluigi/* Media callbacks prototypes */
65231437Sluigistatic void oce_media_status(struct ifnet *ifp, struct ifmediareq *req);
66231437Sluigistatic int  oce_media_change(struct ifnet *ifp);
67231437Sluigi
68231437Sluigi/* Transmit routines prototypes */
69231437Sluigistatic int  oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index);
70231437Sluigistatic void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq);
71231437Sluigistatic void oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx,
72231437Sluigi					uint32_t status);
73231437Sluigistatic int  oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m,
74231437Sluigi				 struct oce_wq *wq);
75231437Sluigi
76231437Sluigi/* Receive routines prototypes */
77231437Sluigistatic void oce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe);
78231437Sluigistatic int  oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
79231437Sluigistatic int  oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
80231437Sluigistatic void oce_rx(struct oce_rq *rq, uint32_t rqe_idx,
81231437Sluigi						struct oce_nic_rx_cqe *cqe);
82231437Sluigi
83231437Sluigi/* Helper function prototypes in this file */
84231437Sluigistatic int  oce_attach_ifp(POCE_SOFTC sc);
85231437Sluigistatic void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag);
86231437Sluigistatic void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag);
87231437Sluigistatic int  oce_vid_config(POCE_SOFTC sc);
88231437Sluigistatic void oce_mac_addr_set(POCE_SOFTC sc);
89231437Sluigistatic int  oce_handle_passthrough(struct ifnet *ifp, caddr_t data);
90231437Sluigistatic void oce_local_timer(void *arg);
91231437Sluigistatic void oce_if_deactivate(POCE_SOFTC sc);
92231437Sluigistatic void oce_if_activate(POCE_SOFTC sc);
93231437Sluigistatic void setup_max_queues_want(POCE_SOFTC sc);
94231437Sluigistatic void update_queues_got(POCE_SOFTC sc);
95231879Sluigistatic void process_link_state(POCE_SOFTC sc,
96231879Sluigi		 struct oce_async_cqe_link_state *acqe);
97231437Sluigi
98231879Sluigi
99231879Sluigi/* IP specific */
100231879Sluigi#if defined(INET6) || defined(INET)
101231879Sluigistatic int  oce_init_lro(POCE_SOFTC sc);
102231879Sluigistatic void oce_rx_flush_lro(struct oce_rq *rq);
103231879Sluigistatic struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp);
104231879Sluigi#endif
105231879Sluigi
106231437Sluigistatic device_method_t oce_dispatch[] = {
107231437Sluigi	DEVMETHOD(device_probe, oce_probe),
108231437Sluigi	DEVMETHOD(device_attach, oce_attach),
109231437Sluigi	DEVMETHOD(device_detach, oce_detach),
110231437Sluigi	DEVMETHOD(device_shutdown, oce_shutdown),
111231437Sluigi	{0, 0}
112231437Sluigi};
113231437Sluigi
114231437Sluigistatic driver_t oce_driver = {
115231437Sluigi	"oce",
116231437Sluigi	oce_dispatch,
117231437Sluigi	sizeof(OCE_SOFTC)
118231437Sluigi};
119231437Sluigistatic devclass_t oce_devclass;
120231437Sluigi
121231437Sluigi
122231437SluigiDRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0);
123231437SluigiMODULE_DEPEND(oce, pci, 1, 1, 1);
124231437SluigiMODULE_DEPEND(oce, ether, 1, 1, 1);
125231437SluigiMODULE_VERSION(oce, 1);
126231437Sluigi
127231437Sluigi
128231437Sluigi/* global vars */
129231437Sluigiconst char component_revision[32] = {"///" COMPONENT_REVISION "///"};
130231437Sluigi
131231437Sluigi/* Module capabilites and parameters */
132231437Sluigiuint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED;
133231437Sluigiuint32_t oce_enable_rss = OCE_MODCAP_RSS;
134231437Sluigi
135231437Sluigi
136231437SluigiTUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled);
137231437SluigiTUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss);
138231437Sluigi
139231437Sluigi
140231437Sluigi/* Supported devices table */
141231437Sluigistatic uint32_t supportedDevices[] =  {
142231437Sluigi	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2,
143231437Sluigi	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3,
144231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3,
145231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201,
146231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF,
147231437Sluigi};
148231437Sluigi
149231437Sluigi
150231437Sluigi
151231437Sluigi
152231437Sluigi/*****************************************************************************
153231437Sluigi *			Driver entry points functions                        *
154231437Sluigi *****************************************************************************/
155231437Sluigi
156231437Sluigistatic int
157231437Sluigioce_probe(device_t dev)
158231437Sluigi{
159231879Sluigi	uint16_t vendor = 0;
160231879Sluigi	uint16_t device = 0;
161231879Sluigi	int i = 0;
162231879Sluigi	char str[256] = {0};
163231437Sluigi	POCE_SOFTC sc;
164231437Sluigi
165231437Sluigi	sc = device_get_softc(dev);
166231437Sluigi	bzero(sc, sizeof(OCE_SOFTC));
167231437Sluigi	sc->dev = dev;
168231437Sluigi
169231437Sluigi	vendor = pci_get_vendor(dev);
170231437Sluigi	device = pci_get_device(dev);
171231437Sluigi
172231879Sluigi	for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) {
173231437Sluigi		if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) {
174231437Sluigi			if (device == (supportedDevices[i] & 0xffff)) {
175231879Sluigi				sprintf(str, "%s:%s", "Emulex CNA NIC function",
176231437Sluigi					component_revision);
177231437Sluigi				device_set_desc_copy(dev, str);
178231437Sluigi
179231437Sluigi				switch (device) {
180231437Sluigi				case PCI_PRODUCT_BE2:
181231437Sluigi					sc->flags |= OCE_FLAGS_BE2;
182231437Sluigi					break;
183231437Sluigi				case PCI_PRODUCT_BE3:
184231437Sluigi					sc->flags |= OCE_FLAGS_BE3;
185231437Sluigi					break;
186231437Sluigi				case PCI_PRODUCT_XE201:
187231437Sluigi				case PCI_PRODUCT_XE201_VF:
188231437Sluigi					sc->flags |= OCE_FLAGS_XE201;
189231437Sluigi					break;
190231437Sluigi				default:
191231437Sluigi					return ENXIO;
192231437Sluigi				}
193231437Sluigi				return BUS_PROBE_DEFAULT;
194231437Sluigi			}
195231437Sluigi		}
196231437Sluigi	}
197231437Sluigi
198231437Sluigi	return ENXIO;
199231437Sluigi}
200231437Sluigi
201231437Sluigi
202231437Sluigistatic int
203231437Sluigioce_attach(device_t dev)
204231437Sluigi{
205231437Sluigi	POCE_SOFTC sc;
206231437Sluigi	int rc = 0;
207231437Sluigi
208231437Sluigi	sc = device_get_softc(dev);
209231437Sluigi
210231437Sluigi	rc = oce_hw_pci_alloc(sc);
211231437Sluigi	if (rc)
212231437Sluigi		return rc;
213231437Sluigi
214231437Sluigi	sc->rss_enable 	 = oce_enable_rss;
215231437Sluigi	sc->tx_ring_size = OCE_TX_RING_SIZE;
216231437Sluigi	sc->rx_ring_size = OCE_RX_RING_SIZE;
217231437Sluigi	sc->rq_frag_size = OCE_RQ_BUF_SIZE;
218231437Sluigi	sc->flow_control = OCE_DEFAULT_FLOW_CONTROL;
219231437Sluigi	sc->promisc	 = OCE_DEFAULT_PROMISCUOUS;
220231437Sluigi
221231437Sluigi	LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock");
222231437Sluigi	LOCK_CREATE(&sc->dev_lock,  "Device_lock");
223231437Sluigi
224231437Sluigi	/* initialise the hardware */
225231437Sluigi	rc = oce_hw_init(sc);
226231437Sluigi	if (rc)
227231437Sluigi		goto pci_res_free;
228231437Sluigi
229231437Sluigi	setup_max_queues_want(sc);
230231437Sluigi
231231437Sluigi	rc = oce_setup_intr(sc);
232231437Sluigi	if (rc)
233231437Sluigi		goto mbox_free;
234231437Sluigi
235231437Sluigi	rc = oce_queue_init_all(sc);
236231437Sluigi	if (rc)
237231437Sluigi		goto intr_free;
238231437Sluigi
239231437Sluigi	rc = oce_attach_ifp(sc);
240231437Sluigi	if (rc)
241231437Sluigi		goto queues_free;
242231437Sluigi
243231511Sbz#if defined(INET6) || defined(INET)
244231437Sluigi	rc = oce_init_lro(sc);
245231437Sluigi	if (rc)
246231879Sluigi		goto ifp_free;
247231511Sbz#endif
248231437Sluigi
249231437Sluigi	rc = oce_hw_start(sc);
250231437Sluigi	if (rc)
251231437Sluigi		goto lro_free;;
252231437Sluigi
253231437Sluigi	sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
254231437Sluigi				oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST);
255231437Sluigi	sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
256231437Sluigi				oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST);
257231437Sluigi
258231437Sluigi	rc = oce_stats_init(sc);
259231437Sluigi	if (rc)
260231437Sluigi		goto vlan_free;
261231437Sluigi
262231437Sluigi	oce_add_sysctls(sc);
263231437Sluigi
264231437Sluigi	callout_init(&sc->timer, CALLOUT_MPSAFE);
265231437Sluigi	rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc);
266231437Sluigi	if (rc)
267231437Sluigi		goto stats_free;
268231879Sluigi#ifdef DEV_NETMAP
269231879Sluigi#endif /* DEV_NETMAP */
270231437Sluigi
271231437Sluigi	return 0;
272231437Sluigi
273231437Sluigistats_free:
274231437Sluigi	callout_drain(&sc->timer);
275231437Sluigi	oce_stats_free(sc);
276231437Sluigivlan_free:
277231437Sluigi	if (sc->vlan_attach)
278231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
279231437Sluigi	if (sc->vlan_detach)
280231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
281231437Sluigi	oce_hw_intr_disable(sc);
282231437Sluigilro_free:
283231511Sbz#if defined(INET6) || defined(INET)
284231437Sluigi	oce_free_lro(sc);
285231437Sluigiifp_free:
286231511Sbz#endif
287231437Sluigi	ether_ifdetach(sc->ifp);
288231437Sluigi	if_free(sc->ifp);
289231437Sluigiqueues_free:
290231437Sluigi	oce_queue_release_all(sc);
291231437Sluigiintr_free:
292231437Sluigi	oce_intr_free(sc);
293231437Sluigimbox_free:
294231437Sluigi	oce_dma_free(sc, &sc->bsmbx);
295231437Sluigipci_res_free:
296231437Sluigi	oce_hw_pci_free(sc);
297231437Sluigi	LOCK_DESTROY(&sc->dev_lock);
298231437Sluigi	LOCK_DESTROY(&sc->bmbx_lock);
299231437Sluigi	return rc;
300231437Sluigi
301231437Sluigi}
302231437Sluigi
303231437Sluigi
304231437Sluigistatic int
305231437Sluigioce_detach(device_t dev)
306231437Sluigi{
307231437Sluigi	POCE_SOFTC sc = device_get_softc(dev);
308231437Sluigi
309231437Sluigi	LOCK(&sc->dev_lock);
310231437Sluigi	oce_if_deactivate(sc);
311231437Sluigi	UNLOCK(&sc->dev_lock);
312231437Sluigi
313231437Sluigi	callout_drain(&sc->timer);
314231437Sluigi
315231437Sluigi	if (sc->vlan_attach != NULL)
316231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
317231437Sluigi	if (sc->vlan_detach != NULL)
318231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
319231437Sluigi
320231437Sluigi	ether_ifdetach(sc->ifp);
321231437Sluigi
322231437Sluigi	if_free(sc->ifp);
323231437Sluigi
324231437Sluigi	oce_hw_shutdown(sc);
325231437Sluigi
326231437Sluigi	bus_generic_detach(dev);
327231437Sluigi
328231437Sluigi	return 0;
329231437Sluigi}
330231437Sluigi
331231437Sluigi
332231437Sluigistatic int
333231437Sluigioce_shutdown(device_t dev)
334231437Sluigi{
335231437Sluigi	int rc;
336231437Sluigi
337231437Sluigi	rc = oce_detach(dev);
338231437Sluigi
339231437Sluigi	return rc;
340231437Sluigi}
341231437Sluigi
342231437Sluigi
343231437Sluigistatic int
344231437Sluigioce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
345231437Sluigi{
346231437Sluigi	struct ifreq *ifr = (struct ifreq *)data;
347231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
348231437Sluigi	int rc = 0;
349231437Sluigi	uint32_t u;
350231437Sluigi
351231437Sluigi	switch (command) {
352231437Sluigi
353231437Sluigi	case SIOCGIFMEDIA:
354231437Sluigi		rc = ifmedia_ioctl(ifp, ifr, &sc->media, command);
355231437Sluigi		break;
356231437Sluigi
357231437Sluigi	case SIOCSIFMTU:
358231437Sluigi		if (ifr->ifr_mtu > OCE_MAX_MTU)
359231437Sluigi			rc = EINVAL;
360231437Sluigi		else
361231437Sluigi			ifp->if_mtu = ifr->ifr_mtu;
362231437Sluigi		break;
363231437Sluigi
364231437Sluigi	case SIOCSIFFLAGS:
365231437Sluigi		if (ifp->if_flags & IFF_UP) {
366231437Sluigi			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
367231437Sluigi				sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
368231437Sluigi				oce_init(sc);
369231437Sluigi			}
370231437Sluigi			device_printf(sc->dev, "Interface Up\n");
371231437Sluigi		} else {
372231437Sluigi			LOCK(&sc->dev_lock);
373231437Sluigi
374231437Sluigi			sc->ifp->if_drv_flags &=
375231437Sluigi			    ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
376231437Sluigi			oce_if_deactivate(sc);
377231437Sluigi
378231437Sluigi			UNLOCK(&sc->dev_lock);
379231437Sluigi
380231437Sluigi			device_printf(sc->dev, "Interface Down\n");
381231437Sluigi		}
382231437Sluigi
383231437Sluigi		if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) {
384231437Sluigi			sc->promisc = TRUE;
385231437Sluigi			oce_rxf_set_promiscuous(sc, sc->promisc);
386231437Sluigi		} else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) {
387231437Sluigi			sc->promisc = FALSE;
388231437Sluigi			oce_rxf_set_promiscuous(sc, sc->promisc);
389231437Sluigi		}
390231437Sluigi
391231437Sluigi		break;
392231437Sluigi
393231437Sluigi	case SIOCADDMULTI:
394231437Sluigi	case SIOCDELMULTI:
395231437Sluigi		rc = oce_hw_update_multicast(sc);
396231437Sluigi		if (rc)
397231437Sluigi			device_printf(sc->dev,
398231437Sluigi				"Update multicast address failed\n");
399231437Sluigi		break;
400231437Sluigi
401231437Sluigi	case SIOCSIFCAP:
402231437Sluigi		u = ifr->ifr_reqcap ^ ifp->if_capenable;
403231437Sluigi
404231437Sluigi		if (u & IFCAP_TXCSUM) {
405231437Sluigi			ifp->if_capenable ^= IFCAP_TXCSUM;
406231437Sluigi			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
407231437Sluigi
408231437Sluigi			if (IFCAP_TSO & ifp->if_capenable &&
409231437Sluigi			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
410231437Sluigi				ifp->if_capenable &= ~IFCAP_TSO;
411231437Sluigi				ifp->if_hwassist &= ~CSUM_TSO;
412231437Sluigi				if_printf(ifp,
413231437Sluigi					 "TSO disabled due to -txcsum.\n");
414231437Sluigi			}
415231437Sluigi		}
416231437Sluigi
417231437Sluigi		if (u & IFCAP_RXCSUM)
418231437Sluigi			ifp->if_capenable ^= IFCAP_RXCSUM;
419231437Sluigi
420231437Sluigi		if (u & IFCAP_TSO4) {
421231437Sluigi			ifp->if_capenable ^= IFCAP_TSO4;
422231437Sluigi
423231437Sluigi			if (IFCAP_TSO & ifp->if_capenable) {
424231437Sluigi				if (IFCAP_TXCSUM & ifp->if_capenable)
425231437Sluigi					ifp->if_hwassist |= CSUM_TSO;
426231437Sluigi				else {
427231437Sluigi					ifp->if_capenable &= ~IFCAP_TSO;
428231437Sluigi					ifp->if_hwassist &= ~CSUM_TSO;
429231437Sluigi					if_printf(ifp,
430231437Sluigi					    "Enable txcsum first.\n");
431231437Sluigi					rc = EAGAIN;
432231437Sluigi				}
433231437Sluigi			} else
434231437Sluigi				ifp->if_hwassist &= ~CSUM_TSO;
435231437Sluigi		}
436231437Sluigi
437231437Sluigi		if (u & IFCAP_VLAN_HWTAGGING)
438231437Sluigi			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
439231437Sluigi
440231437Sluigi		if (u & IFCAP_VLAN_HWFILTER) {
441231437Sluigi			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
442231437Sluigi			oce_vid_config(sc);
443231437Sluigi		}
444231511Sbz#if defined(INET6) || defined(INET)
445231437Sluigi		if (u & IFCAP_LRO)
446231437Sluigi			ifp->if_capenable ^= IFCAP_LRO;
447231511Sbz#endif
448231437Sluigi
449231437Sluigi		break;
450231437Sluigi
451231437Sluigi	case SIOCGPRIVATE_0:
452231437Sluigi		rc = oce_handle_passthrough(ifp, data);
453231437Sluigi		break;
454231437Sluigi	default:
455231437Sluigi		rc = ether_ioctl(ifp, command, data);
456231437Sluigi		break;
457231437Sluigi	}
458231437Sluigi
459231437Sluigi	return rc;
460231437Sluigi}
461231437Sluigi
462231437Sluigi
463231437Sluigistatic void
464231437Sluigioce_init(void *arg)
465231437Sluigi{
466231437Sluigi	POCE_SOFTC sc = arg;
467231437Sluigi
468231437Sluigi	LOCK(&sc->dev_lock);
469231437Sluigi
470231437Sluigi	if (sc->ifp->if_flags & IFF_UP) {
471231437Sluigi		oce_if_deactivate(sc);
472231437Sluigi		oce_if_activate(sc);
473231437Sluigi	}
474231437Sluigi
475231437Sluigi	UNLOCK(&sc->dev_lock);
476231437Sluigi
477231437Sluigi}
478231437Sluigi
479231437Sluigi
480231437Sluigistatic int
481231437Sluigioce_multiq_start(struct ifnet *ifp, struct mbuf *m)
482231437Sluigi{
483231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
484231437Sluigi	struct oce_wq *wq = NULL;
485231437Sluigi	int queue_index = 0;
486231437Sluigi	int status = 0;
487231437Sluigi
488231437Sluigi	if ((m->m_flags & M_FLOWID) != 0)
489231437Sluigi		queue_index = m->m_pkthdr.flowid % sc->nwqs;
490231437Sluigi
491231437Sluigi	wq = sc->wq[queue_index];
492231437Sluigi
493231437Sluigi	if (TRY_LOCK(&wq->tx_lock)) {
494231437Sluigi		status = oce_multiq_transmit(ifp, m, wq);
495231437Sluigi		UNLOCK(&wq->tx_lock);
496231437Sluigi	} else {
497231437Sluigi		status = drbr_enqueue(ifp, wq->br, m);
498231437Sluigi	}
499231437Sluigi	return status;
500231437Sluigi
501231437Sluigi}
502231437Sluigi
503231437Sluigi
504231437Sluigistatic void
505231437Sluigioce_multiq_flush(struct ifnet *ifp)
506231437Sluigi{
507231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
508231437Sluigi	struct mbuf     *m;
509231437Sluigi	int i = 0;
510231437Sluigi
511231437Sluigi	for (i = 0; i < sc->nwqs; i++) {
512231437Sluigi		while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
513231437Sluigi			m_freem(m);
514231437Sluigi	}
515231437Sluigi	if_qflush(ifp);
516231437Sluigi}
517231437Sluigi
518231437Sluigi
519231437Sluigi
520231437Sluigi/*****************************************************************************
521231437Sluigi *                   Driver interrupt routines functions                     *
522231437Sluigi *****************************************************************************/
523231437Sluigi
524231437Sluigistatic void
525231437Sluigioce_intr(void *arg, int pending)
526231437Sluigi{
527231437Sluigi
528231437Sluigi	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
529231437Sluigi	POCE_SOFTC sc = ii->sc;
530231437Sluigi	struct oce_eq *eq = ii->eq;
531231437Sluigi	struct oce_eqe *eqe;
532231437Sluigi	struct oce_cq *cq = NULL;
533231437Sluigi	int i, num_eqes = 0;
534231437Sluigi
535231437Sluigi
536231437Sluigi	bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
537231437Sluigi				 BUS_DMASYNC_POSTWRITE);
538231437Sluigi	do {
539231437Sluigi		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
540231437Sluigi		if (eqe->evnt == 0)
541231437Sluigi			break;
542231437Sluigi		eqe->evnt = 0;
543231437Sluigi		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
544231437Sluigi					BUS_DMASYNC_POSTWRITE);
545231437Sluigi		RING_GET(eq->ring, 1);
546231437Sluigi		num_eqes++;
547231437Sluigi
548231437Sluigi	} while (TRUE);
549231437Sluigi
550231437Sluigi	if (!num_eqes)
551231437Sluigi		goto eq_arm; /* Spurious */
552231437Sluigi
553231437Sluigi 	/* Clear EQ entries, but dont arm */
554231437Sluigi	oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
555231437Sluigi
556231437Sluigi	/* Process TX, RX and MCC. But dont arm CQ*/
557231437Sluigi	for (i = 0; i < eq->cq_valid; i++) {
558231437Sluigi		cq = eq->cq[i];
559231437Sluigi		(*cq->cq_handler)(cq->cb_arg);
560231437Sluigi	}
561231437Sluigi
562231437Sluigi	/* Arm all cqs connected to this EQ */
563231437Sluigi	for (i = 0; i < eq->cq_valid; i++) {
564231437Sluigi		cq = eq->cq[i];
565231437Sluigi		oce_arm_cq(sc, cq->cq_id, 0, TRUE);
566231437Sluigi	}
567231437Sluigi
568231437Sluigieq_arm:
569231437Sluigi	oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
570231437Sluigi	return;
571231437Sluigi}
572231437Sluigi
573231437Sluigi
574231437Sluigistatic int
575231437Sluigioce_setup_intr(POCE_SOFTC sc)
576231437Sluigi{
577231437Sluigi	int rc = 0, use_intx = 0;
578231437Sluigi	int vector = 0, req_vectors = 0;
579231437Sluigi
580231437Sluigi	if (sc->rss_enable)
581231437Sluigi		req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
582231437Sluigi	else
583231437Sluigi		req_vectors = 1;
584231437Sluigi
585231437Sluigi	if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
586231437Sluigi		sc->intr_count = req_vectors;
587231437Sluigi		rc = pci_alloc_msix(sc->dev, &sc->intr_count);
588231437Sluigi		if (rc != 0) {
589231437Sluigi			use_intx = 1;
590231437Sluigi			pci_release_msi(sc->dev);
591231437Sluigi		} else
592231437Sluigi			sc->flags |= OCE_FLAGS_USING_MSIX;
593231437Sluigi	} else
594231437Sluigi		use_intx = 1;
595231437Sluigi
596231437Sluigi	if (use_intx)
597231437Sluigi		sc->intr_count = 1;
598231437Sluigi
599231437Sluigi	/* Scale number of queues based on intr we got */
600231437Sluigi	update_queues_got(sc);
601231437Sluigi
602231437Sluigi	if (use_intx) {
603231437Sluigi		device_printf(sc->dev, "Using legacy interrupt\n");
604231437Sluigi		rc = oce_alloc_intr(sc, vector, oce_intr);
605231437Sluigi		if (rc)
606231437Sluigi			goto error;
607231437Sluigi	} else {
608231437Sluigi		for (; vector < sc->intr_count; vector++) {
609231437Sluigi			rc = oce_alloc_intr(sc, vector, oce_intr);
610231437Sluigi			if (rc)
611231437Sluigi				goto error;
612231437Sluigi		}
613231437Sluigi	}
614231437Sluigi
615231437Sluigi	return 0;
616231437Sluigierror:
617231437Sluigi	oce_intr_free(sc);
618231437Sluigi	return rc;
619231437Sluigi}
620231437Sluigi
621231437Sluigi
622231437Sluigistatic int
623231437Sluigioce_fast_isr(void *arg)
624231437Sluigi{
625231437Sluigi	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
626231437Sluigi	POCE_SOFTC sc = ii->sc;
627231437Sluigi
628231437Sluigi	if (ii->eq == NULL)
629231437Sluigi		return FILTER_STRAY;
630231437Sluigi
631231437Sluigi	oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
632231437Sluigi
633231437Sluigi	taskqueue_enqueue_fast(ii->tq, &ii->task);
634231437Sluigi
635231437Sluigi	return FILTER_HANDLED;
636231437Sluigi}
637231437Sluigi
638231437Sluigi
639231437Sluigistatic int
640231437Sluigioce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
641231437Sluigi{
642231437Sluigi	POCE_INTR_INFO ii = &sc->intrs[vector];
643231437Sluigi	int rc = 0, rr;
644231437Sluigi
645231437Sluigi	if (vector >= OCE_MAX_EQ)
646231437Sluigi		return (EINVAL);
647231437Sluigi
648231437Sluigi	/* Set the resource id for the interrupt.
649231437Sluigi	 * MSIx is vector + 1 for the resource id,
650231437Sluigi	 * INTx is 0 for the resource id.
651231437Sluigi	 */
652231437Sluigi	if (sc->flags & OCE_FLAGS_USING_MSIX)
653231437Sluigi		rr = vector + 1;
654231437Sluigi	else
655231437Sluigi		rr = 0;
656231437Sluigi	ii->intr_res = bus_alloc_resource_any(sc->dev,
657231437Sluigi					      SYS_RES_IRQ,
658231437Sluigi					      &rr, RF_ACTIVE|RF_SHAREABLE);
659231437Sluigi	ii->irq_rr = rr;
660231437Sluigi	if (ii->intr_res == NULL) {
661231437Sluigi		device_printf(sc->dev,
662231437Sluigi			  "Could not allocate interrupt\n");
663231437Sluigi		rc = ENXIO;
664231437Sluigi		return rc;
665231437Sluigi	}
666231437Sluigi
667231437Sluigi	TASK_INIT(&ii->task, 0, isr, ii);
668231437Sluigi	ii->vector = vector;
669231437Sluigi	sprintf(ii->task_name, "oce_task[%d]", ii->vector);
670231437Sluigi	ii->tq = taskqueue_create_fast(ii->task_name,
671231437Sluigi			M_NOWAIT,
672231437Sluigi			taskqueue_thread_enqueue,
673231437Sluigi			&ii->tq);
674231437Sluigi	taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
675231437Sluigi			device_get_nameunit(sc->dev));
676231437Sluigi
677231437Sluigi	ii->sc = sc;
678231437Sluigi	rc = bus_setup_intr(sc->dev,
679231437Sluigi			ii->intr_res,
680231437Sluigi			INTR_TYPE_NET,
681231437Sluigi			oce_fast_isr, NULL, ii, &ii->tag);
682231437Sluigi	return rc;
683231437Sluigi
684231437Sluigi}
685231437Sluigi
686231437Sluigi
687231437Sluigivoid
688231437Sluigioce_intr_free(POCE_SOFTC sc)
689231437Sluigi{
690231437Sluigi	int i = 0;
691231437Sluigi
692231437Sluigi	for (i = 0; i < sc->intr_count; i++) {
693231437Sluigi
694231437Sluigi		if (sc->intrs[i].tag != NULL)
695231437Sluigi			bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
696231437Sluigi						sc->intrs[i].tag);
697231437Sluigi		if (sc->intrs[i].tq != NULL)
698231437Sluigi			taskqueue_free(sc->intrs[i].tq);
699231437Sluigi
700231437Sluigi		if (sc->intrs[i].intr_res != NULL)
701231437Sluigi			bus_release_resource(sc->dev, SYS_RES_IRQ,
702231437Sluigi						sc->intrs[i].irq_rr,
703231437Sluigi						sc->intrs[i].intr_res);
704231437Sluigi		sc->intrs[i].tag = NULL;
705231437Sluigi		sc->intrs[i].intr_res = NULL;
706231437Sluigi	}
707231437Sluigi
708231437Sluigi	if (sc->flags & OCE_FLAGS_USING_MSIX)
709231437Sluigi		pci_release_msi(sc->dev);
710231437Sluigi
711231437Sluigi}
712231437Sluigi
713231437Sluigi
714231437Sluigi
715231437Sluigi/******************************************************************************
716231437Sluigi*			  Media callbacks functions 			      *
717231437Sluigi******************************************************************************/
718231437Sluigi
719231437Sluigistatic void
720231437Sluigioce_media_status(struct ifnet *ifp, struct ifmediareq *req)
721231437Sluigi{
722231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc;
723231437Sluigi
724231437Sluigi
725231437Sluigi	req->ifm_status = IFM_AVALID;
726231437Sluigi	req->ifm_active = IFM_ETHER;
727231437Sluigi
728231437Sluigi	if (sc->link_status == 1)
729231437Sluigi		req->ifm_status |= IFM_ACTIVE;
730231437Sluigi	else
731231437Sluigi		return;
732231437Sluigi
733231437Sluigi	switch (sc->link_speed) {
734231437Sluigi	case 1: /* 10 Mbps */
735231437Sluigi		req->ifm_active |= IFM_10_T | IFM_FDX;
736231437Sluigi		sc->speed = 10;
737231437Sluigi		break;
738231437Sluigi	case 2: /* 100 Mbps */
739231437Sluigi		req->ifm_active |= IFM_100_TX | IFM_FDX;
740231437Sluigi		sc->speed = 100;
741231437Sluigi		break;
742231437Sluigi	case 3: /* 1 Gbps */
743231437Sluigi		req->ifm_active |= IFM_1000_T | IFM_FDX;
744231437Sluigi		sc->speed = 1000;
745231437Sluigi		break;
746231437Sluigi	case 4: /* 10 Gbps */
747231437Sluigi		req->ifm_active |= IFM_10G_SR | IFM_FDX;
748231437Sluigi		sc->speed = 10000;
749231437Sluigi		break;
750231437Sluigi	}
751231437Sluigi
752231437Sluigi	return;
753231437Sluigi}
754231437Sluigi
755231437Sluigi
756231437Sluigiint
757231437Sluigioce_media_change(struct ifnet *ifp)
758231437Sluigi{
759231437Sluigi	return 0;
760231437Sluigi}
761231437Sluigi
762231437Sluigi
763231437Sluigi
764231437Sluigi
765231437Sluigi/*****************************************************************************
766231437Sluigi *			  Transmit routines functions			     *
767231437Sluigi *****************************************************************************/
768231437Sluigi
769231437Sluigistatic int
770231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
771231437Sluigi{
772231437Sluigi	int rc = 0, i, retry_cnt = 0;
773231437Sluigi	bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
774231437Sluigi	struct mbuf *m, *m_temp;
775231437Sluigi	struct oce_wq *wq = sc->wq[wq_index];
776231437Sluigi	struct oce_packet_desc *pd;
777231437Sluigi	uint32_t out;
778231437Sluigi	struct oce_nic_hdr_wqe *nichdr;
779231437Sluigi	struct oce_nic_frag_wqe *nicfrag;
780231437Sluigi	int num_wqes;
781231437Sluigi	uint32_t reg_value;
782231437Sluigi
783231437Sluigi	m = *mpp;
784231437Sluigi	if (!m)
785231437Sluigi		return EINVAL;
786231437Sluigi
787231437Sluigi	if (!(m->m_flags & M_PKTHDR)) {
788231437Sluigi		rc = ENXIO;
789231437Sluigi		goto free_ret;
790231437Sluigi	}
791231437Sluigi
792231437Sluigi	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
793231879Sluigi		/* consolidate packet buffers for TSO/LSO segment offload */
794231511Sbz#if defined(INET6) || defined(INET)
795231879Sluigi		m = oce_tso_setup(sc, mpp);
796231511Sbz#else
797231511Sbz		m = NULL;
798231511Sbz#endif
799231437Sluigi		if (m == NULL) {
800231437Sluigi			rc = ENXIO;
801231437Sluigi			goto free_ret;
802231437Sluigi		}
803231437Sluigi	}
804231437Sluigi
805231437Sluigi	out = wq->packets_out + 1;
806231437Sluigi	if (out == OCE_WQ_PACKET_ARRAY_SIZE)
807231437Sluigi		out = 0;
808231437Sluigi	if (out == wq->packets_in)
809231437Sluigi		return EBUSY;
810231437Sluigi
811231437Sluigi	pd = &wq->pckts[wq->packets_out];
812231437Sluigiretry:
813231437Sluigi	rc = bus_dmamap_load_mbuf_sg(wq->tag,
814231437Sluigi				     pd->map,
815231437Sluigi				     m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
816231437Sluigi	if (rc == 0) {
817231437Sluigi		num_wqes = pd->nsegs + 1;
818231437Sluigi		if (IS_BE(sc)) {
819231437Sluigi			/*Dummy required only for BE3.*/
820231437Sluigi			if (num_wqes & 1)
821231437Sluigi				num_wqes++;
822231437Sluigi		}
823231437Sluigi		if (num_wqes >= RING_NUM_FREE(wq->ring)) {
824231437Sluigi			bus_dmamap_unload(wq->tag, pd->map);
825231437Sluigi			return EBUSY;
826231437Sluigi		}
827231437Sluigi
828231437Sluigi		bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
829231437Sluigi		pd->mbuf = m;
830231437Sluigi		wq->packets_out = out;
831231437Sluigi
832231437Sluigi		nichdr =
833231437Sluigi		    RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
834231437Sluigi		nichdr->u0.dw[0] = 0;
835231437Sluigi		nichdr->u0.dw[1] = 0;
836231437Sluigi		nichdr->u0.dw[2] = 0;
837231437Sluigi		nichdr->u0.dw[3] = 0;
838231437Sluigi
839231437Sluigi		nichdr->u0.s.complete = 1;
840231437Sluigi		nichdr->u0.s.event = 1;
841231437Sluigi		nichdr->u0.s.crc = 1;
842231437Sluigi		nichdr->u0.s.forward = 0;
843231437Sluigi		nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
844231437Sluigi		nichdr->u0.s.udpcs =
845231437Sluigi		    (m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
846231437Sluigi		nichdr->u0.s.tcpcs =
847231437Sluigi		    (m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
848231437Sluigi		nichdr->u0.s.num_wqe = num_wqes;
849231437Sluigi		nichdr->u0.s.total_length = m->m_pkthdr.len;
850231437Sluigi		if (m->m_flags & M_VLANTAG) {
851231437Sluigi			nichdr->u0.s.vlan = 1; /*Vlan present*/
852231437Sluigi			nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
853231437Sluigi		}
854231437Sluigi		if (m->m_pkthdr.csum_flags & CSUM_TSO) {
855231437Sluigi			if (m->m_pkthdr.tso_segsz) {
856231437Sluigi				nichdr->u0.s.lso = 1;
857231437Sluigi				nichdr->u0.s.lso_mss  = m->m_pkthdr.tso_segsz;
858231437Sluigi			}
859231437Sluigi			if (!IS_BE(sc))
860231437Sluigi				nichdr->u0.s.ipcs = 1;
861231437Sluigi		}
862231437Sluigi
863231437Sluigi		RING_PUT(wq->ring, 1);
864231437Sluigi		wq->ring->num_used++;
865231437Sluigi
866231437Sluigi		for (i = 0; i < pd->nsegs; i++) {
867231437Sluigi			nicfrag =
868231437Sluigi			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
869231437Sluigi						      struct oce_nic_frag_wqe);
870231437Sluigi			nicfrag->u0.s.rsvd0 = 0;
871231437Sluigi			nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
872231437Sluigi			nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
873231437Sluigi			nicfrag->u0.s.frag_len = segs[i].ds_len;
874231437Sluigi			pd->wqe_idx = wq->ring->pidx;
875231437Sluigi			RING_PUT(wq->ring, 1);
876231437Sluigi			wq->ring->num_used++;
877231437Sluigi		}
878231437Sluigi		if (num_wqes > (pd->nsegs + 1)) {
879231437Sluigi			nicfrag =
880231437Sluigi			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
881231437Sluigi						      struct oce_nic_frag_wqe);
882231437Sluigi			nicfrag->u0.dw[0] = 0;
883231437Sluigi			nicfrag->u0.dw[1] = 0;
884231437Sluigi			nicfrag->u0.dw[2] = 0;
885231437Sluigi			nicfrag->u0.dw[3] = 0;
886231437Sluigi			pd->wqe_idx = wq->ring->pidx;
887231437Sluigi			RING_PUT(wq->ring, 1);
888231437Sluigi			wq->ring->num_used++;
889231437Sluigi			pd->nsegs++;
890231437Sluigi		}
891231437Sluigi
892231437Sluigi		sc->ifp->if_opackets++;
893231437Sluigi		wq->tx_stats.tx_reqs++;
894231437Sluigi		wq->tx_stats.tx_wrbs += num_wqes;
895231437Sluigi		wq->tx_stats.tx_bytes += m->m_pkthdr.len;
896231437Sluigi		wq->tx_stats.tx_pkts++;
897231437Sluigi
898231437Sluigi		bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
899231437Sluigi				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
900231437Sluigi		reg_value = (num_wqes << 16) | wq->wq_id;
901231437Sluigi		OCE_WRITE_REG32(sc, db, PD_TXULP_DB, reg_value);
902231437Sluigi
903231437Sluigi	} else if (rc == EFBIG)	{
904231437Sluigi		if (retry_cnt == 0) {
905231437Sluigi			m_temp = m_defrag(m, M_DONTWAIT);
906231437Sluigi			if (m_temp == NULL)
907231437Sluigi				goto free_ret;
908231437Sluigi			m = m_temp;
909231437Sluigi			*mpp = m_temp;
910231437Sluigi			retry_cnt = retry_cnt + 1;
911231437Sluigi			goto retry;
912231437Sluigi		} else
913231437Sluigi			goto free_ret;
914231437Sluigi	} else if (rc == ENOMEM)
915231437Sluigi		return rc;
916231437Sluigi	else
917231437Sluigi		goto free_ret;
918231437Sluigi
919231437Sluigi	return 0;
920231437Sluigi
921231437Sluigifree_ret:
922231437Sluigi	m_freem(*mpp);
923231437Sluigi	*mpp = NULL;
924231437Sluigi	return rc;
925231437Sluigi}
926231437Sluigi
927231437Sluigi
928231437Sluigistatic void
929231437Sluigioce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status)
930231437Sluigi{
931231437Sluigi	uint32_t in;
932231437Sluigi	struct oce_packet_desc *pd;
933231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
934231437Sluigi	struct mbuf *m;
935231437Sluigi
936231437Sluigi	if (wq->packets_out == wq->packets_in)
937231437Sluigi		device_printf(sc->dev, "WQ transmit descriptor missing\n");
938231437Sluigi
939231437Sluigi	in = wq->packets_in + 1;
940231437Sluigi	if (in == OCE_WQ_PACKET_ARRAY_SIZE)
941231437Sluigi		in = 0;
942231437Sluigi
943231437Sluigi	pd = &wq->pckts[wq->packets_in];
944231437Sluigi	wq->packets_in = in;
945231437Sluigi	wq->ring->num_used -= (pd->nsegs + 1);
946231437Sluigi	bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
947231437Sluigi	bus_dmamap_unload(wq->tag, pd->map);
948231437Sluigi
949231437Sluigi	m = pd->mbuf;
950231437Sluigi	m_freem(m);
951231437Sluigi	pd->mbuf = NULL;
952231437Sluigi
953231437Sluigi	if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) {
954231437Sluigi		if (wq->ring->num_used < (wq->ring->num_items / 2)) {
955231437Sluigi			sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
956231437Sluigi			oce_tx_restart(sc, wq);
957231437Sluigi		}
958231437Sluigi	}
959231437Sluigi}
960231437Sluigi
961231437Sluigi
962231437Sluigistatic void
963231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
964231437Sluigi{
965231437Sluigi
966231437Sluigi	if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
967231437Sluigi		return;
968231437Sluigi
969231437Sluigi#if __FreeBSD_version >= 800000
970231437Sluigi	if (!drbr_empty(sc->ifp, wq->br))
971231437Sluigi#else
972231437Sluigi	if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd))
973231437Sluigi#endif
974231437Sluigi		taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask);
975231437Sluigi
976231437Sluigi}
977231437Sluigi
978231879Sluigi
979231511Sbz#if defined(INET6) || defined(INET)
980231437Sluigistatic struct mbuf *
981231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
982231437Sluigi{
983231437Sluigi	struct mbuf *m;
984231511Sbz#ifdef INET
985231437Sluigi	struct ip *ip;
986231511Sbz#endif
987231511Sbz#ifdef INET6
988231437Sluigi	struct ip6_hdr *ip6;
989231511Sbz#endif
990231437Sluigi	struct ether_vlan_header *eh;
991231437Sluigi	struct tcphdr *th;
992231437Sluigi	uint16_t etype;
993231879Sluigi	int total_len = 0, ehdrlen = 0;
994231437Sluigi
995231437Sluigi	m = *mpp;
996231437Sluigi
997231437Sluigi	if (M_WRITABLE(m) == 0) {
998231437Sluigi		m = m_dup(*mpp, M_DONTWAIT);
999231437Sluigi		if (!m)
1000231437Sluigi			return NULL;
1001231437Sluigi		m_freem(*mpp);
1002231437Sluigi		*mpp = m;
1003231437Sluigi	}
1004231437Sluigi
1005231437Sluigi	eh = mtod(m, struct ether_vlan_header *);
1006231437Sluigi	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
1007231437Sluigi		etype = ntohs(eh->evl_proto);
1008231437Sluigi		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1009231437Sluigi	} else {
1010231437Sluigi		etype = ntohs(eh->evl_encap_proto);
1011231437Sluigi		ehdrlen = ETHER_HDR_LEN;
1012231437Sluigi	}
1013231437Sluigi
1014231437Sluigi	switch (etype) {
1015231511Sbz#ifdef INET
1016231437Sluigi	case ETHERTYPE_IP:
1017231437Sluigi		ip = (struct ip *)(m->m_data + ehdrlen);
1018231437Sluigi		if (ip->ip_p != IPPROTO_TCP)
1019231437Sluigi			return NULL;
1020231437Sluigi		th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
1021231437Sluigi
1022231437Sluigi		total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
1023231437Sluigi		break;
1024231511Sbz#endif
1025231511Sbz#ifdef INET6
1026231437Sluigi	case ETHERTYPE_IPV6:
1027231437Sluigi		ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
1028231437Sluigi		if (ip6->ip6_nxt != IPPROTO_TCP)
1029231437Sluigi			return NULL;
1030231437Sluigi		th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
1031231437Sluigi
1032231437Sluigi		total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
1033231437Sluigi		break;
1034231511Sbz#endif
1035231437Sluigi	default:
1036231437Sluigi		return NULL;
1037231437Sluigi	}
1038231437Sluigi
1039231437Sluigi	m = m_pullup(m, total_len);
1040231437Sluigi	if (!m)
1041231437Sluigi		return NULL;
1042231437Sluigi	*mpp = m;
1043231437Sluigi	return m;
1044231437Sluigi
1045231437Sluigi}
1046231511Sbz#endif /* INET6 || INET */
1047231437Sluigi
1048231437Sluigivoid
1049231437Sluigioce_tx_task(void *arg, int npending)
1050231437Sluigi{
1051231437Sluigi	struct oce_wq *wq = arg;
1052231437Sluigi	POCE_SOFTC sc = wq->parent;
1053231437Sluigi	struct ifnet *ifp = sc->ifp;
1054231437Sluigi	int rc = 0;
1055231437Sluigi
1056231437Sluigi#if __FreeBSD_version >= 800000
1057231437Sluigi	if (TRY_LOCK(&wq->tx_lock)) {
1058231437Sluigi		rc = oce_multiq_transmit(ifp, NULL, wq);
1059231437Sluigi		if (rc) {
1060231437Sluigi			device_printf(sc->dev,
1061231437Sluigi			 "TX[%d] restart failed\n", wq->queue_index);
1062231437Sluigi		}
1063231437Sluigi		UNLOCK(&wq->tx_lock);
1064231437Sluigi	}
1065231437Sluigi#else
1066231437Sluigi	oce_start(ifp);
1067231437Sluigi#endif
1068231437Sluigi
1069231437Sluigi}
1070231437Sluigi
1071231437Sluigi
1072231437Sluigivoid
1073231437Sluigioce_start(struct ifnet *ifp)
1074231437Sluigi{
1075231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1076231437Sluigi	struct mbuf *m;
1077231437Sluigi	int rc = 0;
1078231879Sluigi	int def_q = 0; /* Defualt tx queue is 0*/
1079231437Sluigi
1080231437Sluigi	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1081231437Sluigi			IFF_DRV_RUNNING)
1082231437Sluigi		return;
1083231437Sluigi
1084231437Sluigi	do {
1085231437Sluigi		IF_DEQUEUE(&sc->ifp->if_snd, m);
1086231437Sluigi		if (m == NULL)
1087231437Sluigi			break;
1088231879Sluigi
1089231879Sluigi		LOCK(&sc->wq[def_q]->tx_lock);
1090231879Sluigi		rc = oce_tx(sc, &m, def_q);
1091231879Sluigi		UNLOCK(&sc->wq[def_q]->tx_lock);
1092231437Sluigi		if (rc) {
1093231437Sluigi			if (m != NULL) {
1094231879Sluigi				sc->wq[def_q]->tx_stats.tx_stops ++;
1095231437Sluigi				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1096231437Sluigi				IFQ_DRV_PREPEND(&ifp->if_snd, m);
1097231437Sluigi				m = NULL;
1098231437Sluigi			}
1099231437Sluigi			break;
1100231437Sluigi		}
1101231437Sluigi		if (m != NULL)
1102231437Sluigi			ETHER_BPF_MTAP(ifp, m);
1103231437Sluigi
1104231879Sluigi	} while (TRUE);
1105231437Sluigi
1106231437Sluigi	return;
1107231437Sluigi}
1108231437Sluigi
1109231437Sluigi
1110231437Sluigi/* Handle the Completion Queue for transmit */
1111231437Sluigiuint16_t
1112231437Sluigioce_wq_handler(void *arg)
1113231437Sluigi{
1114231437Sluigi	struct oce_wq *wq = (struct oce_wq *)arg;
1115231437Sluigi	POCE_SOFTC sc = wq->parent;
1116231437Sluigi	struct oce_cq *cq = wq->cq;
1117231437Sluigi	struct oce_nic_tx_cqe *cqe;
1118231437Sluigi	int num_cqes = 0;
1119231437Sluigi
1120231437Sluigi	LOCK(&wq->tx_lock);
1121231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
1122231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1123231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1124231437Sluigi	while (cqe->u0.dw[3]) {
1125231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
1126231437Sluigi
1127231437Sluigi		wq->ring->cidx = cqe->u0.s.wqe_index + 1;
1128231437Sluigi		if (wq->ring->cidx >= wq->ring->num_items)
1129231437Sluigi			wq->ring->cidx -= wq->ring->num_items;
1130231437Sluigi
1131231437Sluigi		oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status);
1132231437Sluigi		wq->tx_stats.tx_compl++;
1133231437Sluigi		cqe->u0.dw[3] = 0;
1134231437Sluigi		RING_GET(cq->ring, 1);
1135231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
1136231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1137231437Sluigi		cqe =
1138231437Sluigi		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1139231437Sluigi		num_cqes++;
1140231437Sluigi	}
1141231437Sluigi
1142231437Sluigi	if (num_cqes)
1143231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1144231437Sluigi	UNLOCK(&wq->tx_lock);
1145231437Sluigi
1146231437Sluigi	return 0;
1147231437Sluigi}
1148231437Sluigi
1149231437Sluigi
1150231437Sluigistatic int
1151231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq)
1152231437Sluigi{
1153231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1154231437Sluigi	int status = 0, queue_index = 0;
1155231437Sluigi	struct mbuf *next = NULL;
1156231437Sluigi	struct buf_ring *br = NULL;
1157231437Sluigi
1158231437Sluigi	br  = wq->br;
1159231437Sluigi	queue_index = wq->queue_index;
1160231437Sluigi
1161231437Sluigi	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1162231437Sluigi		IFF_DRV_RUNNING) {
1163231437Sluigi		if (m != NULL)
1164231437Sluigi			status = drbr_enqueue(ifp, br, m);
1165231437Sluigi		return status;
1166231437Sluigi	}
1167231437Sluigi
1168231437Sluigi	if (m == NULL)
1169231437Sluigi		next = drbr_dequeue(ifp, br);
1170231437Sluigi	else if (drbr_needs_enqueue(ifp, br)) {
1171231437Sluigi		if ((status = drbr_enqueue(ifp, br, m)) != 0)
1172231437Sluigi			return status;
1173231437Sluigi		next = drbr_dequeue(ifp, br);
1174231437Sluigi	} else
1175231437Sluigi		next = m;
1176231437Sluigi
1177231437Sluigi	while (next != NULL) {
1178231437Sluigi		if (oce_tx(sc, &next, queue_index)) {
1179231437Sluigi			if (next != NULL) {
1180231437Sluigi				wq->tx_stats.tx_stops ++;
1181231437Sluigi				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1182231437Sluigi				status = drbr_enqueue(ifp, br, next);
1183231437Sluigi			}
1184231437Sluigi			break;
1185231437Sluigi		}
1186231437Sluigi		drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags);
1187231437Sluigi		ETHER_BPF_MTAP(ifp, next);
1188231437Sluigi		next = drbr_dequeue(ifp, br);
1189231437Sluigi	}
1190231437Sluigi
1191231437Sluigi	return status;
1192231437Sluigi}
1193231437Sluigi
1194231437Sluigi
1195231437Sluigi
1196231437Sluigi
1197231437Sluigi/*****************************************************************************
1198231437Sluigi *			    Receive  routines functions 		     *
1199231437Sluigi *****************************************************************************/
1200231437Sluigi
1201231437Sluigistatic void
1202231437Sluigioce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe)
1203231437Sluigi{
1204231437Sluigi	uint32_t out;
1205231437Sluigi	struct oce_packet_desc *pd;
1206231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1207231437Sluigi	int i, len, frag_len;
1208231437Sluigi	struct mbuf *m = NULL, *tail = NULL;
1209231437Sluigi	uint16_t vtag;
1210231437Sluigi
1211231437Sluigi	len = cqe->u0.s.pkt_size;
1212231437Sluigi	if (!len) {
1213231437Sluigi		/*partial DMA workaround for Lancer*/
1214231437Sluigi		oce_discard_rx_comp(rq, cqe);
1215231437Sluigi		goto exit;
1216231437Sluigi	}
1217231437Sluigi
1218231879Sluigi	 /* Get vlan_tag value */
1219231879Sluigi	if(IS_BE(sc))
1220231879Sluigi		vtag = BSWAP_16(cqe->u0.s.vlan_tag);
1221231879Sluigi	else
1222231879Sluigi		vtag = cqe->u0.s.vlan_tag;
1223231879Sluigi
1224231879Sluigi
1225231437Sluigi	for (i = 0; i < cqe->u0.s.num_fragments; i++) {
1226231437Sluigi
1227231437Sluigi		if (rq->packets_out == rq->packets_in) {
1228231437Sluigi			device_printf(sc->dev,
1229231437Sluigi				  "RQ transmit descriptor missing\n");
1230231437Sluigi		}
1231231437Sluigi		out = rq->packets_out + 1;
1232231437Sluigi		if (out == OCE_RQ_PACKET_ARRAY_SIZE)
1233231437Sluigi			out = 0;
1234231437Sluigi		pd = &rq->pckts[rq->packets_out];
1235231437Sluigi		rq->packets_out = out;
1236231437Sluigi
1237231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1238231437Sluigi		bus_dmamap_unload(rq->tag, pd->map);
1239231437Sluigi		rq->pending--;
1240231437Sluigi
1241231437Sluigi		frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
1242231437Sluigi		pd->mbuf->m_len = frag_len;
1243231437Sluigi
1244231437Sluigi		if (tail != NULL) {
1245231437Sluigi			/* additional fragments */
1246231437Sluigi			pd->mbuf->m_flags &= ~M_PKTHDR;
1247231437Sluigi			tail->m_next = pd->mbuf;
1248231437Sluigi			tail = pd->mbuf;
1249231437Sluigi		} else {
1250231437Sluigi			/* first fragment, fill out much of the packet header */
1251231437Sluigi			pd->mbuf->m_pkthdr.len = len;
1252231437Sluigi			pd->mbuf->m_pkthdr.csum_flags = 0;
1253231437Sluigi			if (IF_CSUM_ENABLED(sc)) {
1254231437Sluigi				if (cqe->u0.s.l4_cksum_pass) {
1255231437Sluigi					pd->mbuf->m_pkthdr.csum_flags |=
1256231437Sluigi					    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1257231437Sluigi					pd->mbuf->m_pkthdr.csum_data = 0xffff;
1258231437Sluigi				}
1259231437Sluigi				if (cqe->u0.s.ip_cksum_pass) {
1260231879Sluigi					if (!cqe->u0.s.ip_ver) { /* IPV4 */
1261231437Sluigi						pd->mbuf->m_pkthdr.csum_flags |=
1262231437Sluigi						(CSUM_IP_CHECKED|CSUM_IP_VALID);
1263231437Sluigi					}
1264231437Sluigi				}
1265231437Sluigi			}
1266231437Sluigi			m = tail = pd->mbuf;
1267231437Sluigi		}
1268231437Sluigi		pd->mbuf = NULL;
1269231437Sluigi		len -= frag_len;
1270231437Sluigi	}
1271231437Sluigi
1272231437Sluigi	if (m) {
1273231437Sluigi		if (!oce_cqe_portid_valid(sc, cqe)) {
1274231437Sluigi			 m_freem(m);
1275231437Sluigi			 goto exit;
1276231437Sluigi		}
1277231437Sluigi
1278231437Sluigi		m->m_pkthdr.rcvif = sc->ifp;
1279231437Sluigi#if __FreeBSD_version >= 800000
1280231437Sluigi		m->m_pkthdr.flowid = rq->queue_index;
1281231437Sluigi		m->m_flags |= M_FLOWID;
1282231437Sluigi#endif
1283231879Sluigi		/* This deternies if vlan tag is Valid */
1284231437Sluigi		if (oce_cqe_vtp_valid(sc, cqe)) {
1285231437Sluigi			if (sc->function_mode & FNM_FLEX10_MODE) {
1286231879Sluigi				/* FLEX10. If QnQ is not set, neglect VLAN */
1287231437Sluigi				if (cqe->u0.s.qnq) {
1288231879Sluigi					m->m_pkthdr.ether_vtag = vtag;
1289231437Sluigi					m->m_flags |= M_VLANTAG;
1290231437Sluigi				}
1291231879Sluigi			} else if (sc->pvid != (vtag & VLAN_VID_MASK))  {
1292231879Sluigi				/* In UMC mode generally pvid will be striped by
1293231879Sluigi				   hw. But in some cases we have seen it comes
1294231879Sluigi				   with pvid. So if pvid == vlan, neglect vlan.
1295231879Sluigi				*/
1296231879Sluigi				m->m_pkthdr.ether_vtag = vtag;
1297231437Sluigi				m->m_flags |= M_VLANTAG;
1298231437Sluigi			}
1299231437Sluigi		}
1300231437Sluigi
1301231437Sluigi		sc->ifp->if_ipackets++;
1302231511Sbz#if defined(INET6) || defined(INET)
1303231437Sluigi		/* Try to queue to LRO */
1304231437Sluigi		if (IF_LRO_ENABLED(sc) &&
1305231437Sluigi		    !(m->m_flags & M_VLANTAG) &&
1306231437Sluigi		    (cqe->u0.s.ip_cksum_pass) &&
1307231437Sluigi		    (cqe->u0.s.l4_cksum_pass) &&
1308231437Sluigi		    (!cqe->u0.s.ip_ver)       &&
1309231437Sluigi		    (rq->lro.lro_cnt != 0)) {
1310231437Sluigi
1311231437Sluigi			if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
1312231437Sluigi				rq->lro_pkts_queued ++;
1313231437Sluigi				goto post_done;
1314231437Sluigi			}
1315231437Sluigi			/* If LRO posting fails then try to post to STACK */
1316231437Sluigi		}
1317231511Sbz#endif
1318231437Sluigi
1319231437Sluigi		(*sc->ifp->if_input) (sc->ifp, m);
1320231511Sbz#if defined(INET6) || defined(INET)
1321231437Sluigipost_done:
1322231511Sbz#endif
1323231437Sluigi		/* Update rx stats per queue */
1324231437Sluigi		rq->rx_stats.rx_pkts++;
1325231437Sluigi		rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
1326231437Sluigi		rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
1327231437Sluigi		if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
1328231437Sluigi			rq->rx_stats.rx_mcast_pkts++;
1329231437Sluigi		if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
1330231437Sluigi			rq->rx_stats.rx_ucast_pkts++;
1331231437Sluigi	}
1332231437Sluigiexit:
1333231437Sluigi	return;
1334231437Sluigi}
1335231437Sluigi
1336231437Sluigi
1337231437Sluigistatic void
1338231437Sluigioce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
1339231437Sluigi{
1340231437Sluigi	uint32_t out, i = 0;
1341231437Sluigi	struct oce_packet_desc *pd;
1342231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1343231437Sluigi	int num_frags = cqe->u0.s.num_fragments;
1344231437Sluigi
1345231437Sluigi	if (IS_XE201(sc) && cqe->u0.s.error) {
1346231437Sluigi		/* Lancer A0 workaround
1347231437Sluigi		* num_frags will be 1 more than actual in case of error
1348231437Sluigi		 */
1349231437Sluigi		if (num_frags)
1350231437Sluigi			num_frags -= 1;
1351231437Sluigi	}
1352231437Sluigi	for (i = 0; i < num_frags; i++) {
1353231437Sluigi		if (rq->packets_out == rq->packets_in) {
1354231437Sluigi			device_printf(sc->dev,
1355231437Sluigi				"RQ transmit descriptor missing\n");
1356231437Sluigi		}
1357231437Sluigi		out = rq->packets_out + 1;
1358231437Sluigi		if (out == OCE_RQ_PACKET_ARRAY_SIZE)
1359231437Sluigi			out = 0;
1360231437Sluigi		pd = &rq->pckts[rq->packets_out];
1361231437Sluigi		rq->packets_out = out;
1362231437Sluigi
1363231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1364231437Sluigi		bus_dmamap_unload(rq->tag, pd->map);
1365231437Sluigi		rq->pending--;
1366231437Sluigi		m_freem(pd->mbuf);
1367231437Sluigi	}
1368231437Sluigi
1369231437Sluigi}
1370231437Sluigi
1371231437Sluigi
1372231437Sluigistatic int
1373231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
1374231437Sluigi{
1375231437Sluigi	struct oce_nic_rx_cqe_v1 *cqe_v1;
1376231437Sluigi	int vtp = 0;
1377231437Sluigi
1378231437Sluigi	if (sc->be3_native) {
1379231437Sluigi		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1380231437Sluigi		vtp =  cqe_v1->u0.s.vlan_tag_present;
1381231879Sluigi	} else
1382231437Sluigi		vtp = cqe->u0.s.vlan_tag_present;
1383231437Sluigi
1384231437Sluigi	return vtp;
1385231437Sluigi
1386231437Sluigi}
1387231437Sluigi
1388231437Sluigi
1389231437Sluigistatic int
1390231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
1391231437Sluigi{
1392231437Sluigi	struct oce_nic_rx_cqe_v1 *cqe_v1;
1393231437Sluigi	int port_id = 0;
1394231437Sluigi
1395231437Sluigi	if (sc->be3_native && IS_BE(sc)) {
1396231437Sluigi		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1397231437Sluigi		port_id =  cqe_v1->u0.s.port;
1398231437Sluigi		if (sc->port_id != port_id)
1399231437Sluigi			return 0;
1400231437Sluigi	} else
1401231437Sluigi		;/* For BE3 legacy and Lancer this is dummy */
1402231437Sluigi
1403231437Sluigi	return 1;
1404231437Sluigi
1405231437Sluigi}
1406231437Sluigi
1407231511Sbz#if defined(INET6) || defined(INET)
1408231437Sluigistatic void
1409231437Sluigioce_rx_flush_lro(struct oce_rq *rq)
1410231437Sluigi{
1411231437Sluigi	struct lro_ctrl	*lro = &rq->lro;
1412231437Sluigi	struct lro_entry *queued;
1413231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1414231437Sluigi
1415231437Sluigi	if (!IF_LRO_ENABLED(sc))
1416231437Sluigi		return;
1417231437Sluigi
1418231437Sluigi	while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
1419231437Sluigi		SLIST_REMOVE_HEAD(&lro->lro_active, next);
1420231437Sluigi		tcp_lro_flush(lro, queued);
1421231437Sluigi	}
1422231437Sluigi	rq->lro_pkts_queued = 0;
1423231437Sluigi
1424231437Sluigi	return;
1425231437Sluigi}
1426231437Sluigi
1427231437Sluigi
1428231437Sluigistatic int
1429231437Sluigioce_init_lro(POCE_SOFTC sc)
1430231437Sluigi{
1431231437Sluigi	struct lro_ctrl *lro = NULL;
1432231437Sluigi	int i = 0, rc = 0;
1433231437Sluigi
1434231437Sluigi	for (i = 0; i < sc->nrqs; i++) {
1435231437Sluigi		lro = &sc->rq[i]->lro;
1436231437Sluigi		rc = tcp_lro_init(lro);
1437231437Sluigi		if (rc != 0) {
1438231437Sluigi			device_printf(sc->dev, "LRO init failed\n");
1439231437Sluigi			return rc;
1440231437Sluigi		}
1441231437Sluigi		lro->ifp = sc->ifp;
1442231437Sluigi	}
1443231437Sluigi
1444231437Sluigi	return rc;
1445231437Sluigi}
1446231437Sluigi
1447231879Sluigi
1448231437Sluigivoid
1449231437Sluigioce_free_lro(POCE_SOFTC sc)
1450231437Sluigi{
1451231437Sluigi	struct lro_ctrl *lro = NULL;
1452231437Sluigi	int i = 0;
1453231437Sluigi
1454231437Sluigi	for (i = 0; i < sc->nrqs; i++) {
1455231437Sluigi		lro = &sc->rq[i]->lro;
1456231437Sluigi		if (lro)
1457231437Sluigi			tcp_lro_free(lro);
1458231437Sluigi	}
1459231437Sluigi}
1460231879Sluigi#endif /* INET6 || INET */
1461231437Sluigi
1462231437Sluigiint
1463231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count)
1464231437Sluigi{
1465231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1466231437Sluigi	int i, in, rc;
1467231437Sluigi	struct oce_packet_desc *pd;
1468231437Sluigi	bus_dma_segment_t segs[6];
1469231437Sluigi	int nsegs, added = 0;
1470231437Sluigi	struct oce_nic_rqe *rqe;
1471231437Sluigi	pd_rxulp_db_t rxdb_reg;
1472231437Sluigi
1473231437Sluigi
1474231437Sluigi	for (i = 0; i < count; i++) {
1475231437Sluigi		in = rq->packets_in + 1;
1476231437Sluigi		if (in == OCE_RQ_PACKET_ARRAY_SIZE)
1477231437Sluigi			in = 0;
1478231437Sluigi		if (in == rq->packets_out)
1479231437Sluigi			break;	/* no more room */
1480231437Sluigi
1481231437Sluigi		pd = &rq->pckts[rq->packets_in];
1482231437Sluigi		pd->mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1483231437Sluigi		if (pd->mbuf == NULL)
1484231437Sluigi			break;
1485231437Sluigi
1486231437Sluigi		pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES;
1487231437Sluigi		rc = bus_dmamap_load_mbuf_sg(rq->tag,
1488231437Sluigi					     pd->map,
1489231437Sluigi					     pd->mbuf,
1490231437Sluigi					     segs, &nsegs, BUS_DMA_NOWAIT);
1491231437Sluigi		if (rc) {
1492231437Sluigi			m_free(pd->mbuf);
1493231437Sluigi			break;
1494231437Sluigi		}
1495231437Sluigi
1496231437Sluigi		if (nsegs != 1) {
1497231437Sluigi			i--;
1498231437Sluigi			continue;
1499231437Sluigi		}
1500231437Sluigi
1501231437Sluigi		rq->packets_in = in;
1502231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
1503231437Sluigi
1504231437Sluigi		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
1505231437Sluigi		rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
1506231437Sluigi		rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
1507231437Sluigi		DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
1508231437Sluigi		RING_PUT(rq->ring, 1);
1509231437Sluigi		added++;
1510231437Sluigi		rq->pending++;
1511231437Sluigi	}
1512231437Sluigi	if (added != 0) {
1513231437Sluigi		for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) {
1514231437Sluigi			DELAY(1);
1515231437Sluigi			rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS;
1516231437Sluigi			rxdb_reg.bits.qid = rq->rq_id;
1517231437Sluigi			OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1518231437Sluigi			added -= OCE_MAX_RQ_POSTS;
1519231437Sluigi		}
1520231437Sluigi		if (added > 0) {
1521231437Sluigi			DELAY(1);
1522231437Sluigi			rxdb_reg.bits.qid = rq->rq_id;
1523231437Sluigi			rxdb_reg.bits.num_posted = added;
1524231437Sluigi			OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1525231437Sluigi		}
1526231437Sluigi	}
1527231437Sluigi
1528231437Sluigi	return 0;
1529231437Sluigi}
1530231437Sluigi
1531231437Sluigi
1532231437Sluigi/* Handle the Completion Queue for receive */
1533231437Sluigiuint16_t
1534231437Sluigioce_rq_handler(void *arg)
1535231437Sluigi{
1536231437Sluigi	struct oce_rq *rq = (struct oce_rq *)arg;
1537231437Sluigi	struct oce_cq *cq = rq->cq;
1538231437Sluigi	POCE_SOFTC sc = rq->parent;
1539231437Sluigi	struct oce_nic_rx_cqe *cqe;
1540231437Sluigi	int num_cqes = 0, rq_buffers_used = 0;
1541231437Sluigi
1542231437Sluigi
1543231437Sluigi	LOCK(&rq->rx_lock);
1544231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
1545231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1546231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
1547231437Sluigi	while (cqe->u0.dw[2]) {
1548231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
1549231437Sluigi
1550231437Sluigi		RING_GET(rq->ring, 1);
1551231437Sluigi		if (cqe->u0.s.error == 0) {
1552231437Sluigi			oce_rx(rq, cqe->u0.s.frag_index, cqe);
1553231437Sluigi		} else {
1554231437Sluigi			rq->rx_stats.rxcp_err++;
1555231437Sluigi			sc->ifp->if_ierrors++;
1556231437Sluigi			if (IS_XE201(sc))
1557231437Sluigi				/* Lancer A0 no buffer workaround */
1558231437Sluigi				oce_discard_rx_comp(rq, cqe);
1559231437Sluigi			else
1560231437Sluigi				/* Post L3/L4 errors to stack.*/
1561231437Sluigi				oce_rx(rq, cqe->u0.s.frag_index, cqe);
1562231437Sluigi
1563231437Sluigi		}
1564231437Sluigi		rq->rx_stats.rx_compl++;
1565231437Sluigi		cqe->u0.dw[2] = 0;
1566231437Sluigi
1567231511Sbz#if defined(INET6) || defined(INET)
1568231437Sluigi		if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
1569231437Sluigi			oce_rx_flush_lro(rq);
1570231437Sluigi		}
1571231511Sbz#endif
1572231437Sluigi
1573231437Sluigi		RING_GET(cq->ring, 1);
1574231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
1575231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1576231437Sluigi		cqe =
1577231437Sluigi		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
1578231437Sluigi		num_cqes++;
1579231437Sluigi		if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
1580231437Sluigi			break;
1581231437Sluigi	}
1582231879Sluigi
1583231511Sbz#if defined(INET6) || defined(INET)
1584231437Sluigi	if (IF_LRO_ENABLED(sc))
1585231437Sluigi		oce_rx_flush_lro(rq);
1586231511Sbz#endif
1587231437Sluigi
1588231437Sluigi	if (num_cqes) {
1589231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1590231437Sluigi		rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending;
1591231437Sluigi		if (rq_buffers_used > 1)
1592231437Sluigi			oce_alloc_rx_bufs(rq, (rq_buffers_used - 1));
1593231437Sluigi	}
1594231437Sluigi
1595231437Sluigi	UNLOCK(&rq->rx_lock);
1596231437Sluigi
1597231437Sluigi	return 0;
1598231437Sluigi
1599231437Sluigi}
1600231437Sluigi
1601231437Sluigi
1602231437Sluigi
1603231437Sluigi
1604231437Sluigi/*****************************************************************************
1605231437Sluigi *		   Helper function prototypes in this file 		     *
1606231437Sluigi *****************************************************************************/
1607231437Sluigi
1608231437Sluigistatic int
1609231437Sluigioce_attach_ifp(POCE_SOFTC sc)
1610231437Sluigi{
1611231437Sluigi
1612231437Sluigi	sc->ifp = if_alloc(IFT_ETHER);
1613231437Sluigi	if (!sc->ifp)
1614231437Sluigi		return ENOMEM;
1615231437Sluigi
1616231437Sluigi	ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
1617231437Sluigi	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
1618231437Sluigi	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
1619231437Sluigi
1620231437Sluigi	sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
1621231437Sluigi	sc->ifp->if_ioctl = oce_ioctl;
1622231437Sluigi	sc->ifp->if_start = oce_start;
1623231437Sluigi	sc->ifp->if_init = oce_init;
1624231437Sluigi	sc->ifp->if_mtu = ETHERMTU;
1625231437Sluigi	sc->ifp->if_softc = sc;
1626231437Sluigi#if __FreeBSD_version >= 800000
1627231437Sluigi	sc->ifp->if_transmit = oce_multiq_start;
1628231437Sluigi	sc->ifp->if_qflush = oce_multiq_flush;
1629231437Sluigi#endif
1630231437Sluigi
1631231437Sluigi	if_initname(sc->ifp,
1632231437Sluigi		    device_get_name(sc->dev), device_get_unit(sc->dev));
1633231437Sluigi
1634231437Sluigi	sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1;
1635231437Sluigi	IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen);
1636231437Sluigi	IFQ_SET_READY(&sc->ifp->if_snd);
1637231437Sluigi
1638231437Sluigi	sc->ifp->if_hwassist = OCE_IF_HWASSIST;
1639231437Sluigi	sc->ifp->if_hwassist |= CSUM_TSO;
1640231437Sluigi	sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP);
1641231437Sluigi
1642231437Sluigi	sc->ifp->if_capabilities = OCE_IF_CAPABILITIES;
1643231437Sluigi	sc->ifp->if_capabilities |= IFCAP_HWCSUM;
1644231437Sluigi	sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
1645231879Sluigi
1646231511Sbz#if defined(INET6) || defined(INET)
1647231511Sbz	sc->ifp->if_capabilities |= IFCAP_TSO;
1648231437Sluigi	sc->ifp->if_capabilities |= IFCAP_LRO;
1649231879Sluigi	sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
1650231511Sbz#endif
1651231437Sluigi
1652231437Sluigi	sc->ifp->if_capenable = sc->ifp->if_capabilities;
1653231509Sbz	sc->ifp->if_baudrate = IF_Gbps(10UL);
1654231437Sluigi
1655231437Sluigi	ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
1656231437Sluigi
1657231437Sluigi	return 0;
1658231437Sluigi}
1659231437Sluigi
1660231437Sluigi
1661231437Sluigistatic void
1662231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
1663231437Sluigi{
1664231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1665231437Sluigi
1666231437Sluigi	if (ifp->if_softc !=  arg)
1667231437Sluigi		return;
1668231437Sluigi	if ((vtag == 0) || (vtag > 4095))
1669231437Sluigi		return;
1670231437Sluigi
1671231437Sluigi	sc->vlan_tag[vtag] = 1;
1672231437Sluigi	sc->vlans_added++;
1673231437Sluigi	oce_vid_config(sc);
1674231437Sluigi}
1675231437Sluigi
1676231437Sluigi
1677231437Sluigistatic void
1678231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
1679231437Sluigi{
1680231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1681231437Sluigi
1682231437Sluigi	if (ifp->if_softc !=  arg)
1683231437Sluigi		return;
1684231437Sluigi	if ((vtag == 0) || (vtag > 4095))
1685231437Sluigi		return;
1686231437Sluigi
1687231437Sluigi	sc->vlan_tag[vtag] = 0;
1688231437Sluigi	sc->vlans_added--;
1689231437Sluigi	oce_vid_config(sc);
1690231437Sluigi}
1691231437Sluigi
1692231437Sluigi
1693231437Sluigi/*
1694231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures
1695231437Sluigi * more, place the card in vlan promiscuous mode.
1696231437Sluigi */
1697231437Sluigistatic int
1698231437Sluigioce_vid_config(POCE_SOFTC sc)
1699231437Sluigi{
1700231437Sluigi	struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
1701231437Sluigi	uint16_t ntags = 0, i;
1702231437Sluigi	int status = 0;
1703231437Sluigi
1704231437Sluigi	if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
1705231437Sluigi			(sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) {
1706231437Sluigi		for (i = 0; i < MAX_VLANS; i++) {
1707231437Sluigi			if (sc->vlan_tag[i]) {
1708231437Sluigi				vtags[ntags].vtag = i;
1709231437Sluigi				ntags++;
1710231437Sluigi			}
1711231437Sluigi		}
1712231437Sluigi		if (ntags)
1713231437Sluigi			status = oce_config_vlan(sc, (uint8_t) sc->if_id,
1714231437Sluigi						vtags, ntags, 1, 0);
1715231437Sluigi	} else
1716231437Sluigi		status = oce_config_vlan(sc, (uint8_t) sc->if_id,
1717231437Sluigi					 	NULL, 0, 1, 1);
1718231437Sluigi	return status;
1719231437Sluigi}
1720231437Sluigi
1721231437Sluigi
1722231437Sluigistatic void
1723231437Sluigioce_mac_addr_set(POCE_SOFTC sc)
1724231437Sluigi{
1725231437Sluigi	uint32_t old_pmac_id = sc->pmac_id;
1726231437Sluigi	int status = 0;
1727231437Sluigi
1728231437Sluigi
1729231437Sluigi	status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
1730231437Sluigi			 sc->macaddr.size_of_struct);
1731231437Sluigi	if (!status)
1732231437Sluigi		return;
1733231437Sluigi
1734231437Sluigi	status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)),
1735231437Sluigi					sc->if_id, &sc->pmac_id);
1736231437Sluigi	if (!status) {
1737231437Sluigi		status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
1738231437Sluigi		bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
1739231437Sluigi				 sc->macaddr.size_of_struct);
1740231437Sluigi	}
1741231437Sluigi	if (status)
1742231437Sluigi		device_printf(sc->dev, "Failed update macaddress\n");
1743231437Sluigi
1744231437Sluigi}
1745231437Sluigi
1746231437Sluigi
1747231437Sluigistatic int
1748231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data)
1749231437Sluigi{
1750231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1751231437Sluigi	struct ifreq *ifr = (struct ifreq *)data;
1752231437Sluigi	int rc = ENXIO;
1753231437Sluigi	char cookie[32] = {0};
1754231437Sluigi	void *priv_data = (void *)ifr->ifr_data;
1755231437Sluigi	void *ioctl_ptr;
1756231437Sluigi	uint32_t req_size;
1757231437Sluigi	struct mbx_hdr req;
1758231437Sluigi	OCE_DMA_MEM dma_mem;
1759231437Sluigi
1760231437Sluigi
1761231437Sluigi	if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
1762231437Sluigi		return EFAULT;
1763231437Sluigi
1764231437Sluigi	if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
1765231437Sluigi		return EINVAL;
1766231437Sluigi
1767231437Sluigi	ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
1768231437Sluigi	if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
1769231437Sluigi		return EFAULT;
1770231437Sluigi
1771231437Sluigi	req_size = le32toh(req.u0.req.request_length);
1772231437Sluigi	if (req_size > 65536)
1773231437Sluigi		return EINVAL;
1774231437Sluigi
1775231437Sluigi	req_size += sizeof(struct mbx_hdr);
1776231437Sluigi	rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
1777231437Sluigi	if (rc)
1778231437Sluigi		return ENOMEM;
1779231437Sluigi
1780231437Sluigi	if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
1781231437Sluigi		rc = EFAULT;
1782231437Sluigi		goto dma_free;
1783231437Sluigi	}
1784231437Sluigi
1785231437Sluigi	rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
1786231437Sluigi	if (rc) {
1787231437Sluigi		rc = EIO;
1788231437Sluigi		goto dma_free;
1789231437Sluigi	}
1790231437Sluigi
1791231437Sluigi	if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size))
1792231437Sluigi		rc =  EFAULT;
1793231437Sluigi
1794231437Sluigidma_free:
1795231437Sluigi	oce_dma_free(sc, &dma_mem);
1796231437Sluigi	return rc;
1797231437Sluigi
1798231437Sluigi}
1799231437Sluigi
1800231437Sluigi
1801231437Sluigistatic void
1802231437Sluigioce_local_timer(void *arg)
1803231437Sluigi{
1804231437Sluigi	POCE_SOFTC sc = arg;
1805231437Sluigi	int i = 0;
1806231437Sluigi
1807231437Sluigi	oce_refresh_nic_stats(sc);
1808231437Sluigi	oce_refresh_queue_stats(sc);
1809231437Sluigi	oce_mac_addr_set(sc);
1810231437Sluigi
1811231437Sluigi	/* TX Watch Dog*/
1812231437Sluigi	for (i = 0; i < sc->nwqs; i++)
1813231437Sluigi		oce_tx_restart(sc, sc->wq[i]);
1814231437Sluigi
1815231437Sluigi	callout_reset(&sc->timer, hz, oce_local_timer, sc);
1816231437Sluigi}
1817231437Sluigi
1818231437Sluigi
1819231437Sluigistatic void
1820231437Sluigioce_if_deactivate(POCE_SOFTC sc)
1821231437Sluigi{
1822231437Sluigi	int i, mtime = 0;
1823231437Sluigi	int wait_req = 0;
1824231437Sluigi	struct oce_rq *rq;
1825231437Sluigi	struct oce_wq *wq;
1826231437Sluigi	struct oce_eq *eq;
1827231437Sluigi
1828231437Sluigi	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1829231437Sluigi
1830231437Sluigi	/*Wait for max of 400ms for TX completions to be done */
1831231437Sluigi	while (mtime < 400) {
1832231437Sluigi		wait_req = 0;
1833231437Sluigi		for_all_wq_queues(sc, wq, i) {
1834231437Sluigi			if (wq->ring->num_used) {
1835231437Sluigi				wait_req = 1;
1836231437Sluigi				DELAY(1);
1837231437Sluigi				break;
1838231437Sluigi			}
1839231437Sluigi		}
1840231437Sluigi		mtime += 1;
1841231437Sluigi		if (!wait_req)
1842231437Sluigi			break;
1843231437Sluigi	}
1844231437Sluigi
1845231437Sluigi	/* Stop intrs and finish any bottom halves pending */
1846231437Sluigi	oce_hw_intr_disable(sc);
1847231437Sluigi
1848231437Sluigi	for (i = 0; i < sc->intr_count; i++) {
1849231437Sluigi		if (sc->intrs[i].tq != NULL) {
1850231437Sluigi			taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
1851231437Sluigi		}
1852231437Sluigi	}
1853231437Sluigi
1854231437Sluigi	/* Delete RX queue in card with flush param */
1855231437Sluigi	oce_stop_rx(sc);
1856231437Sluigi
1857231437Sluigi	/* Invalidate any pending cq and eq entries*/
1858231437Sluigi	for_all_evnt_queues(sc, eq, i)
1859231437Sluigi		oce_drain_eq(eq);
1860231437Sluigi	for_all_rq_queues(sc, rq, i)
1861231437Sluigi		oce_drain_rq_cq(rq);
1862231437Sluigi	for_all_wq_queues(sc, wq, i)
1863231437Sluigi		oce_drain_wq_cq(wq);
1864231437Sluigi
1865231437Sluigi	/* But still we need to get MCC aync events.
1866231437Sluigi	   So enable intrs and also arm first EQ
1867231437Sluigi        */
1868231437Sluigi	oce_hw_intr_enable(sc);
1869231437Sluigi	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
1870231437Sluigi
1871231437Sluigi	DELAY(10);
1872231437Sluigi}
1873231437Sluigi
1874231437Sluigi
1875231437Sluigistatic void
1876231437Sluigioce_if_activate(POCE_SOFTC sc)
1877231437Sluigi{
1878231437Sluigi	struct oce_eq *eq;
1879231437Sluigi	struct oce_rq *rq;
1880231437Sluigi	struct oce_wq *wq;
1881231437Sluigi	int i, rc = 0;
1882231437Sluigi
1883231437Sluigi	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
1884231437Sluigi
1885231437Sluigi	oce_hw_intr_disable(sc);
1886231437Sluigi
1887231437Sluigi	oce_start_rx(sc);
1888231437Sluigi
1889231437Sluigi	for_all_rq_queues(sc, rq, i) {
1890231437Sluigi		rc = oce_start_rq(rq);
1891231437Sluigi		if (rc)
1892231437Sluigi			device_printf(sc->dev, "Unable to start RX\n");
1893231437Sluigi	}
1894231437Sluigi
1895231437Sluigi	for_all_wq_queues(sc, wq, i) {
1896231437Sluigi		rc = oce_start_wq(wq);
1897231437Sluigi		if (rc)
1898231437Sluigi			device_printf(sc->dev, "Unable to start TX\n");
1899231437Sluigi	}
1900231437Sluigi
1901231437Sluigi
1902231437Sluigi	for_all_evnt_queues(sc, eq, i)
1903231437Sluigi		oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
1904231437Sluigi
1905231437Sluigi	oce_hw_intr_enable(sc);
1906231437Sluigi
1907231437Sluigi}
1908231437Sluigi
1909231879Sluigistatic void
1910231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
1911231879Sluigi{
1912231879Sluigi	/* Update Link status */
1913231879Sluigi	if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
1914231879Sluigi	     ASYNC_EVENT_LINK_UP) {
1915231879Sluigi		sc->link_status = ASYNC_EVENT_LINK_UP;
1916231879Sluigi		if_link_state_change(sc->ifp, LINK_STATE_UP);
1917231879Sluigi	} else {
1918231879Sluigi		sc->link_status = ASYNC_EVENT_LINK_DOWN;
1919231879Sluigi		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
1920231879Sluigi	}
1921231879Sluigi
1922231879Sluigi	/* Update speed */
1923231879Sluigi	sc->link_speed = acqe->u0.s.speed;
1924231879Sluigi	sc->qos_link_speed = (uint32_t) acqe->u0.s.qos_link_speed * 10;
1925231879Sluigi
1926231879Sluigi}
1927231879Sluigi
1928231879Sluigi
1929231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */
1930231437Sluigiuint16_t
1931231437Sluigioce_mq_handler(void *arg)
1932231437Sluigi{
1933231437Sluigi	struct oce_mq *mq = (struct oce_mq *)arg;
1934231437Sluigi	POCE_SOFTC sc = mq->parent;
1935231437Sluigi	struct oce_cq *cq = mq->cq;
1936231879Sluigi	int num_cqes = 0, evt_type = 0, optype = 0;
1937231437Sluigi	struct oce_mq_cqe *cqe;
1938231437Sluigi	struct oce_async_cqe_link_state *acqe;
1939231879Sluigi	struct oce_async_event_grp5_pvid_state *gcqe;
1940231437Sluigi
1941231879Sluigi
1942231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
1943231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1944231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
1945231879Sluigi
1946231437Sluigi	while (cqe->u0.dw[3]) {
1947231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
1948231437Sluigi		if (cqe->u0.s.async_event) {
1949231879Sluigi			evt_type = cqe->u0.s.event_type;
1950231879Sluigi			optype = cqe->u0.s.async_type;
1951231879Sluigi			if (evt_type  == ASYNC_EVENT_CODE_LINK_STATE) {
1952231879Sluigi				/* Link status evt */
1953231879Sluigi				acqe = (struct oce_async_cqe_link_state *)cqe;
1954231879Sluigi				process_link_state(sc, acqe);
1955231879Sluigi			} else if ((evt_type == ASYNC_EVENT_GRP5) &&
1956231879Sluigi				   (optype == ASYNC_EVENT_PVID_STATE)) {
1957231879Sluigi				/* GRP5 PVID */
1958231879Sluigi				gcqe =
1959231879Sluigi				(struct oce_async_event_grp5_pvid_state *)cqe;
1960231879Sluigi				if (gcqe->enabled)
1961231879Sluigi					sc->pvid = gcqe->tag & VLAN_VID_MASK;
1962231879Sluigi				else
1963231879Sluigi					sc->pvid = 0;
1964231879Sluigi
1965231437Sluigi			}
1966231437Sluigi		}
1967231437Sluigi		cqe->u0.dw[3] = 0;
1968231437Sluigi		RING_GET(cq->ring, 1);
1969231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
1970231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1971231437Sluigi		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
1972231437Sluigi		num_cqes++;
1973231437Sluigi	}
1974231437Sluigi
1975231437Sluigi	if (num_cqes)
1976231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1977231437Sluigi
1978231437Sluigi	return 0;
1979231437Sluigi}
1980231437Sluigi
1981231437Sluigi
1982231437Sluigistatic void
1983231437Sluigisetup_max_queues_want(POCE_SOFTC sc)
1984231437Sluigi{
1985231437Sluigi	int max_rss = 0;
1986231437Sluigi
1987231437Sluigi	/* Check if it is FLEX machine. Is so dont use RSS */
1988231437Sluigi	if ((sc->function_mode & FNM_FLEX10_MODE) ||
1989231879Sluigi	    (sc->function_mode & FNM_UMC_MODE)    ||
1990231879Sluigi	    (sc->function_mode & FNM_VNIC_MODE)	  ||
1991231879Sluigi	    (!sc->rss_enable)			  ||
1992231879Sluigi	    (sc->flags & OCE_FLAGS_BE2)) {
1993231437Sluigi		sc->nrqs = 1;
1994231437Sluigi		sc->nwqs = 1;
1995231437Sluigi		sc->rss_enable = 0;
1996231437Sluigi	} else {
1997231437Sluigi		/* For multiq, our deisgn is to have TX rings equal to
1998231437Sluigi		   RSS rings. So that we can pair up one RSS ring and TX
1999231437Sluigi		   to a single intr, which improves CPU cache efficiency.
2000231437Sluigi		 */
2001231437Sluigi		if (IS_BE(sc) && (!sc->be3_native))
2002231437Sluigi			max_rss = OCE_LEGACY_MODE_RSS;
2003231437Sluigi		else
2004231437Sluigi			max_rss = OCE_MAX_RSS;
2005231437Sluigi
2006231437Sluigi		sc->nrqs = MIN(OCE_NCPUS, max_rss) + 1; /* 1 for def RX */
2007231437Sluigi		sc->nwqs = MIN(OCE_NCPUS, max_rss);
2008231437Sluigi	}
2009231437Sluigi
2010231437Sluigi}
2011231437Sluigi
2012231437Sluigi
2013231437Sluigistatic void
2014231437Sluigiupdate_queues_got(POCE_SOFTC sc)
2015231437Sluigi{
2016231437Sluigi	if (sc->rss_enable) {
2017231437Sluigi		sc->nrqs = sc->intr_count + 1;
2018231437Sluigi		sc->nwqs = sc->intr_count;
2019231437Sluigi	} else {
2020231437Sluigi		sc->nrqs = 1;
2021231437Sluigi		sc->nwqs = 1;
2022231437Sluigi	}
2023231437Sluigi}
2024231437Sluigi
2025