Skip to content

Commit

Permalink
test: Add test for IOMMU uclass map/unmap ops
Browse files Browse the repository at this point in the history
Test that the map and unmap operations work for devices that
have DMA translated by an IOMMU and devices that don't have
DMA translated by an IOMMU.

Signed-off-by: Mark Kettenis <kettenis@openbsd.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
  • Loading branch information
kettenis authored and trini committed Jan 27, 2023
1 parent dd6b68e commit 49a1a4b
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 1 deletion.
58 changes: 58 additions & 0 deletions drivers/iommu/sandbox_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,61 @@

#include <common.h>
#include <dm.h>
#include <iommu.h>
#include <lmb.h>
#include <asm/io.h>
#include <linux/sizes.h>

#define IOMMU_PAGE_SIZE SZ_4K

struct sandbox_iommu_priv {
struct lmb lmb;
};

static dma_addr_t sandbox_iommu_map(struct udevice *dev, void *addr,
size_t size)
{
struct sandbox_iommu_priv *priv = dev_get_priv(dev);
phys_addr_t paddr, dva;
phys_size_t psize, off;

paddr = ALIGN_DOWN(virt_to_phys(addr), IOMMU_PAGE_SIZE);
off = virt_to_phys(addr) - paddr;
psize = ALIGN(size + off, IOMMU_PAGE_SIZE);

dva = lmb_alloc(&priv->lmb, psize, IOMMU_PAGE_SIZE);

return dva + off;
}

static void sandbox_iommu_unmap(struct udevice *dev, dma_addr_t addr,
size_t size)
{
struct sandbox_iommu_priv *priv = dev_get_priv(dev);
phys_addr_t dva;
phys_size_t psize;

dva = ALIGN_DOWN(addr, IOMMU_PAGE_SIZE);
psize = size + (addr - dva);
psize = ALIGN(psize, IOMMU_PAGE_SIZE);

lmb_free(&priv->lmb, dva, psize);
}

static struct iommu_ops sandbox_iommu_ops = {
.map = sandbox_iommu_map,
.unmap = sandbox_iommu_unmap,
};

static int sandbox_iommu_probe(struct udevice *dev)
{
struct sandbox_iommu_priv *priv = dev_get_priv(dev);

lmb_init(&priv->lmb);
lmb_add(&priv->lmb, 0x89abc000, SZ_16K);

return 0;
}

static const struct udevice_id sandbox_iommu_ids[] = {
{ .compatible = "sandbox,iommu" },
Expand All @@ -15,4 +70,7 @@ U_BOOT_DRIVER(sandbox_iommu) = {
.name = "sandbox_iommu",
.id = UCLASS_IOMMU,
.of_match = sandbox_iommu_ids,
.priv_auto = sizeof(struct sandbox_iommu_priv),
.ops = &sandbox_iommu_ops,
.probe = sandbox_iommu_probe,
};
44 changes: 43 additions & 1 deletion test/dm/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@
#include <dm/test.h>
#include <dm/uclass-internal.h>
#include <iommu.h>
#include <malloc.h>
#include <test/test.h>
#include <test/ut.h>
#include <asm/io.h>

static int dm_test_iommu(struct unit_test_state *uts)
{
struct udevice *dev;
dma_addr_t dva;
void *addr;

ut_assertok(uclass_find_device(UCLASS_IOMMU, 0, &dev));
ut_assert(!(dev_get_flags(dev) & DM_FLAG_ACTIVATED));
Expand All @@ -22,7 +26,45 @@ static int dm_test_iommu(struct unit_test_state *uts)
ut_assertok(uclass_probe_all(UCLASS_USB));
ut_assert(dev_get_flags(dev) & DM_FLAG_ACTIVATED);

addr = malloc(256);
ut_assert(addr);

ut_assertok(uclass_find_device(UCLASS_USB, 0, &dev));
dva = dev_iommu_dma_map(dev, addr, 256);
ut_assert(dva >= 0x89abc000 && dva < 0x89ac00000);

dev_iommu_dma_unmap(dev, dva, 256);

free(addr);

return 0;
}

DM_TEST(dm_test_iommu, UT_TESTF_SCAN_FDT);

static int dm_test_iommu_noiommu(struct unit_test_state *uts)
{
struct udevice *dev;
dma_addr_t dva;
void *addr;

ut_assertok(uclass_find_device(UCLASS_IOMMU, 0, &dev));
ut_assert(!(dev_get_flags(dev) & DM_FLAG_ACTIVATED));

/* Probing ethernet should not probe the IOMMU */
ut_assertok(uclass_probe_all(UCLASS_ETH));
ut_assert(!(dev_get_flags(dev) & DM_FLAG_ACTIVATED));

addr = malloc(256);
ut_assert(addr);

ut_assertok(uclass_find_device(UCLASS_ETH, 0, &dev));
dva = dev_iommu_dma_map(dev, addr, 256);
ut_assert(dva == virt_to_phys(addr));

dev_iommu_dma_unmap(dev, dva, 256);

free(addr);

return 0;
}
DM_TEST(dm_test_iommu_noiommu, UT_TESTF_SCAN_FDT);

0 comments on commit 49a1a4b

Please sign in to comment.