1 /****************************************************************************** 2 3 Copyright (c) 2013-2014, 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 * 134 * This function: 135 * 1. Initializes the pd entry 136 * 2. Adds pd_entry in the pd_table 137 * 3. Mark the entry valid in i40e_hmc_pd_entry structure 138 * 4. Initializes the pd_entry's ref count to 1 139 * assumptions: 140 * 1. The memory for pd should be pinned down, physically contiguous and 141 * aligned on 4K boundary and zeroed memory. 142 * 2. It should be 4K in size. 143 **/ 144 enum i40e_status_code i40e_add_pd_table_entry(struct i40e_hw *hw, 145 struct i40e_hmc_info *hmc_info, 146 u32 pd_index) 147 { 148 enum i40e_status_code ret_code = I40E_SUCCESS; 149 struct i40e_hmc_pd_table *pd_table; 150 struct i40e_hmc_pd_entry *pd_entry; 151 struct i40e_dma_mem mem; 152 u32 sd_idx, rel_pd_idx; 153 u64 *pd_addr; 154 u64 page_desc; 155 156 if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) { 157 ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; 158 DEBUGOUT("i40e_add_pd_table_entry: bad pd_index\n"); 159 goto exit; 160 } 161 162 /* find corresponding sd */ 163 sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD); 164 if (I40E_SD_TYPE_PAGED != 165 hmc_info->sd_table.sd_entry[sd_idx].entry_type) 166 goto exit; 167 168 rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD); 169 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; 170 pd_entry = &pd_table->pd_entry[rel_pd_idx]; 171 if (!pd_entry->valid) { 172 /* allocate a 4K backing page */ 173 ret_code = i40e_allocate_dma_mem(hw, &mem, i40e_mem_bp, 174 I40E_HMC_PAGED_BP_SIZE, 175 I40E_HMC_PD_BP_BUF_ALIGNMENT); 176 if (ret_code) 177 goto exit; 178 179 i40e_memcpy(&pd_entry->bp.addr, &mem, 180 sizeof(struct i40e_dma_mem), I40E_NONDMA_TO_NONDMA); 181 pd_entry->bp.sd_pd_index = pd_index; 182 pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; 183 /* Set page address and valid bit */ 184 page_desc = mem.pa | 0x1; 185 186 pd_addr = (u64 *)pd_table->pd_page_addr.va; 187 pd_addr += rel_pd_idx; 188 189 /* Add the backing page physical address in the pd entry */ 190 i40e_memcpy(pd_addr, &page_desc, sizeof(u64), 191 I40E_NONDMA_TO_DMA); 192 193 pd_entry->sd_index = sd_idx; 194 pd_entry->valid = TRUE; 195 I40E_INC_PD_REFCNT(pd_table); 196 } 197 I40E_INC_BP_REFCNT(&pd_entry->bp); 198 exit: 199 return ret_code; 200 } 201 202 /** 203 * i40e_remove_pd_bp - remove a backing page from a page descriptor 204 * @hw: pointer to our HW structure 205 * @hmc_info: pointer to the HMC configuration information structure 206 * @idx: the page index 207 * @is_pf: distinguishes a VF from a PF 208 * 209 * This function: 210 * 1. Marks the entry in pd tabe (for paged address mode) or in sd table 211 * (for direct address mode) invalid. 212 * 2. Write to register PMPDINV to invalidate the backing page in FV cache 213 * 3. Decrement the ref count for the pd _entry 214 * assumptions: 215 * 1. Caller can deallocate the memory used by backing storage after this 216 * function returns. 217 **/ 218 enum i40e_status_code i40e_remove_pd_bp(struct i40e_hw *hw, 219 struct i40e_hmc_info *hmc_info, 220 u32 idx) 221 { 222 enum i40e_status_code ret_code = I40E_SUCCESS; 223 struct i40e_hmc_pd_entry *pd_entry; 224 struct i40e_hmc_pd_table *pd_table; 225 struct i40e_hmc_sd_entry *sd_entry; 226 u32 sd_idx, rel_pd_idx; 227 u64 *pd_addr; 228 229 /* calculate index */ 230 sd_idx = idx / I40E_HMC_PD_CNT_IN_SD; 231 rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD; 232 if (sd_idx >= hmc_info->sd_table.sd_cnt) { 233 ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; 234 DEBUGOUT("i40e_remove_pd_bp: bad idx\n"); 235 goto exit; 236 } 237 sd_entry = &hmc_info->sd_table.sd_entry[sd_idx]; 238 if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) { 239 ret_code = I40E_ERR_INVALID_SD_TYPE; 240 DEBUGOUT("i40e_remove_pd_bp: wrong sd_entry type\n"); 241 goto exit; 242 } 243 /* get the entry and decrease its ref counter */ 244 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; 245 pd_entry = &pd_table->pd_entry[rel_pd_idx]; 246 I40E_DEC_BP_REFCNT(&pd_entry->bp); 247 if (pd_entry->bp.ref_cnt) 248 goto exit; 249 250 /* mark the entry invalid */ 251 pd_entry->valid = FALSE; 252 I40E_DEC_PD_REFCNT(pd_table); 253 pd_addr = (u64 *)pd_table->pd_page_addr.va; 254 pd_addr += rel_pd_idx; 255 i40e_memset(pd_addr, 0, sizeof(u64), I40E_DMA_MEM); 256 I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx); 257 258 /* free memory here */ 259 ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr)); 260 if (I40E_SUCCESS != ret_code) 261 goto exit; 262 if (!pd_table->ref_cnt) 263 i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem); 264 exit: 265 return ret_code; 266 } 267 268 /** 269 * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry 270 * @hmc_info: pointer to the HMC configuration information structure 271 * @idx: the page index 272 **/ 273 enum i40e_status_code i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info, 274 u32 idx) 275 { 276 enum i40e_status_code ret_code = I40E_SUCCESS; 277 struct i40e_hmc_sd_entry *sd_entry; 278 279 /* get the entry and decrease its ref counter */ 280 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 281 I40E_DEC_BP_REFCNT(&sd_entry->u.bp); 282 if (sd_entry->u.bp.ref_cnt) { 283 ret_code = I40E_ERR_NOT_READY; 284 goto exit; 285 } 286 I40E_DEC_SD_REFCNT(&hmc_info->sd_table); 287 288 /* mark the entry invalid */ 289 sd_entry->valid = FALSE; 290 exit: 291 return ret_code; 292 } 293 294 /** 295 * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor 296 * @hw: pointer to our hw struct 297 * @hmc_info: pointer to the HMC configuration information structure 298 * @idx: the page index 299 * @is_pf: used to distinguish between VF and PF 300 **/ 301 enum i40e_status_code i40e_remove_sd_bp_new(struct i40e_hw *hw, 302 struct i40e_hmc_info *hmc_info, 303 u32 idx, bool is_pf) 304 { 305 struct i40e_hmc_sd_entry *sd_entry; 306 enum i40e_status_code ret_code = I40E_SUCCESS; 307 308 /* get the entry and decrease its ref counter */ 309 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 310 if (is_pf) { 311 I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); 312 } else { 313 ret_code = I40E_NOT_SUPPORTED; 314 goto exit; 315 } 316 ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr)); 317 if (I40E_SUCCESS != ret_code) 318 goto exit; 319 exit: 320 return ret_code; 321 } 322 323 /** 324 * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry. 325 * @hmc_info: pointer to the HMC configuration information structure 326 * @idx: segment descriptor index to find the relevant page descriptor 327 **/ 328 enum i40e_status_code i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info, 329 u32 idx) 330 { 331 enum i40e_status_code ret_code = I40E_SUCCESS; 332 struct i40e_hmc_sd_entry *sd_entry; 333 334 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 335 336 if (sd_entry->u.pd_table.ref_cnt) { 337 ret_code = I40E_ERR_NOT_READY; 338 goto exit; 339 } 340 341 /* mark the entry invalid */ 342 sd_entry->valid = FALSE; 343 344 I40E_DEC_SD_REFCNT(&hmc_info->sd_table); 345 exit: 346 return ret_code; 347 } 348 349 /** 350 * i40e_remove_pd_page_new - Removes a PD page from sd entry. 351 * @hw: pointer to our hw struct 352 * @hmc_info: pointer to the HMC configuration information structure 353 * @idx: segment descriptor index to find the relevant page descriptor 354 * @is_pf: used to distinguish between VF and PF 355 **/ 356 enum i40e_status_code i40e_remove_pd_page_new(struct i40e_hw *hw, 357 struct i40e_hmc_info *hmc_info, 358 u32 idx, bool is_pf) 359 { 360 enum i40e_status_code ret_code = I40E_SUCCESS; 361 struct i40e_hmc_sd_entry *sd_entry; 362 363 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 364 if (is_pf) { 365 I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); 366 } else { 367 ret_code = I40E_NOT_SUPPORTED; 368 goto exit; 369 } 370 /* free memory here */ 371 ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr)); 372 if (I40E_SUCCESS != ret_code) 373 goto exit; 374 exit: 375 return ret_code; 376 } 377