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
41257187Sdelphij
42231437Sluigi#include "oce_if.h"
43231437Sluigi
44231437Sluigistatic int oce_POST(POCE_SOFTC sc);
45231437Sluigi
46231437Sluigi/**
47231437Sluigi * @brief		Function to post status
48231437Sluigi * @param sc		software handle to the device
49231437Sluigi */
50231437Sluigistatic int
51231437Sluigioce_POST(POCE_SOFTC sc)
52231437Sluigi{
53231437Sluigi	mpu_ep_semaphore_t post_status;
54231437Sluigi	int tmo = 60000;
55231437Sluigi
56231437Sluigi	/* read semaphore CSR */
57252869Sdelphij	post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
58231437Sluigi
59231437Sluigi	/* if host is ready then wait for fw ready else send POST */
60231437Sluigi	if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
61231437Sluigi		post_status.bits.stage = POST_STAGE_CHIP_RESET;
62252869Sdelphij		OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc), post_status.dw0);
63231437Sluigi	}
64231437Sluigi
65231437Sluigi	/* wait for FW ready */
66231437Sluigi	for (;;) {
67231437Sluigi		if (--tmo == 0)
68231437Sluigi			break;
69231437Sluigi
70231437Sluigi		DELAY(1000);
71231437Sluigi
72252869Sdelphij		post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
73231437Sluigi		if (post_status.bits.error) {
74231437Sluigi			device_printf(sc->dev,
75231437Sluigi				  "POST failed: %x\n", post_status.dw0);
76231437Sluigi			return ENXIO;
77231437Sluigi		}
78231437Sluigi		if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
79231437Sluigi			return 0;
80231437Sluigi	}
81231437Sluigi
82231437Sluigi	device_printf(sc->dev, "POST timed out: %x\n", post_status.dw0);
83231437Sluigi
84231437Sluigi	return ENXIO;
85231437Sluigi}
86231437Sluigi
87231437Sluigi/**
88231437Sluigi * @brief		Function for hardware initialization
89231437Sluigi * @param sc		software handle to the device
90231437Sluigi */
91231437Sluigiint
92231437Sluigioce_hw_init(POCE_SOFTC sc)
93231437Sluigi{
94231437Sluigi	int rc = 0;
95231437Sluigi
96231437Sluigi	rc = oce_POST(sc);
97231437Sluigi	if (rc)
98231437Sluigi		return rc;
99231437Sluigi
100231437Sluigi	/* create the bootstrap mailbox */
101231437Sluigi	rc = oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->bsmbx, 0);
102231437Sluigi	if (rc) {
103231437Sluigi		device_printf(sc->dev, "Mailbox alloc failed\n");
104231437Sluigi		return rc;
105231437Sluigi	}
106231437Sluigi
107231437Sluigi	rc = oce_reset_fun(sc);
108231437Sluigi	if (rc)
109231437Sluigi		goto error;
110231437Sluigi
111231437Sluigi
112231437Sluigi	rc = oce_mbox_init(sc);
113231437Sluigi	if (rc)
114231437Sluigi		goto error;
115231437Sluigi
116231437Sluigi
117231437Sluigi	rc = oce_get_fw_version(sc);
118231437Sluigi	if (rc)
119231437Sluigi		goto error;
120231437Sluigi
121231437Sluigi
122231437Sluigi	rc = oce_get_fw_config(sc);
123231437Sluigi	if (rc)
124231437Sluigi		goto error;
125231437Sluigi
126231437Sluigi
127231437Sluigi	sc->macaddr.size_of_struct = 6;
128231437Sluigi	rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
129231437Sluigi					&sc->macaddr);
130231437Sluigi	if (rc)
131231437Sluigi		goto error;
132231437Sluigi
133252869Sdelphij	if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
134231437Sluigi		rc = oce_mbox_check_native_mode(sc);
135231437Sluigi		if (rc)
136231437Sluigi			goto error;
137231437Sluigi	} else
138231437Sluigi		sc->be3_native = 0;
139231437Sluigi
140231437Sluigi	return rc;
141231437Sluigi
142231437Sluigierror:
143231437Sluigi	oce_dma_free(sc, &sc->bsmbx);
144231437Sluigi	device_printf(sc->dev, "Hardware initialisation failed\n");
145231437Sluigi	return rc;
146231437Sluigi}
147231437Sluigi
148231437Sluigi
149231437Sluigi
150231437Sluigi/**
151231437Sluigi * @brief		Releases the obtained pci resources
152231437Sluigi * @param sc		software handle to the device
153231437Sluigi */
154231437Sluigivoid
155231437Sluigioce_hw_pci_free(POCE_SOFTC sc)
156231437Sluigi{
157231437Sluigi	int pci_cfg_barnum = 0;
158231437Sluigi
159231437Sluigi	if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
160231437Sluigi		pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
161231437Sluigi	else
162231437Sluigi		pci_cfg_barnum = OCE_DEV_CFG_BAR;
163231437Sluigi
164231437Sluigi	if (sc->devcfg_res != NULL) {
165231437Sluigi		bus_release_resource(sc->dev,
166231437Sluigi				     SYS_RES_MEMORY,
167231437Sluigi				     PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
168231437Sluigi		sc->devcfg_res = (struct resource *)NULL;
169231437Sluigi		sc->devcfg_btag = (bus_space_tag_t) 0;
170231437Sluigi		sc->devcfg_bhandle = (bus_space_handle_t)0;
171231437Sluigi		sc->devcfg_vhandle = (void *)NULL;
172231437Sluigi	}
173231437Sluigi
174231437Sluigi	if (sc->csr_res != NULL) {
175231437Sluigi		bus_release_resource(sc->dev,
176231437Sluigi				     SYS_RES_MEMORY,
177231437Sluigi				     PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
178231437Sluigi		sc->csr_res = (struct resource *)NULL;
179231437Sluigi		sc->csr_btag = (bus_space_tag_t)0;
180231437Sluigi		sc->csr_bhandle = (bus_space_handle_t)0;
181231437Sluigi		sc->csr_vhandle = (void *)NULL;
182231437Sluigi	}
183231437Sluigi
184231437Sluigi	if (sc->db_res != NULL) {
185231437Sluigi		bus_release_resource(sc->dev,
186231437Sluigi				     SYS_RES_MEMORY,
187231437Sluigi				     PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
188231437Sluigi		sc->db_res = (struct resource *)NULL;
189231437Sluigi		sc->db_btag = (bus_space_tag_t)0;
190231437Sluigi		sc->db_bhandle = (bus_space_handle_t)0;
191231437Sluigi		sc->db_vhandle = (void *)NULL;
192231437Sluigi	}
193231437Sluigi}
194231437Sluigi
195231437Sluigi
196231437Sluigi
197231437Sluigi
198231437Sluigi/**
199231437Sluigi * @brief 		Function to get the PCI capabilities
200231437Sluigi * @param sc		software handle to the device
201231437Sluigi */
202231437Sluigistatic
203231437Sluigivoid oce_get_pci_capabilities(POCE_SOFTC sc)
204231437Sluigi{
205231437Sluigi	uint32_t val;
206231437Sluigi
207257187Sdelphij#if __FreeBSD_version >= 1000000
208257187Sdelphij	#define pci_find_extcap pci_find_cap
209257187Sdelphij#endif
210257187Sdelphij
211257187Sdelphij	if (pci_find_extcap(sc->dev, PCIY_PCIX, &val) == 0) {
212231437Sluigi		if (val != 0)
213231437Sluigi			sc->flags |= OCE_FLAGS_PCIX;
214231437Sluigi	}
215231437Sluigi
216257187Sdelphij	if (pci_find_extcap(sc->dev, PCIY_EXPRESS, &val) == 0) {
217231437Sluigi		if (val != 0) {
218231437Sluigi			uint16_t link_status =
219231437Sluigi			    pci_read_config(sc->dev, val + 0x12, 2);
220231437Sluigi
221231437Sluigi			sc->flags |= OCE_FLAGS_PCIE;
222231437Sluigi			sc->pcie_link_speed = link_status & 0xf;
223231437Sluigi			sc->pcie_link_width = (link_status >> 4) & 0x3f;
224231437Sluigi		}
225231437Sluigi	}
226231437Sluigi
227257187Sdelphij	if (pci_find_extcap(sc->dev, PCIY_MSI, &val) == 0) {
228231437Sluigi		if (val != 0)
229231437Sluigi			sc->flags |= OCE_FLAGS_MSI_CAPABLE;
230231437Sluigi	}
231231437Sluigi
232257187Sdelphij	if (pci_find_extcap(sc->dev, PCIY_MSIX, &val) == 0) {
233231437Sluigi		if (val != 0) {
234231437Sluigi			val = pci_msix_count(sc->dev);
235231437Sluigi			sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
236231437Sluigi		}
237231437Sluigi	}
238231437Sluigi}
239231437Sluigi
240231437Sluigi/**
241231437Sluigi * @brief	Allocate PCI resources.
242231437Sluigi *
243231437Sluigi * @param sc		software handle to the device
244231437Sluigi * @returns		0 if successful, or error
245231437Sluigi */
246231437Sluigiint
247231437Sluigioce_hw_pci_alloc(POCE_SOFTC sc)
248231437Sluigi{
249231437Sluigi	int rr, pci_cfg_barnum = 0;
250231437Sluigi	pci_sli_intf_t intf;
251231437Sluigi
252231437Sluigi	pci_enable_busmaster(sc->dev);
253231437Sluigi
254231437Sluigi	oce_get_pci_capabilities(sc);
255231437Sluigi
256231437Sluigi	sc->fn = pci_get_function(sc->dev);
257231437Sluigi
258231437Sluigi	/* setup the device config region */
259231437Sluigi	if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
260231437Sluigi		pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
261231437Sluigi	else
262231437Sluigi		pci_cfg_barnum = OCE_DEV_CFG_BAR;
263231437Sluigi
264231437Sluigi	rr = PCIR_BAR(pci_cfg_barnum);
265231437Sluigi
266252869Sdelphij	if (IS_BE(sc) || IS_SH(sc))
267231437Sluigi		sc->devcfg_res = bus_alloc_resource_any(sc->dev,
268231437Sluigi				SYS_RES_MEMORY, &rr,
269231437Sluigi				RF_ACTIVE|RF_SHAREABLE);
270231437Sluigi	else
271231437Sluigi		sc->devcfg_res = bus_alloc_resource(sc->dev,
272231437Sluigi				SYS_RES_MEMORY, &rr,
273231437Sluigi				0ul, ~0ul, 32768,
274231437Sluigi				RF_ACTIVE|RF_SHAREABLE);
275231437Sluigi
276231437Sluigi	if (!sc->devcfg_res)
277231437Sluigi		goto error;
278231437Sluigi
279231437Sluigi	sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
280231437Sluigi	sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
281231437Sluigi	sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
282231437Sluigi
283231437Sluigi	/* Read the SLI_INTF register and determine whether we
284231437Sluigi	 * can use this port and its features
285231437Sluigi	 */
286231437Sluigi	intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
287231437Sluigi
288231437Sluigi	if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
289231437Sluigi		goto error;
290231437Sluigi
291231437Sluigi	if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
292231437Sluigi		device_printf(sc->dev, "Adapter doesnt support SLI4\n");
293231437Sluigi		goto error;
294231437Sluigi	}
295231437Sluigi
296231437Sluigi	if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
297231437Sluigi		sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
298231437Sluigi
299231437Sluigi	if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
300231437Sluigi		sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
301231437Sluigi
302231437Sluigi	if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
303231437Sluigi		sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
304231437Sluigi
305231437Sluigi	/* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
306252869Sdelphij	if (IS_BE(sc) || IS_SH(sc)) {
307231437Sluigi		/* set up CSR region */
308231437Sluigi		rr = PCIR_BAR(OCE_PCI_CSR_BAR);
309231437Sluigi		sc->csr_res = bus_alloc_resource_any(sc->dev,
310231437Sluigi				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
311231437Sluigi		if (!sc->csr_res)
312231437Sluigi			goto error;
313231437Sluigi		sc->csr_btag = rman_get_bustag(sc->csr_res);
314231437Sluigi		sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
315231437Sluigi		sc->csr_vhandle = rman_get_virtual(sc->csr_res);
316231437Sluigi
317231437Sluigi		/* set up DB doorbell region */
318231437Sluigi		rr = PCIR_BAR(OCE_PCI_DB_BAR);
319231437Sluigi		sc->db_res = bus_alloc_resource_any(sc->dev,
320231437Sluigi				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
321231437Sluigi		if (!sc->db_res)
322231437Sluigi			goto error;
323231437Sluigi		sc->db_btag = rman_get_bustag(sc->db_res);
324231437Sluigi		sc->db_bhandle = rman_get_bushandle(sc->db_res);
325231437Sluigi		sc->db_vhandle = rman_get_virtual(sc->db_res);
326231437Sluigi	}
327231437Sluigi
328231437Sluigi	return 0;
329231437Sluigi
330231437Sluigierror:
331231437Sluigi	oce_hw_pci_free(sc);
332231437Sluigi	return ENXIO;
333231437Sluigi}
334231437Sluigi
335231437Sluigi
336231437Sluigi/**
337231437Sluigi * @brief		Function for device shutdown
338231437Sluigi * @param sc		software handle to the device
339231437Sluigi * @returns		0 on success, error otherwise
340231437Sluigi */
341231437Sluigivoid
342231437Sluigioce_hw_shutdown(POCE_SOFTC sc)
343231437Sluigi{
344231437Sluigi
345231437Sluigi	oce_stats_free(sc);
346231437Sluigi	/* disable hardware interrupts */
347231437Sluigi	oce_hw_intr_disable(sc);
348231879Sluigi#if defined(INET6) || defined(INET)
349231437Sluigi	/* Free LRO resources */
350231437Sluigi	oce_free_lro(sc);
351231879Sluigi#endif
352231437Sluigi	/* Release queue*/
353231437Sluigi	oce_queue_release_all(sc);
354231437Sluigi	/*Delete Network Interface*/
355231437Sluigi	oce_delete_nw_interface(sc);
356231437Sluigi	/* After fw clean we dont send any cmds to fw.*/
357231437Sluigi	oce_fw_clean(sc);
358231437Sluigi	/* release intr resources */
359231437Sluigi	oce_intr_free(sc);
360231437Sluigi	/* release PCI resources */
361231437Sluigi	oce_hw_pci_free(sc);
362231437Sluigi	/* free mbox specific resources */
363231437Sluigi	LOCK_DESTROY(&sc->bmbx_lock);
364231437Sluigi	LOCK_DESTROY(&sc->dev_lock);
365231437Sluigi
366231437Sluigi	oce_dma_free(sc, &sc->bsmbx);
367231437Sluigi}
368231437Sluigi
369231437Sluigi
370231437Sluigi/**
371231437Sluigi * @brief		Function for creating nw interface.
372231437Sluigi * @param sc		software handle to the device
373231437Sluigi * @returns		0 on success, error otherwise
374231437Sluigi */
375231437Sluigiint
376231437Sluigioce_create_nw_interface(POCE_SOFTC sc)
377231437Sluigi{
378231437Sluigi	int rc;
379231437Sluigi	uint32_t capab_flags;
380231437Sluigi	uint32_t capab_en_flags;
381231437Sluigi
382231437Sluigi	/* interface capabilities to give device when creating interface */
383231437Sluigi	capab_flags = OCE_CAPAB_FLAGS;
384231437Sluigi
385231437Sluigi	/* capabilities to enable by default (others set dynamically) */
386231437Sluigi	capab_en_flags = OCE_CAPAB_ENABLE;
387231437Sluigi
388231437Sluigi	if (IS_XE201(sc)) {
389231437Sluigi		/* LANCER A0 workaround */
390231437Sluigi		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
391231437Sluigi		capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
392231437Sluigi	}
393231437Sluigi
394257187Sdelphij	if (IS_SH(sc) || IS_XE201(sc))
395257187Sdelphij		capab_flags |= MBX_RX_IFACE_FLAGS_MULTICAST;
396257187Sdelphij
397231437Sluigi	/* enable capabilities controlled via driver startup parameters */
398252869Sdelphij	if (is_rss_enabled(sc))
399231437Sluigi		capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
400231437Sluigi	else {
401231437Sluigi		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
402231437Sluigi		capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
403231437Sluigi	}
404231437Sluigi
405231437Sluigi	rc = oce_if_create(sc,
406231437Sluigi			   capab_flags,
407231437Sluigi			   capab_en_flags,
408231437Sluigi			   0, &sc->macaddr.mac_addr[0], &sc->if_id);
409231437Sluigi	if (rc)
410231437Sluigi		return rc;
411231437Sluigi
412231437Sluigi	atomic_inc_32(&sc->nifs);
413231437Sluigi
414231437Sluigi	sc->if_cap_flags = capab_en_flags;
415231437Sluigi
416231437Sluigi	/* set default flow control */
417231437Sluigi	rc = oce_set_flow_control(sc, sc->flow_control);
418231437Sluigi	if (rc)
419231437Sluigi		goto error;
420231437Sluigi
421231437Sluigi	rc = oce_rxf_set_promiscuous(sc, sc->promisc);
422231437Sluigi	if (rc)
423231437Sluigi		goto error;
424231437Sluigi
425231437Sluigi	return rc;
426231437Sluigi
427231437Sluigierror:
428231437Sluigi	oce_delete_nw_interface(sc);
429231437Sluigi	return rc;
430231437Sluigi
431231437Sluigi}
432231437Sluigi
433231437Sluigi/**
434231437Sluigi * @brief		Function to delete a nw interface.
435231437Sluigi * @param sc		software handle to the device
436231437Sluigi */
437231437Sluigivoid
438231437Sluigioce_delete_nw_interface(POCE_SOFTC sc)
439231437Sluigi{
440231437Sluigi	/* currently only single interface is implmeneted */
441231437Sluigi	if (sc->nifs > 0) {
442231437Sluigi		oce_if_del(sc, sc->if_id);
443231437Sluigi		atomic_dec_32(&sc->nifs);
444231437Sluigi	}
445231437Sluigi}
446231437Sluigi
447231437Sluigi/**
448231437Sluigi * @brief Soft reset.
449231437Sluigi * @param sc		software handle to the device
450231437Sluigi * @returns		0 on success, error otherwise
451231437Sluigi */
452231437Sluigiint
453231437Sluigioce_pci_soft_reset(POCE_SOFTC sc)
454231437Sluigi{
455231437Sluigi	int rc;
456231437Sluigi	mpu_ep_control_t ctrl;
457231437Sluigi
458252869Sdelphij	ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
459231437Sluigi	ctrl.bits.cpu_reset = 1;
460252869Sdelphij	OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
461231437Sluigi	DELAY(50);
462231437Sluigi	rc=oce_POST(sc);
463231437Sluigi
464231437Sluigi	return rc;
465231437Sluigi}
466231437Sluigi
467231437Sluigi/**
468231437Sluigi * @brief		Function for hardware start
469231437Sluigi * @param sc		software handle to the device
470231437Sluigi * @returns		0 on success, error otherwise
471231437Sluigi */
472231437Sluigiint
473231437Sluigioce_hw_start(POCE_SOFTC sc)
474231437Sluigi{
475231437Sluigi	struct link_status link = { 0 };
476231437Sluigi	int rc = 0;
477231437Sluigi
478231437Sluigi	rc = oce_get_link_status(sc, &link);
479231437Sluigi	if (rc)
480231437Sluigi		return 1;
481231437Sluigi
482231437Sluigi	if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
483231437Sluigi		sc->link_status = NTWK_LOGICAL_LINK_UP;
484231437Sluigi		if_link_state_change(sc->ifp, LINK_STATE_UP);
485231437Sluigi	} else {
486231437Sluigi		sc->link_status = NTWK_LOGICAL_LINK_DOWN;
487231437Sluigi		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
488231437Sluigi	}
489231437Sluigi
490268046Sdelphij	sc->link_speed = link.phys_port_speed;
491231437Sluigi	sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
492231437Sluigi
493231437Sluigi	rc = oce_start_mq(sc->mq);
494231437Sluigi
495231879Sluigi	/* we need to get MCC aync events. So enable intrs and arm
496231879Sluigi	   first EQ, Other EQs will be armed after interface is UP
497231437Sluigi	*/
498231437Sluigi	oce_hw_intr_enable(sc);
499231437Sluigi	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
500231437Sluigi
501231879Sluigi	/* Send first mcc cmd and after that we get gracious
502231879Sluigi	   MCC notifications from FW
503231879Sluigi	*/
504231879Sluigi	oce_first_mcc_cmd(sc);
505231879Sluigi
506231437Sluigi	return rc;
507231437Sluigi}
508231437Sluigi
509231437Sluigi
510231437Sluigi/**
511231437Sluigi * @brief 		Function for hardware enable interupts.
512231437Sluigi * @param sc		software handle to the device
513231437Sluigi */
514231437Sluigivoid
515231437Sluigioce_hw_intr_enable(POCE_SOFTC sc)
516231437Sluigi{
517231437Sluigi	uint32_t reg;
518231437Sluigi
519231437Sluigi	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
520231437Sluigi	reg |= HOSTINTR_MASK;
521231437Sluigi	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
522231437Sluigi
523231437Sluigi}
524231437Sluigi
525231437Sluigi
526231437Sluigi/**
527231437Sluigi * @brief 		Function for hardware disable interupts
528231437Sluigi * @param sc		software handle to the device
529231437Sluigi */
530231437Sluigivoid
531231437Sluigioce_hw_intr_disable(POCE_SOFTC sc)
532231437Sluigi{
533231437Sluigi	uint32_t reg;
534231437Sluigi
535231437Sluigi	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
536231437Sluigi	reg &= ~HOSTINTR_MASK;
537231437Sluigi	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
538231437Sluigi}
539231437Sluigi
540231437Sluigi
541231437Sluigi
542231437Sluigi/**
543231879Sluigi * @brief		Function for hardware update multicast filter
544231879Sluigi * @param sc		software handle to the device
545231437Sluigi */
546231437Sluigiint
547231437Sluigioce_hw_update_multicast(POCE_SOFTC sc)
548231437Sluigi{
549231437Sluigi	struct ifnet    *ifp = sc->ifp;
550231437Sluigi	struct ifmultiaddr *ifma;
551231437Sluigi	struct mbx_set_common_iface_multicast *req = NULL;
552231437Sluigi	OCE_DMA_MEM dma;
553231437Sluigi	int rc = 0;
554231437Sluigi
555231437Sluigi	/* Allocate DMA mem*/
556231437Sluigi	if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
557231437Sluigi							&dma, 0))
558231437Sluigi		return ENOMEM;
559231437Sluigi
560231437Sluigi	req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
561231437Sluigi	bzero(req, sizeof(struct mbx_set_common_iface_multicast));
562231437Sluigi
563231437Sluigi#if __FreeBSD_version > 800000
564231603Sjhb	if_maddr_rlock(ifp);
565231437Sluigi#endif
566231437Sluigi	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
567231437Sluigi		if (ifma->ifma_addr->sa_family != AF_LINK)
568231437Sluigi			continue;
569231437Sluigi
570231437Sluigi		if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
571231437Sluigi			/*More multicast addresses than our hardware table
572231437Sluigi			  So Enable multicast promiscus in our hardware to
573231437Sluigi			  accept all multicat packets
574231437Sluigi			*/
575231437Sluigi			req->params.req.promiscuous = 1;
576231437Sluigi			break;
577231437Sluigi		}
578231437Sluigi		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
579231437Sluigi			&req->params.req.mac[req->params.req.num_mac],
580231437Sluigi			ETH_ADDR_LEN);
581231437Sluigi		req->params.req.num_mac = req->params.req.num_mac + 1;
582231437Sluigi	}
583231437Sluigi#if __FreeBSD_version > 800000
584231603Sjhb	if_maddr_runlock(ifp);
585231437Sluigi#endif
586231437Sluigi	req->params.req.if_id = sc->if_id;
587231437Sluigi	rc = oce_update_multicast(sc, &dma);
588231437Sluigi	oce_dma_free(sc, &dma);
589231437Sluigi	return rc;
590231437Sluigi}
591231437Sluigi
592