diff options
| -rw-r--r-- | arch/x86/include/asm/amd_iommu_types.h | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/amd_iommu.c | 37 |
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 { | |||
| 253 | struct iommu_dev_data { | 253 | struct 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 | */ |
| 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 | ||
