@@ -93,6 +93,12 @@ struct mock_iommu_domain {
9393 struct xarray pfns ;
9494};
9595
96+ struct mock_iommu_domain_nested {
97+ struct iommu_domain domain ;
98+ struct mock_iommu_domain * parent ;
99+ u32 iotlb [MOCK_NESTED_DOMAIN_IOTLB_NUM ];
100+ };
101+
96102enum selftest_obj_type {
97103 TYPE_IDEV ,
98104};
@@ -217,54 +223,99 @@ const struct iommu_dirty_ops dirty_ops = {
217223};
218224
219225static const struct iommu_ops mock_ops ;
226+ static struct iommu_domain_ops domain_nested_ops ;
220227
221- static struct iommu_domain * mock_domain_alloc (unsigned int iommu_domain_type )
228+ static struct iommu_domain *
229+ __mock_domain_alloc_paging (unsigned int iommu_domain_type , bool needs_dirty_ops )
222230{
223231 struct mock_iommu_domain * mock ;
224232
225- if (iommu_domain_type == IOMMU_DOMAIN_BLOCKED )
226- return & mock_blocking_domain ;
227-
228- if (iommu_domain_type != IOMMU_DOMAIN_UNMANAGED )
229- return NULL ;
230-
231233 mock = kzalloc (sizeof (* mock ), GFP_KERNEL );
232234 if (!mock )
233- return NULL ;
235+ return ERR_PTR ( - ENOMEM ) ;
234236 mock -> domain .geometry .aperture_start = MOCK_APERTURE_START ;
235237 mock -> domain .geometry .aperture_end = MOCK_APERTURE_LAST ;
236238 mock -> domain .pgsize_bitmap = MOCK_IO_PAGE_SIZE ;
237239 mock -> domain .ops = mock_ops .default_domain_ops ;
240+ if (needs_dirty_ops )
241+ mock -> domain .dirty_ops = & dirty_ops ;
238242 mock -> domain .type = iommu_domain_type ;
239243 xa_init (& mock -> pfns );
240244 return & mock -> domain ;
241245}
242246
247+ static struct iommu_domain *
248+ __mock_domain_alloc_nested (struct mock_iommu_domain * mock_parent ,
249+ const struct iommu_hwpt_selftest * user_cfg )
250+ {
251+ struct mock_iommu_domain_nested * mock_nested ;
252+ int i ;
253+
254+ mock_nested = kzalloc (sizeof (* mock_nested ), GFP_KERNEL );
255+ if (!mock_nested )
256+ return ERR_PTR (- ENOMEM );
257+ mock_nested -> parent = mock_parent ;
258+ mock_nested -> domain .ops = & domain_nested_ops ;
259+ mock_nested -> domain .type = IOMMU_DOMAIN_NESTED ;
260+ for (i = 0 ; i < MOCK_NESTED_DOMAIN_IOTLB_NUM ; i ++ )
261+ mock_nested -> iotlb [i ] = user_cfg -> iotlb ;
262+ return & mock_nested -> domain ;
263+ }
264+
265+ static struct iommu_domain * mock_domain_alloc (unsigned int iommu_domain_type )
266+ {
267+ struct iommu_domain * domain ;
268+
269+ if (iommu_domain_type == IOMMU_DOMAIN_BLOCKED )
270+ return & mock_blocking_domain ;
271+ if (iommu_domain_type != IOMMU_DOMAIN_UNMANAGED )
272+ return NULL ;
273+ domain = __mock_domain_alloc_paging (iommu_domain_type , false);
274+ if (IS_ERR (domain ))
275+ domain = NULL ;
276+ return domain ;
277+ }
278+
243279static struct iommu_domain *
244280mock_domain_alloc_user (struct device * dev , u32 flags ,
245281 struct iommu_domain * parent ,
246282 const struct iommu_user_data * user_data )
247283{
248- struct mock_dev * mdev = container_of (dev , struct mock_dev , dev );
249- struct iommu_domain * domain ;
284+ struct mock_iommu_domain * mock_parent ;
285+ struct iommu_hwpt_selftest user_cfg ;
286+ int rc ;
250287
251- if (flags &
252- (~(IOMMU_HWPT_ALLOC_NEST_PARENT | IOMMU_HWPT_ALLOC_DIRTY_TRACKING )))
253- return ERR_PTR (- EOPNOTSUPP );
288+ /* must be mock_domain */
289+ if (!parent ) {
290+ struct mock_dev * mdev = container_of (dev , struct mock_dev , dev );
291+ bool has_dirty_flag = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING ;
292+ bool no_dirty_ops = mdev -> flags & MOCK_FLAGS_DEVICE_NO_DIRTY ;
293+
294+ if (flags & (~(IOMMU_HWPT_ALLOC_NEST_PARENT |
295+ IOMMU_HWPT_ALLOC_DIRTY_TRACKING )))
296+ return ERR_PTR (- EOPNOTSUPP );
297+ if (user_data || (has_dirty_flag && no_dirty_ops ))
298+ return ERR_PTR (- EOPNOTSUPP );
299+ return __mock_domain_alloc_paging (IOMMU_DOMAIN_UNMANAGED ,
300+ has_dirty_flag );
301+ }
254302
255- if (parent || user_data )
303+ /* must be mock_domain_nested */
304+ if (user_data -> type != IOMMU_HWPT_DATA_SELFTEST || flags )
256305 return ERR_PTR (- EOPNOTSUPP );
306+ if (!parent || parent -> ops != mock_ops .default_domain_ops )
307+ return ERR_PTR (- EINVAL );
257308
258- if (( flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING ) &&
259- ( mdev -> flags & MOCK_FLAGS_DEVICE_NO_DIRTY ) )
260- return ERR_PTR (- EOPNOTSUPP );
309+ mock_parent = container_of ( parent , struct mock_iommu_domain , domain );
310+ if (! mock_parent )
311+ return ERR_PTR (- EINVAL );
261312
262- domain = mock_domain_alloc ( IOMMU_DOMAIN_UNMANAGED );
263- if ( domain && !( mdev -> flags & MOCK_FLAGS_DEVICE_NO_DIRTY ))
264- domain -> dirty_ops = & dirty_ops ;
265- if (! domain )
266- domain = ERR_PTR ( - ENOMEM );
267- return domain ;
313+ rc = iommu_copy_struct_from_user ( & user_cfg , user_data ,
314+ IOMMU_HWPT_DATA_SELFTEST , iotlb );
315+ if ( rc )
316+ return ERR_PTR ( rc );
317+
318+ return __mock_domain_alloc_nested ( mock_parent , & user_cfg ) ;
268319}
269320
270321static void mock_domain_free (struct iommu_domain * domain )
@@ -434,26 +485,67 @@ static const struct iommu_ops mock_ops = {
434485 },
435486};
436487
488+ static void mock_domain_free_nested (struct iommu_domain * domain )
489+ {
490+ struct mock_iommu_domain_nested * mock_nested =
491+ container_of (domain , struct mock_iommu_domain_nested , domain );
492+
493+ kfree (mock_nested );
494+ }
495+
496+ static struct iommu_domain_ops domain_nested_ops = {
497+ .free = mock_domain_free_nested ,
498+ .attach_dev = mock_domain_nop_attach ,
499+ };
500+
437501static inline struct iommufd_hw_pagetable *
438- get_md_pagetable (struct iommufd_ucmd * ucmd , u32 mockpt_id ,
439- struct mock_iommu_domain * * mock )
502+ __get_md_pagetable (struct iommufd_ucmd * ucmd , u32 mockpt_id , u32 hwpt_type )
440503{
441- struct iommufd_hw_pagetable * hwpt ;
442504 struct iommufd_object * obj ;
443505
444- obj = iommufd_get_object (ucmd -> ictx , mockpt_id ,
445- IOMMUFD_OBJ_HWPT_PAGING );
506+ obj = iommufd_get_object (ucmd -> ictx , mockpt_id , hwpt_type );
446507 if (IS_ERR (obj ))
447508 return ERR_CAST (obj );
448- hwpt = container_of (obj , struct iommufd_hw_pagetable , obj );
449- if (hwpt -> domain -> ops != mock_ops .default_domain_ops ) {
509+ return container_of (obj , struct iommufd_hw_pagetable , obj );
510+ }
511+
512+ static inline struct iommufd_hw_pagetable *
513+ get_md_pagetable (struct iommufd_ucmd * ucmd , u32 mockpt_id ,
514+ struct mock_iommu_domain * * mock )
515+ {
516+ struct iommufd_hw_pagetable * hwpt ;
517+
518+ hwpt = __get_md_pagetable (ucmd , mockpt_id , IOMMUFD_OBJ_HWPT_PAGING );
519+ if (IS_ERR (hwpt ))
520+ return hwpt ;
521+ if (hwpt -> domain -> type != IOMMU_DOMAIN_UNMANAGED ||
522+ hwpt -> domain -> ops != mock_ops .default_domain_ops ) {
450523 iommufd_put_object (& hwpt -> obj );
451524 return ERR_PTR (- EINVAL );
452525 }
453526 * mock = container_of (hwpt -> domain , struct mock_iommu_domain , domain );
454527 return hwpt ;
455528}
456529
530+ static inline struct iommufd_hw_pagetable *
531+ get_md_pagetable_nested (struct iommufd_ucmd * ucmd , u32 mockpt_id ,
532+ struct mock_iommu_domain_nested * * mock_nested )
533+ {
534+ struct iommufd_hw_pagetable * hwpt ;
535+
536+ hwpt = __get_md_pagetable (ucmd , mockpt_id , IOMMUFD_OBJ_HWPT_NESTED );
537+ if (IS_ERR (hwpt ))
538+ return hwpt ;
539+ if (hwpt -> domain -> type != IOMMU_DOMAIN_NESTED ||
540+ hwpt -> domain -> ops != & domain_nested_ops ) {
541+ iommufd_put_object (& hwpt -> obj );
542+ return ERR_PTR (- EINVAL );
543+ }
544+ * mock_nested = container_of (hwpt -> domain ,
545+ struct mock_iommu_domain_nested , domain );
546+ return hwpt ;
547+ }
548+
457549struct mock_bus_type {
458550 struct bus_type bus ;
459551 struct notifier_block nb ;
0 commit comments