iommu/amd: Refactor GCR3 table helper functions
To use the new per-device struct gcr3_tbl_info. Use GFP_KERNEL flag instead of GFP_ATOMIC for GCR3 table allocation. Also modify set_dte_entry() to use new per device GCR3 table. Also in free_gcr3_table() path replace BUG_ON with WARN_ON_ONCE(). Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Co-developed-by: Vasant Hegde <vasant.hegde@amd.com> Signed-off-by: Vasant Hegde <vasant.hegde@amd.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/20240205115615.6053-14-vasant.hegde@amd.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
fb575d1781
commit
cf70873e3d
1 changed files with 31 additions and 22 deletions
|
@ -75,6 +75,9 @@ struct kmem_cache *amd_iommu_irq_cache;
|
||||||
|
|
||||||
static void detach_device(struct device *dev);
|
static void detach_device(struct device *dev);
|
||||||
|
|
||||||
|
static void set_dte_entry(struct amd_iommu *iommu,
|
||||||
|
struct iommu_dev_data *dev_data);
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* Helper functions
|
* Helper functions
|
||||||
|
@ -1666,16 +1669,19 @@ static void free_gcr3_tbl_level2(u64 *tbl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_gcr3_table(struct protection_domain *domain)
|
static void free_gcr3_table(struct gcr3_tbl_info *gcr3_info)
|
||||||
{
|
{
|
||||||
if (domain->glx == 2)
|
if (gcr3_info->glx == 2)
|
||||||
free_gcr3_tbl_level2(domain->gcr3_tbl);
|
free_gcr3_tbl_level2(gcr3_info->gcr3_tbl);
|
||||||
else if (domain->glx == 1)
|
else if (gcr3_info->glx == 1)
|
||||||
free_gcr3_tbl_level1(domain->gcr3_tbl);
|
free_gcr3_tbl_level1(gcr3_info->gcr3_tbl);
|
||||||
else
|
else
|
||||||
BUG_ON(domain->glx != 0);
|
WARN_ON_ONCE(gcr3_info->glx != 0);
|
||||||
|
|
||||||
free_page((unsigned long)domain->gcr3_tbl);
|
gcr3_info->glx = 0;
|
||||||
|
|
||||||
|
free_page((unsigned long)gcr3_info->gcr3_tbl);
|
||||||
|
gcr3_info->gcr3_tbl = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1694,22 +1700,23 @@ static int get_gcr3_levels(int pasids)
|
||||||
return levels ? (DIV_ROUND_UP(levels, 9) - 1) : levels;
|
return levels ? (DIV_ROUND_UP(levels, 9) - 1) : levels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: This function expects iommu_domain->lock to be held prior calling the function. */
|
static int setup_gcr3_table(struct gcr3_tbl_info *gcr3_info,
|
||||||
static int setup_gcr3_table(struct protection_domain *domain, int pasids)
|
struct amd_iommu *iommu, int pasids)
|
||||||
{
|
{
|
||||||
int levels = get_gcr3_levels(pasids);
|
int levels = get_gcr3_levels(pasids);
|
||||||
|
int nid = iommu ? dev_to_node(&iommu->dev->dev) : NUMA_NO_NODE;
|
||||||
|
|
||||||
if (levels > amd_iommu_max_glx_val)
|
if (levels > amd_iommu_max_glx_val)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
domain->gcr3_tbl = alloc_pgtable_page(domain->nid, GFP_ATOMIC);
|
if (gcr3_info->gcr3_tbl)
|
||||||
if (domain->gcr3_tbl == NULL)
|
return -EBUSY;
|
||||||
|
|
||||||
|
gcr3_info->gcr3_tbl = alloc_pgtable_page(nid, GFP_KERNEL);
|
||||||
|
if (gcr3_info->gcr3_tbl == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
domain->glx = levels;
|
gcr3_info->glx = levels;
|
||||||
domain->flags |= PD_IOMMUV2_MASK;
|
|
||||||
|
|
||||||
amd_iommu_domain_update(domain);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1808,6 +1815,7 @@ static void set_dte_entry(struct amd_iommu *iommu,
|
||||||
u16 devid = dev_data->devid;
|
u16 devid = dev_data->devid;
|
||||||
struct protection_domain *domain = dev_data->domain;
|
struct protection_domain *domain = dev_data->domain;
|
||||||
struct dev_table_entry *dev_table = get_dev_table(iommu);
|
struct dev_table_entry *dev_table = get_dev_table(iommu);
|
||||||
|
struct gcr3_tbl_info *gcr3_info = &dev_data->gcr3_info;
|
||||||
|
|
||||||
if (domain->iop.mode != PAGE_MODE_NONE)
|
if (domain->iop.mode != PAGE_MODE_NONE)
|
||||||
pte_root = iommu_virt_to_phys(domain->iop.root);
|
pte_root = iommu_virt_to_phys(domain->iop.root);
|
||||||
|
@ -1835,9 +1843,9 @@ static void set_dte_entry(struct amd_iommu *iommu,
|
||||||
if (domain->dirty_tracking)
|
if (domain->dirty_tracking)
|
||||||
pte_root |= DTE_FLAG_HAD;
|
pte_root |= DTE_FLAG_HAD;
|
||||||
|
|
||||||
if (domain->flags & PD_IOMMUV2_MASK) {
|
if (gcr3_info && gcr3_info->gcr3_tbl) {
|
||||||
u64 gcr3 = iommu_virt_to_phys(domain->gcr3_tbl);
|
u64 gcr3 = iommu_virt_to_phys(gcr3_info->gcr3_tbl);
|
||||||
u64 glx = domain->glx;
|
u64 glx = gcr3_info->glx;
|
||||||
u64 tmp;
|
u64 tmp;
|
||||||
|
|
||||||
pte_root |= DTE_FLAG_GV;
|
pte_root |= DTE_FLAG_GV;
|
||||||
|
@ -1865,7 +1873,8 @@ static void set_dte_entry(struct amd_iommu *iommu,
|
||||||
((u64)GUEST_PGTABLE_5_LEVEL << DTE_GPT_LEVEL_SHIFT);
|
((u64)GUEST_PGTABLE_5_LEVEL << DTE_GPT_LEVEL_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain->flags & PD_GIOV_MASK)
|
/* GIOV is supported with V2 page table mode only */
|
||||||
|
if (pdom_is_v2_pgtbl_mode(domain))
|
||||||
pte_root |= DTE_FLAG_GIOV;
|
pte_root |= DTE_FLAG_GIOV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1922,14 +1931,14 @@ static int do_attach(struct iommu_dev_data *dev_data,
|
||||||
/* Init GCR3 table and update device table */
|
/* Init GCR3 table and update device table */
|
||||||
if (domain->pd_mode == PD_MODE_V2) {
|
if (domain->pd_mode == PD_MODE_V2) {
|
||||||
/* By default, setup GCR3 table to support single PASID */
|
/* By default, setup GCR3 table to support single PASID */
|
||||||
ret = setup_gcr3_table(dev_data->domain, 1);
|
ret = setup_gcr3_table(&dev_data->gcr3_info, iommu, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = update_gcr3(dev_data, 0,
|
ret = update_gcr3(dev_data, 0,
|
||||||
iommu_virt_to_phys(domain->iop.pgd), true);
|
iommu_virt_to_phys(domain->iop.pgd), true);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
free_gcr3_table(dev_data->domain);
|
free_gcr3_table(&dev_data->gcr3_info);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1951,7 +1960,7 @@ static void do_detach(struct iommu_dev_data *dev_data)
|
||||||
/* Clear GCR3 table */
|
/* Clear GCR3 table */
|
||||||
if (domain->pd_mode == PD_MODE_V2) {
|
if (domain->pd_mode == PD_MODE_V2) {
|
||||||
update_gcr3(dev_data, 0, 0, false);
|
update_gcr3(dev_data, 0, 0, false);
|
||||||
free_gcr3_table(dev_data->domain);
|
free_gcr3_table(&dev_data->gcr3_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update data structures */
|
/* Update data structures */
|
||||||
|
|
Loading…
Add table
Reference in a new issue