diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2009-11-25 09:59:57 -0500 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2009-11-27 08:20:33 -0500 |
commit | 241000556f751dacd332df6ab2e903a23746e51e (patch) | |
tree | b3dad45997c5e3c9eb754901e24dbca9c959852a /arch/x86/kernel/amd_iommu.c | |
parent | 657cbb6b6cba0f9c98c5299e0c803b2c0e67ea0a (diff) |
x86/amd-iommu: Add device bind reference counting
This patch adds a reference count to each device to count
how often the device was bound to that domain. This is
important for single devices that act as an alias for a
number of others. These devices must stay bound to their
domains until all devices that alias to it are unbound from
the same domain.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'arch/x86/kernel/amd_iommu.c')
-rw-r--r-- | arch/x86/kernel/amd_iommu.c | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index 3214e8806f9..f5db7d5e444 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 | */ |
1450 | static void __detach_device(struct device *dev) | 1457 | static 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 | ||