162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "i40e.h" 562306a36Sopenharmony_ci#include "i40e_osdep.h" 662306a36Sopenharmony_ci#include "i40e_register.h" 762306a36Sopenharmony_ci#include "i40e_alloc.h" 862306a36Sopenharmony_ci#include "i40e_hmc.h" 962306a36Sopenharmony_ci#include "i40e_type.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/** 1262306a36Sopenharmony_ci * i40e_add_sd_table_entry - Adds a segment descriptor to the table 1362306a36Sopenharmony_ci * @hw: pointer to our hw struct 1462306a36Sopenharmony_ci * @hmc_info: pointer to the HMC configuration information struct 1562306a36Sopenharmony_ci * @sd_index: segment descriptor index to manipulate 1662306a36Sopenharmony_ci * @type: what type of segment descriptor we're manipulating 1762306a36Sopenharmony_ci * @direct_mode_sz: size to alloc in direct mode 1862306a36Sopenharmony_ci **/ 1962306a36Sopenharmony_ciint i40e_add_sd_table_entry(struct i40e_hw *hw, 2062306a36Sopenharmony_ci struct i40e_hmc_info *hmc_info, 2162306a36Sopenharmony_ci u32 sd_index, 2262306a36Sopenharmony_ci enum i40e_sd_entry_type type, 2362306a36Sopenharmony_ci u64 direct_mode_sz) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci enum i40e_memory_type mem_type __attribute__((unused)); 2662306a36Sopenharmony_ci struct i40e_hmc_sd_entry *sd_entry; 2762306a36Sopenharmony_ci bool dma_mem_alloc_done = false; 2862306a36Sopenharmony_ci struct i40e_dma_mem mem; 2962306a36Sopenharmony_ci int ret_code = 0; 3062306a36Sopenharmony_ci u64 alloc_len; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (NULL == hmc_info->sd_table.sd_entry) { 3362306a36Sopenharmony_ci ret_code = -EINVAL; 3462306a36Sopenharmony_ci hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_entry\n"); 3562306a36Sopenharmony_ci goto exit; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (sd_index >= hmc_info->sd_table.sd_cnt) { 3962306a36Sopenharmony_ci ret_code = -EINVAL; 4062306a36Sopenharmony_ci hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_index\n"); 4162306a36Sopenharmony_ci goto exit; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci sd_entry = &hmc_info->sd_table.sd_entry[sd_index]; 4562306a36Sopenharmony_ci if (!sd_entry->valid) { 4662306a36Sopenharmony_ci if (I40E_SD_TYPE_PAGED == type) { 4762306a36Sopenharmony_ci mem_type = i40e_mem_pd; 4862306a36Sopenharmony_ci alloc_len = I40E_HMC_PAGED_BP_SIZE; 4962306a36Sopenharmony_ci } else { 5062306a36Sopenharmony_ci mem_type = i40e_mem_bp_jumbo; 5162306a36Sopenharmony_ci alloc_len = direct_mode_sz; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* allocate a 4K pd page or 2M backing page */ 5562306a36Sopenharmony_ci ret_code = i40e_allocate_dma_mem(hw, &mem, mem_type, alloc_len, 5662306a36Sopenharmony_ci I40E_HMC_PD_BP_BUF_ALIGNMENT); 5762306a36Sopenharmony_ci if (ret_code) 5862306a36Sopenharmony_ci goto exit; 5962306a36Sopenharmony_ci dma_mem_alloc_done = true; 6062306a36Sopenharmony_ci if (I40E_SD_TYPE_PAGED == type) { 6162306a36Sopenharmony_ci ret_code = i40e_allocate_virt_mem(hw, 6262306a36Sopenharmony_ci &sd_entry->u.pd_table.pd_entry_virt_mem, 6362306a36Sopenharmony_ci sizeof(struct i40e_hmc_pd_entry) * 512); 6462306a36Sopenharmony_ci if (ret_code) 6562306a36Sopenharmony_ci goto exit; 6662306a36Sopenharmony_ci sd_entry->u.pd_table.pd_entry = 6762306a36Sopenharmony_ci (struct i40e_hmc_pd_entry *) 6862306a36Sopenharmony_ci sd_entry->u.pd_table.pd_entry_virt_mem.va; 6962306a36Sopenharmony_ci sd_entry->u.pd_table.pd_page_addr = mem; 7062306a36Sopenharmony_ci } else { 7162306a36Sopenharmony_ci sd_entry->u.bp.addr = mem; 7262306a36Sopenharmony_ci sd_entry->u.bp.sd_pd_index = sd_index; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci /* initialize the sd entry */ 7562306a36Sopenharmony_ci hmc_info->sd_table.sd_entry[sd_index].entry_type = type; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* increment the ref count */ 7862306a36Sopenharmony_ci I40E_INC_SD_REFCNT(&hmc_info->sd_table); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci /* Increment backing page reference count */ 8162306a36Sopenharmony_ci if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type) 8262306a36Sopenharmony_ci I40E_INC_BP_REFCNT(&sd_entry->u.bp); 8362306a36Sopenharmony_ciexit: 8462306a36Sopenharmony_ci if (ret_code) 8562306a36Sopenharmony_ci if (dma_mem_alloc_done) 8662306a36Sopenharmony_ci i40e_free_dma_mem(hw, &mem); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return ret_code; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/** 9262306a36Sopenharmony_ci * i40e_add_pd_table_entry - Adds page descriptor to the specified table 9362306a36Sopenharmony_ci * @hw: pointer to our HW structure 9462306a36Sopenharmony_ci * @hmc_info: pointer to the HMC configuration information structure 9562306a36Sopenharmony_ci * @pd_index: which page descriptor index to manipulate 9662306a36Sopenharmony_ci * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one. 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * This function: 9962306a36Sopenharmony_ci * 1. Initializes the pd entry 10062306a36Sopenharmony_ci * 2. Adds pd_entry in the pd_table 10162306a36Sopenharmony_ci * 3. Mark the entry valid in i40e_hmc_pd_entry structure 10262306a36Sopenharmony_ci * 4. Initializes the pd_entry's ref count to 1 10362306a36Sopenharmony_ci * assumptions: 10462306a36Sopenharmony_ci * 1. The memory for pd should be pinned down, physically contiguous and 10562306a36Sopenharmony_ci * aligned on 4K boundary and zeroed memory. 10662306a36Sopenharmony_ci * 2. It should be 4K in size. 10762306a36Sopenharmony_ci **/ 10862306a36Sopenharmony_ciint i40e_add_pd_table_entry(struct i40e_hw *hw, 10962306a36Sopenharmony_ci struct i40e_hmc_info *hmc_info, 11062306a36Sopenharmony_ci u32 pd_index, 11162306a36Sopenharmony_ci struct i40e_dma_mem *rsrc_pg) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct i40e_hmc_pd_table *pd_table; 11462306a36Sopenharmony_ci struct i40e_hmc_pd_entry *pd_entry; 11562306a36Sopenharmony_ci struct i40e_dma_mem mem; 11662306a36Sopenharmony_ci struct i40e_dma_mem *page = &mem; 11762306a36Sopenharmony_ci u32 sd_idx, rel_pd_idx; 11862306a36Sopenharmony_ci int ret_code = 0; 11962306a36Sopenharmony_ci u64 page_desc; 12062306a36Sopenharmony_ci u64 *pd_addr; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) { 12362306a36Sopenharmony_ci ret_code = -EINVAL; 12462306a36Sopenharmony_ci hw_dbg(hw, "i40e_add_pd_table_entry: bad pd_index\n"); 12562306a36Sopenharmony_ci goto exit; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* find corresponding sd */ 12962306a36Sopenharmony_ci sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD); 13062306a36Sopenharmony_ci if (I40E_SD_TYPE_PAGED != 13162306a36Sopenharmony_ci hmc_info->sd_table.sd_entry[sd_idx].entry_type) 13262306a36Sopenharmony_ci goto exit; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD); 13562306a36Sopenharmony_ci pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; 13662306a36Sopenharmony_ci pd_entry = &pd_table->pd_entry[rel_pd_idx]; 13762306a36Sopenharmony_ci if (!pd_entry->valid) { 13862306a36Sopenharmony_ci if (rsrc_pg) { 13962306a36Sopenharmony_ci pd_entry->rsrc_pg = true; 14062306a36Sopenharmony_ci page = rsrc_pg; 14162306a36Sopenharmony_ci } else { 14262306a36Sopenharmony_ci /* allocate a 4K backing page */ 14362306a36Sopenharmony_ci ret_code = i40e_allocate_dma_mem(hw, page, i40e_mem_bp, 14462306a36Sopenharmony_ci I40E_HMC_PAGED_BP_SIZE, 14562306a36Sopenharmony_ci I40E_HMC_PD_BP_BUF_ALIGNMENT); 14662306a36Sopenharmony_ci if (ret_code) 14762306a36Sopenharmony_ci goto exit; 14862306a36Sopenharmony_ci pd_entry->rsrc_pg = false; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci pd_entry->bp.addr = *page; 15262306a36Sopenharmony_ci pd_entry->bp.sd_pd_index = pd_index; 15362306a36Sopenharmony_ci pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; 15462306a36Sopenharmony_ci /* Set page address and valid bit */ 15562306a36Sopenharmony_ci page_desc = page->pa | 0x1; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci pd_addr = (u64 *)pd_table->pd_page_addr.va; 15862306a36Sopenharmony_ci pd_addr += rel_pd_idx; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Add the backing page physical address in the pd entry */ 16162306a36Sopenharmony_ci memcpy(pd_addr, &page_desc, sizeof(u64)); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci pd_entry->sd_index = sd_idx; 16462306a36Sopenharmony_ci pd_entry->valid = true; 16562306a36Sopenharmony_ci I40E_INC_PD_REFCNT(pd_table); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci I40E_INC_BP_REFCNT(&pd_entry->bp); 16862306a36Sopenharmony_ciexit: 16962306a36Sopenharmony_ci return ret_code; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/** 17362306a36Sopenharmony_ci * i40e_remove_pd_bp - remove a backing page from a page descriptor 17462306a36Sopenharmony_ci * @hw: pointer to our HW structure 17562306a36Sopenharmony_ci * @hmc_info: pointer to the HMC configuration information structure 17662306a36Sopenharmony_ci * @idx: the page index 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * This function: 17962306a36Sopenharmony_ci * 1. Marks the entry in pd tabe (for paged address mode) or in sd table 18062306a36Sopenharmony_ci * (for direct address mode) invalid. 18162306a36Sopenharmony_ci * 2. Write to register PMPDINV to invalidate the backing page in FV cache 18262306a36Sopenharmony_ci * 3. Decrement the ref count for the pd _entry 18362306a36Sopenharmony_ci * assumptions: 18462306a36Sopenharmony_ci * 1. Caller can deallocate the memory used by backing storage after this 18562306a36Sopenharmony_ci * function returns. 18662306a36Sopenharmony_ci **/ 18762306a36Sopenharmony_ciint i40e_remove_pd_bp(struct i40e_hw *hw, 18862306a36Sopenharmony_ci struct i40e_hmc_info *hmc_info, 18962306a36Sopenharmony_ci u32 idx) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct i40e_hmc_pd_entry *pd_entry; 19262306a36Sopenharmony_ci struct i40e_hmc_pd_table *pd_table; 19362306a36Sopenharmony_ci struct i40e_hmc_sd_entry *sd_entry; 19462306a36Sopenharmony_ci u32 sd_idx, rel_pd_idx; 19562306a36Sopenharmony_ci int ret_code = 0; 19662306a36Sopenharmony_ci u64 *pd_addr; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* calculate index */ 19962306a36Sopenharmony_ci sd_idx = idx / I40E_HMC_PD_CNT_IN_SD; 20062306a36Sopenharmony_ci rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD; 20162306a36Sopenharmony_ci if (sd_idx >= hmc_info->sd_table.sd_cnt) { 20262306a36Sopenharmony_ci ret_code = -EINVAL; 20362306a36Sopenharmony_ci hw_dbg(hw, "i40e_remove_pd_bp: bad idx\n"); 20462306a36Sopenharmony_ci goto exit; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci sd_entry = &hmc_info->sd_table.sd_entry[sd_idx]; 20762306a36Sopenharmony_ci if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) { 20862306a36Sopenharmony_ci ret_code = -EINVAL; 20962306a36Sopenharmony_ci hw_dbg(hw, "i40e_remove_pd_bp: wrong sd_entry type\n"); 21062306a36Sopenharmony_ci goto exit; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci /* get the entry and decrease its ref counter */ 21362306a36Sopenharmony_ci pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; 21462306a36Sopenharmony_ci pd_entry = &pd_table->pd_entry[rel_pd_idx]; 21562306a36Sopenharmony_ci I40E_DEC_BP_REFCNT(&pd_entry->bp); 21662306a36Sopenharmony_ci if (pd_entry->bp.ref_cnt) 21762306a36Sopenharmony_ci goto exit; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* mark the entry invalid */ 22062306a36Sopenharmony_ci pd_entry->valid = false; 22162306a36Sopenharmony_ci I40E_DEC_PD_REFCNT(pd_table); 22262306a36Sopenharmony_ci pd_addr = (u64 *)pd_table->pd_page_addr.va; 22362306a36Sopenharmony_ci pd_addr += rel_pd_idx; 22462306a36Sopenharmony_ci memset(pd_addr, 0, sizeof(u64)); 22562306a36Sopenharmony_ci I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* free memory here */ 22862306a36Sopenharmony_ci if (!pd_entry->rsrc_pg) 22962306a36Sopenharmony_ci ret_code = i40e_free_dma_mem(hw, &pd_entry->bp.addr); 23062306a36Sopenharmony_ci if (ret_code) 23162306a36Sopenharmony_ci goto exit; 23262306a36Sopenharmony_ci if (!pd_table->ref_cnt) 23362306a36Sopenharmony_ci i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem); 23462306a36Sopenharmony_ciexit: 23562306a36Sopenharmony_ci return ret_code; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/** 23962306a36Sopenharmony_ci * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry 24062306a36Sopenharmony_ci * @hmc_info: pointer to the HMC configuration information structure 24162306a36Sopenharmony_ci * @idx: the page index 24262306a36Sopenharmony_ci **/ 24362306a36Sopenharmony_ciint i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info, 24462306a36Sopenharmony_ci u32 idx) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct i40e_hmc_sd_entry *sd_entry; 24762306a36Sopenharmony_ci int ret_code = 0; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* get the entry and decrease its ref counter */ 25062306a36Sopenharmony_ci sd_entry = &hmc_info->sd_table.sd_entry[idx]; 25162306a36Sopenharmony_ci I40E_DEC_BP_REFCNT(&sd_entry->u.bp); 25262306a36Sopenharmony_ci if (sd_entry->u.bp.ref_cnt) { 25362306a36Sopenharmony_ci ret_code = -EBUSY; 25462306a36Sopenharmony_ci goto exit; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci I40E_DEC_SD_REFCNT(&hmc_info->sd_table); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* mark the entry invalid */ 25962306a36Sopenharmony_ci sd_entry->valid = false; 26062306a36Sopenharmony_ciexit: 26162306a36Sopenharmony_ci return ret_code; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/** 26562306a36Sopenharmony_ci * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor 26662306a36Sopenharmony_ci * @hw: pointer to our hw struct 26762306a36Sopenharmony_ci * @hmc_info: pointer to the HMC configuration information structure 26862306a36Sopenharmony_ci * @idx: the page index 26962306a36Sopenharmony_ci * @is_pf: used to distinguish between VF and PF 27062306a36Sopenharmony_ci **/ 27162306a36Sopenharmony_ciint i40e_remove_sd_bp_new(struct i40e_hw *hw, 27262306a36Sopenharmony_ci struct i40e_hmc_info *hmc_info, 27362306a36Sopenharmony_ci u32 idx, bool is_pf) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct i40e_hmc_sd_entry *sd_entry; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (!is_pf) 27862306a36Sopenharmony_ci return -EOPNOTSUPP; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* get the entry and decrease its ref counter */ 28162306a36Sopenharmony_ci sd_entry = &hmc_info->sd_table.sd_entry[idx]; 28262306a36Sopenharmony_ci I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return i40e_free_dma_mem(hw, &sd_entry->u.bp.addr); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/** 28862306a36Sopenharmony_ci * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry. 28962306a36Sopenharmony_ci * @hmc_info: pointer to the HMC configuration information structure 29062306a36Sopenharmony_ci * @idx: segment descriptor index to find the relevant page descriptor 29162306a36Sopenharmony_ci **/ 29262306a36Sopenharmony_ciint i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info, 29362306a36Sopenharmony_ci u32 idx) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct i40e_hmc_sd_entry *sd_entry; 29662306a36Sopenharmony_ci int ret_code = 0; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci sd_entry = &hmc_info->sd_table.sd_entry[idx]; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (sd_entry->u.pd_table.ref_cnt) { 30162306a36Sopenharmony_ci ret_code = -EBUSY; 30262306a36Sopenharmony_ci goto exit; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* mark the entry invalid */ 30662306a36Sopenharmony_ci sd_entry->valid = false; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci I40E_DEC_SD_REFCNT(&hmc_info->sd_table); 30962306a36Sopenharmony_ciexit: 31062306a36Sopenharmony_ci return ret_code; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/** 31462306a36Sopenharmony_ci * i40e_remove_pd_page_new - Removes a PD page from sd entry. 31562306a36Sopenharmony_ci * @hw: pointer to our hw struct 31662306a36Sopenharmony_ci * @hmc_info: pointer to the HMC configuration information structure 31762306a36Sopenharmony_ci * @idx: segment descriptor index to find the relevant page descriptor 31862306a36Sopenharmony_ci * @is_pf: used to distinguish between VF and PF 31962306a36Sopenharmony_ci **/ 32062306a36Sopenharmony_ciint i40e_remove_pd_page_new(struct i40e_hw *hw, 32162306a36Sopenharmony_ci struct i40e_hmc_info *hmc_info, 32262306a36Sopenharmony_ci u32 idx, bool is_pf) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct i40e_hmc_sd_entry *sd_entry; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!is_pf) 32762306a36Sopenharmony_ci return -EOPNOTSUPP; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci sd_entry = &hmc_info->sd_table.sd_entry[idx]; 33062306a36Sopenharmony_ci I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci return i40e_free_dma_mem(hw, &sd_entry->u.pd_table.pd_page_addr); 33362306a36Sopenharmony_ci} 334