19d26e4fcSRobert Mustacchi /*
29d26e4fcSRobert Mustacchi  * This file and its contents are supplied under the terms of the
39d26e4fcSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
49d26e4fcSRobert Mustacchi  * You may only use this file in accordance with the terms of version
59d26e4fcSRobert Mustacchi  * 1.0 of the CDDL.
69d26e4fcSRobert Mustacchi  *
79d26e4fcSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
89d26e4fcSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
99d26e4fcSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
109d26e4fcSRobert Mustacchi  */
119d26e4fcSRobert Mustacchi 
129d26e4fcSRobert Mustacchi /*
139d26e4fcSRobert Mustacchi  * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
149d26e4fcSRobert Mustacchi  * Copyright 2016 Joyent, Inc.
159d26e4fcSRobert Mustacchi  */
169d26e4fcSRobert Mustacchi 
179d26e4fcSRobert Mustacchi #include "i40e_sw.h"
189d26e4fcSRobert Mustacchi #include "i40e_type.h"
199d26e4fcSRobert Mustacchi #include "i40e_alloc.h"
209d26e4fcSRobert Mustacchi #include "i40e_osdep.h"
219d26e4fcSRobert Mustacchi 
229d26e4fcSRobert Mustacchi #include <sys/dtrace.h>
239d26e4fcSRobert Mustacchi 
249d26e4fcSRobert Mustacchi /* ARGSUSED */
259d26e4fcSRobert Mustacchi i40e_status
i40e_allocate_virt_mem(struct i40e_hw * hw,struct i40e_virt_mem * mem,u32 size)269d26e4fcSRobert Mustacchi i40e_allocate_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem, u32 size)
279d26e4fcSRobert Mustacchi {
289d26e4fcSRobert Mustacchi 	mem->va = kmem_zalloc(size, KM_SLEEP);
299d26e4fcSRobert Mustacchi 	mem->size = size;
309d26e4fcSRobert Mustacchi 	return (I40E_SUCCESS);
319d26e4fcSRobert Mustacchi }
329d26e4fcSRobert Mustacchi 
339d26e4fcSRobert Mustacchi /* ARGSUSED */
349d26e4fcSRobert Mustacchi i40e_status
i40e_free_virt_mem(struct i40e_hw * hw,struct i40e_virt_mem * mem)359d26e4fcSRobert Mustacchi i40e_free_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem)
369d26e4fcSRobert Mustacchi {
379d26e4fcSRobert Mustacchi 	if (mem->va != NULL)
389d26e4fcSRobert Mustacchi 		kmem_free(mem->va, mem->size);
399d26e4fcSRobert Mustacchi 	return (I40E_SUCCESS);
409d26e4fcSRobert Mustacchi }
419d26e4fcSRobert Mustacchi 
429d26e4fcSRobert Mustacchi /* ARGSUSED */
439d26e4fcSRobert Mustacchi i40e_status
i40e_allocate_dma_mem(struct i40e_hw * hw,struct i40e_dma_mem * mem,enum i40e_memory_type type,u64 size,u32 alignment)449d26e4fcSRobert Mustacchi i40e_allocate_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem,
459d26e4fcSRobert Mustacchi     enum i40e_memory_type type, u64 size, u32 alignment)
469d26e4fcSRobert Mustacchi {
479d26e4fcSRobert Mustacchi 	int rc;
489d26e4fcSRobert Mustacchi 	i40e_t *i40e = OS_DEP(hw)->ios_i40e;
499d26e4fcSRobert Mustacchi 	dev_info_t *dip = i40e->i40e_dip;
509d26e4fcSRobert Mustacchi 	size_t len;
519d26e4fcSRobert Mustacchi 	ddi_dma_cookie_t cookie;
529d26e4fcSRobert Mustacchi 	uint_t cookie_num;
539d26e4fcSRobert Mustacchi 	ddi_dma_attr_t attr;
549d26e4fcSRobert Mustacchi 
559d26e4fcSRobert Mustacchi 	/*
569d26e4fcSRobert Mustacchi 	 * Because we need to honor the specified alignment, we need to
579d26e4fcSRobert Mustacchi 	 * dynamically construct the attributes. We save the alignment for
589d26e4fcSRobert Mustacchi 	 * debugging purposes.
599d26e4fcSRobert Mustacchi 	 */
609d26e4fcSRobert Mustacchi 	bcopy(&i40e->i40e_static_dma_attr, &attr, sizeof (ddi_dma_attr_t));
619d26e4fcSRobert Mustacchi 	attr.dma_attr_align = alignment;
629d26e4fcSRobert Mustacchi 	mem->idm_alignment = alignment;
639d26e4fcSRobert Mustacchi 	rc = ddi_dma_alloc_handle(dip, &i40e->i40e_static_dma_attr,
649d26e4fcSRobert Mustacchi 	    DDI_DMA_DONTWAIT, NULL, &mem->idm_dma_handle);
659d26e4fcSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
669d26e4fcSRobert Mustacchi 		mem->idm_dma_handle = NULL;
679d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to allocate DMA handle for common "
689d26e4fcSRobert Mustacchi 		    "code: %d", rc);
699d26e4fcSRobert Mustacchi 
709d26e4fcSRobert Mustacchi 		/*
719d26e4fcSRobert Mustacchi 		 * Swallow unknown errors and treat them like we do
729d26e4fcSRobert Mustacchi 		 * DDI_DMA_NORESOURCES, in other words, a memory error.
739d26e4fcSRobert Mustacchi 		 */
749d26e4fcSRobert Mustacchi 		if (rc == DDI_DMA_BADATTR)
759d26e4fcSRobert Mustacchi 			return (I40E_ERR_PARAM);
769d26e4fcSRobert Mustacchi 		return (I40E_ERR_NO_MEMORY);
779d26e4fcSRobert Mustacchi 	}
789d26e4fcSRobert Mustacchi 
799d26e4fcSRobert Mustacchi 	rc = ddi_dma_mem_alloc(mem->idm_dma_handle, size,
809d26e4fcSRobert Mustacchi 	    &i40e->i40e_buf_acc_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT,
819d26e4fcSRobert Mustacchi 	    NULL, (caddr_t *)&mem->va, &len, &mem->idm_acc_handle);
829d26e4fcSRobert Mustacchi 	if (rc != DDI_SUCCESS) {
839d26e4fcSRobert Mustacchi 		mem->idm_acc_handle = NULL;
849d26e4fcSRobert Mustacchi 		mem->va = NULL;
859d26e4fcSRobert Mustacchi 		ASSERT(mem->idm_dma_handle != NULL);
869d26e4fcSRobert Mustacchi 		ddi_dma_free_handle(&mem->idm_dma_handle);
879d26e4fcSRobert Mustacchi 		mem->idm_dma_handle = NULL;
889d26e4fcSRobert Mustacchi 
899d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to allocate %" PRIu64 " bytes of DMA "
909d26e4fcSRobert Mustacchi 		    "memory for common code", size);
919d26e4fcSRobert Mustacchi 		return (I40E_ERR_NO_MEMORY);
929d26e4fcSRobert Mustacchi 	}
939d26e4fcSRobert Mustacchi 
949d26e4fcSRobert Mustacchi 	bzero(mem->va, len);
959d26e4fcSRobert Mustacchi 
969d26e4fcSRobert Mustacchi 	rc = ddi_dma_addr_bind_handle(mem->idm_dma_handle, NULL, mem->va, len,
979d26e4fcSRobert Mustacchi 	    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL,
989d26e4fcSRobert Mustacchi 	    &cookie, &cookie_num);
999d26e4fcSRobert Mustacchi 	if (rc != DDI_DMA_MAPPED) {
100*ae6f9789SToomas Soome 		mem->pa = 0;
1019d26e4fcSRobert Mustacchi 		ASSERT(mem->idm_acc_handle != NULL);
1029d26e4fcSRobert Mustacchi 		ddi_dma_mem_free(&mem->idm_acc_handle);
1039d26e4fcSRobert Mustacchi 		mem->idm_acc_handle = NULL;
1049d26e4fcSRobert Mustacchi 		mem->va = NULL;
1059d26e4fcSRobert Mustacchi 		ASSERT(mem->idm_dma_handle != NULL);
1069d26e4fcSRobert Mustacchi 		ddi_dma_free_handle(&mem->idm_dma_handle);
1079d26e4fcSRobert Mustacchi 		mem->idm_dma_handle = NULL;
1089d26e4fcSRobert Mustacchi 
1099d26e4fcSRobert Mustacchi 		i40e_error(i40e, "failed to bind %ld byte sized dma region: %d",
1109d26e4fcSRobert Mustacchi 		    len, rc);
1119d26e4fcSRobert Mustacchi 		switch (rc) {
1129d26e4fcSRobert Mustacchi 		case DDI_DMA_INUSE:
1139d26e4fcSRobert Mustacchi 			return (I40E_ERR_NOT_READY);
1149d26e4fcSRobert Mustacchi 		case DDI_DMA_TOOBIG:
1159d26e4fcSRobert Mustacchi 			return (I40E_ERR_INVALID_SIZE);
1169d26e4fcSRobert Mustacchi 		case DDI_DMA_NOMAPPING:
1179d26e4fcSRobert Mustacchi 		case DDI_DMA_NORESOURCES:
1189d26e4fcSRobert Mustacchi 		default:
1199d26e4fcSRobert Mustacchi 			return (I40E_ERR_NO_MEMORY);
1209d26e4fcSRobert Mustacchi 		}
1219d26e4fcSRobert Mustacchi 	}
1229d26e4fcSRobert Mustacchi 
1239d26e4fcSRobert Mustacchi 	ASSERT(cookie_num == 1);
1249d26e4fcSRobert Mustacchi 	mem->pa = cookie.dmac_laddress;
1259d26e4fcSRobert Mustacchi 	/*
1269d26e4fcSRobert Mustacchi 	 * Lint doesn't like this because the common code gives us a uint64_t as
1279d26e4fcSRobert Mustacchi 	 * input, but the common code then asks us to assign it to a size_t. So
1289d26e4fcSRobert Mustacchi 	 * lint's right, but in this case there isn't much we can do.
1299d26e4fcSRobert Mustacchi 	 */
1309d26e4fcSRobert Mustacchi 	mem->size = (size_t)size;
1319d26e4fcSRobert Mustacchi 
1329d26e4fcSRobert Mustacchi 	return (I40E_SUCCESS);
1339d26e4fcSRobert Mustacchi }
1349d26e4fcSRobert Mustacchi 
1359d26e4fcSRobert Mustacchi /* ARGSUSED */
1369d26e4fcSRobert Mustacchi i40e_status
i40e_free_dma_mem(struct i40e_hw * hw,struct i40e_dma_mem * mem)1379d26e4fcSRobert Mustacchi i40e_free_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem)
1389d26e4fcSRobert Mustacchi {
1399d26e4fcSRobert Mustacchi 	if (mem->pa != 0) {
1409d26e4fcSRobert Mustacchi 		VERIFY(mem->idm_dma_handle != NULL);
1419d26e4fcSRobert Mustacchi 		(void) ddi_dma_unbind_handle(mem->idm_dma_handle);
1429d26e4fcSRobert Mustacchi 		mem->pa = 0;
1439d26e4fcSRobert Mustacchi 		mem->size = 0;
1449d26e4fcSRobert Mustacchi 	}
1459d26e4fcSRobert Mustacchi 
1469d26e4fcSRobert Mustacchi 	if (mem->idm_acc_handle != NULL) {
1479d26e4fcSRobert Mustacchi 		ddi_dma_mem_free(&mem->idm_acc_handle);
1489d26e4fcSRobert Mustacchi 		mem->idm_acc_handle = NULL;
1499d26e4fcSRobert Mustacchi 		mem->va = NULL;
1509d26e4fcSRobert Mustacchi 	}
1519d26e4fcSRobert Mustacchi 
1529d26e4fcSRobert Mustacchi 	if (mem->idm_dma_handle != NULL) {
1539d26e4fcSRobert Mustacchi 		ddi_dma_free_handle(&mem->idm_dma_handle);
1549d26e4fcSRobert Mustacchi 		mem->idm_dma_handle = NULL;
1559d26e4fcSRobert Mustacchi 	}
1569d26e4fcSRobert Mustacchi 
1579d26e4fcSRobert Mustacchi 	/*
1589d26e4fcSRobert Mustacchi 	 * Watch out for sloppiness.
1599d26e4fcSRobert Mustacchi 	 */
1609d26e4fcSRobert Mustacchi 	ASSERT(mem->pa == 0);
1619d26e4fcSRobert Mustacchi 	ASSERT(mem->va == NULL);
1629d26e4fcSRobert Mustacchi 	ASSERT(mem->size == 0);
1639d26e4fcSRobert Mustacchi 	mem->idm_alignment = UINT32_MAX;
1649d26e4fcSRobert Mustacchi 
1659d26e4fcSRobert Mustacchi 	return (I40E_SUCCESS);
1669d26e4fcSRobert Mustacchi }
1679d26e4fcSRobert Mustacchi 
1689d26e4fcSRobert Mustacchi /*
1699d26e4fcSRobert Mustacchi  * The common code wants to initialize its 'spinlocks' here, aka adaptive
1709d26e4fcSRobert Mustacchi  * mutexes. At this time these are only used to maintain the adminq's data and
1719d26e4fcSRobert Mustacchi  * as such it will only be used outside of interrupt context and even then,
1729d26e4fcSRobert Mustacchi  * we're not going to actually end up ever doing anything above lock level and
1739d26e4fcSRobert Mustacchi  * up in doing stuff with high level interrupts.
1749d26e4fcSRobert Mustacchi  */
1759d26e4fcSRobert Mustacchi void
i40e_init_spinlock(struct i40e_spinlock * lock)1769d26e4fcSRobert Mustacchi i40e_init_spinlock(struct i40e_spinlock *lock)
1779d26e4fcSRobert Mustacchi {
1789d26e4fcSRobert Mustacchi 	mutex_init(&lock->ispl_mutex, NULL, MUTEX_DRIVER, NULL);
1799d26e4fcSRobert Mustacchi }
1809d26e4fcSRobert Mustacchi 
1819d26e4fcSRobert Mustacchi void
i40e_acquire_spinlock(struct i40e_spinlock * lock)1829d26e4fcSRobert Mustacchi i40e_acquire_spinlock(struct i40e_spinlock *lock)
1839d26e4fcSRobert Mustacchi {
1849d26e4fcSRobert Mustacchi 	mutex_enter(&lock->ispl_mutex);
1859d26e4fcSRobert Mustacchi }
1869d26e4fcSRobert Mustacchi 
1879d26e4fcSRobert Mustacchi void
i40e_release_spinlock(struct i40e_spinlock * lock)1889d26e4fcSRobert Mustacchi i40e_release_spinlock(struct i40e_spinlock *lock)
1899d26e4fcSRobert Mustacchi {
1909d26e4fcSRobert Mustacchi 	mutex_exit(&lock->ispl_mutex);
1919d26e4fcSRobert Mustacchi }
1929d26e4fcSRobert Mustacchi 
1939d26e4fcSRobert Mustacchi void
i40e_destroy_spinlock(struct i40e_spinlock * lock)1949d26e4fcSRobert Mustacchi i40e_destroy_spinlock(struct i40e_spinlock *lock)
1959d26e4fcSRobert Mustacchi {
1969d26e4fcSRobert Mustacchi 	mutex_destroy(&lock->ispl_mutex);
1979d26e4fcSRobert Mustacchi }
1989d26e4fcSRobert Mustacchi 
1999d26e4fcSRobert Mustacchi boolean_t
i40e_set_hw_bus_info(struct i40e_hw * hw)2009d26e4fcSRobert Mustacchi i40e_set_hw_bus_info(struct i40e_hw *hw)
2019d26e4fcSRobert Mustacchi {
2029d26e4fcSRobert Mustacchi 	uint8_t pcie_id = PCI_CAP_ID_PCI_E;
2039d26e4fcSRobert Mustacchi 	uint16_t pcie_cap, value;
2049d26e4fcSRobert Mustacchi 	int status;
2059d26e4fcSRobert Mustacchi 
2069d26e4fcSRobert Mustacchi 	/* locate the pci-e capability block */
2079d26e4fcSRobert Mustacchi 	status = pci_lcap_locate((OS_DEP(hw))->ios_cfg_handle, pcie_id,
2089d26e4fcSRobert Mustacchi 	    &pcie_cap);
2099d26e4fcSRobert Mustacchi 	if (status != DDI_SUCCESS) {
2109d26e4fcSRobert Mustacchi 		i40e_error(OS_DEP(hw)->ios_i40e, "failed to locate PCIe "
2119d26e4fcSRobert Mustacchi 		    "capability block: %d",
2129d26e4fcSRobert Mustacchi 		    status);
2139d26e4fcSRobert Mustacchi 		return (B_FALSE);
2149d26e4fcSRobert Mustacchi 	}
2159d26e4fcSRobert Mustacchi 
2169d26e4fcSRobert Mustacchi 	value = pci_config_get16(OS_DEP(hw)->ios_cfg_handle,
2179d26e4fcSRobert Mustacchi 	    pcie_cap + PCIE_LINKSTS);
2189d26e4fcSRobert Mustacchi 
2199d26e4fcSRobert Mustacchi 	i40e_set_pci_config_data(hw, value);
2209d26e4fcSRobert Mustacchi 
2219d26e4fcSRobert Mustacchi 	return (B_TRUE);
2229d26e4fcSRobert Mustacchi }
2239d26e4fcSRobert Mustacchi 
2249d26e4fcSRobert Mustacchi /* ARGSUSED */
2259d26e4fcSRobert Mustacchi void
i40e_debug(void * hw,u32 mask,char * fmt,...)2269d26e4fcSRobert Mustacchi i40e_debug(void *hw, u32 mask, char *fmt, ...)
2279d26e4fcSRobert Mustacchi {
2289d26e4fcSRobert Mustacchi 	char buf[1024];
2299d26e4fcSRobert Mustacchi 	va_list args;
2309d26e4fcSRobert Mustacchi 
2319d26e4fcSRobert Mustacchi 	va_start(args, fmt);
2329d26e4fcSRobert Mustacchi 	(void) vsnprintf(buf, sizeof (buf), fmt, args);
2339d26e4fcSRobert Mustacchi 	va_end(args);
2349d26e4fcSRobert Mustacchi 
2359d26e4fcSRobert Mustacchi 	DTRACE_PROBE2(i40e__debug, uint32_t, mask, char *, buf);
2369d26e4fcSRobert Mustacchi }
237