1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. 14 * Copyright 2016 Joyent, Inc. 15 */ 16 17 #include "i40e_sw.h" 18 #include "i40e_type.h" 19 #include "i40e_alloc.h" 20 #include "i40e_osdep.h" 21 22 #include <sys/dtrace.h> 23 24 /* ARGSUSED */ 25 i40e_status 26 i40e_allocate_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem, u32 size) 27 { 28 mem->va = kmem_zalloc(size, KM_SLEEP); 29 mem->size = size; 30 return (I40E_SUCCESS); 31 } 32 33 /* ARGSUSED */ 34 i40e_status 35 i40e_free_virt_mem(struct i40e_hw *hw, struct i40e_virt_mem *mem) 36 { 37 if (mem->va != NULL) 38 kmem_free(mem->va, mem->size); 39 return (I40E_SUCCESS); 40 } 41 42 /* ARGSUSED */ 43 i40e_status 44 i40e_allocate_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem, 45 enum i40e_memory_type type, u64 size, u32 alignment) 46 { 47 int rc; 48 i40e_t *i40e = OS_DEP(hw)->ios_i40e; 49 dev_info_t *dip = i40e->i40e_dip; 50 size_t len; 51 ddi_dma_cookie_t cookie; 52 uint_t cookie_num; 53 ddi_dma_attr_t attr; 54 55 /* 56 * Because we need to honor the specified alignment, we need to 57 * dynamically construct the attributes. We save the alignment for 58 * debugging purposes. 59 */ 60 bcopy(&i40e->i40e_static_dma_attr, &attr, sizeof (ddi_dma_attr_t)); 61 attr.dma_attr_align = alignment; 62 mem->idm_alignment = alignment; 63 rc = ddi_dma_alloc_handle(dip, &i40e->i40e_static_dma_attr, 64 DDI_DMA_DONTWAIT, NULL, &mem->idm_dma_handle); 65 if (rc != DDI_SUCCESS) { 66 mem->idm_dma_handle = NULL; 67 i40e_error(i40e, "failed to allocate DMA handle for common " 68 "code: %d", rc); 69 70 /* 71 * Swallow unknown errors and treat them like we do 72 * DDI_DMA_NORESOURCES, in other words, a memory error. 73 */ 74 if (rc == DDI_DMA_BADATTR) 75 return (I40E_ERR_PARAM); 76 return (I40E_ERR_NO_MEMORY); 77 } 78 79 rc = ddi_dma_mem_alloc(mem->idm_dma_handle, size, 80 &i40e->i40e_buf_acc_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 81 NULL, (caddr_t *)&mem->va, &len, &mem->idm_acc_handle); 82 if (rc != DDI_SUCCESS) { 83 mem->idm_acc_handle = NULL; 84 mem->va = NULL; 85 ASSERT(mem->idm_dma_handle != NULL); 86 ddi_dma_free_handle(&mem->idm_dma_handle); 87 mem->idm_dma_handle = NULL; 88 89 i40e_error(i40e, "failed to allocate %" PRIu64 " bytes of DMA " 90 "memory for common code", size); 91 return (I40E_ERR_NO_MEMORY); 92 } 93 94 bzero(mem->va, len); 95 96 rc = ddi_dma_addr_bind_handle(mem->idm_dma_handle, NULL, mem->va, len, 97 DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL, 98 &cookie, &cookie_num); 99 if (rc != DDI_DMA_MAPPED) { 100 mem->pa = NULL; 101 ASSERT(mem->idm_acc_handle != NULL); 102 ddi_dma_mem_free(&mem->idm_acc_handle); 103 mem->idm_acc_handle = NULL; 104 mem->va = NULL; 105 ASSERT(mem->idm_dma_handle != NULL); 106 ddi_dma_free_handle(&mem->idm_dma_handle); 107 mem->idm_dma_handle = NULL; 108 109 i40e_error(i40e, "failed to bind %ld byte sized dma region: %d", 110 len, rc); 111 switch (rc) { 112 case DDI_DMA_INUSE: 113 return (I40E_ERR_NOT_READY); 114 case DDI_DMA_TOOBIG: 115 return (I40E_ERR_INVALID_SIZE); 116 case DDI_DMA_NOMAPPING: 117 case DDI_DMA_NORESOURCES: 118 default: 119 return (I40E_ERR_NO_MEMORY); 120 } 121 } 122 123 ASSERT(cookie_num == 1); 124 mem->pa = cookie.dmac_laddress; 125 /* 126 * Lint doesn't like this because the common code gives us a uint64_t as 127 * input, but the common code then asks us to assign it to a size_t. So 128 * lint's right, but in this case there isn't much we can do. 129 */ 130 mem->size = (size_t)size; 131 132 return (I40E_SUCCESS); 133 } 134 135 /* ARGSUSED */ 136 i40e_status 137 i40e_free_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem) 138 { 139 if (mem->pa != 0) { 140 VERIFY(mem->idm_dma_handle != NULL); 141 (void) ddi_dma_unbind_handle(mem->idm_dma_handle); 142 mem->pa = 0; 143 mem->size = 0; 144 } 145 146 if (mem->idm_acc_handle != NULL) { 147 ddi_dma_mem_free(&mem->idm_acc_handle); 148 mem->idm_acc_handle = NULL; 149 mem->va = NULL; 150 } 151 152 if (mem->idm_dma_handle != NULL) { 153 ddi_dma_free_handle(&mem->idm_dma_handle); 154 mem->idm_dma_handle = NULL; 155 } 156 157 /* 158 * Watch out for sloppiness. 159 */ 160 ASSERT(mem->pa == 0); 161 ASSERT(mem->va == NULL); 162 ASSERT(mem->size == 0); 163 mem->idm_alignment = UINT32_MAX; 164 165 return (I40E_SUCCESS); 166 } 167 168 /* 169 * The common code wants to initialize its 'spinlocks' here, aka adaptive 170 * mutexes. At this time these are only used to maintain the adminq's data and 171 * as such it will only be used outside of interrupt context and even then, 172 * we're not going to actually end up ever doing anything above lock level and 173 * up in doing stuff with high level interrupts. 174 */ 175 void 176 i40e_init_spinlock(struct i40e_spinlock *lock) 177 { 178 mutex_init(&lock->ispl_mutex, NULL, MUTEX_DRIVER, NULL); 179 } 180 181 void 182 i40e_acquire_spinlock(struct i40e_spinlock *lock) 183 { 184 mutex_enter(&lock->ispl_mutex); 185 } 186 187 void 188 i40e_release_spinlock(struct i40e_spinlock *lock) 189 { 190 mutex_exit(&lock->ispl_mutex); 191 } 192 193 void 194 i40e_destroy_spinlock(struct i40e_spinlock *lock) 195 { 196 mutex_destroy(&lock->ispl_mutex); 197 } 198 199 boolean_t 200 i40e_set_hw_bus_info(struct i40e_hw *hw) 201 { 202 uint8_t pcie_id = PCI_CAP_ID_PCI_E; 203 uint16_t pcie_cap, value; 204 int status; 205 206 /* locate the pci-e capability block */ 207 status = pci_lcap_locate((OS_DEP(hw))->ios_cfg_handle, pcie_id, 208 &pcie_cap); 209 if (status != DDI_SUCCESS) { 210 i40e_error(OS_DEP(hw)->ios_i40e, "failed to locate PCIe " 211 "capability block: %d", 212 status); 213 return (B_FALSE); 214 } 215 216 value = pci_config_get16(OS_DEP(hw)->ios_cfg_handle, 217 pcie_cap + PCIE_LINKSTS); 218 219 i40e_set_pci_config_data(hw, value); 220 221 return (B_TRUE); 222 } 223 224 /* ARGSUSED */ 225 void 226 i40e_debug(void *hw, u32 mask, char *fmt, ...) 227 { 228 char buf[1024]; 229 va_list args; 230 231 va_start(args, fmt); 232 (void) vsnprintf(buf, sizeof (buf), fmt, args); 233 va_end(args); 234 235 DTRACE_PROBE2(i40e__debug, uint32_t, mask, char *, buf); 236 } 237