diff mbox series

[RFC,v3,3/4] riscv: cpufeature: Extract extension names from "riscv, isa"

Message ID b89e73d6a178d04e447ae9d142477731b1f8998d.1638408984.git.research_trasio@irq.a4lg.com (mailing list archive)
State New, archived
Headers show
Series riscv: cpufeature: Improvements for extended feature handling | expand

Commit Message

Tsukasa OI Dec. 2, 2021, 1:41 a.m. UTC
It's possible that we only need extension names implemented but not
version numbers.  This commit doesn't parse version numbers but does
extract implemented extension names.

Beware that the extension name is **not** null-terminated.

Use `MATCH_EXT` macro to match extension name (the argument is
lower-case constant string).

Signed-off-by: Tsukasa OI <research_trasio@irq.a4lg.com>
---
 arch/riscv/kernel/cpufeature.c | 35 +++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)
diff mbox series

Patch

diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index d4ff704db53b..f52e15488a70 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -102,6 +102,7 @@  void __init riscv_fill_hwcap(void)
 #endif
 		for (; *isa; ++isa) {
 			const char *ext = isa++;
+			const char *ext_end = isa;
 			bool ext_long, ext_err = false;
 
 			switch (*ext) {
@@ -111,13 +112,28 @@  void __init riscv_fill_hwcap(void)
 				ext_long = true;
 				/* Multi-letter extension must be delimited */
 				for (; *isa && *isa != '_'; ++isa)
-					if (!islower(*isa) && !isdigit(*isa))
+					if (unlikely(!islower(*isa)
+						     && !isdigit(*isa)))
 						ext_err = true;
-				/* ... but must be ignored. */
+				/* Find end of the extension name backwards */
+				ext_end = isa;
+				if (unlikely(ext_err))
+					break;
+				if (!isdigit(ext_end[-1]))
+					break;
+				while (isdigit(*--ext_end))
+					;
+				if (ext_end[0] != 'p'
+				    || !isdigit(ext_end[-1])) {
+					++ext_end;
+					break;
+				}
+				while (isdigit(*--ext_end))
+					;
 				break;
 			default:
 				ext_long = false;
-				if (!islower(*ext)) {
+				if (unlikely(!islower(*ext))) {
 					ext_err = true;
 					break;
 				}
@@ -138,14 +154,15 @@  void __init riscv_fill_hwcap(void)
 			}
 			if (*isa != '_')
 				--isa;
-			/*
-			 * TODO: Full version-aware handling including
-			 * multi-letter extensions will be added in-future.
-			 */
-			if (ext_err || ext_long)
+
+#define MATCH_EXT(name)  (ext_end - ext == sizeof(name) - 1 \
+			  && !memcmp(ext, name, sizeof(name) - 1))
+			if (unlikely(ext_err))
 				continue;
 			this_hwcap |= isa2hwcap[(unsigned char)(*ext)];
-			this_isa |= (1UL << (*ext - 'a'));
+			if (!ext_long)
+				this_isa |= (1UL << (*ext - 'a'));
+#undef MATCH_EXT
 		}
 
 		/*