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