Skip to content

Commit 103f4e7

Browse files
ssuthiku-amdjoergroedel
authored andcommitted
iommu/amd: Add support for nested domain attach/detach
Introduce set_dte_nested() to program guest translation settings in the host DTE when attaches the nested domain to a device. Reviewed-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
1 parent 93eee2a commit 103f4e7

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

drivers/iommu/amd/nested.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,78 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
183183
return ERR_PTR(ret);
184184
}
185185

186+
static void set_dte_nested(struct amd_iommu *iommu, struct iommu_domain *dom,
187+
struct iommu_dev_data *dev_data, struct dev_table_entry *new)
188+
{
189+
struct protection_domain *parent;
190+
struct nested_domain *ndom = to_ndomain(dom);
191+
struct iommu_hwpt_amd_guest *gdte = &ndom->gdte;
192+
struct pt_iommu_amdv1_hw_info pt_info;
193+
194+
/*
195+
* The nest parent domain is attached during the call to the
196+
* struct iommu_ops.viommu_init(), which will be stored as part
197+
* of the struct amd_iommu_viommu.parent.
198+
*/
199+
if (WARN_ON(!ndom->viommu || !ndom->viommu->parent))
200+
return;
201+
202+
parent = ndom->viommu->parent;
203+
amd_iommu_make_clear_dte(dev_data, new);
204+
205+
/* Retrieve the current pagetable info via the IOMMU PT API. */
206+
pt_iommu_amdv1_hw_info(&parent->amdv1, &pt_info);
207+
208+
/*
209+
* Use domain ID from nested domain to program DTE.
210+
* See amd_iommu_alloc_domain_nested().
211+
*/
212+
amd_iommu_set_dte_v1(dev_data, parent, ndom->gdom_info->hdom_id,
213+
&pt_info, new);
214+
215+
/* GV is required for nested page table */
216+
new->data[0] |= DTE_FLAG_GV;
217+
218+
/* Guest PPR */
219+
new->data[0] |= gdte->dte[0] & DTE_FLAG_PPR;
220+
221+
/* Guest translation stuff */
222+
new->data[0] |= gdte->dte[0] & (DTE_GLX | DTE_FLAG_GIOV);
223+
224+
/* GCR3 table */
225+
new->data[0] |= gdte->dte[0] & DTE_GCR3_14_12;
226+
new->data[1] |= gdte->dte[1] & (DTE_GCR3_30_15 | DTE_GCR3_51_31);
227+
228+
/* Guest paging mode */
229+
new->data[2] |= gdte->dte[2] & DTE_GPT_LEVEL_MASK;
230+
}
231+
232+
static int nested_attach_device(struct iommu_domain *dom, struct device *dev,
233+
struct iommu_domain *old)
234+
{
235+
struct dev_table_entry new = {0};
236+
struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);
237+
struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data);
238+
int ret = 0;
239+
240+
/*
241+
* Needs to make sure PASID is not enabled
242+
* for this attach path.
243+
*/
244+
if (WARN_ON(dev_data->pasid_enabled))
245+
return -EINVAL;
246+
247+
mutex_lock(&dev_data->mutex);
248+
249+
set_dte_nested(iommu, dom, dev_data, &new);
250+
251+
amd_iommu_update_dte(iommu, dev_data, &new);
252+
253+
mutex_unlock(&dev_data->mutex);
254+
255+
return ret;
256+
}
257+
186258
static void nested_domain_free(struct iommu_domain *dom)
187259
{
188260
struct guest_domain_mapping_info *curr;
@@ -217,5 +289,6 @@ static void nested_domain_free(struct iommu_domain *dom)
217289
}
218290

219291
static const struct iommu_domain_ops nested_domain_ops = {
292+
.attach_dev = nested_attach_device,
220293
.free = nested_domain_free,
221294
};

0 commit comments

Comments
 (0)