From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E4D0AFCC9A5 for ; Tue, 10 Mar 2026 00:50:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=WsjHSh34KgXR35GQwX8Ip7EOE1YJW1p6E2+i8GrhIQc=; b=31HQyFJNgIW85H vSPviMEmG6P+N5RcpC/wL8QgP+VUqtvc3G1P9YQpVdZaL+4xCxhMP+FkaIXRyEN2t/EjlGeWH23Dn ISC4/kNhfYrHDLZxv2uPZC12cfwQl+J35omrdWheFSNsOy/85g62ksCj6j1epGrGczzGEWg0dWfWO CjRJWeMlTsTcRHdamWbpIJmE3Ox3kL4D8XiEpB70FutI+ibrst9AIQMayA6yoeLI51dgKRQOlJZnP IepbwlGIgCQ8bT2/UIUowcEnAUGQZc7sYwFFQrd5PvdG/xQc3wFjytwVInGZvfq9EohzRkyuNnjZ3 3wU+RByLNcBCt0zLsN3w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) id 1vzlJA-00000008QQQ-1UOz; Tue, 10 Mar 2026 00:50:48 +0000 Received: from mail-pf1-x42a.google.com ([2607:f8b0:4864:20::42a]) by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) id 1vzlJ7-00000008QOs-29Br for opensbi@lists.infradead.org; Tue, 10 Mar 2026 00:50:46 +0000 Received: by mail-pf1-x42a.google.com with SMTP id d2e1a72fcca58-823c56765fdso6086093b3a.1 for ; Mon, 09 Mar 2026 17:50:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773103844; x=1773708644; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=TlndCJhBqKVcC5WGOOvGVMD6gdqPNPkYZnLPJPEHnZg=; b=VKuMtBBd5x9Kj8X51AuVK24epSQhoq1vYNdrjdeyjc68xeu0QZ1grjRNKKGFO3HbCY UJTuv5lrF1zN71KbKtahWDdkxr491Z5K8sq0UY7/HqbvTAaTwRJII+5OOqgI3LF4XerB 7SN08QZObzisLMTTFz+2gTfFrVk3iRha93u0T8WR/v7kmybGjIVXqeiFVtlRA6GUlzuc H26s9DFq2iYwzGbFjkNvP1fVwloOOP/uFd/s97LNWlDVfq2j0fbQJpKiLBoYlTTVK9Od ez5KjIHK0D/7irMqiYO9J1soXb/7tWO+yuNfkBAUXEDEUQrCI0jFYaBlL8OojuqQ0R/j QQmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773103844; x=1773708644; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=TlndCJhBqKVcC5WGOOvGVMD6gdqPNPkYZnLPJPEHnZg=; b=DVvtWo3G1TBYrP0iJCbM+KGyKzg04D7BZk9XOyMQEnULH3oP3FszGzdt8BjFOsmVcc T0hiXsVA2bHtmKlTL/kWWx7lz27jYdUm0qekEgtK9QK3d4j6XS3RLdY1VrHbV1wwK7ho Zw6/JVGFyPYSVxAP1aIwHLSClteIKm8iwwyFzcAMQTbfqsJSgLLsJxwgw0fdaEbfTo1z +odpmSJSFe317hd7Rjh0zaUpVbPveWFrHTm3ekyiPVKvDovj7LwkHZG4v4hv8FcWzxRU b51+vC8dzAB41hYQM40MPp8WSqINAPehpYMmbx6tNPNea8ZWsDMqa5GeLpDGVbLoyJI4 FMvA== X-Gm-Message-State: AOJu0YzUTVa0iBvfVAPmayVgnJ2vQQVQV0S0d5UkEY+68xL+L/WxsslW zd727PHkzKE4M2eovK6252Zm9KNxYNl2ZcU1+lfhEauaDY1o7j3hdnXTRO5iZg== X-Gm-Gg: ATEYQzw6diiLJz2wBvqg1IEEXbB0Gphkw4ggueLUoSx+NoDEUEb/y0MRm8/C3uH6+tN M9yVhQ6D49mqqg4JO6GGpRrqqs6nfjEiVnaF3fP1gl0Qx1wMSz4sPNeaAGGT7Uo0umvGBXkodDe x8qDjleGlyj9OYcd6VRMHe4fGgkpyYkyx+iEg5T8U8RwVKGn4/qbfMdBa/XGVxLjhKrCESycyuq cWND/TvXDu9WFoxSkTcjIlD2eoVBOeVsLhLAoTIJUZQkjq5UYcweU7978DDD8/Ff76G3CcAte7y RETsavKDuJR/dHIs73qZNRh8o0YHOtVUwoQxnWz8qbjPw1QqYi/NRBDTYrqX2in4DmACfflJoXl yfjycNQ0SGfIEWBPTWd7T8Jh2joHljmflRc5wu5rjSfbWLppS3NDgq+wfa6RxUbjF5rd38DxgFl 2WB1HuN3outnmHFckVXpeR1JrxWBdm2RLP+ya6tJLzduunGkyo1c994Ze0fWepYjN7+DU3 X-Received: by 2002:a05:6a00:4612:b0:829:91f6:e544 with SMTP id d2e1a72fcca58-829a30cc76emr12610899b3a.63.1773103843926; Mon, 09 Mar 2026 17:50:43 -0700 (PDT) Received: from lima-default (103.95.112.190.qld.leaptel.network. [103.95.112.190]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-829a46765a6sm11357635b3a.29.2026.03.09.17.50.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Mar 2026 17:50:43 -0700 (PDT) From: Nicholas Piggin To: opensbi@lists.infradead.org Cc: Nicholas Piggin Subject: [PATCH 4/4] platform: generic: tenstorrent: Add RISC-V IOMMU support Date: Tue, 10 Mar 2026 10:49:57 +1000 Message-ID: <20260310005000.3837512-4-npiggin@gmail.com> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260310005000.3837512-1-npiggin@gmail.com> References: <20260310005000.3837512-1-npiggin@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260309_175045_562898_C8271237 X-CRM114-Status: GOOD ( 31.00 ) X-BeenThere: opensbi@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "opensbi" Errors-To: opensbi-bounces+opensbi=archiver.kernel.org@lists.infradead.org Add support for the Tenstorrent RISC-V IOMMU, and enable it for the Atlantis platform. The IOMMU must have PMA and PMP registers set up. These are implemented as MMRs with the same format as the corresponding HART CSRs, making it possible to reuse much existing PMP code. PMAs are copied from HART CSRs directly because those are set up by a prior boot stage. Signed-off-by: Nicholas Piggin --- platform/generic/Kconfig | 1 + platform/generic/include/tenstorrent/iommu.h | 12 + platform/generic/tenstorrent/Kconfig | 3 + platform/generic/tenstorrent/atlantis.c | 18 ++ platform/generic/tenstorrent/iommu.c | 245 +++++++++++++++++++ platform/generic/tenstorrent/objects.mk | 1 + platform/generic/tenstorrent/pma.c | 3 +- 7 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 platform/generic/include/tenstorrent/iommu.h create mode 100644 platform/generic/tenstorrent/iommu.c diff --git a/platform/generic/Kconfig b/platform/generic/Kconfig index 7de5e5a6..ba2cfa38 100644 --- a/platform/generic/Kconfig +++ b/platform/generic/Kconfig @@ -88,6 +88,7 @@ config PLATFORM_STARFIVE_JH7110 config PLATFORM_TENSTORRENT_ATLANTIS bool "Tenstorrent Atlantis support" select CPU_TENSTORRENT_ASCALON + select CPU_TENSTORRENT_IOMMU default n config PLATFORM_THEAD diff --git a/platform/generic/include/tenstorrent/iommu.h b/platform/generic/include/tenstorrent/iommu.h new file mode 100644 index 00000000..45231dfa --- /dev/null +++ b/platform/generic/include/tenstorrent/iommu.h @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef __TENSTORRENT_IOMMU_H__ +#define __TENSTORRENT_IOMMU_H__ + +int tt_iommu_configure(unsigned long iommu_m_regs); +int tt_iommu_fdt_configure(const void *fdt); + +#endif diff --git a/platform/generic/tenstorrent/Kconfig b/platform/generic/tenstorrent/Kconfig index 76c7fb32..5c524b33 100644 --- a/platform/generic/tenstorrent/Kconfig +++ b/platform/generic/tenstorrent/Kconfig @@ -3,3 +3,6 @@ config CPU_TENSTORRENT_ASCALON bool + +config CPU_TENSTORRENT_IOMMU + bool diff --git a/platform/generic/tenstorrent/atlantis.c b/platform/generic/tenstorrent/atlantis.c index 4c312f7e..59bbd0eb 100644 --- a/platform/generic/tenstorrent/atlantis.c +++ b/platform/generic/tenstorrent/atlantis.c @@ -12,12 +12,30 @@ #include #include +#include static int tt_atlantis_final_init(bool cold_boot) { if (cold_boot) { + int rc; + /* Boot firmware sets HART PMAs. Read and verify them. */ tt_ascalon_discover_pmas_from_boot_hart(); + + /* + * IOMMU must be configured at platform final_init time, to get + * the right PMP settings, see init_coldboot() comment. IOMMU + * is also configured with PMAs discovered from the boot HART, + * above. + */ + rc = tt_iommu_fdt_configure(fdt_get_address()); + if (rc) { + if (rc == SBI_ENOTSUPP) + sbi_printf("Tenstorrent Atlantis: No IOMMU " + "in device tree, continuing.\n"); + else + return rc; + } } else { /* Verify nonboot HARTs have PMAs matching boot HART */ tt_ascalon_verify_pmas_nonboot_hart(); diff --git a/platform/generic/tenstorrent/iommu.c b/platform/generic/tenstorrent/iommu.c new file mode 100644 index 00000000..acc31c09 --- /dev/null +++ b/platform/generic/tenstorrent/iommu.c @@ -0,0 +1,245 @@ +/* + * SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* PMA/PMP register offsets */ +#define RISCV_IOMMU_REG_PMA_CFG 0x1000 +#define RISCV_IOMMU_REG_PMP_CFG 0x2000 +#define RISCV_IOMMU_REG_PMP_ADDR 0x2040 +#define RISCV_IOMMU_REG_MACHINE_SIZE 0x3000 /* Minimum size of MMRs used */ + +static int iommu_pmp_write(void *iommu, unsigned int n, pmp_t *pmp) +{ + void *pmpcfg_reg, *pmpaddr_reg; + u64 pmpcfg; + unsigned int pmpcfg_shift; + + if (n >= PMP_COUNT) + return SBI_EINVAL; + + pmpaddr_reg = iommu + RISCV_IOMMU_REG_PMP_ADDR + n * 8; + writeq(pmp->addr, pmpaddr_reg); + + pmpcfg_reg = iommu + RISCV_IOMMU_REG_PMP_CFG + (n / 8) * 8; + pmpcfg_shift = (n % 8) * 8; + pmpcfg = readq(pmpcfg_reg); + pmpcfg &= ~((u64)0xff << pmpcfg_shift); + pmpcfg |= (u64)pmp->cfg << pmpcfg_shift; + writeq(pmpcfg, pmpcfg_reg); + + return SBI_OK; +} + +static int iommu_pmp_disable(void *iommu, unsigned int n) +{ + struct pmp pmp = { .cfg = 0, .addr = 0 }; + + return iommu_pmp_write(iommu, n, &pmp); +} + +static int iommu_pmp_set(void *iommu, unsigned int n, + unsigned long prot, unsigned long addr, unsigned long log2len) +{ + pmp_t pmp; + int rc; + + rc = pmp_create(&pmp, prot, addr, log2len); + if (rc) + return rc; + + return iommu_pmp_write(iommu, n, &pmp); +} + +/* This matches sbi_hart_oldpmp_configure. IOMMU does not support Smepmp */ +static int iommu_pmp_configure(void *iommu, unsigned int pmp_count, + unsigned int pmp_log2gran, unsigned long pmp_addr_max) +{ + struct sbi_domain_memregion *reg; + struct sbi_domain *dom; + unsigned int pmp_idx, pmp_flags; + + /* For now, attach IOMMUs to root domain */ + dom = &root; + + /* Disable all PMPs */ + for (int i = 0; i < pmp_count; i++) + iommu_pmp_disable(iommu, i); + + pmp_idx = 0; + sbi_domain_for_each_memregion(dom, reg) { + if (pmp_count <= pmp_idx) + break; + + pmp_flags = 0; + + /* + * If permissions are to be enforced for all modes on + * this region, the lock bit should be set. + */ + if (reg->flags & SBI_DOMAIN_MEMREGION_ENF_PERMISSIONS) + pmp_flags |= PMP_L; + + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_READABLE) + pmp_flags |= PMP_R; + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_WRITABLE) + pmp_flags |= PMP_W; + if (reg->flags & SBI_DOMAIN_MEMREGION_SU_EXECUTABLE) + pmp_flags |= PMP_X; + + if (reg->order < pmp_log2gran || (reg->base >> PMP_SHIFT) >= pmp_addr_max) { + sbi_printf("Can not configure pmp for domain %s because" + " memory region address 0x%lx or size 0x%lx " + "is not in range.\n", dom->name, reg->base, + reg->order); + continue; + } + + iommu_pmp_set(iommu, pmp_idx, pmp_flags, reg->base, reg->order); + pmp_idx++; + } + + return 0; +} + +static int iommu_pma_write(void *iommu, unsigned int n, u64 pma) +{ + void *pmacfg_reg; + + if (n >= TT_MAX_PMAS) + return SBI_EINVAL; + + pmacfg_reg = iommu + RISCV_IOMMU_REG_PMA_CFG + n*8; + + writeq(pma, pmacfg_reg); + + if (readq(pmacfg_reg) != pma) + return SBI_ENOTSUPP; + + return SBI_OK; +} + +static int iommu_pma_configure(void *iommu) +{ + for (int i = 0; i < TT_MAX_PMAS; i++) { + int rc = iommu_pma_write(iommu, i, tt_pma_get(i)); + if (rc) { + sbi_printf("IOMMU: Error setting unimplemented PMA%02u\n", i); + return rc; + } + } + + return SBI_OK; +} + +static void tt_iommu_detect_pmp(void *iommu, unsigned int *pmp_count, + unsigned int *pmp_log2gran, + unsigned long *pmp_addr_max) +{ + unsigned long pmp_addr_bits; + void *pmpaddr_reg; + u64 val; + unsigned int i; + + pmpaddr_reg = iommu + RISCV_IOMMU_REG_PMP_ADDR + 0 * 8; + writeq(PMP_ADDR_MASK, pmpaddr_reg); + val = readq(pmpaddr_reg); + *pmp_log2gran = sbi_ffs(val) + 2; + pmp_addr_bits = sbi_fls(val); + + *pmp_addr_max = (1UL << pmp_addr_bits) | ((1UL << pmp_addr_bits) - 1); + + for (i = 0; i < PMP_COUNT; i++) { + pmpaddr_reg = iommu + RISCV_IOMMU_REG_PMP_ADDR + i * 8; + writeq(val, pmpaddr_reg); + val = readq(pmpaddr_reg); + if (!val) + break; + writeq(0, pmpaddr_reg); + } + *pmp_count = i; +} + +int tt_iommu_configure(unsigned long iommu_m_regs) +{ + unsigned int pmp_count; + unsigned int pmp_log2gran; + unsigned long pmp_addr_max; + int rc; + + rc = iommu_pma_configure((void *)iommu_m_regs); + if (rc) { + sbi_printf("IOMMU: Failed to set PMAs\n"); + return rc; + } + + tt_iommu_detect_pmp((void *)iommu_m_regs, &pmp_count, + &pmp_log2gran, &pmp_addr_max); + sbi_dprintf("IOMMU: detected %u PMPs %u log2gran 0x%016lx addr max\n", + pmp_count, pmp_log2gran, pmp_addr_max); + + rc = iommu_pmp_configure((void *)iommu_m_regs, pmp_count, + pmp_log2gran, pmp_addr_max); + if (rc) { + sbi_printf("IOMMU: Failed to set PMPs\n"); + return rc; + } + + return SBI_OK; +} + +int tt_iommu_fdt_configure(const void *fdt) +{ + const char *compatible = "tenstorrent,riscv-iommu"; + bool found_dt = false; + int offset = -1; + + for (;;) { + uint64_t addr, size; + int rc; + + offset = fdt_node_offset_by_compatible(fdt, offset, compatible); + if (offset < 0) + break; + + rc = fdt_get_node_addr_size_by_name(fdt, offset, "machine", + &addr, &size); + if (rc < 0 || !size) { + sbi_printf("tenstorrent,riscv-iommu did not find " + "machine regs\n"); + continue; + } + + if (size < RISCV_IOMMU_REG_MACHINE_SIZE) { + sbi_printf("tenstorrent,riscv-iommu@0x%016lx " + " machine regs region too small\n", addr); + continue; + } + + sbi_dprintf("tenstorrent,riscv-iommu found machine regs " + "0x%016lx-0x%016lx\n", addr, addr + size - 1); + + rc = tt_iommu_configure(addr); + if (rc) + sbi_printf("tenstorrent,riscv-iommu@0x%016lx " + "init failed\n", addr); + } + + if (!found_dt) + return SBI_ENOTSUPP; + + return SBI_OK; +} diff --git a/platform/generic/tenstorrent/objects.mk b/platform/generic/tenstorrent/objects.mk index 1e4aeb2d..0bf9c69b 100644 --- a/platform/generic/tenstorrent/objects.mk +++ b/platform/generic/tenstorrent/objects.mk @@ -5,6 +5,7 @@ platform-objs-y += tenstorrent/pma.o platform-objs-$(CONFIG_CPU_TENSTORRENT_ASCALON) += tenstorrent/ascalon.o +platform-objs-$(CONFIG_CPU_TENSTORRENT_IOMMU) += tenstorrent/iommu.o carray-platform_override_modules-$(CONFIG_PLATFORM_TENSTORRENT_ATLANTIS) += tenstorrent_atlantis platform-objs-$(CONFIG_PLATFORM_TENSTORRENT_ATLANTIS) += tenstorrent/atlantis.o diff --git a/platform/generic/tenstorrent/pma.c b/platform/generic/tenstorrent/pma.c index daf60192..1556707c 100644 --- a/platform/generic/tenstorrent/pma.c +++ b/platform/generic/tenstorrent/pma.c @@ -13,7 +13,8 @@ /* * All PMAs in the system should be the same (after boot). The init code - * must have set PMAs for all HARTs. + * must have set PMAs for all HARTs. IOMMU init programs IOMMU PMAs to + * match the HARTs. */ /* -- 2.51.0 -- opensbi mailing list opensbi@lists.infradead.org http://lists.infradead.org/mailman/listinfo/opensbi