xref: /freebsd/sys/dev/oce/oce_hw.c (revision e17f5b1d)
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 
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
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
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
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 = (struct resource *)NULL;
171 		sc->devcfg_btag = (bus_space_tag_t) 0;
172 		sc->devcfg_bhandle = (bus_space_handle_t)0;
173 		sc->devcfg_vhandle = (void *)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 = (struct resource *)NULL;
181 		sc->csr_btag = (bus_space_tag_t)0;
182 		sc->csr_bhandle = (bus_space_handle_t)0;
183 		sc->csr_vhandle = (void *)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 = (struct resource *)NULL;
191 		sc->db_btag = (bus_space_tag_t)0;
192 		sc->db_bhandle = (bus_space_handle_t)0;
193 		sc->db_vhandle = (void *)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
205 void oce_get_pci_capabilities(POCE_SOFTC sc)
206 {
207 	uint32_t val;
208 
209 	if (pci_find_cap(sc->dev, PCIY_PCIX, &val) == 0) {
210 		if (val != 0)
211 			sc->flags |= OCE_FLAGS_PCIX;
212 	}
213 
214 	if (pci_find_cap(sc->dev, PCIY_EXPRESS, &val) == 0) {
215 		if (val != 0) {
216 			uint16_t link_status =
217 			    pci_read_config(sc->dev, val + 0x12, 2);
218 
219 			sc->flags |= OCE_FLAGS_PCIE;
220 			sc->pcie_link_speed = link_status & 0xf;
221 			sc->pcie_link_width = (link_status >> 4) & 0x3f;
222 		}
223 	}
224 
225 	if (pci_find_cap(sc->dev, PCIY_MSI, &val) == 0) {
226 		if (val != 0)
227 			sc->flags |= OCE_FLAGS_MSI_CAPABLE;
228 	}
229 
230 	if (pci_find_cap(sc->dev, PCIY_MSIX, &val) == 0) {
231 		if (val != 0) {
232 			val = pci_msix_count(sc->dev);
233 			sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
234 		}
235 	}
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
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_anywhere(sc->dev,
270 				SYS_RES_MEMORY, &rr, 32768,
271 				RF_ACTIVE|RF_SHAREABLE);
272 
273 	if (!sc->devcfg_res)
274 		goto error;
275 
276 	sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
277 	sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
278 	sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
279 
280 	/* Read the SLI_INTF register and determine whether we
281 	 * can use this port and its features
282 	 */
283 	intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
284 
285 	if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
286 		goto error;
287 
288 	if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
289 		device_printf(sc->dev, "Adapter doesnt support SLI4\n");
290 		goto error;
291 	}
292 
293 	if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
294 		sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
295 
296 	if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
297 		sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
298 
299 	if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
300 		sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
301 
302 	/* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
303 	if (IS_BE(sc) || IS_SH(sc)) {
304 		/* set up CSR region */
305 		rr = PCIR_BAR(OCE_PCI_CSR_BAR);
306 		sc->csr_res = bus_alloc_resource_any(sc->dev,
307 				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
308 		if (!sc->csr_res)
309 			goto error;
310 		sc->csr_btag = rman_get_bustag(sc->csr_res);
311 		sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
312 		sc->csr_vhandle = rman_get_virtual(sc->csr_res);
313 
314 		/* set up DB doorbell region */
315 		rr = PCIR_BAR(OCE_PCI_DB_BAR);
316 		sc->db_res = bus_alloc_resource_any(sc->dev,
317 				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
318 		if (!sc->db_res)
319 			goto error;
320 		sc->db_btag = rman_get_bustag(sc->db_res);
321 		sc->db_bhandle = rman_get_bushandle(sc->db_res);
322 		sc->db_vhandle = rman_get_virtual(sc->db_res);
323 	}
324 
325 	return 0;
326 
327 error:
328 	oce_hw_pci_free(sc);
329 	return ENXIO;
330 }
331 
332 
333 /**
334  * @brief		Function for device shutdown
335  * @param sc		software handle to the device
336  * @returns		0 on success, error otherwise
337  */
338 void
339 oce_hw_shutdown(POCE_SOFTC sc)
340 {
341 
342 	oce_stats_free(sc);
343 	/* disable hardware interrupts */
344 	oce_hw_intr_disable(sc);
345 #if defined(INET6) || defined(INET)
346 	/* Free LRO resources */
347 	oce_free_lro(sc);
348 #endif
349 	/* Release queue*/
350 	oce_queue_release_all(sc);
351 	/*Delete Network Interface*/
352 	oce_delete_nw_interface(sc);
353 	/* After fw clean we dont send any cmds to fw.*/
354 	oce_fw_clean(sc);
355 	/* release intr resources */
356 	oce_intr_free(sc);
357 	/* release PCI resources */
358 	oce_hw_pci_free(sc);
359 	/* free mbox specific resources */
360 	LOCK_DESTROY(&sc->bmbx_lock);
361 	LOCK_DESTROY(&sc->dev_lock);
362 
363 	oce_dma_free(sc, &sc->bsmbx);
364 }
365 
366 
367 /**
368  * @brief		Function for creating nw interface.
369  * @param sc		software handle to the device
370  * @returns		0 on success, error otherwise
371  */
372 int
373 oce_create_nw_interface(POCE_SOFTC sc)
374 {
375 	int rc;
376 	uint32_t capab_flags;
377 	uint32_t capab_en_flags;
378 
379 	/* interface capabilities to give device when creating interface */
380 	capab_flags = OCE_CAPAB_FLAGS;
381 
382 	/* capabilities to enable by default (others set dynamically) */
383 	capab_en_flags = OCE_CAPAB_ENABLE;
384 
385 	if (IS_XE201(sc)) {
386 		/* LANCER A0 workaround */
387 		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
388 		capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
389 	}
390 
391 	if (IS_SH(sc) || IS_XE201(sc))
392 		capab_flags |= MBX_RX_IFACE_FLAGS_MULTICAST;
393 
394         if (sc->enable_hwlro) {
395                 capab_flags |= MBX_RX_IFACE_FLAGS_LRO;
396                 capab_en_flags |= MBX_RX_IFACE_FLAGS_LRO;
397         }
398 
399 	/* enable capabilities controlled via driver startup parameters */
400 	if (is_rss_enabled(sc))
401 		capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
402 	else {
403 		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
404 		capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
405 	}
406 
407 	rc = oce_if_create(sc,
408 			   capab_flags,
409 			   capab_en_flags,
410 			   0, &sc->macaddr.mac_addr[0], &sc->if_id);
411 	if (rc)
412 		return rc;
413 
414 	atomic_inc_32(&sc->nifs);
415 
416 	sc->if_cap_flags = capab_en_flags;
417 
418 	/* set default flow control */
419 	rc = oce_set_flow_control(sc, sc->flow_control);
420 	if (rc)
421 		goto error;
422 
423 	rc = oce_rxf_set_promiscuous(sc, sc->promisc);
424 	if (rc)
425 		goto error;
426 
427 	return rc;
428 
429 error:
430 	oce_delete_nw_interface(sc);
431 	return rc;
432 
433 }
434 
435 /**
436  * @brief		Function to delete a nw interface.
437  * @param sc		software handle to the device
438  */
439 void
440 oce_delete_nw_interface(POCE_SOFTC sc)
441 {
442 	/* currently only single interface is implmeneted */
443 	if (sc->nifs > 0) {
444 		oce_if_del(sc, sc->if_id);
445 		atomic_dec_32(&sc->nifs);
446 	}
447 }
448 
449 /**
450  * @brief Soft reset.
451  * @param sc		software handle to the device
452  * @returns		0 on success, error otherwise
453  */
454 int
455 oce_pci_soft_reset(POCE_SOFTC sc)
456 {
457 	int rc;
458 	mpu_ep_control_t ctrl;
459 
460 	ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
461 	ctrl.bits.cpu_reset = 1;
462 	OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
463 	DELAY(50);
464 	rc=oce_POST(sc);
465 
466 	return rc;
467 }
468 
469 /**
470  * @brief		Function for hardware start
471  * @param sc		software handle to the device
472  * @returns		0 on success, error otherwise
473  */
474 int
475 oce_hw_start(POCE_SOFTC sc)
476 {
477 	struct link_status link = { 0 };
478 	int rc = 0;
479 
480 	rc = oce_get_link_status(sc, &link);
481 	if (rc)
482 		return 1;
483 
484 	if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
485 		sc->link_status = NTWK_LOGICAL_LINK_UP;
486 		if_link_state_change(sc->ifp, LINK_STATE_UP);
487 	} else {
488 		sc->link_status = NTWK_LOGICAL_LINK_DOWN;
489 		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
490 	}
491 
492 	sc->link_speed = link.phys_port_speed;
493 	sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
494 
495 	rc = oce_start_mq(sc->mq);
496 
497 	/* we need to get MCC aync events. So enable intrs and arm
498 	   first EQ, Other EQs will be armed after interface is UP
499 	*/
500 	oce_hw_intr_enable(sc);
501 	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
502 
503 	/* Send first mcc cmd and after that we get gracious
504 	   MCC notifications from FW
505 	*/
506 	oce_first_mcc_cmd(sc);
507 
508 	return rc;
509 }
510 
511 
512 /**
513  * @brief 		Function for hardware enable interupts.
514  * @param sc		software handle to the device
515  */
516 void
517 oce_hw_intr_enable(POCE_SOFTC sc)
518 {
519 	uint32_t reg;
520 
521 	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
522 	reg |= HOSTINTR_MASK;
523 	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
524 
525 }
526 
527 
528 /**
529  * @brief 		Function for hardware disable interupts
530  * @param sc		software handle to the device
531  */
532 void
533 oce_hw_intr_disable(POCE_SOFTC sc)
534 {
535 	uint32_t reg;
536 
537 	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
538 	reg &= ~HOSTINTR_MASK;
539 	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
540 }
541 
542 
543 static u_int
544 oce_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
545 {
546 	struct mbx_set_common_iface_multicast *req = arg;
547 
548 	if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE)
549 		return (0);
550 
551 	bcopy(LLADDR(sdl), &req->params.req.mac[req->params.req.num_mac++],
552 	    ETHER_ADDR_LEN);
553 
554 	return (1);
555 }
556 
557 
558 /**
559  * @brief		Function for hardware update multicast filter
560  * @param sc		software handle to the device
561  */
562 int
563 oce_hw_update_multicast(POCE_SOFTC sc)
564 {
565 	struct ifnet    *ifp = sc->ifp;
566 	struct mbx_set_common_iface_multicast *req = NULL;
567 	OCE_DMA_MEM dma;
568 	int rc = 0;
569 
570 	/* Allocate DMA mem*/
571 	if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
572 							&dma, 0))
573 		return ENOMEM;
574 
575 	req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
576 	bzero(req, sizeof(struct mbx_set_common_iface_multicast));
577 
578 	if_foreach_llmaddr(ifp, oce_copy_maddr, req);
579 	if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
580 		/*More multicast addresses than our hardware table
581 		  So Enable multicast promiscus in our hardware to
582 		  accept all multicat packets
583 		*/
584 		req->params.req.promiscuous = 1;
585 	}
586 
587 	req->params.req.if_id = sc->if_id;
588 	rc = oce_update_multicast(sc, &dma);
589 	oce_dma_free(sc, &dma);
590 	return rc;
591 }
592 
593