1/*-
2 * Copyright (C) 2013 Emulex
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the Emulex Corporation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Contact Information:
32 * freebsd-drivers@emulex.com
33 *
34 * Emulex
35 * 3333 Susan Street
36 * Costa Mesa, CA 92626
37 */
38
39/* $FreeBSD: head/sys/dev/oce/oce_hw.c 257007 2013-10-23 18:58:38Z delphij $ */
40
41
42#include "oce_if.h"
43
44static int oce_POST(POCE_SOFTC sc);
45
46/**
47 * @brief Function to post status
48 * @param sc software handle to the device
49 */
50static int
51oce_POST(POCE_SOFTC sc)
52{
53 mpu_ep_semaphore_t post_status;
54 int tmo = 60000;
55
56 /* read semaphore CSR */
57 post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
58
59 /* if host is ready then wait for fw ready else send POST */
60 if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
61 post_status.bits.stage = POST_STAGE_CHIP_RESET;
62 OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc), post_status.dw0);
63 }
64
65 /* wait for FW ready */
66 for (;;) {
67 if (--tmo == 0)
68 break;
69
70 DELAY(1000);
71
72 post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
73 if (post_status.bits.error) {
74 device_printf(sc->dev,
75 "POST failed: %x\n", post_status.dw0);
76 return ENXIO;
77 }
78 if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
79 return 0;
80 }
81
82 device_printf(sc->dev, "POST timed out: %x\n", post_status.dw0);
83
84 return ENXIO;
85}
86
87/**
88 * @brief Function for hardware initialization
89 * @param sc software handle to the device
90 */
91int
92oce_hw_init(POCE_SOFTC sc)
93{
94 int rc = 0;
95
96 rc = oce_POST(sc);
97 if (rc)
98 return rc;
99
100 /* create the bootstrap mailbox */
101 rc = oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->bsmbx, 0);
102 if (rc) {
103 device_printf(sc->dev, "Mailbox alloc failed\n");
104 return rc;
105 }
106
107 rc = oce_reset_fun(sc);
108 if (rc)
109 goto error;
110
111
112 rc = oce_mbox_init(sc);
113 if (rc)
114 goto error;
115
116
117 rc = oce_get_fw_version(sc);
118 if (rc)
119 goto error;
120
121
122 rc = oce_get_fw_config(sc);
123 if (rc)
124 goto error;
125
126
127 sc->macaddr.size_of_struct = 6;
128 rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
129 &sc->macaddr);
130 if (rc)
131 goto error;
132
133 if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
134 rc = oce_mbox_check_native_mode(sc);
135 if (rc)
136 goto error;
137 } else
138 sc->be3_native = 0;
139
140 return rc;
141
142error:
143 oce_dma_free(sc, &sc->bsmbx);
144 device_printf(sc->dev, "Hardware initialisation failed\n");
145 return rc;
146}
147
148
149
150/**
151 * @brief Releases the obtained pci resources
152 * @param sc software handle to the device
153 */
154void
155oce_hw_pci_free(POCE_SOFTC sc)
156{
157 int pci_cfg_barnum = 0;
158
159 if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
160 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
161 else
162 pci_cfg_barnum = OCE_DEV_CFG_BAR;
163
164 if (sc->devcfg_res != NULL) {
165 bus_release_resource(sc->dev,
166 SYS_RES_MEMORY,
167 PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
168 sc->devcfg_res = (struct resource *)NULL;
169 sc->devcfg_btag = (bus_space_tag_t) 0;
170 sc->devcfg_bhandle = (bus_space_handle_t)0;
171 sc->devcfg_vhandle = (void *)NULL;
172 }
173
174 if (sc->csr_res != NULL) {
175 bus_release_resource(sc->dev,
176 SYS_RES_MEMORY,
177 PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
178 sc->csr_res = (struct resource *)NULL;
179 sc->csr_btag = (bus_space_tag_t)0;
180 sc->csr_bhandle = (bus_space_handle_t)0;
181 sc->csr_vhandle = (void *)NULL;
182 }
183
184 if (sc->db_res != NULL) {
185 bus_release_resource(sc->dev,
186 SYS_RES_MEMORY,
187 PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
188 sc->db_res = (struct resource *)NULL;
189 sc->db_btag = (bus_space_tag_t)0;
190 sc->db_bhandle = (bus_space_handle_t)0;
191 sc->db_vhandle = (void *)NULL;
192 }
193}
194
195
196
197
198/**
199 * @brief Function to get the PCI capabilities
200 * @param sc software handle to the device
201 */
202static
203void oce_get_pci_capabilities(POCE_SOFTC sc)
204{
205 uint32_t val;
206
207#if __FreeBSD_version >= 1000000
208 #define pci_find_extcap pci_find_cap
209#endif
210
211 if (pci_find_extcap(sc->dev, PCIY_PCIX, &val) == 0) {
212 if (val != 0)
213 sc->flags |= OCE_FLAGS_PCIX;
214 }
215
216 if (pci_find_extcap(sc->dev, PCIY_EXPRESS, &val) == 0) {
217 if (val != 0) {
218 uint16_t link_status =
219 pci_read_config(sc->dev, val + 0x12, 2);
220
221 sc->flags |= OCE_FLAGS_PCIE;
222 sc->pcie_link_speed = link_status & 0xf;
223 sc->pcie_link_width = (link_status >> 4) & 0x3f;
224 }
225 }
226
227 if (pci_find_extcap(sc->dev, PCIY_MSI, &val) == 0) {
228 if (val != 0)
229 sc->flags |= OCE_FLAGS_MSI_CAPABLE;
230 }
231
232 if (pci_find_extcap(sc->dev, PCIY_MSIX, &val) == 0) {
233 if (val != 0) {
234 val = pci_msix_count(sc->dev);
235 sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
236 }
237 }
238}
239
240/**
241 * @brief Allocate PCI resources.
242 *
243 * @param sc software handle to the device
244 * @returns 0 if successful, or error
245 */
246int
247oce_hw_pci_alloc(POCE_SOFTC sc)
248{
249 int rr, pci_cfg_barnum = 0;
250 pci_sli_intf_t intf;
251
252 pci_enable_busmaster(sc->dev);
253
254 oce_get_pci_capabilities(sc);
255
256 sc->fn = pci_get_function(sc->dev);
257
258 /* setup the device config region */
259 if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
260 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
261 else
262 pci_cfg_barnum = OCE_DEV_CFG_BAR;
263
264 rr = PCIR_BAR(pci_cfg_barnum);
265
266 if (IS_BE(sc) || IS_SH(sc))
267 sc->devcfg_res = bus_alloc_resource_any(sc->dev,
268 SYS_RES_MEMORY, &rr,
269 RF_ACTIVE|RF_SHAREABLE);
270 else
271 sc->devcfg_res = bus_alloc_resource(sc->dev,
272 SYS_RES_MEMORY, &rr,
273 0ul, ~0ul, 32768,
274 RF_ACTIVE|RF_SHAREABLE);
275
276 if (!sc->devcfg_res)
277 goto error;
278
279 sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
280 sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
281 sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
282
283 /* Read the SLI_INTF register and determine whether we
284 * can use this port and its features
285 */
286 intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
287
288 if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
289 goto error;
290
291 if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
292 device_printf(sc->dev, "Adapter doesnt support SLI4\n");
293 goto error;
294 }
295
296 if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
297 sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
298
299 if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
300 sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
301
302 if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
303 sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
304
305 /* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
306 if (IS_BE(sc) || IS_SH(sc)) {
307 /* set up CSR region */
308 rr = PCIR_BAR(OCE_PCI_CSR_BAR);
309 sc->csr_res = bus_alloc_resource_any(sc->dev,
310 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
311 if (!sc->csr_res)
312 goto error;
313 sc->csr_btag = rman_get_bustag(sc->csr_res);
314 sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
315 sc->csr_vhandle = rman_get_virtual(sc->csr_res);
316
317 /* set up DB doorbell region */
318 rr = PCIR_BAR(OCE_PCI_DB_BAR);
319 sc->db_res = bus_alloc_resource_any(sc->dev,
320 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
321 if (!sc->db_res)
322 goto error;
323 sc->db_btag = rman_get_bustag(sc->db_res);
324 sc->db_bhandle = rman_get_bushandle(sc->db_res);
325 sc->db_vhandle = rman_get_virtual(sc->db_res);
326 }
327
328 return 0;
329
330error:
331 oce_hw_pci_free(sc);
332 return ENXIO;
333}
334
335
336/**
337 * @brief Function for device shutdown
338 * @param sc software handle to the device
339 * @returns 0 on success, error otherwise
340 */
341void
342oce_hw_shutdown(POCE_SOFTC sc)
343{
344
345 oce_stats_free(sc);
346 /* disable hardware interrupts */
347 oce_hw_intr_disable(sc);
348#if defined(INET6) || defined(INET)
349 /* Free LRO resources */
350 oce_free_lro(sc);
351#endif
352 /* Release queue*/
353 oce_queue_release_all(sc);
354 /*Delete Network Interface*/
355 oce_delete_nw_interface(sc);
356 /* After fw clean we dont send any cmds to fw.*/
357 oce_fw_clean(sc);
358 /* release intr resources */
359 oce_intr_free(sc);
360 /* release PCI resources */
361 oce_hw_pci_free(sc);
362 /* free mbox specific resources */
363 LOCK_DESTROY(&sc->bmbx_lock);
364 LOCK_DESTROY(&sc->dev_lock);
365
366 oce_dma_free(sc, &sc->bsmbx);
367}
368
369
370/**
371 * @brief Function for creating nw interface.
372 * @param sc software handle to the device
373 * @returns 0 on success, error otherwise
374 */
375int
376oce_create_nw_interface(POCE_SOFTC sc)
377{
378 int rc;
379 uint32_t capab_flags;
380 uint32_t capab_en_flags;
381
382 /* interface capabilities to give device when creating interface */
383 capab_flags = OCE_CAPAB_FLAGS;
384
385 /* capabilities to enable by default (others set dynamically) */
386 capab_en_flags = OCE_CAPAB_ENABLE;
387
388 if (IS_XE201(sc)) {
389 /* LANCER A0 workaround */
390 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
391 capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
392 }
393
394 if (IS_SH(sc) || IS_XE201(sc))
395 capab_flags |= MBX_RX_IFACE_FLAGS_MULTICAST;
396
397 /* enable capabilities controlled via driver startup parameters */
398 if (is_rss_enabled(sc))
399 capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
400 else {
401 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
402 capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
403 }
404
405 rc = oce_if_create(sc,
406 capab_flags,
407 capab_en_flags,
408 0, &sc->macaddr.mac_addr[0], &sc->if_id);
409 if (rc)
410 return rc;
411
412 atomic_inc_32(&sc->nifs);
413
414 sc->if_cap_flags = capab_en_flags;
415
416 /* set default flow control */
417 rc = oce_set_flow_control(sc, sc->flow_control);
418 if (rc)
419 goto error;
420
421 rc = oce_rxf_set_promiscuous(sc, sc->promisc);
422 if (rc)
423 goto error;
424
425 return rc;
426
427error:
428 oce_delete_nw_interface(sc);
429 return rc;
430
431}
432
433/**
434 * @brief Function to delete a nw interface.
435 * @param sc software handle to the device
436 */
437void
438oce_delete_nw_interface(POCE_SOFTC sc)
439{
440 /* currently only single interface is implmeneted */
441 if (sc->nifs > 0) {
442 oce_if_del(sc, sc->if_id);
443 atomic_dec_32(&sc->nifs);
444 }
445}
446
447/**
448 * @brief Soft reset.
449 * @param sc software handle to the device
450 * @returns 0 on success, error otherwise
451 */
452int
453oce_pci_soft_reset(POCE_SOFTC sc)
454{
455 int rc;
456 mpu_ep_control_t ctrl;
457
458 ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
459 ctrl.bits.cpu_reset = 1;
460 OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
461 DELAY(50);
462 rc=oce_POST(sc);
463
464 return rc;
465}
466
467/**
468 * @brief Function for hardware start
469 * @param sc software handle to the device
470 * @returns 0 on success, error otherwise
471 */
472int
473oce_hw_start(POCE_SOFTC sc)
474{
475 struct link_status link = { 0 };
476 int rc = 0;
477
478 rc = oce_get_link_status(sc, &link);
479 if (rc)
480 return 1;
481
482 if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
483 sc->link_status = NTWK_LOGICAL_LINK_UP;
484 if_link_state_change(sc->ifp, LINK_STATE_UP);
485 } else {
486 sc->link_status = NTWK_LOGICAL_LINK_DOWN;
487 if_link_state_change(sc->ifp, LINK_STATE_DOWN);
488 }
489
490 if (link.mac_speed > 0 && link.mac_speed < 5)
491 sc->link_speed = link.mac_speed;
492 else
493 sc->link_speed = 0;
494
495 sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
496
497 rc = oce_start_mq(sc->mq);
498
499 /* we need to get MCC aync events. So enable intrs and arm
500 first EQ, Other EQs will be armed after interface is UP
501 */
502 oce_hw_intr_enable(sc);
503 oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
504
505 /* Send first mcc cmd and after that we get gracious
506 MCC notifications from FW
507 */
508 oce_first_mcc_cmd(sc);
509
510 return rc;
511}
512
513
514/**
515 * @brief Function for hardware enable interupts.
516 * @param sc software handle to the device
517 */
518void
519oce_hw_intr_enable(POCE_SOFTC sc)
520{
521 uint32_t reg;
522
523 reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
524 reg |= HOSTINTR_MASK;
525 OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
526
527}
528
529
530/**
531 * @brief Function for hardware disable interupts
532 * @param sc software handle to the device
533 */
534void
535oce_hw_intr_disable(POCE_SOFTC sc)
536{
537 uint32_t reg;
538
539 reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
540 reg &= ~HOSTINTR_MASK;
541 OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
542}
543
544
545
546/**
547 * @brief Function for hardware update multicast filter
548 * @param sc software handle to the device
549 */
550int
551oce_hw_update_multicast(POCE_SOFTC sc)
552{
553 struct ifnet *ifp = sc->ifp;
554 struct ifmultiaddr *ifma;
555 struct mbx_set_common_iface_multicast *req = NULL;
556 OCE_DMA_MEM dma;
557 int rc = 0;
558
559 /* Allocate DMA mem*/
560 if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
561 &dma, 0))
562 return ENOMEM;
563
564 req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
565 bzero(req, sizeof(struct mbx_set_common_iface_multicast));
566
567#if __FreeBSD_version > 800000
568 if_maddr_rlock(ifp);
569#endif
570 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
571 if (ifma->ifma_addr->sa_family != AF_LINK)
572 continue;
573
574 if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
575 /*More multicast addresses than our hardware table
576 So Enable multicast promiscus in our hardware to
577 accept all multicat packets
578 */
579 req->params.req.promiscuous = 1;
580 break;
581 }
582 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
583 &req->params.req.mac[req->params.req.num_mac],
584 ETH_ADDR_LEN);
585 req->params.req.num_mac = req->params.req.num_mac + 1;
586 }
587#if __FreeBSD_version > 800000
588 if_maddr_runlock(ifp);
589#endif
590 req->params.req.if_id = sc->if_id;
591 rc = oce_update_multicast(sc, &dma);
592 oce_dma_free(sc, &dma);
593 return rc;
594}
595
2 * Copyright (C) 2013 Emulex
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the Emulex Corporation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Contact Information:
32 * freebsd-drivers@emulex.com
33 *
34 * Emulex
35 * 3333 Susan Street
36 * Costa Mesa, CA 92626
37 */
38
39/* $FreeBSD: head/sys/dev/oce/oce_hw.c 257007 2013-10-23 18:58:38Z delphij $ */
40
41
42#include "oce_if.h"
43
44static int oce_POST(POCE_SOFTC sc);
45
46/**
47 * @brief Function to post status
48 * @param sc software handle to the device
49 */
50static int
51oce_POST(POCE_SOFTC sc)
52{
53 mpu_ep_semaphore_t post_status;
54 int tmo = 60000;
55
56 /* read semaphore CSR */
57 post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
58
59 /* if host is ready then wait for fw ready else send POST */
60 if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
61 post_status.bits.stage = POST_STAGE_CHIP_RESET;
62 OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc), post_status.dw0);
63 }
64
65 /* wait for FW ready */
66 for (;;) {
67 if (--tmo == 0)
68 break;
69
70 DELAY(1000);
71
72 post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
73 if (post_status.bits.error) {
74 device_printf(sc->dev,
75 "POST failed: %x\n", post_status.dw0);
76 return ENXIO;
77 }
78 if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
79 return 0;
80 }
81
82 device_printf(sc->dev, "POST timed out: %x\n", post_status.dw0);
83
84 return ENXIO;
85}
86
87/**
88 * @brief Function for hardware initialization
89 * @param sc software handle to the device
90 */
91int
92oce_hw_init(POCE_SOFTC sc)
93{
94 int rc = 0;
95
96 rc = oce_POST(sc);
97 if (rc)
98 return rc;
99
100 /* create the bootstrap mailbox */
101 rc = oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->bsmbx, 0);
102 if (rc) {
103 device_printf(sc->dev, "Mailbox alloc failed\n");
104 return rc;
105 }
106
107 rc = oce_reset_fun(sc);
108 if (rc)
109 goto error;
110
111
112 rc = oce_mbox_init(sc);
113 if (rc)
114 goto error;
115
116
117 rc = oce_get_fw_version(sc);
118 if (rc)
119 goto error;
120
121
122 rc = oce_get_fw_config(sc);
123 if (rc)
124 goto error;
125
126
127 sc->macaddr.size_of_struct = 6;
128 rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
129 &sc->macaddr);
130 if (rc)
131 goto error;
132
133 if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
134 rc = oce_mbox_check_native_mode(sc);
135 if (rc)
136 goto error;
137 } else
138 sc->be3_native = 0;
139
140 return rc;
141
142error:
143 oce_dma_free(sc, &sc->bsmbx);
144 device_printf(sc->dev, "Hardware initialisation failed\n");
145 return rc;
146}
147
148
149
150/**
151 * @brief Releases the obtained pci resources
152 * @param sc software handle to the device
153 */
154void
155oce_hw_pci_free(POCE_SOFTC sc)
156{
157 int pci_cfg_barnum = 0;
158
159 if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
160 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
161 else
162 pci_cfg_barnum = OCE_DEV_CFG_BAR;
163
164 if (sc->devcfg_res != NULL) {
165 bus_release_resource(sc->dev,
166 SYS_RES_MEMORY,
167 PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
168 sc->devcfg_res = (struct resource *)NULL;
169 sc->devcfg_btag = (bus_space_tag_t) 0;
170 sc->devcfg_bhandle = (bus_space_handle_t)0;
171 sc->devcfg_vhandle = (void *)NULL;
172 }
173
174 if (sc->csr_res != NULL) {
175 bus_release_resource(sc->dev,
176 SYS_RES_MEMORY,
177 PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
178 sc->csr_res = (struct resource *)NULL;
179 sc->csr_btag = (bus_space_tag_t)0;
180 sc->csr_bhandle = (bus_space_handle_t)0;
181 sc->csr_vhandle = (void *)NULL;
182 }
183
184 if (sc->db_res != NULL) {
185 bus_release_resource(sc->dev,
186 SYS_RES_MEMORY,
187 PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
188 sc->db_res = (struct resource *)NULL;
189 sc->db_btag = (bus_space_tag_t)0;
190 sc->db_bhandle = (bus_space_handle_t)0;
191 sc->db_vhandle = (void *)NULL;
192 }
193}
194
195
196
197
198/**
199 * @brief Function to get the PCI capabilities
200 * @param sc software handle to the device
201 */
202static
203void oce_get_pci_capabilities(POCE_SOFTC sc)
204{
205 uint32_t val;
206
207#if __FreeBSD_version >= 1000000
208 #define pci_find_extcap pci_find_cap
209#endif
210
211 if (pci_find_extcap(sc->dev, PCIY_PCIX, &val) == 0) {
212 if (val != 0)
213 sc->flags |= OCE_FLAGS_PCIX;
214 }
215
216 if (pci_find_extcap(sc->dev, PCIY_EXPRESS, &val) == 0) {
217 if (val != 0) {
218 uint16_t link_status =
219 pci_read_config(sc->dev, val + 0x12, 2);
220
221 sc->flags |= OCE_FLAGS_PCIE;
222 sc->pcie_link_speed = link_status & 0xf;
223 sc->pcie_link_width = (link_status >> 4) & 0x3f;
224 }
225 }
226
227 if (pci_find_extcap(sc->dev, PCIY_MSI, &val) == 0) {
228 if (val != 0)
229 sc->flags |= OCE_FLAGS_MSI_CAPABLE;
230 }
231
232 if (pci_find_extcap(sc->dev, PCIY_MSIX, &val) == 0) {
233 if (val != 0) {
234 val = pci_msix_count(sc->dev);
235 sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
236 }
237 }
238}
239
240/**
241 * @brief Allocate PCI resources.
242 *
243 * @param sc software handle to the device
244 * @returns 0 if successful, or error
245 */
246int
247oce_hw_pci_alloc(POCE_SOFTC sc)
248{
249 int rr, pci_cfg_barnum = 0;
250 pci_sli_intf_t intf;
251
252 pci_enable_busmaster(sc->dev);
253
254 oce_get_pci_capabilities(sc);
255
256 sc->fn = pci_get_function(sc->dev);
257
258 /* setup the device config region */
259 if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
260 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
261 else
262 pci_cfg_barnum = OCE_DEV_CFG_BAR;
263
264 rr = PCIR_BAR(pci_cfg_barnum);
265
266 if (IS_BE(sc) || IS_SH(sc))
267 sc->devcfg_res = bus_alloc_resource_any(sc->dev,
268 SYS_RES_MEMORY, &rr,
269 RF_ACTIVE|RF_SHAREABLE);
270 else
271 sc->devcfg_res = bus_alloc_resource(sc->dev,
272 SYS_RES_MEMORY, &rr,
273 0ul, ~0ul, 32768,
274 RF_ACTIVE|RF_SHAREABLE);
275
276 if (!sc->devcfg_res)
277 goto error;
278
279 sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
280 sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
281 sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
282
283 /* Read the SLI_INTF register and determine whether we
284 * can use this port and its features
285 */
286 intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
287
288 if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
289 goto error;
290
291 if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
292 device_printf(sc->dev, "Adapter doesnt support SLI4\n");
293 goto error;
294 }
295
296 if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
297 sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
298
299 if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
300 sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
301
302 if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
303 sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
304
305 /* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
306 if (IS_BE(sc) || IS_SH(sc)) {
307 /* set up CSR region */
308 rr = PCIR_BAR(OCE_PCI_CSR_BAR);
309 sc->csr_res = bus_alloc_resource_any(sc->dev,
310 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
311 if (!sc->csr_res)
312 goto error;
313 sc->csr_btag = rman_get_bustag(sc->csr_res);
314 sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
315 sc->csr_vhandle = rman_get_virtual(sc->csr_res);
316
317 /* set up DB doorbell region */
318 rr = PCIR_BAR(OCE_PCI_DB_BAR);
319 sc->db_res = bus_alloc_resource_any(sc->dev,
320 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
321 if (!sc->db_res)
322 goto error;
323 sc->db_btag = rman_get_bustag(sc->db_res);
324 sc->db_bhandle = rman_get_bushandle(sc->db_res);
325 sc->db_vhandle = rman_get_virtual(sc->db_res);
326 }
327
328 return 0;
329
330error:
331 oce_hw_pci_free(sc);
332 return ENXIO;
333}
334
335
336/**
337 * @brief Function for device shutdown
338 * @param sc software handle to the device
339 * @returns 0 on success, error otherwise
340 */
341void
342oce_hw_shutdown(POCE_SOFTC sc)
343{
344
345 oce_stats_free(sc);
346 /* disable hardware interrupts */
347 oce_hw_intr_disable(sc);
348#if defined(INET6) || defined(INET)
349 /* Free LRO resources */
350 oce_free_lro(sc);
351#endif
352 /* Release queue*/
353 oce_queue_release_all(sc);
354 /*Delete Network Interface*/
355 oce_delete_nw_interface(sc);
356 /* After fw clean we dont send any cmds to fw.*/
357 oce_fw_clean(sc);
358 /* release intr resources */
359 oce_intr_free(sc);
360 /* release PCI resources */
361 oce_hw_pci_free(sc);
362 /* free mbox specific resources */
363 LOCK_DESTROY(&sc->bmbx_lock);
364 LOCK_DESTROY(&sc->dev_lock);
365
366 oce_dma_free(sc, &sc->bsmbx);
367}
368
369
370/**
371 * @brief Function for creating nw interface.
372 * @param sc software handle to the device
373 * @returns 0 on success, error otherwise
374 */
375int
376oce_create_nw_interface(POCE_SOFTC sc)
377{
378 int rc;
379 uint32_t capab_flags;
380 uint32_t capab_en_flags;
381
382 /* interface capabilities to give device when creating interface */
383 capab_flags = OCE_CAPAB_FLAGS;
384
385 /* capabilities to enable by default (others set dynamically) */
386 capab_en_flags = OCE_CAPAB_ENABLE;
387
388 if (IS_XE201(sc)) {
389 /* LANCER A0 workaround */
390 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
391 capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
392 }
393
394 if (IS_SH(sc) || IS_XE201(sc))
395 capab_flags |= MBX_RX_IFACE_FLAGS_MULTICAST;
396
397 /* enable capabilities controlled via driver startup parameters */
398 if (is_rss_enabled(sc))
399 capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
400 else {
401 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
402 capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
403 }
404
405 rc = oce_if_create(sc,
406 capab_flags,
407 capab_en_flags,
408 0, &sc->macaddr.mac_addr[0], &sc->if_id);
409 if (rc)
410 return rc;
411
412 atomic_inc_32(&sc->nifs);
413
414 sc->if_cap_flags = capab_en_flags;
415
416 /* set default flow control */
417 rc = oce_set_flow_control(sc, sc->flow_control);
418 if (rc)
419 goto error;
420
421 rc = oce_rxf_set_promiscuous(sc, sc->promisc);
422 if (rc)
423 goto error;
424
425 return rc;
426
427error:
428 oce_delete_nw_interface(sc);
429 return rc;
430
431}
432
433/**
434 * @brief Function to delete a nw interface.
435 * @param sc software handle to the device
436 */
437void
438oce_delete_nw_interface(POCE_SOFTC sc)
439{
440 /* currently only single interface is implmeneted */
441 if (sc->nifs > 0) {
442 oce_if_del(sc, sc->if_id);
443 atomic_dec_32(&sc->nifs);
444 }
445}
446
447/**
448 * @brief Soft reset.
449 * @param sc software handle to the device
450 * @returns 0 on success, error otherwise
451 */
452int
453oce_pci_soft_reset(POCE_SOFTC sc)
454{
455 int rc;
456 mpu_ep_control_t ctrl;
457
458 ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
459 ctrl.bits.cpu_reset = 1;
460 OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
461 DELAY(50);
462 rc=oce_POST(sc);
463
464 return rc;
465}
466
467/**
468 * @brief Function for hardware start
469 * @param sc software handle to the device
470 * @returns 0 on success, error otherwise
471 */
472int
473oce_hw_start(POCE_SOFTC sc)
474{
475 struct link_status link = { 0 };
476 int rc = 0;
477
478 rc = oce_get_link_status(sc, &link);
479 if (rc)
480 return 1;
481
482 if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
483 sc->link_status = NTWK_LOGICAL_LINK_UP;
484 if_link_state_change(sc->ifp, LINK_STATE_UP);
485 } else {
486 sc->link_status = NTWK_LOGICAL_LINK_DOWN;
487 if_link_state_change(sc->ifp, LINK_STATE_DOWN);
488 }
489
490 if (link.mac_speed > 0 && link.mac_speed < 5)
491 sc->link_speed = link.mac_speed;
492 else
493 sc->link_speed = 0;
494
495 sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
496
497 rc = oce_start_mq(sc->mq);
498
499 /* we need to get MCC aync events. So enable intrs and arm
500 first EQ, Other EQs will be armed after interface is UP
501 */
502 oce_hw_intr_enable(sc);
503 oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
504
505 /* Send first mcc cmd and after that we get gracious
506 MCC notifications from FW
507 */
508 oce_first_mcc_cmd(sc);
509
510 return rc;
511}
512
513
514/**
515 * @brief Function for hardware enable interupts.
516 * @param sc software handle to the device
517 */
518void
519oce_hw_intr_enable(POCE_SOFTC sc)
520{
521 uint32_t reg;
522
523 reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
524 reg |= HOSTINTR_MASK;
525 OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
526
527}
528
529
530/**
531 * @brief Function for hardware disable interupts
532 * @param sc software handle to the device
533 */
534void
535oce_hw_intr_disable(POCE_SOFTC sc)
536{
537 uint32_t reg;
538
539 reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
540 reg &= ~HOSTINTR_MASK;
541 OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
542}
543
544
545
546/**
547 * @brief Function for hardware update multicast filter
548 * @param sc software handle to the device
549 */
550int
551oce_hw_update_multicast(POCE_SOFTC sc)
552{
553 struct ifnet *ifp = sc->ifp;
554 struct ifmultiaddr *ifma;
555 struct mbx_set_common_iface_multicast *req = NULL;
556 OCE_DMA_MEM dma;
557 int rc = 0;
558
559 /* Allocate DMA mem*/
560 if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
561 &dma, 0))
562 return ENOMEM;
563
564 req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
565 bzero(req, sizeof(struct mbx_set_common_iface_multicast));
566
567#if __FreeBSD_version > 800000
568 if_maddr_rlock(ifp);
569#endif
570 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
571 if (ifma->ifma_addr->sa_family != AF_LINK)
572 continue;
573
574 if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
575 /*More multicast addresses than our hardware table
576 So Enable multicast promiscus in our hardware to
577 accept all multicat packets
578 */
579 req->params.req.promiscuous = 1;
580 break;
581 }
582 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
583 &req->params.req.mac[req->params.req.num_mac],
584 ETH_ADDR_LEN);
585 req->params.req.num_mac = req->params.req.num_mac + 1;
586 }
587#if __FreeBSD_version > 800000
588 if_maddr_runlock(ifp);
589#endif
590 req->params.req.if_id = sc->if_id;
591 rc = oce_update_multicast(sc, &dma);
592 oce_dma_free(sc, &dma);
593 return rc;
594}
595