diff options
Diffstat (limited to 'drivers/pci/intel-iommu.c')
-rw-r--r-- | drivers/pci/intel-iommu.c | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 505c1c7075f..6af6b628175 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/syscore_ops.h> | 39 | #include <linux/syscore_ops.h> |
40 | #include <linux/tboot.h> | 40 | #include <linux/tboot.h> |
41 | #include <linux/dmi.h> | 41 | #include <linux/dmi.h> |
42 | #include <linux/pci-ats.h> | ||
42 | #include <asm/cacheflush.h> | 43 | #include <asm/cacheflush.h> |
43 | #include <asm/iommu.h> | 44 | #include <asm/iommu.h> |
44 | #include "pci.h" | 45 | #include "pci.h" |
@@ -1299,7 +1300,7 @@ static void iommu_detach_domain(struct dmar_domain *domain, | |||
1299 | static struct iova_domain reserved_iova_list; | 1300 | static struct iova_domain reserved_iova_list; |
1300 | static struct lock_class_key reserved_rbtree_key; | 1301 | static struct lock_class_key reserved_rbtree_key; |
1301 | 1302 | ||
1302 | static void dmar_init_reserved_ranges(void) | 1303 | static int dmar_init_reserved_ranges(void) |
1303 | { | 1304 | { |
1304 | struct pci_dev *pdev = NULL; | 1305 | struct pci_dev *pdev = NULL; |
1305 | struct iova *iova; | 1306 | struct iova *iova; |
@@ -1313,8 +1314,10 @@ static void dmar_init_reserved_ranges(void) | |||
1313 | /* IOAPIC ranges shouldn't be accessed by DMA */ | 1314 | /* IOAPIC ranges shouldn't be accessed by DMA */ |
1314 | iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START), | 1315 | iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START), |
1315 | IOVA_PFN(IOAPIC_RANGE_END)); | 1316 | IOVA_PFN(IOAPIC_RANGE_END)); |
1316 | if (!iova) | 1317 | if (!iova) { |
1317 | printk(KERN_ERR "Reserve IOAPIC range failed\n"); | 1318 | printk(KERN_ERR "Reserve IOAPIC range failed\n"); |
1319 | return -ENODEV; | ||
1320 | } | ||
1318 | 1321 | ||
1319 | /* Reserve all PCI MMIO to avoid peer-to-peer access */ | 1322 | /* Reserve all PCI MMIO to avoid peer-to-peer access */ |
1320 | for_each_pci_dev(pdev) { | 1323 | for_each_pci_dev(pdev) { |
@@ -1327,11 +1330,13 @@ static void dmar_init_reserved_ranges(void) | |||
1327 | iova = reserve_iova(&reserved_iova_list, | 1330 | iova = reserve_iova(&reserved_iova_list, |
1328 | IOVA_PFN(r->start), | 1331 | IOVA_PFN(r->start), |
1329 | IOVA_PFN(r->end)); | 1332 | IOVA_PFN(r->end)); |
1330 | if (!iova) | 1333 | if (!iova) { |
1331 | printk(KERN_ERR "Reserve iova failed\n"); | 1334 | printk(KERN_ERR "Reserve iova failed\n"); |
1335 | return -ENODEV; | ||
1336 | } | ||
1332 | } | 1337 | } |
1333 | } | 1338 | } |
1334 | 1339 | return 0; | |
1335 | } | 1340 | } |
1336 | 1341 | ||
1337 | static void domain_reserve_special_ranges(struct dmar_domain *domain) | 1342 | static void domain_reserve_special_ranges(struct dmar_domain *domain) |
@@ -1835,7 +1840,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) | |||
1835 | 1840 | ||
1836 | ret = iommu_attach_domain(domain, iommu); | 1841 | ret = iommu_attach_domain(domain, iommu); |
1837 | if (ret) { | 1842 | if (ret) { |
1838 | domain_exit(domain); | 1843 | free_domain_mem(domain); |
1839 | goto error; | 1844 | goto error; |
1840 | } | 1845 | } |
1841 | 1846 | ||
@@ -2213,7 +2218,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw) | |||
2213 | return 0; | 2218 | return 0; |
2214 | } | 2219 | } |
2215 | 2220 | ||
2216 | int __init init_dmars(void) | 2221 | static int __init init_dmars(int force_on) |
2217 | { | 2222 | { |
2218 | struct dmar_drhd_unit *drhd; | 2223 | struct dmar_drhd_unit *drhd; |
2219 | struct dmar_rmrr_unit *rmrr; | 2224 | struct dmar_rmrr_unit *rmrr; |
@@ -2393,8 +2398,15 @@ int __init init_dmars(void) | |||
2393 | * enable translation | 2398 | * enable translation |
2394 | */ | 2399 | */ |
2395 | for_each_drhd_unit(drhd) { | 2400 | for_each_drhd_unit(drhd) { |
2396 | if (drhd->ignored) | 2401 | if (drhd->ignored) { |
2402 | /* | ||
2403 | * we always have to disable PMRs or DMA may fail on | ||
2404 | * this device | ||
2405 | */ | ||
2406 | if (force_on) | ||
2407 | iommu_disable_protect_mem_regions(drhd->iommu); | ||
2397 | continue; | 2408 | continue; |
2409 | } | ||
2398 | iommu = drhd->iommu; | 2410 | iommu = drhd->iommu; |
2399 | 2411 | ||
2400 | iommu_flush_write_buffer(iommu); | 2412 | iommu_flush_write_buffer(iommu); |
@@ -3240,9 +3252,15 @@ static int device_notifier(struct notifier_block *nb, | |||
3240 | if (!domain) | 3252 | if (!domain) |
3241 | return 0; | 3253 | return 0; |
3242 | 3254 | ||
3243 | if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) | 3255 | if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) { |
3244 | domain_remove_one_dev_info(domain, pdev); | 3256 | domain_remove_one_dev_info(domain, pdev); |
3245 | 3257 | ||
3258 | if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) && | ||
3259 | !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) && | ||
3260 | list_empty(&domain->devices)) | ||
3261 | domain_exit(domain); | ||
3262 | } | ||
3263 | |||
3246 | return 0; | 3264 | return 0; |
3247 | } | 3265 | } |
3248 | 3266 | ||
@@ -3277,12 +3295,21 @@ int __init intel_iommu_init(void) | |||
3277 | if (no_iommu || dmar_disabled) | 3295 | if (no_iommu || dmar_disabled) |
3278 | return -ENODEV; | 3296 | return -ENODEV; |
3279 | 3297 | ||
3280 | iommu_init_mempool(); | 3298 | if (iommu_init_mempool()) { |
3281 | dmar_init_reserved_ranges(); | 3299 | if (force_on) |
3300 | panic("tboot: Failed to initialize iommu memory\n"); | ||
3301 | return -ENODEV; | ||
3302 | } | ||
3303 | |||
3304 | if (dmar_init_reserved_ranges()) { | ||
3305 | if (force_on) | ||
3306 | panic("tboot: Failed to reserve iommu ranges\n"); | ||
3307 | return -ENODEV; | ||
3308 | } | ||
3282 | 3309 | ||
3283 | init_no_remapping_devices(); | 3310 | init_no_remapping_devices(); |
3284 | 3311 | ||
3285 | ret = init_dmars(); | 3312 | ret = init_dmars(force_on); |
3286 | if (ret) { | 3313 | if (ret) { |
3287 | if (force_on) | 3314 | if (force_on) |
3288 | panic("tboot: Failed to initialize DMARs\n"); | 3315 | panic("tboot: Failed to initialize DMARs\n"); |
@@ -3391,6 +3418,11 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, | |||
3391 | domain->iommu_count--; | 3418 | domain->iommu_count--; |
3392 | domain_update_iommu_cap(domain); | 3419 | domain_update_iommu_cap(domain); |
3393 | spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags); | 3420 | spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags); |
3421 | |||
3422 | spin_lock_irqsave(&iommu->lock, tmp_flags); | ||
3423 | clear_bit(domain->id, iommu->domain_ids); | ||
3424 | iommu->domains[domain->id] = NULL; | ||
3425 | spin_unlock_irqrestore(&iommu->lock, tmp_flags); | ||
3394 | } | 3426 | } |
3395 | 3427 | ||
3396 | spin_unlock_irqrestore(&device_domain_lock, flags); | 3428 | spin_unlock_irqrestore(&device_domain_lock, flags); |
@@ -3607,9 +3639,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, | |||
3607 | 3639 | ||
3608 | pte = dmar_domain->pgd; | 3640 | pte = dmar_domain->pgd; |
3609 | if (dma_pte_present(pte)) { | 3641 | if (dma_pte_present(pte)) { |
3610 | free_pgtable_page(dmar_domain->pgd); | ||
3611 | dmar_domain->pgd = (struct dma_pte *) | 3642 | dmar_domain->pgd = (struct dma_pte *) |
3612 | phys_to_virt(dma_pte_addr(pte)); | 3643 | phys_to_virt(dma_pte_addr(pte)); |
3644 | free_pgtable_page(pte); | ||
3613 | } | 3645 | } |
3614 | dmar_domain->agaw--; | 3646 | dmar_domain->agaw--; |
3615 | } | 3647 | } |