Skip to content

Commit 93eee2a

Browse files
ssuthiku-amdjoergroedel
authored andcommitted
iommu/amd: Refactor logic to program the host page table in DTE
Introduce the amd_iommu_set_dte_v1() helper function to configure IOMMU host (v1) page table into DTE. This will be used later when attaching nested doamin. Also, remove obsolete warning when SNP is enabled and domain id is zero since this check is no longer applicable. Suggested-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
1 parent 4e1b09d commit 93eee2a

3 files changed

Lines changed: 82 additions & 73 deletions

File tree

drivers/iommu/amd/amd_iommu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ void amd_iommu_domain_set_pgtable(struct protection_domain *domain,
190190
struct dev_table_entry *get_dev_table(struct amd_iommu *iommu);
191191
struct iommu_dev_data *search_dev_data(struct amd_iommu *iommu, u16 devid);
192192

193+
void amd_iommu_set_dte_v1(struct iommu_dev_data *dev_data,
194+
struct protection_domain *domain, u16 domid,
195+
struct pt_iommu_amdv1_hw_info *pt_info,
196+
struct dev_table_entry *new);
193197
void amd_iommu_update_dte(struct amd_iommu *iommu,
194198
struct iommu_dev_data *dev_data,
195199
struct dev_table_entry *new);

drivers/iommu/amd/amd_iommu_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@
357357
#define DTE_FLAG_HAD (3ULL << 7)
358358
#define DTE_MODE_MASK GENMASK_ULL(11, 9)
359359
#define DTE_HOST_TRP GENMASK_ULL(51, 12)
360+
#define DTE_FLAG_PPR BIT_ULL(52)
360361
#define DTE_FLAG_GIOV BIT_ULL(54)
361362
#define DTE_FLAG_GV BIT_ULL(55)
362363
#define DTE_GLX GENMASK_ULL(57, 56)

drivers/iommu/amd/iommu.c

Lines changed: 77 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,102 +2072,106 @@ int amd_iommu_clear_gcr3(struct iommu_dev_data *dev_data, ioasid_t pasid)
20722072
* Note:
20732073
* The old value for GCR3 table and GPT have been cleared from caller.
20742074
*/
2075-
static void set_dte_gcr3_table(struct amd_iommu *iommu,
2076-
struct iommu_dev_data *dev_data,
2077-
struct dev_table_entry *target)
2075+
static void set_dte_gcr3_table(struct iommu_dev_data *dev_data,
2076+
struct dev_table_entry *new)
20782077
{
20792078
struct gcr3_tbl_info *gcr3_info = &dev_data->gcr3_info;
2080-
u64 gcr3;
2079+
u64 gcr3 = iommu_virt_to_phys(gcr3_info->gcr3_tbl);
20812080

2082-
if (!gcr3_info->gcr3_tbl)
2083-
return;
2084-
2085-
pr_debug("%s: devid=%#x, glx=%#x, gcr3_tbl=%#llx\n",
2086-
__func__, dev_data->devid, gcr3_info->glx,
2087-
(unsigned long long)gcr3_info->gcr3_tbl);
2088-
2089-
gcr3 = iommu_virt_to_phys(gcr3_info->gcr3_tbl);
2081+
new->data[0] |= DTE_FLAG_TV |
2082+
(dev_data->ppr ? DTE_FLAG_PPR : 0) |
2083+
(pdom_is_v2_pgtbl_mode(dev_data->domain) ? DTE_FLAG_GIOV : 0) |
2084+
DTE_FLAG_GV |
2085+
FIELD_PREP(DTE_GLX, gcr3_info->glx) |
2086+
FIELD_PREP(DTE_GCR3_14_12, gcr3 >> 12) |
2087+
DTE_FLAG_IR | DTE_FLAG_IW;
20902088

2091-
target->data[0] |= DTE_FLAG_GV |
2092-
FIELD_PREP(DTE_GLX, gcr3_info->glx) |
2093-
FIELD_PREP(DTE_GCR3_14_12, gcr3 >> 12);
2094-
if (pdom_is_v2_pgtbl_mode(dev_data->domain))
2095-
target->data[0] |= DTE_FLAG_GIOV;
2096-
2097-
target->data[1] |= FIELD_PREP(DTE_GCR3_30_15, gcr3 >> 15) |
2098-
FIELD_PREP(DTE_GCR3_51_31, gcr3 >> 31);
2089+
new->data[1] |= FIELD_PREP(DTE_DOMID_MASK, dev_data->gcr3_info.domid) |
2090+
FIELD_PREP(DTE_GCR3_30_15, gcr3 >> 15) |
2091+
(dev_data->ats_enabled ? DTE_FLAG_IOTLB : 0) |
2092+
FIELD_PREP(DTE_GCR3_51_31, gcr3 >> 31);
20992093

21002094
/* Guest page table can only support 4 and 5 levels */
21012095
if (amd_iommu_gpt_level == PAGE_MODE_5_LEVEL)
2102-
target->data[2] |= FIELD_PREP(DTE_GPT_LEVEL_MASK, GUEST_PGTABLE_5_LEVEL);
2096+
new->data[2] |= FIELD_PREP(DTE_GPT_LEVEL_MASK, GUEST_PGTABLE_5_LEVEL);
21032097
else
2104-
target->data[2] |= FIELD_PREP(DTE_GPT_LEVEL_MASK, GUEST_PGTABLE_4_LEVEL);
2098+
new->data[2] |= FIELD_PREP(DTE_GPT_LEVEL_MASK, GUEST_PGTABLE_4_LEVEL);
2099+
}
2100+
2101+
void amd_iommu_set_dte_v1(struct iommu_dev_data *dev_data,
2102+
struct protection_domain *domain, u16 domid,
2103+
struct pt_iommu_amdv1_hw_info *pt_info,
2104+
struct dev_table_entry *new)
2105+
{
2106+
u64 host_pt_root = __sme_set(pt_info->host_pt_root);
2107+
2108+
/* Note Dirty tracking is used for v1 table only for now */
2109+
new->data[0] |= DTE_FLAG_TV |
2110+
FIELD_PREP(DTE_MODE_MASK, pt_info->mode) |
2111+
(domain->dirty_tracking ? DTE_FLAG_HAD : 0) |
2112+
FIELD_PREP(DTE_HOST_TRP, host_pt_root >> 12) |
2113+
DTE_FLAG_IR | DTE_FLAG_IW;
2114+
2115+
new->data[1] |= FIELD_PREP(DTE_DOMID_MASK, domid) |
2116+
(dev_data->ats_enabled ? DTE_FLAG_IOTLB : 0);
2117+
}
2118+
2119+
static void set_dte_v1(struct iommu_dev_data *dev_data,
2120+
struct protection_domain *domain, u16 domid,
2121+
phys_addr_t top_paddr, unsigned int top_level,
2122+
struct dev_table_entry *new)
2123+
{
2124+
struct pt_iommu_amdv1_hw_info pt_info;
2125+
2126+
/*
2127+
* When updating the IO pagetable, the new top and level
2128+
* are provided as parameters. For other operations i.e.
2129+
* device attach, retrieve the current pagetable info
2130+
* via the IOMMU PT API.
2131+
*/
2132+
if (top_paddr) {
2133+
pt_info.host_pt_root = top_paddr;
2134+
pt_info.mode = top_level + 1;
2135+
} else {
2136+
WARN_ON(top_paddr || top_level);
2137+
pt_iommu_amdv1_hw_info(&domain->amdv1, &pt_info);
2138+
}
2139+
2140+
amd_iommu_set_dte_v1(dev_data, domain, domid, &pt_info, new);
2141+
}
2142+
2143+
static void set_dte_passthrough(struct iommu_dev_data *dev_data,
2144+
struct protection_domain *domain,
2145+
struct dev_table_entry *new)
2146+
{
2147+
new->data[0] |= DTE_FLAG_TV | DTE_FLAG_IR | DTE_FLAG_IW;
2148+
2149+
new->data[1] |= FIELD_PREP(DTE_DOMID_MASK, domain->id) |
2150+
(dev_data->ats_enabled) ? DTE_FLAG_IOTLB : 0;
21052151
}
21062152

21072153
static void set_dte_entry(struct amd_iommu *iommu,
21082154
struct iommu_dev_data *dev_data,
21092155
phys_addr_t top_paddr, unsigned int top_level)
21102156
{
2111-
u16 domid;
21122157
u32 old_domid;
21132158
struct dev_table_entry new = {};
21142159
struct protection_domain *domain = dev_data->domain;
21152160
struct gcr3_tbl_info *gcr3_info = &dev_data->gcr3_info;
21162161
struct dev_table_entry *dte = &get_dev_table(iommu)[dev_data->devid];
2117-
struct pt_iommu_amdv1_hw_info pt_info;
21182162

21192163
amd_iommu_make_clear_dte(dev_data, &new);
21202164

2121-
if (gcr3_info && gcr3_info->gcr3_tbl)
2122-
domid = dev_data->gcr3_info.domid;
2123-
else {
2124-
domid = domain->id;
2125-
2126-
if (domain->domain.type & __IOMMU_DOMAIN_PAGING) {
2127-
/*
2128-
* When updating the IO pagetable, the new top and level
2129-
* are provided as parameters. For other operations i.e.
2130-
* device attach, retrieve the current pagetable info
2131-
* via the IOMMU PT API.
2132-
*/
2133-
if (top_paddr) {
2134-
pt_info.host_pt_root = top_paddr;
2135-
pt_info.mode = top_level + 1;
2136-
} else {
2137-
WARN_ON(top_paddr || top_level);
2138-
pt_iommu_amdv1_hw_info(&domain->amdv1,
2139-
&pt_info);
2140-
}
2141-
2142-
new.data[0] |= __sme_set(pt_info.host_pt_root) |
2143-
(pt_info.mode & DEV_ENTRY_MODE_MASK)
2144-
<< DEV_ENTRY_MODE_SHIFT;
2145-
}
2146-
}
2147-
2148-
new.data[0] |= DTE_FLAG_IR | DTE_FLAG_IW;
2149-
2150-
/*
2151-
* When SNP is enabled, we can only support TV=1 with non-zero domain ID.
2152-
* This is prevented by the SNP-enable and IOMMU_DOMAIN_IDENTITY check in
2153-
* do_iommu_domain_alloc().
2154-
*/
2155-
WARN_ON(amd_iommu_snp_en && (domid == 0));
2156-
new.data[0] |= DTE_FLAG_TV;
2157-
2158-
if (dev_data->ppr)
2159-
new.data[0] |= 1ULL << DEV_ENTRY_PPR;
2160-
2161-
if (domain->dirty_tracking)
2162-
new.data[0] |= DTE_FLAG_HAD;
2163-
2164-
if (dev_data->ats_enabled)
2165-
new.data[1] |= DTE_FLAG_IOTLB;
2166-
21672165
old_domid = READ_ONCE(dte->data[1]) & DTE_DOMID_MASK;
2168-
new.data[1] |= domid;
2169-
2170-
set_dte_gcr3_table(iommu, dev_data, &new);
2166+
if (gcr3_info->gcr3_tbl)
2167+
set_dte_gcr3_table(dev_data, &new);
2168+
else if (domain->domain.type == IOMMU_DOMAIN_IDENTITY)
2169+
set_dte_passthrough(dev_data, domain, &new);
2170+
else if ((domain->domain.type & __IOMMU_DOMAIN_PAGING) &&
2171+
domain->pd_mode == PD_MODE_V1)
2172+
set_dte_v1(dev_data, domain, domain->id, top_paddr, top_level, &new);
2173+
else
2174+
WARN_ON(true);
21712175

21722176
amd_iommu_update_dte(iommu, dev_data, &new);
21732177

0 commit comments

Comments
 (0)