@@ -1877,6 +1877,7 @@ static struct dmar_domain *alloc_domain(int flags)
1877
1877
domain -> flags |= DOMAIN_FLAG_USE_FIRST_LEVEL ;
1878
1878
domain -> has_iotlb_device = false;
1879
1879
INIT_LIST_HEAD (& domain -> devices );
1880
+ INIT_LIST_HEAD (& domain -> subdevices );
1880
1881
1881
1882
return domain ;
1882
1883
}
@@ -2547,7 +2548,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
2547
2548
info -> iommu = iommu ;
2548
2549
info -> pasid_table = NULL ;
2549
2550
info -> auxd_enabled = 0 ;
2550
- INIT_LIST_HEAD (& info -> auxiliary_domains );
2551
+ INIT_LIST_HEAD (& info -> subdevices );
2551
2552
2552
2553
if (dev && dev_is_pci (dev )) {
2553
2554
struct pci_dev * pdev = to_pci_dev (info -> dev );
@@ -4475,33 +4476,61 @@ is_aux_domain(struct device *dev, struct iommu_domain *domain)
4475
4476
domain -> type == IOMMU_DOMAIN_UNMANAGED ;
4476
4477
}
4477
4478
4478
- static void auxiliary_link_device (struct dmar_domain * domain ,
4479
- struct device * dev )
4479
+ static inline struct subdev_domain_info *
4480
+ lookup_subdev_info (struct dmar_domain * domain , struct device * dev )
4481
+ {
4482
+ struct subdev_domain_info * sinfo ;
4483
+
4484
+ if (!list_empty (& domain -> subdevices )) {
4485
+ list_for_each_entry (sinfo , & domain -> subdevices , link_domain ) {
4486
+ if (sinfo -> pdev == dev )
4487
+ return sinfo ;
4488
+ }
4489
+ }
4490
+
4491
+ return NULL ;
4492
+ }
4493
+
4494
+ static int auxiliary_link_device (struct dmar_domain * domain ,
4495
+ struct device * dev )
4480
4496
{
4481
4497
struct device_domain_info * info = get_domain_info (dev );
4498
+ struct subdev_domain_info * sinfo = lookup_subdev_info (domain , dev );
4482
4499
4483
4500
assert_spin_locked (& device_domain_lock );
4484
4501
if (WARN_ON (!info ))
4485
- return ;
4502
+ return - EINVAL ;
4503
+
4504
+ if (!sinfo ) {
4505
+ sinfo = kzalloc (sizeof (* sinfo ), GFP_ATOMIC );
4506
+ sinfo -> domain = domain ;
4507
+ sinfo -> pdev = dev ;
4508
+ list_add (& sinfo -> link_phys , & info -> subdevices );
4509
+ list_add (& sinfo -> link_domain , & domain -> subdevices );
4510
+ }
4486
4511
4487
- domain -> auxd_refcnt ++ ;
4488
- list_add (& domain -> auxd , & info -> auxiliary_domains );
4512
+ return ++ sinfo -> users ;
4489
4513
}
4490
4514
4491
- static void auxiliary_unlink_device (struct dmar_domain * domain ,
4492
- struct device * dev )
4515
+ static int auxiliary_unlink_device (struct dmar_domain * domain ,
4516
+ struct device * dev )
4493
4517
{
4494
4518
struct device_domain_info * info = get_domain_info (dev );
4519
+ struct subdev_domain_info * sinfo = lookup_subdev_info (domain , dev );
4520
+ int ret ;
4495
4521
4496
4522
assert_spin_locked (& device_domain_lock );
4497
- if (WARN_ON (!info ))
4498
- return ;
4523
+ if (WARN_ON (!info || ! sinfo || sinfo -> users <= 0 ))
4524
+ return - EINVAL ;
4499
4525
4500
- list_del (& domain -> auxd );
4501
- domain -> auxd_refcnt -- ;
4526
+ ret = -- sinfo -> users ;
4527
+ if (!ret ) {
4528
+ list_del (& sinfo -> link_phys );
4529
+ list_del (& sinfo -> link_domain );
4530
+ kfree (sinfo );
4531
+ }
4502
4532
4503
- if (!domain -> auxd_refcnt && domain -> default_pasid > 0 )
4504
- ioasid_put (domain -> default_pasid );
4533
+ return ret ;
4505
4534
}
4506
4535
4507
4536
static int aux_domain_add_dev (struct dmar_domain * domain ,
@@ -4530,6 +4559,19 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
4530
4559
}
4531
4560
4532
4561
spin_lock_irqsave (& device_domain_lock , flags );
4562
+ ret = auxiliary_link_device (domain , dev );
4563
+ if (ret <= 0 )
4564
+ goto link_failed ;
4565
+
4566
+ /*
4567
+ * Subdevices from the same physical device can be attached to the
4568
+ * same domain. For such cases, only the first subdevice attachment
4569
+ * needs to go through the full steps in this function. So if ret >
4570
+ * 1, just goto out.
4571
+ */
4572
+ if (ret > 1 )
4573
+ goto out ;
4574
+
4533
4575
/*
4534
4576
* iommu->lock must be held to attach domain to iommu and setup the
4535
4577
* pasid entry for second level translation.
@@ -4548,10 +4590,9 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
4548
4590
domain -> default_pasid );
4549
4591
if (ret )
4550
4592
goto table_failed ;
4551
- spin_unlock (& iommu -> lock );
4552
-
4553
- auxiliary_link_device (domain , dev );
4554
4593
4594
+ spin_unlock (& iommu -> lock );
4595
+ out :
4555
4596
spin_unlock_irqrestore (& device_domain_lock , flags );
4556
4597
4557
4598
return 0 ;
@@ -4560,8 +4601,10 @@ static int aux_domain_add_dev(struct dmar_domain *domain,
4560
4601
domain_detach_iommu (domain , iommu );
4561
4602
attach_failed :
4562
4603
spin_unlock (& iommu -> lock );
4604
+ auxiliary_unlink_device (domain , dev );
4605
+ link_failed :
4563
4606
spin_unlock_irqrestore (& device_domain_lock , flags );
4564
- if (! domain -> auxd_refcnt && domain -> default_pasid > 0 )
4607
+ if (list_empty ( & domain -> subdevices ) && domain -> default_pasid > 0 )
4565
4608
ioasid_put (domain -> default_pasid );
4566
4609
4567
4610
return ret ;
@@ -4581,14 +4624,18 @@ static void aux_domain_remove_dev(struct dmar_domain *domain,
4581
4624
info = get_domain_info (dev );
4582
4625
iommu = info -> iommu ;
4583
4626
4584
- auxiliary_unlink_device (domain , dev );
4585
-
4586
- spin_lock (& iommu -> lock );
4587
- intel_pasid_tear_down_entry (iommu , dev , domain -> default_pasid , false);
4588
- domain_detach_iommu (domain , iommu );
4589
- spin_unlock (& iommu -> lock );
4627
+ if (!auxiliary_unlink_device (domain , dev )) {
4628
+ spin_lock (& iommu -> lock );
4629
+ intel_pasid_tear_down_entry (iommu , dev ,
4630
+ domain -> default_pasid , false);
4631
+ domain_detach_iommu (domain , iommu );
4632
+ spin_unlock (& iommu -> lock );
4633
+ }
4590
4634
4591
4635
spin_unlock_irqrestore (& device_domain_lock , flags );
4636
+
4637
+ if (list_empty (& domain -> subdevices ) && domain -> default_pasid > 0 )
4638
+ ioasid_put (domain -> default_pasid );
4592
4639
}
4593
4640
4594
4641
static int prepare_domain_attach_device (struct iommu_domain * domain ,
0 commit comments