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