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