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: src/sys/dev/oce/oce_hw.c,v 1.8 2013/07/07 00:30:13 svnexp Exp $ */
40
41 #include "opt_inet6.h"
42 #include "opt_inet.h"
43
44 #include "oce_if.h"
45
46 static int oce_POST(POCE_SOFTC sc);
47
48 /**
49 * @brief Function to post status
50 * @param sc software handle to the device
51 */
52 static int
oce_POST(POCE_SOFTC sc)53 oce_POST(POCE_SOFTC sc)
54 {
55 mpu_ep_semaphore_t post_status;
56 int tmo = 60000;
57
58 /* read semaphore CSR */
59 post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
60
61 /* if host is ready then wait for fw ready else send POST */
62 if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
63 post_status.bits.stage = POST_STAGE_CHIP_RESET;
64 OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc), post_status.dw0);
65 }
66
67 /* wait for FW ready */
68 for (;;) {
69 if (--tmo == 0)
70 break;
71
72 DELAY(1000);
73
74 post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
75 if (post_status.bits.error) {
76 device_printf(sc->dev,
77 "POST failed: %x\n", post_status.dw0);
78 return ENXIO;
79 }
80 if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
81 return 0;
82 }
83
84 device_printf(sc->dev, "POST timed out: %x\n", post_status.dw0);
85
86 return ENXIO;
87 }
88
89 /**
90 * @brief Function for hardware initialization
91 * @param sc software handle to the device
92 */
93 int
oce_hw_init(POCE_SOFTC sc)94 oce_hw_init(POCE_SOFTC sc)
95 {
96 int rc = 0;
97
98 rc = oce_POST(sc);
99 if (rc)
100 return rc;
101
102 /* create the bootstrap mailbox */
103 rc = oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->bsmbx, 0);
104 if (rc) {
105 device_printf(sc->dev, "Mailbox alloc failed\n");
106 return rc;
107 }
108
109 rc = oce_reset_fun(sc);
110 if (rc)
111 goto error;
112
113
114 rc = oce_mbox_init(sc);
115 if (rc)
116 goto error;
117
118
119 rc = oce_get_fw_version(sc);
120 if (rc)
121 goto error;
122
123
124 rc = oce_get_fw_config(sc);
125 if (rc)
126 goto error;
127
128
129 sc->macaddr.size_of_struct = 6;
130 rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
131 &sc->macaddr);
132 if (rc)
133 goto error;
134
135 if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
136 rc = oce_mbox_check_native_mode(sc);
137 if (rc)
138 goto error;
139 } else
140 sc->be3_native = 0;
141
142 return rc;
143
144 error:
145 oce_dma_free(sc, &sc->bsmbx);
146 device_printf(sc->dev, "Hardware initialisation failed\n");
147 return rc;
148 }
149
150
151
152 /**
153 * @brief Releases the obtained pci resources
154 * @param sc software handle to the device
155 */
156 void
oce_hw_pci_free(POCE_SOFTC sc)157 oce_hw_pci_free(POCE_SOFTC sc)
158 {
159 int pci_cfg_barnum = 0;
160
161 if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
162 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
163 else
164 pci_cfg_barnum = OCE_DEV_CFG_BAR;
165
166 if (sc->devcfg_res != NULL) {
167 bus_release_resource(sc->dev,
168 SYS_RES_MEMORY,
169 PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
170 sc->devcfg_res = NULL;
171 sc->devcfg_btag = (bus_space_tag_t) 0;
172 sc->devcfg_bhandle = (bus_space_handle_t)0;
173 sc->devcfg_vhandle = NULL;
174 }
175
176 if (sc->csr_res != NULL) {
177 bus_release_resource(sc->dev,
178 SYS_RES_MEMORY,
179 PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
180 sc->csr_res = NULL;
181 sc->csr_btag = (bus_space_tag_t)0;
182 sc->csr_bhandle = (bus_space_handle_t)0;
183 sc->csr_vhandle = NULL;
184 }
185
186 if (sc->db_res != NULL) {
187 bus_release_resource(sc->dev,
188 SYS_RES_MEMORY,
189 PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
190 sc->db_res = NULL;
191 sc->db_btag = (bus_space_tag_t)0;
192 sc->db_bhandle = (bus_space_handle_t)0;
193 sc->db_vhandle = NULL;
194 }
195 }
196
197
198
199
200 /**
201 * @brief Function to get the PCI capabilities
202 * @param sc software handle to the device
203 */
204 static
oce_get_pci_capabilities(POCE_SOFTC sc)205 void oce_get_pci_capabilities(POCE_SOFTC sc)
206 {
207 uint32_t val;
208
209 if (pci_is_pcix(sc->dev))
210 sc->flags |= OCE_FLAGS_PCIX;
211
212 if (pci_find_extcap(sc->dev, PCIY_EXPRESS, &val) == 0) {
213 if (val != 0) {
214 uint16_t link_status =
215 pci_read_config(sc->dev, val + 0x12, 2);
216
217 sc->flags |= OCE_FLAGS_PCIE;
218 sc->pcie_link_speed = link_status & 0xf;
219 sc->pcie_link_width = (link_status >> 4) & 0x3f;
220 }
221 }
222
223 if (pci_find_extcap(sc->dev, PCIY_MSI, &val) == 0) {
224 if (val != 0)
225 sc->flags |= OCE_FLAGS_MSI_CAPABLE;
226 }
227
228 #if 0 /* XXX swildner: MSI-X */
229 if (pci_find_cap(sc->dev, PCIY_MSIX, &val) == 0) {
230 if (val != 0) {
231 val = pci_msix_count(sc->dev);
232 sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
233 }
234 }
235 #endif
236 }
237
238 /**
239 * @brief Allocate PCI resources.
240 *
241 * @param sc software handle to the device
242 * @returns 0 if successful, or error
243 */
244 int
oce_hw_pci_alloc(POCE_SOFTC sc)245 oce_hw_pci_alloc(POCE_SOFTC sc)
246 {
247 int rr, pci_cfg_barnum = 0;
248 pci_sli_intf_t intf;
249
250 pci_enable_busmaster(sc->dev);
251
252 oce_get_pci_capabilities(sc);
253
254 sc->fn = pci_get_function(sc->dev);
255
256 /* setup the device config region */
257 if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
258 pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
259 else
260 pci_cfg_barnum = OCE_DEV_CFG_BAR;
261
262 rr = PCIR_BAR(pci_cfg_barnum);
263
264 if (IS_BE(sc) || IS_SH(sc))
265 sc->devcfg_res = bus_alloc_resource_any(sc->dev,
266 SYS_RES_MEMORY, &rr,
267 RF_ACTIVE|RF_SHAREABLE);
268 else
269 sc->devcfg_res = bus_alloc_resource(sc->dev,
270 SYS_RES_MEMORY, &rr,
271 0ul, ~0ul, 32768,
272 RF_ACTIVE|RF_SHAREABLE);
273
274 if (!sc->devcfg_res)
275 goto error;
276
277 sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
278 sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
279 sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
280
281 /* Read the SLI_INTF register and determine whether we
282 * can use this port and its features
283 */
284 intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
285
286 if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
287 goto error;
288
289 if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
290 device_printf(sc->dev, "Adapter does not support SLI4\n");
291 goto error;
292 }
293
294 if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
295 sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
296
297 if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
298 sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
299
300 if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
301 sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
302
303 /* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
304 if (IS_BE(sc) || IS_SH(sc)) {
305 /* set up CSR region */
306 rr = PCIR_BAR(OCE_PCI_CSR_BAR);
307 sc->csr_res = bus_alloc_resource_any(sc->dev,
308 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
309 if (!sc->csr_res)
310 goto error;
311 sc->csr_btag = rman_get_bustag(sc->csr_res);
312 sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
313 sc->csr_vhandle = rman_get_virtual(sc->csr_res);
314
315 /* set up DB doorbell region */
316 rr = PCIR_BAR(OCE_PCI_DB_BAR);
317 sc->db_res = bus_alloc_resource_any(sc->dev,
318 SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
319 if (!sc->db_res)
320 goto error;
321 sc->db_btag = rman_get_bustag(sc->db_res);
322 sc->db_bhandle = rman_get_bushandle(sc->db_res);
323 sc->db_vhandle = rman_get_virtual(sc->db_res);
324 }
325
326 return 0;
327
328 error:
329 oce_hw_pci_free(sc);
330 return ENXIO;
331 }
332
333
334 /**
335 * @brief Function for device shutdown
336 * @param sc software handle to the device
337 * @returns 0 on success, error otherwise
338 */
339 void
oce_hw_shutdown(POCE_SOFTC sc)340 oce_hw_shutdown(POCE_SOFTC sc)
341 {
342
343 oce_stats_free(sc);
344 /* disable hardware interrupts */
345 oce_hw_intr_disable(sc);
346 #if defined(INET6) || defined(INET)
347 #if 0 /* XXX swildner: LRO */
348 /* Free LRO resources */
349 oce_free_lro(sc);
350 #endif
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 */
375 int
oce_create_nw_interface(POCE_SOFTC sc)376 oce_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 /* enable capabilities controlled via driver startup parameters */
395 if (is_rss_enabled(sc))
396 capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
397 else {
398 capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
399 capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
400 }
401
402 rc = oce_if_create(sc,
403 capab_flags,
404 capab_en_flags,
405 0, &sc->macaddr.mac_addr[0], &sc->if_id);
406 if (rc)
407 return rc;
408
409 atomic_inc_32(&sc->nifs);
410
411 sc->if_cap_flags = capab_en_flags;
412
413 /* set default flow control */
414 rc = oce_set_flow_control(sc, sc->flow_control);
415 if (rc)
416 goto error;
417
418 rc = oce_rxf_set_promiscuous(sc, sc->promisc);
419 if (rc)
420 goto error;
421
422 return rc;
423
424 error:
425 oce_delete_nw_interface(sc);
426 return rc;
427
428 }
429
430 /**
431 * @brief Function to delete a nw interface.
432 * @param sc software handle to the device
433 */
434 void
oce_delete_nw_interface(POCE_SOFTC sc)435 oce_delete_nw_interface(POCE_SOFTC sc)
436 {
437 /* currently only single interface is implmeneted */
438 if (sc->nifs > 0) {
439 oce_if_del(sc, sc->if_id);
440 atomic_dec_32(&sc->nifs);
441 }
442 }
443
444 /**
445 * @brief Soft reset.
446 * @param sc software handle to the device
447 * @returns 0 on success, error otherwise
448 */
449 int
oce_pci_soft_reset(POCE_SOFTC sc)450 oce_pci_soft_reset(POCE_SOFTC sc)
451 {
452 int rc;
453 mpu_ep_control_t ctrl;
454
455 ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
456 ctrl.bits.cpu_reset = 1;
457 OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
458 DELAY(50);
459 rc=oce_POST(sc);
460
461 return rc;
462 }
463
464 /**
465 * @brief Function for hardware start
466 * @param sc software handle to the device
467 * @returns 0 on success, error otherwise
468 */
469 int
oce_hw_start(POCE_SOFTC sc)470 oce_hw_start(POCE_SOFTC sc)
471 {
472 struct link_status link = { 0 };
473 int rc = 0;
474
475 rc = oce_get_link_status(sc, &link);
476 if (rc)
477 return 1;
478
479 if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
480 sc->link_status = NTWK_LOGICAL_LINK_UP;
481 if_link_state_change(sc->ifp);
482 } else {
483 sc->link_status = NTWK_LOGICAL_LINK_DOWN;
484 if_link_state_change(sc->ifp);
485 }
486
487 if (link.mac_speed > 0 && link.mac_speed < 5)
488 sc->link_speed = link.mac_speed;
489 else
490 sc->link_speed = 0;
491
492 sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
493
494 rc = oce_start_mq(sc->mq);
495
496 /* we need to get MCC aync events. So enable intrs and arm
497 first EQ, Other EQs will be armed after interface is UP
498 */
499 oce_hw_intr_enable(sc);
500 oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
501
502 /* Send first mcc cmd and after that we get gracious
503 MCC notifications from FW
504 */
505 oce_first_mcc_cmd(sc);
506
507 return rc;
508 }
509
510
511 /**
512 * @brief Function for hardware enable interupts.
513 * @param sc software handle to the device
514 */
515 void
oce_hw_intr_enable(POCE_SOFTC sc)516 oce_hw_intr_enable(POCE_SOFTC sc)
517 {
518 uint32_t reg;
519
520 reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
521 reg |= HOSTINTR_MASK;
522 OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
523
524 }
525
526
527 /**
528 * @brief Function for hardware disable interupts
529 * @param sc software handle to the device
530 */
531 void
oce_hw_intr_disable(POCE_SOFTC sc)532 oce_hw_intr_disable(POCE_SOFTC sc)
533 {
534 uint32_t reg;
535
536 reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
537 reg &= ~HOSTINTR_MASK;
538 OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
539 }
540
541
542
543 /**
544 * @brief Function for hardware update multicast filter
545 * @param sc software handle to the device
546 */
547 int
oce_hw_update_multicast(POCE_SOFTC sc)548 oce_hw_update_multicast(POCE_SOFTC sc)
549 {
550 struct ifnet *ifp = sc->ifp;
551 struct ifmultiaddr *ifma;
552 struct mbx_set_common_iface_multicast *req = NULL;
553 OCE_DMA_MEM dma;
554 int rc = 0;
555
556 /* Allocate DMA mem*/
557 if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
558 &dma, 0))
559 return ENOMEM;
560
561 req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
562 bzero(req, sizeof(struct mbx_set_common_iface_multicast));
563
564 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
565 if (ifma->ifma_addr->sa_family != AF_LINK)
566 continue;
567
568 if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
569 /*More multicast addresses than our hardware table
570 So Enable multicast promiscus in our hardware to
571 accept all multicat packets
572 */
573 req->params.req.promiscuous = 1;
574 break;
575 }
576 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
577 &req->params.req.mac[req->params.req.num_mac],
578 ETH_ADDR_LEN);
579 req->params.req.num_mac = req->params.req.num_mac + 1;
580 }
581 req->params.req.if_id = sc->if_id;
582 rc = oce_update_multicast(sc, &dma);
583 oce_dma_free(sc, &dma);
584 return rc;
585 }
586