xref: /dragonfly/sys/dev/netif/oce/oce_hw.c (revision 56b41dfb)
1229aec1cSSascha Wildner /*-
2c976b08eSSascha Wildner  * Copyright (C) 2013 Emulex
3229aec1cSSascha Wildner  * All rights reserved.
4229aec1cSSascha Wildner  *
5229aec1cSSascha Wildner  * Redistribution and use in source and binary forms, with or without
6229aec1cSSascha Wildner  * modification, are permitted provided that the following conditions are met:
7229aec1cSSascha Wildner  *
8229aec1cSSascha Wildner  * 1. Redistributions of source code must retain the above copyright notice,
9229aec1cSSascha Wildner  *    this list of conditions and the following disclaimer.
10229aec1cSSascha Wildner  *
11229aec1cSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
12229aec1cSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
13229aec1cSSascha Wildner  *    documentation and/or other materials provided with the distribution.
14229aec1cSSascha Wildner  *
15229aec1cSSascha Wildner  * 3. Neither the name of the Emulex Corporation nor the names of its
16229aec1cSSascha Wildner  *    contributors may be used to endorse or promote products derived from
17229aec1cSSascha Wildner  *    this software without specific prior written permission.
18229aec1cSSascha Wildner  *
19229aec1cSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20229aec1cSSascha Wildner  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21229aec1cSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22229aec1cSSascha Wildner  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23229aec1cSSascha Wildner  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24229aec1cSSascha Wildner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25229aec1cSSascha Wildner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26229aec1cSSascha Wildner  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27229aec1cSSascha Wildner  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28229aec1cSSascha Wildner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29229aec1cSSascha Wildner  * POSSIBILITY OF SUCH DAMAGE.
30229aec1cSSascha Wildner  *
31229aec1cSSascha Wildner  * Contact Information:
32229aec1cSSascha Wildner  * freebsd-drivers@emulex.com
33229aec1cSSascha Wildner  *
34229aec1cSSascha Wildner  * Emulex
35229aec1cSSascha Wildner  * 3333 Susan Street
36229aec1cSSascha Wildner  * Costa Mesa, CA 92626
37229aec1cSSascha Wildner  */
38229aec1cSSascha Wildner 
39c976b08eSSascha Wildner /* $FreeBSD: src/sys/dev/oce/oce_hw.c,v 1.8 2013/07/07 00:30:13 svnexp Exp $ */
40229aec1cSSascha Wildner 
41*56b41dfbSSascha Wildner #include "opt_inet6.h"
42*56b41dfbSSascha Wildner #include "opt_inet.h"
43*56b41dfbSSascha Wildner 
44229aec1cSSascha Wildner #include "oce_if.h"
45229aec1cSSascha Wildner 
46229aec1cSSascha Wildner static int oce_POST(POCE_SOFTC sc);
47229aec1cSSascha Wildner 
48229aec1cSSascha Wildner /**
49229aec1cSSascha Wildner  * @brief		Function to post status
50229aec1cSSascha Wildner  * @param sc		software handle to the device
51229aec1cSSascha Wildner  */
52229aec1cSSascha Wildner static int
oce_POST(POCE_SOFTC sc)53229aec1cSSascha Wildner oce_POST(POCE_SOFTC sc)
54229aec1cSSascha Wildner {
55229aec1cSSascha Wildner 	mpu_ep_semaphore_t post_status;
56229aec1cSSascha Wildner 	int tmo = 60000;
57229aec1cSSascha Wildner 
58229aec1cSSascha Wildner 	/* read semaphore CSR */
59c976b08eSSascha Wildner 	post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
60229aec1cSSascha Wildner 
61229aec1cSSascha Wildner 	/* if host is ready then wait for fw ready else send POST */
62229aec1cSSascha Wildner 	if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
63229aec1cSSascha Wildner 		post_status.bits.stage = POST_STAGE_CHIP_RESET;
64c976b08eSSascha Wildner 		OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc), post_status.dw0);
65229aec1cSSascha Wildner 	}
66229aec1cSSascha Wildner 
67229aec1cSSascha Wildner 	/* wait for FW ready */
68229aec1cSSascha Wildner 	for (;;) {
69229aec1cSSascha Wildner 		if (--tmo == 0)
70229aec1cSSascha Wildner 			break;
71229aec1cSSascha Wildner 
72229aec1cSSascha Wildner 		DELAY(1000);
73229aec1cSSascha Wildner 
74c976b08eSSascha Wildner 		post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
75229aec1cSSascha Wildner 		if (post_status.bits.error) {
76229aec1cSSascha Wildner 			device_printf(sc->dev,
77229aec1cSSascha Wildner 				  "POST failed: %x\n", post_status.dw0);
78229aec1cSSascha Wildner 			return ENXIO;
79229aec1cSSascha Wildner 		}
80229aec1cSSascha Wildner 		if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
81229aec1cSSascha Wildner 			return 0;
82229aec1cSSascha Wildner 	}
83229aec1cSSascha Wildner 
84229aec1cSSascha Wildner 	device_printf(sc->dev, "POST timed out: %x\n", post_status.dw0);
85229aec1cSSascha Wildner 
86229aec1cSSascha Wildner 	return ENXIO;
87229aec1cSSascha Wildner }
88229aec1cSSascha Wildner 
89229aec1cSSascha Wildner /**
90229aec1cSSascha Wildner  * @brief		Function for hardware initialization
91229aec1cSSascha Wildner  * @param sc		software handle to the device
92229aec1cSSascha Wildner  */
93229aec1cSSascha Wildner int
oce_hw_init(POCE_SOFTC sc)94229aec1cSSascha Wildner oce_hw_init(POCE_SOFTC sc)
95229aec1cSSascha Wildner {
96229aec1cSSascha Wildner 	int rc = 0;
97229aec1cSSascha Wildner 
98229aec1cSSascha Wildner 	rc = oce_POST(sc);
99229aec1cSSascha Wildner 	if (rc)
100229aec1cSSascha Wildner 		return rc;
101229aec1cSSascha Wildner 
102229aec1cSSascha Wildner 	/* create the bootstrap mailbox */
103229aec1cSSascha Wildner 	rc = oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->bsmbx, 0);
104229aec1cSSascha Wildner 	if (rc) {
105229aec1cSSascha Wildner 		device_printf(sc->dev, "Mailbox alloc failed\n");
106229aec1cSSascha Wildner 		return rc;
107229aec1cSSascha Wildner 	}
108229aec1cSSascha Wildner 
109229aec1cSSascha Wildner 	rc = oce_reset_fun(sc);
110229aec1cSSascha Wildner 	if (rc)
111229aec1cSSascha Wildner 		goto error;
112229aec1cSSascha Wildner 
113229aec1cSSascha Wildner 
114229aec1cSSascha Wildner 	rc = oce_mbox_init(sc);
115229aec1cSSascha Wildner 	if (rc)
116229aec1cSSascha Wildner 		goto error;
117229aec1cSSascha Wildner 
118229aec1cSSascha Wildner 
119229aec1cSSascha Wildner 	rc = oce_get_fw_version(sc);
120229aec1cSSascha Wildner 	if (rc)
121229aec1cSSascha Wildner 		goto error;
122229aec1cSSascha Wildner 
123229aec1cSSascha Wildner 
124229aec1cSSascha Wildner 	rc = oce_get_fw_config(sc);
125229aec1cSSascha Wildner 	if (rc)
126229aec1cSSascha Wildner 		goto error;
127229aec1cSSascha Wildner 
128229aec1cSSascha Wildner 
129229aec1cSSascha Wildner 	sc->macaddr.size_of_struct = 6;
130229aec1cSSascha Wildner 	rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
131229aec1cSSascha Wildner 					&sc->macaddr);
132229aec1cSSascha Wildner 	if (rc)
133229aec1cSSascha Wildner 		goto error;
134229aec1cSSascha Wildner 
135c976b08eSSascha Wildner 	if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
136229aec1cSSascha Wildner 		rc = oce_mbox_check_native_mode(sc);
137229aec1cSSascha Wildner 		if (rc)
138229aec1cSSascha Wildner 			goto error;
139229aec1cSSascha Wildner 	} else
140229aec1cSSascha Wildner 		sc->be3_native = 0;
141229aec1cSSascha Wildner 
142229aec1cSSascha Wildner 	return rc;
143229aec1cSSascha Wildner 
144229aec1cSSascha Wildner error:
145229aec1cSSascha Wildner 	oce_dma_free(sc, &sc->bsmbx);
146229aec1cSSascha Wildner 	device_printf(sc->dev, "Hardware initialisation failed\n");
147229aec1cSSascha Wildner 	return rc;
148229aec1cSSascha Wildner }
149229aec1cSSascha Wildner 
150229aec1cSSascha Wildner 
151229aec1cSSascha Wildner 
152229aec1cSSascha Wildner /**
153229aec1cSSascha Wildner  * @brief		Releases the obtained pci resources
154229aec1cSSascha Wildner  * @param sc		software handle to the device
155229aec1cSSascha Wildner  */
156229aec1cSSascha Wildner void
oce_hw_pci_free(POCE_SOFTC sc)157229aec1cSSascha Wildner oce_hw_pci_free(POCE_SOFTC sc)
158229aec1cSSascha Wildner {
159229aec1cSSascha Wildner 	int pci_cfg_barnum = 0;
160229aec1cSSascha Wildner 
161229aec1cSSascha Wildner 	if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
162229aec1cSSascha Wildner 		pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
163229aec1cSSascha Wildner 	else
164229aec1cSSascha Wildner 		pci_cfg_barnum = OCE_DEV_CFG_BAR;
165229aec1cSSascha Wildner 
166229aec1cSSascha Wildner 	if (sc->devcfg_res != NULL) {
167229aec1cSSascha Wildner 		bus_release_resource(sc->dev,
168229aec1cSSascha Wildner 				     SYS_RES_MEMORY,
169229aec1cSSascha Wildner 				     PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
17079ac1d4aSSascha Wildner 		sc->devcfg_res = NULL;
171229aec1cSSascha Wildner 		sc->devcfg_btag = (bus_space_tag_t) 0;
172229aec1cSSascha Wildner 		sc->devcfg_bhandle = (bus_space_handle_t)0;
17379ac1d4aSSascha Wildner 		sc->devcfg_vhandle = NULL;
174229aec1cSSascha Wildner 	}
175229aec1cSSascha Wildner 
176229aec1cSSascha Wildner 	if (sc->csr_res != NULL) {
177229aec1cSSascha Wildner 		bus_release_resource(sc->dev,
178229aec1cSSascha Wildner 				     SYS_RES_MEMORY,
179229aec1cSSascha Wildner 				     PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
18079ac1d4aSSascha Wildner 		sc->csr_res = NULL;
181229aec1cSSascha Wildner 		sc->csr_btag = (bus_space_tag_t)0;
182229aec1cSSascha Wildner 		sc->csr_bhandle = (bus_space_handle_t)0;
18379ac1d4aSSascha Wildner 		sc->csr_vhandle = NULL;
184229aec1cSSascha Wildner 	}
185229aec1cSSascha Wildner 
186229aec1cSSascha Wildner 	if (sc->db_res != NULL) {
187229aec1cSSascha Wildner 		bus_release_resource(sc->dev,
188229aec1cSSascha Wildner 				     SYS_RES_MEMORY,
189229aec1cSSascha Wildner 				     PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
19079ac1d4aSSascha Wildner 		sc->db_res = NULL;
191229aec1cSSascha Wildner 		sc->db_btag = (bus_space_tag_t)0;
192229aec1cSSascha Wildner 		sc->db_bhandle = (bus_space_handle_t)0;
19379ac1d4aSSascha Wildner 		sc->db_vhandle = NULL;
194229aec1cSSascha Wildner 	}
195229aec1cSSascha Wildner }
196229aec1cSSascha Wildner 
197229aec1cSSascha Wildner 
198229aec1cSSascha Wildner 
199229aec1cSSascha Wildner 
200229aec1cSSascha Wildner /**
201229aec1cSSascha Wildner  * @brief 		Function to get the PCI capabilities
202229aec1cSSascha Wildner  * @param sc		software handle to the device
203229aec1cSSascha Wildner  */
204229aec1cSSascha Wildner static
oce_get_pci_capabilities(POCE_SOFTC sc)205229aec1cSSascha Wildner void oce_get_pci_capabilities(POCE_SOFTC sc)
206229aec1cSSascha Wildner {
207229aec1cSSascha Wildner 	uint32_t val;
208229aec1cSSascha Wildner 
209229aec1cSSascha Wildner 	if (pci_is_pcix(sc->dev))
210229aec1cSSascha Wildner 		sc->flags |= OCE_FLAGS_PCIX;
211229aec1cSSascha Wildner 
212229aec1cSSascha Wildner 	if (pci_find_extcap(sc->dev, PCIY_EXPRESS, &val) == 0) {
213229aec1cSSascha Wildner 		if (val != 0) {
214229aec1cSSascha Wildner 			uint16_t link_status =
215229aec1cSSascha Wildner 			    pci_read_config(sc->dev, val + 0x12, 2);
216229aec1cSSascha Wildner 
217229aec1cSSascha Wildner 			sc->flags |= OCE_FLAGS_PCIE;
218229aec1cSSascha Wildner 			sc->pcie_link_speed = link_status & 0xf;
219229aec1cSSascha Wildner 			sc->pcie_link_width = (link_status >> 4) & 0x3f;
220229aec1cSSascha Wildner 		}
221229aec1cSSascha Wildner 	}
222229aec1cSSascha Wildner 
223229aec1cSSascha Wildner 	if (pci_find_extcap(sc->dev, PCIY_MSI, &val) == 0) {
224229aec1cSSascha Wildner 		if (val != 0)
225229aec1cSSascha Wildner 			sc->flags |= OCE_FLAGS_MSI_CAPABLE;
226229aec1cSSascha Wildner 	}
227229aec1cSSascha Wildner 
228229aec1cSSascha Wildner #if 0 /* XXX swildner: MSI-X */
229229aec1cSSascha Wildner 	if (pci_find_cap(sc->dev, PCIY_MSIX, &val) == 0) {
230229aec1cSSascha Wildner 		if (val != 0) {
231229aec1cSSascha Wildner 			val = pci_msix_count(sc->dev);
232229aec1cSSascha Wildner 			sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
233229aec1cSSascha Wildner 		}
234229aec1cSSascha Wildner 	}
235229aec1cSSascha Wildner #endif
236229aec1cSSascha Wildner }
237229aec1cSSascha Wildner 
238229aec1cSSascha Wildner /**
239229aec1cSSascha Wildner  * @brief	Allocate PCI resources.
240229aec1cSSascha Wildner  *
241229aec1cSSascha Wildner  * @param sc		software handle to the device
242229aec1cSSascha Wildner  * @returns		0 if successful, or error
243229aec1cSSascha Wildner  */
244229aec1cSSascha Wildner int
oce_hw_pci_alloc(POCE_SOFTC sc)245229aec1cSSascha Wildner oce_hw_pci_alloc(POCE_SOFTC sc)
246229aec1cSSascha Wildner {
247229aec1cSSascha Wildner 	int rr, pci_cfg_barnum = 0;
248229aec1cSSascha Wildner 	pci_sli_intf_t intf;
249229aec1cSSascha Wildner 
250229aec1cSSascha Wildner 	pci_enable_busmaster(sc->dev);
251229aec1cSSascha Wildner 
252229aec1cSSascha Wildner 	oce_get_pci_capabilities(sc);
253229aec1cSSascha Wildner 
254229aec1cSSascha Wildner 	sc->fn = pci_get_function(sc->dev);
255229aec1cSSascha Wildner 
256229aec1cSSascha Wildner 	/* setup the device config region */
257229aec1cSSascha Wildner 	if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
258229aec1cSSascha Wildner 		pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
259229aec1cSSascha Wildner 	else
260229aec1cSSascha Wildner 		pci_cfg_barnum = OCE_DEV_CFG_BAR;
261229aec1cSSascha Wildner 
262229aec1cSSascha Wildner 	rr = PCIR_BAR(pci_cfg_barnum);
263229aec1cSSascha Wildner 
264c976b08eSSascha Wildner 	if (IS_BE(sc) || IS_SH(sc))
265229aec1cSSascha Wildner 		sc->devcfg_res = bus_alloc_resource_any(sc->dev,
266229aec1cSSascha Wildner 				SYS_RES_MEMORY, &rr,
267229aec1cSSascha Wildner 				RF_ACTIVE|RF_SHAREABLE);
268229aec1cSSascha Wildner 	else
269229aec1cSSascha Wildner 		sc->devcfg_res = bus_alloc_resource(sc->dev,
270229aec1cSSascha Wildner 				SYS_RES_MEMORY, &rr,
271229aec1cSSascha Wildner 				0ul, ~0ul, 32768,
272229aec1cSSascha Wildner 				RF_ACTIVE|RF_SHAREABLE);
273229aec1cSSascha Wildner 
274229aec1cSSascha Wildner 	if (!sc->devcfg_res)
275229aec1cSSascha Wildner 		goto error;
276229aec1cSSascha Wildner 
277229aec1cSSascha Wildner 	sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
278229aec1cSSascha Wildner 	sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
279229aec1cSSascha Wildner 	sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
280229aec1cSSascha Wildner 
281229aec1cSSascha Wildner 	/* Read the SLI_INTF register and determine whether we
282229aec1cSSascha Wildner 	 * can use this port and its features
283229aec1cSSascha Wildner 	 */
284229aec1cSSascha Wildner 	intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
285229aec1cSSascha Wildner 
286229aec1cSSascha Wildner 	if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
287229aec1cSSascha Wildner 		goto error;
288229aec1cSSascha Wildner 
289229aec1cSSascha Wildner 	if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
290f734ea4bSSascha Wildner 		device_printf(sc->dev, "Adapter does not support SLI4\n");
291229aec1cSSascha Wildner 		goto error;
292229aec1cSSascha Wildner 	}
293229aec1cSSascha Wildner 
294229aec1cSSascha Wildner 	if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
295229aec1cSSascha Wildner 		sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
296229aec1cSSascha Wildner 
297229aec1cSSascha Wildner 	if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
298229aec1cSSascha Wildner 		sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
299229aec1cSSascha Wildner 
300229aec1cSSascha Wildner 	if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
301229aec1cSSascha Wildner 		sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
302229aec1cSSascha Wildner 
303229aec1cSSascha Wildner 	/* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
304c976b08eSSascha Wildner 	if (IS_BE(sc) || IS_SH(sc)) {
305229aec1cSSascha Wildner 		/* set up CSR region */
306229aec1cSSascha Wildner 		rr = PCIR_BAR(OCE_PCI_CSR_BAR);
307229aec1cSSascha Wildner 		sc->csr_res = bus_alloc_resource_any(sc->dev,
308229aec1cSSascha Wildner 				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
309229aec1cSSascha Wildner 		if (!sc->csr_res)
310229aec1cSSascha Wildner 			goto error;
311229aec1cSSascha Wildner 		sc->csr_btag = rman_get_bustag(sc->csr_res);
312229aec1cSSascha Wildner 		sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
313229aec1cSSascha Wildner 		sc->csr_vhandle = rman_get_virtual(sc->csr_res);
314229aec1cSSascha Wildner 
315229aec1cSSascha Wildner 		/* set up DB doorbell region */
316229aec1cSSascha Wildner 		rr = PCIR_BAR(OCE_PCI_DB_BAR);
317229aec1cSSascha Wildner 		sc->db_res = bus_alloc_resource_any(sc->dev,
318229aec1cSSascha Wildner 				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
319229aec1cSSascha Wildner 		if (!sc->db_res)
320229aec1cSSascha Wildner 			goto error;
321229aec1cSSascha Wildner 		sc->db_btag = rman_get_bustag(sc->db_res);
322229aec1cSSascha Wildner 		sc->db_bhandle = rman_get_bushandle(sc->db_res);
323229aec1cSSascha Wildner 		sc->db_vhandle = rman_get_virtual(sc->db_res);
324229aec1cSSascha Wildner 	}
325229aec1cSSascha Wildner 
326229aec1cSSascha Wildner 	return 0;
327229aec1cSSascha Wildner 
328229aec1cSSascha Wildner error:
329229aec1cSSascha Wildner 	oce_hw_pci_free(sc);
330229aec1cSSascha Wildner 	return ENXIO;
331229aec1cSSascha Wildner }
332229aec1cSSascha Wildner 
333229aec1cSSascha Wildner 
334229aec1cSSascha Wildner /**
335229aec1cSSascha Wildner  * @brief		Function for device shutdown
336229aec1cSSascha Wildner  * @param sc		software handle to the device
337229aec1cSSascha Wildner  * @returns		0 on success, error otherwise
338229aec1cSSascha Wildner  */
339229aec1cSSascha Wildner void
oce_hw_shutdown(POCE_SOFTC sc)340229aec1cSSascha Wildner oce_hw_shutdown(POCE_SOFTC sc)
341229aec1cSSascha Wildner {
342229aec1cSSascha Wildner 
343229aec1cSSascha Wildner 	oce_stats_free(sc);
344229aec1cSSascha Wildner 	/* disable hardware interrupts */
345229aec1cSSascha Wildner 	oce_hw_intr_disable(sc);
346229aec1cSSascha Wildner #if defined(INET6) || defined(INET)
347*56b41dfbSSascha Wildner #if 0 /* XXX swildner: LRO */
348229aec1cSSascha Wildner 	/* Free LRO resources */
349229aec1cSSascha Wildner 	oce_free_lro(sc);
350229aec1cSSascha Wildner #endif
351*56b41dfbSSascha Wildner #endif
352229aec1cSSascha Wildner 	/* Release queue*/
353229aec1cSSascha Wildner 	oce_queue_release_all(sc);
354229aec1cSSascha Wildner 	/*Delete Network Interface*/
355229aec1cSSascha Wildner 	oce_delete_nw_interface(sc);
356229aec1cSSascha Wildner 	/* After fw clean we dont send any cmds to fw.*/
357229aec1cSSascha Wildner 	oce_fw_clean(sc);
358229aec1cSSascha Wildner 	/* release intr resources */
359229aec1cSSascha Wildner 	oce_intr_free(sc);
360229aec1cSSascha Wildner 	/* release PCI resources */
361229aec1cSSascha Wildner 	oce_hw_pci_free(sc);
362229aec1cSSascha Wildner 	/* free mbox specific resources */
363229aec1cSSascha Wildner 	LOCK_DESTROY(&sc->bmbx_lock);
364229aec1cSSascha Wildner 	LOCK_DESTROY(&sc->dev_lock);
365229aec1cSSascha Wildner 
366229aec1cSSascha Wildner 	oce_dma_free(sc, &sc->bsmbx);
367229aec1cSSascha Wildner }
368229aec1cSSascha Wildner 
369229aec1cSSascha Wildner 
370229aec1cSSascha Wildner /**
371229aec1cSSascha Wildner  * @brief		Function for creating nw interface.
372229aec1cSSascha Wildner  * @param sc		software handle to the device
373229aec1cSSascha Wildner  * @returns		0 on success, error otherwise
374229aec1cSSascha Wildner  */
375229aec1cSSascha Wildner int
oce_create_nw_interface(POCE_SOFTC sc)376229aec1cSSascha Wildner oce_create_nw_interface(POCE_SOFTC sc)
377229aec1cSSascha Wildner {
378229aec1cSSascha Wildner 	int rc;
379229aec1cSSascha Wildner 	uint32_t capab_flags;
380229aec1cSSascha Wildner 	uint32_t capab_en_flags;
381229aec1cSSascha Wildner 
382229aec1cSSascha Wildner 	/* interface capabilities to give device when creating interface */
383229aec1cSSascha Wildner 	capab_flags = OCE_CAPAB_FLAGS;
384229aec1cSSascha Wildner 
385229aec1cSSascha Wildner 	/* capabilities to enable by default (others set dynamically) */
386229aec1cSSascha Wildner 	capab_en_flags = OCE_CAPAB_ENABLE;
387229aec1cSSascha Wildner 
388229aec1cSSascha Wildner 	if (IS_XE201(sc)) {
389229aec1cSSascha Wildner 		/* LANCER A0 workaround */
390229aec1cSSascha Wildner 		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
391229aec1cSSascha Wildner 		capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
392229aec1cSSascha Wildner 	}
393229aec1cSSascha Wildner 
394229aec1cSSascha Wildner 	/* enable capabilities controlled via driver startup parameters */
395c976b08eSSascha Wildner 	if (is_rss_enabled(sc))
396229aec1cSSascha Wildner 		capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
397229aec1cSSascha Wildner 	else {
398229aec1cSSascha Wildner 		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
399229aec1cSSascha Wildner 		capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
400229aec1cSSascha Wildner 	}
401229aec1cSSascha Wildner 
402229aec1cSSascha Wildner 	rc = oce_if_create(sc,
403229aec1cSSascha Wildner 			   capab_flags,
404229aec1cSSascha Wildner 			   capab_en_flags,
405229aec1cSSascha Wildner 			   0, &sc->macaddr.mac_addr[0], &sc->if_id);
406229aec1cSSascha Wildner 	if (rc)
407229aec1cSSascha Wildner 		return rc;
408229aec1cSSascha Wildner 
409229aec1cSSascha Wildner 	atomic_inc_32(&sc->nifs);
410229aec1cSSascha Wildner 
411229aec1cSSascha Wildner 	sc->if_cap_flags = capab_en_flags;
412229aec1cSSascha Wildner 
413229aec1cSSascha Wildner 	/* set default flow control */
414229aec1cSSascha Wildner 	rc = oce_set_flow_control(sc, sc->flow_control);
415229aec1cSSascha Wildner 	if (rc)
416229aec1cSSascha Wildner 		goto error;
417229aec1cSSascha Wildner 
418229aec1cSSascha Wildner 	rc = oce_rxf_set_promiscuous(sc, sc->promisc);
419229aec1cSSascha Wildner 	if (rc)
420229aec1cSSascha Wildner 		goto error;
421229aec1cSSascha Wildner 
422229aec1cSSascha Wildner 	return rc;
423229aec1cSSascha Wildner 
424229aec1cSSascha Wildner error:
425229aec1cSSascha Wildner 	oce_delete_nw_interface(sc);
426229aec1cSSascha Wildner 	return rc;
427229aec1cSSascha Wildner 
428229aec1cSSascha Wildner }
429229aec1cSSascha Wildner 
430229aec1cSSascha Wildner /**
431229aec1cSSascha Wildner  * @brief		Function to delete a nw interface.
432229aec1cSSascha Wildner  * @param sc		software handle to the device
433229aec1cSSascha Wildner  */
434229aec1cSSascha Wildner void
oce_delete_nw_interface(POCE_SOFTC sc)435229aec1cSSascha Wildner oce_delete_nw_interface(POCE_SOFTC sc)
436229aec1cSSascha Wildner {
437229aec1cSSascha Wildner 	/* currently only single interface is implmeneted */
438229aec1cSSascha Wildner 	if (sc->nifs > 0) {
439229aec1cSSascha Wildner 		oce_if_del(sc, sc->if_id);
440229aec1cSSascha Wildner 		atomic_dec_32(&sc->nifs);
441229aec1cSSascha Wildner 	}
442229aec1cSSascha Wildner }
443229aec1cSSascha Wildner 
444229aec1cSSascha Wildner /**
445229aec1cSSascha Wildner  * @brief Soft reset.
446229aec1cSSascha Wildner  * @param sc		software handle to the device
447229aec1cSSascha Wildner  * @returns		0 on success, error otherwise
448229aec1cSSascha Wildner  */
449229aec1cSSascha Wildner int
oce_pci_soft_reset(POCE_SOFTC sc)450229aec1cSSascha Wildner oce_pci_soft_reset(POCE_SOFTC sc)
451229aec1cSSascha Wildner {
452229aec1cSSascha Wildner 	int rc;
453229aec1cSSascha Wildner 	mpu_ep_control_t ctrl;
454229aec1cSSascha Wildner 
455c976b08eSSascha Wildner 	ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
456229aec1cSSascha Wildner 	ctrl.bits.cpu_reset = 1;
457c976b08eSSascha Wildner 	OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
458229aec1cSSascha Wildner 	DELAY(50);
459229aec1cSSascha Wildner 	rc=oce_POST(sc);
460229aec1cSSascha Wildner 
461229aec1cSSascha Wildner 	return rc;
462229aec1cSSascha Wildner }
463229aec1cSSascha Wildner 
464229aec1cSSascha Wildner /**
465229aec1cSSascha Wildner  * @brief		Function for hardware start
466229aec1cSSascha Wildner  * @param sc		software handle to the device
467229aec1cSSascha Wildner  * @returns		0 on success, error otherwise
468229aec1cSSascha Wildner  */
469229aec1cSSascha Wildner int
oce_hw_start(POCE_SOFTC sc)470229aec1cSSascha Wildner oce_hw_start(POCE_SOFTC sc)
471229aec1cSSascha Wildner {
472229aec1cSSascha Wildner 	struct link_status link = { 0 };
473229aec1cSSascha Wildner 	int rc = 0;
474229aec1cSSascha Wildner 
475229aec1cSSascha Wildner 	rc = oce_get_link_status(sc, &link);
476229aec1cSSascha Wildner 	if (rc)
477229aec1cSSascha Wildner 		return 1;
478229aec1cSSascha Wildner 
479229aec1cSSascha Wildner 	if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
480229aec1cSSascha Wildner 		sc->link_status = NTWK_LOGICAL_LINK_UP;
481229aec1cSSascha Wildner 		if_link_state_change(sc->ifp);
482229aec1cSSascha Wildner 	} else {
483229aec1cSSascha Wildner 		sc->link_status = NTWK_LOGICAL_LINK_DOWN;
484229aec1cSSascha Wildner 		if_link_state_change(sc->ifp);
485229aec1cSSascha Wildner 	}
486229aec1cSSascha Wildner 
487229aec1cSSascha Wildner 	if (link.mac_speed > 0 && link.mac_speed < 5)
488229aec1cSSascha Wildner 		sc->link_speed = link.mac_speed;
489229aec1cSSascha Wildner 	else
490229aec1cSSascha Wildner 		sc->link_speed = 0;
491229aec1cSSascha Wildner 
492229aec1cSSascha Wildner 	sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
493229aec1cSSascha Wildner 
494229aec1cSSascha Wildner 	rc = oce_start_mq(sc->mq);
495229aec1cSSascha Wildner 
496229aec1cSSascha Wildner 	/* we need to get MCC aync events. So enable intrs and arm
497229aec1cSSascha Wildner 	   first EQ, Other EQs will be armed after interface is UP
498229aec1cSSascha Wildner 	*/
499229aec1cSSascha Wildner 	oce_hw_intr_enable(sc);
500229aec1cSSascha Wildner 	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
501229aec1cSSascha Wildner 
502229aec1cSSascha Wildner 	/* Send first mcc cmd and after that we get gracious
503229aec1cSSascha Wildner 	   MCC notifications from FW
504229aec1cSSascha Wildner 	*/
505229aec1cSSascha Wildner 	oce_first_mcc_cmd(sc);
506229aec1cSSascha Wildner 
507229aec1cSSascha Wildner 	return rc;
508229aec1cSSascha Wildner }
509229aec1cSSascha Wildner 
510229aec1cSSascha Wildner 
511229aec1cSSascha Wildner /**
512229aec1cSSascha Wildner  * @brief 		Function for hardware enable interupts.
513229aec1cSSascha Wildner  * @param sc		software handle to the device
514229aec1cSSascha Wildner  */
515229aec1cSSascha Wildner void
oce_hw_intr_enable(POCE_SOFTC sc)516229aec1cSSascha Wildner oce_hw_intr_enable(POCE_SOFTC sc)
517229aec1cSSascha Wildner {
518229aec1cSSascha Wildner 	uint32_t reg;
519229aec1cSSascha Wildner 
520229aec1cSSascha Wildner 	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
521229aec1cSSascha Wildner 	reg |= HOSTINTR_MASK;
522229aec1cSSascha Wildner 	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
523229aec1cSSascha Wildner 
524229aec1cSSascha Wildner }
525229aec1cSSascha Wildner 
526229aec1cSSascha Wildner 
527229aec1cSSascha Wildner /**
528229aec1cSSascha Wildner  * @brief 		Function for hardware disable interupts
529229aec1cSSascha Wildner  * @param sc		software handle to the device
530229aec1cSSascha Wildner  */
531229aec1cSSascha Wildner void
oce_hw_intr_disable(POCE_SOFTC sc)532229aec1cSSascha Wildner oce_hw_intr_disable(POCE_SOFTC sc)
533229aec1cSSascha Wildner {
534229aec1cSSascha Wildner 	uint32_t reg;
535229aec1cSSascha Wildner 
536229aec1cSSascha Wildner 	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
537229aec1cSSascha Wildner 	reg &= ~HOSTINTR_MASK;
538229aec1cSSascha Wildner 	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
539229aec1cSSascha Wildner }
540229aec1cSSascha Wildner 
541229aec1cSSascha Wildner 
542229aec1cSSascha Wildner 
543229aec1cSSascha Wildner /**
544229aec1cSSascha Wildner  * @brief		Function for hardware update multicast filter
545229aec1cSSascha Wildner  * @param sc		software handle to the device
546229aec1cSSascha Wildner  */
547229aec1cSSascha Wildner int
oce_hw_update_multicast(POCE_SOFTC sc)548229aec1cSSascha Wildner oce_hw_update_multicast(POCE_SOFTC sc)
549229aec1cSSascha Wildner {
550229aec1cSSascha Wildner 	struct ifnet    *ifp = sc->ifp;
551229aec1cSSascha Wildner 	struct ifmultiaddr *ifma;
552229aec1cSSascha Wildner 	struct mbx_set_common_iface_multicast *req = NULL;
553229aec1cSSascha Wildner 	OCE_DMA_MEM dma;
554229aec1cSSascha Wildner 	int rc = 0;
555229aec1cSSascha Wildner 
556229aec1cSSascha Wildner 	/* Allocate DMA mem*/
557229aec1cSSascha Wildner 	if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
558229aec1cSSascha Wildner 							&dma, 0))
559229aec1cSSascha Wildner 		return ENOMEM;
560229aec1cSSascha Wildner 
561229aec1cSSascha Wildner 	req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
562229aec1cSSascha Wildner 	bzero(req, sizeof(struct mbx_set_common_iface_multicast));
563229aec1cSSascha Wildner 
564229aec1cSSascha Wildner 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
565229aec1cSSascha Wildner 		if (ifma->ifma_addr->sa_family != AF_LINK)
566229aec1cSSascha Wildner 			continue;
567229aec1cSSascha Wildner 
568229aec1cSSascha Wildner 		if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
569229aec1cSSascha Wildner 			/*More multicast addresses than our hardware table
570229aec1cSSascha Wildner 			  So Enable multicast promiscus in our hardware to
571229aec1cSSascha Wildner 			  accept all multicat packets
572229aec1cSSascha Wildner 			*/
573229aec1cSSascha Wildner 			req->params.req.promiscuous = 1;
574229aec1cSSascha Wildner 			break;
575229aec1cSSascha Wildner 		}
576229aec1cSSascha Wildner 		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
577229aec1cSSascha Wildner 			&req->params.req.mac[req->params.req.num_mac],
578229aec1cSSascha Wildner 			ETH_ADDR_LEN);
579229aec1cSSascha Wildner 		req->params.req.num_mac = req->params.req.num_mac + 1;
580229aec1cSSascha Wildner 	}
581229aec1cSSascha Wildner 	req->params.req.if_id = sc->if_id;
582229aec1cSSascha Wildner 	rc = oce_update_multicast(sc, &dma);
583229aec1cSSascha Wildner 	oce_dma_free(sc, &dma);
584229aec1cSSascha Wildner 	return rc;
585229aec1cSSascha Wildner }
586