aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/amd_iommu_types.h1
-rw-r--r--arch/x86/kernel/amd_iommu.c37
2 files changed, 30 insertions, 8 deletions
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h
index 9eaa27b46860..434e90ed89c5 100644
--- a/arch/x86/include/asm/amd_iommu_types.h
+++ b/arch/x86/include/asm/amd_iommu_types.h
@@ -253,6 +253,7 @@ struct protection_domain {
253struct iommu_dev_data { 253struct iommu_dev_data {
254 struct device *alias; /* The Alias Device */ 254 struct device *alias; /* The Alias Device */
255 struct protection_domain *domain; /* Domain the device is bound to */ 255 struct protection_domain *domain; /* Domain the device is bound to */
256 atomic_t bind; /* Domain attach reverent count */
256}; 257};
257 258
258/* 259/*
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 3214e8806f95..f5db7d5e444e 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -152,6 +152,8 @@ static int iommu_init_device(struct device *dev)
152 if (pdev) 152 if (pdev)
153 dev_data->alias = &pdev->dev; 153 dev_data->alias = &pdev->dev;
154 154
155 atomic_set(&dev_data->bind, 0);
156
155 dev->archdata.iommu = dev_data; 157 dev->archdata.iommu = dev_data;
156 158
157 159
@@ -1403,10 +1405,13 @@ static int __attach_device(struct device *dev,
1403 return -EBUSY; 1405 return -EBUSY;
1404 1406
1405 /* Do real assignment */ 1407 /* Do real assignment */
1406 if (alias != devid && 1408 if (alias != devid) {
1407 alias_data->domain == NULL) { 1409 if (alias_data->domain == NULL) {
1408 alias_data->domain = domain; 1410 alias_data->domain = domain;
1409 set_dte_entry(alias, domain); 1411 set_dte_entry(alias, domain);
1412 }
1413
1414 atomic_inc(&alias_data->bind);
1410 } 1415 }
1411 1416
1412 if (dev_data->domain == NULL) { 1417 if (dev_data->domain == NULL) {
@@ -1414,6 +1419,8 @@ static int __attach_device(struct device *dev,
1414 set_dte_entry(devid, domain); 1419 set_dte_entry(devid, domain);
1415 } 1420 }
1416 1421
1422 atomic_inc(&dev_data->bind);
1423
1417 /* ready */ 1424 /* ready */
1418 spin_unlock(&domain->lock); 1425 spin_unlock(&domain->lock);
1419 1426
@@ -1449,20 +1456,34 @@ static int attach_device(struct device *dev,
1449 */ 1456 */
1450static void __detach_device(struct device *dev) 1457static void __detach_device(struct device *dev)
1451{ 1458{
1452 u16 devid = get_device_id(dev); 1459 u16 devid = get_device_id(dev), alias;
1453 struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; 1460 struct amd_iommu *iommu = amd_iommu_rlookup_table[devid];
1454 struct iommu_dev_data *dev_data = get_dev_data(dev); 1461 struct iommu_dev_data *dev_data = get_dev_data(dev);
1462 struct iommu_dev_data *alias_data;
1455 1463
1456 BUG_ON(!iommu); 1464 BUG_ON(!iommu);
1457 1465
1458 clear_dte_entry(devid); 1466 devid = get_device_id(dev);
1459 dev_data->domain = NULL; 1467 alias = get_device_id(dev_data->alias);
1468
1469 if (devid != alias) {
1470 alias_data = get_dev_data(dev_data->alias);
1471 if (atomic_dec_and_test(&alias_data->bind)) {
1472 clear_dte_entry(alias);
1473 alias_data->domain = NULL;
1474 }
1475 }
1476
1477 if (atomic_dec_and_test(&dev_data->bind)) {
1478 clear_dte_entry(devid);
1479 dev_data->domain = NULL;
1480 }
1460 1481
1461 /* 1482 /*
1462 * If we run in passthrough mode the device must be assigned to the 1483 * If we run in passthrough mode the device must be assigned to the
1463 * passthrough domain if it is detached from any other domain 1484 * passthrough domain if it is detached from any other domain
1464 */ 1485 */
1465 if (iommu_pass_through) 1486 if (iommu_pass_through && dev_data->domain == NULL)
1466 __attach_device(dev, pt_domain); 1487 __attach_device(dev, pt_domain);
1467} 1488}
1468 1489