xref: /freebsd/sys/dev/oce/oce_hw.c (revision f078c492a9b57877c723586db26d789cda1b98ea)
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 }
577