| From foo@baz Tue Feb 2 02:03:57 PM CET 2021 |
| From: Filippo Sironi <sironi@amazon.de> |
| Date: Tue, 2 Feb 2021 01:09:36 +0100 |
| Subject: iommu/vt-d: Gracefully handle DMAR units with no supported address widths |
| To: <gregkh@linuxfoundation.org> |
| Cc: <stable@vger.kernel.org>, <samjonas@amazon.com>, <dwmw@amazon.co.uk>, <sironi@amazon.de>, Joerg Roedel <jroedel@suse.de> |
| Message-ID: <20210202000937.2151-1-sironi@amazon.de> |
| |
| From: David Woodhouse <dwmw@amazon.co.uk> |
| |
| commit c40aaaac1018ff1382f2d35df5129a6bcea3df6b upstream. |
| |
| Instead of bailing out completely, such a unit can still be used for |
| interrupt remapping. |
| |
| Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> |
| Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> |
| Link: https://lore.kernel.org/linux-iommu/549928db2de6532117f36c9c810373c14cf76f51.camel@infradead.org/ |
| Signed-off-by: Joerg Roedel <jroedel@suse.de> |
| [ - context change due to moving drivers/iommu/dmar.c to |
| drivers/iommu/intel/dmar.c |
| - remove the unused err_unmap label |
| - use iommu->iommu_dev instead of iommu->iommu.ops to decide whether |
| when freeing ] |
| Signed-off-by: Filippo Sironi <sironi@amazon.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/iommu/dmar.c | 44 +++++++++++++++++++++++++++----------------- |
| 1 file changed, 27 insertions(+), 17 deletions(-) |
| |
| --- a/drivers/iommu/dmar.c |
| +++ b/drivers/iommu/dmar.c |
| @@ -1012,8 +1012,8 @@ static int alloc_iommu(struct dmar_drhd_ |
| { |
| struct intel_iommu *iommu; |
| u32 ver, sts; |
| - int agaw = 0; |
| - int msagaw = 0; |
| + int agaw = -1; |
| + int msagaw = -1; |
| int err; |
| |
| if (!drhd->reg_base_addr) { |
| @@ -1038,17 +1038,28 @@ static int alloc_iommu(struct dmar_drhd_ |
| } |
| |
| err = -EINVAL; |
| - agaw = iommu_calculate_agaw(iommu); |
| - if (agaw < 0) { |
| - pr_err("Cannot get a valid agaw for iommu (seq_id = %d)\n", |
| - iommu->seq_id); |
| - goto err_unmap; |
| - } |
| - msagaw = iommu_calculate_max_sagaw(iommu); |
| - if (msagaw < 0) { |
| - pr_err("Cannot get a valid max agaw for iommu (seq_id = %d)\n", |
| - iommu->seq_id); |
| - goto err_unmap; |
| + if (cap_sagaw(iommu->cap) == 0) { |
| + pr_info("%s: No supported address widths. Not attempting DMA translation.\n", |
| + iommu->name); |
| + drhd->ignored = 1; |
| + } |
| + |
| + if (!drhd->ignored) { |
| + agaw = iommu_calculate_agaw(iommu); |
| + if (agaw < 0) { |
| + pr_err("Cannot get a valid agaw for iommu (seq_id = %d)\n", |
| + iommu->seq_id); |
| + drhd->ignored = 1; |
| + } |
| + } |
| + if (!drhd->ignored) { |
| + msagaw = iommu_calculate_max_sagaw(iommu); |
| + if (msagaw < 0) { |
| + pr_err("Cannot get a valid max agaw for iommu (seq_id = %d)\n", |
| + iommu->seq_id); |
| + drhd->ignored = 1; |
| + agaw = -1; |
| + } |
| } |
| iommu->agaw = agaw; |
| iommu->msagaw = msagaw; |
| @@ -1077,15 +1088,13 @@ static int alloc_iommu(struct dmar_drhd_ |
| |
| drhd->iommu = iommu; |
| |
| - if (intel_iommu_enabled) |
| + if (intel_iommu_enabled && !drhd->ignored) |
| iommu->iommu_dev = iommu_device_create(NULL, iommu, |
| intel_iommu_groups, |
| "%s", iommu->name); |
| |
| return 0; |
| |
| -err_unmap: |
| - unmap_iommu(iommu); |
| error_free_seq_id: |
| dmar_free_seq_id(iommu); |
| error: |
| @@ -1095,7 +1104,8 @@ error: |
| |
| static void free_iommu(struct intel_iommu *iommu) |
| { |
| - iommu_device_destroy(iommu->iommu_dev); |
| + if (intel_iommu_enabled && iommu->iommu_dev) |
| + iommu_device_destroy(iommu->iommu_dev); |
| |
| if (iommu->irq) { |
| if (iommu->pr_irq) { |