Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64/sysreg: allow *Enum blocks in SysregFields blocks

We'd like to support Enum/SignedEnum/UnsignedEnum blocks within
SysregFields blocks, so that we can define enumerations for sets of
registers. This isn't currently supported by gen-sysreg.awk due to the
way we track the active block, which can't handle more than a single
layer of nesting, which imposes an awkward requirement that when ending
a block we know what the parent block is when calling change_block()

Make this nicer by using a stack of active blocks, with block_push() to
start a block, and block_pop() to end a block. Doing so means that we
only need to check the active block at the start of parsing a line: for
the start of a block we can check the parent is valid, and for the end
of a block we check that the active block is valid.

This structure makes the block parsing simpler and makes it easy to
permit a block to live under several potential parents (e.g. by
permitting Enum to start when the active block is Sysreg or
SysregFields). It also permits further nesting, if we need that in
future.

To aid debugging, the stack of active blocks is reported for fatal
errors, and an error is raised if the file is terminated without ending
the active block. For clarity I've renamed the top-level element from
"None" to "Root".

The Fields element it intended only for use within Sysreg blocks, and
does not make sense within SysregFields blocks, and so remains forbidden
within a SysregFields block.

I've verified using sha1sum that this patch does not change the
current generated contents of <asm/sysreg-defs.h>.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Will Deacon <will@kernel.org>
Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20230306114836.2575432-1-mark.rutland@arm.com
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Mark Rutland and committed by
Will Deacon
013ecd44 e8d018dd

+57 -36
+57 -36
arch/arm64/tools/gen-sysreg.awk
··· 4 4 # 5 5 # Usage: awk -f gen-sysreg.awk sysregs.txt 6 6 7 + function block_current() { 8 + return __current_block[__current_block_depth]; 9 + } 10 + 7 11 # Log an error and terminate 8 12 function fatal(msg) { 9 13 print "Error at " NR ": " msg > "/dev/stderr" 14 + 15 + printf "Current block nesting:" 16 + 17 + for (i = 0; i <= __current_block_depth; i++) { 18 + printf " " __current_block[i] 19 + } 20 + printf "\n" 21 + 10 22 exit 1 11 23 } 12 24 13 - # Sanity check that the start or end of a block makes sense at this point in 14 - # the file. If not, produce an error and terminate. 15 - # 16 - # @this - the $Block or $EndBlock 17 - # @prev - the only valid block to already be in (value of @block) 18 - # @new - the new value of @block 19 - function change_block(this, prev, new) { 20 - if (block != prev) 21 - fatal("unexpected " this " (inside " block ")") 25 + # Enter a new block, setting the active block to @block 26 + function block_push(block) { 27 + __current_block[++__current_block_depth] = block 28 + } 22 29 23 - block = new 30 + # Exit a block, setting the active block to the parent block 31 + function block_pop() { 32 + if (__current_block_depth == 0) 33 + fatal("error: block_pop() in root block") 34 + 35 + __current_block_depth--; 24 36 } 25 37 26 38 # Sanity check the number of records for a field makes sense. If not, produce ··· 96 84 print "/* Generated file - do not edit */" 97 85 print "" 98 86 99 - block = "None" 87 + __current_block_depth = 0 88 + __current_block[__current_block_depth] = "Root" 100 89 } 101 90 102 91 END { 92 + if (__current_block_depth != 0) 93 + fatal("Missing terminator for " block_current() " block") 94 + 103 95 print "#endif /* __ASM_SYSREG_DEFS_H */" 104 96 } 105 97 ··· 111 95 /^$/ { next } 112 96 /^[\t ]*#/ { next } 113 97 114 - /^SysregFields/ { 115 - change_block("SysregFields", "None", "SysregFields") 98 + /^SysregFields/ && block_current() == "Root" { 99 + block_push("SysregFields") 100 + 116 101 expect_fields(2) 117 102 118 103 reg = $2 ··· 127 110 next 128 111 } 129 112 130 - /^EndSysregFields/ { 113 + /^EndSysregFields/ && block_current() == "SysregFields" { 131 114 if (next_bit > 0) 132 115 fatal("Unspecified bits in " reg) 133 - 134 - change_block("EndSysregFields", "SysregFields", "None") 135 116 136 117 define(reg "_RES0", "(" res0 ")") 137 118 define(reg "_RES1", "(" res1 ")") ··· 141 126 res1 = null 142 127 unkn = null 143 128 129 + block_pop() 144 130 next 145 131 } 146 132 147 - /^Sysreg/ { 148 - change_block("Sysreg", "None", "Sysreg") 133 + /^Sysreg/ && block_current() == "Root" { 134 + block_push("Sysreg") 135 + 149 136 expect_fields(7) 150 137 151 138 reg = $2 ··· 177 160 next 178 161 } 179 162 180 - /^EndSysreg/ { 163 + /^EndSysreg/ && block_current() == "Sysreg" { 181 164 if (next_bit > 0) 182 165 fatal("Unspecified bits in " reg) 183 - 184 - change_block("EndSysreg", "Sysreg", "None") 185 166 186 167 if (res0 != null) 187 168 define(reg "_RES0", "(" res0 ")") ··· 200 185 res1 = null 201 186 unkn = null 202 187 188 + block_pop() 203 189 next 204 190 } 205 191 206 192 # Currently this is effectivey a comment, in future we may want to emit 207 193 # defines for the fields. 208 - /^Fields/ && (block == "Sysreg") { 194 + /^Fields/ && block_current() == "Sysreg" { 209 195 expect_fields(2) 210 196 211 197 if (next_bit != 63) ··· 224 208 } 225 209 226 210 227 - /^Res0/ && (block == "Sysreg" || block == "SysregFields") { 211 + /^Res0/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 228 212 expect_fields(2) 229 213 parse_bitdef(reg, "RES0", $2) 230 214 field = "RES0_" msb "_" lsb ··· 234 218 next 235 219 } 236 220 237 - /^Res1/ && (block == "Sysreg" || block == "SysregFields") { 221 + /^Res1/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 238 222 expect_fields(2) 239 223 parse_bitdef(reg, "RES1", $2) 240 224 field = "RES1_" msb "_" lsb ··· 244 228 next 245 229 } 246 230 247 - /^Unkn/ && (block == "Sysreg" || block == "SysregFields") { 231 + /^Unkn/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 248 232 expect_fields(2) 249 233 parse_bitdef(reg, "UNKN", $2) 250 234 field = "UNKN_" msb "_" lsb ··· 254 238 next 255 239 } 256 240 257 - /^Field/ && (block == "Sysreg" || block == "SysregFields") { 241 + /^Field/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 258 242 expect_fields(3) 259 243 field = $3 260 244 parse_bitdef(reg, field, $2) ··· 265 249 next 266 250 } 267 251 268 - /^Raz/ && (block == "Sysreg" || block == "SysregFields") { 252 + /^Raz/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 269 253 expect_fields(2) 270 254 parse_bitdef(reg, field, $2) 271 255 272 256 next 273 257 } 274 258 275 - /^SignedEnum/ { 276 - change_block("Enum<", "Sysreg", "Enum") 259 + /^SignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 260 + block_push("Enum") 261 + 277 262 expect_fields(3) 278 263 field = $3 279 264 parse_bitdef(reg, field, $2) ··· 285 268 next 286 269 } 287 270 288 - /^UnsignedEnum/ { 289 - change_block("Enum<", "Sysreg", "Enum") 271 + /^UnsignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 272 + block_push("Enum") 273 + 290 274 expect_fields(3) 291 275 field = $3 292 276 parse_bitdef(reg, field, $2) ··· 298 280 next 299 281 } 300 282 301 - /^Enum/ { 302 - change_block("Enum", "Sysreg", "Enum") 283 + /^Enum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { 284 + block_push("Enum") 285 + 303 286 expect_fields(3) 304 287 field = $3 305 288 parse_bitdef(reg, field, $2) ··· 310 291 next 311 292 } 312 293 313 - /^EndEnum/ { 314 - change_block("EndEnum", "Enum", "Sysreg") 294 + /^EndEnum/ && block_current() == "Enum" { 295 + 315 296 field = null 316 297 msb = null 317 298 lsb = null 318 299 print "" 300 + 301 + block_pop() 319 302 next 320 303 } 321 304 322 - /0b[01]+/ && block == "Enum" { 305 + /0b[01]+/ && block_current() == "Enum" { 323 306 expect_fields(2) 324 307 val = $1 325 308 name = $2