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