@@ -19,11 +19,59 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
+
+#include "gk20a.h"
#include "mem.h"
#include "vmm.h"
+#include <nvkm/core/tegra.h>
#include <nvif/class.h>
+static void
+gk20a_mmu_ctor(const struct nvkm_mmu_func *func, struct nvkm_device *device,
+ int index, struct gk20a_mmu *mmu)
+{
+ struct iommu_domain *domain = iommu_get_domain_for_dev(device->dev);
+ struct nvkm_device_tegra *tegra = device->func->tegra(device);
+
+ nvkm_mmu_ctor(func, device, index, &mmu->base);
+
+ /*
+ * If the DMA API is backed by an IOMMU, make sure the IOMMU bit is
+ * set for all buffer accesses. If the IOMMU is explicitly used, it
+ * is only used for instance blocks and the MMU doesn't care, since
+ * buffer objects are only mapped through the MMU, not through the
+ * IOMMU.
+ *
+ * Big page support could be implemented using explicit IOMMU usage,
+ * but the DMA API already provides that for free, so we don't worry
+ * about it for now.
+ */
+ if (domain && !tegra->iommu.domain) {
+ mmu->iommu_mask = BIT_ULL(tegra->func->iommu_bit);
+ nvkm_debug(&mmu->base.subdev, "IOMMU mask: %llx\n",
+ mmu->iommu_mask);
+ }
+}
+
+int
+gk20a_mmu_new_(const struct nvkm_mmu_func *func, struct nvkm_device *device,
+ int index, struct nvkm_mmu **pmmu)
+{
+ struct gk20a_mmu *mmu;
+
+ mmu = kzalloc(sizeof(*mmu), GFP_KERNEL);
+ if (!mmu)
+ return -ENOMEM;
+
+ gk20a_mmu_ctor(func, device, index, mmu);
+
+ if (pmmu)
+ *pmmu = &mmu->base;
+
+ return 0;
+}
+
static const struct nvkm_mmu_func
gk20a_mmu = {
.dma_bits = 40,
@@ -37,5 +85,5 @@ gk20a_mmu = {
int
gk20a_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu)
{
- return nvkm_mmu_new_(&gk20a_mmu, device, index, pmmu);
+ return gk20a_mmu_new_(&gk20a_mmu, device, index, pmmu);
}
new file mode 100644
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 NVIDIA Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __NVKM_MMU_GK20A_H__
+#define __NVKM_MMU_GK20A_H__
+
+#include "priv.h"
+
+struct gk20a_mmu {
+ struct nvkm_mmu base;
+
+ /*
+ * If an IOMMU is used, indicates which address bit will trigger an
+ * IOMMU translation when set (when this bit is not set, the IOMMU is
+ * bypassed). A value of 0 means an IOMMU is never used.
+ */
+ u64 iommu_mask;
+};
+
+#define gk20a_mmu(mmu) container_of(mmu, struct gk20a_mmu, base)
+
+int gk20a_mmu_new_(const struct nvkm_mmu_func *, struct nvkm_device *,
+ int index, struct nvkm_mmu **);
+
+#endif
@@ -19,6 +19,8 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
+
+#include "gk20a.h"
#include "mem.h"
#include "vmm.h"
@@ -50,6 +52,6 @@ int
gm20b_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu)
{
if (device->fb->page)
- return nvkm_mmu_new_(&gm20b_mmu_fixed, device, index, pmmu);
- return nvkm_mmu_new_(&gm20b_mmu, device, index, pmmu);
+ return gk20a_mmu_new_(&gm20b_mmu_fixed, device, index, pmmu);
+ return gk20a_mmu_new_(&gm20b_mmu, device, index, pmmu);
}
@@ -19,6 +19,8 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
+
+#include "gk20a.h"
#include "mem.h"
#include "vmm.h"
@@ -41,5 +43,5 @@ gp10b_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu)
{
if (!nvkm_boolopt(device->cfgopt, "GP100MmuLayout", true))
return gm20b_mmu_new(device, index, pmmu);
- return nvkm_mmu_new_(&gp10b_mmu, device, index, pmmu);
+ return gk20a_mmu_new_(&gp10b_mmu, device, index, pmmu);
}
@@ -213,6 +213,7 @@ void gf100_vmm_invalidate(struct nvkm_vmm *, u32 type);
void gf100_vmm_invalidate_pdb(struct nvkm_vmm *, u64 addr);
int gk20a_vmm_aper(enum nvkm_memory_target);
+int gk20a_vmm_valid(struct nvkm_vmm *, void *, u32, struct nvkm_vmm_map *);
int gm200_vmm_new_(const struct nvkm_vmm_func *, const struct nvkm_vmm_func *,
struct nvkm_mmu *, bool, u64, u64, void *, u32,
@@ -19,6 +19,8 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
+
+#include "gk20a.h"
#include "vmm.h"
#include <core/memory.h>
@@ -33,12 +35,28 @@ gk20a_vmm_aper(enum nvkm_memory_target target)
}
}
+int
+gk20a_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
+ struct nvkm_vmm_map *map)
+{
+ struct gk20a_mmu *mmu = gk20a_mmu(vmm->mmu);
+ int ret;
+
+ ret = gf100_vmm_valid(vmm, argv, argc, map);
+ if (ret < 0)
+ return ret;
+
+ map->type |= mmu->iommu_mask >> 8;
+
+ return 0;
+}
+
static const struct nvkm_vmm_func
gk20a_vmm_17 = {
.join = gf100_vmm_join,
.part = gf100_vmm_part,
.aper = gf100_vmm_aper,
- .valid = gf100_vmm_valid,
+ .valid = gk20a_vmm_valid,
.flush = gf100_vmm_flush,
.invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
@@ -53,7 +71,7 @@ gk20a_vmm_16 = {
.join = gf100_vmm_join,
.part = gf100_vmm_part,
.aper = gf100_vmm_aper,
- .valid = gf100_vmm_valid,
+ .valid = gk20a_vmm_valid,
.flush = gf100_vmm_flush,
.invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
@@ -26,7 +26,7 @@ gm20b_vmm_17 = {
.join = gm200_vmm_join,
.part = gf100_vmm_part,
.aper = gk20a_vmm_aper,
- .valid = gf100_vmm_valid,
+ .valid = gk20a_vmm_valid,
.flush = gf100_vmm_flush,
.invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
@@ -42,7 +42,7 @@ gm20b_vmm_16 = {
.join = gm200_vmm_join,
.part = gf100_vmm_part,
.aper = gk20a_vmm_aper,
- .valid = gf100_vmm_valid,
+ .valid = gk20a_vmm_valid,
.flush = gf100_vmm_flush,
.invalidate_pdb = gf100_vmm_invalidate_pdb,
.page = {
@@ -19,14 +19,32 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
+
+#include "gk20a.h"
#include "vmm.h"
+static int
+gp10b_vmm_valid(struct nvkm_vmm *vmm, void *argv, u32 argc,
+ struct nvkm_vmm_map *map)
+{
+ struct gk20a_mmu *mmu = gk20a_mmu(vmm->mmu);
+ int ret;
+
+ ret = gp100_vmm_valid(vmm, argv, argc, map);
+ if (ret < 0)
+ return ret;
+
+ map->type |= mmu->iommu_mask >> 4;
+
+ return 0;
+}
+
static const struct nvkm_vmm_func
gp10b_vmm = {
.join = gp100_vmm_join,
.part = gf100_vmm_part,
.aper = gk20a_vmm_aper,
- .valid = gp100_vmm_valid,
+ .valid = gp10b_vmm_valid,
.flush = gp100_vmm_flush,
.mthd = gp100_vmm_mthd,
.invalidate_pdb = gp100_vmm_invalidate_pdb,