2008-11-22 12:59:19

by FUJITA Tomonori

[permalink] [raw]
Subject: [PATCH] IA64: fix VT-d dma_mapping_error

Hmm, IA64 VT-d dma_mapping_error() is broken?

=
Subject: [PATCH] IA64: fix VT-d dma_mapping_error
From: FUJITA Tomonori <[email protected]>

IA64 VT-d dma_mapping_error always says that the dma mapping is
successful even though intel_map_single() could fail.

VT-d uses X86 dependent dma_mapping_error() code. This patch adds
VT-d's own dma_mapping_error() that works for both X86_64 and IA64.

Signed-off-by: FUJITA Tomonori <[email protected]>
---
arch/ia64/dig/dig_vtd_iommu.c | 2 +-
drivers/pci/intel-iommu.c | 6 ++++++
include/linux/intel-iommu.h | 1 +
3 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/arch/ia64/dig/dig_vtd_iommu.c b/arch/ia64/dig/dig_vtd_iommu.c
index 1c8a079..e663eac 100644
--- a/arch/ia64/dig/dig_vtd_iommu.c
+++ b/arch/ia64/dig/dig_vtd_iommu.c
@@ -54,6 +54,6 @@ EXPORT_SYMBOL_GPL(vtd_unmap_sg_attrs);
int
vtd_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
- return 0;
+ return intel_dma_mapping_error(dev, dma_addr);
}
EXPORT_SYMBOL_GPL(vtd_dma_mapping_error);
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 5c8baa4..5289fc1 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -2157,6 +2157,11 @@ int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
return nelems;
}

+int intel_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
+{
+ return !dma_addr;
+}
+
static struct dma_mapping_ops intel_dma_ops = {
.alloc_coherent = intel_alloc_coherent,
.free_coherent = intel_free_coherent,
@@ -2164,6 +2169,7 @@ static struct dma_mapping_ops intel_dma_ops = {
.unmap_single = intel_unmap_single,
.map_sg = intel_map_sg,
.unmap_sg = intel_unmap_sg,
+ .mapping_error = intel_dma_mapping_error,
};

static inline int iommu_domain_cache_init(void)
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index 3d017cf..027e75e 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -359,5 +359,6 @@ extern dma_addr_t intel_map_single(struct device *, phys_addr_t, size_t, int);
extern void intel_unmap_single(struct device *, dma_addr_t, size_t, int);
extern int intel_map_sg(struct device *, struct scatterlist *, int, int);
extern void intel_unmap_sg(struct device *, struct scatterlist *, int, int);
+extern int intel_dma_mapping_error(struct device *, dma_addr_t);

#endif
--
1.5.6.5


2008-11-22 16:18:21

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH] IA64: fix VT-d dma_mapping_error


>+int intel_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
>+{
>+ return !dma_addr;
>+}

The implementation of inte_dma_mapping_error is incomplete.

Dma_addr is valid only when it belongs to hwdev's domain. This is all about VT-d isolation fundamental.

+int intel_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
+{
+ struct pci_dev *pdev = to_pci_dev(hwdev);
+ struct dmar_domain *domain;
+ struct iova *iova;
+
+ domain = find_domain(pdev);
+
+ iova = find_iova(&domain->iovad, IOVA_PFN(dma_addr));
+ if (!iova)
+ return -EINVAL;
+ return 0;
+}

2008-11-22 16:41:17

by FUJITA Tomonori

[permalink] [raw]
Subject: RE: [PATCH] IA64: fix VT-d dma_mapping_error

On Sat, 22 Nov 2008 08:18:02 -0800
"Yu, Fenghua" <[email protected]> wrote:

>
> >+int intel_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
> >+{
> >+ return !dma_addr;
> >+}
>
> The implementation of inte_dma_mapping_error is incomplete.
>
> Dma_addr is valid only when it belongs to hwdev's domain. This is all about VT-d isolation fundamental.
>
> +int intel_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr)
> +{
> + struct pci_dev *pdev = to_pci_dev(hwdev);
> + struct dmar_domain *domain;
> + struct iova *iova;
> +
> + domain = find_domain(pdev);
> +
> + iova = find_iova(&domain->iovad, IOVA_PFN(dma_addr));
> + if (!iova)
> + return -EINVAL;
> + return 0;
> +}

Hmm, intel_dma_mapping_error is used to test only the value that
intel_map_single() returns. If intel_map_single() returns a non-zero
dma address, it belongs to hwdev's domain. So intel_dma_mapping_error
can simply return 1 (failure) if the dma_addr is zero.

Do I misunderstand something?

2008-11-23 06:10:27

by Fenghua Yu

[permalink] [raw]
Subject: RE: [PATCH] IA64: fix VT-d dma_mapping_error

>Hmm, intel_dma_mapping_error is used to test only the value that
>intel_map_single() returns. If intel_map_single() returns a non-zero
>dma address, it belongs to hwdev's domain. So intel_dma_mapping_error
>can simply return 1 (failure) if the dma_addr is zero.

Then there is no usage of hwdev which is one of two parameters in intel_dma_mapping_error?

Maybe checking dma_addr only is good enough for the function? At least it's fast to check errors.

Thanks.

-Fenghua

2008-11-23 06:32:42

by FUJITA Tomonori

[permalink] [raw]
Subject: RE: [PATCH] IA64: fix VT-d dma_mapping_error

On Sat, 22 Nov 2008 22:10:05 -0800
"Yu, Fenghua" <[email protected]> wrote:

> >Hmm, intel_dma_mapping_error is used to test only the value that
> >intel_map_single() returns. If intel_map_single() returns a non-zero
> >dma address, it belongs to hwdev's domain. So intel_dma_mapping_error
> >can simply return 1 (failure) if the dma_addr is zero.
>
> Then there is no usage of hwdev which is one of two parameters in intel_dma_mapping_error?

Yes, and that's how VT-d dma_mapping_error() works on X86_64.

Note that we use hwdev in the following way, see
arch/x86/kernel/include/asm/dma-mapping.h

static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
#ifdef CONFIG_X86_32
return 0;
#else
struct dma_mapping_ops *ops = get_dma_ops(dev);
if (ops->mapping_error)
return ops->mapping_error(dev, dma_addr);

return (dma_addr == bad_dma_address);
#endif
}

dma_mapping_error uses a point to struct device to choose a proper
dma_mapping_ops.


> Maybe checking dma_addr only is good enough for the function? At least it's fast to check errors.

Yeah, that's what my patch does (and what x86 VT-d dma_mapping_error()
does).