oce_hw.c revision 331722
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: stable/11/sys/dev/oce/oce_hw.c 331722 2018-03-29 02:50:57Z eadler $ */
40
41
42#include "oce_if.h"
43
44static int oce_POST(POCE_SOFTC sc);
45
46/**
47 * @brief		Function to post status
48 * @param sc		software handle to the device
49 */
50static int
51oce_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 */
91int
92oce_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
142error:
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 */
154void
155oce_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 */
202static
203void 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 */
246int
247oce_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
329error:
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 */
340void
341oce_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 */
374int
375oce_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	/* enable capabilities controlled via driver startup parameters */
397	if (is_rss_enabled(sc))
398		capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
399	else {
400		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
401		capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
402	}
403
404	rc = oce_if_create(sc,
405			   capab_flags,
406			   capab_en_flags,
407			   0, &sc->macaddr.mac_addr[0], &sc->if_id);
408	if (rc)
409		return rc;
410
411	atomic_inc_32(&sc->nifs);
412
413	sc->if_cap_flags = capab_en_flags;
414
415	/* set default flow control */
416	rc = oce_set_flow_control(sc, sc->flow_control);
417	if (rc)
418		goto error;
419
420	rc = oce_rxf_set_promiscuous(sc, sc->promisc);
421	if (rc)
422		goto error;
423
424	return rc;
425
426error:
427	oce_delete_nw_interface(sc);
428	return rc;
429
430}
431
432/**
433 * @brief		Function to delete a nw interface.
434 * @param sc		software handle to the device
435 */
436void
437oce_delete_nw_interface(POCE_SOFTC sc)
438{
439	/* currently only single interface is implmeneted */
440	if (sc->nifs > 0) {
441		oce_if_del(sc, sc->if_id);
442		atomic_dec_32(&sc->nifs);
443	}
444}
445
446/**
447 * @brief Soft reset.
448 * @param sc		software handle to the device
449 * @returns		0 on success, error otherwise
450 */
451int
452oce_pci_soft_reset(POCE_SOFTC sc)
453{
454	int rc;
455	mpu_ep_control_t ctrl;
456
457	ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
458	ctrl.bits.cpu_reset = 1;
459	OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
460	DELAY(50);
461	rc=oce_POST(sc);
462
463	return rc;
464}
465
466/**
467 * @brief		Function for hardware start
468 * @param sc		software handle to the device
469 * @returns		0 on success, error otherwise
470 */
471int
472oce_hw_start(POCE_SOFTC sc)
473{
474	struct link_status link = { 0 };
475	int rc = 0;
476
477	rc = oce_get_link_status(sc, &link);
478	if (rc)
479		return 1;
480
481	if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
482		sc->link_status = NTWK_LOGICAL_LINK_UP;
483		if_link_state_change(sc->ifp, LINK_STATE_UP);
484	} else {
485		sc->link_status = NTWK_LOGICAL_LINK_DOWN;
486		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
487	}
488
489	sc->link_speed = link.phys_port_speed;
490	sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
491
492	rc = oce_start_mq(sc->mq);
493
494	/* we need to get MCC aync events. So enable intrs and arm
495	   first EQ, Other EQs will be armed after interface is UP
496	*/
497	oce_hw_intr_enable(sc);
498	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
499
500	/* Send first mcc cmd and after that we get gracious
501	   MCC notifications from FW
502	*/
503	oce_first_mcc_cmd(sc);
504
505	return rc;
506}
507
508
509/**
510 * @brief 		Function for hardware enable interupts.
511 * @param sc		software handle to the device
512 */
513void
514oce_hw_intr_enable(POCE_SOFTC sc)
515{
516	uint32_t reg;
517
518	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
519	reg |= HOSTINTR_MASK;
520	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
521
522}
523
524
525/**
526 * @brief 		Function for hardware disable interupts
527 * @param sc		software handle to the device
528 */
529void
530oce_hw_intr_disable(POCE_SOFTC sc)
531{
532	uint32_t reg;
533
534	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
535	reg &= ~HOSTINTR_MASK;
536	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
537}
538
539
540
541/**
542 * @brief		Function for hardware update multicast filter
543 * @param sc		software handle to the device
544 */
545int
546oce_hw_update_multicast(POCE_SOFTC sc)
547{
548	struct ifnet    *ifp = sc->ifp;
549	struct ifmultiaddr *ifma;
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 __FreeBSD_version > 800000
563	if_maddr_rlock(ifp);
564#endif
565	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
566		if (ifma->ifma_addr->sa_family != AF_LINK)
567			continue;
568
569		if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
570			/*More multicast addresses than our hardware table
571			  So Enable multicast promiscus in our hardware to
572			  accept all multicat packets
573			*/
574			req->params.req.promiscuous = 1;
575			break;
576		}
577		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
578			&req->params.req.mac[req->params.req.num_mac],
579			ETH_ADDR_LEN);
580		req->params.req.num_mac = req->params.req.num_mac + 1;
581	}
582#if __FreeBSD_version > 800000
583	if_maddr_runlock(ifp);
584#endif
585	req->params.req.if_id = sc->if_id;
586	rc = oce_update_multicast(sc, &dma);
587	oce_dma_free(sc, &dma);
588	return rc;
589}
590
591