xref: /freebsd/sys/dev/oce/oce_hw.c (revision 783d3ff6d7fae619db8a7990b8a6387de0c677b5)
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 
42 #include "oce_if.h"
43 
44 static int oce_POST(POCE_SOFTC sc);
45 
46 /**
47  * @brief		Function to post status
48  * @param sc		software handle to the device
49  */
50 static int
51 oce_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  */
91 int
92 oce_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 	rc = oce_get_fw_version(sc);
117 	if (rc)
118 		goto error;
119 
120 	rc = oce_get_fw_config(sc);
121 	if (rc)
122 		goto error;
123 
124 	sc->macaddr.size_of_struct = 6;
125 	rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
126 					&sc->macaddr);
127 	if (rc)
128 		goto error;
129 
130 	if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
131 		rc = oce_mbox_check_native_mode(sc);
132 		if (rc)
133 			goto error;
134 	} else
135 		sc->be3_native = 0;
136 
137 	return rc;
138 
139 error:
140 	oce_dma_free(sc, &sc->bsmbx);
141 	device_printf(sc->dev, "Hardware initialisation failed\n");
142 	return rc;
143 }
144 
145 /**
146  * @brief		Releases the obtained pci resources
147  * @param sc		software handle to the device
148  */
149 void
150 oce_hw_pci_free(POCE_SOFTC sc)
151 {
152 	int pci_cfg_barnum = 0;
153 
154 	if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
155 		pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
156 	else
157 		pci_cfg_barnum = OCE_DEV_CFG_BAR;
158 
159 	if (sc->devcfg_res != NULL) {
160 		bus_release_resource(sc->dev,
161 				     SYS_RES_MEMORY,
162 				     PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
163 		sc->devcfg_res = (struct resource *)NULL;
164 		sc->devcfg_btag = (bus_space_tag_t) 0;
165 		sc->devcfg_bhandle = (bus_space_handle_t)0;
166 		sc->devcfg_vhandle = (void *)NULL;
167 	}
168 
169 	if (sc->csr_res != NULL) {
170 		bus_release_resource(sc->dev,
171 				     SYS_RES_MEMORY,
172 				     PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
173 		sc->csr_res = (struct resource *)NULL;
174 		sc->csr_btag = (bus_space_tag_t)0;
175 		sc->csr_bhandle = (bus_space_handle_t)0;
176 		sc->csr_vhandle = (void *)NULL;
177 	}
178 
179 	if (sc->db_res != NULL) {
180 		bus_release_resource(sc->dev,
181 				     SYS_RES_MEMORY,
182 				     PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
183 		sc->db_res = (struct resource *)NULL;
184 		sc->db_btag = (bus_space_tag_t)0;
185 		sc->db_bhandle = (bus_space_handle_t)0;
186 		sc->db_vhandle = (void *)NULL;
187 	}
188 }
189 
190 /**
191  * @brief 		Function to get the PCI capabilities
192  * @param sc		software handle to the device
193  */
194 static
195 void oce_get_pci_capabilities(POCE_SOFTC sc)
196 {
197 	uint32_t val;
198 
199 	if (pci_find_cap(sc->dev, PCIY_PCIX, &val) == 0) {
200 		if (val != 0)
201 			sc->flags |= OCE_FLAGS_PCIX;
202 	}
203 
204 	if (pci_find_cap(sc->dev, PCIY_EXPRESS, &val) == 0) {
205 		if (val != 0) {
206 			uint16_t link_status =
207 			    pci_read_config(sc->dev, val + 0x12, 2);
208 
209 			sc->flags |= OCE_FLAGS_PCIE;
210 			sc->pcie_link_speed = link_status & 0xf;
211 			sc->pcie_link_width = (link_status >> 4) & 0x3f;
212 		}
213 	}
214 
215 	if (pci_find_cap(sc->dev, PCIY_MSI, &val) == 0) {
216 		if (val != 0)
217 			sc->flags |= OCE_FLAGS_MSI_CAPABLE;
218 	}
219 
220 	if (pci_find_cap(sc->dev, PCIY_MSIX, &val) == 0) {
221 		if (val != 0) {
222 			val = pci_msix_count(sc->dev);
223 			sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
224 		}
225 	}
226 }
227 
228 /**
229  * @brief	Allocate PCI resources.
230  *
231  * @param sc		software handle to the device
232  * @returns		0 if successful, or error
233  */
234 int
235 oce_hw_pci_alloc(POCE_SOFTC sc)
236 {
237 	int rr, pci_cfg_barnum = 0;
238 	pci_sli_intf_t intf;
239 
240 	pci_enable_busmaster(sc->dev);
241 
242 	oce_get_pci_capabilities(sc);
243 
244 	sc->fn = pci_get_function(sc->dev);
245 
246 	/* setup the device config region */
247 	if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
248 		pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
249 	else
250 		pci_cfg_barnum = OCE_DEV_CFG_BAR;
251 
252 	rr = PCIR_BAR(pci_cfg_barnum);
253 
254 	if (IS_BE(sc) || IS_SH(sc))
255 		sc->devcfg_res = bus_alloc_resource_any(sc->dev,
256 				SYS_RES_MEMORY, &rr,
257 				RF_ACTIVE|RF_SHAREABLE);
258 	else
259 		sc->devcfg_res = bus_alloc_resource_anywhere(sc->dev,
260 				SYS_RES_MEMORY, &rr, 32768,
261 				RF_ACTIVE|RF_SHAREABLE);
262 
263 	if (!sc->devcfg_res)
264 		goto error;
265 
266 	sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
267 	sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
268 	sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
269 
270 	/* Read the SLI_INTF register and determine whether we
271 	 * can use this port and its features
272 	 */
273 	intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
274 
275 	if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
276 		goto error;
277 
278 	if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
279 		device_printf(sc->dev, "Adapter doesnt support SLI4\n");
280 		goto error;
281 	}
282 
283 	if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
284 		sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
285 
286 	if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
287 		sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
288 
289 	if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
290 		sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
291 
292 	/* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
293 	if (IS_BE(sc) || IS_SH(sc)) {
294 		/* set up CSR region */
295 		rr = PCIR_BAR(OCE_PCI_CSR_BAR);
296 		sc->csr_res = bus_alloc_resource_any(sc->dev,
297 				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
298 		if (!sc->csr_res)
299 			goto error;
300 		sc->csr_btag = rman_get_bustag(sc->csr_res);
301 		sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
302 		sc->csr_vhandle = rman_get_virtual(sc->csr_res);
303 
304 		/* set up DB doorbell region */
305 		rr = PCIR_BAR(OCE_PCI_DB_BAR);
306 		sc->db_res = bus_alloc_resource_any(sc->dev,
307 				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
308 		if (!sc->db_res)
309 			goto error;
310 		sc->db_btag = rman_get_bustag(sc->db_res);
311 		sc->db_bhandle = rman_get_bushandle(sc->db_res);
312 		sc->db_vhandle = rman_get_virtual(sc->db_res);
313 	}
314 
315 	return 0;
316 
317 error:
318 	oce_hw_pci_free(sc);
319 	return ENXIO;
320 }
321 
322 /**
323  * @brief		Function for device shutdown
324  * @param sc		software handle to the device
325  * @returns		0 on success, error otherwise
326  */
327 void
328 oce_hw_shutdown(POCE_SOFTC sc)
329 {
330 
331 	oce_stats_free(sc);
332 	/* disable hardware interrupts */
333 	oce_hw_intr_disable(sc);
334 #if defined(INET6) || defined(INET)
335 	/* Free LRO resources */
336 	oce_free_lro(sc);
337 #endif
338 	/* Release queue*/
339 	oce_queue_release_all(sc);
340 	/*Delete Network Interface*/
341 	oce_delete_nw_interface(sc);
342 	/* After fw clean we dont send any cmds to fw.*/
343 	oce_fw_clean(sc);
344 	/* release intr resources */
345 	oce_intr_free(sc);
346 	/* release PCI resources */
347 	oce_hw_pci_free(sc);
348 	/* free mbox specific resources */
349 	LOCK_DESTROY(&sc->bmbx_lock);
350 	LOCK_DESTROY(&sc->dev_lock);
351 
352 	oce_dma_free(sc, &sc->bsmbx);
353 }
354 
355 /**
356  * @brief		Function for creating nw interface.
357  * @param sc		software handle to the device
358  * @returns		0 on success, error otherwise
359  */
360 int
361 oce_create_nw_interface(POCE_SOFTC sc)
362 {
363 	int rc;
364 	uint32_t capab_flags;
365 	uint32_t capab_en_flags;
366 
367 	/* interface capabilities to give device when creating interface */
368 	capab_flags = OCE_CAPAB_FLAGS;
369 
370 	/* capabilities to enable by default (others set dynamically) */
371 	capab_en_flags = OCE_CAPAB_ENABLE;
372 
373 	if (IS_XE201(sc)) {
374 		/* LANCER A0 workaround */
375 		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
376 		capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
377 	}
378 
379 	if (IS_SH(sc) || IS_XE201(sc))
380 		capab_flags |= MBX_RX_IFACE_FLAGS_MULTICAST;
381 
382         if (sc->enable_hwlro) {
383                 capab_flags |= MBX_RX_IFACE_FLAGS_LRO;
384                 capab_en_flags |= MBX_RX_IFACE_FLAGS_LRO;
385         }
386 
387 	/* enable capabilities controlled via driver startup parameters */
388 	if (is_rss_enabled(sc))
389 		capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
390 	else {
391 		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
392 		capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
393 	}
394 
395 	rc = oce_if_create(sc,
396 			   capab_flags,
397 			   capab_en_flags,
398 			   0, &sc->macaddr.mac_addr[0], &sc->if_id);
399 	if (rc)
400 		return rc;
401 
402 	atomic_inc_32(&sc->nifs);
403 
404 	sc->if_cap_flags = capab_en_flags;
405 
406 	/* set default flow control */
407 	rc = oce_set_flow_control(sc, sc->flow_control);
408 	if (rc)
409 		goto error;
410 
411 	rc = oce_rxf_set_promiscuous(sc, sc->promisc);
412 	if (rc)
413 		goto error;
414 
415 	return rc;
416 
417 error:
418 	oce_delete_nw_interface(sc);
419 	return rc;
420 
421 }
422 
423 /**
424  * @brief		Function to delete a nw interface.
425  * @param sc		software handle to the device
426  */
427 void
428 oce_delete_nw_interface(POCE_SOFTC sc)
429 {
430 	/* currently only single interface is implmeneted */
431 	if (sc->nifs > 0) {
432 		oce_if_del(sc, sc->if_id);
433 		atomic_dec_32(&sc->nifs);
434 	}
435 }
436 
437 /**
438  * @brief Soft reset.
439  * @param sc		software handle to the device
440  * @returns		0 on success, error otherwise
441  */
442 int
443 oce_pci_soft_reset(POCE_SOFTC sc)
444 {
445 	int rc;
446 	mpu_ep_control_t ctrl;
447 
448 	ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
449 	ctrl.bits.cpu_reset = 1;
450 	OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
451 	DELAY(50);
452 	rc=oce_POST(sc);
453 
454 	return rc;
455 }
456 
457 /**
458  * @brief		Function for hardware start
459  * @param sc		software handle to the device
460  * @returns		0 on success, error otherwise
461  */
462 int
463 oce_hw_start(POCE_SOFTC sc)
464 {
465 	struct link_status link = { 0 };
466 	int rc = 0;
467 
468 	rc = oce_get_link_status(sc, &link);
469 	if (rc)
470 		return 1;
471 
472 	if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
473 		sc->link_status = NTWK_LOGICAL_LINK_UP;
474 		if_link_state_change(sc->ifp, LINK_STATE_UP);
475 	} else {
476 		sc->link_status = NTWK_LOGICAL_LINK_DOWN;
477 		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
478 	}
479 
480 	sc->link_speed = link.phys_port_speed;
481 	sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
482 
483 	rc = oce_start_mq(sc->mq);
484 
485 	/* we need to get MCC aync events. So enable intrs and arm
486 	   first EQ, Other EQs will be armed after interface is UP
487 	*/
488 	oce_hw_intr_enable(sc);
489 	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
490 
491 	/* Send first mcc cmd and after that we get gracious
492 	   MCC notifications from FW
493 	*/
494 	oce_first_mcc_cmd(sc);
495 
496 	return rc;
497 }
498 
499 /**
500  * @brief 		Function for hardware enable interupts.
501  * @param sc		software handle to the device
502  */
503 void
504 oce_hw_intr_enable(POCE_SOFTC sc)
505 {
506 	uint32_t reg;
507 
508 	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
509 	reg |= HOSTINTR_MASK;
510 	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
511 
512 }
513 
514 /**
515  * @brief 		Function for hardware disable interupts
516  * @param sc		software handle to the device
517  */
518 void
519 oce_hw_intr_disable(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 static u_int
529 oce_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
530 {
531 	struct mbx_set_common_iface_multicast *req = arg;
532 
533 	if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE)
534 		return (0);
535 
536 	bcopy(LLADDR(sdl), &req->params.req.mac[req->params.req.num_mac++],
537 	    ETHER_ADDR_LEN);
538 
539 	return (1);
540 }
541 
542 /**
543  * @brief		Function for hardware update multicast filter
544  * @param sc		software handle to the device
545  */
546 int
547 oce_hw_update_multicast(POCE_SOFTC sc)
548 {
549 	if_t ifp = sc->ifp;
550 	struct mbx_set_common_iface_multicast *req = NULL;
551 	OCE_DMA_MEM dma;
552 	int rc = 0;
553 
554 	/* Allocate DMA mem*/
555 	if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
556 							&dma, 0))
557 		return ENOMEM;
558 
559 	req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
560 	bzero(req, sizeof(struct mbx_set_common_iface_multicast));
561 
562 	if_foreach_llmaddr(ifp, oce_copy_maddr, req);
563 	if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
564 		/*More multicast addresses than our hardware table
565 		  So Enable multicast promiscus in our hardware to
566 		  accept all multicat packets
567 		*/
568 		req->params.req.promiscuous = 1;
569 	}
570 
571 	req->params.req.if_id = sc->if_id;
572 	rc = oce_update_multicast(sc, &dma);
573 	oce_dma_free(sc, &dma);
574 	return rc;
575 }
576