oce_if.c revision 268156
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: head/sys/dev/oce/oce_if.c 268156 2014-07-02 12:13:11Z luigi $ */
40231437Sluigi
41231511Sbz#include "opt_inet6.h"
42231511Sbz#include "opt_inet.h"
43231511Sbz
44231437Sluigi#include "oce_if.h"
45231437Sluigi
46257007Sdelphij/* UE Status Low CSR */
47257007Sdelphijstatic char *ue_status_low_desc[] = {
48257007Sdelphij	"CEV",
49257007Sdelphij	"CTX",
50257007Sdelphij	"DBUF",
51257007Sdelphij	"ERX",
52257007Sdelphij	"Host",
53257007Sdelphij	"MPU",
54257007Sdelphij	"NDMA",
55257007Sdelphij	"PTC ",
56257007Sdelphij	"RDMA ",
57257007Sdelphij	"RXF ",
58257007Sdelphij	"RXIPS ",
59257007Sdelphij	"RXULP0 ",
60257007Sdelphij	"RXULP1 ",
61257007Sdelphij	"RXULP2 ",
62257007Sdelphij	"TIM ",
63257007Sdelphij	"TPOST ",
64257007Sdelphij	"TPRE ",
65257007Sdelphij	"TXIPS ",
66257007Sdelphij	"TXULP0 ",
67257007Sdelphij	"TXULP1 ",
68257007Sdelphij	"UC ",
69257007Sdelphij	"WDMA ",
70257007Sdelphij	"TXULP2 ",
71257007Sdelphij	"HOST1 ",
72257007Sdelphij	"P0_OB_LINK ",
73257007Sdelphij	"P1_OB_LINK ",
74257007Sdelphij	"HOST_GPIO ",
75257007Sdelphij	"MBOX ",
76257007Sdelphij	"AXGMAC0",
77257007Sdelphij	"AXGMAC1",
78257007Sdelphij	"JTAG",
79257007Sdelphij	"MPU_INTPEND"
80257007Sdelphij};
81231437Sluigi
82257007Sdelphij/* UE Status High CSR */
83257007Sdelphijstatic char *ue_status_hi_desc[] = {
84257007Sdelphij	"LPCMEMHOST",
85257007Sdelphij	"MGMT_MAC",
86257007Sdelphij	"PCS0ONLINE",
87257007Sdelphij	"MPU_IRAM",
88257007Sdelphij	"PCS1ONLINE",
89257007Sdelphij	"PCTL0",
90257007Sdelphij	"PCTL1",
91257007Sdelphij	"PMEM",
92257007Sdelphij	"RR",
93257007Sdelphij	"TXPB",
94257007Sdelphij	"RXPP",
95257007Sdelphij	"XAUI",
96257007Sdelphij	"TXP",
97257007Sdelphij	"ARM",
98257007Sdelphij	"IPC",
99257007Sdelphij	"HOST2",
100257007Sdelphij	"HOST3",
101257007Sdelphij	"HOST4",
102257007Sdelphij	"HOST5",
103257007Sdelphij	"HOST6",
104257007Sdelphij	"HOST7",
105257007Sdelphij	"HOST8",
106257007Sdelphij	"HOST9",
107257007Sdelphij	"NETC",
108257007Sdelphij	"Unknown",
109257007Sdelphij	"Unknown",
110257007Sdelphij	"Unknown",
111257007Sdelphij	"Unknown",
112257007Sdelphij	"Unknown",
113257007Sdelphij	"Unknown",
114257007Sdelphij	"Unknown",
115257007Sdelphij	"Unknown"
116257007Sdelphij};
117257007Sdelphij
118257007Sdelphij
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) {
462257007Sdelphij			if (!oce_rxf_set_promiscuous(sc, (1 | (1 << 1))))
463257007Sdelphij				sc->promisc = TRUE;
464231437Sluigi		} else if (!(ifp->if_flags & IFF_PROMISC) && sc->promisc) {
465257007Sdelphij			if (!oce_rxf_set_promiscuous(sc, 0))
466257007Sdelphij				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
566231437Sluigi	if ((m->m_flags & M_FLOWID) != 0)
567231437Sluigi		queue_index = m->m_pkthdr.flowid % sc->nwqs;
568252869Sdelphij
569231437Sluigi	wq = sc->wq[queue_index];
570231437Sluigi
571252869Sdelphij	LOCK(&wq->tx_lock);
572252869Sdelphij	status = oce_multiq_transmit(ifp, m, wq);
573252869Sdelphij	UNLOCK(&wq->tx_lock);
574252869Sdelphij
575231437Sluigi	return status;
576231437Sluigi
577231437Sluigi}
578231437Sluigi
579231437Sluigi
580231437Sluigistatic void
581231437Sluigioce_multiq_flush(struct ifnet *ifp)
582231437Sluigi{
583231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
584231437Sluigi	struct mbuf     *m;
585231437Sluigi	int i = 0;
586231437Sluigi
587231437Sluigi	for (i = 0; i < sc->nwqs; i++) {
588231437Sluigi		while ((m = buf_ring_dequeue_sc(sc->wq[i]->br)) != NULL)
589231437Sluigi			m_freem(m);
590231437Sluigi	}
591231437Sluigi	if_qflush(ifp);
592231437Sluigi}
593231437Sluigi
594231437Sluigi
595231437Sluigi
596231437Sluigi/*****************************************************************************
597231437Sluigi *                   Driver interrupt routines functions                     *
598231437Sluigi *****************************************************************************/
599231437Sluigi
600231437Sluigistatic void
601231437Sluigioce_intr(void *arg, int pending)
602231437Sluigi{
603231437Sluigi
604231437Sluigi	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
605231437Sluigi	POCE_SOFTC sc = ii->sc;
606231437Sluigi	struct oce_eq *eq = ii->eq;
607231437Sluigi	struct oce_eqe *eqe;
608231437Sluigi	struct oce_cq *cq = NULL;
609231437Sluigi	int i, num_eqes = 0;
610231437Sluigi
611231437Sluigi
612231437Sluigi	bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
613231437Sluigi				 BUS_DMASYNC_POSTWRITE);
614231437Sluigi	do {
615231437Sluigi		eqe = RING_GET_CONSUMER_ITEM_VA(eq->ring, struct oce_eqe);
616231437Sluigi		if (eqe->evnt == 0)
617231437Sluigi			break;
618231437Sluigi		eqe->evnt = 0;
619231437Sluigi		bus_dmamap_sync(eq->ring->dma.tag, eq->ring->dma.map,
620231437Sluigi					BUS_DMASYNC_POSTWRITE);
621231437Sluigi		RING_GET(eq->ring, 1);
622231437Sluigi		num_eqes++;
623231437Sluigi
624231437Sluigi	} while (TRUE);
625231437Sluigi
626231437Sluigi	if (!num_eqes)
627231437Sluigi		goto eq_arm; /* Spurious */
628231437Sluigi
629231437Sluigi 	/* Clear EQ entries, but dont arm */
630231437Sluigi	oce_arm_eq(sc, eq->eq_id, num_eqes, FALSE, FALSE);
631231437Sluigi
632231437Sluigi	/* Process TX, RX and MCC. But dont arm CQ*/
633231437Sluigi	for (i = 0; i < eq->cq_valid; i++) {
634231437Sluigi		cq = eq->cq[i];
635231437Sluigi		(*cq->cq_handler)(cq->cb_arg);
636231437Sluigi	}
637231437Sluigi
638231437Sluigi	/* Arm all cqs connected to this EQ */
639231437Sluigi	for (i = 0; i < eq->cq_valid; i++) {
640231437Sluigi		cq = eq->cq[i];
641231437Sluigi		oce_arm_cq(sc, cq->cq_id, 0, TRUE);
642231437Sluigi	}
643231437Sluigi
644231437Sluigieq_arm:
645231437Sluigi	oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
646247880Sdelphij
647231437Sluigi	return;
648231437Sluigi}
649231437Sluigi
650231437Sluigi
651231437Sluigistatic int
652231437Sluigioce_setup_intr(POCE_SOFTC sc)
653231437Sluigi{
654231437Sluigi	int rc = 0, use_intx = 0;
655231437Sluigi	int vector = 0, req_vectors = 0;
656231437Sluigi
657252869Sdelphij	if (is_rss_enabled(sc))
658231437Sluigi		req_vectors = MAX((sc->nrqs - 1), sc->nwqs);
659231437Sluigi	else
660231437Sluigi		req_vectors = 1;
661231437Sluigi
662231437Sluigi	if (sc->flags & OCE_FLAGS_MSIX_CAPABLE) {
663231437Sluigi		sc->intr_count = req_vectors;
664231437Sluigi		rc = pci_alloc_msix(sc->dev, &sc->intr_count);
665231437Sluigi		if (rc != 0) {
666231437Sluigi			use_intx = 1;
667231437Sluigi			pci_release_msi(sc->dev);
668231437Sluigi		} else
669231437Sluigi			sc->flags |= OCE_FLAGS_USING_MSIX;
670231437Sluigi	} else
671231437Sluigi		use_intx = 1;
672231437Sluigi
673231437Sluigi	if (use_intx)
674231437Sluigi		sc->intr_count = 1;
675231437Sluigi
676231437Sluigi	/* Scale number of queues based on intr we got */
677231437Sluigi	update_queues_got(sc);
678231437Sluigi
679231437Sluigi	if (use_intx) {
680231437Sluigi		device_printf(sc->dev, "Using legacy interrupt\n");
681231437Sluigi		rc = oce_alloc_intr(sc, vector, oce_intr);
682231437Sluigi		if (rc)
683231437Sluigi			goto error;
684231437Sluigi	} else {
685231437Sluigi		for (; vector < sc->intr_count; vector++) {
686231437Sluigi			rc = oce_alloc_intr(sc, vector, oce_intr);
687231437Sluigi			if (rc)
688231437Sluigi				goto error;
689231437Sluigi		}
690231437Sluigi	}
691231437Sluigi
692231437Sluigi	return 0;
693231437Sluigierror:
694231437Sluigi	oce_intr_free(sc);
695231437Sluigi	return rc;
696231437Sluigi}
697231437Sluigi
698231437Sluigi
699231437Sluigistatic int
700231437Sluigioce_fast_isr(void *arg)
701231437Sluigi{
702231437Sluigi	POCE_INTR_INFO ii = (POCE_INTR_INFO) arg;
703231437Sluigi	POCE_SOFTC sc = ii->sc;
704231437Sluigi
705231437Sluigi	if (ii->eq == NULL)
706231437Sluigi		return FILTER_STRAY;
707231437Sluigi
708231437Sluigi	oce_arm_eq(sc, ii->eq->eq_id, 0, FALSE, TRUE);
709231437Sluigi
710231437Sluigi	taskqueue_enqueue_fast(ii->tq, &ii->task);
711231437Sluigi
712247880Sdelphij 	ii->eq->intr++;
713247880Sdelphij
714231437Sluigi	return FILTER_HANDLED;
715231437Sluigi}
716231437Sluigi
717231437Sluigi
718231437Sluigistatic int
719231437Sluigioce_alloc_intr(POCE_SOFTC sc, int vector, void (*isr) (void *arg, int pending))
720231437Sluigi{
721231437Sluigi	POCE_INTR_INFO ii = &sc->intrs[vector];
722231437Sluigi	int rc = 0, rr;
723231437Sluigi
724231437Sluigi	if (vector >= OCE_MAX_EQ)
725231437Sluigi		return (EINVAL);
726231437Sluigi
727231437Sluigi	/* Set the resource id for the interrupt.
728231437Sluigi	 * MSIx is vector + 1 for the resource id,
729231437Sluigi	 * INTx is 0 for the resource id.
730231437Sluigi	 */
731231437Sluigi	if (sc->flags & OCE_FLAGS_USING_MSIX)
732231437Sluigi		rr = vector + 1;
733231437Sluigi	else
734231437Sluigi		rr = 0;
735231437Sluigi	ii->intr_res = bus_alloc_resource_any(sc->dev,
736231437Sluigi					      SYS_RES_IRQ,
737231437Sluigi					      &rr, RF_ACTIVE|RF_SHAREABLE);
738231437Sluigi	ii->irq_rr = rr;
739231437Sluigi	if (ii->intr_res == NULL) {
740231437Sluigi		device_printf(sc->dev,
741231437Sluigi			  "Could not allocate interrupt\n");
742231437Sluigi		rc = ENXIO;
743231437Sluigi		return rc;
744231437Sluigi	}
745231437Sluigi
746231437Sluigi	TASK_INIT(&ii->task, 0, isr, ii);
747231437Sluigi	ii->vector = vector;
748231437Sluigi	sprintf(ii->task_name, "oce_task[%d]", ii->vector);
749231437Sluigi	ii->tq = taskqueue_create_fast(ii->task_name,
750231437Sluigi			M_NOWAIT,
751231437Sluigi			taskqueue_thread_enqueue,
752231437Sluigi			&ii->tq);
753231437Sluigi	taskqueue_start_threads(&ii->tq, 1, PI_NET, "%s taskq",
754231437Sluigi			device_get_nameunit(sc->dev));
755231437Sluigi
756231437Sluigi	ii->sc = sc;
757231437Sluigi	rc = bus_setup_intr(sc->dev,
758231437Sluigi			ii->intr_res,
759231437Sluigi			INTR_TYPE_NET,
760231437Sluigi			oce_fast_isr, NULL, ii, &ii->tag);
761231437Sluigi	return rc;
762231437Sluigi
763231437Sluigi}
764231437Sluigi
765231437Sluigi
766231437Sluigivoid
767231437Sluigioce_intr_free(POCE_SOFTC sc)
768231437Sluigi{
769231437Sluigi	int i = 0;
770231437Sluigi
771231437Sluigi	for (i = 0; i < sc->intr_count; i++) {
772231437Sluigi
773231437Sluigi		if (sc->intrs[i].tag != NULL)
774231437Sluigi			bus_teardown_intr(sc->dev, sc->intrs[i].intr_res,
775231437Sluigi						sc->intrs[i].tag);
776231437Sluigi		if (sc->intrs[i].tq != NULL)
777231437Sluigi			taskqueue_free(sc->intrs[i].tq);
778231437Sluigi
779231437Sluigi		if (sc->intrs[i].intr_res != NULL)
780231437Sluigi			bus_release_resource(sc->dev, SYS_RES_IRQ,
781231437Sluigi						sc->intrs[i].irq_rr,
782231437Sluigi						sc->intrs[i].intr_res);
783231437Sluigi		sc->intrs[i].tag = NULL;
784231437Sluigi		sc->intrs[i].intr_res = NULL;
785231437Sluigi	}
786231437Sluigi
787231437Sluigi	if (sc->flags & OCE_FLAGS_USING_MSIX)
788231437Sluigi		pci_release_msi(sc->dev);
789231437Sluigi
790231437Sluigi}
791231437Sluigi
792231437Sluigi
793231437Sluigi
794231437Sluigi/******************************************************************************
795231437Sluigi*			  Media callbacks functions 			      *
796231437Sluigi******************************************************************************/
797231437Sluigi
798231437Sluigistatic void
799231437Sluigioce_media_status(struct ifnet *ifp, struct ifmediareq *req)
800231437Sluigi{
801231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) ifp->if_softc;
802231437Sluigi
803231437Sluigi
804231437Sluigi	req->ifm_status = IFM_AVALID;
805231437Sluigi	req->ifm_active = IFM_ETHER;
806231437Sluigi
807231437Sluigi	if (sc->link_status == 1)
808231437Sluigi		req->ifm_status |= IFM_ACTIVE;
809231437Sluigi	else
810231437Sluigi		return;
811231437Sluigi
812231437Sluigi	switch (sc->link_speed) {
813231437Sluigi	case 1: /* 10 Mbps */
814231437Sluigi		req->ifm_active |= IFM_10_T | IFM_FDX;
815231437Sluigi		sc->speed = 10;
816231437Sluigi		break;
817231437Sluigi	case 2: /* 100 Mbps */
818231437Sluigi		req->ifm_active |= IFM_100_TX | IFM_FDX;
819231437Sluigi		sc->speed = 100;
820231437Sluigi		break;
821231437Sluigi	case 3: /* 1 Gbps */
822231437Sluigi		req->ifm_active |= IFM_1000_T | IFM_FDX;
823231437Sluigi		sc->speed = 1000;
824231437Sluigi		break;
825231437Sluigi	case 4: /* 10 Gbps */
826231437Sluigi		req->ifm_active |= IFM_10G_SR | IFM_FDX;
827231437Sluigi		sc->speed = 10000;
828231437Sluigi		break;
829267839Sdelphij	case 5: /* 20 Gbps */
830267839Sdelphij		req->ifm_active |= IFM_10G_SR | IFM_FDX;
831267839Sdelphij		sc->speed = 20000;
832267839Sdelphij		break;
833267839Sdelphij	case 6: /* 25 Gbps */
834267839Sdelphij		req->ifm_active |= IFM_10G_SR | IFM_FDX;
835267839Sdelphij		sc->speed = 25000;
836267839Sdelphij		break;
837258941Sdelphij	case 7: /* 40 Gbps */
838258941Sdelphij		req->ifm_active |= IFM_40G_SR4 | IFM_FDX;
839258941Sdelphij		sc->speed = 40000;
840258941Sdelphij		break;
841267839Sdelphij	default:
842267839Sdelphij		sc->speed = 0;
843267839Sdelphij		break;
844231437Sluigi	}
845231437Sluigi
846231437Sluigi	return;
847231437Sluigi}
848231437Sluigi
849231437Sluigi
850231437Sluigiint
851231437Sluigioce_media_change(struct ifnet *ifp)
852231437Sluigi{
853231437Sluigi	return 0;
854231437Sluigi}
855231437Sluigi
856231437Sluigi
857231437Sluigi
858231437Sluigi
859231437Sluigi/*****************************************************************************
860231437Sluigi *			  Transmit routines functions			     *
861231437Sluigi *****************************************************************************/
862231437Sluigi
863231437Sluigistatic int
864231437Sluigioce_tx(POCE_SOFTC sc, struct mbuf **mpp, int wq_index)
865231437Sluigi{
866231437Sluigi	int rc = 0, i, retry_cnt = 0;
867231437Sluigi	bus_dma_segment_t segs[OCE_MAX_TX_ELEMENTS];
868231437Sluigi	struct mbuf *m, *m_temp;
869231437Sluigi	struct oce_wq *wq = sc->wq[wq_index];
870231437Sluigi	struct oce_packet_desc *pd;
871231437Sluigi	struct oce_nic_hdr_wqe *nichdr;
872231437Sluigi	struct oce_nic_frag_wqe *nicfrag;
873231437Sluigi	int num_wqes;
874231437Sluigi	uint32_t reg_value;
875247880Sdelphij	boolean_t complete = TRUE;
876231437Sluigi
877231437Sluigi	m = *mpp;
878231437Sluigi	if (!m)
879231437Sluigi		return EINVAL;
880231437Sluigi
881231437Sluigi	if (!(m->m_flags & M_PKTHDR)) {
882231437Sluigi		rc = ENXIO;
883231437Sluigi		goto free_ret;
884231437Sluigi	}
885231437Sluigi
886247880Sdelphij	if(oce_tx_asic_stall_verify(sc, m)) {
887247880Sdelphij		m = oce_insert_vlan_tag(sc, m, &complete);
888247880Sdelphij		if(!m) {
889247880Sdelphij			device_printf(sc->dev, "Insertion unsuccessful\n");
890247880Sdelphij			return 0;
891247880Sdelphij		}
892247880Sdelphij
893247880Sdelphij	}
894247880Sdelphij
895231437Sluigi	if (m->m_pkthdr.csum_flags & CSUM_TSO) {
896231879Sluigi		/* consolidate packet buffers for TSO/LSO segment offload */
897231511Sbz#if defined(INET6) || defined(INET)
898231879Sluigi		m = oce_tso_setup(sc, mpp);
899231511Sbz#else
900231511Sbz		m = NULL;
901231511Sbz#endif
902231437Sluigi		if (m == NULL) {
903231437Sluigi			rc = ENXIO;
904231437Sluigi			goto free_ret;
905231437Sluigi		}
906231437Sluigi	}
907231437Sluigi
908252869Sdelphij	pd = &wq->pckts[wq->pkt_desc_head];
909231437Sluigiretry:
910231437Sluigi	rc = bus_dmamap_load_mbuf_sg(wq->tag,
911231437Sluigi				     pd->map,
912231437Sluigi				     m, segs, &pd->nsegs, BUS_DMA_NOWAIT);
913231437Sluigi	if (rc == 0) {
914231437Sluigi		num_wqes = pd->nsegs + 1;
915252869Sdelphij		if (IS_BE(sc) || IS_SH(sc)) {
916231437Sluigi			/*Dummy required only for BE3.*/
917231437Sluigi			if (num_wqes & 1)
918231437Sluigi				num_wqes++;
919231437Sluigi		}
920231437Sluigi		if (num_wqes >= RING_NUM_FREE(wq->ring)) {
921231437Sluigi			bus_dmamap_unload(wq->tag, pd->map);
922231437Sluigi			return EBUSY;
923231437Sluigi		}
924252869Sdelphij		atomic_store_rel_int(&wq->pkt_desc_head,
925252869Sdelphij				     (wq->pkt_desc_head + 1) % \
926252869Sdelphij				      OCE_WQ_PACKET_ARRAY_SIZE);
927231437Sluigi		bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_PREWRITE);
928231437Sluigi		pd->mbuf = m;
929231437Sluigi
930231437Sluigi		nichdr =
931231437Sluigi		    RING_GET_PRODUCER_ITEM_VA(wq->ring, struct oce_nic_hdr_wqe);
932231437Sluigi		nichdr->u0.dw[0] = 0;
933231437Sluigi		nichdr->u0.dw[1] = 0;
934231437Sluigi		nichdr->u0.dw[2] = 0;
935231437Sluigi		nichdr->u0.dw[3] = 0;
936231437Sluigi
937247880Sdelphij		nichdr->u0.s.complete = complete;
938231437Sluigi		nichdr->u0.s.event = 1;
939231437Sluigi		nichdr->u0.s.crc = 1;
940231437Sluigi		nichdr->u0.s.forward = 0;
941231437Sluigi		nichdr->u0.s.ipcs = (m->m_pkthdr.csum_flags & CSUM_IP) ? 1 : 0;
942231437Sluigi		nichdr->u0.s.udpcs =
943247880Sdelphij			(m->m_pkthdr.csum_flags & CSUM_UDP) ? 1 : 0;
944231437Sluigi		nichdr->u0.s.tcpcs =
945247880Sdelphij			(m->m_pkthdr.csum_flags & CSUM_TCP) ? 1 : 0;
946231437Sluigi		nichdr->u0.s.num_wqe = num_wqes;
947231437Sluigi		nichdr->u0.s.total_length = m->m_pkthdr.len;
948257007Sdelphij
949231437Sluigi		if (m->m_flags & M_VLANTAG) {
950231437Sluigi			nichdr->u0.s.vlan = 1; /*Vlan present*/
951231437Sluigi			nichdr->u0.s.vlan_tag = m->m_pkthdr.ether_vtag;
952231437Sluigi		}
953257007Sdelphij
954231437Sluigi		if (m->m_pkthdr.csum_flags & CSUM_TSO) {
955231437Sluigi			if (m->m_pkthdr.tso_segsz) {
956231437Sluigi				nichdr->u0.s.lso = 1;
957231437Sluigi				nichdr->u0.s.lso_mss  = m->m_pkthdr.tso_segsz;
958231437Sluigi			}
959252869Sdelphij			if (!IS_BE(sc) || !IS_SH(sc))
960231437Sluigi				nichdr->u0.s.ipcs = 1;
961231437Sluigi		}
962231437Sluigi
963231437Sluigi		RING_PUT(wq->ring, 1);
964252869Sdelphij		atomic_add_int(&wq->ring->num_used, 1);
965231437Sluigi
966231437Sluigi		for (i = 0; i < pd->nsegs; i++) {
967231437Sluigi			nicfrag =
968231437Sluigi			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
969231437Sluigi						      struct oce_nic_frag_wqe);
970231437Sluigi			nicfrag->u0.s.rsvd0 = 0;
971231437Sluigi			nicfrag->u0.s.frag_pa_hi = ADDR_HI(segs[i].ds_addr);
972231437Sluigi			nicfrag->u0.s.frag_pa_lo = ADDR_LO(segs[i].ds_addr);
973231437Sluigi			nicfrag->u0.s.frag_len = segs[i].ds_len;
974231437Sluigi			pd->wqe_idx = wq->ring->pidx;
975231437Sluigi			RING_PUT(wq->ring, 1);
976252869Sdelphij			atomic_add_int(&wq->ring->num_used, 1);
977231437Sluigi		}
978231437Sluigi		if (num_wqes > (pd->nsegs + 1)) {
979231437Sluigi			nicfrag =
980231437Sluigi			    RING_GET_PRODUCER_ITEM_VA(wq->ring,
981231437Sluigi						      struct oce_nic_frag_wqe);
982231437Sluigi			nicfrag->u0.dw[0] = 0;
983231437Sluigi			nicfrag->u0.dw[1] = 0;
984231437Sluigi			nicfrag->u0.dw[2] = 0;
985231437Sluigi			nicfrag->u0.dw[3] = 0;
986231437Sluigi			pd->wqe_idx = wq->ring->pidx;
987231437Sluigi			RING_PUT(wq->ring, 1);
988252869Sdelphij			atomic_add_int(&wq->ring->num_used, 1);
989231437Sluigi			pd->nsegs++;
990231437Sluigi		}
991231437Sluigi
992231437Sluigi		sc->ifp->if_opackets++;
993231437Sluigi		wq->tx_stats.tx_reqs++;
994231437Sluigi		wq->tx_stats.tx_wrbs += num_wqes;
995231437Sluigi		wq->tx_stats.tx_bytes += m->m_pkthdr.len;
996231437Sluigi		wq->tx_stats.tx_pkts++;
997247880Sdelphij
998231437Sluigi		bus_dmamap_sync(wq->ring->dma.tag, wq->ring->dma.map,
999231437Sluigi				BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1000231437Sluigi		reg_value = (num_wqes << 16) | wq->wq_id;
1001252869Sdelphij		OCE_WRITE_REG32(sc, db, wq->db_offset, reg_value);
1002231437Sluigi
1003231437Sluigi	} else if (rc == EFBIG)	{
1004231437Sluigi		if (retry_cnt == 0) {
1005243857Sglebius			m_temp = m_defrag(m, M_NOWAIT);
1006231437Sluigi			if (m_temp == NULL)
1007231437Sluigi				goto free_ret;
1008231437Sluigi			m = m_temp;
1009231437Sluigi			*mpp = m_temp;
1010231437Sluigi			retry_cnt = retry_cnt + 1;
1011231437Sluigi			goto retry;
1012231437Sluigi		} else
1013231437Sluigi			goto free_ret;
1014231437Sluigi	} else if (rc == ENOMEM)
1015231437Sluigi		return rc;
1016231437Sluigi	else
1017231437Sluigi		goto free_ret;
1018252869Sdelphij
1019231437Sluigi	return 0;
1020231437Sluigi
1021231437Sluigifree_ret:
1022231437Sluigi	m_freem(*mpp);
1023231437Sluigi	*mpp = NULL;
1024231437Sluigi	return rc;
1025231437Sluigi}
1026231437Sluigi
1027231437Sluigi
1028231437Sluigistatic void
1029231437Sluigioce_tx_complete(struct oce_wq *wq, uint32_t wqe_idx, uint32_t status)
1030231437Sluigi{
1031231437Sluigi	struct oce_packet_desc *pd;
1032231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) wq->parent;
1033231437Sluigi	struct mbuf *m;
1034231437Sluigi
1035252869Sdelphij	pd = &wq->pckts[wq->pkt_desc_tail];
1036252869Sdelphij	atomic_store_rel_int(&wq->pkt_desc_tail,
1037252869Sdelphij			     (wq->pkt_desc_tail + 1) % OCE_WQ_PACKET_ARRAY_SIZE);
1038252869Sdelphij	atomic_subtract_int(&wq->ring->num_used, pd->nsegs + 1);
1039231437Sluigi	bus_dmamap_sync(wq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1040231437Sluigi	bus_dmamap_unload(wq->tag, pd->map);
1041231437Sluigi
1042231437Sluigi	m = pd->mbuf;
1043231437Sluigi	m_freem(m);
1044231437Sluigi	pd->mbuf = NULL;
1045231437Sluigi
1046252869Sdelphij
1047231437Sluigi	if (sc->ifp->if_drv_flags & IFF_DRV_OACTIVE) {
1048231437Sluigi		if (wq->ring->num_used < (wq->ring->num_items / 2)) {
1049231437Sluigi			sc->ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE);
1050231437Sluigi			oce_tx_restart(sc, wq);
1051231437Sluigi		}
1052231437Sluigi	}
1053231437Sluigi}
1054231437Sluigi
1055231437Sluigi
1056231437Sluigistatic void
1057231437Sluigioce_tx_restart(POCE_SOFTC sc, struct oce_wq *wq)
1058231437Sluigi{
1059231437Sluigi
1060231437Sluigi	if ((sc->ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
1061231437Sluigi		return;
1062231437Sluigi
1063231437Sluigi#if __FreeBSD_version >= 800000
1064231437Sluigi	if (!drbr_empty(sc->ifp, wq->br))
1065231437Sluigi#else
1066231437Sluigi	if (!IFQ_DRV_IS_EMPTY(&sc->ifp->if_snd))
1067231437Sluigi#endif
1068231437Sluigi		taskqueue_enqueue_fast(taskqueue_swi, &wq->txtask);
1069231437Sluigi
1070231437Sluigi}
1071231437Sluigi
1072231879Sluigi
1073231511Sbz#if defined(INET6) || defined(INET)
1074231437Sluigistatic struct mbuf *
1075231879Sluigioce_tso_setup(POCE_SOFTC sc, struct mbuf **mpp)
1076231437Sluigi{
1077231437Sluigi	struct mbuf *m;
1078231511Sbz#ifdef INET
1079231437Sluigi	struct ip *ip;
1080231511Sbz#endif
1081231511Sbz#ifdef INET6
1082231437Sluigi	struct ip6_hdr *ip6;
1083231511Sbz#endif
1084231437Sluigi	struct ether_vlan_header *eh;
1085231437Sluigi	struct tcphdr *th;
1086231437Sluigi	uint16_t etype;
1087231879Sluigi	int total_len = 0, ehdrlen = 0;
1088231437Sluigi
1089231437Sluigi	m = *mpp;
1090231437Sluigi
1091231437Sluigi	if (M_WRITABLE(m) == 0) {
1092243857Sglebius		m = m_dup(*mpp, M_NOWAIT);
1093231437Sluigi		if (!m)
1094231437Sluigi			return NULL;
1095231437Sluigi		m_freem(*mpp);
1096231437Sluigi		*mpp = m;
1097231437Sluigi	}
1098231437Sluigi
1099231437Sluigi	eh = mtod(m, struct ether_vlan_header *);
1100231437Sluigi	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
1101231437Sluigi		etype = ntohs(eh->evl_proto);
1102231437Sluigi		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1103231437Sluigi	} else {
1104231437Sluigi		etype = ntohs(eh->evl_encap_proto);
1105231437Sluigi		ehdrlen = ETHER_HDR_LEN;
1106231437Sluigi	}
1107231437Sluigi
1108231437Sluigi	switch (etype) {
1109231511Sbz#ifdef INET
1110231437Sluigi	case ETHERTYPE_IP:
1111231437Sluigi		ip = (struct ip *)(m->m_data + ehdrlen);
1112231437Sluigi		if (ip->ip_p != IPPROTO_TCP)
1113231437Sluigi			return NULL;
1114231437Sluigi		th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2));
1115231437Sluigi
1116231437Sluigi		total_len = ehdrlen + (ip->ip_hl << 2) + (th->th_off << 2);
1117231437Sluigi		break;
1118231511Sbz#endif
1119231511Sbz#ifdef INET6
1120231437Sluigi	case ETHERTYPE_IPV6:
1121231437Sluigi		ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen);
1122231437Sluigi		if (ip6->ip6_nxt != IPPROTO_TCP)
1123231437Sluigi			return NULL;
1124231437Sluigi		th = (struct tcphdr *)((caddr_t)ip6 + sizeof(struct ip6_hdr));
1125231437Sluigi
1126231437Sluigi		total_len = ehdrlen + sizeof(struct ip6_hdr) + (th->th_off << 2);
1127231437Sluigi		break;
1128231511Sbz#endif
1129231437Sluigi	default:
1130231437Sluigi		return NULL;
1131231437Sluigi	}
1132231437Sluigi
1133231437Sluigi	m = m_pullup(m, total_len);
1134231437Sluigi	if (!m)
1135231437Sluigi		return NULL;
1136231437Sluigi	*mpp = m;
1137231437Sluigi	return m;
1138231437Sluigi
1139231437Sluigi}
1140231511Sbz#endif /* INET6 || INET */
1141231437Sluigi
1142231437Sluigivoid
1143231437Sluigioce_tx_task(void *arg, int npending)
1144231437Sluigi{
1145231437Sluigi	struct oce_wq *wq = arg;
1146231437Sluigi	POCE_SOFTC sc = wq->parent;
1147231437Sluigi	struct ifnet *ifp = sc->ifp;
1148231437Sluigi	int rc = 0;
1149252869Sdelphij
1150231437Sluigi#if __FreeBSD_version >= 800000
1151252869Sdelphij	LOCK(&wq->tx_lock);
1152252869Sdelphij	rc = oce_multiq_transmit(ifp, NULL, wq);
1153252869Sdelphij	if (rc) {
1154252869Sdelphij		device_printf(sc->dev,
1155252869Sdelphij				"TX[%d] restart failed\n", wq->queue_index);
1156231437Sluigi	}
1157252869Sdelphij	UNLOCK(&wq->tx_lock);
1158231437Sluigi#else
1159231437Sluigi	oce_start(ifp);
1160231437Sluigi#endif
1161231437Sluigi
1162231437Sluigi}
1163231437Sluigi
1164231437Sluigi
1165231437Sluigivoid
1166231437Sluigioce_start(struct ifnet *ifp)
1167231437Sluigi{
1168231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1169231437Sluigi	struct mbuf *m;
1170231437Sluigi	int rc = 0;
1171231879Sluigi	int def_q = 0; /* Defualt tx queue is 0*/
1172231437Sluigi
1173231437Sluigi	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1174231437Sluigi			IFF_DRV_RUNNING)
1175231437Sluigi		return;
1176247880Sdelphij
1177247880Sdelphij	if (!sc->link_status)
1178247880Sdelphij		return;
1179231437Sluigi
1180231437Sluigi	do {
1181231437Sluigi		IF_DEQUEUE(&sc->ifp->if_snd, m);
1182231437Sluigi		if (m == NULL)
1183231437Sluigi			break;
1184231879Sluigi
1185231879Sluigi		LOCK(&sc->wq[def_q]->tx_lock);
1186231879Sluigi		rc = oce_tx(sc, &m, def_q);
1187231879Sluigi		UNLOCK(&sc->wq[def_q]->tx_lock);
1188231437Sluigi		if (rc) {
1189231437Sluigi			if (m != NULL) {
1190231879Sluigi				sc->wq[def_q]->tx_stats.tx_stops ++;
1191231437Sluigi				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1192231437Sluigi				IFQ_DRV_PREPEND(&ifp->if_snd, m);
1193231437Sluigi				m = NULL;
1194231437Sluigi			}
1195231437Sluigi			break;
1196231437Sluigi		}
1197231437Sluigi		if (m != NULL)
1198231437Sluigi			ETHER_BPF_MTAP(ifp, m);
1199231437Sluigi
1200231879Sluigi	} while (TRUE);
1201231437Sluigi
1202231437Sluigi	return;
1203231437Sluigi}
1204231437Sluigi
1205231437Sluigi
1206231437Sluigi/* Handle the Completion Queue for transmit */
1207231437Sluigiuint16_t
1208231437Sluigioce_wq_handler(void *arg)
1209231437Sluigi{
1210231437Sluigi	struct oce_wq *wq = (struct oce_wq *)arg;
1211231437Sluigi	POCE_SOFTC sc = wq->parent;
1212231437Sluigi	struct oce_cq *cq = wq->cq;
1213231437Sluigi	struct oce_nic_tx_cqe *cqe;
1214231437Sluigi	int num_cqes = 0;
1215231437Sluigi
1216231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
1217231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1218231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1219231437Sluigi	while (cqe->u0.dw[3]) {
1220231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_wq_cqe));
1221231437Sluigi
1222231437Sluigi		wq->ring->cidx = cqe->u0.s.wqe_index + 1;
1223231437Sluigi		if (wq->ring->cidx >= wq->ring->num_items)
1224231437Sluigi			wq->ring->cidx -= wq->ring->num_items;
1225231437Sluigi
1226231437Sluigi		oce_tx_complete(wq, cqe->u0.s.wqe_index, cqe->u0.s.status);
1227231437Sluigi		wq->tx_stats.tx_compl++;
1228231437Sluigi		cqe->u0.dw[3] = 0;
1229231437Sluigi		RING_GET(cq->ring, 1);
1230231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
1231231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1232231437Sluigi		cqe =
1233231437Sluigi		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
1234231437Sluigi		num_cqes++;
1235231437Sluigi	}
1236231437Sluigi
1237231437Sluigi	if (num_cqes)
1238231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1239231437Sluigi
1240231437Sluigi	return 0;
1241231437Sluigi}
1242231437Sluigi
1243231437Sluigi
1244231437Sluigistatic int
1245231437Sluigioce_multiq_transmit(struct ifnet *ifp, struct mbuf *m, struct oce_wq *wq)
1246231437Sluigi{
1247231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1248231437Sluigi	int status = 0, queue_index = 0;
1249231437Sluigi	struct mbuf *next = NULL;
1250231437Sluigi	struct buf_ring *br = NULL;
1251231437Sluigi
1252231437Sluigi	br  = wq->br;
1253231437Sluigi	queue_index = wq->queue_index;
1254231437Sluigi
1255231437Sluigi	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1256231437Sluigi		IFF_DRV_RUNNING) {
1257231437Sluigi		if (m != NULL)
1258231437Sluigi			status = drbr_enqueue(ifp, br, m);
1259231437Sluigi		return status;
1260231437Sluigi	}
1261231437Sluigi
1262257007Sdelphij	if (m != NULL) {
1263231437Sluigi		if ((status = drbr_enqueue(ifp, br, m)) != 0)
1264231437Sluigi			return status;
1265246482Srrs	}
1266246482Srrs	while ((next = drbr_peek(ifp, br)) != NULL) {
1267231437Sluigi		if (oce_tx(sc, &next, queue_index)) {
1268246482Srrs			if (next == NULL) {
1269246482Srrs				drbr_advance(ifp, br);
1270246482Srrs			} else {
1271246482Srrs				drbr_putback(ifp, br, next);
1272231437Sluigi				wq->tx_stats.tx_stops ++;
1273231437Sluigi				ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1274231437Sluigi			}
1275231437Sluigi			break;
1276231437Sluigi		}
1277246482Srrs		drbr_advance(ifp, br);
1278241037Sglebius		ifp->if_obytes += next->m_pkthdr.len;
1279241037Sglebius		if (next->m_flags & M_MCAST)
1280241037Sglebius			ifp->if_omcasts++;
1281231437Sluigi		ETHER_BPF_MTAP(ifp, next);
1282231437Sluigi	}
1283231437Sluigi
1284268156Sluigi	return 0;
1285231437Sluigi}
1286231437Sluigi
1287231437Sluigi
1288231437Sluigi
1289231437Sluigi
1290231437Sluigi/*****************************************************************************
1291231437Sluigi *			    Receive  routines functions 		     *
1292231437Sluigi *****************************************************************************/
1293231437Sluigi
1294231437Sluigistatic void
1295231437Sluigioce_rx(struct oce_rq *rq, uint32_t rqe_idx, struct oce_nic_rx_cqe *cqe)
1296231437Sluigi{
1297231437Sluigi	uint32_t out;
1298231437Sluigi	struct oce_packet_desc *pd;
1299231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1300231437Sluigi	int i, len, frag_len;
1301231437Sluigi	struct mbuf *m = NULL, *tail = NULL;
1302231437Sluigi	uint16_t vtag;
1303231437Sluigi
1304231437Sluigi	len = cqe->u0.s.pkt_size;
1305231437Sluigi	if (!len) {
1306231437Sluigi		/*partial DMA workaround for Lancer*/
1307231437Sluigi		oce_discard_rx_comp(rq, cqe);
1308231437Sluigi		goto exit;
1309231437Sluigi	}
1310231437Sluigi
1311231879Sluigi	 /* Get vlan_tag value */
1312252869Sdelphij	if(IS_BE(sc) || IS_SH(sc))
1313231879Sluigi		vtag = BSWAP_16(cqe->u0.s.vlan_tag);
1314231879Sluigi	else
1315231879Sluigi		vtag = cqe->u0.s.vlan_tag;
1316231879Sluigi
1317231879Sluigi
1318231437Sluigi	for (i = 0; i < cqe->u0.s.num_fragments; i++) {
1319231437Sluigi
1320231437Sluigi		if (rq->packets_out == rq->packets_in) {
1321231437Sluigi			device_printf(sc->dev,
1322231437Sluigi				  "RQ transmit descriptor missing\n");
1323231437Sluigi		}
1324231437Sluigi		out = rq->packets_out + 1;
1325231437Sluigi		if (out == OCE_RQ_PACKET_ARRAY_SIZE)
1326231437Sluigi			out = 0;
1327231437Sluigi		pd = &rq->pckts[rq->packets_out];
1328231437Sluigi		rq->packets_out = out;
1329231437Sluigi
1330231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1331231437Sluigi		bus_dmamap_unload(rq->tag, pd->map);
1332231437Sluigi		rq->pending--;
1333231437Sluigi
1334231437Sluigi		frag_len = (len > rq->cfg.frag_size) ? rq->cfg.frag_size : len;
1335231437Sluigi		pd->mbuf->m_len = frag_len;
1336231437Sluigi
1337231437Sluigi		if (tail != NULL) {
1338231437Sluigi			/* additional fragments */
1339231437Sluigi			pd->mbuf->m_flags &= ~M_PKTHDR;
1340231437Sluigi			tail->m_next = pd->mbuf;
1341231437Sluigi			tail = pd->mbuf;
1342231437Sluigi		} else {
1343231437Sluigi			/* first fragment, fill out much of the packet header */
1344231437Sluigi			pd->mbuf->m_pkthdr.len = len;
1345231437Sluigi			pd->mbuf->m_pkthdr.csum_flags = 0;
1346231437Sluigi			if (IF_CSUM_ENABLED(sc)) {
1347231437Sluigi				if (cqe->u0.s.l4_cksum_pass) {
1348231437Sluigi					pd->mbuf->m_pkthdr.csum_flags |=
1349231437Sluigi					    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
1350231437Sluigi					pd->mbuf->m_pkthdr.csum_data = 0xffff;
1351231437Sluigi				}
1352231437Sluigi				if (cqe->u0.s.ip_cksum_pass) {
1353231879Sluigi					if (!cqe->u0.s.ip_ver) { /* IPV4 */
1354231437Sluigi						pd->mbuf->m_pkthdr.csum_flags |=
1355231437Sluigi						(CSUM_IP_CHECKED|CSUM_IP_VALID);
1356231437Sluigi					}
1357231437Sluigi				}
1358231437Sluigi			}
1359231437Sluigi			m = tail = pd->mbuf;
1360231437Sluigi		}
1361231437Sluigi		pd->mbuf = NULL;
1362231437Sluigi		len -= frag_len;
1363231437Sluigi	}
1364231437Sluigi
1365231437Sluigi	if (m) {
1366231437Sluigi		if (!oce_cqe_portid_valid(sc, cqe)) {
1367231437Sluigi			 m_freem(m);
1368231437Sluigi			 goto exit;
1369231437Sluigi		}
1370231437Sluigi
1371231437Sluigi		m->m_pkthdr.rcvif = sc->ifp;
1372231437Sluigi#if __FreeBSD_version >= 800000
1373252869Sdelphij		if (rq->queue_index)
1374252869Sdelphij			m->m_pkthdr.flowid = (rq->queue_index - 1);
1375252869Sdelphij		else
1376252869Sdelphij			m->m_pkthdr.flowid = rq->queue_index;
1377231437Sluigi		m->m_flags |= M_FLOWID;
1378231437Sluigi#endif
1379231879Sluigi		/* This deternies if vlan tag is Valid */
1380231437Sluigi		if (oce_cqe_vtp_valid(sc, cqe)) {
1381231437Sluigi			if (sc->function_mode & FNM_FLEX10_MODE) {
1382231879Sluigi				/* FLEX10. If QnQ is not set, neglect VLAN */
1383231437Sluigi				if (cqe->u0.s.qnq) {
1384231879Sluigi					m->m_pkthdr.ether_vtag = vtag;
1385231437Sluigi					m->m_flags |= M_VLANTAG;
1386231437Sluigi				}
1387231879Sluigi			} else if (sc->pvid != (vtag & VLAN_VID_MASK))  {
1388231879Sluigi				/* In UMC mode generally pvid will be striped by
1389231879Sluigi				   hw. But in some cases we have seen it comes
1390231879Sluigi				   with pvid. So if pvid == vlan, neglect vlan.
1391231879Sluigi				*/
1392231879Sluigi				m->m_pkthdr.ether_vtag = vtag;
1393231437Sluigi				m->m_flags |= M_VLANTAG;
1394231437Sluigi			}
1395231437Sluigi		}
1396231437Sluigi
1397231437Sluigi		sc->ifp->if_ipackets++;
1398231511Sbz#if defined(INET6) || defined(INET)
1399231437Sluigi		/* Try to queue to LRO */
1400231437Sluigi		if (IF_LRO_ENABLED(sc) &&
1401231437Sluigi		    (cqe->u0.s.ip_cksum_pass) &&
1402231437Sluigi		    (cqe->u0.s.l4_cksum_pass) &&
1403231437Sluigi		    (!cqe->u0.s.ip_ver)       &&
1404231437Sluigi		    (rq->lro.lro_cnt != 0)) {
1405231437Sluigi
1406231437Sluigi			if (tcp_lro_rx(&rq->lro, m, 0) == 0) {
1407231437Sluigi				rq->lro_pkts_queued ++;
1408231437Sluigi				goto post_done;
1409231437Sluigi			}
1410231437Sluigi			/* If LRO posting fails then try to post to STACK */
1411231437Sluigi		}
1412231511Sbz#endif
1413231437Sluigi
1414231437Sluigi		(*sc->ifp->if_input) (sc->ifp, m);
1415231511Sbz#if defined(INET6) || defined(INET)
1416231437Sluigipost_done:
1417231511Sbz#endif
1418231437Sluigi		/* Update rx stats per queue */
1419231437Sluigi		rq->rx_stats.rx_pkts++;
1420231437Sluigi		rq->rx_stats.rx_bytes += cqe->u0.s.pkt_size;
1421231437Sluigi		rq->rx_stats.rx_frags += cqe->u0.s.num_fragments;
1422231437Sluigi		if (cqe->u0.s.pkt_type == OCE_MULTICAST_PACKET)
1423231437Sluigi			rq->rx_stats.rx_mcast_pkts++;
1424231437Sluigi		if (cqe->u0.s.pkt_type == OCE_UNICAST_PACKET)
1425231437Sluigi			rq->rx_stats.rx_ucast_pkts++;
1426231437Sluigi	}
1427231437Sluigiexit:
1428231437Sluigi	return;
1429231437Sluigi}
1430231437Sluigi
1431231437Sluigi
1432231437Sluigistatic void
1433231437Sluigioce_discard_rx_comp(struct oce_rq *rq, struct oce_nic_rx_cqe *cqe)
1434231437Sluigi{
1435231437Sluigi	uint32_t out, i = 0;
1436231437Sluigi	struct oce_packet_desc *pd;
1437231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1438231437Sluigi	int num_frags = cqe->u0.s.num_fragments;
1439231437Sluigi
1440231437Sluigi	for (i = 0; i < num_frags; i++) {
1441231437Sluigi		if (rq->packets_out == rq->packets_in) {
1442231437Sluigi			device_printf(sc->dev,
1443231437Sluigi				"RQ transmit descriptor missing\n");
1444231437Sluigi		}
1445231437Sluigi		out = rq->packets_out + 1;
1446231437Sluigi		if (out == OCE_RQ_PACKET_ARRAY_SIZE)
1447231437Sluigi			out = 0;
1448231437Sluigi		pd = &rq->pckts[rq->packets_out];
1449231437Sluigi		rq->packets_out = out;
1450231437Sluigi
1451231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_POSTWRITE);
1452231437Sluigi		bus_dmamap_unload(rq->tag, pd->map);
1453231437Sluigi		rq->pending--;
1454231437Sluigi		m_freem(pd->mbuf);
1455231437Sluigi	}
1456231437Sluigi
1457231437Sluigi}
1458231437Sluigi
1459231437Sluigi
1460231437Sluigistatic int
1461231437Sluigioce_cqe_vtp_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
1462231437Sluigi{
1463231437Sluigi	struct oce_nic_rx_cqe_v1 *cqe_v1;
1464231437Sluigi	int vtp = 0;
1465231437Sluigi
1466231437Sluigi	if (sc->be3_native) {
1467231437Sluigi		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1468231437Sluigi		vtp =  cqe_v1->u0.s.vlan_tag_present;
1469231879Sluigi	} else
1470231437Sluigi		vtp = cqe->u0.s.vlan_tag_present;
1471231437Sluigi
1472231437Sluigi	return vtp;
1473231437Sluigi
1474231437Sluigi}
1475231437Sluigi
1476231437Sluigi
1477231437Sluigistatic int
1478231437Sluigioce_cqe_portid_valid(POCE_SOFTC sc, struct oce_nic_rx_cqe *cqe)
1479231437Sluigi{
1480231437Sluigi	struct oce_nic_rx_cqe_v1 *cqe_v1;
1481231437Sluigi	int port_id = 0;
1482231437Sluigi
1483252869Sdelphij	if (sc->be3_native && (IS_BE(sc) || IS_SH(sc))) {
1484231437Sluigi		cqe_v1 = (struct oce_nic_rx_cqe_v1 *)cqe;
1485231437Sluigi		port_id =  cqe_v1->u0.s.port;
1486231437Sluigi		if (sc->port_id != port_id)
1487231437Sluigi			return 0;
1488231437Sluigi	} else
1489231437Sluigi		;/* For BE3 legacy and Lancer this is dummy */
1490231437Sluigi
1491231437Sluigi	return 1;
1492231437Sluigi
1493231437Sluigi}
1494231437Sluigi
1495231511Sbz#if defined(INET6) || defined(INET)
1496231437Sluigistatic void
1497231437Sluigioce_rx_flush_lro(struct oce_rq *rq)
1498231437Sluigi{
1499231437Sluigi	struct lro_ctrl	*lro = &rq->lro;
1500231437Sluigi	struct lro_entry *queued;
1501231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1502231437Sluigi
1503231437Sluigi	if (!IF_LRO_ENABLED(sc))
1504231437Sluigi		return;
1505231437Sluigi
1506231437Sluigi	while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) {
1507231437Sluigi		SLIST_REMOVE_HEAD(&lro->lro_active, next);
1508231437Sluigi		tcp_lro_flush(lro, queued);
1509231437Sluigi	}
1510231437Sluigi	rq->lro_pkts_queued = 0;
1511231437Sluigi
1512231437Sluigi	return;
1513231437Sluigi}
1514231437Sluigi
1515231437Sluigi
1516231437Sluigistatic int
1517231437Sluigioce_init_lro(POCE_SOFTC sc)
1518231437Sluigi{
1519231437Sluigi	struct lro_ctrl *lro = NULL;
1520231437Sluigi	int i = 0, rc = 0;
1521231437Sluigi
1522231437Sluigi	for (i = 0; i < sc->nrqs; i++) {
1523231437Sluigi		lro = &sc->rq[i]->lro;
1524231437Sluigi		rc = tcp_lro_init(lro);
1525231437Sluigi		if (rc != 0) {
1526231437Sluigi			device_printf(sc->dev, "LRO init failed\n");
1527231437Sluigi			return rc;
1528231437Sluigi		}
1529231437Sluigi		lro->ifp = sc->ifp;
1530231437Sluigi	}
1531231437Sluigi
1532231437Sluigi	return rc;
1533231437Sluigi}
1534231437Sluigi
1535231879Sluigi
1536231437Sluigivoid
1537231437Sluigioce_free_lro(POCE_SOFTC sc)
1538231437Sluigi{
1539231437Sluigi	struct lro_ctrl *lro = NULL;
1540231437Sluigi	int i = 0;
1541231437Sluigi
1542231437Sluigi	for (i = 0; i < sc->nrqs; i++) {
1543231437Sluigi		lro = &sc->rq[i]->lro;
1544231437Sluigi		if (lro)
1545231437Sluigi			tcp_lro_free(lro);
1546231437Sluigi	}
1547231437Sluigi}
1548247880Sdelphij#endif
1549231437Sluigi
1550231437Sluigiint
1551231437Sluigioce_alloc_rx_bufs(struct oce_rq *rq, int count)
1552231437Sluigi{
1553231437Sluigi	POCE_SOFTC sc = (POCE_SOFTC) rq->parent;
1554231437Sluigi	int i, in, rc;
1555231437Sluigi	struct oce_packet_desc *pd;
1556231437Sluigi	bus_dma_segment_t segs[6];
1557231437Sluigi	int nsegs, added = 0;
1558231437Sluigi	struct oce_nic_rqe *rqe;
1559231437Sluigi	pd_rxulp_db_t rxdb_reg;
1560231437Sluigi
1561247880Sdelphij	bzero(&rxdb_reg, sizeof(pd_rxulp_db_t));
1562231437Sluigi	for (i = 0; i < count; i++) {
1563231437Sluigi		in = rq->packets_in + 1;
1564231437Sluigi		if (in == OCE_RQ_PACKET_ARRAY_SIZE)
1565231437Sluigi			in = 0;
1566231437Sluigi		if (in == rq->packets_out)
1567231437Sluigi			break;	/* no more room */
1568231437Sluigi
1569231437Sluigi		pd = &rq->pckts[rq->packets_in];
1570243857Sglebius		pd->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1571231437Sluigi		if (pd->mbuf == NULL)
1572231437Sluigi			break;
1573231437Sluigi
1574231437Sluigi		pd->mbuf->m_len = pd->mbuf->m_pkthdr.len = MCLBYTES;
1575231437Sluigi		rc = bus_dmamap_load_mbuf_sg(rq->tag,
1576231437Sluigi					     pd->map,
1577231437Sluigi					     pd->mbuf,
1578231437Sluigi					     segs, &nsegs, BUS_DMA_NOWAIT);
1579231437Sluigi		if (rc) {
1580231437Sluigi			m_free(pd->mbuf);
1581231437Sluigi			break;
1582231437Sluigi		}
1583231437Sluigi
1584231437Sluigi		if (nsegs != 1) {
1585231437Sluigi			i--;
1586231437Sluigi			continue;
1587231437Sluigi		}
1588231437Sluigi
1589231437Sluigi		rq->packets_in = in;
1590231437Sluigi		bus_dmamap_sync(rq->tag, pd->map, BUS_DMASYNC_PREREAD);
1591231437Sluigi
1592231437Sluigi		rqe = RING_GET_PRODUCER_ITEM_VA(rq->ring, struct oce_nic_rqe);
1593231437Sluigi		rqe->u0.s.frag_pa_hi = ADDR_HI(segs[0].ds_addr);
1594231437Sluigi		rqe->u0.s.frag_pa_lo = ADDR_LO(segs[0].ds_addr);
1595231437Sluigi		DW_SWAP(u32ptr(rqe), sizeof(struct oce_nic_rqe));
1596231437Sluigi		RING_PUT(rq->ring, 1);
1597231437Sluigi		added++;
1598231437Sluigi		rq->pending++;
1599231437Sluigi	}
1600231437Sluigi	if (added != 0) {
1601231437Sluigi		for (i = added / OCE_MAX_RQ_POSTS; i > 0; i--) {
1602231437Sluigi			rxdb_reg.bits.num_posted = OCE_MAX_RQ_POSTS;
1603231437Sluigi			rxdb_reg.bits.qid = rq->rq_id;
1604231437Sluigi			OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1605231437Sluigi			added -= OCE_MAX_RQ_POSTS;
1606231437Sluigi		}
1607231437Sluigi		if (added > 0) {
1608231437Sluigi			rxdb_reg.bits.qid = rq->rq_id;
1609231437Sluigi			rxdb_reg.bits.num_posted = added;
1610231437Sluigi			OCE_WRITE_REG32(sc, db, PD_RXULP_DB, rxdb_reg.dw0);
1611231437Sluigi		}
1612231437Sluigi	}
1613231437Sluigi
1614231437Sluigi	return 0;
1615231437Sluigi}
1616231437Sluigi
1617231437Sluigi
1618231437Sluigi/* Handle the Completion Queue for receive */
1619231437Sluigiuint16_t
1620231437Sluigioce_rq_handler(void *arg)
1621231437Sluigi{
1622231437Sluigi	struct oce_rq *rq = (struct oce_rq *)arg;
1623231437Sluigi	struct oce_cq *cq = rq->cq;
1624231437Sluigi	POCE_SOFTC sc = rq->parent;
1625231437Sluigi	struct oce_nic_rx_cqe *cqe;
1626231437Sluigi	int num_cqes = 0, rq_buffers_used = 0;
1627231437Sluigi
1628231437Sluigi
1629231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
1630231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1631231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
1632231437Sluigi	while (cqe->u0.dw[2]) {
1633231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_rq_cqe));
1634231437Sluigi
1635231437Sluigi		RING_GET(rq->ring, 1);
1636231437Sluigi		if (cqe->u0.s.error == 0) {
1637231437Sluigi			oce_rx(rq, cqe->u0.s.frag_index, cqe);
1638231437Sluigi		} else {
1639231437Sluigi			rq->rx_stats.rxcp_err++;
1640231437Sluigi			sc->ifp->if_ierrors++;
1641247880Sdelphij			/* Post L3/L4 errors to stack.*/
1642247880Sdelphij			oce_rx(rq, cqe->u0.s.frag_index, cqe);
1643231437Sluigi		}
1644231437Sluigi		rq->rx_stats.rx_compl++;
1645231437Sluigi		cqe->u0.dw[2] = 0;
1646231437Sluigi
1647231511Sbz#if defined(INET6) || defined(INET)
1648231437Sluigi		if (IF_LRO_ENABLED(sc) && rq->lro_pkts_queued >= 16) {
1649231437Sluigi			oce_rx_flush_lro(rq);
1650231437Sluigi		}
1651231511Sbz#endif
1652231437Sluigi
1653231437Sluigi		RING_GET(cq->ring, 1);
1654231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
1655231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
1656231437Sluigi		cqe =
1657231437Sluigi		    RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_rx_cqe);
1658231437Sluigi		num_cqes++;
1659231437Sluigi		if (num_cqes >= (IS_XE201(sc) ? 8 : oce_max_rsp_handled))
1660231437Sluigi			break;
1661231437Sluigi	}
1662231879Sluigi
1663231511Sbz#if defined(INET6) || defined(INET)
1664231437Sluigi	if (IF_LRO_ENABLED(sc))
1665231437Sluigi		oce_rx_flush_lro(rq);
1666231511Sbz#endif
1667231437Sluigi
1668231437Sluigi	if (num_cqes) {
1669231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
1670231437Sluigi		rq_buffers_used = OCE_RQ_PACKET_ARRAY_SIZE - rq->pending;
1671231437Sluigi		if (rq_buffers_used > 1)
1672231437Sluigi			oce_alloc_rx_bufs(rq, (rq_buffers_used - 1));
1673231437Sluigi	}
1674231437Sluigi
1675231437Sluigi	return 0;
1676231437Sluigi
1677231437Sluigi}
1678231437Sluigi
1679231437Sluigi
1680231437Sluigi
1681231437Sluigi
1682231437Sluigi/*****************************************************************************
1683231437Sluigi *		   Helper function prototypes in this file 		     *
1684231437Sluigi *****************************************************************************/
1685231437Sluigi
1686231437Sluigistatic int
1687231437Sluigioce_attach_ifp(POCE_SOFTC sc)
1688231437Sluigi{
1689231437Sluigi
1690231437Sluigi	sc->ifp = if_alloc(IFT_ETHER);
1691231437Sluigi	if (!sc->ifp)
1692231437Sluigi		return ENOMEM;
1693231437Sluigi
1694231437Sluigi	ifmedia_init(&sc->media, IFM_IMASK, oce_media_change, oce_media_status);
1695231437Sluigi	ifmedia_add(&sc->media, IFM_ETHER | IFM_AUTO, 0, NULL);
1696231437Sluigi	ifmedia_set(&sc->media, IFM_ETHER | IFM_AUTO);
1697231437Sluigi
1698231437Sluigi	sc->ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
1699231437Sluigi	sc->ifp->if_ioctl = oce_ioctl;
1700231437Sluigi	sc->ifp->if_start = oce_start;
1701231437Sluigi	sc->ifp->if_init = oce_init;
1702231437Sluigi	sc->ifp->if_mtu = ETHERMTU;
1703231437Sluigi	sc->ifp->if_softc = sc;
1704231437Sluigi#if __FreeBSD_version >= 800000
1705231437Sluigi	sc->ifp->if_transmit = oce_multiq_start;
1706231437Sluigi	sc->ifp->if_qflush = oce_multiq_flush;
1707231437Sluigi#endif
1708231437Sluigi
1709231437Sluigi	if_initname(sc->ifp,
1710231437Sluigi		    device_get_name(sc->dev), device_get_unit(sc->dev));
1711231437Sluigi
1712231437Sluigi	sc->ifp->if_snd.ifq_drv_maxlen = OCE_MAX_TX_DESC - 1;
1713231437Sluigi	IFQ_SET_MAXLEN(&sc->ifp->if_snd, sc->ifp->if_snd.ifq_drv_maxlen);
1714231437Sluigi	IFQ_SET_READY(&sc->ifp->if_snd);
1715231437Sluigi
1716231437Sluigi	sc->ifp->if_hwassist = OCE_IF_HWASSIST;
1717231437Sluigi	sc->ifp->if_hwassist |= CSUM_TSO;
1718231437Sluigi	sc->ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP);
1719231437Sluigi
1720231437Sluigi	sc->ifp->if_capabilities = OCE_IF_CAPABILITIES;
1721231437Sluigi	sc->ifp->if_capabilities |= IFCAP_HWCSUM;
1722231437Sluigi	sc->ifp->if_capabilities |= IFCAP_VLAN_HWFILTER;
1723231879Sluigi
1724231511Sbz#if defined(INET6) || defined(INET)
1725231511Sbz	sc->ifp->if_capabilities |= IFCAP_TSO;
1726231437Sluigi	sc->ifp->if_capabilities |= IFCAP_LRO;
1727231879Sluigi	sc->ifp->if_capabilities |= IFCAP_VLAN_HWTSO;
1728231511Sbz#endif
1729231437Sluigi
1730231437Sluigi	sc->ifp->if_capenable = sc->ifp->if_capabilities;
1731263102Sglebius	sc->ifp->if_baudrate = IF_Gbps(10);
1732231437Sluigi
1733257007Sdelphij#if __FreeBSD_version >= 1000000
1734257007Sdelphij	sc->ifp->if_hw_tsomax = OCE_MAX_TSO_SIZE;
1735257007Sdelphij#endif
1736257007Sdelphij
1737231437Sluigi	ether_ifattach(sc->ifp, sc->macaddr.mac_addr);
1738231437Sluigi
1739231437Sluigi	return 0;
1740231437Sluigi}
1741231437Sluigi
1742231437Sluigi
1743231437Sluigistatic void
1744231437Sluigioce_add_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
1745231437Sluigi{
1746231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1747231437Sluigi
1748231437Sluigi	if (ifp->if_softc !=  arg)
1749231437Sluigi		return;
1750231437Sluigi	if ((vtag == 0) || (vtag > 4095))
1751231437Sluigi		return;
1752231437Sluigi
1753231437Sluigi	sc->vlan_tag[vtag] = 1;
1754231437Sluigi	sc->vlans_added++;
1755257007Sdelphij	if (sc->vlans_added <= (sc->max_vlans + 1))
1756257007Sdelphij		oce_vid_config(sc);
1757231437Sluigi}
1758231437Sluigi
1759231437Sluigi
1760231437Sluigistatic void
1761231437Sluigioce_del_vlan(void *arg, struct ifnet *ifp, uint16_t vtag)
1762231437Sluigi{
1763231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1764231437Sluigi
1765231437Sluigi	if (ifp->if_softc !=  arg)
1766231437Sluigi		return;
1767231437Sluigi	if ((vtag == 0) || (vtag > 4095))
1768231437Sluigi		return;
1769231437Sluigi
1770231437Sluigi	sc->vlan_tag[vtag] = 0;
1771231437Sluigi	sc->vlans_added--;
1772231437Sluigi	oce_vid_config(sc);
1773231437Sluigi}
1774231437Sluigi
1775231437Sluigi
1776231437Sluigi/*
1777231437Sluigi * A max of 64 vlans can be configured in BE. If the user configures
1778231437Sluigi * more, place the card in vlan promiscuous mode.
1779231437Sluigi */
1780231437Sluigistatic int
1781231437Sluigioce_vid_config(POCE_SOFTC sc)
1782231437Sluigi{
1783231437Sluigi	struct normal_vlan vtags[MAX_VLANFILTER_SIZE];
1784231437Sluigi	uint16_t ntags = 0, i;
1785231437Sluigi	int status = 0;
1786231437Sluigi
1787231437Sluigi	if ((sc->vlans_added <= MAX_VLANFILTER_SIZE) &&
1788231437Sluigi			(sc->ifp->if_capenable & IFCAP_VLAN_HWFILTER)) {
1789231437Sluigi		for (i = 0; i < MAX_VLANS; i++) {
1790231437Sluigi			if (sc->vlan_tag[i]) {
1791231437Sluigi				vtags[ntags].vtag = i;
1792231437Sluigi				ntags++;
1793231437Sluigi			}
1794231437Sluigi		}
1795231437Sluigi		if (ntags)
1796231437Sluigi			status = oce_config_vlan(sc, (uint8_t) sc->if_id,
1797231437Sluigi						vtags, ntags, 1, 0);
1798231437Sluigi	} else
1799231437Sluigi		status = oce_config_vlan(sc, (uint8_t) sc->if_id,
1800231437Sluigi					 	NULL, 0, 1, 1);
1801231437Sluigi	return status;
1802231437Sluigi}
1803231437Sluigi
1804231437Sluigi
1805231437Sluigistatic void
1806231437Sluigioce_mac_addr_set(POCE_SOFTC sc)
1807231437Sluigi{
1808231437Sluigi	uint32_t old_pmac_id = sc->pmac_id;
1809231437Sluigi	int status = 0;
1810231437Sluigi
1811231437Sluigi
1812231437Sluigi	status = bcmp((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
1813231437Sluigi			 sc->macaddr.size_of_struct);
1814231437Sluigi	if (!status)
1815231437Sluigi		return;
1816231437Sluigi
1817231437Sluigi	status = oce_mbox_macaddr_add(sc, (uint8_t *)(IF_LLADDR(sc->ifp)),
1818231437Sluigi					sc->if_id, &sc->pmac_id);
1819231437Sluigi	if (!status) {
1820231437Sluigi		status = oce_mbox_macaddr_del(sc, sc->if_id, old_pmac_id);
1821231437Sluigi		bcopy((IF_LLADDR(sc->ifp)), sc->macaddr.mac_addr,
1822231437Sluigi				 sc->macaddr.size_of_struct);
1823231437Sluigi	}
1824231437Sluigi	if (status)
1825231437Sluigi		device_printf(sc->dev, "Failed update macaddress\n");
1826231437Sluigi
1827231437Sluigi}
1828231437Sluigi
1829231437Sluigi
1830231437Sluigistatic int
1831231437Sluigioce_handle_passthrough(struct ifnet *ifp, caddr_t data)
1832231437Sluigi{
1833231437Sluigi	POCE_SOFTC sc = ifp->if_softc;
1834231437Sluigi	struct ifreq *ifr = (struct ifreq *)data;
1835231437Sluigi	int rc = ENXIO;
1836231437Sluigi	char cookie[32] = {0};
1837231437Sluigi	void *priv_data = (void *)ifr->ifr_data;
1838231437Sluigi	void *ioctl_ptr;
1839231437Sluigi	uint32_t req_size;
1840231437Sluigi	struct mbx_hdr req;
1841231437Sluigi	OCE_DMA_MEM dma_mem;
1842247880Sdelphij	struct mbx_common_get_cntl_attr *fw_cmd;
1843231437Sluigi
1844231437Sluigi	if (copyin(priv_data, cookie, strlen(IOCTL_COOKIE)))
1845231437Sluigi		return EFAULT;
1846247880Sdelphij
1847231437Sluigi	if (memcmp(cookie, IOCTL_COOKIE, strlen(IOCTL_COOKIE)))
1848231437Sluigi		return EINVAL;
1849247880Sdelphij
1850231437Sluigi	ioctl_ptr = (char *)priv_data + strlen(IOCTL_COOKIE);
1851231437Sluigi	if (copyin(ioctl_ptr, &req, sizeof(struct mbx_hdr)))
1852231437Sluigi		return EFAULT;
1853247880Sdelphij
1854231437Sluigi	req_size = le32toh(req.u0.req.request_length);
1855231437Sluigi	if (req_size > 65536)
1856231437Sluigi		return EINVAL;
1857231437Sluigi
1858231437Sluigi	req_size += sizeof(struct mbx_hdr);
1859231437Sluigi	rc = oce_dma_alloc(sc, req_size, &dma_mem, 0);
1860231437Sluigi	if (rc)
1861231437Sluigi		return ENOMEM;
1862231437Sluigi
1863231437Sluigi	if (copyin(ioctl_ptr, OCE_DMAPTR(&dma_mem,char), req_size)) {
1864231437Sluigi		rc = EFAULT;
1865231437Sluigi		goto dma_free;
1866231437Sluigi	}
1867231437Sluigi
1868231437Sluigi	rc = oce_pass_through_mbox(sc, &dma_mem, req_size);
1869231437Sluigi	if (rc) {
1870231437Sluigi		rc = EIO;
1871231437Sluigi		goto dma_free;
1872231437Sluigi	}
1873231437Sluigi
1874231437Sluigi	if (copyout(OCE_DMAPTR(&dma_mem,char), ioctl_ptr, req_size))
1875231437Sluigi		rc =  EFAULT;
1876231437Sluigi
1877247880Sdelphij	/*
1878247880Sdelphij	   firmware is filling all the attributes for this ioctl except
1879247880Sdelphij	   the driver version..so fill it
1880247880Sdelphij	 */
1881247880Sdelphij	if(req.u0.rsp.opcode == OPCODE_COMMON_GET_CNTL_ATTRIBUTES) {
1882247880Sdelphij		fw_cmd = (struct mbx_common_get_cntl_attr *) ioctl_ptr;
1883247880Sdelphij		strncpy(fw_cmd->params.rsp.cntl_attr_info.hba_attr.drv_ver_str,
1884247880Sdelphij			COMPONENT_REVISION, strlen(COMPONENT_REVISION));
1885247880Sdelphij	}
1886247880Sdelphij
1887231437Sluigidma_free:
1888231437Sluigi	oce_dma_free(sc, &dma_mem);
1889231437Sluigi	return rc;
1890231437Sluigi
1891231437Sluigi}
1892231437Sluigi
1893247880Sdelphijstatic void
1894247880Sdelphijoce_eqd_set_periodic(POCE_SOFTC sc)
1895247880Sdelphij{
1896247880Sdelphij	struct oce_set_eqd set_eqd[OCE_MAX_EQ];
1897247880Sdelphij	struct oce_aic_obj *aic;
1898247880Sdelphij	struct oce_eq *eqo;
1899247880Sdelphij	uint64_t now = 0, delta;
1900247880Sdelphij	int eqd, i, num = 0;
1901247880Sdelphij	uint32_t ips = 0;
1902247880Sdelphij	int tps;
1903231437Sluigi
1904247880Sdelphij	for (i = 0 ; i < sc->neqs; i++) {
1905247880Sdelphij		eqo = sc->eq[i];
1906247880Sdelphij		aic = &sc->aic_obj[i];
1907247880Sdelphij		/* When setting the static eq delay from the user space */
1908247880Sdelphij		if (!aic->enable) {
1909247880Sdelphij			eqd = aic->et_eqd;
1910247880Sdelphij			goto modify_eqd;
1911247880Sdelphij		}
1912247880Sdelphij
1913247880Sdelphij		now = ticks;
1914247880Sdelphij
1915247880Sdelphij		/* Over flow check */
1916247880Sdelphij		if ((now < aic->ticks) || (eqo->intr < aic->intr_prev))
1917247880Sdelphij			goto done;
1918247880Sdelphij
1919247880Sdelphij		delta = now - aic->ticks;
1920247880Sdelphij		tps = delta/hz;
1921247880Sdelphij
1922247880Sdelphij		/* Interrupt rate based on elapsed ticks */
1923247880Sdelphij		if(tps)
1924247880Sdelphij			ips = (uint32_t)(eqo->intr - aic->intr_prev) / tps;
1925247880Sdelphij
1926247880Sdelphij		if (ips > INTR_RATE_HWM)
1927247880Sdelphij			eqd = aic->cur_eqd + 20;
1928247880Sdelphij		else if (ips < INTR_RATE_LWM)
1929247880Sdelphij			eqd = aic->cur_eqd / 2;
1930247880Sdelphij		else
1931247880Sdelphij			goto done;
1932247880Sdelphij
1933247880Sdelphij		if (eqd < 10)
1934247880Sdelphij			eqd = 0;
1935247880Sdelphij
1936247880Sdelphij		/* Make sure that the eq delay is in the known range */
1937247880Sdelphij		eqd = min(eqd, aic->max_eqd);
1938247880Sdelphij		eqd = max(eqd, aic->min_eqd);
1939247880Sdelphij
1940247880Sdelphijmodify_eqd:
1941247880Sdelphij		if (eqd != aic->cur_eqd) {
1942247880Sdelphij			set_eqd[num].delay_multiplier = (eqd * 65)/100;
1943247880Sdelphij			set_eqd[num].eq_id = eqo->eq_id;
1944247880Sdelphij			aic->cur_eqd = eqd;
1945247880Sdelphij			num++;
1946247880Sdelphij		}
1947247880Sdelphijdone:
1948247880Sdelphij		aic->intr_prev = eqo->intr;
1949247880Sdelphij		aic->ticks = now;
1950247880Sdelphij	}
1951247880Sdelphij
1952247880Sdelphij	/* Is there atleast one eq that needs to be modified? */
1953247880Sdelphij	if(num)
1954247880Sdelphij		oce_mbox_eqd_modify_periodic(sc, set_eqd, num);
1955247880Sdelphij}
1956247880Sdelphij
1957257007Sdelphijstatic void oce_detect_hw_error(POCE_SOFTC sc)
1958257007Sdelphij{
1959257007Sdelphij
1960257007Sdelphij	uint32_t ue_low = 0, ue_high = 0, ue_low_mask = 0, ue_high_mask = 0;
1961257007Sdelphij	uint32_t sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
1962257007Sdelphij	uint32_t i;
1963257007Sdelphij
1964257007Sdelphij	if (sc->hw_error)
1965257007Sdelphij		return;
1966257007Sdelphij
1967257007Sdelphij	if (IS_XE201(sc)) {
1968257007Sdelphij		sliport_status = OCE_READ_REG32(sc, db, SLIPORT_STATUS_OFFSET);
1969257007Sdelphij		if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
1970257007Sdelphij			sliport_err1 = OCE_READ_REG32(sc, db, SLIPORT_ERROR1_OFFSET);
1971257007Sdelphij			sliport_err2 = OCE_READ_REG32(sc, db, SLIPORT_ERROR2_OFFSET);
1972257007Sdelphij		}
1973257007Sdelphij	} else {
1974257007Sdelphij		ue_low = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW);
1975257007Sdelphij		ue_high = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HIGH);
1976257007Sdelphij		ue_low_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_LOW_MASK);
1977257007Sdelphij		ue_high_mask = OCE_READ_REG32(sc, devcfg, PCICFG_UE_STATUS_HI_MASK);
1978257007Sdelphij
1979257007Sdelphij		ue_low = (ue_low & ~ue_low_mask);
1980257007Sdelphij		ue_high = (ue_high & ~ue_high_mask);
1981257007Sdelphij	}
1982257007Sdelphij
1983257007Sdelphij	/* On certain platforms BE hardware can indicate spurious UEs.
1984257007Sdelphij	 * Allow the h/w to stop working completely in case of a real UE.
1985257007Sdelphij	 * Hence not setting the hw_error for UE detection.
1986257007Sdelphij	 */
1987257007Sdelphij	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
1988257007Sdelphij		sc->hw_error = TRUE;
1989257007Sdelphij		device_printf(sc->dev, "Error detected in the card\n");
1990257007Sdelphij	}
1991257007Sdelphij
1992257007Sdelphij	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
1993257007Sdelphij		device_printf(sc->dev,
1994257007Sdelphij				"ERR: sliport status 0x%x\n", sliport_status);
1995257007Sdelphij		device_printf(sc->dev,
1996257007Sdelphij				"ERR: sliport error1 0x%x\n", sliport_err1);
1997257007Sdelphij		device_printf(sc->dev,
1998257007Sdelphij				"ERR: sliport error2 0x%x\n", sliport_err2);
1999257007Sdelphij	}
2000257007Sdelphij
2001257007Sdelphij	if (ue_low) {
2002257007Sdelphij		for (i = 0; ue_low; ue_low >>= 1, i++) {
2003257007Sdelphij			if (ue_low & 1)
2004257007Sdelphij				device_printf(sc->dev, "UE: %s bit set\n",
2005257007Sdelphij							ue_status_low_desc[i]);
2006257007Sdelphij		}
2007257007Sdelphij	}
2008257007Sdelphij
2009257007Sdelphij	if (ue_high) {
2010257007Sdelphij		for (i = 0; ue_high; ue_high >>= 1, i++) {
2011257007Sdelphij			if (ue_high & 1)
2012257007Sdelphij				device_printf(sc->dev, "UE: %s bit set\n",
2013257007Sdelphij							ue_status_hi_desc[i]);
2014257007Sdelphij		}
2015257007Sdelphij	}
2016257007Sdelphij
2017257007Sdelphij}
2018257007Sdelphij
2019257007Sdelphij
2020231437Sluigistatic void
2021231437Sluigioce_local_timer(void *arg)
2022231437Sluigi{
2023231437Sluigi	POCE_SOFTC sc = arg;
2024231437Sluigi	int i = 0;
2025231437Sluigi
2026257007Sdelphij	oce_detect_hw_error(sc);
2027231437Sluigi	oce_refresh_nic_stats(sc);
2028231437Sluigi	oce_refresh_queue_stats(sc);
2029231437Sluigi	oce_mac_addr_set(sc);
2030231437Sluigi
2031231437Sluigi	/* TX Watch Dog*/
2032231437Sluigi	for (i = 0; i < sc->nwqs; i++)
2033231437Sluigi		oce_tx_restart(sc, sc->wq[i]);
2034231437Sluigi
2035247880Sdelphij	/* calculate and set the eq delay for optimal interrupt rate */
2036252869Sdelphij	if (IS_BE(sc) || IS_SH(sc))
2037247880Sdelphij		oce_eqd_set_periodic(sc);
2038247880Sdelphij
2039231437Sluigi	callout_reset(&sc->timer, hz, oce_local_timer, sc);
2040231437Sluigi}
2041231437Sluigi
2042231437Sluigi
2043246799Sjpaetzel/* NOTE : This should only be called holding
2044246799Sjpaetzel *        DEVICE_LOCK.
2045257007Sdelphij */
2046231437Sluigistatic void
2047231437Sluigioce_if_deactivate(POCE_SOFTC sc)
2048231437Sluigi{
2049231437Sluigi	int i, mtime = 0;
2050231437Sluigi	int wait_req = 0;
2051231437Sluigi	struct oce_rq *rq;
2052231437Sluigi	struct oce_wq *wq;
2053231437Sluigi	struct oce_eq *eq;
2054231437Sluigi
2055231437Sluigi	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2056231437Sluigi
2057231437Sluigi	/*Wait for max of 400ms for TX completions to be done */
2058231437Sluigi	while (mtime < 400) {
2059231437Sluigi		wait_req = 0;
2060231437Sluigi		for_all_wq_queues(sc, wq, i) {
2061231437Sluigi			if (wq->ring->num_used) {
2062231437Sluigi				wait_req = 1;
2063231437Sluigi				DELAY(1);
2064231437Sluigi				break;
2065231437Sluigi			}
2066231437Sluigi		}
2067231437Sluigi		mtime += 1;
2068231437Sluigi		if (!wait_req)
2069231437Sluigi			break;
2070231437Sluigi	}
2071231437Sluigi
2072231437Sluigi	/* Stop intrs and finish any bottom halves pending */
2073231437Sluigi	oce_hw_intr_disable(sc);
2074231437Sluigi
2075247880Sdelphij	/* Since taskqueue_drain takes a Gaint Lock, We should not acquire
2076247880Sdelphij	   any other lock. So unlock device lock and require after
2077247880Sdelphij	   completing taskqueue_drain.
2078247880Sdelphij	*/
2079247880Sdelphij	UNLOCK(&sc->dev_lock);
2080231437Sluigi	for (i = 0; i < sc->intr_count; i++) {
2081231437Sluigi		if (sc->intrs[i].tq != NULL) {
2082231437Sluigi			taskqueue_drain(sc->intrs[i].tq, &sc->intrs[i].task);
2083231437Sluigi		}
2084231437Sluigi	}
2085247880Sdelphij	LOCK(&sc->dev_lock);
2086231437Sluigi
2087231437Sluigi	/* Delete RX queue in card with flush param */
2088231437Sluigi	oce_stop_rx(sc);
2089231437Sluigi
2090231437Sluigi	/* Invalidate any pending cq and eq entries*/
2091231437Sluigi	for_all_evnt_queues(sc, eq, i)
2092231437Sluigi		oce_drain_eq(eq);
2093231437Sluigi	for_all_rq_queues(sc, rq, i)
2094231437Sluigi		oce_drain_rq_cq(rq);
2095231437Sluigi	for_all_wq_queues(sc, wq, i)
2096231437Sluigi		oce_drain_wq_cq(wq);
2097231437Sluigi
2098231437Sluigi	/* But still we need to get MCC aync events.
2099231437Sluigi	   So enable intrs and also arm first EQ
2100247880Sdelphij	*/
2101231437Sluigi	oce_hw_intr_enable(sc);
2102231437Sluigi	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
2103231437Sluigi
2104231437Sluigi	DELAY(10);
2105231437Sluigi}
2106231437Sluigi
2107231437Sluigi
2108231437Sluigistatic void
2109231437Sluigioce_if_activate(POCE_SOFTC sc)
2110231437Sluigi{
2111231437Sluigi	struct oce_eq *eq;
2112231437Sluigi	struct oce_rq *rq;
2113231437Sluigi	struct oce_wq *wq;
2114231437Sluigi	int i, rc = 0;
2115231437Sluigi
2116231437Sluigi	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
2117231437Sluigi
2118231437Sluigi	oce_hw_intr_disable(sc);
2119231437Sluigi
2120231437Sluigi	oce_start_rx(sc);
2121231437Sluigi
2122231437Sluigi	for_all_rq_queues(sc, rq, i) {
2123231437Sluigi		rc = oce_start_rq(rq);
2124231437Sluigi		if (rc)
2125231437Sluigi			device_printf(sc->dev, "Unable to start RX\n");
2126231437Sluigi	}
2127231437Sluigi
2128231437Sluigi	for_all_wq_queues(sc, wq, i) {
2129231437Sluigi		rc = oce_start_wq(wq);
2130231437Sluigi		if (rc)
2131231437Sluigi			device_printf(sc->dev, "Unable to start TX\n");
2132231437Sluigi	}
2133231437Sluigi
2134231437Sluigi
2135231437Sluigi	for_all_evnt_queues(sc, eq, i)
2136231437Sluigi		oce_arm_eq(sc, eq->eq_id, 0, TRUE, FALSE);
2137231437Sluigi
2138231437Sluigi	oce_hw_intr_enable(sc);
2139231437Sluigi
2140231437Sluigi}
2141231437Sluigi
2142231879Sluigistatic void
2143231879Sluigiprocess_link_state(POCE_SOFTC sc, struct oce_async_cqe_link_state *acqe)
2144231879Sluigi{
2145231879Sluigi	/* Update Link status */
2146231879Sluigi	if ((acqe->u0.s.link_status & ~ASYNC_EVENT_LOGICAL) ==
2147231879Sluigi	     ASYNC_EVENT_LINK_UP) {
2148231879Sluigi		sc->link_status = ASYNC_EVENT_LINK_UP;
2149231879Sluigi		if_link_state_change(sc->ifp, LINK_STATE_UP);
2150231879Sluigi	} else {
2151231879Sluigi		sc->link_status = ASYNC_EVENT_LINK_DOWN;
2152231879Sluigi		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
2153231879Sluigi	}
2154231879Sluigi}
2155231879Sluigi
2156231879Sluigi
2157231437Sluigi/* Handle the Completion Queue for the Mailbox/Async notifications */
2158231437Sluigiuint16_t
2159231437Sluigioce_mq_handler(void *arg)
2160231437Sluigi{
2161231437Sluigi	struct oce_mq *mq = (struct oce_mq *)arg;
2162231437Sluigi	POCE_SOFTC sc = mq->parent;
2163231437Sluigi	struct oce_cq *cq = mq->cq;
2164231879Sluigi	int num_cqes = 0, evt_type = 0, optype = 0;
2165231437Sluigi	struct oce_mq_cqe *cqe;
2166231437Sluigi	struct oce_async_cqe_link_state *acqe;
2167231879Sluigi	struct oce_async_event_grp5_pvid_state *gcqe;
2168247880Sdelphij	struct oce_async_event_qnq *dbgcqe;
2169231437Sluigi
2170231879Sluigi
2171231437Sluigi	bus_dmamap_sync(cq->ring->dma.tag,
2172231437Sluigi			cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2173231437Sluigi	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
2174231879Sluigi
2175231437Sluigi	while (cqe->u0.dw[3]) {
2176231437Sluigi		DW_SWAP((uint32_t *) cqe, sizeof(oce_mq_cqe));
2177231437Sluigi		if (cqe->u0.s.async_event) {
2178231879Sluigi			evt_type = cqe->u0.s.event_type;
2179231879Sluigi			optype = cqe->u0.s.async_type;
2180231879Sluigi			if (evt_type  == ASYNC_EVENT_CODE_LINK_STATE) {
2181231879Sluigi				/* Link status evt */
2182231879Sluigi				acqe = (struct oce_async_cqe_link_state *)cqe;
2183231879Sluigi				process_link_state(sc, acqe);
2184231879Sluigi			} else if ((evt_type == ASYNC_EVENT_GRP5) &&
2185231879Sluigi				   (optype == ASYNC_EVENT_PVID_STATE)) {
2186231879Sluigi				/* GRP5 PVID */
2187231879Sluigi				gcqe =
2188231879Sluigi				(struct oce_async_event_grp5_pvid_state *)cqe;
2189231879Sluigi				if (gcqe->enabled)
2190231879Sluigi					sc->pvid = gcqe->tag & VLAN_VID_MASK;
2191231879Sluigi				else
2192231879Sluigi					sc->pvid = 0;
2193231879Sluigi
2194231437Sluigi			}
2195247880Sdelphij			else if(evt_type == ASYNC_EVENT_CODE_DEBUG &&
2196247880Sdelphij				optype == ASYNC_EVENT_DEBUG_QNQ) {
2197247880Sdelphij				dbgcqe =
2198247880Sdelphij				(struct oce_async_event_qnq *)cqe;
2199247880Sdelphij				if(dbgcqe->valid)
2200247880Sdelphij					sc->qnqid = dbgcqe->vlan_tag;
2201247880Sdelphij				sc->qnq_debug_event = TRUE;
2202247880Sdelphij			}
2203231437Sluigi		}
2204231437Sluigi		cqe->u0.dw[3] = 0;
2205231437Sluigi		RING_GET(cq->ring, 1);
2206231437Sluigi		bus_dmamap_sync(cq->ring->dma.tag,
2207231437Sluigi				cq->ring->dma.map, BUS_DMASYNC_POSTWRITE);
2208231437Sluigi		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_mq_cqe);
2209231437Sluigi		num_cqes++;
2210231437Sluigi	}
2211231437Sluigi
2212231437Sluigi	if (num_cqes)
2213231437Sluigi		oce_arm_cq(sc, cq->cq_id, num_cqes, FALSE);
2214231437Sluigi
2215231437Sluigi	return 0;
2216231437Sluigi}
2217231437Sluigi
2218231437Sluigi
2219231437Sluigistatic void
2220231437Sluigisetup_max_queues_want(POCE_SOFTC sc)
2221231437Sluigi{
2222231437Sluigi	/* Check if it is FLEX machine. Is so dont use RSS */
2223231437Sluigi	if ((sc->function_mode & FNM_FLEX10_MODE) ||
2224231879Sluigi	    (sc->function_mode & FNM_UMC_MODE)    ||
2225231879Sluigi	    (sc->function_mode & FNM_VNIC_MODE)	  ||
2226252869Sdelphij	    (!is_rss_enabled(sc))		  ||
2227267839Sdelphij	    IS_BE2(sc)) {
2228231437Sluigi		sc->nrqs = 1;
2229231437Sluigi		sc->nwqs = 1;
2230257007Sdelphij	} else {
2231257007Sdelphij		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
2232257007Sdelphij		sc->nwqs = MIN(OCE_NCPUS, sc->nrssqs);
2233231437Sluigi	}
2234267839Sdelphij
2235267839Sdelphij	if (IS_BE2(sc) && is_rss_enabled(sc))
2236267839Sdelphij		sc->nrqs = MIN(OCE_NCPUS, sc->nrssqs) + 1;
2237231437Sluigi}
2238231437Sluigi
2239231437Sluigi
2240231437Sluigistatic void
2241231437Sluigiupdate_queues_got(POCE_SOFTC sc)
2242231437Sluigi{
2243252869Sdelphij	if (is_rss_enabled(sc)) {
2244231437Sluigi		sc->nrqs = sc->intr_count + 1;
2245231437Sluigi		sc->nwqs = sc->intr_count;
2246231437Sluigi	} else {
2247231437Sluigi		sc->nrqs = 1;
2248231437Sluigi		sc->nwqs = 1;
2249231437Sluigi	}
2250267839Sdelphij
2251267839Sdelphij	if (IS_BE2(sc))
2252267839Sdelphij		sc->nwqs = 1;
2253231437Sluigi}
2254231437Sluigi
2255247880Sdelphijstatic int
2256247880Sdelphijoce_check_ipv6_ext_hdr(struct mbuf *m)
2257247880Sdelphij{
2258247880Sdelphij	struct ether_header *eh = mtod(m, struct ether_header *);
2259247880Sdelphij	caddr_t m_datatemp = m->m_data;
2260247880Sdelphij
2261247880Sdelphij	if (eh->ether_type == htons(ETHERTYPE_IPV6)) {
2262247880Sdelphij		m->m_data += sizeof(struct ether_header);
2263247880Sdelphij		struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
2264247880Sdelphij
2265247880Sdelphij		if((ip6->ip6_nxt != IPPROTO_TCP) && \
2266247880Sdelphij				(ip6->ip6_nxt != IPPROTO_UDP)){
2267247880Sdelphij			struct ip6_ext *ip6e = NULL;
2268247880Sdelphij			m->m_data += sizeof(struct ip6_hdr);
2269247880Sdelphij
2270247880Sdelphij			ip6e = (struct ip6_ext *) mtod(m, struct ip6_ext *);
2271247880Sdelphij			if(ip6e->ip6e_len == 0xff) {
2272247880Sdelphij				m->m_data = m_datatemp;
2273247880Sdelphij				return TRUE;
2274247880Sdelphij			}
2275247880Sdelphij		}
2276247880Sdelphij		m->m_data = m_datatemp;
2277247880Sdelphij	}
2278247880Sdelphij	return FALSE;
2279247880Sdelphij}
2280247880Sdelphij
2281247880Sdelphijstatic int
2282247880Sdelphijis_be3_a1(POCE_SOFTC sc)
2283247880Sdelphij{
2284247880Sdelphij	if((sc->flags & OCE_FLAGS_BE3)  && ((sc->asic_revision & 0xFF) < 2)) {
2285247880Sdelphij		return TRUE;
2286247880Sdelphij	}
2287247880Sdelphij	return FALSE;
2288247880Sdelphij}
2289247880Sdelphij
2290247880Sdelphijstatic struct mbuf *
2291247880Sdelphijoce_insert_vlan_tag(POCE_SOFTC sc, struct mbuf *m, boolean_t *complete)
2292247880Sdelphij{
2293247880Sdelphij	uint16_t vlan_tag = 0;
2294247880Sdelphij
2295247880Sdelphij	if(!M_WRITABLE(m))
2296247880Sdelphij		return NULL;
2297247880Sdelphij
2298247880Sdelphij	/* Embed vlan tag in the packet if it is not part of it */
2299247880Sdelphij	if(m->m_flags & M_VLANTAG) {
2300247880Sdelphij		vlan_tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
2301247880Sdelphij		m->m_flags &= ~M_VLANTAG;
2302247880Sdelphij	}
2303247880Sdelphij
2304247880Sdelphij	/* if UMC, ignore vlan tag insertion and instead insert pvid */
2305247880Sdelphij	if(sc->pvid) {
2306247880Sdelphij		if(!vlan_tag)
2307247880Sdelphij			vlan_tag = sc->pvid;
2308247880Sdelphij		*complete = FALSE;
2309247880Sdelphij	}
2310247880Sdelphij
2311247880Sdelphij	if(vlan_tag) {
2312247880Sdelphij		m = ether_vlanencap(m, vlan_tag);
2313247880Sdelphij	}
2314247880Sdelphij
2315247880Sdelphij	if(sc->qnqid) {
2316247880Sdelphij		m = ether_vlanencap(m, sc->qnqid);
2317247880Sdelphij		*complete = FALSE;
2318247880Sdelphij	}
2319247880Sdelphij	return m;
2320247880Sdelphij}
2321247880Sdelphij
2322247880Sdelphijstatic int
2323247880Sdelphijoce_tx_asic_stall_verify(POCE_SOFTC sc, struct mbuf *m)
2324247880Sdelphij{
2325247880Sdelphij	if(is_be3_a1(sc) && IS_QNQ_OR_UMC(sc) && \
2326247880Sdelphij			oce_check_ipv6_ext_hdr(m)) {
2327247880Sdelphij		return TRUE;
2328247880Sdelphij	}
2329247880Sdelphij	return FALSE;
2330247880Sdelphij}
2331252869Sdelphij
2332252869Sdelphijstatic void
2333252869Sdelphijoce_get_config(POCE_SOFTC sc)
2334252869Sdelphij{
2335252869Sdelphij	int rc = 0;
2336252869Sdelphij	uint32_t max_rss = 0;
2337252869Sdelphij
2338252869Sdelphij	if ((IS_BE(sc) || IS_SH(sc)) && (!sc->be3_native))
2339252869Sdelphij		max_rss = OCE_LEGACY_MODE_RSS;
2340252869Sdelphij	else
2341252869Sdelphij		max_rss = OCE_MAX_RSS;
2342252869Sdelphij
2343252869Sdelphij	if (!IS_BE(sc)) {
2344258941Sdelphij		rc = oce_get_profile_config(sc, max_rss);
2345252869Sdelphij		if (rc) {
2346252869Sdelphij			sc->nwqs = OCE_MAX_WQ;
2347252869Sdelphij			sc->nrssqs = max_rss;
2348252869Sdelphij			sc->nrqs = sc->nrssqs + 1;
2349252869Sdelphij		}
2350252869Sdelphij	}
2351258941Sdelphij	else { /* For BE3 don't rely on fw for determining the resources */
2352252869Sdelphij		sc->nrssqs = max_rss;
2353252869Sdelphij		sc->nrqs = sc->nrssqs + 1;
2354258941Sdelphij		sc->nwqs = OCE_MAX_WQ;
2355258941Sdelphij		sc->max_vlans = MAX_VLANFILTER_SIZE;
2356252869Sdelphij	}
2357252869Sdelphij}
2358