xref: /freebsd/sys/dev/oce/oce_hw.c (revision 71625ec9)
12f345d8eSLuigi Rizzo /*-
27282444bSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
37282444bSPedro F. Giffuni  *
4291a1934SXin LI  * Copyright (C) 2013 Emulex
52f345d8eSLuigi Rizzo  * All rights reserved.
62f345d8eSLuigi Rizzo  *
72f345d8eSLuigi Rizzo  * Redistribution and use in source and binary forms, with or without
82f345d8eSLuigi Rizzo  * modification, are permitted provided that the following conditions are met:
92f345d8eSLuigi Rizzo  *
102f345d8eSLuigi Rizzo  * 1. Redistributions of source code must retain the above copyright notice,
112f345d8eSLuigi Rizzo  *    this list of conditions and the following disclaimer.
122f345d8eSLuigi Rizzo  *
132f345d8eSLuigi Rizzo  * 2. Redistributions in binary form must reproduce the above copyright
142f345d8eSLuigi Rizzo  *    notice, this list of conditions and the following disclaimer in the
152f345d8eSLuigi Rizzo  *    documentation and/or other materials provided with the distribution.
162f345d8eSLuigi Rizzo  *
172f345d8eSLuigi Rizzo  * 3. Neither the name of the Emulex Corporation nor the names of its
182f345d8eSLuigi Rizzo  *    contributors may be used to endorse or promote products derived from
192f345d8eSLuigi Rizzo  *    this software without specific prior written permission.
202f345d8eSLuigi Rizzo  *
212f345d8eSLuigi Rizzo  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
222f345d8eSLuigi Rizzo  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232f345d8eSLuigi Rizzo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242f345d8eSLuigi Rizzo  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
252f345d8eSLuigi Rizzo  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
262f345d8eSLuigi Rizzo  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
272f345d8eSLuigi Rizzo  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
282f345d8eSLuigi Rizzo  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
292f345d8eSLuigi Rizzo  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
302f345d8eSLuigi Rizzo  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
312f345d8eSLuigi Rizzo  * POSSIBILITY OF SUCH DAMAGE.
322f345d8eSLuigi Rizzo  *
332f345d8eSLuigi Rizzo  * Contact Information:
342f345d8eSLuigi Rizzo  * freebsd-drivers@emulex.com
352f345d8eSLuigi Rizzo  *
362f345d8eSLuigi Rizzo  * Emulex
372f345d8eSLuigi Rizzo  * 3333 Susan Street
382f345d8eSLuigi Rizzo  * Costa Mesa, CA 92626
392f345d8eSLuigi Rizzo  */
402f345d8eSLuigi Rizzo 
412f345d8eSLuigi Rizzo 
422f345d8eSLuigi Rizzo #include "oce_if.h"
432f345d8eSLuigi Rizzo 
442f345d8eSLuigi Rizzo static int oce_POST(POCE_SOFTC sc);
452f345d8eSLuigi Rizzo 
462f345d8eSLuigi Rizzo /**
472f345d8eSLuigi Rizzo  * @brief		Function to post status
482f345d8eSLuigi Rizzo  * @param sc		software handle to the device
492f345d8eSLuigi Rizzo  */
502f345d8eSLuigi Rizzo static int
oce_POST(POCE_SOFTC sc)512f345d8eSLuigi Rizzo oce_POST(POCE_SOFTC sc)
522f345d8eSLuigi Rizzo {
532f345d8eSLuigi Rizzo 	mpu_ep_semaphore_t post_status;
542f345d8eSLuigi Rizzo 	int tmo = 60000;
552f345d8eSLuigi Rizzo 
562f345d8eSLuigi Rizzo 	/* read semaphore CSR */
57291a1934SXin LI 	post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
582f345d8eSLuigi Rizzo 
592f345d8eSLuigi Rizzo 	/* if host is ready then wait for fw ready else send POST */
602f345d8eSLuigi Rizzo 	if (post_status.bits.stage <= POST_STAGE_AWAITING_HOST_RDY) {
612f345d8eSLuigi Rizzo 		post_status.bits.stage = POST_STAGE_CHIP_RESET;
62291a1934SXin LI 		OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc), post_status.dw0);
632f345d8eSLuigi Rizzo 	}
642f345d8eSLuigi Rizzo 
652f345d8eSLuigi Rizzo 	/* wait for FW ready */
662f345d8eSLuigi Rizzo 	for (;;) {
672f345d8eSLuigi Rizzo 		if (--tmo == 0)
682f345d8eSLuigi Rizzo 			break;
692f345d8eSLuigi Rizzo 
702f345d8eSLuigi Rizzo 		DELAY(1000);
712f345d8eSLuigi Rizzo 
72291a1934SXin LI 		post_status.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_SEMAPHORE(sc));
732f345d8eSLuigi Rizzo 		if (post_status.bits.error) {
742f345d8eSLuigi Rizzo 			device_printf(sc->dev,
752f345d8eSLuigi Rizzo 				  "POST failed: %x\n", post_status.dw0);
762f345d8eSLuigi Rizzo 			return ENXIO;
772f345d8eSLuigi Rizzo 		}
782f345d8eSLuigi Rizzo 		if (post_status.bits.stage == POST_STAGE_ARMFW_READY)
792f345d8eSLuigi Rizzo 			return 0;
802f345d8eSLuigi Rizzo 	}
812f345d8eSLuigi Rizzo 
822f345d8eSLuigi Rizzo 	device_printf(sc->dev, "POST timed out: %x\n", post_status.dw0);
832f345d8eSLuigi Rizzo 
842f345d8eSLuigi Rizzo 	return ENXIO;
852f345d8eSLuigi Rizzo }
862f345d8eSLuigi Rizzo 
872f345d8eSLuigi Rizzo /**
882f345d8eSLuigi Rizzo  * @brief		Function for hardware initialization
892f345d8eSLuigi Rizzo  * @param sc		software handle to the device
902f345d8eSLuigi Rizzo  */
912f345d8eSLuigi Rizzo int
oce_hw_init(POCE_SOFTC sc)922f345d8eSLuigi Rizzo oce_hw_init(POCE_SOFTC sc)
932f345d8eSLuigi Rizzo {
942f345d8eSLuigi Rizzo 	int rc = 0;
952f345d8eSLuigi Rizzo 
962f345d8eSLuigi Rizzo 	rc = oce_POST(sc);
972f345d8eSLuigi Rizzo 	if (rc)
982f345d8eSLuigi Rizzo 		return rc;
992f345d8eSLuigi Rizzo 
1002f345d8eSLuigi Rizzo 	/* create the bootstrap mailbox */
1012f345d8eSLuigi Rizzo 	rc = oce_dma_alloc(sc, sizeof(struct oce_bmbx), &sc->bsmbx, 0);
1022f345d8eSLuigi Rizzo 	if (rc) {
1032f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Mailbox alloc failed\n");
1042f345d8eSLuigi Rizzo 		return rc;
1052f345d8eSLuigi Rizzo 	}
1062f345d8eSLuigi Rizzo 
1072f345d8eSLuigi Rizzo 	rc = oce_reset_fun(sc);
1082f345d8eSLuigi Rizzo 	if (rc)
1092f345d8eSLuigi Rizzo 		goto error;
1102f345d8eSLuigi Rizzo 
1112f345d8eSLuigi Rizzo 
1122f345d8eSLuigi Rizzo 	rc = oce_mbox_init(sc);
1132f345d8eSLuigi Rizzo 	if (rc)
1142f345d8eSLuigi Rizzo 		goto error;
1152f345d8eSLuigi Rizzo 
1162f345d8eSLuigi Rizzo 	rc = oce_get_fw_version(sc);
1172f345d8eSLuigi Rizzo 	if (rc)
1182f345d8eSLuigi Rizzo 		goto error;
1192f345d8eSLuigi Rizzo 
1202f345d8eSLuigi Rizzo 	rc = oce_get_fw_config(sc);
1212f345d8eSLuigi Rizzo 	if (rc)
1222f345d8eSLuigi Rizzo 		goto error;
1232f345d8eSLuigi Rizzo 
1242f345d8eSLuigi Rizzo 	sc->macaddr.size_of_struct = 6;
1252f345d8eSLuigi Rizzo 	rc = oce_read_mac_addr(sc, 0, 1, MAC_ADDRESS_TYPE_NETWORK,
1262f345d8eSLuigi Rizzo 					&sc->macaddr);
1272f345d8eSLuigi Rizzo 	if (rc)
1282f345d8eSLuigi Rizzo 		goto error;
1292f345d8eSLuigi Rizzo 
130291a1934SXin LI 	if ((IS_BE(sc) && (sc->flags & OCE_FLAGS_BE3)) || IS_SH(sc)) {
1312f345d8eSLuigi Rizzo 		rc = oce_mbox_check_native_mode(sc);
1322f345d8eSLuigi Rizzo 		if (rc)
1332f345d8eSLuigi Rizzo 			goto error;
1342f345d8eSLuigi Rizzo 	} else
1352f345d8eSLuigi Rizzo 		sc->be3_native = 0;
1362f345d8eSLuigi Rizzo 
1372f345d8eSLuigi Rizzo 	return rc;
1382f345d8eSLuigi Rizzo 
1392f345d8eSLuigi Rizzo error:
1402f345d8eSLuigi Rizzo 	oce_dma_free(sc, &sc->bsmbx);
1412f345d8eSLuigi Rizzo 	device_printf(sc->dev, "Hardware initialisation failed\n");
1422f345d8eSLuigi Rizzo 	return rc;
1432f345d8eSLuigi Rizzo }
1442f345d8eSLuigi Rizzo 
1452f345d8eSLuigi Rizzo /**
1462f345d8eSLuigi Rizzo  * @brief		Releases the obtained pci resources
1472f345d8eSLuigi Rizzo  * @param sc		software handle to the device
1482f345d8eSLuigi Rizzo  */
1492f345d8eSLuigi Rizzo void
oce_hw_pci_free(POCE_SOFTC sc)1502f345d8eSLuigi Rizzo oce_hw_pci_free(POCE_SOFTC sc)
1512f345d8eSLuigi Rizzo {
1522f345d8eSLuigi Rizzo 	int pci_cfg_barnum = 0;
1532f345d8eSLuigi Rizzo 
1542f345d8eSLuigi Rizzo 	if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
1552f345d8eSLuigi Rizzo 		pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
1562f345d8eSLuigi Rizzo 	else
1572f345d8eSLuigi Rizzo 		pci_cfg_barnum = OCE_DEV_CFG_BAR;
1582f345d8eSLuigi Rizzo 
1592f345d8eSLuigi Rizzo 	if (sc->devcfg_res != NULL) {
1602f345d8eSLuigi Rizzo 		bus_release_resource(sc->dev,
1612f345d8eSLuigi Rizzo 				     SYS_RES_MEMORY,
1622f345d8eSLuigi Rizzo 				     PCIR_BAR(pci_cfg_barnum), sc->devcfg_res);
1632f345d8eSLuigi Rizzo 		sc->devcfg_res = (struct resource *)NULL;
1642f345d8eSLuigi Rizzo 		sc->devcfg_btag = (bus_space_tag_t) 0;
1652f345d8eSLuigi Rizzo 		sc->devcfg_bhandle = (bus_space_handle_t)0;
1662f345d8eSLuigi Rizzo 		sc->devcfg_vhandle = (void *)NULL;
1672f345d8eSLuigi Rizzo 	}
1682f345d8eSLuigi Rizzo 
1692f345d8eSLuigi Rizzo 	if (sc->csr_res != NULL) {
1702f345d8eSLuigi Rizzo 		bus_release_resource(sc->dev,
1712f345d8eSLuigi Rizzo 				     SYS_RES_MEMORY,
1722f345d8eSLuigi Rizzo 				     PCIR_BAR(OCE_PCI_CSR_BAR), sc->csr_res);
1732f345d8eSLuigi Rizzo 		sc->csr_res = (struct resource *)NULL;
1742f345d8eSLuigi Rizzo 		sc->csr_btag = (bus_space_tag_t)0;
1752f345d8eSLuigi Rizzo 		sc->csr_bhandle = (bus_space_handle_t)0;
1762f345d8eSLuigi Rizzo 		sc->csr_vhandle = (void *)NULL;
1772f345d8eSLuigi Rizzo 	}
1782f345d8eSLuigi Rizzo 
1792f345d8eSLuigi Rizzo 	if (sc->db_res != NULL) {
1802f345d8eSLuigi Rizzo 		bus_release_resource(sc->dev,
1812f345d8eSLuigi Rizzo 				     SYS_RES_MEMORY,
1822f345d8eSLuigi Rizzo 				     PCIR_BAR(OCE_PCI_DB_BAR), sc->db_res);
1832f345d8eSLuigi Rizzo 		sc->db_res = (struct resource *)NULL;
1842f345d8eSLuigi Rizzo 		sc->db_btag = (bus_space_tag_t)0;
1852f345d8eSLuigi Rizzo 		sc->db_bhandle = (bus_space_handle_t)0;
1862f345d8eSLuigi Rizzo 		sc->db_vhandle = (void *)NULL;
1872f345d8eSLuigi Rizzo 	}
1882f345d8eSLuigi Rizzo }
1892f345d8eSLuigi Rizzo 
1902f345d8eSLuigi Rizzo /**
1912f345d8eSLuigi Rizzo  * @brief 		Function to get the PCI capabilities
1922f345d8eSLuigi Rizzo  * @param sc		software handle to the device
1932f345d8eSLuigi Rizzo  */
1942f345d8eSLuigi Rizzo static
oce_get_pci_capabilities(POCE_SOFTC sc)1952f345d8eSLuigi Rizzo void oce_get_pci_capabilities(POCE_SOFTC sc)
1962f345d8eSLuigi Rizzo {
1972f345d8eSLuigi Rizzo 	uint32_t val;
1982f345d8eSLuigi Rizzo 
199a9208e98SWarner Losh 	if (pci_find_cap(sc->dev, PCIY_PCIX, &val) == 0) {
2002f345d8eSLuigi Rizzo 		if (val != 0)
2012f345d8eSLuigi Rizzo 			sc->flags |= OCE_FLAGS_PCIX;
2022f345d8eSLuigi Rizzo 	}
2032f345d8eSLuigi Rizzo 
204a9208e98SWarner Losh 	if (pci_find_cap(sc->dev, PCIY_EXPRESS, &val) == 0) {
2052f345d8eSLuigi Rizzo 		if (val != 0) {
2062f345d8eSLuigi Rizzo 			uint16_t link_status =
2072f345d8eSLuigi Rizzo 			    pci_read_config(sc->dev, val + 0x12, 2);
2082f345d8eSLuigi Rizzo 
2092f345d8eSLuigi Rizzo 			sc->flags |= OCE_FLAGS_PCIE;
2102f345d8eSLuigi Rizzo 			sc->pcie_link_speed = link_status & 0xf;
2112f345d8eSLuigi Rizzo 			sc->pcie_link_width = (link_status >> 4) & 0x3f;
2122f345d8eSLuigi Rizzo 		}
2132f345d8eSLuigi Rizzo 	}
2142f345d8eSLuigi Rizzo 
215a9208e98SWarner Losh 	if (pci_find_cap(sc->dev, PCIY_MSI, &val) == 0) {
2162f345d8eSLuigi Rizzo 		if (val != 0)
2172f345d8eSLuigi Rizzo 			sc->flags |= OCE_FLAGS_MSI_CAPABLE;
2182f345d8eSLuigi Rizzo 	}
2192f345d8eSLuigi Rizzo 
220a9208e98SWarner Losh 	if (pci_find_cap(sc->dev, PCIY_MSIX, &val) == 0) {
2212f345d8eSLuigi Rizzo 		if (val != 0) {
2222f345d8eSLuigi Rizzo 			val = pci_msix_count(sc->dev);
2232f345d8eSLuigi Rizzo 			sc->flags |= OCE_FLAGS_MSIX_CAPABLE;
2242f345d8eSLuigi Rizzo 		}
2252f345d8eSLuigi Rizzo 	}
2262f345d8eSLuigi Rizzo }
2272f345d8eSLuigi Rizzo 
2282f345d8eSLuigi Rizzo /**
2292f345d8eSLuigi Rizzo  * @brief	Allocate PCI resources.
2302f345d8eSLuigi Rizzo  *
2312f345d8eSLuigi Rizzo  * @param sc		software handle to the device
2322f345d8eSLuigi Rizzo  * @returns		0 if successful, or error
2332f345d8eSLuigi Rizzo  */
2342f345d8eSLuigi Rizzo int
oce_hw_pci_alloc(POCE_SOFTC sc)2352f345d8eSLuigi Rizzo oce_hw_pci_alloc(POCE_SOFTC sc)
2362f345d8eSLuigi Rizzo {
2372f345d8eSLuigi Rizzo 	int rr, pci_cfg_barnum = 0;
2382f345d8eSLuigi Rizzo 	pci_sli_intf_t intf;
2392f345d8eSLuigi Rizzo 
2402f345d8eSLuigi Rizzo 	pci_enable_busmaster(sc->dev);
2412f345d8eSLuigi Rizzo 
2422f345d8eSLuigi Rizzo 	oce_get_pci_capabilities(sc);
2432f345d8eSLuigi Rizzo 
2442f345d8eSLuigi Rizzo 	sc->fn = pci_get_function(sc->dev);
2452f345d8eSLuigi Rizzo 
2462f345d8eSLuigi Rizzo 	/* setup the device config region */
2472f345d8eSLuigi Rizzo 	if (IS_BE(sc) && (sc->flags & OCE_FLAGS_BE2))
2482f345d8eSLuigi Rizzo 		pci_cfg_barnum = OCE_DEV_BE2_CFG_BAR;
2492f345d8eSLuigi Rizzo 	else
2502f345d8eSLuigi Rizzo 		pci_cfg_barnum = OCE_DEV_CFG_BAR;
2512f345d8eSLuigi Rizzo 
2522f345d8eSLuigi Rizzo 	rr = PCIR_BAR(pci_cfg_barnum);
2532f345d8eSLuigi Rizzo 
254291a1934SXin LI 	if (IS_BE(sc) || IS_SH(sc))
2552f345d8eSLuigi Rizzo 		sc->devcfg_res = bus_alloc_resource_any(sc->dev,
2562f345d8eSLuigi Rizzo 				SYS_RES_MEMORY, &rr,
2572f345d8eSLuigi Rizzo 				RF_ACTIVE|RF_SHAREABLE);
2582f345d8eSLuigi Rizzo 	else
259c47476d7SJustin Hibbits 		sc->devcfg_res = bus_alloc_resource_anywhere(sc->dev,
260c47476d7SJustin Hibbits 				SYS_RES_MEMORY, &rr, 32768,
2612f345d8eSLuigi Rizzo 				RF_ACTIVE|RF_SHAREABLE);
2622f345d8eSLuigi Rizzo 
2632f345d8eSLuigi Rizzo 	if (!sc->devcfg_res)
2642f345d8eSLuigi Rizzo 		goto error;
2652f345d8eSLuigi Rizzo 
2662f345d8eSLuigi Rizzo 	sc->devcfg_btag = rman_get_bustag(sc->devcfg_res);
2672f345d8eSLuigi Rizzo 	sc->devcfg_bhandle = rman_get_bushandle(sc->devcfg_res);
2682f345d8eSLuigi Rizzo 	sc->devcfg_vhandle = rman_get_virtual(sc->devcfg_res);
2692f345d8eSLuigi Rizzo 
2702f345d8eSLuigi Rizzo 	/* Read the SLI_INTF register and determine whether we
2712f345d8eSLuigi Rizzo 	 * can use this port and its features
2722f345d8eSLuigi Rizzo 	 */
2732f345d8eSLuigi Rizzo 	intf.dw0 = pci_read_config((sc)->dev,OCE_INTF_REG_OFFSET,4);
2742f345d8eSLuigi Rizzo 
2752f345d8eSLuigi Rizzo 	if (intf.bits.sli_valid != OCE_INTF_VALID_SIG)
2762f345d8eSLuigi Rizzo 		goto error;
2772f345d8eSLuigi Rizzo 
2782f345d8eSLuigi Rizzo 	if (intf.bits.sli_rev != OCE_INTF_SLI_REV4) {
2792f345d8eSLuigi Rizzo 		device_printf(sc->dev, "Adapter doesnt support SLI4\n");
2802f345d8eSLuigi Rizzo 		goto error;
2812f345d8eSLuigi Rizzo 	}
2822f345d8eSLuigi Rizzo 
2832f345d8eSLuigi Rizzo 	if (intf.bits.sli_if_type == OCE_INTF_IF_TYPE_1)
2842f345d8eSLuigi Rizzo 		sc->flags |= OCE_FLAGS_MBOX_ENDIAN_RQD;
2852f345d8eSLuigi Rizzo 
2862f345d8eSLuigi Rizzo 	if (intf.bits.sli_hint1 == OCE_INTF_FUNC_RESET_REQD)
2872f345d8eSLuigi Rizzo 		sc->flags |= OCE_FLAGS_FUNCRESET_RQD;
2882f345d8eSLuigi Rizzo 
2892f345d8eSLuigi Rizzo 	if (intf.bits.sli_func_type == OCE_INTF_VIRT_FUNC)
2902f345d8eSLuigi Rizzo 		sc->flags |= OCE_FLAGS_VIRTUAL_PORT;
2912f345d8eSLuigi Rizzo 
2922f345d8eSLuigi Rizzo 	/* Lancer has one BAR (CFG) but BE3 has three (CFG, CSR, DB) */
293291a1934SXin LI 	if (IS_BE(sc) || IS_SH(sc)) {
2942f345d8eSLuigi Rizzo 		/* set up CSR region */
2952f345d8eSLuigi Rizzo 		rr = PCIR_BAR(OCE_PCI_CSR_BAR);
2962f345d8eSLuigi Rizzo 		sc->csr_res = bus_alloc_resource_any(sc->dev,
2972f345d8eSLuigi Rizzo 				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
2982f345d8eSLuigi Rizzo 		if (!sc->csr_res)
2992f345d8eSLuigi Rizzo 			goto error;
3002f345d8eSLuigi Rizzo 		sc->csr_btag = rman_get_bustag(sc->csr_res);
3012f345d8eSLuigi Rizzo 		sc->csr_bhandle = rman_get_bushandle(sc->csr_res);
3022f345d8eSLuigi Rizzo 		sc->csr_vhandle = rman_get_virtual(sc->csr_res);
3032f345d8eSLuigi Rizzo 
3042f345d8eSLuigi Rizzo 		/* set up DB doorbell region */
3052f345d8eSLuigi Rizzo 		rr = PCIR_BAR(OCE_PCI_DB_BAR);
3062f345d8eSLuigi Rizzo 		sc->db_res = bus_alloc_resource_any(sc->dev,
3072f345d8eSLuigi Rizzo 				SYS_RES_MEMORY, &rr, RF_ACTIVE|RF_SHAREABLE);
3082f345d8eSLuigi Rizzo 		if (!sc->db_res)
3092f345d8eSLuigi Rizzo 			goto error;
3102f345d8eSLuigi Rizzo 		sc->db_btag = rman_get_bustag(sc->db_res);
3112f345d8eSLuigi Rizzo 		sc->db_bhandle = rman_get_bushandle(sc->db_res);
3122f345d8eSLuigi Rizzo 		sc->db_vhandle = rman_get_virtual(sc->db_res);
3132f345d8eSLuigi Rizzo 	}
3142f345d8eSLuigi Rizzo 
3152f345d8eSLuigi Rizzo 	return 0;
3162f345d8eSLuigi Rizzo 
3172f345d8eSLuigi Rizzo error:
3182f345d8eSLuigi Rizzo 	oce_hw_pci_free(sc);
3192f345d8eSLuigi Rizzo 	return ENXIO;
3202f345d8eSLuigi Rizzo }
3212f345d8eSLuigi Rizzo 
3222f345d8eSLuigi Rizzo /**
3232f345d8eSLuigi Rizzo  * @brief		Function for device shutdown
3242f345d8eSLuigi Rizzo  * @param sc		software handle to the device
3252f345d8eSLuigi Rizzo  * @returns		0 on success, error otherwise
3262f345d8eSLuigi Rizzo  */
3272f345d8eSLuigi Rizzo void
oce_hw_shutdown(POCE_SOFTC sc)3282f345d8eSLuigi Rizzo oce_hw_shutdown(POCE_SOFTC sc)
3292f345d8eSLuigi Rizzo {
3302f345d8eSLuigi Rizzo 
3312f345d8eSLuigi Rizzo 	oce_stats_free(sc);
3322f345d8eSLuigi Rizzo 	/* disable hardware interrupts */
3332f345d8eSLuigi Rizzo 	oce_hw_intr_disable(sc);
3349bd3250aSLuigi Rizzo #if defined(INET6) || defined(INET)
3352f345d8eSLuigi Rizzo 	/* Free LRO resources */
3362f345d8eSLuigi Rizzo 	oce_free_lro(sc);
3379bd3250aSLuigi Rizzo #endif
3382f345d8eSLuigi Rizzo 	/* Release queue*/
3392f345d8eSLuigi Rizzo 	oce_queue_release_all(sc);
3402f345d8eSLuigi Rizzo 	/*Delete Network Interface*/
3412f345d8eSLuigi Rizzo 	oce_delete_nw_interface(sc);
3422f345d8eSLuigi Rizzo 	/* After fw clean we dont send any cmds to fw.*/
3432f345d8eSLuigi Rizzo 	oce_fw_clean(sc);
3442f345d8eSLuigi Rizzo 	/* release intr resources */
3452f345d8eSLuigi Rizzo 	oce_intr_free(sc);
3462f345d8eSLuigi Rizzo 	/* release PCI resources */
3472f345d8eSLuigi Rizzo 	oce_hw_pci_free(sc);
3482f345d8eSLuigi Rizzo 	/* free mbox specific resources */
3492f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->bmbx_lock);
3502f345d8eSLuigi Rizzo 	LOCK_DESTROY(&sc->dev_lock);
3512f345d8eSLuigi Rizzo 
3522f345d8eSLuigi Rizzo 	oce_dma_free(sc, &sc->bsmbx);
3532f345d8eSLuigi Rizzo }
3542f345d8eSLuigi Rizzo 
3552f345d8eSLuigi Rizzo /**
3562f345d8eSLuigi Rizzo  * @brief		Function for creating nw interface.
3572f345d8eSLuigi Rizzo  * @param sc		software handle to the device
3582f345d8eSLuigi Rizzo  * @returns		0 on success, error otherwise
3592f345d8eSLuigi Rizzo  */
3602f345d8eSLuigi Rizzo int
oce_create_nw_interface(POCE_SOFTC sc)3612f345d8eSLuigi Rizzo oce_create_nw_interface(POCE_SOFTC sc)
3622f345d8eSLuigi Rizzo {
3632f345d8eSLuigi Rizzo 	int rc;
3642f345d8eSLuigi Rizzo 	uint32_t capab_flags;
3652f345d8eSLuigi Rizzo 	uint32_t capab_en_flags;
3662f345d8eSLuigi Rizzo 
3672f345d8eSLuigi Rizzo 	/* interface capabilities to give device when creating interface */
3682f345d8eSLuigi Rizzo 	capab_flags = OCE_CAPAB_FLAGS;
3692f345d8eSLuigi Rizzo 
3702f345d8eSLuigi Rizzo 	/* capabilities to enable by default (others set dynamically) */
3712f345d8eSLuigi Rizzo 	capab_en_flags = OCE_CAPAB_ENABLE;
3722f345d8eSLuigi Rizzo 
3732f345d8eSLuigi Rizzo 	if (IS_XE201(sc)) {
3742f345d8eSLuigi Rizzo 		/* LANCER A0 workaround */
3752f345d8eSLuigi Rizzo 		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
3762f345d8eSLuigi Rizzo 		capab_flags &= ~MBX_RX_IFACE_FLAGS_PASS_L3L4_ERR;
3772f345d8eSLuigi Rizzo 	}
3782f345d8eSLuigi Rizzo 
3795fbb6830SXin LI 	if (IS_SH(sc) || IS_XE201(sc))
3805fbb6830SXin LI 		capab_flags |= MBX_RX_IFACE_FLAGS_MULTICAST;
3815fbb6830SXin LI 
382c2625e6eSJosh Paetzel         if (sc->enable_hwlro) {
383c2625e6eSJosh Paetzel                 capab_flags |= MBX_RX_IFACE_FLAGS_LRO;
384c2625e6eSJosh Paetzel                 capab_en_flags |= MBX_RX_IFACE_FLAGS_LRO;
385c2625e6eSJosh Paetzel         }
386c2625e6eSJosh Paetzel 
3872f345d8eSLuigi Rizzo 	/* enable capabilities controlled via driver startup parameters */
388291a1934SXin LI 	if (is_rss_enabled(sc))
3892f345d8eSLuigi Rizzo 		capab_en_flags |= MBX_RX_IFACE_FLAGS_RSS;
3902f345d8eSLuigi Rizzo 	else {
3912f345d8eSLuigi Rizzo 		capab_en_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
3922f345d8eSLuigi Rizzo 		capab_flags &= ~MBX_RX_IFACE_FLAGS_RSS;
3932f345d8eSLuigi Rizzo 	}
3942f345d8eSLuigi Rizzo 
3952f345d8eSLuigi Rizzo 	rc = oce_if_create(sc,
3962f345d8eSLuigi Rizzo 			   capab_flags,
3972f345d8eSLuigi Rizzo 			   capab_en_flags,
3982f345d8eSLuigi Rizzo 			   0, &sc->macaddr.mac_addr[0], &sc->if_id);
3992f345d8eSLuigi Rizzo 	if (rc)
4002f345d8eSLuigi Rizzo 		return rc;
4012f345d8eSLuigi Rizzo 
4022f345d8eSLuigi Rizzo 	atomic_inc_32(&sc->nifs);
4032f345d8eSLuigi Rizzo 
4042f345d8eSLuigi Rizzo 	sc->if_cap_flags = capab_en_flags;
4052f345d8eSLuigi Rizzo 
4062f345d8eSLuigi Rizzo 	/* set default flow control */
4072f345d8eSLuigi Rizzo 	rc = oce_set_flow_control(sc, sc->flow_control);
4082f345d8eSLuigi Rizzo 	if (rc)
4092f345d8eSLuigi Rizzo 		goto error;
4102f345d8eSLuigi Rizzo 
4112f345d8eSLuigi Rizzo 	rc = oce_rxf_set_promiscuous(sc, sc->promisc);
4122f345d8eSLuigi Rizzo 	if (rc)
4132f345d8eSLuigi Rizzo 		goto error;
4142f345d8eSLuigi Rizzo 
4152f345d8eSLuigi Rizzo 	return rc;
4162f345d8eSLuigi Rizzo 
4172f345d8eSLuigi Rizzo error:
4182f345d8eSLuigi Rizzo 	oce_delete_nw_interface(sc);
4192f345d8eSLuigi Rizzo 	return rc;
4202f345d8eSLuigi Rizzo 
4212f345d8eSLuigi Rizzo }
4222f345d8eSLuigi Rizzo 
4232f345d8eSLuigi Rizzo /**
4242f345d8eSLuigi Rizzo  * @brief		Function to delete a nw interface.
4252f345d8eSLuigi Rizzo  * @param sc		software handle to the device
4262f345d8eSLuigi Rizzo  */
4272f345d8eSLuigi Rizzo void
oce_delete_nw_interface(POCE_SOFTC sc)4282f345d8eSLuigi Rizzo oce_delete_nw_interface(POCE_SOFTC sc)
4292f345d8eSLuigi Rizzo {
4302f345d8eSLuigi Rizzo 	/* currently only single interface is implmeneted */
4312f345d8eSLuigi Rizzo 	if (sc->nifs > 0) {
4322f345d8eSLuigi Rizzo 		oce_if_del(sc, sc->if_id);
4332f345d8eSLuigi Rizzo 		atomic_dec_32(&sc->nifs);
4342f345d8eSLuigi Rizzo 	}
4352f345d8eSLuigi Rizzo }
4362f345d8eSLuigi Rizzo 
4372f345d8eSLuigi Rizzo /**
4382f345d8eSLuigi Rizzo  * @brief Soft reset.
4392f345d8eSLuigi Rizzo  * @param sc		software handle to the device
4402f345d8eSLuigi Rizzo  * @returns		0 on success, error otherwise
4412f345d8eSLuigi Rizzo  */
4422f345d8eSLuigi Rizzo int
oce_pci_soft_reset(POCE_SOFTC sc)4432f345d8eSLuigi Rizzo oce_pci_soft_reset(POCE_SOFTC sc)
4442f345d8eSLuigi Rizzo {
4452f345d8eSLuigi Rizzo 	int rc;
4462f345d8eSLuigi Rizzo 	mpu_ep_control_t ctrl;
4472f345d8eSLuigi Rizzo 
448291a1934SXin LI 	ctrl.dw0 = OCE_READ_CSR_MPU(sc, csr, MPU_EP_CONTROL);
4492f345d8eSLuigi Rizzo 	ctrl.bits.cpu_reset = 1;
450291a1934SXin LI 	OCE_WRITE_CSR_MPU(sc, csr, MPU_EP_CONTROL, ctrl.dw0);
4512f345d8eSLuigi Rizzo 	DELAY(50);
4522f345d8eSLuigi Rizzo 	rc=oce_POST(sc);
4532f345d8eSLuigi Rizzo 
4542f345d8eSLuigi Rizzo 	return rc;
4552f345d8eSLuigi Rizzo }
4562f345d8eSLuigi Rizzo 
4572f345d8eSLuigi Rizzo /**
4582f345d8eSLuigi Rizzo  * @brief		Function for hardware start
4592f345d8eSLuigi Rizzo  * @param sc		software handle to the device
4602f345d8eSLuigi Rizzo  * @returns		0 on success, error otherwise
4612f345d8eSLuigi Rizzo  */
4622f345d8eSLuigi Rizzo int
oce_hw_start(POCE_SOFTC sc)4632f345d8eSLuigi Rizzo oce_hw_start(POCE_SOFTC sc)
4642f345d8eSLuigi Rizzo {
4652f345d8eSLuigi Rizzo 	struct link_status link = { 0 };
4662f345d8eSLuigi Rizzo 	int rc = 0;
4672f345d8eSLuigi Rizzo 
4682f345d8eSLuigi Rizzo 	rc = oce_get_link_status(sc, &link);
4692f345d8eSLuigi Rizzo 	if (rc)
4702f345d8eSLuigi Rizzo 		return 1;
4712f345d8eSLuigi Rizzo 
4722f345d8eSLuigi Rizzo 	if (link.logical_link_status == NTWK_LOGICAL_LINK_UP) {
4732f345d8eSLuigi Rizzo 		sc->link_status = NTWK_LOGICAL_LINK_UP;
4742f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_UP);
4752f345d8eSLuigi Rizzo 	} else {
4762f345d8eSLuigi Rizzo 		sc->link_status = NTWK_LOGICAL_LINK_DOWN;
4772f345d8eSLuigi Rizzo 		if_link_state_change(sc->ifp, LINK_STATE_DOWN);
4782f345d8eSLuigi Rizzo 	}
4792f345d8eSLuigi Rizzo 
480a4f734b4SXin LI 	sc->link_speed = link.phys_port_speed;
4812f345d8eSLuigi Rizzo 	sc->qos_link_speed = (uint32_t )link.qos_link_speed * 10;
4822f345d8eSLuigi Rizzo 
4832f345d8eSLuigi Rizzo 	rc = oce_start_mq(sc->mq);
4842f345d8eSLuigi Rizzo 
4859bd3250aSLuigi Rizzo 	/* we need to get MCC aync events. So enable intrs and arm
4869bd3250aSLuigi Rizzo 	   first EQ, Other EQs will be armed after interface is UP
4872f345d8eSLuigi Rizzo 	*/
4882f345d8eSLuigi Rizzo 	oce_hw_intr_enable(sc);
4892f345d8eSLuigi Rizzo 	oce_arm_eq(sc, sc->eq[0]->eq_id, 0, TRUE, FALSE);
4902f345d8eSLuigi Rizzo 
4919bd3250aSLuigi Rizzo 	/* Send first mcc cmd and after that we get gracious
4929bd3250aSLuigi Rizzo 	   MCC notifications from FW
4939bd3250aSLuigi Rizzo 	*/
4949bd3250aSLuigi Rizzo 	oce_first_mcc_cmd(sc);
4959bd3250aSLuigi Rizzo 
4962f345d8eSLuigi Rizzo 	return rc;
4972f345d8eSLuigi Rizzo }
4982f345d8eSLuigi Rizzo 
4992f345d8eSLuigi Rizzo /**
5002f345d8eSLuigi Rizzo  * @brief 		Function for hardware enable interupts.
5012f345d8eSLuigi Rizzo  * @param sc		software handle to the device
5022f345d8eSLuigi Rizzo  */
5032f345d8eSLuigi Rizzo void
oce_hw_intr_enable(POCE_SOFTC sc)5042f345d8eSLuigi Rizzo oce_hw_intr_enable(POCE_SOFTC sc)
5052f345d8eSLuigi Rizzo {
5062f345d8eSLuigi Rizzo 	uint32_t reg;
5072f345d8eSLuigi Rizzo 
5082f345d8eSLuigi Rizzo 	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
5092f345d8eSLuigi Rizzo 	reg |= HOSTINTR_MASK;
5102f345d8eSLuigi Rizzo 	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
5112f345d8eSLuigi Rizzo 
5122f345d8eSLuigi Rizzo }
5132f345d8eSLuigi Rizzo 
5142f345d8eSLuigi Rizzo /**
5152f345d8eSLuigi Rizzo  * @brief 		Function for hardware disable interupts
5162f345d8eSLuigi Rizzo  * @param sc		software handle to the device
5172f345d8eSLuigi Rizzo  */
5182f345d8eSLuigi Rizzo void
oce_hw_intr_disable(POCE_SOFTC sc)5192f345d8eSLuigi Rizzo oce_hw_intr_disable(POCE_SOFTC sc)
5202f345d8eSLuigi Rizzo {
5212f345d8eSLuigi Rizzo 	uint32_t reg;
5222f345d8eSLuigi Rizzo 
5232f345d8eSLuigi Rizzo 	reg = OCE_READ_REG32(sc, devcfg, PCICFG_INTR_CTRL);
5242f345d8eSLuigi Rizzo 	reg &= ~HOSTINTR_MASK;
5252f345d8eSLuigi Rizzo 	OCE_WRITE_REG32(sc, devcfg, PCICFG_INTR_CTRL, reg);
5262f345d8eSLuigi Rizzo }
5272f345d8eSLuigi Rizzo 
5287384b10fSGleb Smirnoff static u_int
oce_copy_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)5297384b10fSGleb Smirnoff oce_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
5307384b10fSGleb Smirnoff {
5317384b10fSGleb Smirnoff 	struct mbx_set_common_iface_multicast *req = arg;
5327384b10fSGleb Smirnoff 
5337384b10fSGleb Smirnoff 	if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE)
5347384b10fSGleb Smirnoff 		return (0);
5357384b10fSGleb Smirnoff 
5367384b10fSGleb Smirnoff 	bcopy(LLADDR(sdl), &req->params.req.mac[req->params.req.num_mac++],
537e81998f4SEric Joyner 	    ETHER_ADDR_LEN);
5387384b10fSGleb Smirnoff 
5397384b10fSGleb Smirnoff 	return (1);
5407384b10fSGleb Smirnoff }
5417384b10fSGleb Smirnoff 
5422f345d8eSLuigi Rizzo /**
5432f345d8eSLuigi Rizzo  * @brief		Function for hardware update multicast filter
5442f345d8eSLuigi Rizzo  * @param sc		software handle to the device
5452f345d8eSLuigi Rizzo  */
5462f345d8eSLuigi Rizzo int
oce_hw_update_multicast(POCE_SOFTC sc)5472f345d8eSLuigi Rizzo oce_hw_update_multicast(POCE_SOFTC sc)
5482f345d8eSLuigi Rizzo {
54967fd4c9dSJustin Hibbits 	if_t ifp = sc->ifp;
5502f345d8eSLuigi Rizzo 	struct mbx_set_common_iface_multicast *req = NULL;
5512f345d8eSLuigi Rizzo 	OCE_DMA_MEM dma;
5522f345d8eSLuigi Rizzo 	int rc = 0;
5532f345d8eSLuigi Rizzo 
5542f345d8eSLuigi Rizzo 	/* Allocate DMA mem*/
5552f345d8eSLuigi Rizzo 	if (oce_dma_alloc(sc, sizeof(struct mbx_set_common_iface_multicast),
5562f345d8eSLuigi Rizzo 							&dma, 0))
5572f345d8eSLuigi Rizzo 		return ENOMEM;
5582f345d8eSLuigi Rizzo 
5592f345d8eSLuigi Rizzo 	req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast);
5602f345d8eSLuigi Rizzo 	bzero(req, sizeof(struct mbx_set_common_iface_multicast));
5612f345d8eSLuigi Rizzo 
5627384b10fSGleb Smirnoff 	if_foreach_llmaddr(ifp, oce_copy_maddr, req);
5632f345d8eSLuigi Rizzo 	if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) {
5642f345d8eSLuigi Rizzo 		/*More multicast addresses than our hardware table
5652f345d8eSLuigi Rizzo 		  So Enable multicast promiscus in our hardware to
5662f345d8eSLuigi Rizzo 		  accept all multicat packets
5672f345d8eSLuigi Rizzo 		*/
5682f345d8eSLuigi Rizzo 		req->params.req.promiscuous = 1;
5692f345d8eSLuigi Rizzo 	}
5707384b10fSGleb Smirnoff 
5712f345d8eSLuigi Rizzo 	req->params.req.if_id = sc->if_id;
5722f345d8eSLuigi Rizzo 	rc = oce_update_multicast(sc, &dma);
5732f345d8eSLuigi Rizzo 	oce_dma_free(sc, &dma);
5742f345d8eSLuigi Rizzo 	return rc;
5752f345d8eSLuigi Rizzo }
576