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$ */
40231437Sluigi
41231511Sbz#include "opt_inet6.h"
42231511Sbz#include "opt_inet.h"
43231511Sbz
44231437Sluigi#include "oce_if.h"
45231437Sluigi
46257187Sdelphij/* UE Status Low CSR */
47257187Sdelphijstatic char *ue_status_low_desc[] = {
48257187Sdelphij	"CEV",
49257187Sdelphij	"CTX",
50257187Sdelphij	"DBUF",
51257187Sdelphij	"ERX",
52257187Sdelphij	"Host",
53257187Sdelphij	"MPU",
54257187Sdelphij	"NDMA",
55257187Sdelphij	"PTC ",
56257187Sdelphij	"RDMA ",
57257187Sdelphij	"RXF ",
58257187Sdelphij	"RXIPS ",
59257187Sdelphij	"RXULP0 ",
60257187Sdelphij	"RXULP1 ",
61257187Sdelphij	"RXULP2 ",
62257187Sdelphij	"TIM ",
63257187Sdelphij	"TPOST ",
64257187Sdelphij	"TPRE ",
65257187Sdelphij	"TXIPS ",
66257187Sdelphij	"TXULP0 ",
67257187Sdelphij	"TXULP1 ",
68257187Sdelphij	"UC ",
69257187Sdelphij	"WDMA ",
70257187Sdelphij	"TXULP2 ",
71257187Sdelphij	"HOST1 ",
72257187Sdelphij	"P0_OB_LINK ",
73257187Sdelphij	"P1_OB_LINK ",
74257187Sdelphij	"HOST_GPIO ",
75257187Sdelphij	"MBOX ",
76257187Sdelphij	"AXGMAC0",
77257187Sdelphij	"AXGMAC1",
78257187Sdelphij	"JTAG",
79257187Sdelphij	"MPU_INTPEND"
80257187Sdelphij};
81231437Sluigi
82257187Sdelphij/* UE Status High CSR */
83257187Sdelphijstatic char *ue_status_hi_desc[] = {
84257187Sdelphij	"LPCMEMHOST",
85257187Sdelphij	"MGMT_MAC",
86257187Sdelphij	"PCS0ONLINE",
87257187Sdelphij	"MPU_IRAM",
88257187Sdelphij	"PCS1ONLINE",
89257187Sdelphij	"PCTL0",
90257187Sdelphij	"PCTL1",
91257187Sdelphij	"PMEM",
92257187Sdelphij	"RR",
93257187Sdelphij	"TXPB",
94257187Sdelphij	"RXPP",
95257187Sdelphij	"XAUI",
96257187Sdelphij	"TXP",
97257187Sdelphij	"ARM",
98257187Sdelphij	"IPC",
99257187Sdelphij	"HOST2",
100257187Sdelphij	"HOST3",
101257187Sdelphij	"HOST4",
102257187Sdelphij	"HOST5",
103257187Sdelphij	"HOST6",
104257187Sdelphij	"HOST7",
105257187Sdelphij	"HOST8",
106257187Sdelphij	"HOST9",
107257187Sdelphij	"NETC",
108257187Sdelphij	"Unknown",
109257187Sdelphij	"Unknown",
110257187Sdelphij	"Unknown",
111257187Sdelphij	"Unknown",
112257187Sdelphij	"Unknown",
113257187Sdelphij	"Unknown",
114257187Sdelphij	"Unknown",
115257187Sdelphij	"Unknown"
116257187Sdelphij};
117257187Sdelphij
118257187Sdelphij
119231437Sluigi/* Driver entry points prototypes */
120231437Sluigistatic int  oce_probe(device_t dev);
121231437Sluigistatic int  oce_attach(device_t dev);
122231437Sluigistatic int  oce_detach(device_t dev);
123231437Sluigistatic int  oce_shutdown(device_t dev);
124231437Sluigistatic int  oce_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
125231437Sluigistatic void oce_init(void *xsc);
126231437Sluigistatic int  oce_multiq_start(struct ifnet *ifp, struct mbuf *m);
127231437Sluigistatic void oce_multiq_flush(struct ifnet *ifp);
128231437Sluigi
129231437Sluigi/* Driver interrupt routines protypes */
130231437Sluigistatic void oce_intr(void *arg, int pending);
131231437Sluigistatic int  oce_setup_intr(POCE_SOFTC sc);
132231437Sluigistatic int  oce_fast_isr(void *arg);
133231437Sluigistatic int  oce_alloc_intr(POCE_SOFTC sc, int vector,
134231437Sluigi			  void (*isr) (void *arg, int pending));
135231437Sluigi
136231437Sluigi/* Media callbacks prototypes */
137231437Sluigistatic void oce_media_status(struct ifnet *ifp, struct ifmediareq *req);
138231437Sluigistatic int  oce_media_change(struct ifnet *ifp);
139231437Sluigi
140231437Sluigi/* Transmit routines prototypes */
141231437Sluigistatic int  oce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index);
142231437Sluigistatic void oce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq);
143231437Sluigistatic void oce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx,
144231437Sluigi					uint32_t status);
145231437Sluigistatic int  oce_multiq_transmit(struct ifnet *ifp, struct mbuf *m,
146231437Sluigi				 struct oce_wq *wq);
147231437Sluigi
148231437Sluigi/* Receive routines prototypes */
149231437Sluigistatic void oce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe);
150231437Sluigistatic int  oce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
151231437Sluigistatic int  oce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe);
152231437Sluigistatic void oce_rx(struct oce_rq *rq, uint32_t rqe_idx,
153231437Sluigi						struct oce_nic_rx_cqe *cqe);
154231437Sluigi
155231437Sluigi/* Helper function prototypes in this file */
156231437Sluigistatic int  oce_attach_ifp(POCE_SOFTC sc);
157231437Sluigistatic void oce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag);
158231437Sluigistatic void oce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag);
159231437Sluigistatic int  oce_vid_config(POCE_SOFTC sc);
160231437Sluigistatic void oce_mac_addr_set(POCE_SOFTC sc);
161231437Sluigistatic int  oce_handle_passthrough(struct ifnet *ifp, caddr_t data);
162231437Sluigistatic void oce_local_timer(void *arg);
163231437Sluigistatic void oce_if_deactivate(POCE_SOFTC sc);
164231437Sluigistatic void oce_if_activate(POCE_SOFTC sc);
165231437Sluigistatic void setup_max_queues_want(POCE_SOFTC sc);
166231437Sluigistatic void update_queues_got(POCE_SOFTC sc);
167231879Sluigistatic void process_link_state(POCE_SOFTC sc,
168231879Sluigi		 struct oce_async_cqe_link_state *acqe);
169247880Sdelphijstatic int oce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m);
170252869Sdelphijstatic void oce_get_config(POCE_SOFTC sc);
171247880Sdelphijstatic struct mbuf *oce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete);
172231437Sluigi
173231879Sluigi/* IP specific */
174231879Sluigi#if defined(INET6) || defined(INET)
175231879Sluigistatic int  oce_init_lro(POCE_SOFTC sc);
176231879Sluigistatic void oce_rx_flush_lro(struct oce_rq *rq);
177231879Sluigistatic struct mbuf * oce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp);
178231879Sluigi#endif
179231879Sluigi
180231437Sluigistatic device_method_t oce_dispatch[] = {
181231437Sluigi	DEVMETHOD(device_probe, oce_probe),
182231437Sluigi	DEVMETHOD(device_attach, oce_attach),
183231437Sluigi	DEVMETHOD(device_detach, oce_detach),
184231437Sluigi	DEVMETHOD(device_shutdown, oce_shutdown),
185246128Ssbz
186246128Ssbz	DEVMETHOD_END
187231437Sluigi};
188231437Sluigi
189231437Sluigistatic driver_t oce_driver = {
190231437Sluigi	"oce",
191231437Sluigi	oce_dispatch,
192231437Sluigi	sizeof(OCE_SOFTC)
193231437Sluigi};
194231437Sluigistatic devclass_t oce_devclass;
195231437Sluigi
196231437Sluigi
197231437SluigiDRIVER_MODULE(oce, pci, oce_driver, oce_devclass, 0, 0);
198231437SluigiMODULE_DEPEND(oce, pci, 1, 1, 1);
199231437SluigiMODULE_DEPEND(oce, ether, 1, 1, 1);
200231437SluigiMODULE_VERSION(oce, 1);
201231437Sluigi
202231437Sluigi
203231437Sluigi/* global vars */
204231437Sluigiconst char component_revision[32] = {"///" COMPONENT_REVISION "///"};
205231437Sluigi
206231437Sluigi/* Module capabilites and parameters */
207231437Sluigiuint32_t oce_max_rsp_handled = OCE_MAX_RSP_HANDLED;
208231437Sluigiuint32_t oce_enable_rss = OCE_MODCAP_RSS;
209231437Sluigi
210231437Sluigi
211231437SluigiTUNABLE_INT("hw.oce.max_rsp_handled", &oce_max_rsp_handled);
212231437SluigiTUNABLE_INT("hw.oce.enable_rss", &oce_enable_rss);
213231437Sluigi
214231437Sluigi
215231437Sluigi/* Supported devices table */
216231437Sluigistatic uint32_t supportedDevices[] =  {
217231437Sluigi	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE2,
218231437Sluigi	(PCI_VENDOR_SERVERENGINES << 16) | PCI_PRODUCT_BE3,
219231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_BE3,
220231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201,
221231437Sluigi	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_XE201_VF,
222252869Sdelphij	(PCI_VENDOR_EMULEX << 16) | PCI_PRODUCT_SH
223231437Sluigi};
224231437Sluigi
225231437Sluigi
226231437Sluigi
227231437Sluigi
228231437Sluigi/*****************************************************************************
229231437Sluigi *			Driver entry points functions                        *
230231437Sluigi *****************************************************************************/
231231437Sluigi
232231437Sluigistatic int
233231437Sluigioce_probe(device_t dev)
234231437Sluigi{
235231879Sluigi	uint16_t vendor = 0;
236231879Sluigi	uint16_t device = 0;
237231879Sluigi	int i = 0;
238231879Sluigi	char str[256] = {0};
239231437Sluigi	POCE_SOFTC sc;
240231437Sluigi
241231437Sluigi	sc = device_get_softc(dev);
242231437Sluigi	bzero(sc, sizeof(OCE_SOFTC));
243231437Sluigi	sc->dev = dev;
244231437Sluigi
245231437Sluigi	vendor = pci_get_vendor(dev);
246231437Sluigi	device = pci_get_device(dev);
247231437Sluigi
248231879Sluigi	for (i = 0; i < (sizeof(supportedDevices) / sizeof(uint32_t)); i++) {
249231437Sluigi		if (vendor == ((supportedDevices[i] >> 16) & 0xffff)) {
250231437Sluigi			if (device == (supportedDevices[i] & 0xffff)) {
251231879Sluigi				sprintf(str, "%s:%s", "Emulex CNA NIC function",
252231437Sluigi					component_revision);
253231437Sluigi				device_set_desc_copy(dev, str);
254231437Sluigi
255231437Sluigi				switch (device) {
256231437Sluigi				case PCI_PRODUCT_BE2:
257231437Sluigi					sc->flags |= OCE_FLAGS_BE2;
258231437Sluigi					break;
259231437Sluigi				case PCI_PRODUCT_BE3:
260231437Sluigi					sc->flags |= OCE_FLAGS_BE3;
261231437Sluigi					break;
262231437Sluigi				case PCI_PRODUCT_XE201:
263231437Sluigi				case PCI_PRODUCT_XE201_VF:
264231437Sluigi					sc->flags |= OCE_FLAGS_XE201;
265231437Sluigi					break;
266252869Sdelphij				case PCI_PRODUCT_SH:
267252869Sdelphij					sc->flags |= OCE_FLAGS_SH;
268252869Sdelphij					break;
269231437Sluigi				default:
270231437Sluigi					return ENXIO;
271231437Sluigi				}
272231437Sluigi				return BUS_PROBE_DEFAULT;
273231437Sluigi			}
274231437Sluigi		}
275231437Sluigi	}
276231437Sluigi
277231437Sluigi	return ENXIO;
278231437Sluigi}
279231437Sluigi
280231437Sluigi
281231437Sluigistatic int
282231437Sluigioce_attach(device_t dev)
283231437Sluigi{
284231437Sluigi	POCE_SOFTC sc;
285231437Sluigi	int rc = 0;
286231437Sluigi
287231437Sluigi	sc = device_get_softc(dev);
288231437Sluigi
289231437Sluigi	rc = oce_hw_pci_alloc(sc);
290231437Sluigi	if (rc)
291231437Sluigi		return rc;
292231437Sluigi
293231437Sluigi	sc->tx_ring_size = OCE_TX_RING_SIZE;
294231437Sluigi	sc->rx_ring_size = OCE_RX_RING_SIZE;
295231437Sluigi	sc->rq_frag_size = OCE_RQ_BUF_SIZE;
296231437Sluigi	sc->flow_control = OCE_DEFAULT_FLOW_CONTROL;
297231437Sluigi	sc->promisc	 = OCE_DEFAULT_PROMISCUOUS;
298231437Sluigi
299231437Sluigi	LOCK_CREATE(&sc->bmbx_lock, "Mailbox_lock");
300231437Sluigi	LOCK_CREATE(&sc->dev_lock,  "Device_lock");
301231437Sluigi
302231437Sluigi	/* initialise the hardware */
303231437Sluigi	rc = oce_hw_init(sc);
304231437Sluigi	if (rc)
305231437Sluigi		goto pci_res_free;
306231437Sluigi
307252869Sdelphij	oce_get_config(sc);
308252869Sdelphij
309231437Sluigi	setup_max_queues_want(sc);
310231437Sluigi
311231437Sluigi	rc = oce_setup_intr(sc);
312231437Sluigi	if (rc)
313231437Sluigi		goto mbox_free;
314231437Sluigi
315231437Sluigi	rc = oce_queue_init_all(sc);
316231437Sluigi	if (rc)
317231437Sluigi		goto intr_free;
318231437Sluigi
319231437Sluigi	rc = oce_attach_ifp(sc);
320231437Sluigi	if (rc)
321231437Sluigi		goto queues_free;
322231437Sluigi
323231511Sbz#if defined(INET6) || defined(INET)
324231437Sluigi	rc = oce_init_lro(sc);
325231437Sluigi	if (rc)
326231879Sluigi		goto ifp_free;
327231511Sbz#endif
328231437Sluigi
329231437Sluigi	rc = oce_hw_start(sc);
330231437Sluigi	if (rc)
331241844Seadler		goto lro_free;
332231437Sluigi
333231437Sluigi	sc->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
334231437Sluigi				oce_add_vlan, sc, EVENTHANDLER_PRI_FIRST);
335231437Sluigi	sc->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
336231437Sluigi				oce_del_vlan, sc, EVENTHANDLER_PRI_FIRST);
337231437Sluigi
338231437Sluigi	rc = oce_stats_init(sc);
339231437Sluigi	if (rc)
340231437Sluigi		goto vlan_free;
341231437Sluigi
342231437Sluigi	oce_add_sysctls(sc);
343231437Sluigi
344231437Sluigi	callout_init(&sc->timer, CALLOUT_MPSAFE);
345231437Sluigi	rc = callout_reset(&sc->timer, 2 * hz, oce_local_timer, sc);
346231437Sluigi	if (rc)
347231437Sluigi		goto stats_free;
348231437Sluigi
349231437Sluigi	return 0;
350231437Sluigi
351231437Sluigistats_free:
352231437Sluigi	callout_drain(&sc->timer);
353231437Sluigi	oce_stats_free(sc);
354231437Sluigivlan_free:
355231437Sluigi	if (sc->vlan_attach)
356231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
357231437Sluigi	if (sc->vlan_detach)
358231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
359231437Sluigi	oce_hw_intr_disable(sc);
360231437Sluigilro_free:
361231511Sbz#if defined(INET6) || defined(INET)
362231437Sluigi	oce_free_lro(sc);
363231437Sluigiifp_free:
364231511Sbz#endif
365231437Sluigi	ether_ifdetach(sc->ifp);
366231437Sluigi	if_free(sc->ifp);
367231437Sluigiqueues_free:
368231437Sluigi	oce_queue_release_all(sc);
369231437Sluigiintr_free:
370231437Sluigi	oce_intr_free(sc);
371231437Sluigimbox_free:
372231437Sluigi	oce_dma_free(sc, &sc->bsmbx);
373231437Sluigipci_res_free:
374231437Sluigi	oce_hw_pci_free(sc);
375231437Sluigi	LOCK_DESTROY(&sc->dev_lock);
376231437Sluigi	LOCK_DESTROY(&sc->bmbx_lock);
377231437Sluigi	return rc;
378231437Sluigi
379231437Sluigi}
380231437Sluigi
381231437Sluigi
382231437Sluigistatic int
383231437Sluigioce_detach(device_t dev)
384231437Sluigi{
385231437Sluigi	POCE_SOFTC sc = device_get_softc(dev);
386231437Sluigi
387231437Sluigi	LOCK(&sc->dev_lock);
388231437Sluigi	oce_if_deactivate(sc);
389231437Sluigi	UNLOCK(&sc->dev_lock);
390231437Sluigi
391231437Sluigi	callout_drain(&sc->timer);
392231437Sluigi
393231437Sluigi	if (sc->vlan_attach != NULL)
394231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach);
395231437Sluigi	if (sc->vlan_detach != NULL)
396231437Sluigi		EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach);
397231437Sluigi
398231437Sluigi	ether_ifdetach(sc->ifp);
399231437Sluigi
400231437Sluigi	if_free(sc->ifp);
401231437Sluigi
402231437Sluigi	oce_hw_shutdown(sc);
403231437Sluigi
404231437Sluigi	bus_generic_detach(dev);
405231437Sluigi
406231437Sluigi	return 0;
407231437Sluigi}
408231437Sluigi
409231437Sluigi
410231437Sluigistatic int
411231437Sluigioce_shutdown(device_t dev)
412231437Sluigi{
413231437Sluigi	int rc;
414231437Sluigi
415231437Sluigi	rc = oce_detach(dev);
416231437Sluigi
417231437Sluigi	return rc;
418231437Sluigi}
419231437Sluigi
420231437Sluigi
421231437Sluigistatic int
422231437Sluigioce_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
423231437Sluigi{
424231437Sluigi	struct ifreq *ifr = (struct ifreq *)data;
425231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
426231437Sluigi	int rc = 0;
427231437Sluigi	uint32_t u;
428231437Sluigi
429231437Sluigi	switch (command) {
430231437Sluigi
431231437Sluigi	case SIOCGIFMEDIA:
432231437Sluigi		rc = ifmedia_ioctl(ifp, ifr, &sc->media, command);
433231437Sluigi		break;
434231437Sluigi
435231437Sluigi	case SIOCSIFMTU:
436231437Sluigi		if (ifr->ifr_mtu > OCE_MAX_MTU)
437231437Sluigi			rc = EINVAL;
438231437Sluigi		else
439231437Sluigi			ifp->if_mtu = ifr->ifr_mtu;
440231437Sluigi		break;
441231437Sluigi
442231437Sluigi	case SIOCSIFFLAGS:
443231437Sluigi		if (ifp->if_flags & IFF_UP) {
444231437Sluigi			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
445231437Sluigi				sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
446231437Sluigi				oce_init(sc);
447231437Sluigi			}
448231437Sluigi			device_printf(sc->dev, "Interface Up\n");
449231437Sluigi		} else {
450231437Sluigi			LOCK(&sc->dev_lock);
451231437Sluigi
452231437Sluigi			sc->ifp->if_drv_flags &=
453231437Sluigi			    ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
454231437Sluigi			oce_if_deactivate(sc);
455231437Sluigi
456231437Sluigi			UNLOCK(&sc->dev_lock);
457231437Sluigi
458231437Sluigi			device_printf(sc->dev, "Interface Down\n");
459231437Sluigi		}
460231437Sluigi
461231437Sluigi		if ((ifp->if_flags & IFF_PROMISC) && !sc->promisc) {
462257187Sdelphij			if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1))))
463257187Sdelphij				sc->promisc = TRUE;
464231437Sluigi		} else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) {
465257187Sdelphij			if (!oce_rxf_set_promiscuous(sc, 0))
466257187Sdelphij				sc->promisc = FALSE;
467231437Sluigi		}
468231437Sluigi
469231437Sluigi		break;
470231437Sluigi
471231437Sluigi	case SIOCADDMULTI:
472231437Sluigi	case SIOCDELMULTI:
473231437Sluigi		rc = oce_hw_update_multicast(sc);
474231437Sluigi		if (rc)
475231437Sluigi			device_printf(sc->dev,
476231437Sluigi				"Update multicast address failed\n");
477231437Sluigi		break;
478231437Sluigi
479231437Sluigi	case SIOCSIFCAP:
480231437Sluigi		u = ifr->ifr_reqcap ^ ifp->if_capenable;
481231437Sluigi
482231437Sluigi		if (u & IFCAP_TXCSUM) {
483231437Sluigi			ifp->if_capenable ^= IFCAP_TXCSUM;
484231437Sluigi			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
485231437Sluigi
486231437Sluigi			if (IFCAP_TSO & ifp->if_capenable &&
487231437Sluigi			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
488231437Sluigi				ifp->if_capenable &= ~IFCAP_TSO;
489231437Sluigi				ifp->if_hwassist &= ~CSUM_TSO;
490231437Sluigi				if_printf(ifp,
491231437Sluigi					 "TSO disabled due to -txcsum.\n");
492231437Sluigi			}
493231437Sluigi		}
494231437Sluigi
495231437Sluigi		if (u & IFCAP_RXCSUM)
496231437Sluigi			ifp->if_capenable ^= IFCAP_RXCSUM;
497231437Sluigi
498231437Sluigi		if (u & IFCAP_TSO4) {
499231437Sluigi			ifp->if_capenable ^= IFCAP_TSO4;
500231437Sluigi
501231437Sluigi			if (IFCAP_TSO & ifp->if_capenable) {
502231437Sluigi				if (IFCAP_TXCSUM & ifp->if_capenable)
503231437Sluigi					ifp->if_hwassist |= CSUM_TSO;
504231437Sluigi				else {
505231437Sluigi					ifp->if_capenable &= ~IFCAP_TSO;
506231437Sluigi					ifp->if_hwassist &= ~CSUM_TSO;
507231437Sluigi					if_printf(ifp,
508231437Sluigi					    "Enable txcsum first.\n");
509231437Sluigi					rc = EAGAIN;
510231437Sluigi				}
511231437Sluigi			} else
512231437Sluigi				ifp->if_hwassist &= ~CSUM_TSO;
513231437Sluigi		}
514231437Sluigi
515231437Sluigi		if (u & IFCAP_VLAN_HWTAGGING)
516231437Sluigi			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
517231437Sluigi
518231437Sluigi		if (u & IFCAP_VLAN_HWFILTER) {
519231437Sluigi			ifp->if_capenable ^= IFCAP_VLAN_HWFILTER;
520231437Sluigi			oce_vid_config(sc);
521231437Sluigi		}
522231511Sbz#if defined(INET6) || defined(INET)
523231437Sluigi		if (u & IFCAP_LRO)
524231437Sluigi			ifp->if_capenable ^= IFCAP_LRO;
525231511Sbz#endif
526231437Sluigi
527231437Sluigi		break;
528231437Sluigi
529231437Sluigi	case SIOCGPRIVATE_0:
530231437Sluigi		rc = oce_handle_passthrough(ifp, data);
531231437Sluigi		break;
532231437Sluigi	default:
533231437Sluigi		rc = ether_ioctl(ifp, command, data);
534231437Sluigi		break;
535231437Sluigi	}
536231437Sluigi
537231437Sluigi	return rc;
538231437Sluigi}
539231437Sluigi
540231437Sluigi
541231437Sluigistatic void
542231437Sluigioce_init(void *arg)
543231437Sluigi{
544231437Sluigi	POCE_SOFTC sc = arg;
545231437Sluigi
546231437Sluigi	LOCK(&sc->dev_lock);
547231437Sluigi
548231437Sluigi	if (sc->ifp->if_flags & IFF_UP) {
549231437Sluigi		oce_if_deactivate(sc);
550231437Sluigi		oce_if_activate(sc);
551231437Sluigi	}
552231437Sluigi
553231437Sluigi	UNLOCK(&sc->dev_lock);
554231437Sluigi
555231437Sluigi}
556231437Sluigi
557231437Sluigi
558231437Sluigistatic int
559231437Sluigioce_multiq_start(struct ifnet *ifp, struct mbuf *m)
560231437Sluigi{
561231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
562231437Sluigi	struct oce_wq *wq = NULL;
563231437Sluigi	int queue_index = 0;
564231437Sluigi	int status = 0;
565247880Sdelphij
566252869Sdelphij	if (!sc->link_status)
567252869Sdelphij		return ENXIO;
568252869Sdelphij
569231437Sluigi	if ((m->m_flags & M_FLOWID) != 0)
570231437Sluigi		queue_index = m->m_pkthdr.flowid % sc->nwqs;
571252869Sdelphij
572231437Sluigi	wq = sc->wq[queue_index];
573231437Sluigi
574252869Sdelphij	LOCK(&wq->tx_lock);
575252869Sdelphij	status = oce_multiq_transmit(ifp, m, wq);
576252869Sdelphij	UNLOCK(&wq->tx_lock);
577252869Sdelphij
578231437Sluigi	return status;
579231437Sluigi
580231437Sluigi}
581231437Sluigi
582231437Sluigi
583231437Sluigistatic void
584231437Sluigioce_multiq_flush(struct ifnet *ifp)
585231437Sluigi{
586231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
587231437Sluigi	struct mbuf     *m;
588231437Sluigi	int i = 0;
589231437Sluigi
590231437Sluigi	for (i = 0; i < sc->nwqs; i++) {
591231437Sluigi		while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
592231437Sluigi			m_freem(m);
593231437Sluigi	}
594231437Sluigi	if_qflush(ifp);
595231437Sluigi}
596231437Sluigi
597231437Sluigi
598231437Sluigi
599231437Sluigi/*****************************************************************************
600231437Sluigi *                   Driver interrupt routines functions                     *
601231437Sluigi *****************************************************************************/
602231437Sluigi
603231437Sluigistatic void
604231437Sluigioce_intr(void *arg, int pending)
605231437Sluigi{
606231437Sluigi
607231437Sluigi	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
608231437Sluigi	POCE_SOFTC sc = ii->sc;
609231437Sluigi	struct oce_eq *eq = ii->eq;
610231437Sluigi	struct oce_eqe *eqe;
611231437Sluigi	struct oce_cq *cq = NULL;
612231437Sluigi	int i, num_eqes = 0;
613231437Sluigi
614231437Sluigi
615231437Sluigi	bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
616231437Sluigi				 BUS_DMASYNC_POSTWRITE);
617231437Sluigi	do {
618231437Sluigi		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
619231437Sluigi		if (eqe->evnt == 0)
620231437Sluigi			break;
621231437Sluigi		eqe->evnt = 0;
622231437Sluigi		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
623231437Sluigi					BUS_DMASYNC_POSTWRITE);
624231437Sluigi		RING_GET(eq->ring, 1);
625231437Sluigi		num_eqes++;
626231437Sluigi
627231437Sluigi	} while (TRUE);
628231437Sluigi
629231437Sluigi	if (!num_eqes)
630231437Sluigi		goto eq_arm; /* Spurious */
631231437Sluigi
632231437Sluigi 	/* Clear EQ entries, but dont arm */
633231437Sluigi	oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
634231437Sluigi
635231437Sluigi	/* Process TX, RX and MCC. But dont arm CQ*/
636231437Sluigi	for (i = 0; i < eq->cq_valid; i++) {
637231437Sluigi		cq = eq->cq[i];
638231437Sluigi		(*cq->cq_handler)(cq->cb_arg);
639231437Sluigi	}
640231437Sluigi
641231437Sluigi	/* Arm all cqs connected to this EQ */
642231437Sluigi	for (i = 0; i < eq->cq_valid; i++) {
643231437Sluigi		cq = eq->cq[i];
644231437Sluigi		oce_arm_cq(sc, cq->cq_id, 0, TRUE);
645231437Sluigi	}
646231437Sluigi
647231437Sluigieq_arm:
648231437Sluigi	oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
649247880Sdelphij
650231437Sluigi	return;
651231437Sluigi}
652231437Sluigi
653231437Sluigi
654231437Sluigistatic int
655231437Sluigioce_setup_intr(POCE_SOFTC sc)
656231437Sluigi{
657231437Sluigi	int rc = 0, use_intx = 0;
658231437Sluigi	int vector = 0, req_vectors = 0;
659231437Sluigi
660252869Sdelphij	if (is_rss_enabled(sc))
661231437Sluigi		req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
662231437Sluigi	else
663231437Sluigi		req_vectors = 1;
664231437Sluigi
665231437Sluigi	if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
666231437Sluigi		sc->intr_count = req_vectors;
667231437Sluigi		rc = pci_alloc_msix(sc->dev, &sc->intr_count);
668231437Sluigi		if (rc != 0) {
669231437Sluigi			use_intx = 1;
670231437Sluigi			pci_release_msi(sc->dev);
671231437Sluigi		} else
672231437Sluigi			sc->flags |= OCE_FLAGS_USING_MSIX;
673231437Sluigi	} else
674231437Sluigi		use_intx = 1;
675231437Sluigi
676231437Sluigi	if (use_intx)
677231437Sluigi		sc->intr_count = 1;
678231437Sluigi
679231437Sluigi	/* Scale number of queues based on intr we got */
680231437Sluigi	update_queues_got(sc);
681231437Sluigi
682231437Sluigi	if (use_intx) {
683231437Sluigi		device_printf(sc->dev, "Using legacy interrupt\n");
684231437Sluigi		rc = oce_alloc_intr(sc, vector, oce_intr);
685231437Sluigi		if (rc)
686231437Sluigi			goto error;
687231437Sluigi	} else {
688231437Sluigi		for (; vector < sc->intr_count; vector++) {
689231437Sluigi			rc = oce_alloc_intr(sc, vector, oce_intr);
690231437Sluigi			if (rc)
691231437Sluigi				goto error;
692231437Sluigi		}
693231437Sluigi	}
694231437Sluigi
695231437Sluigi	return 0;
696231437Sluigierror:
697231437Sluigi	oce_intr_free(sc);
698231437Sluigi	return rc;
699231437Sluigi}
700231437Sluigi
701231437Sluigi
702231437Sluigistatic int
703231437Sluigioce_fast_isr(void *arg)
704231437Sluigi{
705231437Sluigi	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
706231437Sluigi	POCE_SOFTC sc = ii->sc;
707231437Sluigi
708231437Sluigi	if (ii->eq == NULL)
709231437Sluigi		return FILTER_STRAY;
710231437Sluigi
711231437Sluigi	oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
712231437Sluigi
713231437Sluigi	taskqueue_enqueue_fast(ii->tq, &ii->task);
714231437Sluigi
715247880Sdelphij 	ii->eq->intr++;
716247880Sdelphij
717231437Sluigi	return FILTER_HANDLED;
718231437Sluigi}
719231437Sluigi
720231437Sluigi
721231437Sluigistatic int
722231437Sluigioce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
723231437Sluigi{
724231437Sluigi	POCE_INTR_INFO ii = &sc->intrs[vector];
725231437Sluigi	int rc = 0, rr;
726231437Sluigi
727231437Sluigi	if (vector >= OCE_MAX_EQ)
728231437Sluigi		return (EINVAL);
729231437Sluigi
730231437Sluigi	/* Set the resource id for the interrupt.
731231437Sluigi	 * MSIx is vector + 1 for the resource id,
732231437Sluigi	 * INTx is 0 for the resource id.
733231437Sluigi	 */
734231437Sluigi	if (sc->flags & OCE_FLAGS_USING_MSIX)
735231437Sluigi		rr = vector + 1;
736231437Sluigi	else
737231437Sluigi		rr = 0;
738231437Sluigi	ii->intr_res = bus_alloc_resource_any(sc->dev,
739231437Sluigi					      SYS_RES_IRQ,
740231437Sluigi					      &rr, RF_ACTIVE|RF_SHAREABLE);
741231437Sluigi	ii->irq_rr = rr;
742231437Sluigi	if (ii->intr_res == NULL) {
743231437Sluigi		device_printf(sc->dev,
744231437Sluigi			  "Could not allocate interrupt\n");
745231437Sluigi		rc = ENXIO;
746231437Sluigi		return rc;
747231437Sluigi	}
748231437Sluigi
749231437Sluigi	TASK_INIT(&ii->task, 0, isr, ii);
750231437Sluigi	ii->vector = vector;
751231437Sluigi	sprintf(ii->task_name, "oce_task[%d]", ii->vector);
752231437Sluigi	ii->tq = taskqueue_create_fast(ii->task_name,
753231437Sluigi			M_NOWAIT,
754231437Sluigi			taskqueue_thread_enqueue,
755231437Sluigi			&ii->tq);
756231437Sluigi	taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
757231437Sluigi			device_get_nameunit(sc->dev));
758231437Sluigi
759231437Sluigi	ii->sc = sc;
760231437Sluigi	rc = bus_setup_intr(sc->dev,
761231437Sluigi			ii->intr_res,
762231437Sluigi			INTR_TYPE_NET,
763231437Sluigi			oce_fast_isr, NULL, ii, &ii->tag);
764231437Sluigi	return rc;
765231437Sluigi
766231437Sluigi}
767231437Sluigi
768231437Sluigi
769231437Sluigivoid
770231437Sluigioce_intr_free(POCE_SOFTC sc)
771231437Sluigi{
772231437Sluigi	int i = 0;
773231437Sluigi
774231437Sluigi	for (i = 0; i < sc->intr_count; i++) {
775231437Sluigi
776231437Sluigi		if (sc->intrs[i].tag != NULL)
777231437Sluigi			bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
778231437Sluigi						sc->intrs[i].tag);
779231437Sluigi		if (sc->intrs[i].tq != NULL)
780231437Sluigi			taskqueue_free(sc->intrs[i].tq);
781231437Sluigi
782231437Sluigi		if (sc->intrs[i].intr_res != NULL)
783231437Sluigi			bus_release_resource(sc->dev, SYS_RES_IRQ,
784231437Sluigi						sc->intrs[i].irq_rr,
785231437Sluigi						sc->intrs[i].intr_res);
786231437Sluigi		sc->intrs[i].tag = NULL;
787231437Sluigi		sc->intrs[i].intr_res = NULL;
788231437Sluigi	}
789231437Sluigi
790231437Sluigi	if (sc->flags & OCE_FLAGS_USING_MSIX)
791231437Sluigi		pci_release_msi(sc->dev);
792231437Sluigi
793231437Sluigi}
794231437Sluigi
795231437Sluigi
796231437Sluigi
797231437Sluigi/******************************************************************************
798231437Sluigi*			  Media callbacks functions 			      *
799231437Sluigi******************************************************************************/
800231437Sluigi
801231437Sluigistatic void
802231437Sluigioce_media_status(struct ifnet *ifp, struct ifmediareq *req)
803231437Sluigi{
804231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc;
805231437Sluigi
806231437Sluigi
807231437Sluigi	req->ifm_status = IFM_AVALID;
808231437Sluigi	req->ifm_active = IFM_ETHER;
809231437Sluigi
810231437Sluigi	if (sc->link_status == 1)
811231437Sluigi		req->ifm_status |= IFM_ACTIVE;
812231437Sluigi	else
813231437Sluigi		return;
814231437Sluigi
815231437Sluigi	switch (sc->link_speed) {
816231437Sluigi	case 1: /* 10 Mbps */
817231437Sluigi		req->ifm_active |= IFM_10_T | IFM_FDX;
818231437Sluigi		sc->speed = 10;
819231437Sluigi		break;
820231437Sluigi	case 2: /* 100 Mbps */
821231437Sluigi		req->ifm_active |= IFM_100_TX | IFM_FDX;
822231437Sluigi		sc->speed = 100;
823231437Sluigi		break;
824231437Sluigi	case 3: /* 1 Gbps */
825231437Sluigi		req->ifm_active |= IFM_1000_T | IFM_FDX;
826231437Sluigi		sc->speed = 1000;
827231437Sluigi		break;
828231437Sluigi	case 4: /* 10 Gbps */
829231437Sluigi		req->ifm_active |= IFM_10G_SR | IFM_FDX;
830231437Sluigi		sc->speed = 10000;
831231437Sluigi		break;
832259050Sdelphij	case 7: /* 40 Gbps */
833259050Sdelphij		req->ifm_active |= IFM_40G_SR4 | IFM_FDX;
834259050Sdelphij		sc->speed = 40000;
835259050Sdelphij		break;
836231437Sluigi	}
837231437Sluigi
838231437Sluigi	return;
839231437Sluigi}
840231437Sluigi
841231437Sluigi
842231437Sluigiint
843231437Sluigioce_media_change(struct ifnet *ifp)
844231437Sluigi{
845231437Sluigi	return 0;
846231437Sluigi}
847231437Sluigi
848231437Sluigi
849231437Sluigi
850231437Sluigi
851231437Sluigi/*****************************************************************************
852231437Sluigi *			  Transmit routines functions			     *
853231437Sluigi *****************************************************************************/
854231437Sluigi
855231437Sluigistatic int
856231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
857231437Sluigi{
858231437Sluigi	int rc = 0, i, retry_cnt = 0;
859231437Sluigi	bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
860231437Sluigi	struct mbuf *m, *m_temp;
861231437Sluigi	struct oce_wq *wq = sc->wq[wq_index];
862231437Sluigi	struct oce_packet_desc *pd;
863231437Sluigi	struct oce_nic_hdr_wqe *nichdr;
864231437Sluigi	struct oce_nic_frag_wqe *nicfrag;
865231437Sluigi	int num_wqes;
866231437Sluigi	uint32_t reg_value;
867247880Sdelphij	boolean_t complete = TRUE;
868231437Sluigi
869231437Sluigi	m = *mpp;
870231437Sluigi	if (!m)
871231437Sluigi		return EINVAL;
872231437Sluigi
873231437Sluigi	if (!(m->m_flags & M_PKTHDR)) {
874231437Sluigi		rc = ENXIO;
875231437Sluigi		goto free_ret;
876231437Sluigi	}
877231437Sluigi
878247880Sdelphij	if(oce_tx_asic_stall_verify(sc, m)) {
879247880Sdelphij		m = oce_insert_vlan_tag(sc, m, &complete);
880247880Sdelphij		if(!m) {
881247880Sdelphij			device_printf(sc->dev, "Insertion unsuccessful\n");
882247880Sdelphij			return 0;
883247880Sdelphij		}
884247880Sdelphij
885247880Sdelphij	}
886247880Sdelphij
887231437Sluigi	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
888231879Sluigi		/* consolidate packet buffers for TSO/LSO segment offload */
889231511Sbz#if defined(INET6) || defined(INET)
890231879Sluigi		m = oce_tso_setup(sc, mpp);
891231511Sbz#else
892231511Sbz		m = NULL;
893231511Sbz#endif
894231437Sluigi		if (m == NULL) {
895231437Sluigi			rc = ENXIO;
896231437Sluigi			goto free_ret;
897231437Sluigi		}
898231437Sluigi	}
899231437Sluigi
900252869Sdelphij	pd = &wq->pckts[wq->pkt_desc_head];
901231437Sluigiretry:
902231437Sluigi	rc = bus_dmamap_load_mbuf_sg(wq->tag,
903231437Sluigi				     pd->map,
904231437Sluigi				     m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
905231437Sluigi	if (rc == 0) {
906231437Sluigi		num_wqes = pd->nsegs + 1;
907252869Sdelphij		if (IS_BE(sc) || IS_SH(sc)) {
908231437Sluigi			/*Dummy required only for BE3.*/
909231437Sluigi			if (num_wqes & 1)
910231437Sluigi				num_wqes++;
911231437Sluigi		}
912231437Sluigi		if (num_wqes >= RING_NUM_FREE(wq->ring)) {
913231437Sluigi			bus_dmamap_unload(wq->tag, pd->map);
914231437Sluigi			return EBUSY;
915231437Sluigi		}
916252869Sdelphij		atomic_store_rel_int(&wq->pkt_desc_head,
917252869Sdelphij				     (wq->pkt_desc_head + 1) % \
918252869Sdelphij				      OCE_WQ_PACKET_ARRAY_SIZE);
919231437Sluigi		bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
920231437Sluigi		pd->mbuf = m;
921231437Sluigi
922231437Sluigi		nichdr =
923231437Sluigi		    RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
924231437Sluigi		nichdr->u0.dw[0] = 0;
925231437Sluigi		nichdr->u0.dw[1] = 0;
926231437Sluigi		nichdr->u0.dw[2] = 0;
927231437Sluigi		nichdr->u0.dw[3] = 0;
928231437Sluigi
929247880Sdelphij		nichdr->u0.s.complete = complete;
930231437Sluigi		nichdr->u0.s.event = 1;
931231437Sluigi		nichdr->u0.s.crc = 1;
932231437Sluigi		nichdr->u0.s.forward = 0;
933231437Sluigi		nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
934231437Sluigi		nichdr->u0.s.udpcs =
935247880Sdelphij			(m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
936231437Sluigi		nichdr->u0.s.tcpcs =
937247880Sdelphij			(m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
938231437Sluigi		nichdr->u0.s.num_wqe = num_wqes;
939231437Sluigi		nichdr->u0.s.total_length = m->m_pkthdr.len;
940257187Sdelphij
941231437Sluigi		if (m->m_flags & M_VLANTAG) {
942231437Sluigi			nichdr->u0.s.vlan = 1; /*Vlan present*/
943231437Sluigi			nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
944231437Sluigi		}
945257187Sdelphij
946231437Sluigi		if (m->m_pkthdr.csum_flags & CSUM_TSO) {
947231437Sluigi			if (m->m_pkthdr.tso_segsz) {
948231437Sluigi				nichdr->u0.s.lso = 1;
949231437Sluigi				nichdr->u0.s.lso_mss  = m->m_pkthdr.tso_segsz;
950231437Sluigi			}
951252869Sdelphij			if (!IS_BE(sc) || !IS_SH(sc))
952231437Sluigi				nichdr->u0.s.ipcs = 1;
953231437Sluigi		}
954231437Sluigi
955231437Sluigi		RING_PUT(wq->ring, 1);
956252869Sdelphij		atomic_add_int(&wq->ring->num_used, 1);
957231437Sluigi
958231437Sluigi		for (i = 0; i < pd->nsegs; i++) {
959231437Sluigi			nicfrag =
960231437Sluigi			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
961231437Sluigi						      struct oce_nic_frag_wqe);
962231437Sluigi			nicfrag->u0.s.rsvd0 = 0;
963231437Sluigi			nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
964231437Sluigi			nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
965231437Sluigi			nicfrag->u0.s.frag_len = segs[i].ds_len;
966231437Sluigi			pd->wqe_idx = wq->ring->pidx;
967231437Sluigi			RING_PUT(wq->ring, 1);
968252869Sdelphij			atomic_add_int(&wq->ring->num_used, 1);
969231437Sluigi		}
970231437Sluigi		if (num_wqes > (pd->nsegs + 1)) {
971231437Sluigi			nicfrag =
972231437Sluigi			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
973231437Sluigi						      struct oce_nic_frag_wqe);
974231437Sluigi			nicfrag->u0.dw[0] = 0;
975231437Sluigi			nicfrag->u0.dw[1] = 0;
976231437Sluigi			nicfrag->u0.dw[2] = 0;
977231437Sluigi			nicfrag->u0.dw[3] = 0;
978231437Sluigi			pd->wqe_idx = wq->ring->pidx;
979231437Sluigi			RING_PUT(wq->ring, 1);
980252869Sdelphij			atomic_add_int(&wq->ring->num_used, 1);
981231437Sluigi			pd->nsegs++;
982231437Sluigi		}
983231437Sluigi
984231437Sluigi		sc->ifp->if_opackets++;
985231437Sluigi		wq->tx_stats.tx_reqs++;
986231437Sluigi		wq->tx_stats.tx_wrbs += num_wqes;
987231437Sluigi		wq->tx_stats.tx_bytes += m->m_pkthdr.len;
988231437Sluigi		wq->tx_stats.tx_pkts++;
989247880Sdelphij
990231437Sluigi		bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
991231437Sluigi				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
992231437Sluigi		reg_value = (num_wqes << 16) | wq->wq_id;
993252869Sdelphij		OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value);
994231437Sluigi
995231437Sluigi	} else if (rc == EFBIG)	{
996231437Sluigi		if (retry_cnt == 0) {
997243857Sglebius			m_temp = m_defrag(m, M_NOWAIT);
998231437Sluigi			if (m_temp == NULL)
999231437Sluigi				goto free_ret;
1000231437Sluigi			m = m_temp;
1001231437Sluigi			*mpp = m_temp;
1002231437Sluigi			retry_cnt = retry_cnt + 1;
1003231437Sluigi			goto retry;
1004231437Sluigi		} else
1005231437Sluigi			goto free_ret;
1006231437Sluigi	} else if (rc == ENOMEM)
1007231437Sluigi		return rc;
1008231437Sluigi	else
1009231437Sluigi		goto free_ret;
1010252869Sdelphij
1011231437Sluigi	return 0;
1012231437Sluigi
1013231437Sluigifree_ret:
1014231437Sluigi	m_freem(*mpp);
1015231437Sluigi	*mpp = NULL;
1016231437Sluigi	return rc;
1017231437Sluigi}
1018231437Sluigi
1019231437Sluigi
1020231437Sluigistatic void
1021231437Sluigioce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status)
1022231437Sluigi{
1023231437Sluigi	struct oce_packet_desc *pd;
1024231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
1025231437Sluigi	struct mbuf *m;
1026231437Sluigi
1027252869Sdelphij	pd = &wq->pckts[wq->pkt_desc_tail];
1028252869Sdelphij	atomic_store_rel_int(&wq->pkt_desc_tail,
1029252869Sdelphij			     (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE);
1030252869Sdelphij	atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1);
1031231437Sluigi	bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1032231437Sluigi	bus_dmamap_unload(wq->tag, pd->map);
1033231437Sluigi
1034231437Sluigi	m = pd->mbuf;
1035231437Sluigi	m_freem(m);
1036231437Sluigi	pd->mbuf = NULL;
1037231437Sluigi
1038252869Sdelphij
1039231437Sluigi	if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1040231437Sluigi		if (wq->ring->num_used < (wq->ring->num_items / 2)) {
1041231437Sluigi			sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
1042231437Sluigi			oce_tx_restart(sc, wq);
1043231437Sluigi		}
1044231437Sluigi	}
1045231437Sluigi}
1046231437Sluigi
1047231437Sluigi
1048231437Sluigistatic void
1049231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
1050231437Sluigi{
1051231437Sluigi
1052231437Sluigi	if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
1053231437Sluigi		return;
1054231437Sluigi
1055231437Sluigi#if __FreeBSD_version >= 800000
1056231437Sluigi	if (!drbr_empty(sc->ifp, wq->br))
1057231437Sluigi#else
1058231437Sluigi	if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd))
1059231437Sluigi#endif
1060231437Sluigi		taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask);
1061231437Sluigi
1062231437Sluigi}
1063231437Sluigi
1064231879Sluigi
1065231511Sbz#if defined(INET6) || defined(INET)
1066231437Sluigistatic struct mbuf *
1067231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
1068231437Sluigi{
1069231437Sluigi	struct mbuf *m;
1070231511Sbz#ifdef INET
1071231437Sluigi	struct ip *ip;
1072231511Sbz#endif
1073231511Sbz#ifdef INET6
1074231437Sluigi	struct ip6_hdr *ip6;
1075231511Sbz#endif
1076231437Sluigi	struct ether_vlan_header *eh;
1077231437Sluigi	struct tcphdr *th;
1078231437Sluigi	uint16_t etype;
1079231879Sluigi	int total_len = 0, ehdrlen = 0;
1080231437Sluigi
1081231437Sluigi	m = *mpp;
1082231437Sluigi
1083231437Sluigi	if (M_WRITABLE(m) == 0) {
1084243857Sglebius		m = m_dup(*mpp, M_NOWAIT);
1085231437Sluigi		if (!m)
1086231437Sluigi			return NULL;
1087231437Sluigi		m_freem(*mpp);
1088231437Sluigi		*mpp = m;
1089231437Sluigi	}
1090231437Sluigi
1091231437Sluigi	eh = mtod(m, struct ether_vlan_header *);
1092231437Sluigi	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
1093231437Sluigi		etype = ntohs(eh->evl_proto);
1094231437Sluigi		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1095231437Sluigi	} else {
1096231437Sluigi		etype = ntohs(eh->evl_encap_proto);
1097231437Sluigi		ehdrlen = ETHER_HDR_LEN;
1098231437Sluigi	}
1099231437Sluigi
1100231437Sluigi	switch (etype) {
1101231511Sbz#ifdef INET
1102231437Sluigi	case ETHERTYPE_IP:
1103231437Sluigi		ip = (struct ip *)(m->m_data + ehdrlen);
1104231437Sluigi		if (ip->ip_p != IPPROTO_TCP)
1105231437Sluigi			return NULL;
1106231437Sluigi		th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
1107231437Sluigi
1108231437Sluigi		total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
1109231437Sluigi		break;
1110231511Sbz#endif
1111231511Sbz#ifdef INET6
1112231437Sluigi	case ETHERTYPE_IPV6:
1113231437Sluigi		ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
1114231437Sluigi		if (ip6->ip6_nxt != IPPROTO_TCP)
1115231437Sluigi			return NULL;
1116231437Sluigi		th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
1117231437Sluigi
1118231437Sluigi		total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
1119231437Sluigi		break;
1120231511Sbz#endif
1121231437Sluigi	default:
1122231437Sluigi		return NULL;
1123231437Sluigi	}
1124231437Sluigi
1125231437Sluigi	m = m_pullup(m, total_len);
1126231437Sluigi	if (!m)
1127231437Sluigi		return NULL;
1128231437Sluigi	*mpp = m;
1129231437Sluigi	return m;
1130231437Sluigi
1131231437Sluigi}
1132231511Sbz#endif /* INET6 || INET */
1133231437Sluigi
1134231437Sluigivoid
1135231437Sluigioce_tx_task(void *arg, int npending)
1136231437Sluigi{
1137231437Sluigi	struct oce_wq *wq = arg;
1138231437Sluigi	POCE_SOFTC sc = wq->parent;
1139231437Sluigi	struct ifnet *ifp = sc->ifp;
1140231437Sluigi	int rc = 0;
1141252869Sdelphij
1142231437Sluigi#if __FreeBSD_version >= 800000
1143252869Sdelphij	LOCK(&wq->tx_lock);
1144252869Sdelphij	rc = oce_multiq_transmit(ifp, NULL, wq);
1145252869Sdelphij	if (rc) {
1146252869Sdelphij		device_printf(sc->dev,
1147252869Sdelphij				"TX[%d] restart failed\n", wq->queue_index);
1148231437Sluigi	}
1149252869Sdelphij	UNLOCK(&wq->tx_lock);
1150231437Sluigi#else
1151231437Sluigi	oce_start(ifp);
1152231437Sluigi#endif
1153231437Sluigi
1154231437Sluigi}
1155231437Sluigi
1156231437Sluigi
1157231437Sluigivoid
1158231437Sluigioce_start(struct ifnet *ifp)
1159231437Sluigi{
1160231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1161231437Sluigi	struct mbuf *m;
1162231437Sluigi	int rc = 0;
1163231879Sluigi	int def_q = 0; /* Defualt tx queue is 0*/
1164231437Sluigi
1165231437Sluigi	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1166231437Sluigi			IFF_DRV_RUNNING)
1167231437Sluigi		return;
1168247880Sdelphij
1169247880Sdelphij	if (!sc->link_status)
1170247880Sdelphij		return;
1171231437Sluigi
1172231437Sluigi	do {
1173231437Sluigi		IF_DEQUEUE(&sc->ifp->if_snd, m);
1174231437Sluigi		if (m == NULL)
1175231437Sluigi			break;
1176231879Sluigi
1177231879Sluigi		LOCK(&sc->wq[def_q]->tx_lock);
1178231879Sluigi		rc = oce_tx(sc, &m, def_q);
1179231879Sluigi		UNLOCK(&sc->wq[def_q]->tx_lock);
1180231437Sluigi		if (rc) {
1181231437Sluigi			if (m != NULL) {
1182231879Sluigi				sc->wq[def_q]->tx_stats.tx_stops ++;
1183231437Sluigi				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1184231437Sluigi				IFQ_DRV_PREPEND(&ifp->if_snd, m);
1185231437Sluigi				m = NULL;
1186231437Sluigi			}
1187231437Sluigi			break;
1188231437Sluigi		}
1189231437Sluigi		if (m != NULL)
1190231437Sluigi			ETHER_BPF_MTAP(ifp, m);
1191231437Sluigi
1192231879Sluigi	} while (TRUE);
1193231437Sluigi
1194231437Sluigi	return;
1195231437Sluigi}
1196231437Sluigi
1197231437Sluigi
1198231437Sluigi/* Handle the Completion Queue for transmit */
1199231437Sluigiuint16_t
1200231437Sluigioce_wq_handler(void *arg)
1201231437Sluigi{
1202231437Sluigi	struct oce_wq *wq = (struct oce_wq *)arg;
1203231437Sluigi	POCE_SOFTC sc = wq->parent;
1204231437Sluigi	struct oce_cq *cq = wq->cq;
1205231437Sluigi	struct oce_nic_tx_cqe *cqe;
1206231437Sluigi	int num_cqes = 0;
1207231437Sluigi
1208231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
1209231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1210231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1211231437Sluigi	while (cqe->u0.dw[3]) {
1212231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
1213231437Sluigi
1214231437Sluigi		wq->ring->cidx = cqe->u0.s.wqe_index + 1;
1215231437Sluigi		if (wq->ring->cidx >= wq->ring->num_items)
1216231437Sluigi			wq->ring->cidx -= wq->ring->num_items;
1217231437Sluigi
1218231437Sluigi		oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status);
1219231437Sluigi		wq->tx_stats.tx_compl++;
1220231437Sluigi		cqe->u0.dw[3] = 0;
1221231437Sluigi		RING_GET(cq->ring, 1);
1222231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
1223231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1224231437Sluigi		cqe =
1225231437Sluigi		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1226231437Sluigi		num_cqes++;
1227231437Sluigi	}
1228231437Sluigi
1229231437Sluigi	if (num_cqes)
1230231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1231231437Sluigi
1232231437Sluigi	return 0;
1233231437Sluigi}
1234231437Sluigi
1235231437Sluigi
1236257187Sdelphij#if __FreeBSD_version >= 1000000
1237257187Sdelphijstatic __inline void
1238257187Sdelphijdrbr_stats_update(struct ifnet *ifp, int len, int mflags)
1239257187Sdelphij{
1240257187Sdelphij#ifndef NO_SLOW_STATS
1241257187Sdelphij	ifp->if_obytes += len;
1242257187Sdelphij	if (mflags & M_MCAST)
1243257187Sdelphij		ifp->if_omcasts++;
1244257187Sdelphij#endif
1245257187Sdelphij}
1246257187Sdelphij#endif
1247257187Sdelphij
1248231437Sluigistatic int
1249231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq)
1250231437Sluigi{
1251231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1252231437Sluigi	int status = 0, queue_index = 0;
1253231437Sluigi	struct mbuf *next = NULL;
1254231437Sluigi	struct buf_ring *br = NULL;
1255231437Sluigi
1256231437Sluigi	br  = wq->br;
1257231437Sluigi	queue_index = wq->queue_index;
1258231437Sluigi
1259231437Sluigi	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1260231437Sluigi		IFF_DRV_RUNNING) {
1261231437Sluigi		if (m != NULL)
1262231437Sluigi			status = drbr_enqueue(ifp, br, m);
1263231437Sluigi		return status;
1264231437Sluigi	}
1265231437Sluigi
1266257187Sdelphij	if (m != NULL) {
1267231437Sluigi		if ((status = drbr_enqueue(ifp, br, m)) != 0)
1268231437Sluigi			return status;
1269246482Srrs	}
1270246482Srrs	while ((next = drbr_peek(ifp, br)) != NULL) {
1271231437Sluigi		if (oce_tx(sc, &next, queue_index)) {
1272246482Srrs			if (next == NULL) {
1273246482Srrs				drbr_advance(ifp, br);
1274246482Srrs			} else {
1275246482Srrs				drbr_putback(ifp, br, next);
1276231437Sluigi				wq->tx_stats.tx_stops ++;
1277231437Sluigi				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1278231437Sluigi				status = drbr_enqueue(ifp, br, next);
1279231437Sluigi			}
1280231437Sluigi			break;
1281231437Sluigi		}
1282246482Srrs		drbr_advance(ifp, br);
1283241037Sglebius		ifp->if_obytes += next->m_pkthdr.len;
1284241037Sglebius		if (next->m_flags & M_MCAST)
1285241037Sglebius			ifp->if_omcasts++;
1286231437Sluigi		ETHER_BPF_MTAP(ifp, next);
1287231437Sluigi	}
1288231437Sluigi
1289231437Sluigi	return status;
1290231437Sluigi}
1291231437Sluigi
1292231437Sluigi
1293231437Sluigi
1294231437Sluigi
1295231437Sluigi/*****************************************************************************
1296231437Sluigi *			    Receive  routines functions 		     *
1297231437Sluigi *****************************************************************************/
1298231437Sluigi
1299231437Sluigistatic void
1300231437Sluigioce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe)
1301231437Sluigi{
1302231437Sluigi	uint32_t out;
1303231437Sluigi	struct oce_packet_desc *pd;
1304231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1305231437Sluigi	int i, len, frag_len;
1306231437Sluigi	struct mbuf *m = NULL, *tail = NULL;
1307231437Sluigi	uint16_t vtag;
1308231437Sluigi
1309231437Sluigi	len = cqe->u0.s.pkt_size;
1310231437Sluigi	if (!len) {
1311231437Sluigi		/*partial DMA workaround for Lancer*/
1312231437Sluigi		oce_discard_rx_comp(rq, cqe);
1313231437Sluigi		goto exit;
1314231437Sluigi	}
1315231437Sluigi
1316231879Sluigi	 /* Get vlan_tag value */
1317252869Sdelphij	if(IS_BE(sc) || IS_SH(sc))
1318231879Sluigi		vtag = BSWAP_16(cqe->u0.s.vlan_tag);
1319231879Sluigi	else
1320231879Sluigi		vtag = cqe->u0.s.vlan_tag;
1321231879Sluigi
1322231879Sluigi
1323231437Sluigi	for (i = 0; i < cqe->u0.s.num_fragments; i++) {
1324231437Sluigi
1325231437Sluigi		if (rq->packets_out == rq->packets_in) {
1326231437Sluigi			device_printf(sc->dev,
1327231437Sluigi				  "RQ transmit descriptor missing\n");
1328231437Sluigi		}
1329231437Sluigi		out = rq->packets_out + 1;
1330231437Sluigi		if (out == OCE_RQ_PACKET_ARRAY_SIZE)
1331231437Sluigi			out = 0;
1332231437Sluigi		pd = &rq->pckts[rq->packets_out];
1333231437Sluigi		rq->packets_out = out;
1334231437Sluigi
1335231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1336231437Sluigi		bus_dmamap_unload(rq->tag, pd->map);
1337231437Sluigi		rq->pending--;
1338231437Sluigi
1339231437Sluigi		frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
1340231437Sluigi		pd->mbuf->m_len = frag_len;
1341231437Sluigi
1342231437Sluigi		if (tail != NULL) {
1343231437Sluigi			/* additional fragments */
1344231437Sluigi			pd->mbuf->m_flags &= ~M_PKTHDR;
1345231437Sluigi			tail->m_next = pd->mbuf;
1346231437Sluigi			tail = pd->mbuf;
1347231437Sluigi		} else {
1348231437Sluigi			/* first fragment, fill out much of the packet header */
1349231437Sluigi			pd->mbuf->m_pkthdr.len = len;
1350231437Sluigi			pd->mbuf->m_pkthdr.csum_flags = 0;
1351231437Sluigi			if (IF_CSUM_ENABLED(sc)) {
1352231437Sluigi				if (cqe->u0.s.l4_cksum_pass) {
1353231437Sluigi					pd->mbuf->m_pkthdr.csum_flags |=
1354231437Sluigi					    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1355231437Sluigi					pd->mbuf->m_pkthdr.csum_data = 0xffff;
1356231437Sluigi				}
1357231437Sluigi				if (cqe->u0.s.ip_cksum_pass) {
1358231879Sluigi					if (!cqe->u0.s.ip_ver) { /* IPV4 */
1359231437Sluigi						pd->mbuf->m_pkthdr.csum_flags |=
1360231437Sluigi						(CSUM_IP_CHECKED|CSUM_IP_VALID);
1361231437Sluigi					}
1362231437Sluigi				}
1363231437Sluigi			}
1364231437Sluigi			m = tail = pd->mbuf;
1365231437Sluigi		}
1366231437Sluigi		pd->mbuf = NULL;
1367231437Sluigi		len -= frag_len;
1368231437Sluigi	}
1369231437Sluigi
1370231437Sluigi	if (m) {
1371231437Sluigi		if (!oce_cqe_portid_valid(sc, cqe)) {
1372231437Sluigi			 m_freem(m);
1373231437Sluigi			 goto exit;
1374231437Sluigi		}
1375231437Sluigi
1376231437Sluigi		m->m_pkthdr.rcvif = sc->ifp;
1377231437Sluigi#if __FreeBSD_version >= 800000
1378252869Sdelphij		if (rq->queue_index)
1379252869Sdelphij			m->m_pkthdr.flowid = (rq->queue_index - 1);
1380252869Sdelphij		else
1381252869Sdelphij			m->m_pkthdr.flowid = rq->queue_index;
1382231437Sluigi		m->m_flags |= M_FLOWID;
1383231437Sluigi#endif
1384231879Sluigi		/* This deternies if vlan tag is Valid */
1385231437Sluigi		if (oce_cqe_vtp_valid(sc, cqe)) {
1386231437Sluigi			if (sc->function_mode & FNM_FLEX10_MODE) {
1387231879Sluigi				/* FLEX10. If QnQ is not set, neglect VLAN */
1388231437Sluigi				if (cqe->u0.s.qnq) {
1389231879Sluigi					m->m_pkthdr.ether_vtag = vtag;
1390231437Sluigi					m->m_flags |= M_VLANTAG;
1391231437Sluigi				}
1392231879Sluigi			} else if (sc->pvid != (vtag & VLAN_VID_MASK))  {
1393231879Sluigi				/* In UMC mode generally pvid will be striped by
1394231879Sluigi				   hw. But in some cases we have seen it comes
1395231879Sluigi				   with pvid. So if pvid == vlan, neglect vlan.
1396231879Sluigi				*/
1397231879Sluigi				m->m_pkthdr.ether_vtag = vtag;
1398231437Sluigi				m->m_flags |= M_VLANTAG;
1399231437Sluigi			}
1400231437Sluigi		}
1401231437Sluigi
1402231437Sluigi		sc->ifp->if_ipackets++;
1403231511Sbz#if defined(INET6) || defined(INET)
1404231437Sluigi		/* Try to queue to LRO */
1405231437Sluigi		if (IF_LRO_ENABLED(sc) &&
1406231437Sluigi		    (cqe->u0.s.ip_cksum_pass) &&
1407231437Sluigi		    (cqe->u0.s.l4_cksum_pass) &&
1408231437Sluigi		    (!cqe->u0.s.ip_ver)       &&
1409231437Sluigi		    (rq->lro.lro_cnt != 0)) {
1410231437Sluigi
1411231437Sluigi			if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
1412231437Sluigi				rq->lro_pkts_queued ++;
1413231437Sluigi				goto post_done;
1414231437Sluigi			}
1415231437Sluigi			/* If LRO posting fails then try to post to STACK */
1416231437Sluigi		}
1417231511Sbz#endif
1418231437Sluigi
1419231437Sluigi		(*sc->ifp->if_input) (sc->ifp, m);
1420231511Sbz#if defined(INET6) || defined(INET)
1421231437Sluigipost_done:
1422231511Sbz#endif
1423231437Sluigi		/* Update rx stats per queue */
1424231437Sluigi		rq->rx_stats.rx_pkts++;
1425231437Sluigi		rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
1426231437Sluigi		rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
1427231437Sluigi		if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
1428231437Sluigi			rq->rx_stats.rx_mcast_pkts++;
1429231437Sluigi		if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
1430231437Sluigi			rq->rx_stats.rx_ucast_pkts++;
1431231437Sluigi	}
1432231437Sluigiexit:
1433231437Sluigi	return;
1434231437Sluigi}
1435231437Sluigi
1436231437Sluigi
1437231437Sluigistatic void
1438231437Sluigioce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
1439231437Sluigi{
1440231437Sluigi	uint32_t out, i = 0;
1441231437Sluigi	struct oce_packet_desc *pd;
1442231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1443231437Sluigi	int num_frags = cqe->u0.s.num_fragments;
1444231437Sluigi
1445231437Sluigi	for (i = 0; i < num_frags; i++) {
1446231437Sluigi		if (rq->packets_out == rq->packets_in) {
1447231437Sluigi			device_printf(sc->dev,
1448231437Sluigi				"RQ transmit descriptor missing\n");
1449231437Sluigi		}
1450231437Sluigi		out = rq->packets_out + 1;
1451231437Sluigi		if (out == OCE_RQ_PACKET_ARRAY_SIZE)
1452231437Sluigi			out = 0;
1453231437Sluigi		pd = &rq->pckts[rq->packets_out];
1454231437Sluigi		rq->packets_out = out;
1455231437Sluigi
1456231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1457231437Sluigi		bus_dmamap_unload(rq->tag, pd->map);
1458231437Sluigi		rq->pending--;
1459231437Sluigi		m_freem(pd->mbuf);
1460231437Sluigi	}
1461231437Sluigi
1462231437Sluigi}
1463231437Sluigi
1464231437Sluigi
1465231437Sluigistatic int
1466231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
1467231437Sluigi{
1468231437Sluigi	struct oce_nic_rx_cqe_v1 *cqe_v1;
1469231437Sluigi	int vtp = 0;
1470231437Sluigi
1471231437Sluigi	if (sc->be3_native) {
1472231437Sluigi		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1473231437Sluigi		vtp =  cqe_v1->u0.s.vlan_tag_present;
1474231879Sluigi	} else
1475231437Sluigi		vtp = cqe->u0.s.vlan_tag_present;
1476231437Sluigi
1477231437Sluigi	return vtp;
1478231437Sluigi
1479231437Sluigi}
1480231437Sluigi
1481231437Sluigi
1482231437Sluigistatic int
1483231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
1484231437Sluigi{
1485231437Sluigi	struct oce_nic_rx_cqe_v1 *cqe_v1;
1486231437Sluigi	int port_id = 0;
1487231437Sluigi
1488252869Sdelphij	if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) {
1489231437Sluigi		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1490231437Sluigi		port_id =  cqe_v1->u0.s.port;
1491231437Sluigi		if (sc->port_id != port_id)
1492231437Sluigi			return 0;
1493231437Sluigi	} else
1494231437Sluigi		;/* For BE3 legacy and Lancer this is dummy */
1495231437Sluigi
1496231437Sluigi	return 1;
1497231437Sluigi
1498231437Sluigi}
1499231437Sluigi
1500231511Sbz#if defined(INET6) || defined(INET)
1501231437Sluigistatic void
1502231437Sluigioce_rx_flush_lro(struct oce_rq *rq)
1503231437Sluigi{
1504231437Sluigi	struct lro_ctrl	*lro = &rq->lro;
1505231437Sluigi	struct lro_entry *queued;
1506231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1507231437Sluigi
1508231437Sluigi	if (!IF_LRO_ENABLED(sc))
1509231437Sluigi		return;
1510231437Sluigi
1511231437Sluigi	while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
1512231437Sluigi		SLIST_REMOVE_HEAD(&lro->lro_active, next);
1513231437Sluigi		tcp_lro_flush(lro, queued);
1514231437Sluigi	}
1515231437Sluigi	rq->lro_pkts_queued = 0;
1516231437Sluigi
1517231437Sluigi	return;
1518231437Sluigi}
1519231437Sluigi
1520231437Sluigi
1521231437Sluigistatic int
1522231437Sluigioce_init_lro(POCE_SOFTC sc)
1523231437Sluigi{
1524231437Sluigi	struct lro_ctrl *lro = NULL;
1525231437Sluigi	int i = 0, rc = 0;
1526231437Sluigi
1527231437Sluigi	for (i = 0; i < sc->nrqs; i++) {
1528231437Sluigi		lro = &sc->rq[i]->lro;
1529231437Sluigi		rc = tcp_lro_init(lro);
1530231437Sluigi		if (rc != 0) {
1531231437Sluigi			device_printf(sc->dev, "LRO init failed\n");
1532231437Sluigi			return rc;
1533231437Sluigi		}
1534231437Sluigi		lro->ifp = sc->ifp;
1535231437Sluigi	}
1536231437Sluigi
1537231437Sluigi	return rc;
1538231437Sluigi}
1539231437Sluigi
1540231879Sluigi
1541231437Sluigivoid
1542231437Sluigioce_free_lro(POCE_SOFTC sc)
1543231437Sluigi{
1544231437Sluigi	struct lro_ctrl *lro = NULL;
1545231437Sluigi	int i = 0;
1546231437Sluigi
1547231437Sluigi	for (i = 0; i < sc->nrqs; i++) {
1548231437Sluigi		lro = &sc->rq[i]->lro;
1549231437Sluigi		if (lro)
1550231437Sluigi			tcp_lro_free(lro);
1551231437Sluigi	}
1552231437Sluigi}
1553247880Sdelphij#endif
1554231437Sluigi
1555231437Sluigiint
1556231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count)
1557231437Sluigi{
1558231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1559231437Sluigi	int i, in, rc;
1560231437Sluigi	struct oce_packet_desc *pd;
1561231437Sluigi	bus_dma_segment_t segs[6];
1562231437Sluigi	int nsegs, added = 0;
1563231437Sluigi	struct oce_nic_rqe *rqe;
1564231437Sluigi	pd_rxulp_db_t rxdb_reg;
1565231437Sluigi
1566247880Sdelphij	bzero(&rxdb_reg, sizeof(pd_rxulp_db_t));
1567231437Sluigi	for (i = 0; i < count; i++) {
1568231437Sluigi		in = rq->packets_in + 1;
1569231437Sluigi		if (in == OCE_RQ_PACKET_ARRAY_SIZE)
1570231437Sluigi			in = 0;
1571231437Sluigi		if (in == rq->packets_out)
1572231437Sluigi			break;	/* no more room */
1573231437Sluigi
1574231437Sluigi		pd = &rq->pckts[rq->packets_in];
1575243857Sglebius		pd->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1576231437Sluigi		if (pd->mbuf == NULL)
1577231437Sluigi			break;
1578231437Sluigi
1579231437Sluigi		pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES;
1580231437Sluigi		rc = bus_dmamap_load_mbuf_sg(rq->tag,
1581231437Sluigi					     pd->map,
1582231437Sluigi					     pd->mbuf,
1583231437Sluigi					     segs, &nsegs, BUS_DMA_NOWAIT);
1584231437Sluigi		if (rc) {
1585231437Sluigi			m_free(pd->mbuf);
1586231437Sluigi			break;
1587231437Sluigi		}
1588231437Sluigi
1589231437Sluigi		if (nsegs != 1) {
1590231437Sluigi			i--;
1591231437Sluigi			continue;
1592231437Sluigi		}
1593231437Sluigi
1594231437Sluigi		rq->packets_in = in;
1595231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
1596231437Sluigi
1597231437Sluigi		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
1598231437Sluigi		rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
1599231437Sluigi		rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
1600231437Sluigi		DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
1601231437Sluigi		RING_PUT(rq->ring, 1);
1602231437Sluigi		added++;
1603231437Sluigi		rq->pending++;
1604231437Sluigi	}
1605231437Sluigi	if (added != 0) {
1606231437Sluigi		for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) {
1607231437Sluigi			rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS;
1608231437Sluigi			rxdb_reg.bits.qid = rq->rq_id;
1609231437Sluigi			OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1610231437Sluigi			added -= OCE_MAX_RQ_POSTS;
1611231437Sluigi		}
1612231437Sluigi		if (added > 0) {
1613231437Sluigi			rxdb_reg.bits.qid = rq->rq_id;
1614231437Sluigi			rxdb_reg.bits.num_posted = added;
1615231437Sluigi			OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1616231437Sluigi		}
1617231437Sluigi	}
1618231437Sluigi
1619231437Sluigi	return 0;
1620231437Sluigi}
1621231437Sluigi
1622231437Sluigi
1623231437Sluigi/* Handle the Completion Queue for receive */
1624231437Sluigiuint16_t
1625231437Sluigioce_rq_handler(void *arg)
1626231437Sluigi{
1627231437Sluigi	struct oce_rq *rq = (struct oce_rq *)arg;
1628231437Sluigi	struct oce_cq *cq = rq->cq;
1629231437Sluigi	POCE_SOFTC sc = rq->parent;
1630231437Sluigi	struct oce_nic_rx_cqe *cqe;
1631231437Sluigi	int num_cqes = 0, rq_buffers_used = 0;
1632231437Sluigi
1633231437Sluigi
1634231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
1635231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1636231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
1637231437Sluigi	while (cqe->u0.dw[2]) {
1638231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
1639231437Sluigi
1640231437Sluigi		RING_GET(rq->ring, 1);
1641231437Sluigi		if (cqe->u0.s.error == 0) {
1642231437Sluigi			oce_rx(rq, cqe->u0.s.frag_index, cqe);
1643231437Sluigi		} else {
1644231437Sluigi			rq->rx_stats.rxcp_err++;
1645231437Sluigi			sc->ifp->if_ierrors++;
1646247880Sdelphij			/* Post L3/L4 errors to stack.*/
1647247880Sdelphij			oce_rx(rq, cqe->u0.s.frag_index, cqe);
1648231437Sluigi		}
1649231437Sluigi		rq->rx_stats.rx_compl++;
1650231437Sluigi		cqe->u0.dw[2] = 0;
1651231437Sluigi
1652231511Sbz#if defined(INET6) || defined(INET)
1653231437Sluigi		if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
1654231437Sluigi			oce_rx_flush_lro(rq);
1655231437Sluigi		}
1656231511Sbz#endif
1657231437Sluigi
1658231437Sluigi		RING_GET(cq->ring, 1);
1659231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
1660231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1661231437Sluigi		cqe =
1662231437Sluigi		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
1663231437Sluigi		num_cqes++;
1664231437Sluigi		if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
1665231437Sluigi			break;
1666231437Sluigi	}
1667231879Sluigi
1668231511Sbz#if defined(INET6) || defined(INET)
1669231437Sluigi	if (IF_LRO_ENABLED(sc))
1670231437Sluigi		oce_rx_flush_lro(rq);
1671231511Sbz#endif
1672231437Sluigi
1673231437Sluigi	if (num_cqes) {
1674231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1675231437Sluigi		rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending;
1676231437Sluigi		if (rq_buffers_used > 1)
1677231437Sluigi			oce_alloc_rx_bufs(rq, (rq_buffers_used - 1));
1678231437Sluigi	}
1679231437Sluigi
1680231437Sluigi	return 0;
1681231437Sluigi
1682231437Sluigi}
1683231437Sluigi
1684231437Sluigi
1685231437Sluigi
1686231437Sluigi
1687231437Sluigi/*****************************************************************************
1688231437Sluigi *		   Helper function prototypes in this file 		     *
1689231437Sluigi *****************************************************************************/
1690231437Sluigi
1691231437Sluigistatic int
1692231437Sluigioce_attach_ifp(POCE_SOFTC sc)
1693231437Sluigi{
1694231437Sluigi
1695231437Sluigi	sc->ifp = if_alloc(IFT_ETHER);
1696231437Sluigi	if (!sc->ifp)
1697231437Sluigi		return ENOMEM;
1698231437Sluigi
1699231437Sluigi	ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
1700231437Sluigi	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
1701231437Sluigi	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
1702231437Sluigi
1703231437Sluigi	sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
1704231437Sluigi	sc->ifp->if_ioctl = oce_ioctl;
1705231437Sluigi	sc->ifp->if_start = oce_start;
1706231437Sluigi	sc->ifp->if_init = oce_init;
1707231437Sluigi	sc->ifp->if_mtu = ETHERMTU;
1708231437Sluigi	sc->ifp->if_softc = sc;
1709231437Sluigi#if __FreeBSD_version >= 800000
1710231437Sluigi	sc->ifp->if_transmit = oce_multiq_start;
1711231437Sluigi	sc->ifp->if_qflush = oce_multiq_flush;
1712231437Sluigi#endif
1713231437Sluigi
1714231437Sluigi	if_initname(sc->ifp,
1715231437Sluigi		    device_get_name(sc->dev), device_get_unit(sc->dev));
1716231437Sluigi
1717231437Sluigi	sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1;
1718231437Sluigi	IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen);
1719231437Sluigi	IFQ_SET_READY(&sc->ifp->if_snd);
1720231437Sluigi
1721231437Sluigi	sc->ifp->if_hwassist = OCE_IF_HWASSIST;
1722231437Sluigi	sc->ifp->if_hwassist |= CSUM_TSO;
1723231437Sluigi	sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP);
1724231437Sluigi
1725231437Sluigi	sc->ifp->if_capabilities = OCE_IF_CAPABILITIES;
1726231437Sluigi	sc->ifp->if_capabilities |= IFCAP_HWCSUM;
1727231437Sluigi	sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
1728231879Sluigi
1729231511Sbz#if defined(INET6) || defined(INET)
1730231511Sbz	sc->ifp->if_capabilities |= IFCAP_TSO;
1731231437Sluigi	sc->ifp->if_capabilities |= IFCAP_LRO;
1732231879Sluigi	sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
1733231511Sbz#endif
1734231437Sluigi
1735231437Sluigi	sc->ifp->if_capenable = sc->ifp->if_capabilities;
1736241691Sjhb	if_initbaudrate(sc->ifp, IF_Gbps(10));
1737231437Sluigi
1738257187Sdelphij#if __FreeBSD_version >= 1000000
1739257187Sdelphij	sc->ifp->if_hw_tsomax = OCE_MAX_TSO_SIZE;
1740257187Sdelphij#endif
1741257187Sdelphij
1742231437Sluigi	ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
1743231437Sluigi
1744231437Sluigi	return 0;
1745231437Sluigi}
1746231437Sluigi
1747231437Sluigi
1748231437Sluigistatic void
1749231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
1750231437Sluigi{
1751231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1752231437Sluigi
1753231437Sluigi	if (ifp->if_softc !=  arg)
1754231437Sluigi		return;
1755231437Sluigi	if ((vtag == 0) || (vtag > 4095))
1756231437Sluigi		return;
1757231437Sluigi
1758231437Sluigi	sc->vlan_tag[vtag] = 1;
1759231437Sluigi	sc->vlans_added++;
1760257187Sdelphij	if (sc->vlans_added <= (sc->max_vlans + 1))
1761257187Sdelphij		oce_vid_config(sc);
1762231437Sluigi}
1763231437Sluigi
1764231437Sluigi
1765231437Sluigistatic void
1766231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
1767231437Sluigi{
1768231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1769231437Sluigi
1770231437Sluigi	if (ifp->if_softc !=  arg)
1771231437Sluigi		return;
1772231437Sluigi	if ((vtag == 0) || (vtag > 4095))
1773231437Sluigi		return;
1774231437Sluigi
1775231437Sluigi	sc->vlan_tag[vtag] = 0;
1776231437Sluigi	sc->vlans_added--;
1777231437Sluigi	oce_vid_config(sc);
1778231437Sluigi}
1779231437Sluigi
1780231437Sluigi
1781231437Sluigi/*
1782231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures
1783231437Sluigi * more, place the card in vlan promiscuous mode.
1784231437Sluigi */
1785231437Sluigistatic int
1786231437Sluigioce_vid_config(POCE_SOFTC sc)
1787231437Sluigi{
1788231437Sluigi	struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
1789231437Sluigi	uint16_t ntags = 0, i;
1790231437Sluigi	int status = 0;
1791231437Sluigi
1792231437Sluigi	if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
1793231437Sluigi			(sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) {
1794231437Sluigi		for (i = 0; i < MAX_VLANS; i++) {
1795231437Sluigi			if (sc->vlan_tag[i]) {
1796231437Sluigi				vtags[ntags].vtag = i;
1797231437Sluigi				ntags++;
1798231437Sluigi			}
1799231437Sluigi		}
1800231437Sluigi		if (ntags)
1801231437Sluigi			status = oce_config_vlan(sc, (uint8_t) sc->if_id,
1802231437Sluigi						vtags, ntags, 1, 0);
1803231437Sluigi	} else
1804231437Sluigi		status = oce_config_vlan(sc, (uint8_t) sc->if_id,
1805231437Sluigi					 	NULL, 0, 1, 1);
1806231437Sluigi	return status;
1807231437Sluigi}
1808231437Sluigi
1809231437Sluigi
1810231437Sluigistatic void
1811231437Sluigioce_mac_addr_set(POCE_SOFTC sc)
1812231437Sluigi{
1813231437Sluigi	uint32_t old_pmac_id = sc->pmac_id;
1814231437Sluigi	int status = 0;
1815231437Sluigi
1816231437Sluigi
1817231437Sluigi	status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
1818231437Sluigi			 sc->macaddr.size_of_struct);
1819231437Sluigi	if (!status)
1820231437Sluigi		return;
1821231437Sluigi
1822231437Sluigi	status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)),
1823231437Sluigi					sc->if_id, &sc->pmac_id);
1824231437Sluigi	if (!status) {
1825231437Sluigi		status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
1826231437Sluigi		bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
1827231437Sluigi				 sc->macaddr.size_of_struct);
1828231437Sluigi	}
1829231437Sluigi	if (status)
1830231437Sluigi		device_printf(sc->dev, "Failed update macaddress\n");
1831231437Sluigi
1832231437Sluigi}
1833231437Sluigi
1834231437Sluigi
1835231437Sluigistatic int
1836231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data)
1837231437Sluigi{
1838231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1839231437Sluigi	struct ifreq *ifr = (struct ifreq *)data;
1840231437Sluigi	int rc = ENXIO;
1841231437Sluigi	char cookie[32] = {0};
1842231437Sluigi	void *priv_data = (void *)ifr->ifr_data;
1843231437Sluigi	void *ioctl_ptr;
1844231437Sluigi	uint32_t req_size;
1845231437Sluigi	struct mbx_hdr req;
1846231437Sluigi	OCE_DMA_MEM dma_mem;
1847247880Sdelphij	struct mbx_common_get_cntl_attr *fw_cmd;
1848231437Sluigi
1849231437Sluigi	if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
1850231437Sluigi		return EFAULT;
1851247880Sdelphij
1852231437Sluigi	if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
1853231437Sluigi		return EINVAL;
1854247880Sdelphij
1855231437Sluigi	ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
1856231437Sluigi	if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
1857231437Sluigi		return EFAULT;
1858247880Sdelphij
1859231437Sluigi	req_size = le32toh(req.u0.req.request_length);
1860231437Sluigi	if (req_size > 65536)
1861231437Sluigi		return EINVAL;
1862231437Sluigi
1863231437Sluigi	req_size += sizeof(struct mbx_hdr);
1864231437Sluigi	rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
1865231437Sluigi	if (rc)
1866231437Sluigi		return ENOMEM;
1867231437Sluigi
1868231437Sluigi	if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
1869231437Sluigi		rc = EFAULT;
1870231437Sluigi		goto dma_free;
1871231437Sluigi	}
1872231437Sluigi
1873231437Sluigi	rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
1874231437Sluigi	if (rc) {
1875231437Sluigi		rc = EIO;
1876231437Sluigi		goto dma_free;
1877231437Sluigi	}
1878231437Sluigi
1879231437Sluigi	if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size))
1880231437Sluigi		rc =  EFAULT;
1881231437Sluigi
1882247880Sdelphij	/*
1883247880Sdelphij	   firmware is filling all the attributes for this ioctl except
1884247880Sdelphij	   the driver version..so fill it
1885247880Sdelphij	 */
1886247880Sdelphij	if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) {
1887247880Sdelphij		fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr;
1888247880Sdelphij		strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str,
1889247880Sdelphij			COMPONENT_REVISION, strlen(COMPONENT_REVISION));
1890247880Sdelphij	}
1891247880Sdelphij
1892231437Sluigidma_free:
1893231437Sluigi	oce_dma_free(sc, &dma_mem);
1894231437Sluigi	return rc;
1895231437Sluigi
1896231437Sluigi}
1897231437Sluigi
1898247880Sdelphijstatic void
1899247880Sdelphijoce_eqd_set_periodic(POCE_SOFTC sc)
1900247880Sdelphij{
1901247880Sdelphij	struct oce_set_eqd set_eqd[OCE_MAX_EQ];
1902247880Sdelphij	struct oce_aic_obj *aic;
1903247880Sdelphij	struct oce_eq *eqo;
1904247880Sdelphij	uint64_t now = 0, delta;
1905247880Sdelphij	int eqd, i, num = 0;
1906247880Sdelphij	uint32_t ips = 0;
1907247880Sdelphij	int tps;
1908231437Sluigi
1909247880Sdelphij	for (i = 0 ; i < sc->neqs; i++) {
1910247880Sdelphij		eqo = sc->eq[i];
1911247880Sdelphij		aic = &sc->aic_obj[i];
1912247880Sdelphij		/* When setting the static eq delay from the user space */
1913247880Sdelphij		if (!aic->enable) {
1914247880Sdelphij			eqd = aic->et_eqd;
1915247880Sdelphij			goto modify_eqd;
1916247880Sdelphij		}
1917247880Sdelphij
1918247880Sdelphij		now = ticks;
1919247880Sdelphij
1920247880Sdelphij		/* Over flow check */
1921247880Sdelphij		if ((now < aic->ticks) || (eqo->intr < aic->intr_prev))
1922247880Sdelphij			goto done;
1923247880Sdelphij
1924247880Sdelphij		delta = now - aic->ticks;
1925247880Sdelphij		tps = delta/hz;
1926247880Sdelphij
1927247880Sdelphij		/* Interrupt rate based on elapsed ticks */
1928247880Sdelphij		if(tps)
1929247880Sdelphij			ips = (uint32_t)(eqo->intr - aic->intr_prev) / tps;
1930247880Sdelphij
1931247880Sdelphij		if (ips > INTR_RATE_HWM)
1932247880Sdelphij			eqd = aic->cur_eqd + 20;
1933247880Sdelphij		else if (ips < INTR_RATE_LWM)
1934247880Sdelphij			eqd = aic->cur_eqd / 2;
1935247880Sdelphij		else
1936247880Sdelphij			goto done;
1937247880Sdelphij
1938247880Sdelphij		if (eqd < 10)
1939247880Sdelphij			eqd = 0;
1940247880Sdelphij
1941247880Sdelphij		/* Make sure that the eq delay is in the known range */
1942247880Sdelphij		eqd = min(eqd, aic->max_eqd);
1943247880Sdelphij		eqd = max(eqd, aic->min_eqd);
1944247880Sdelphij
1945247880Sdelphijmodify_eqd:
1946247880Sdelphij		if (eqd != aic->cur_eqd) {
1947247880Sdelphij			set_eqd[num].delay_multiplier = (eqd * 65)/100;
1948247880Sdelphij			set_eqd[num].eq_id = eqo->eq_id;
1949247880Sdelphij			aic->cur_eqd = eqd;
1950247880Sdelphij			num++;
1951247880Sdelphij		}
1952247880Sdelphijdone:
1953247880Sdelphij		aic->intr_prev = eqo->intr;
1954247880Sdelphij		aic->ticks = now;
1955247880Sdelphij	}
1956247880Sdelphij
1957247880Sdelphij	/* Is there atleast one eq that needs to be modified? */
1958247880Sdelphij	if(num)
1959247880Sdelphij		oce_mbox_eqd_modify_periodic(sc, set_eqd, num);
1960247880Sdelphij}
1961247880Sdelphij
1962257187Sdelphijstatic void oce_detect_hw_error(POCE_SOFTC sc)
1963257187Sdelphij{
1964257187Sdelphij
1965257187Sdelphij	uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0;
1966257187Sdelphij	uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
1967257187Sdelphij	uint32_t i;
1968257187Sdelphij
1969257187Sdelphij	if (sc->hw_error)
1970257187Sdelphij		return;
1971257187Sdelphij
1972257187Sdelphij	if (IS_XE201(sc)) {
1973257187Sdelphij		sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET);
1974257187Sdelphij		if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
1975257187Sdelphij			sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET);
1976257187Sdelphij			sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET);
1977257187Sdelphij		}
1978257187Sdelphij	} else {
1979257187Sdelphij		ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW);
1980257187Sdelphij		ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH);
1981257187Sdelphij		ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK);
1982257187Sdelphij		ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK);
1983257187Sdelphij
1984257187Sdelphij		ue_low = (ue_low & ~ue_low_mask);
1985257187Sdelphij		ue_high = (ue_high & ~ue_high_mask);
1986257187Sdelphij	}
1987257187Sdelphij
1988257187Sdelphij	/* On certain platforms BE hardware can indicate spurious UEs.
1989257187Sdelphij	 * Allow the h/w to stop working completely in case of a real UE.
1990257187Sdelphij	 * Hence not setting the hw_error for UE detection.
1991257187Sdelphij	 */
1992257187Sdelphij	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
1993257187Sdelphij		sc->hw_error = TRUE;
1994257187Sdelphij		device_printf(sc->dev, "Error detected in the card\n");
1995257187Sdelphij	}
1996257187Sdelphij
1997257187Sdelphij	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
1998257187Sdelphij		device_printf(sc->dev,
1999257187Sdelphij				"ERR: sliport status 0x%x\n", sliport_status);
2000257187Sdelphij		device_printf(sc->dev,
2001257187Sdelphij				"ERR: sliport error1 0x%x\n", sliport_err1);
2002257187Sdelphij		device_printf(sc->dev,
2003257187Sdelphij				"ERR: sliport error2 0x%x\n", sliport_err2);
2004257187Sdelphij	}
2005257187Sdelphij
2006257187Sdelphij	if (ue_low) {
2007257187Sdelphij		for (i = 0; ue_low; ue_low >>= 1, i++) {
2008257187Sdelphij			if (ue_low & 1)
2009257187Sdelphij				device_printf(sc->dev, "UE: %s bit set\n",
2010257187Sdelphij							ue_status_low_desc[i]);
2011257187Sdelphij		}
2012257187Sdelphij	}
2013257187Sdelphij
2014257187Sdelphij	if (ue_high) {
2015257187Sdelphij		for (i = 0; ue_high; ue_high >>= 1, i++) {
2016257187Sdelphij			if (ue_high & 1)
2017257187Sdelphij				device_printf(sc->dev, "UE: %s bit set\n",
2018257187Sdelphij							ue_status_hi_desc[i]);
2019257187Sdelphij		}
2020257187Sdelphij	}
2021257187Sdelphij
2022257187Sdelphij}
2023257187Sdelphij
2024257187Sdelphij
2025231437Sluigistatic void
2026231437Sluigioce_local_timer(void *arg)
2027231437Sluigi{
2028231437Sluigi	POCE_SOFTC sc = arg;
2029231437Sluigi	int i = 0;
2030231437Sluigi
2031257187Sdelphij	oce_detect_hw_error(sc);
2032231437Sluigi	oce_refresh_nic_stats(sc);
2033231437Sluigi	oce_refresh_queue_stats(sc);
2034231437Sluigi	oce_mac_addr_set(sc);
2035231437Sluigi
2036231437Sluigi	/* TX Watch Dog*/
2037231437Sluigi	for (i = 0; i < sc->nwqs; i++)
2038231437Sluigi		oce_tx_restart(sc, sc->wq[i]);
2039231437Sluigi
2040247880Sdelphij	/* calculate and set the eq delay for optimal interrupt rate */
2041252869Sdelphij	if (IS_BE(sc) || IS_SH(sc))
2042247880Sdelphij		oce_eqd_set_periodic(sc);
2043247880Sdelphij
2044231437Sluigi	callout_reset(&sc->timer, hz, oce_local_timer, sc);
2045231437Sluigi}
2046231437Sluigi
2047231437Sluigi
2048246799Sjpaetzel/* NOTE : This should only be called holding
2049246799Sjpaetzel *        DEVICE_LOCK.
2050257187Sdelphij */
2051231437Sluigistatic void
2052231437Sluigioce_if_deactivate(POCE_SOFTC sc)
2053231437Sluigi{
2054231437Sluigi	int i, mtime = 0;
2055231437Sluigi	int wait_req = 0;
2056231437Sluigi	struct oce_rq *rq;
2057231437Sluigi	struct oce_wq *wq;
2058231437Sluigi	struct oce_eq *eq;
2059231437Sluigi
2060231437Sluigi	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2061231437Sluigi
2062231437Sluigi	/*Wait for max of 400ms for TX completions to be done */
2063231437Sluigi	while (mtime < 400) {
2064231437Sluigi		wait_req = 0;
2065231437Sluigi		for_all_wq_queues(sc, wq, i) {
2066231437Sluigi			if (wq->ring->num_used) {
2067231437Sluigi				wait_req = 1;
2068231437Sluigi				DELAY(1);
2069231437Sluigi				break;
2070231437Sluigi			}
2071231437Sluigi		}
2072231437Sluigi		mtime += 1;
2073231437Sluigi		if (!wait_req)
2074231437Sluigi			break;
2075231437Sluigi	}
2076231437Sluigi
2077231437Sluigi	/* Stop intrs and finish any bottom halves pending */
2078231437Sluigi	oce_hw_intr_disable(sc);
2079231437Sluigi
2080247880Sdelphij	/* Since taskqueue_drain takes a Gaint Lock, We should not acquire
2081247880Sdelphij	   any other lock. So unlock device lock and require after
2082247880Sdelphij	   completing taskqueue_drain.
2083247880Sdelphij	*/
2084247880Sdelphij	UNLOCK(&sc->dev_lock);
2085231437Sluigi	for (i = 0; i < sc->intr_count; i++) {
2086231437Sluigi		if (sc->intrs[i].tq != NULL) {
2087231437Sluigi			taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
2088231437Sluigi		}
2089231437Sluigi	}
2090247880Sdelphij	LOCK(&sc->dev_lock);
2091231437Sluigi
2092231437Sluigi	/* Delete RX queue in card with flush param */
2093231437Sluigi	oce_stop_rx(sc);
2094231437Sluigi
2095231437Sluigi	/* Invalidate any pending cq and eq entries*/
2096231437Sluigi	for_all_evnt_queues(sc, eq, i)
2097231437Sluigi		oce_drain_eq(eq);
2098231437Sluigi	for_all_rq_queues(sc, rq, i)
2099231437Sluigi		oce_drain_rq_cq(rq);
2100231437Sluigi	for_all_wq_queues(sc, wq, i)
2101231437Sluigi		oce_drain_wq_cq(wq);
2102231437Sluigi
2103231437Sluigi	/* But still we need to get MCC aync events.
2104231437Sluigi	   So enable intrs and also arm first EQ
2105247880Sdelphij	*/
2106231437Sluigi	oce_hw_intr_enable(sc);
2107231437Sluigi	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
2108231437Sluigi
2109231437Sluigi	DELAY(10);
2110231437Sluigi}
2111231437Sluigi
2112231437Sluigi
2113231437Sluigistatic void
2114231437Sluigioce_if_activate(POCE_SOFTC sc)
2115231437Sluigi{
2116231437Sluigi	struct oce_eq *eq;
2117231437Sluigi	struct oce_rq *rq;
2118231437Sluigi	struct oce_wq *wq;
2119231437Sluigi	int i, rc = 0;
2120231437Sluigi
2121231437Sluigi	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
2122231437Sluigi
2123231437Sluigi	oce_hw_intr_disable(sc);
2124231437Sluigi
2125231437Sluigi	oce_start_rx(sc);
2126231437Sluigi
2127231437Sluigi	for_all_rq_queues(sc, rq, i) {
2128231437Sluigi		rc = oce_start_rq(rq);
2129231437Sluigi		if (rc)
2130231437Sluigi			device_printf(sc->dev, "Unable to start RX\n");
2131231437Sluigi	}
2132231437Sluigi
2133231437Sluigi	for_all_wq_queues(sc, wq, i) {
2134231437Sluigi		rc = oce_start_wq(wq);
2135231437Sluigi		if (rc)
2136231437Sluigi			device_printf(sc->dev, "Unable to start TX\n");
2137231437Sluigi	}
2138231437Sluigi
2139231437Sluigi
2140231437Sluigi	for_all_evnt_queues(sc, eq, i)
2141231437Sluigi		oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
2142231437Sluigi
2143231437Sluigi	oce_hw_intr_enable(sc);
2144231437Sluigi
2145231437Sluigi}
2146231437Sluigi
2147231879Sluigistatic void
2148231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
2149231879Sluigi{
2150231879Sluigi	/* Update Link status */
2151231879Sluigi	if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
2152231879Sluigi	     ASYNC_EVENT_LINK_UP) {
2153231879Sluigi		sc->link_status = ASYNC_EVENT_LINK_UP;
2154231879Sluigi		if_link_state_change(sc->ifp, LINK_STATE_UP);
2155231879Sluigi	} else {
2156231879Sluigi		sc->link_status = ASYNC_EVENT_LINK_DOWN;
2157231879Sluigi		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
2158231879Sluigi	}
2159231879Sluigi}
2160231879Sluigi
2161231879Sluigi
2162231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */
2163231437Sluigiuint16_t
2164231437Sluigioce_mq_handler(void *arg)
2165231437Sluigi{
2166231437Sluigi	struct oce_mq *mq = (struct oce_mq *)arg;
2167231437Sluigi	POCE_SOFTC sc = mq->parent;
2168231437Sluigi	struct oce_cq *cq = mq->cq;
2169231879Sluigi	int num_cqes = 0, evt_type = 0, optype = 0;
2170231437Sluigi	struct oce_mq_cqe *cqe;
2171231437Sluigi	struct oce_async_cqe_link_state *acqe;
2172231879Sluigi	struct oce_async_event_grp5_pvid_state *gcqe;
2173247880Sdelphij	struct oce_async_event_qnq *dbgcqe;
2174231437Sluigi
2175231879Sluigi
2176231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
2177231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2178231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
2179231879Sluigi
2180231437Sluigi	while (cqe->u0.dw[3]) {
2181231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
2182231437Sluigi		if (cqe->u0.s.async_event) {
2183231879Sluigi			evt_type = cqe->u0.s.event_type;
2184231879Sluigi			optype = cqe->u0.s.async_type;
2185231879Sluigi			if (evt_type  == ASYNC_EVENT_CODE_LINK_STATE) {
2186231879Sluigi				/* Link status evt */
2187231879Sluigi				acqe = (struct oce_async_cqe_link_state *)cqe;
2188231879Sluigi				process_link_state(sc, acqe);
2189231879Sluigi			} else if ((evt_type == ASYNC_EVENT_GRP5) &&
2190231879Sluigi				   (optype == ASYNC_EVENT_PVID_STATE)) {
2191231879Sluigi				/* GRP5 PVID */
2192231879Sluigi				gcqe =
2193231879Sluigi				(struct oce_async_event_grp5_pvid_state *)cqe;
2194231879Sluigi				if (gcqe->enabled)
2195231879Sluigi					sc->pvid = gcqe->tag & VLAN_VID_MASK;
2196231879Sluigi				else
2197231879Sluigi					sc->pvid = 0;
2198231879Sluigi
2199231437Sluigi			}
2200247880Sdelphij			else if(evt_type == ASYNC_EVENT_CODE_DEBUG &&
2201247880Sdelphij				optype == ASYNC_EVENT_DEBUG_QNQ) {
2202247880Sdelphij				dbgcqe =
2203247880Sdelphij				(struct oce_async_event_qnq *)cqe;
2204247880Sdelphij				if(dbgcqe->valid)
2205247880Sdelphij					sc->qnqid = dbgcqe->vlan_tag;
2206247880Sdelphij				sc->qnq_debug_event = TRUE;
2207247880Sdelphij			}
2208231437Sluigi		}
2209231437Sluigi		cqe->u0.dw[3] = 0;
2210231437Sluigi		RING_GET(cq->ring, 1);
2211231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
2212231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2213231437Sluigi		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
2214231437Sluigi		num_cqes++;
2215231437Sluigi	}
2216231437Sluigi
2217231437Sluigi	if (num_cqes)
2218231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
2219231437Sluigi
2220231437Sluigi	return 0;
2221231437Sluigi}
2222231437Sluigi
2223231437Sluigi
2224231437Sluigistatic void
2225231437Sluigisetup_max_queues_want(POCE_SOFTC sc)
2226231437Sluigi{
2227231437Sluigi	/* Check if it is FLEX machine. Is so dont use RSS */
2228231437Sluigi	if ((sc->function_mode & FNM_FLEX10_MODE) ||
2229231879Sluigi	    (sc->function_mode & FNM_UMC_MODE)    ||
2230231879Sluigi	    (sc->function_mode & FNM_VNIC_MODE)	  ||
2231252869Sdelphij	    (!is_rss_enabled(sc))		  ||
2232231879Sluigi	    (sc->flags & OCE_FLAGS_BE2)) {
2233231437Sluigi		sc->nrqs = 1;
2234231437Sluigi		sc->nwqs = 1;
2235257187Sdelphij	} else {
2236257187Sdelphij		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
2237257187Sdelphij		sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs);
2238231437Sluigi	}
2239231437Sluigi}
2240231437Sluigi
2241231437Sluigi
2242231437Sluigistatic void
2243231437Sluigiupdate_queues_got(POCE_SOFTC sc)
2244231437Sluigi{
2245252869Sdelphij	if (is_rss_enabled(sc)) {
2246231437Sluigi		sc->nrqs = sc->intr_count + 1;
2247231437Sluigi		sc->nwqs = sc->intr_count;
2248231437Sluigi	} else {
2249231437Sluigi		sc->nrqs = 1;
2250231437Sluigi		sc->nwqs = 1;
2251231437Sluigi	}
2252231437Sluigi}
2253231437Sluigi
2254247880Sdelphijstatic int
2255247880Sdelphijoce_check_ipv6_ext_hdr(struct mbuf *m)
2256247880Sdelphij{
2257247880Sdelphij	struct ether_header *eh = mtod(m, struct ether_header *);
2258247880Sdelphij	caddr_t m_datatemp = m->m_data;
2259247880Sdelphij
2260247880Sdelphij	if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2261247880Sdelphij		m->m_data += sizeof(struct ether_header);
2262247880Sdelphij		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2263247880Sdelphij
2264247880Sdelphij		if((ip6->ip6_nxt != IPPROTO_TCP) && \
2265247880Sdelphij				(ip6->ip6_nxt != IPPROTO_UDP)){
2266247880Sdelphij			struct ip6_ext *ip6e = NULL;
2267247880Sdelphij			m->m_data += sizeof(struct ip6_hdr);
2268247880Sdelphij
2269247880Sdelphij			ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *);
2270247880Sdelphij			if(ip6e->ip6e_len == 0xff) {
2271247880Sdelphij				m->m_data = m_datatemp;
2272247880Sdelphij				return TRUE;
2273247880Sdelphij			}
2274247880Sdelphij		}
2275247880Sdelphij		m->m_data = m_datatemp;
2276247880Sdelphij	}
2277247880Sdelphij	return FALSE;
2278247880Sdelphij}
2279247880Sdelphij
2280247880Sdelphijstatic int
2281247880Sdelphijis_be3_a1(POCE_SOFTC sc)
2282247880Sdelphij{
2283247880Sdelphij	if((sc->flags & OCE_FLAGS_BE3)  && ((sc->asic_revision & 0xFF) < 2)) {
2284247880Sdelphij		return TRUE;
2285247880Sdelphij	}
2286247880Sdelphij	return FALSE;
2287247880Sdelphij}
2288247880Sdelphij
2289247880Sdelphijstatic struct mbuf *
2290247880Sdelphijoce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete)
2291247880Sdelphij{
2292247880Sdelphij	uint16_t vlan_tag = 0;
2293247880Sdelphij
2294247880Sdelphij	if(!M_WRITABLE(m))
2295247880Sdelphij		return NULL;
2296247880Sdelphij
2297247880Sdelphij	/* Embed vlan tag in the packet if it is not part of it */
2298247880Sdelphij	if(m->m_flags & M_VLANTAG) {
2299247880Sdelphij		vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
2300247880Sdelphij		m->m_flags &= ~M_VLANTAG;
2301247880Sdelphij	}
2302247880Sdelphij
2303247880Sdelphij	/* if UMC, ignore vlan tag insertion and instead insert pvid */
2304247880Sdelphij	if(sc->pvid) {
2305247880Sdelphij		if(!vlan_tag)
2306247880Sdelphij			vlan_tag = sc->pvid;
2307247880Sdelphij		*complete = FALSE;
2308247880Sdelphij	}
2309247880Sdelphij
2310247880Sdelphij	if(vlan_tag) {
2311247880Sdelphij		m = ether_vlanencap(m, vlan_tag);
2312247880Sdelphij	}
2313247880Sdelphij
2314247880Sdelphij	if(sc->qnqid) {
2315247880Sdelphij		m = ether_vlanencap(m, sc->qnqid);
2316247880Sdelphij		*complete = FALSE;
2317247880Sdelphij	}
2318247880Sdelphij	return m;
2319247880Sdelphij}
2320247880Sdelphij
2321247880Sdelphijstatic int
2322247880Sdelphijoce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m)
2323247880Sdelphij{
2324247880Sdelphij	if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \
2325247880Sdelphij			oce_check_ipv6_ext_hdr(m)) {
2326247880Sdelphij		return TRUE;
2327247880Sdelphij	}
2328247880Sdelphij	return FALSE;
2329247880Sdelphij}
2330252869Sdelphij
2331252869Sdelphijstatic void
2332252869Sdelphijoce_get_config(POCE_SOFTC sc)
2333252869Sdelphij{
2334252869Sdelphij	int rc = 0;
2335252869Sdelphij	uint32_t max_rss = 0;
2336252869Sdelphij
2337252869Sdelphij	if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native))
2338252869Sdelphij		max_rss = OCE_LEGACY_MODE_RSS;
2339252869Sdelphij	else
2340252869Sdelphij		max_rss = OCE_MAX_RSS;
2341252869Sdelphij
2342252869Sdelphij	if (!IS_BE(sc)) {
2343259050Sdelphij		rc = oce_get_profile_config(sc, max_rss);
2344252869Sdelphij		if (rc) {
2345252869Sdelphij			sc->nwqs = OCE_MAX_WQ;
2346252869Sdelphij			sc->nrssqs = max_rss;
2347252869Sdelphij			sc->nrqs = sc->nrssqs + 1;
2348252869Sdelphij		}
2349252869Sdelphij	}
2350259050Sdelphij	else { /* For BE3 don't rely on fw for determining the resources */
2351252869Sdelphij		sc->nrssqs = max_rss;
2352252869Sdelphij		sc->nrqs = sc->nrssqs + 1;
2353259050Sdelphij		sc->nwqs = OCE_MAX_WQ;
2354259050Sdelphij		sc->max_vlans = MAX_VLANFILTER_SIZE;
2355252869Sdelphij	}
2356252869Sdelphij}
2357