diff options
author | Jiang Liu <jiang.liu@linux.intel.com> | 2014-01-06 01:18:27 -0500 |
---|---|---|
committer | Joerg Roedel <joro@8bytes.org> | 2014-01-09 06:44:30 -0500 |
commit | 9bdc531ec63bf894c5e3b7b5a766ce342eb2f52e (patch) | |
tree | 39facee7d5df268b651c5ec1b877313185c955bc | |
parent | b707cb027edf5b7ff1b8637c184b9a58d74e5159 (diff) |
iommu/vt-d: free all resources if failed to initialize DMARs
Enhance intel_iommu_init() to free all resources if failed to
initialize DMAR hardware.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Signed-off-by: Joerg Roedel <joro@8bytes.org>
-rw-r--r-- | drivers/iommu/intel-iommu.c | 81 |
1 files changed, 49 insertions, 32 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 948c6a0d0f5a..5ac7efc70ca9 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c | |||
@@ -2624,6 +2624,7 @@ static int __init init_dmars(void) | |||
2624 | error: | 2624 | error: |
2625 | for_each_active_iommu(iommu, drhd) | 2625 | for_each_active_iommu(iommu, drhd) |
2626 | free_dmar_iommu(iommu); | 2626 | free_dmar_iommu(iommu); |
2627 | kfree(deferred_flush); | ||
2627 | kfree(g_iommus); | 2628 | kfree(g_iommus); |
2628 | return ret; | 2629 | return ret; |
2629 | } | 2630 | } |
@@ -3467,18 +3468,12 @@ static int __init | |||
3467 | rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) | 3468 | rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) |
3468 | { | 3469 | { |
3469 | struct acpi_dmar_reserved_memory *rmrr; | 3470 | struct acpi_dmar_reserved_memory *rmrr; |
3470 | int ret; | ||
3471 | 3471 | ||
3472 | rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; | 3472 | rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; |
3473 | ret = dmar_parse_dev_scope((void *)(rmrr + 1), | 3473 | return dmar_parse_dev_scope((void *)(rmrr + 1), |
3474 | ((void *)rmrr) + rmrr->header.length, | 3474 | ((void *)rmrr) + rmrr->header.length, |
3475 | &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); | 3475 | &rmrru->devices_cnt, &rmrru->devices, |
3476 | 3476 | rmrr->segment); | |
3477 | if (ret || (rmrru->devices_cnt == 0)) { | ||
3478 | list_del(&rmrru->list); | ||
3479 | kfree(rmrru); | ||
3480 | } | ||
3481 | return ret; | ||
3482 | } | 3477 | } |
3483 | 3478 | ||
3484 | static LIST_HEAD(dmar_atsr_units); | 3479 | static LIST_HEAD(dmar_atsr_units); |
@@ -3503,23 +3498,39 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr) | |||
3503 | 3498 | ||
3504 | static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) | 3499 | static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru) |
3505 | { | 3500 | { |
3506 | int rc; | ||
3507 | struct acpi_dmar_atsr *atsr; | 3501 | struct acpi_dmar_atsr *atsr; |
3508 | 3502 | ||
3509 | if (atsru->include_all) | 3503 | if (atsru->include_all) |
3510 | return 0; | 3504 | return 0; |
3511 | 3505 | ||
3512 | atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); | 3506 | atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header); |
3513 | rc = dmar_parse_dev_scope((void *)(atsr + 1), | 3507 | return dmar_parse_dev_scope((void *)(atsr + 1), |
3514 | (void *)atsr + atsr->header.length, | 3508 | (void *)atsr + atsr->header.length, |
3515 | &atsru->devices_cnt, &atsru->devices, | 3509 | &atsru->devices_cnt, &atsru->devices, |
3516 | atsr->segment); | 3510 | atsr->segment); |
3517 | if (rc || !atsru->devices_cnt) { | 3511 | } |
3518 | list_del(&atsru->list); | 3512 | |
3519 | kfree(atsru); | 3513 | static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru) |
3514 | { | ||
3515 | dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt); | ||
3516 | kfree(atsru); | ||
3517 | } | ||
3518 | |||
3519 | static void intel_iommu_free_dmars(void) | ||
3520 | { | ||
3521 | struct dmar_rmrr_unit *rmrru, *rmrr_n; | ||
3522 | struct dmar_atsr_unit *atsru, *atsr_n; | ||
3523 | |||
3524 | list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) { | ||
3525 | list_del(&rmrru->list); | ||
3526 | dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt); | ||
3527 | kfree(rmrru); | ||
3520 | } | 3528 | } |
3521 | 3529 | ||
3522 | return rc; | 3530 | list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) { |
3531 | list_del(&atsru->list); | ||
3532 | intel_iommu_free_atsr(atsru); | ||
3533 | } | ||
3523 | } | 3534 | } |
3524 | 3535 | ||
3525 | int dmar_find_matched_atsr_unit(struct pci_dev *dev) | 3536 | int dmar_find_matched_atsr_unit(struct pci_dev *dev) |
@@ -3563,17 +3574,17 @@ found: | |||
3563 | 3574 | ||
3564 | int __init dmar_parse_rmrr_atsr_dev(void) | 3575 | int __init dmar_parse_rmrr_atsr_dev(void) |
3565 | { | 3576 | { |
3566 | struct dmar_rmrr_unit *rmrr, *rmrr_n; | 3577 | struct dmar_rmrr_unit *rmrr; |
3567 | struct dmar_atsr_unit *atsr, *atsr_n; | 3578 | struct dmar_atsr_unit *atsr; |
3568 | int ret = 0; | 3579 | int ret = 0; |
3569 | 3580 | ||
3570 | list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) { | 3581 | list_for_each_entry(rmrr, &dmar_rmrr_units, list) { |
3571 | ret = rmrr_parse_dev(rmrr); | 3582 | ret = rmrr_parse_dev(rmrr); |
3572 | if (ret) | 3583 | if (ret) |
3573 | return ret; | 3584 | return ret; |
3574 | } | 3585 | } |
3575 | 3586 | ||
3576 | list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) { | 3587 | list_for_each_entry(atsr, &dmar_atsr_units, list) { |
3577 | ret = atsr_parse_dev(atsr); | 3588 | ret = atsr_parse_dev(atsr); |
3578 | if (ret) | 3589 | if (ret) |
3579 | return ret; | 3590 | return ret; |
@@ -3620,7 +3631,7 @@ static struct notifier_block device_nb = { | |||
3620 | 3631 | ||
3621 | int __init intel_iommu_init(void) | 3632 | int __init intel_iommu_init(void) |
3622 | { | 3633 | { |
3623 | int ret = 0; | 3634 | int ret = -ENODEV; |
3624 | struct dmar_drhd_unit *drhd; | 3635 | struct dmar_drhd_unit *drhd; |
3625 | struct intel_iommu *iommu; | 3636 | struct intel_iommu *iommu; |
3626 | 3637 | ||
@@ -3630,7 +3641,7 @@ int __init intel_iommu_init(void) | |||
3630 | if (dmar_table_init()) { | 3641 | if (dmar_table_init()) { |
3631 | if (force_on) | 3642 | if (force_on) |
3632 | panic("tboot: Failed to initialize DMAR table\n"); | 3643 | panic("tboot: Failed to initialize DMAR table\n"); |
3633 | return -ENODEV; | 3644 | goto out_free_dmar; |
3634 | } | 3645 | } |
3635 | 3646 | ||
3636 | /* | 3647 | /* |
@@ -3643,16 +3654,16 @@ int __init intel_iommu_init(void) | |||
3643 | if (dmar_dev_scope_init() < 0) { | 3654 | if (dmar_dev_scope_init() < 0) { |
3644 | if (force_on) | 3655 | if (force_on) |
3645 | panic("tboot: Failed to initialize DMAR device scope\n"); | 3656 | panic("tboot: Failed to initialize DMAR device scope\n"); |
3646 | return -ENODEV; | 3657 | goto out_free_dmar; |
3647 | } | 3658 | } |
3648 | 3659 | ||
3649 | if (no_iommu || dmar_disabled) | 3660 | if (no_iommu || dmar_disabled) |
3650 | return -ENODEV; | 3661 | goto out_free_dmar; |
3651 | 3662 | ||
3652 | if (iommu_init_mempool()) { | 3663 | if (iommu_init_mempool()) { |
3653 | if (force_on) | 3664 | if (force_on) |
3654 | panic("tboot: Failed to initialize iommu memory\n"); | 3665 | panic("tboot: Failed to initialize iommu memory\n"); |
3655 | return -ENODEV; | 3666 | goto out_free_dmar; |
3656 | } | 3667 | } |
3657 | 3668 | ||
3658 | if (list_empty(&dmar_rmrr_units)) | 3669 | if (list_empty(&dmar_rmrr_units)) |
@@ -3664,7 +3675,7 @@ int __init intel_iommu_init(void) | |||
3664 | if (dmar_init_reserved_ranges()) { | 3675 | if (dmar_init_reserved_ranges()) { |
3665 | if (force_on) | 3676 | if (force_on) |
3666 | panic("tboot: Failed to reserve iommu ranges\n"); | 3677 | panic("tboot: Failed to reserve iommu ranges\n"); |
3667 | return -ENODEV; | 3678 | goto out_free_mempool; |
3668 | } | 3679 | } |
3669 | 3680 | ||
3670 | init_no_remapping_devices(); | 3681 | init_no_remapping_devices(); |
@@ -3674,9 +3685,7 @@ int __init intel_iommu_init(void) | |||
3674 | if (force_on) | 3685 | if (force_on) |
3675 | panic("tboot: Failed to initialize DMARs\n"); | 3686 | panic("tboot: Failed to initialize DMARs\n"); |
3676 | printk(KERN_ERR "IOMMU: dmar init failed\n"); | 3687 | printk(KERN_ERR "IOMMU: dmar init failed\n"); |
3677 | put_iova_domain(&reserved_iova_list); | 3688 | goto out_free_reserved_range; |
3678 | iommu_exit_mempool(); | ||
3679 | return ret; | ||
3680 | } | 3689 | } |
3681 | printk(KERN_INFO | 3690 | printk(KERN_INFO |
3682 | "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n"); | 3691 | "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n"); |
@@ -3696,6 +3705,14 @@ int __init intel_iommu_init(void) | |||
3696 | intel_iommu_enabled = 1; | 3705 | intel_iommu_enabled = 1; |
3697 | 3706 | ||
3698 | return 0; | 3707 | return 0; |
3708 | |||
3709 | out_free_reserved_range: | ||
3710 | put_iova_domain(&reserved_iova_list); | ||
3711 | out_free_mempool: | ||
3712 | iommu_exit_mempool(); | ||
3713 | out_free_dmar: | ||
3714 | intel_iommu_free_dmars(); | ||
3715 | return ret; | ||
3699 | } | 3716 | } |
3700 | 3717 | ||
3701 | static void iommu_detach_dependent_devices(struct intel_iommu *iommu, | 3718 | static void iommu_detach_dependent_devices(struct intel_iommu *iommu, |