@@ -20,9 +20,12 @@ static void iommufd_group_release(struct kref *kref)
20
20
struct iommufd_group * igroup =
21
21
container_of (kref , struct iommufd_group , ref );
22
22
23
+ WARN_ON (igroup -> hwpt || !list_empty (& igroup -> device_list ));
24
+
23
25
xa_cmpxchg (& igroup -> ictx -> groups , iommu_group_id (igroup -> group ), igroup ,
24
26
NULL , GFP_KERNEL );
25
27
iommu_group_put (igroup -> group );
28
+ mutex_destroy (& igroup -> lock );
26
29
kfree (igroup );
27
30
}
28
31
@@ -83,6 +86,8 @@ static struct iommufd_group *iommufd_get_group(struct iommufd_ctx *ictx,
83
86
}
84
87
85
88
kref_init (& new_igroup -> ref );
89
+ mutex_init (& new_igroup -> lock );
90
+ INIT_LIST_HEAD (& new_igroup -> device_list );
86
91
/* group reference moves into new_igroup */
87
92
new_igroup -> group = group ;
88
93
@@ -320,29 +325,18 @@ static int iommufd_device_setup_msi(struct iommufd_device *idev,
320
325
return 0 ;
321
326
}
322
327
323
- static bool iommufd_hw_pagetable_has_group (struct iommufd_hw_pagetable * hwpt ,
324
- struct iommufd_group * igroup )
325
- {
326
- struct iommufd_device * cur_dev ;
327
-
328
- lockdep_assert_held (& hwpt -> devices_lock );
329
-
330
- list_for_each_entry (cur_dev , & hwpt -> devices , devices_item )
331
- if (cur_dev -> igroup -> group == igroup -> group )
332
- return true;
333
- return false;
334
- }
335
-
336
328
int iommufd_hw_pagetable_attach (struct iommufd_hw_pagetable * hwpt ,
337
329
struct iommufd_device * idev )
338
330
{
339
331
phys_addr_t sw_msi_start = PHYS_ADDR_MAX ;
340
332
int rc ;
341
333
342
- lockdep_assert_held ( & hwpt -> devices_lock );
334
+ mutex_lock ( & idev -> igroup -> lock );
343
335
344
- if (WARN_ON (idev -> hwpt ))
345
- return - EINVAL ;
336
+ if (idev -> igroup -> hwpt != NULL && idev -> igroup -> hwpt != hwpt ) {
337
+ rc = - EINVAL ;
338
+ goto err_unlock ;
339
+ }
346
340
347
341
/*
348
342
* Try to upgrade the domain we have, it is an iommu driver bug to
@@ -356,60 +350,62 @@ int iommufd_hw_pagetable_attach(struct iommufd_hw_pagetable *hwpt,
356
350
hwpt -> domain -> ops -> enforce_cache_coherency (
357
351
hwpt -> domain );
358
352
if (!hwpt -> enforce_cache_coherency ) {
359
- WARN_ON (list_empty (& hwpt -> devices ));
360
- return - EINVAL ;
353
+ WARN_ON (list_empty (& idev -> igroup -> device_list ));
354
+ rc = - EINVAL ;
355
+ goto err_unlock ;
361
356
}
362
357
}
363
358
364
359
rc = iopt_table_enforce_group_resv_regions (& hwpt -> ioas -> iopt , idev -> dev ,
365
360
idev -> igroup -> group ,
366
361
& sw_msi_start );
367
362
if (rc )
368
- return rc ;
363
+ goto err_unlock ;
369
364
370
365
rc = iommufd_device_setup_msi (idev , hwpt , sw_msi_start );
371
366
if (rc )
372
367
goto err_unresv ;
373
368
374
369
/*
375
- * FIXME: Hack around missing a device-centric iommu api, only attach to
376
- * the group once for the first device that is in the group.
370
+ * Only attach to the group once for the first device that is in the
371
+ * group. All the other devices will follow this attachment. The user
372
+ * should attach every device individually to the hwpt as the per-device
373
+ * reserved regions are only updated during individual device
374
+ * attachment.
377
375
*/
378
- if (! iommufd_hw_pagetable_has_group ( hwpt , idev -> igroup )) {
376
+ if (list_empty ( & idev -> igroup -> device_list )) {
379
377
rc = iommu_attach_group (hwpt -> domain , idev -> igroup -> group );
380
378
if (rc )
381
379
goto err_unresv ;
380
+ idev -> igroup -> hwpt = hwpt ;
382
381
}
382
+ refcount_inc (& hwpt -> obj .users );
383
+ list_add_tail (& idev -> group_item , & idev -> igroup -> device_list );
384
+ mutex_unlock (& idev -> igroup -> lock );
383
385
return 0 ;
384
386
err_unresv :
385
387
iopt_remove_reserved_iova (& hwpt -> ioas -> iopt , idev -> dev );
388
+ err_unlock :
389
+ mutex_unlock (& idev -> igroup -> lock );
386
390
return rc ;
387
391
}
388
392
389
- void iommufd_hw_pagetable_detach ( struct iommufd_hw_pagetable * hwpt ,
390
- struct iommufd_device * idev )
393
+ struct iommufd_hw_pagetable *
394
+ iommufd_hw_pagetable_detach ( struct iommufd_device * idev )
391
395
{
392
- if (!iommufd_hw_pagetable_has_group (hwpt , idev -> igroup ))
396
+ struct iommufd_hw_pagetable * hwpt = idev -> igroup -> hwpt ;
397
+
398
+ mutex_lock (& idev -> igroup -> lock );
399
+ list_del (& idev -> group_item );
400
+ if (list_empty (& idev -> igroup -> device_list )) {
393
401
iommu_detach_group (hwpt -> domain , idev -> igroup -> group );
402
+ idev -> igroup -> hwpt = NULL ;
403
+ }
394
404
iopt_remove_reserved_iova (& hwpt -> ioas -> iopt , idev -> dev );
395
- }
396
-
397
- static int iommufd_device_do_attach (struct iommufd_device * idev ,
398
- struct iommufd_hw_pagetable * hwpt )
399
- {
400
- int rc ;
401
-
402
- mutex_lock (& hwpt -> devices_lock );
403
- rc = iommufd_hw_pagetable_attach (hwpt , idev );
404
- if (rc )
405
- goto out_unlock ;
405
+ mutex_unlock (& idev -> igroup -> lock );
406
406
407
- idev -> hwpt = hwpt ;
408
- refcount_inc (& hwpt -> obj .users );
409
- list_add (& idev -> devices_item , & hwpt -> devices );
410
- out_unlock :
411
- mutex_unlock (& hwpt -> devices_lock );
412
- return rc ;
407
+ /* Caller must destroy hwpt */
408
+ return hwpt ;
413
409
}
414
410
415
411
/*
@@ -418,7 +414,7 @@ static int iommufd_device_do_attach(struct iommufd_device *idev,
418
414
* Automatic domain selection will never pick a manually created domain.
419
415
*/
420
416
static int iommufd_device_auto_get_domain (struct iommufd_device * idev ,
421
- struct iommufd_ioas * ioas )
417
+ struct iommufd_ioas * ioas , u32 * pt_id )
422
418
{
423
419
struct iommufd_hw_pagetable * hwpt ;
424
420
int rc ;
@@ -435,7 +431,7 @@ static int iommufd_device_auto_get_domain(struct iommufd_device *idev,
435
431
436
432
if (!iommufd_lock_obj (& hwpt -> obj ))
437
433
continue ;
438
- rc = iommufd_device_do_attach ( idev , hwpt );
434
+ rc = iommufd_hw_pagetable_attach ( hwpt , idev );
439
435
iommufd_put_object (& hwpt -> obj );
440
436
441
437
/*
@@ -445,6 +441,7 @@ static int iommufd_device_auto_get_domain(struct iommufd_device *idev,
445
441
*/
446
442
if (rc == - EINVAL )
447
443
continue ;
444
+ * pt_id = hwpt -> obj .id ;
448
445
goto out_unlock ;
449
446
}
450
447
@@ -454,6 +451,7 @@ static int iommufd_device_auto_get_domain(struct iommufd_device *idev,
454
451
goto out_unlock ;
455
452
}
456
453
hwpt -> auto_domain = true;
454
+ * pt_id = hwpt -> obj .id ;
457
455
458
456
mutex_unlock (& ioas -> mutex );
459
457
iommufd_object_finalize (idev -> ictx , & hwpt -> obj );
@@ -489,7 +487,7 @@ int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id)
489
487
struct iommufd_hw_pagetable * hwpt =
490
488
container_of (pt_obj , struct iommufd_hw_pagetable , obj );
491
489
492
- rc = iommufd_device_do_attach ( idev , hwpt );
490
+ rc = iommufd_hw_pagetable_attach ( hwpt , idev );
493
491
if (rc )
494
492
goto out_put_pt_obj ;
495
493
break ;
@@ -498,7 +496,7 @@ int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id)
498
496
struct iommufd_ioas * ioas =
499
497
container_of (pt_obj , struct iommufd_ioas , obj );
500
498
501
- rc = iommufd_device_auto_get_domain (idev , ioas );
499
+ rc = iommufd_device_auto_get_domain (idev , ioas , pt_id );
502
500
if (rc )
503
501
goto out_put_pt_obj ;
504
502
break ;
@@ -509,7 +507,6 @@ int iommufd_device_attach(struct iommufd_device *idev, u32 *pt_id)
509
507
}
510
508
511
509
refcount_inc (& idev -> obj .users );
512
- * pt_id = idev -> hwpt -> obj .id ;
513
510
rc = 0 ;
514
511
515
512
out_put_pt_obj :
@@ -527,14 +524,9 @@ EXPORT_SYMBOL_NS_GPL(iommufd_device_attach, IOMMUFD);
527
524
*/
528
525
void iommufd_device_detach (struct iommufd_device * idev )
529
526
{
530
- struct iommufd_hw_pagetable * hwpt = idev -> hwpt ;
531
-
532
- mutex_lock (& hwpt -> devices_lock );
533
- list_del (& idev -> devices_item );
534
- idev -> hwpt = NULL ;
535
- iommufd_hw_pagetable_detach (hwpt , idev );
536
- mutex_unlock (& hwpt -> devices_lock );
527
+ struct iommufd_hw_pagetable * hwpt ;
537
528
529
+ hwpt = iommufd_hw_pagetable_detach (idev );
538
530
if (hwpt -> auto_domain )
539
531
iommufd_object_destroy_user (idev -> ictx , & hwpt -> obj );
540
532
else
0 commit comments