1 /****************************************************************************** 2 3 Copyright (c) 2013-2015, Intel Corporation 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are met: 8 9 1. Redistributions of source code must retain the above copyright notice, 10 this list of conditions and the following disclaimer. 11 12 2. Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in the 14 documentation and/or other materials provided with the distribution. 15 16 3. Neither the name of the Intel Corporation nor the names of its 17 contributors may be used to endorse or promote products derived from 18 this software without specific prior written permission. 19 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 POSSIBILITY OF SUCH DAMAGE. 31 32 ******************************************************************************/ 33 /*$FreeBSD$*/ 34 35 #include "i40e_osdep.h" 36 #include "i40e_register.h" 37 #include "i40e_status.h" 38 #include "i40e_alloc.h" 39 #include "i40e_hmc.h" 40 #ifndef I40E_NO_TYPE_HEADER 41 #include "i40e_type.h" 42 #endif 43 44 /** 45 * i40e_add_sd_table_entry - Adds a segment descriptor to the table 46 * @hw: pointer to our hw struct 47 * @hmc_info: pointer to the HMC configuration information struct 48 * @sd_index: segment descriptor index to manipulate 49 * @type: what type of segment descriptor we're manipulating 50 * @direct_mode_sz: size to alloc in direct mode 51 **/ 52 enum i40e_status_code i40e_add_sd_table_entry(struct i40e_hw *hw, 53 struct i40e_hmc_info *hmc_info, 54 u32 sd_index, 55 enum i40e_sd_entry_type type, 56 u64 direct_mode_sz) 57 { 58 enum i40e_status_code ret_code = I40E_SUCCESS; 59 struct i40e_hmc_sd_entry *sd_entry; 60 enum i40e_memory_type mem_type; 61 bool dma_mem_alloc_done = FALSE; 62 struct i40e_dma_mem mem; 63 u64 alloc_len; 64 65 if (NULL == hmc_info->sd_table.sd_entry) { 66 ret_code = I40E_ERR_BAD_PTR; 67 DEBUGOUT("i40e_add_sd_table_entry: bad sd_entry\n"); 68 goto exit; 69 } 70 71 if (sd_index >= hmc_info->sd_table.sd_cnt) { 72 ret_code = I40E_ERR_INVALID_SD_INDEX; 73 DEBUGOUT("i40e_add_sd_table_entry: bad sd_index\n"); 74 goto exit; 75 } 76 77 sd_entry = &hmc_info->sd_table.sd_entry[sd_index]; 78 if (!sd_entry->valid) { 79 if (I40E_SD_TYPE_PAGED == type) { 80 mem_type = i40e_mem_pd; 81 alloc_len = I40E_HMC_PAGED_BP_SIZE; 82 } else { 83 mem_type = i40e_mem_bp_jumbo; 84 alloc_len = direct_mode_sz; 85 } 86 87 /* allocate a 4K pd page or 2M backing page */ 88 ret_code = i40e_allocate_dma_mem(hw, &mem, mem_type, alloc_len, 89 I40E_HMC_PD_BP_BUF_ALIGNMENT); 90 if (ret_code) 91 goto exit; 92 dma_mem_alloc_done = TRUE; 93 if (I40E_SD_TYPE_PAGED == type) { 94 ret_code = i40e_allocate_virt_mem(hw, 95 &sd_entry->u.pd_table.pd_entry_virt_mem, 96 sizeof(struct i40e_hmc_pd_entry) * 512); 97 if (ret_code) 98 goto exit; 99 sd_entry->u.pd_table.pd_entry = 100 (struct i40e_hmc_pd_entry *) 101 sd_entry->u.pd_table.pd_entry_virt_mem.va; 102 i40e_memcpy(&sd_entry->u.pd_table.pd_page_addr, 103 &mem, sizeof(struct i40e_dma_mem), 104 I40E_NONDMA_TO_NONDMA); 105 } else { 106 i40e_memcpy(&sd_entry->u.bp.addr, 107 &mem, sizeof(struct i40e_dma_mem), 108 I40E_NONDMA_TO_NONDMA); 109 sd_entry->u.bp.sd_pd_index = sd_index; 110 } 111 /* initialize the sd entry */ 112 hmc_info->sd_table.sd_entry[sd_index].entry_type = type; 113 114 /* increment the ref count */ 115 I40E_INC_SD_REFCNT(&hmc_info->sd_table); 116 } 117 /* Increment backing page reference count */ 118 if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type) 119 I40E_INC_BP_REFCNT(&sd_entry->u.bp); 120 exit: 121 if (I40E_SUCCESS != ret_code) 122 if (dma_mem_alloc_done) 123 i40e_free_dma_mem(hw, &mem); 124 125 return ret_code; 126 } 127 128 /** 129 * i40e_add_pd_table_entry - Adds page descriptor to the specified table 130 * @hw: pointer to our HW structure 131 * @hmc_info: pointer to the HMC configuration information structure 132 * @pd_index: which page descriptor index to manipulate 133 * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one. 134 * 135 * This function: 136 * 1. Initializes the pd entry 137 * 2. Adds pd_entry in the pd_table 138 * 3. Mark the entry valid in i40e_hmc_pd_entry structure 139 * 4. Initializes the pd_entry's ref count to 1 140 * assumptions: 141 * 1. The memory for pd should be pinned down, physically contiguous and 142 * aligned on 4K boundary and zeroed memory. 143 * 2. It should be 4K in size. 144 **/ 145 enum i40e_status_code i40e_add_pd_table_entry(struct i40e_hw *hw, 146 struct i40e_hmc_info *hmc_info, 147 u32 pd_index, 148 struct i40e_dma_mem *rsrc_pg) 149 { 150 enum i40e_status_code ret_code = I40E_SUCCESS; 151 struct i40e_hmc_pd_table *pd_table; 152 struct i40e_hmc_pd_entry *pd_entry; 153 struct i40e_dma_mem mem; 154 struct i40e_dma_mem *page = &mem; 155 u32 sd_idx, rel_pd_idx; 156 u64 *pd_addr; 157 u64 page_desc; 158 159 if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) { 160 ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; 161 DEBUGOUT("i40e_add_pd_table_entry: bad pd_index\n"); 162 goto exit; 163 } 164 165 /* find corresponding sd */ 166 sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD); 167 if (I40E_SD_TYPE_PAGED != 168 hmc_info->sd_table.sd_entry[sd_idx].entry_type) 169 goto exit; 170 171 rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD); 172 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; 173 pd_entry = &pd_table->pd_entry[rel_pd_idx]; 174 if (!pd_entry->valid) { 175 if (rsrc_pg) { 176 pd_entry->rsrc_pg = TRUE; 177 page = rsrc_pg; 178 } else { 179 /* allocate a 4K backing page */ 180 ret_code = i40e_allocate_dma_mem(hw, page, i40e_mem_bp, 181 I40E_HMC_PAGED_BP_SIZE, 182 I40E_HMC_PD_BP_BUF_ALIGNMENT); 183 if (ret_code) 184 goto exit; 185 pd_entry->rsrc_pg = FALSE; 186 } 187 188 i40e_memcpy(&pd_entry->bp.addr, page, 189 sizeof(struct i40e_dma_mem), I40E_NONDMA_TO_NONDMA); 190 pd_entry->bp.sd_pd_index = pd_index; 191 pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; 192 /* Set page address and valid bit */ 193 page_desc = page->pa | 0x1; 194 195 pd_addr = (u64 *)pd_table->pd_page_addr.va; 196 pd_addr += rel_pd_idx; 197 198 /* Add the backing page physical address in the pd entry */ 199 i40e_memcpy(pd_addr, &page_desc, sizeof(u64), 200 I40E_NONDMA_TO_DMA); 201 202 pd_entry->sd_index = sd_idx; 203 pd_entry->valid = TRUE; 204 I40E_INC_PD_REFCNT(pd_table); 205 } 206 I40E_INC_BP_REFCNT(&pd_entry->bp); 207 exit: 208 return ret_code; 209 } 210 211 /** 212 * i40e_remove_pd_bp - remove a backing page from a page descriptor 213 * @hw: pointer to our HW structure 214 * @hmc_info: pointer to the HMC configuration information structure 215 * @idx: the page index 216 * @is_pf: distinguishes a VF from a PF 217 * 218 * This function: 219 * 1. Marks the entry in pd tabe (for paged address mode) or in sd table 220 * (for direct address mode) invalid. 221 * 2. Write to register PMPDINV to invalidate the backing page in FV cache 222 * 3. Decrement the ref count for the pd _entry 223 * assumptions: 224 * 1. Caller can deallocate the memory used by backing storage after this 225 * function returns. 226 **/ 227 enum i40e_status_code i40e_remove_pd_bp(struct i40e_hw *hw, 228 struct i40e_hmc_info *hmc_info, 229 u32 idx) 230 { 231 enum i40e_status_code ret_code = I40E_SUCCESS; 232 struct i40e_hmc_pd_entry *pd_entry; 233 struct i40e_hmc_pd_table *pd_table; 234 struct i40e_hmc_sd_entry *sd_entry; 235 u32 sd_idx, rel_pd_idx; 236 u64 *pd_addr; 237 238 /* calculate index */ 239 sd_idx = idx / I40E_HMC_PD_CNT_IN_SD; 240 rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD; 241 if (sd_idx >= hmc_info->sd_table.sd_cnt) { 242 ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; 243 DEBUGOUT("i40e_remove_pd_bp: bad idx\n"); 244 goto exit; 245 } 246 sd_entry = &hmc_info->sd_table.sd_entry[sd_idx]; 247 if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) { 248 ret_code = I40E_ERR_INVALID_SD_TYPE; 249 DEBUGOUT("i40e_remove_pd_bp: wrong sd_entry type\n"); 250 goto exit; 251 } 252 /* get the entry and decrease its ref counter */ 253 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; 254 pd_entry = &pd_table->pd_entry[rel_pd_idx]; 255 I40E_DEC_BP_REFCNT(&pd_entry->bp); 256 if (pd_entry->bp.ref_cnt) 257 goto exit; 258 259 /* mark the entry invalid */ 260 pd_entry->valid = FALSE; 261 I40E_DEC_PD_REFCNT(pd_table); 262 pd_addr = (u64 *)pd_table->pd_page_addr.va; 263 pd_addr += rel_pd_idx; 264 i40e_memset(pd_addr, 0, sizeof(u64), I40E_DMA_MEM); 265 I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx); 266 267 /* free memory here */ 268 if (!pd_entry->rsrc_pg) 269 ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr)); 270 if (I40E_SUCCESS != ret_code) 271 goto exit; 272 if (!pd_table->ref_cnt) 273 i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem); 274 exit: 275 return ret_code; 276 } 277 278 /** 279 * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry 280 * @hmc_info: pointer to the HMC configuration information structure 281 * @idx: the page index 282 **/ 283 enum i40e_status_code i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info, 284 u32 idx) 285 { 286 enum i40e_status_code ret_code = I40E_SUCCESS; 287 struct i40e_hmc_sd_entry *sd_entry; 288 289 /* get the entry and decrease its ref counter */ 290 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 291 I40E_DEC_BP_REFCNT(&sd_entry->u.bp); 292 if (sd_entry->u.bp.ref_cnt) { 293 ret_code = I40E_ERR_NOT_READY; 294 goto exit; 295 } 296 I40E_DEC_SD_REFCNT(&hmc_info->sd_table); 297 298 /* mark the entry invalid */ 299 sd_entry->valid = FALSE; 300 exit: 301 return ret_code; 302 } 303 304 /** 305 * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor 306 * @hw: pointer to our hw struct 307 * @hmc_info: pointer to the HMC configuration information structure 308 * @idx: the page index 309 * @is_pf: used to distinguish between VF and PF 310 **/ 311 enum i40e_status_code i40e_remove_sd_bp_new(struct i40e_hw *hw, 312 struct i40e_hmc_info *hmc_info, 313 u32 idx, bool is_pf) 314 { 315 struct i40e_hmc_sd_entry *sd_entry; 316 317 if (!is_pf) 318 return I40E_NOT_SUPPORTED; 319 320 /* get the entry and decrease its ref counter */ 321 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 322 I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); 323 324 return i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr)); 325 } 326 327 /** 328 * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry. 329 * @hmc_info: pointer to the HMC configuration information structure 330 * @idx: segment descriptor index to find the relevant page descriptor 331 **/ 332 enum i40e_status_code i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info, 333 u32 idx) 334 { 335 enum i40e_status_code ret_code = I40E_SUCCESS; 336 struct i40e_hmc_sd_entry *sd_entry; 337 338 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 339 340 if (sd_entry->u.pd_table.ref_cnt) { 341 ret_code = I40E_ERR_NOT_READY; 342 goto exit; 343 } 344 345 /* mark the entry invalid */ 346 sd_entry->valid = FALSE; 347 348 I40E_DEC_SD_REFCNT(&hmc_info->sd_table); 349 exit: 350 return ret_code; 351 } 352 353 /** 354 * i40e_remove_pd_page_new - Removes a PD page from sd entry. 355 * @hw: pointer to our hw struct 356 * @hmc_info: pointer to the HMC configuration information structure 357 * @idx: segment descriptor index to find the relevant page descriptor 358 * @is_pf: used to distinguish between VF and PF 359 **/ 360 enum i40e_status_code i40e_remove_pd_page_new(struct i40e_hw *hw, 361 struct i40e_hmc_info *hmc_info, 362 u32 idx, bool is_pf) 363 { 364 struct i40e_hmc_sd_entry *sd_entry; 365 366 if (!is_pf) 367 return I40E_NOT_SUPPORTED; 368 369 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 370 I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); 371 372 return i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr)); 373 } 374