/*- * SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB * * Copyright (c) 2015 - 2021 Intel Corporation * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenFabrics.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /*$FreeBSD$*/ #include "osdep.h" #include "irdma_hmc.h" #include "irdma_defs.h" #include "irdma_type.h" #include "irdma_protos.h" /** * irdma_find_sd_index_limit - finds segment descriptor index limit * @hmc_info: pointer to the HMC configuration information structure * @type: type of HMC resources we're searching * @idx: starting index for the object * @cnt: number of objects we're trying to create * @sd_idx: pointer to return index of the segment descriptor in question * @sd_limit: pointer to return the maximum number of segment descriptors * * This function calculates the segment descriptor index and index limit * for the resource defined by irdma_hmc_rsrc_type. */ static void irdma_find_sd_index_limit(struct irdma_hmc_info *hmc_info, u32 type, u32 idx, u32 cnt, u32 *sd_idx, u32 *sd_limit) { u64 fpm_addr, fpm_limit; fpm_addr = hmc_info->hmc_obj[(type)].base + hmc_info->hmc_obj[type].size * idx; fpm_limit = fpm_addr + hmc_info->hmc_obj[type].size * cnt; *sd_idx = (u32)(fpm_addr / IRDMA_HMC_DIRECT_BP_SIZE); *sd_limit = (u32)((fpm_limit - 1) / IRDMA_HMC_DIRECT_BP_SIZE); *sd_limit += 1; } /** * irdma_find_pd_index_limit - finds page descriptor index limit * @hmc_info: pointer to the HMC configuration information struct * @type: HMC resource type we're examining * @idx: starting index for the object * @cnt: number of objects we're trying to create * @pd_idx: pointer to return page descriptor index * @pd_limit: pointer to return page descriptor index limit * * Calculates the page descriptor index and index limit for the resource * defined by irdma_hmc_rsrc_type. */ static void irdma_find_pd_index_limit(struct irdma_hmc_info *hmc_info, u32 type, u32 idx, u32 cnt, u32 *pd_idx, u32 *pd_limit) { u64 fpm_adr, fpm_limit; fpm_adr = hmc_info->hmc_obj[type].base + hmc_info->hmc_obj[type].size * idx; fpm_limit = fpm_adr + (hmc_info)->hmc_obj[(type)].size * (cnt); *pd_idx = (u32)(fpm_adr / IRDMA_HMC_PAGED_BP_SIZE); *pd_limit = (u32)((fpm_limit - 1) / IRDMA_HMC_PAGED_BP_SIZE); *pd_limit += 1; } /** * irdma_set_sd_entry - setup entry for sd programming * @pa: physical addr * @idx: sd index * @type: paged or direct sd * @entry: sd entry ptr */ static void irdma_set_sd_entry(u64 pa, u32 idx, enum irdma_sd_entry_type type, struct irdma_update_sd_entry *entry) { entry->data = pa | (IRDMA_HMC_MAX_BP_COUNT << IRDMA_PFHMC_SDDATALOW_PMSDBPCOUNT_S) | (((type == IRDMA_SD_TYPE_PAGED) ? 0 : 1) << IRDMA_PFHMC_SDDATALOW_PMSDTYPE_S) | (1 << IRDMA_PFHMC_SDDATALOW_PMSDVALID_S); entry->cmd = (idx | (1 << IRDMA_PFHMC_SDCMD_PMSDWR_S) | (1 << 15)); } /** * irdma_clr_sd_entry - setup entry for sd clear * @idx: sd index * @type: paged or direct sd * @entry: sd entry ptr */ static void irdma_clr_sd_entry(u32 idx, enum irdma_sd_entry_type type, struct irdma_update_sd_entry *entry) { entry->data = (IRDMA_HMC_MAX_BP_COUNT << IRDMA_PFHMC_SDDATALOW_PMSDBPCOUNT_S) | (((type == IRDMA_SD_TYPE_PAGED) ? 0 : 1) << IRDMA_PFHMC_SDDATALOW_PMSDTYPE_S); entry->cmd = (idx | (1 << IRDMA_PFHMC_SDCMD_PMSDWR_S) | (1 << 15)); } /** * irdma_invalidate_pf_hmc_pd - Invalidates the pd cache in the hardware for PF * @dev: pointer to our device struct * @sd_idx: segment descriptor index * @pd_idx: page descriptor index */ static inline void irdma_invalidate_pf_hmc_pd(struct irdma_sc_dev *dev, u32 sd_idx, u32 pd_idx) { u32 val = LS_32(sd_idx, IRDMA_PFHMC_PDINV_PMSDIDX) | LS_32(1, IRDMA_PFHMC_PDINV_PMSDPARTSEL) | LS_32(pd_idx, IRDMA_PFHMC_PDINV_PMPDIDX); writel(val, dev->hw_regs[IRDMA_PFHMC_PDINV]); } /** * irdma_hmc_sd_one - setup 1 sd entry for cqp * @dev: pointer to the device structure * @hmc_fn_id: hmc's function id * @pa: physical addr * @sd_idx: sd index * @type: paged or direct sd * @setsd: flag to set or clear sd */ int irdma_hmc_sd_one(struct irdma_sc_dev *dev, u8 hmc_fn_id, u64 pa, u32 sd_idx, enum irdma_sd_entry_type type, bool setsd) { struct irdma_update_sds_info sdinfo; sdinfo.cnt = 1; sdinfo.hmc_fn_id = hmc_fn_id; if (setsd) irdma_set_sd_entry(pa, sd_idx, type, sdinfo.entry); else irdma_clr_sd_entry(sd_idx, type, sdinfo.entry); return dev->cqp->process_cqp_sds(dev, &sdinfo); } /** * irdma_hmc_sd_grp - setup group of sd entries for cqp * @dev: pointer to the device structure * @hmc_info: pointer to the HMC configuration information struct * @sd_index: sd index * @sd_cnt: number of sd entries * @setsd: flag to set or clear sd */ static int irdma_hmc_sd_grp(struct irdma_sc_dev *dev, struct irdma_hmc_info *hmc_info, u32 sd_index, u32 sd_cnt, bool setsd) { struct irdma_hmc_sd_entry *sd_entry; struct irdma_update_sds_info sdinfo = {0}; u64 pa; u32 i; int ret_code = 0; sdinfo.hmc_fn_id = hmc_info->hmc_fn_id; for (i = sd_index; i < sd_index + sd_cnt; i++) { sd_entry = &hmc_info->sd_table.sd_entry[i]; if (!sd_entry || (!sd_entry->valid && setsd) || (sd_entry->valid && !setsd)) continue; if (setsd) { pa = (sd_entry->entry_type == IRDMA_SD_TYPE_PAGED) ? sd_entry->u.pd_table.pd_page_addr.pa : sd_entry->u.bp.addr.pa; irdma_set_sd_entry(pa, i, sd_entry->entry_type, &sdinfo.entry[sdinfo.cnt]); } else { irdma_clr_sd_entry(i, sd_entry->entry_type, &sdinfo.entry[sdinfo.cnt]); } sdinfo.cnt++; if (sdinfo.cnt == IRDMA_MAX_SD_ENTRIES) { ret_code = dev->cqp->process_cqp_sds(dev, &sdinfo); if (ret_code) { irdma_debug(dev, IRDMA_DEBUG_HMC, "sd_programming failed err=%d\n", ret_code); return ret_code; } sdinfo.cnt = 0; } } if (sdinfo.cnt) ret_code = dev->cqp->process_cqp_sds(dev, &sdinfo); return ret_code; } /** * irdma_hmc_finish_add_sd_reg - program sd entries for objects * @dev: pointer to the device structure * @info: create obj info */ static int irdma_hmc_finish_add_sd_reg(struct irdma_sc_dev *dev, struct irdma_hmc_create_obj_info *info) { if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) return -EINVAL; if ((info->start_idx + info->count) > info->hmc_info->hmc_obj[info->rsrc_type].cnt) return -EINVAL; if (!info->add_sd_cnt) return 0; return irdma_hmc_sd_grp(dev, info->hmc_info, info->hmc_info->sd_indexes[0], info->add_sd_cnt, true); } /** * irdma_sc_create_hmc_obj - allocate backing store for hmc objects * @dev: pointer to the device structure * @info: pointer to irdma_hmc_create_obj_info struct * * This will allocate memory for PDs and backing pages and populate * the sd and pd entries. */ int irdma_sc_create_hmc_obj(struct irdma_sc_dev *dev, struct irdma_hmc_create_obj_info *info) { struct irdma_hmc_sd_entry *sd_entry; u32 sd_idx, sd_lmt; u32 pd_idx = 0, pd_lmt = 0; u32 pd_idx1 = 0, pd_lmt1 = 0; u32 i, j; bool pd_error = false; int ret_code = 0; if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) return -EINVAL; if ((info->start_idx + info->count) > info->hmc_info->hmc_obj[info->rsrc_type].cnt) { irdma_debug(dev, IRDMA_DEBUG_HMC, "error type %u, start = %u, req cnt %u, cnt = %u\n", info->rsrc_type, info->start_idx, info->count, info->hmc_info->hmc_obj[info->rsrc_type].cnt); return -EINVAL; } irdma_find_sd_index_limit(info->hmc_info, info->rsrc_type, info->start_idx, info->count, &sd_idx, &sd_lmt); if (sd_idx >= info->hmc_info->sd_table.sd_cnt || sd_lmt > info->hmc_info->sd_table.sd_cnt) { return -EINVAL; } irdma_find_pd_index_limit(info->hmc_info, info->rsrc_type, info->start_idx, info->count, &pd_idx, &pd_lmt); for (j = sd_idx; j < sd_lmt; j++) { ret_code = irdma_add_sd_table_entry(dev->hw, info->hmc_info, j, info->entry_type, IRDMA_HMC_DIRECT_BP_SIZE); if (ret_code) goto exit_sd_error; sd_entry = &info->hmc_info->sd_table.sd_entry[j]; if (sd_entry->entry_type == IRDMA_SD_TYPE_PAGED && (dev->hmc_info == info->hmc_info && info->rsrc_type != IRDMA_HMC_IW_PBLE)) { pd_idx1 = max(pd_idx, (j * IRDMA_HMC_MAX_BP_COUNT)); pd_lmt1 = min(pd_lmt, (j + 1) * IRDMA_HMC_MAX_BP_COUNT); for (i = pd_idx1; i < pd_lmt1; i++) { /* update the pd table entry */ ret_code = irdma_add_pd_table_entry(dev, info->hmc_info, i, NULL); if (ret_code) { pd_error = true; break; } } if (pd_error) { while (i && (i > pd_idx1)) { irdma_remove_pd_bp(dev, info->hmc_info, i - 1); i--; } } } if (sd_entry->valid) continue; info->hmc_info->sd_indexes[info->add_sd_cnt] = (u16)j; info->add_sd_cnt++; sd_entry->valid = true; } return irdma_hmc_finish_add_sd_reg(dev, info); exit_sd_error: while (j && (j > sd_idx)) { sd_entry = &info->hmc_info->sd_table.sd_entry[j - 1]; switch (sd_entry->entry_type) { case IRDMA_SD_TYPE_PAGED: pd_idx1 = max(pd_idx, (j - 1) * IRDMA_HMC_MAX_BP_COUNT); pd_lmt1 = min(pd_lmt, (j * IRDMA_HMC_MAX_BP_COUNT)); for (i = pd_idx1; i < pd_lmt1; i++) irdma_prep_remove_pd_page(info->hmc_info, i); break; case IRDMA_SD_TYPE_DIRECT: irdma_prep_remove_pd_page(info->hmc_info, (j - 1)); break; default: ret_code = -EINVAL; break; } j--; } return ret_code; } /** * irdma_finish_del_sd_reg - delete sd entries for objects * @dev: pointer to the device structure * @info: dele obj info * @reset: true if called before reset */ static int irdma_finish_del_sd_reg(struct irdma_sc_dev *dev, struct irdma_hmc_del_obj_info *info, bool reset) { struct irdma_hmc_sd_entry *sd_entry; int ret_code = 0; struct irdma_dma_mem *mem; u32 i, sd_idx; if (!reset) ret_code = irdma_hmc_sd_grp(dev, info->hmc_info, info->hmc_info->sd_indexes[0], info->del_sd_cnt, false); if (ret_code) irdma_debug(dev, IRDMA_DEBUG_HMC, "error cqp sd sd_grp\n"); for (i = 0; i < info->del_sd_cnt; i++) { sd_idx = info->hmc_info->sd_indexes[i]; sd_entry = &info->hmc_info->sd_table.sd_entry[sd_idx]; mem = (sd_entry->entry_type == IRDMA_SD_TYPE_PAGED) ? &sd_entry->u.pd_table.pd_page_addr : &sd_entry->u.bp.addr; if (!mem || !mem->va) irdma_debug(dev, IRDMA_DEBUG_HMC, "error cqp sd mem\n"); else irdma_free_dma_mem(dev->hw, mem); } return ret_code; } /** * irdma_sc_del_hmc_obj - remove pe hmc objects * @dev: pointer to the device structure * @info: pointer to irdma_hmc_del_obj_info struct * @reset: true if called before reset * * This will de-populate the SDs and PDs. It frees * the memory for PDS and backing storage. After this function is returned, * caller should deallocate memory allocated previously for * book-keeping information about PDs and backing storage. */ int irdma_sc_del_hmc_obj(struct irdma_sc_dev *dev, struct irdma_hmc_del_obj_info *info, bool reset) { struct irdma_hmc_pd_table *pd_table; u32 sd_idx, sd_lmt; u32 pd_idx, pd_lmt, rel_pd_idx; u32 i, j; int ret_code = 0; if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) { irdma_debug(dev, IRDMA_DEBUG_HMC, "error start_idx[%04d] >= [type %04d].cnt[%04d]\n", info->start_idx, info->rsrc_type, info->hmc_info->hmc_obj[info->rsrc_type].cnt); return -EINVAL; } if ((info->start_idx + info->count) > info->hmc_info->hmc_obj[info->rsrc_type].cnt) { irdma_debug(dev, IRDMA_DEBUG_HMC, "error start_idx[%04d] + count %04d >= [type %04d].cnt[%04d]\n", info->start_idx, info->count, info->rsrc_type, info->hmc_info->hmc_obj[info->rsrc_type].cnt); return -EINVAL; } irdma_find_pd_index_limit(info->hmc_info, info->rsrc_type, info->start_idx, info->count, &pd_idx, &pd_lmt); for (j = pd_idx; j < pd_lmt; j++) { sd_idx = j / IRDMA_HMC_PD_CNT_IN_SD; if (!info->hmc_info->sd_table.sd_entry[sd_idx].valid) continue; if (info->hmc_info->sd_table.sd_entry[sd_idx].entry_type != IRDMA_SD_TYPE_PAGED) continue; rel_pd_idx = j % IRDMA_HMC_PD_CNT_IN_SD; pd_table = &info->hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; if (pd_table->pd_entry && pd_table->pd_entry[rel_pd_idx].valid) { ret_code = irdma_remove_pd_bp(dev, info->hmc_info, j); if (ret_code) { irdma_debug(dev, IRDMA_DEBUG_HMC, "remove_pd_bp error\n"); return ret_code; } } } irdma_find_sd_index_limit(info->hmc_info, info->rsrc_type, info->start_idx, info->count, &sd_idx, &sd_lmt); if (sd_idx >= info->hmc_info->sd_table.sd_cnt || sd_lmt > info->hmc_info->sd_table.sd_cnt) { irdma_debug(dev, IRDMA_DEBUG_HMC, "invalid sd_idx\n"); return -EINVAL; } for (i = sd_idx; i < sd_lmt; i++) { pd_table = &info->hmc_info->sd_table.sd_entry[i].u.pd_table; if (!info->hmc_info->sd_table.sd_entry[i].valid) continue; switch (info->hmc_info->sd_table.sd_entry[i].entry_type) { case IRDMA_SD_TYPE_DIRECT: ret_code = irdma_prep_remove_sd_bp(info->hmc_info, i); if (!ret_code) { info->hmc_info->sd_indexes[info->del_sd_cnt] = (u16)i; info->del_sd_cnt++; } break; case IRDMA_SD_TYPE_PAGED: ret_code = irdma_prep_remove_pd_page(info->hmc_info, i); if (ret_code) break; if (dev->hmc_info != info->hmc_info && info->rsrc_type == IRDMA_HMC_IW_PBLE && pd_table->pd_entry) { kfree(pd_table->pd_entry_virt_mem.va); pd_table->pd_entry = NULL; } info->hmc_info->sd_indexes[info->del_sd_cnt] = (u16)i; info->del_sd_cnt++; break; default: break; } } return irdma_finish_del_sd_reg(dev, info, reset); } /** * irdma_add_sd_table_entry - Adds a segment descriptor to the table * @hw: pointer to our hw struct * @hmc_info: pointer to the HMC configuration information struct * @sd_index: segment descriptor index to manipulate * @type: what type of segment descriptor we're manipulating * @direct_mode_sz: size to alloc in direct mode */ int irdma_add_sd_table_entry(struct irdma_hw *hw, struct irdma_hmc_info *hmc_info, u32 sd_index, enum irdma_sd_entry_type type, u64 direct_mode_sz) { struct irdma_hmc_sd_entry *sd_entry; struct irdma_dma_mem dma_mem; u64 alloc_len; sd_entry = &hmc_info->sd_table.sd_entry[sd_index]; if (!sd_entry->valid) { if (type == IRDMA_SD_TYPE_PAGED) alloc_len = IRDMA_HMC_PAGED_BP_SIZE; else alloc_len = direct_mode_sz; /* allocate a 4K pd page or 2M backing page */ dma_mem.size = alloc_len; dma_mem.va = irdma_allocate_dma_mem(hw, &dma_mem, dma_mem.size, IRDMA_HMC_PD_BP_BUF_ALIGNMENT); if (!dma_mem.va) return -ENOMEM; if (type == IRDMA_SD_TYPE_PAGED) { struct irdma_virt_mem *vmem = &sd_entry->u.pd_table.pd_entry_virt_mem; vmem->size = sizeof(struct irdma_hmc_pd_entry) * 512; vmem->va = kzalloc(vmem->size, GFP_ATOMIC); if (!vmem->va) { irdma_free_dma_mem(hw, &dma_mem); return -ENOMEM; } sd_entry->u.pd_table.pd_entry = vmem->va; irdma_memcpy(&sd_entry->u.pd_table.pd_page_addr, &dma_mem, sizeof(sd_entry->u.pd_table.pd_page_addr)); } else { irdma_memcpy(&sd_entry->u.bp.addr, &dma_mem, sizeof(sd_entry->u.bp.addr)); sd_entry->u.bp.sd_pd_index = sd_index; } hmc_info->sd_table.sd_entry[sd_index].entry_type = type; hmc_info->sd_table.use_cnt++; } if (sd_entry->entry_type == IRDMA_SD_TYPE_DIRECT) sd_entry->u.bp.use_cnt++; return 0; } /** * irdma_add_pd_table_entry - Adds page descriptor to the specified table * @dev: pointer to our device structure * @hmc_info: pointer to the HMC configuration information structure * @pd_index: which page descriptor index to manipulate * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one. * * This function: * 1. Initializes the pd entry * 2. Adds pd_entry in the pd_table * 3. Mark the entry valid in irdma_hmc_pd_entry structure * 4. Initializes the pd_entry's ref count to 1 * assumptions: * 1. The memory for pd should be pinned down, physically contiguous and * aligned on 4K boundary and zeroed memory. * 2. It should be 4K in size. */ int irdma_add_pd_table_entry(struct irdma_sc_dev *dev, struct irdma_hmc_info *hmc_info, u32 pd_index, struct irdma_dma_mem *rsrc_pg) { struct irdma_hmc_pd_table *pd_table; struct irdma_hmc_pd_entry *pd_entry; struct irdma_dma_mem mem; struct irdma_dma_mem *page = &mem; u32 sd_idx, rel_pd_idx; u64 *pd_addr; u64 page_desc; if (pd_index / IRDMA_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) return -EINVAL; sd_idx = (pd_index / IRDMA_HMC_PD_CNT_IN_SD); if (hmc_info->sd_table.sd_entry[sd_idx].entry_type != IRDMA_SD_TYPE_PAGED) return 0; rel_pd_idx = (pd_index % IRDMA_HMC_PD_CNT_IN_SD); pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; pd_entry = &pd_table->pd_entry[rel_pd_idx]; if (!pd_entry->valid) { if (rsrc_pg) { pd_entry->rsrc_pg = true; page = rsrc_pg; } else { page->size = IRDMA_HMC_PAGED_BP_SIZE; page->va = irdma_allocate_dma_mem(dev->hw, page, page->size, IRDMA_HMC_PD_BP_BUF_ALIGNMENT); if (!page->va) return -ENOMEM; pd_entry->rsrc_pg = false; } irdma_memcpy(&pd_entry->bp.addr, page, sizeof(pd_entry->bp.addr)); pd_entry->bp.sd_pd_index = pd_index; pd_entry->bp.entry_type = IRDMA_SD_TYPE_PAGED; page_desc = page->pa | 0x1; pd_addr = pd_table->pd_page_addr.va; pd_addr += rel_pd_idx; irdma_memcpy(pd_addr, &page_desc, sizeof(*pd_addr)); pd_entry->sd_index = sd_idx; pd_entry->valid = true; pd_table->use_cnt++; irdma_invalidate_pf_hmc_pd(dev, sd_idx, rel_pd_idx); } pd_entry->bp.use_cnt++; return 0; } /** * irdma_remove_pd_bp - remove a backing page from a page descriptor * @dev: pointer to our HW structure * @hmc_info: pointer to the HMC configuration information structure * @idx: the page index * * This function: * 1. Marks the entry in pd table (for paged address mode) or in sd table * (for direct address mode) invalid. * 2. Write to register PMPDINV to invalidate the backing page in FV cache * 3. Decrement the ref count for the pd _entry * assumptions: * 1. Caller can deallocate the memory used by backing storage after this * function returns. */ int irdma_remove_pd_bp(struct irdma_sc_dev *dev, struct irdma_hmc_info *hmc_info, u32 idx) { struct irdma_hmc_pd_entry *pd_entry; struct irdma_hmc_pd_table *pd_table; struct irdma_hmc_sd_entry *sd_entry; u32 sd_idx, rel_pd_idx; struct irdma_dma_mem *mem; u64 *pd_addr; sd_idx = idx / IRDMA_HMC_PD_CNT_IN_SD; rel_pd_idx = idx % IRDMA_HMC_PD_CNT_IN_SD; if (sd_idx >= hmc_info->sd_table.sd_cnt) return -EINVAL; sd_entry = &hmc_info->sd_table.sd_entry[sd_idx]; if (sd_entry->entry_type != IRDMA_SD_TYPE_PAGED) return -EINVAL; pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; pd_entry = &pd_table->pd_entry[rel_pd_idx]; if (--pd_entry->bp.use_cnt) return 0; pd_entry->valid = false; pd_table->use_cnt--; pd_addr = pd_table->pd_page_addr.va; pd_addr += rel_pd_idx; irdma_memset(pd_addr, 0, sizeof(u64)); irdma_invalidate_pf_hmc_pd(dev, sd_idx, idx); if (!pd_entry->rsrc_pg) { mem = &pd_entry->bp.addr; if (!mem || !mem->va) return -EINVAL; irdma_free_dma_mem(dev->hw, mem); } if (!pd_table->use_cnt) kfree(pd_table->pd_entry_virt_mem.va); return 0; } /** * irdma_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry * @hmc_info: pointer to the HMC configuration information structure * @idx: the page index */ int irdma_prep_remove_sd_bp(struct irdma_hmc_info *hmc_info, u32 idx) { struct irdma_hmc_sd_entry *sd_entry; sd_entry = &hmc_info->sd_table.sd_entry[idx]; if (--sd_entry->u.bp.use_cnt) return -EBUSY; hmc_info->sd_table.use_cnt--; sd_entry->valid = false; return 0; } /** * irdma_prep_remove_pd_page - Prepares to remove a PD page from sd entry. * @hmc_info: pointer to the HMC configuration information structure * @idx: segment descriptor index to find the relevant page descriptor */ int irdma_prep_remove_pd_page(struct irdma_hmc_info *hmc_info, u32 idx) { struct irdma_hmc_sd_entry *sd_entry; sd_entry = &hmc_info->sd_table.sd_entry[idx]; if (sd_entry->u.pd_table.use_cnt) return -EBUSY; sd_entry->valid = false; hmc_info->sd_table.use_cnt--; return 0; }