Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Suravee Suthikulpanit and committed by
Joerg Roedel
103f4e7c 93eee2a4

+73
+73
drivers/iommu/amd/nested.c
··· 183 183 return ERR_PTR(ret); 184 184 } 185 185 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 + 186 258 static void nested_domain_free(struct iommu_domain *dom) 187 259 { 188 260 struct guest_domain_mapping_info *curr; ··· 289 217 } 290 218 291 219 static const struct iommu_domain_ops nested_domain_ops = { 220 + .attach_dev = nested_attach_device, 292 221 .free = nested_domain_free, 293 222 };