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