From: kettenis Date: Thu, 25 Feb 2021 22:14:54 +0000 (+0000) Subject: Add a framework for IOMMUs. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=682b00ca823eee4a1cc0ac47a0ceb71d7c91153e;p=openbsd Add a framework for IOMMUs. ok patrick@ --- diff --git a/sys/dev/ofw/ofw_misc.c b/sys/dev/ofw/ofw_misc.c index b3019b8744e..32f239eddad 100644 --- a/sys/dev/ofw/ofw_misc.c +++ b/sys/dev/ofw/ofw_misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_misc.c,v 1.27 2020/11/30 17:57:36 kettenis Exp $ */ +/* $OpenBSD: ofw_misc.c,v 1.28 2021/02/25 22:14:54 kettenis Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -839,3 +839,95 @@ mii_byphandle(uint32_t phandle) return mii_bynode(node); } + +/* IOMMU support */ + +LIST_HEAD(, iommu_device) iommu_devices = + LIST_HEAD_INITIALIZER(iommu_devices); + +void +iommu_device_register(struct iommu_device *id) +{ + id->id_phandle = OF_getpropint(id->id_node, "phandle", 0); + if (id->id_phandle == 0) + return; + + LIST_INSERT_HEAD(&iommu_devices, id, id_list); +} + +bus_dma_tag_t +iommu_device_do_map(uint32_t phandle, uint32_t *cells, bus_dma_tag_t dmat) +{ + struct iommu_device *id; + + if (phandle == 0) + return dmat; + + LIST_FOREACH(id, &iommu_devices, id_list) { + if (id->id_phandle == phandle) + return id->id_map(id->id_cookie, cells, dmat); + } + + return dmat; +} + +bus_dma_tag_t +iommu_device_map_pci(int node, uint32_t rid, bus_dma_tag_t dmat) +{ + uint64_t sid_base, sid = 0; + uint32_t phandle = 0; + uint32_t *cell; + uint32_t *map; + uint32_t mask, rid_base; + uint32_t scells[2]; + int i, len, length, icells, ncells; + + len = OF_getproplen(node, "iommu-map"); + if (len <= 0) + return dmat; + + map = malloc(len, M_TEMP, M_WAITOK); + OF_getpropintarray(node, "iommu-map", map, len); + + mask = OF_getpropint(node, "msi-map-mask", 0xffff); + rid = rid & mask; + + cell = map; + ncells = len / sizeof(uint32_t); + while (ncells > 1) { + node = OF_getnodebyphandle(cell[1]); + if (node == 0) + goto out; + + icells = OF_getpropint(node, "#iommu-cells", 1); + if (ncells < icells + 3) + goto out; + + /* We support 64-bit stream IDs. */ + KASSERT(icells >= 1 && icells <= 2); + + rid_base = cell[0]; + length = cell[2 + icells]; + sid_base = cell[2]; + for (i = 1; i < icells; i++) { + sid_base <<= 32; + sid_base |= cell[2 + i]; + } + if (rid >= rid_base && rid < rid_base + length) { + sid = sid_base + (rid - rid_base); + phandle = cell[1]; + break; + } + + cell += (3 + icells); + ncells -= (3 + icells); + } + +out: + free(map, M_TEMP, len); + + /* Map stream ID back into cells. */ + scells[0] = sid >> 32; + scells[1] = sid & 0xffffffff; + return iommu_device_do_map(phandle, scells, dmat); +} diff --git a/sys/dev/ofw/ofw_misc.h b/sys/dev/ofw/ofw_misc.h index 48ad8e8356f..a0cc4cbbba9 100644 --- a/sys/dev/ofw/ofw_misc.h +++ b/sys/dev/ofw/ofw_misc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ofw_misc.h,v 1.17 2020/11/30 17:57:36 kettenis Exp $ */ +/* $OpenBSD: ofw_misc.h,v 1.18 2021/02/25 22:14:54 kettenis Exp $ */ /* * Copyright (c) 2017 Mark Kettenis * @@ -233,4 +233,18 @@ void mii_register(struct mii_bus *); struct mii_bus *mii_bynode(int); struct mii_bus *mii_byphandle(uint32_t); +/* IOMMU support */ + +struct iommu_device { + int id_node; + void *id_cookie; + bus_dma_tag_t (*id_map)(void *, uint32_t *, bus_dma_tag_t); + + LIST_ENTRY(iommu_device) id_list; + uint32_t id_phandle; +}; + +void iommu_device_register(struct iommu_device *); +bus_dma_tag_t iommu_device_map_pci(int, uint32_t, bus_dma_tag_t); + #endif /* _DEV_OFW_MISC_H_ */