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