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