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