1 // SPDX-License-Identifier: GPL-2.0 2 /******************************************************************************* 3 * 4 * Intel Ethernet Controller XL710 Family Linux Driver 5 * Copyright(c) 2013 - 2014 Intel Corporation. 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms and conditions of the GNU General Public License, 9 * version 2, as published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program. If not, see <http://www.gnu.org/licenses/>. 18 * 19 * The full GNU General Public License is included in this distribution in 20 * the file called "COPYING". 21 * 22 * Contact Information: 23 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> 24 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 25 * 26 ******************************************************************************/ 27 28 #include "i40e_osdep.h" 29 #include "i40e_register.h" 30 #include "i40e_status.h" 31 #include "i40e_alloc.h" 32 #include "i40e_hmc.h" 33 #include "i40e_type.h" 34 35 /** 36 * i40e_add_sd_table_entry - Adds a segment descriptor to the table 37 * @hw: pointer to our hw struct 38 * @hmc_info: pointer to the HMC configuration information struct 39 * @sd_index: segment descriptor index to manipulate 40 * @type: what type of segment descriptor we're manipulating 41 * @direct_mode_sz: size to alloc in direct mode 42 **/ 43 i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, 44 struct i40e_hmc_info *hmc_info, 45 u32 sd_index, 46 enum i40e_sd_entry_type type, 47 u64 direct_mode_sz) 48 { 49 enum i40e_memory_type mem_type __attribute__((unused)); 50 struct i40e_hmc_sd_entry *sd_entry; 51 bool dma_mem_alloc_done = false; 52 struct i40e_dma_mem mem; 53 i40e_status ret_code = I40E_SUCCESS; 54 u64 alloc_len; 55 56 if (NULL == hmc_info->sd_table.sd_entry) { 57 ret_code = I40E_ERR_BAD_PTR; 58 hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_entry\n"); 59 goto exit; 60 } 61 62 if (sd_index >= hmc_info->sd_table.sd_cnt) { 63 ret_code = I40E_ERR_INVALID_SD_INDEX; 64 hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_index\n"); 65 goto exit; 66 } 67 68 sd_entry = &hmc_info->sd_table.sd_entry[sd_index]; 69 if (!sd_entry->valid) { 70 if (I40E_SD_TYPE_PAGED == type) { 71 mem_type = i40e_mem_pd; 72 alloc_len = I40E_HMC_PAGED_BP_SIZE; 73 } else { 74 mem_type = i40e_mem_bp_jumbo; 75 alloc_len = direct_mode_sz; 76 } 77 78 /* allocate a 4K pd page or 2M backing page */ 79 ret_code = i40e_allocate_dma_mem(hw, &mem, mem_type, alloc_len, 80 I40E_HMC_PD_BP_BUF_ALIGNMENT); 81 if (ret_code) 82 goto exit; 83 dma_mem_alloc_done = true; 84 if (I40E_SD_TYPE_PAGED == type) { 85 ret_code = i40e_allocate_virt_mem(hw, 86 &sd_entry->u.pd_table.pd_entry_virt_mem, 87 sizeof(struct i40e_hmc_pd_entry) * 512); 88 if (ret_code) 89 goto exit; 90 sd_entry->u.pd_table.pd_entry = 91 (struct i40e_hmc_pd_entry *) 92 sd_entry->u.pd_table.pd_entry_virt_mem.va; 93 sd_entry->u.pd_table.pd_page_addr = mem; 94 } else { 95 sd_entry->u.bp.addr = mem; 96 sd_entry->u.bp.sd_pd_index = sd_index; 97 } 98 /* initialize the sd entry */ 99 hmc_info->sd_table.sd_entry[sd_index].entry_type = type; 100 101 /* increment the ref count */ 102 I40E_INC_SD_REFCNT(&hmc_info->sd_table); 103 } 104 /* Increment backing page reference count */ 105 if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type) 106 I40E_INC_BP_REFCNT(&sd_entry->u.bp); 107 exit: 108 if (ret_code) 109 if (dma_mem_alloc_done) 110 i40e_free_dma_mem(hw, &mem); 111 112 return ret_code; 113 } 114 115 /** 116 * i40e_add_pd_table_entry - Adds page descriptor to the specified table 117 * @hw: pointer to our HW structure 118 * @hmc_info: pointer to the HMC configuration information structure 119 * @pd_index: which page descriptor index to manipulate 120 * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one. 121 * 122 * This function: 123 * 1. Initializes the pd entry 124 * 2. Adds pd_entry in the pd_table 125 * 3. Mark the entry valid in i40e_hmc_pd_entry structure 126 * 4. Initializes the pd_entry's ref count to 1 127 * assumptions: 128 * 1. The memory for pd should be pinned down, physically contiguous and 129 * aligned on 4K boundary and zeroed memory. 130 * 2. It should be 4K in size. 131 **/ 132 i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, 133 struct i40e_hmc_info *hmc_info, 134 u32 pd_index, 135 struct i40e_dma_mem *rsrc_pg) 136 { 137 i40e_status ret_code = 0; 138 struct i40e_hmc_pd_table *pd_table; 139 struct i40e_hmc_pd_entry *pd_entry; 140 struct i40e_dma_mem mem; 141 struct i40e_dma_mem *page = &mem; 142 u32 sd_idx, rel_pd_idx; 143 u64 *pd_addr; 144 u64 page_desc; 145 146 if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) { 147 ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; 148 hw_dbg(hw, "i40e_add_pd_table_entry: bad pd_index\n"); 149 goto exit; 150 } 151 152 /* find corresponding sd */ 153 sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD); 154 if (I40E_SD_TYPE_PAGED != 155 hmc_info->sd_table.sd_entry[sd_idx].entry_type) 156 goto exit; 157 158 rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD); 159 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; 160 pd_entry = &pd_table->pd_entry[rel_pd_idx]; 161 if (!pd_entry->valid) { 162 if (rsrc_pg) { 163 pd_entry->rsrc_pg = true; 164 page = rsrc_pg; 165 } else { 166 /* allocate a 4K backing page */ 167 ret_code = i40e_allocate_dma_mem(hw, page, i40e_mem_bp, 168 I40E_HMC_PAGED_BP_SIZE, 169 I40E_HMC_PD_BP_BUF_ALIGNMENT); 170 if (ret_code) 171 goto exit; 172 pd_entry->rsrc_pg = false; 173 } 174 175 pd_entry->bp.addr = *page; 176 pd_entry->bp.sd_pd_index = pd_index; 177 pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; 178 /* Set page address and valid bit */ 179 page_desc = page->pa | 0x1; 180 181 pd_addr = (u64 *)pd_table->pd_page_addr.va; 182 pd_addr += rel_pd_idx; 183 184 /* Add the backing page physical address in the pd entry */ 185 memcpy(pd_addr, &page_desc, sizeof(u64)); 186 187 pd_entry->sd_index = sd_idx; 188 pd_entry->valid = true; 189 I40E_INC_PD_REFCNT(pd_table); 190 } 191 I40E_INC_BP_REFCNT(&pd_entry->bp); 192 exit: 193 return ret_code; 194 } 195 196 /** 197 * i40e_remove_pd_bp - remove a backing page from a page descriptor 198 * @hw: pointer to our HW structure 199 * @hmc_info: pointer to the HMC configuration information structure 200 * @idx: the page index 201 * @is_pf: distinguishes a VF from a PF 202 * 203 * This function: 204 * 1. Marks the entry in pd tabe (for paged address mode) or in sd table 205 * (for direct address mode) invalid. 206 * 2. Write to register PMPDINV to invalidate the backing page in FV cache 207 * 3. Decrement the ref count for the pd _entry 208 * assumptions: 209 * 1. Caller can deallocate the memory used by backing storage after this 210 * function returns. 211 **/ 212 i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, 213 struct i40e_hmc_info *hmc_info, 214 u32 idx) 215 { 216 i40e_status ret_code = 0; 217 struct i40e_hmc_pd_entry *pd_entry; 218 struct i40e_hmc_pd_table *pd_table; 219 struct i40e_hmc_sd_entry *sd_entry; 220 u32 sd_idx, rel_pd_idx; 221 u64 *pd_addr; 222 223 /* calculate index */ 224 sd_idx = idx / I40E_HMC_PD_CNT_IN_SD; 225 rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD; 226 if (sd_idx >= hmc_info->sd_table.sd_cnt) { 227 ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX; 228 hw_dbg(hw, "i40e_remove_pd_bp: bad idx\n"); 229 goto exit; 230 } 231 sd_entry = &hmc_info->sd_table.sd_entry[sd_idx]; 232 if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) { 233 ret_code = I40E_ERR_INVALID_SD_TYPE; 234 hw_dbg(hw, "i40e_remove_pd_bp: wrong sd_entry type\n"); 235 goto exit; 236 } 237 /* get the entry and decrease its ref counter */ 238 pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; 239 pd_entry = &pd_table->pd_entry[rel_pd_idx]; 240 I40E_DEC_BP_REFCNT(&pd_entry->bp); 241 if (pd_entry->bp.ref_cnt) 242 goto exit; 243 244 /* mark the entry invalid */ 245 pd_entry->valid = false; 246 I40E_DEC_PD_REFCNT(pd_table); 247 pd_addr = (u64 *)pd_table->pd_page_addr.va; 248 pd_addr += rel_pd_idx; 249 memset(pd_addr, 0, sizeof(u64)); 250 I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx); 251 252 /* free memory here */ 253 if (!pd_entry->rsrc_pg) 254 ret_code = i40e_free_dma_mem(hw, &pd_entry->bp.addr); 255 if (ret_code) 256 goto exit; 257 if (!pd_table->ref_cnt) 258 i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem); 259 exit: 260 return ret_code; 261 } 262 263 /** 264 * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry 265 * @hmc_info: pointer to the HMC configuration information structure 266 * @idx: the page index 267 **/ 268 i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info, 269 u32 idx) 270 { 271 i40e_status ret_code = 0; 272 struct i40e_hmc_sd_entry *sd_entry; 273 274 /* get the entry and decrease its ref counter */ 275 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 276 I40E_DEC_BP_REFCNT(&sd_entry->u.bp); 277 if (sd_entry->u.bp.ref_cnt) { 278 ret_code = I40E_ERR_NOT_READY; 279 goto exit; 280 } 281 I40E_DEC_SD_REFCNT(&hmc_info->sd_table); 282 283 /* mark the entry invalid */ 284 sd_entry->valid = false; 285 exit: 286 return ret_code; 287 } 288 289 /** 290 * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor 291 * @hw: pointer to our hw struct 292 * @hmc_info: pointer to the HMC configuration information structure 293 * @idx: the page index 294 * @is_pf: used to distinguish between VF and PF 295 **/ 296 i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw, 297 struct i40e_hmc_info *hmc_info, 298 u32 idx, bool is_pf) 299 { 300 struct i40e_hmc_sd_entry *sd_entry; 301 302 if (!is_pf) 303 return I40E_NOT_SUPPORTED; 304 305 /* get the entry and decrease its ref counter */ 306 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 307 I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); 308 309 return i40e_free_dma_mem(hw, &sd_entry->u.bp.addr); 310 } 311 312 /** 313 * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry. 314 * @hmc_info: pointer to the HMC configuration information structure 315 * @idx: segment descriptor index to find the relevant page descriptor 316 **/ 317 i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info, 318 u32 idx) 319 { 320 i40e_status ret_code = 0; 321 struct i40e_hmc_sd_entry *sd_entry; 322 323 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 324 325 if (sd_entry->u.pd_table.ref_cnt) { 326 ret_code = I40E_ERR_NOT_READY; 327 goto exit; 328 } 329 330 /* mark the entry invalid */ 331 sd_entry->valid = false; 332 333 I40E_DEC_SD_REFCNT(&hmc_info->sd_table); 334 exit: 335 return ret_code; 336 } 337 338 /** 339 * i40e_remove_pd_page_new - Removes a PD page from sd entry. 340 * @hw: pointer to our hw struct 341 * @hmc_info: pointer to the HMC configuration information structure 342 * @idx: segment descriptor index to find the relevant page descriptor 343 * @is_pf: used to distinguish between VF and PF 344 **/ 345 i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw, 346 struct i40e_hmc_info *hmc_info, 347 u32 idx, bool is_pf) 348 { 349 struct i40e_hmc_sd_entry *sd_entry; 350 351 if (!is_pf) 352 return I40E_NOT_SUPPORTED; 353 354 sd_entry = &hmc_info->sd_table.sd_entry[idx]; 355 I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); 356 357 return i40e_free_dma_mem(hw, &sd_entry->u.pd_table.pd_page_addr); 358 } 359