All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nicholas Piggin <npiggin@gmail.com>
To: opensbi@lists.infradead.org
Cc: Nicholas Piggin <npiggin@gmail.com>
Subject: [PATCH 2/4] lib: sbi: Move PMP encoding into a new file
Date: Tue, 10 Mar 2026 10:49:55 +1000	[thread overview]
Message-ID: <20260310005000.3837512-2-npiggin@gmail.com> (raw)
In-Reply-To: <20260310005000.3837512-1-npiggin@gmail.com>

The Tenstorrent RISC-V IOMMU PMP MMRs use the same encoding as PMP CSRs.
In preparation to support it, move the non hart-specific PMP operations
into their own file where they will also be used to build the IOMMU
PMPs.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 include/sbi/riscv_asm.h |   2 +-
 include/sbi/sbi_pmp.h   |  24 +++++++
 lib/sbi/objects.mk      |   1 +
 lib/sbi/riscv_asm.c     | 156 ++++++++++++----------------------------
 lib/sbi/sbi_pmp.c       |  91 +++++++++++++++++++++++
 5 files changed, 164 insertions(+), 110 deletions(-)
 create mode 100644 include/sbi/sbi_pmp.h
 create mode 100644 lib/sbi/sbi_pmp.c

diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h
index 0cf3fc37..b97e1880 100644
--- a/include/sbi/riscv_asm.h
+++ b/include/sbi/riscv_asm.h
@@ -213,7 +213,7 @@ void misa_string(int xlen, char *out, unsigned int out_sz);
 int pmp_disable(unsigned int n);
 
 /* Check if the matching field is set */
-int is_pmp_entry_mapped(unsigned long entry);
+int is_pmp_entry_mapped(unsigned int entry);
 
 int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
 	    unsigned long log2len);
diff --git a/include/sbi/sbi_pmp.h b/include/sbi/sbi_pmp.h
new file mode 100644
index 00000000..66664bb0
--- /dev/null
+++ b/include/sbi/sbi_pmp.h
@@ -0,0 +1,24 @@
+/*
+ * SPDX-FileCopyrightText: (c) 2025-2026 Tenstorrent USA, Inc.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef __SBI_PMP_H__
+#define __SBI_PMP_H__
+
+#include <sbi/sbi_types.h>
+
+struct pmp {
+	u8	cfg;
+	u64	addr;
+};
+typedef struct pmp pmp_t;
+
+bool pmp_enabled(pmp_t *pmp);
+
+int pmp_create(pmp_t *pmp, unsigned long prot, unsigned long addr,
+	    unsigned long log2len);
+int pmp_decode(pmp_t *pmp, unsigned long *prot, unsigned long *addr,
+	    unsigned long *log2len);
+
+#endif
diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
index 07d13229..0e29a277 100644
--- a/lib/sbi/objects.mk
+++ b/lib/sbi/objects.mk
@@ -87,6 +87,7 @@ libsbi-objs-y += sbi_init.o
 libsbi-objs-y += sbi_ipi.o
 libsbi-objs-y += sbi_irqchip.o
 libsbi-objs-y += sbi_platform.o
+libsbi-objs-y += sbi_pmp.o
 libsbi-objs-y += sbi_pmu.o
 libsbi-objs-y += sbi_dbtr.o
 libsbi-objs-y += sbi_mpxy.o
diff --git a/lib/sbi/riscv_asm.c b/lib/sbi/riscv_asm.c
index 3e44320f..c11abb1a 100644
--- a/lib/sbi/riscv_asm.c
+++ b/lib/sbi/riscv_asm.c
@@ -12,6 +12,7 @@
 #include <sbi/sbi_error.h>
 #include <sbi/sbi_platform.h>
 #include <sbi/sbi_console.h>
+#include <sbi/sbi_pmp.h>
 
 /* determine CPU extension, return non-zero support */
 int misa_extension_imp(char ext)
@@ -272,24 +273,9 @@ void csr_write_num(int csr_num, unsigned long val)
 #undef switchcase_csr_write
 }
 
-static unsigned long ctz(unsigned long x)
+int hart_pmp_read(unsigned int n, pmp_t *pmp)
 {
-	unsigned long ret = 0;
-
-	if (x == 0)
-		return 8 * sizeof(x);
-
-	while (!(x & 1UL)) {
-		ret++;
-		x = x >> 1;
-	}
-
-	return ret;
-}
-
-int pmp_disable(unsigned int n)
-{
-	int pmpcfg_csr, pmpcfg_shift;
+	int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
 	unsigned long cfgmask, pmpcfg;
 
 	if (n >= PMP_COUNT)
@@ -304,44 +290,24 @@ int pmp_disable(unsigned int n)
 #else
 # error "Unexpected __riscv_xlen"
 #endif
+	pmpaddr_csr = CSR_PMPADDR0 + n;
+	pmp->addr = csr_read_num(pmpaddr_csr);
 
-	/* Clear the address matching bits to disable the pmp entry */
-	cfgmask = ~(0xffUL << pmpcfg_shift);
-	pmpcfg	= (csr_read_num(pmpcfg_csr) & cfgmask);
-
-	csr_write_num(pmpcfg_csr, pmpcfg);
+	cfgmask = (0xffUL << pmpcfg_shift);
+	pmpcfg = csr_read_num(pmpcfg_csr) & cfgmask;
+	pmp->cfg = pmpcfg >> pmpcfg_shift;
 
 	return SBI_OK;
 }
 
-int is_pmp_entry_mapped(unsigned long entry)
-{
-	unsigned long prot;
-	unsigned long addr;
-	unsigned long log2len;
-
-	if (pmp_get(entry, &prot, &addr, &log2len) != 0)
-		return false;
-
-	/* If address matching bits are non-zero, the entry is enable */
-	if (prot & PMP_A)
-		return true;
-
-	return false;
-}
-
-int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
-	    unsigned long log2len)
+int hart_pmp_write(unsigned int n, pmp_t *pmp)
 {
 	int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
 	unsigned long cfgmask, pmpcfg;
-	unsigned long addrmask, pmpaddr;
 
-	/* check parameters */
-	if (n >= PMP_COUNT || log2len > __riscv_xlen || log2len < PMP_SHIFT)
+	if (n >= PMP_COUNT)
 		return SBI_EINVAL;
 
-	/* calculate PMP register and offset */
 #if __riscv_xlen == 32
 	pmpcfg_csr   = CSR_PMPCFG0 + (n >> 2);
 	pmpcfg_shift = (n & 3) << 3;
@@ -353,82 +319,54 @@ int pmp_set(unsigned int n, unsigned long prot, unsigned long addr,
 #endif
 	pmpaddr_csr = CSR_PMPADDR0 + n;
 
-	/* encode PMP config */
-	prot &= ~PMP_A;
-	prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
 	cfgmask = ~(0xffUL << pmpcfg_shift);
 	pmpcfg	= (csr_read_num(pmpcfg_csr) & cfgmask);
-	pmpcfg |= ((prot << pmpcfg_shift) & ~cfgmask);
-
-	/* encode PMP address */
-	if (log2len == PMP_SHIFT) {
-		pmpaddr = (addr >> PMP_SHIFT);
-	} else {
-		if (log2len == __riscv_xlen) {
-			pmpaddr = -1UL;
-		} else {
-			addrmask = (1UL << (log2len - PMP_SHIFT)) - 1;
-			pmpaddr	 = ((addr >> PMP_SHIFT) & ~addrmask);
-			pmpaddr |= (addrmask >> 1);
-		}
-	}
+	pmpcfg |= (unsigned long)pmp->cfg << pmpcfg_shift;
 
-	/* write csrs */
-	csr_write_num(pmpaddr_csr, pmpaddr);
+	csr_write_num(pmpaddr_csr, pmp->addr);
 	csr_write_num(pmpcfg_csr, pmpcfg);
 
-	return 0;
+	return SBI_OK;
 }
 
-int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
-	    unsigned long *log2len)
+int pmp_disable(unsigned int n)
 {
-	int pmpcfg_csr, pmpcfg_shift, pmpaddr_csr;
-	unsigned long cfgmask, pmpcfg, prot;
-	unsigned long t1, addr, len;
+	struct pmp pmp = { .cfg = 0, .addr = 0 };
+	return hart_pmp_write(n, &pmp);
+}
 
-	/* check parameters */
-	if (n >= PMP_COUNT || !prot_out || !addr_out || !log2len)
-		return SBI_EINVAL;
-	*prot_out = *addr_out = *log2len = 0;
+int is_pmp_entry_mapped(unsigned int entry)
+{
+	pmp_t pmp;
 
-	/* calculate PMP register and offset */
-#if __riscv_xlen == 32
-	pmpcfg_csr   = CSR_PMPCFG0 + (n >> 2);
-	pmpcfg_shift = (n & 3) << 3;
-#elif __riscv_xlen == 64
-	pmpcfg_csr   = (CSR_PMPCFG0 + (n >> 2)) & ~1;
-	pmpcfg_shift = (n & 7) << 3;
-#else
-# error "Unexpected __riscv_xlen"
-#endif
-	pmpaddr_csr = CSR_PMPADDR0 + n;
+	if (hart_pmp_read(entry, &pmp))
+		return pmp_enabled(&pmp);
 
-	/* decode PMP config */
-	cfgmask = (0xffUL << pmpcfg_shift);
-	pmpcfg	= csr_read_num(pmpcfg_csr) & cfgmask;
-	prot	= pmpcfg >> pmpcfg_shift;
-
-	/* decode PMP address */
-	if ((prot & PMP_A) == PMP_A_NAPOT) {
-		addr = csr_read_num(pmpaddr_csr);
-		if (addr == -1UL) {
-			addr	= 0;
-			len	= __riscv_xlen;
-		} else {
-			t1	= ctz(~addr);
-			addr	= (addr & ~((1UL << t1) - 1)) << PMP_SHIFT;
-			len	= (t1 + PMP_SHIFT + 1);
-		}
-	} else {
-		addr	= csr_read_num(pmpaddr_csr) << PMP_SHIFT;
-		len	= PMP_SHIFT;
-	}
+	return false;
+}
+
+int pmp_set(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 hart_pmp_write(n, &pmp);
+}
+
+int pmp_get(unsigned int n, unsigned long *prot_out, unsigned long *addr_out,
+	    unsigned long *log2len)
+{
+	pmp_t pmp;
+	int rc;
 
-	/* return details */
-	*prot_out    = prot;
-	*addr_out    = addr;
-	*log2len     = len;
+	rc = hart_pmp_read(n, &pmp);
+	if (rc)
+		return rc;
 
-	return 0;
+	return pmp_decode(&pmp, prot_out, addr_out, log2len);
 }
diff --git a/lib/sbi/sbi_pmp.c b/lib/sbi/sbi_pmp.c
new file mode 100644
index 00000000..22132d81
--- /dev/null
+++ b/lib/sbi/sbi_pmp.c
@@ -0,0 +1,91 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Western Digital Corporation or its affiliates.
+ *
+ * Authors:
+ *   Anup Patel <anup.patel@wdc.com>
+ */
+
+#include <sbi/riscv_asm.h>
+#include <sbi/riscv_encoding.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_pmp.h>
+
+bool pmp_enabled(pmp_t *pmp)
+{
+	return pmp->cfg & PMP_A;
+}
+
+int pmp_create(pmp_t *pmp, unsigned long prot, unsigned long addr,
+	    unsigned long log2len)
+{
+	unsigned long addrmask, pmpaddr;
+
+	/* check parameters */
+	if (log2len > __riscv_xlen || log2len < PMP_SHIFT)
+		return SBI_EINVAL;
+
+	/* encode PMP config */
+	prot &= ~PMP_A;
+	prot |= (log2len == PMP_SHIFT) ? PMP_A_NA4 : PMP_A_NAPOT;
+
+	/* encode PMP address */
+	if (log2len == PMP_SHIFT) {
+		pmpaddr = (addr >> PMP_SHIFT);
+	} else {
+		if (log2len == __riscv_xlen) {
+			pmpaddr = -1UL;
+		} else {
+			addrmask = (1UL << (log2len - PMP_SHIFT)) - 1;
+			pmpaddr	 = ((addr >> PMP_SHIFT) & ~addrmask);
+			pmpaddr |= (addrmask >> 1);
+		}
+	}
+
+	pmp->cfg = prot;
+	pmp->addr = pmpaddr;
+
+	return SBI_OK;
+}
+
+static unsigned long cto(unsigned long x)
+{
+	unsigned long ret = 0;
+
+	while (x & 1UL) {
+		ret++;
+		x = x >> 1;
+	}
+
+	return ret;
+}
+
+int pmp_decode(pmp_t *pmp, unsigned long *prot_out, unsigned long *addr_out,
+	    unsigned long *log2len)
+{
+	/* check parameters */
+	if (!pmp || !prot_out || !addr_out || !log2len)
+		return SBI_EINVAL;
+
+	if (!pmp_enabled(pmp))
+		return SBI_EINVAL;
+
+	/* decode PMP address */
+	if ((pmp->cfg & PMP_A) == PMP_A_NAPOT) {
+		if (pmp->addr == -1UL) {
+			*addr_out = 0;
+			*log2len = __riscv_xlen + 3;
+		} else {
+			unsigned long mask = ~((1UL << cto(pmp->addr)) - 1);
+			*addr_out = (pmp->addr & mask) << PMP_SHIFT;
+			*log2len = (cto(pmp->addr) + PMP_SHIFT + 1);
+		}
+	} else {
+		*addr_out = pmp->addr << PMP_SHIFT;
+		*log2len = PMP_SHIFT;
+	}
+
+	return SBI_OK;
+}
-- 
2.51.0


-- 
opensbi mailing list
opensbi@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/opensbi

  reply	other threads:[~2026-03-10  0:50 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-10  0:49 [PATCH 1/4] platform: generic: Tenstorrent Atlantis support Nicholas Piggin
2026-03-10  0:49 ` Nicholas Piggin [this message]
2026-04-01 12:50   ` [PATCH 2/4] lib: sbi: Move PMP encoding into a new file Joel Stanley
2026-04-23  0:59     ` Nicholas Piggin
2026-03-10  0:49 ` [PATCH 3/4] lib: sbi: Add hart_ prefix to PMP functions Nicholas Piggin
2026-04-01 12:50   ` Joel Stanley
2026-03-10  0:49 ` [PATCH 4/4] platform: generic: tenstorrent: Add RISC-V IOMMU support Nicholas Piggin
2026-04-01 12:51   ` Joel Stanley
2026-04-23  1:01     ` Nicholas Piggin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260310005000.3837512-2-npiggin@gmail.com \
    --to=npiggin@gmail.com \
    --cc=opensbi@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.