| 1 | /* |
| 2 | * Test Octeon-specific user-mode instructions. |
| 3 | * |
| 4 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 5 | */ |
| 6 | |
| 7 | #include <assert.h> |
| 8 | #include <stdint.h> |
| 9 | |
| 10 | static uint64_t octeon_baddu(uint64_t rs, uint64_t rt) |
| 11 | { |
| 12 | uint64_t rd; |
| 13 | |
| 14 | asm volatile( |
| 15 | "move $8, %[rs]\n\t" |
| 16 | "move $9, %[rt]\n\t" |
| 17 | ".word 0x71095028\n\t" /* baddu $10, $8, $9 */ |
| 18 | "move %[rd], $10\n\t" |
| 19 | : [rd] "=r" (rd) |
| 20 | : [rs] "r" (rs), [rt] "r" (rt) |
| 21 | : "$8", "$9", "$10"); |
| 22 | |
| 23 | return rd; |
| 24 | } |
| 25 | |
| 26 | static uint64_t octeon_dmul(uint64_t rs, uint64_t rt) |
| 27 | { |
| 28 | uint64_t rd; |
| 29 | |
| 30 | asm volatile( |
| 31 | "move $8, %[rs]\n\t" |
| 32 | "move $9, %[rt]\n\t" |
| 33 | ".word 0x71095003\n\t" /* dmul $10, $8, $9 */ |
| 34 | "move %[rd], $10\n\t" |
| 35 | : [rd] "=r" (rd) |
| 36 | : [rs] "r" (rs), [rt] "r" (rt) |
| 37 | : "$8", "$9", "$10"); |
| 38 | |
| 39 | return rd; |
| 40 | } |
| 41 | |
| 42 | static uint64_t octeon_dpop(uint64_t rs) |
| 43 | { |
| 44 | uint64_t rd; |
| 45 | |
| 46 | asm volatile( |
| 47 | "move $8, %[rs]\n\t" |
| 48 | ".word 0x7100502d\n\t" /* dpop $10, $8 */ |
| 49 | "move %[rd], $10\n\t" |
| 50 | : [rd] "=r" (rd) |
| 51 | : [rs] "r" (rs) |
| 52 | : "$8", "$10"); |
| 53 | |
| 54 | return rd; |
| 55 | } |
| 56 | |
| 57 | static uint64_t octeon_seq(uint64_t rs, uint64_t rt) |
| 58 | { |
| 59 | uint64_t rd; |
| 60 | |
| 61 | asm volatile( |
| 62 | "move $8, %[rs]\n\t" |
| 63 | "move $9, %[rt]\n\t" |
| 64 | ".word 0x7109502a\n\t" /* seq $10, $8, $9 */ |
| 65 | "move %[rd], $10\n\t" |
| 66 | : [rd] "=r" (rd) |
| 67 | : [rs] "r" (rs), [rt] "r" (rt) |
| 68 | : "$8", "$9", "$10"); |
| 69 | |
| 70 | return rd; |
| 71 | } |
| 72 | |
| 73 | static uint64_t octeon_sne(uint64_t rs, uint64_t rt) |
| 74 | { |
| 75 | uint64_t rd; |
| 76 | |
| 77 | asm volatile( |
| 78 | "move $8, %[rs]\n\t" |
| 79 | "move $9, %[rt]\n\t" |
| 80 | ".word 0x7109502b\n\t" /* sne $10, $8, $9 */ |
| 81 | "move %[rd], $10\n\t" |
| 82 | : [rd] "=r" (rd) |
| 83 | : [rs] "r" (rs), [rt] "r" (rt) |
| 84 | : "$8", "$9", "$10"); |
| 85 | |
| 86 | return rd; |
| 87 | } |
| 88 | |
| 89 | static uint64_t octeon_vmulu(uint64_t mpl0, uint64_t rs, uint64_t rt) |
| 90 | { |
| 91 | uint64_t rd; |
| 92 | |
| 93 | asm volatile( |
| 94 | "move $8, %[mpl0]\n\t" |
| 95 | "move $9, $0\n\t" |
| 96 | ".word 0x71090008\n\t" /* mtm0 $8, $9 */ |
| 97 | "move $8, %[rs]\n\t" |
| 98 | "move $9, %[rt]\n\t" |
| 99 | ".word 0x7109500f\n\t" /* vmulu $10, $8, $9 */ |
| 100 | "move %[rd], $10\n\t" |
| 101 | : [rd] "=r" (rd) |
| 102 | : [mpl0] "r" (mpl0), [rs] "r" (rs), [rt] "r" (rt) |
| 103 | : "$8", "$9", "$10"); |
| 104 | |
| 105 | return rd; |
| 106 | } |
| 107 | |
| 108 | static uint64_t octeon_vmm0(uint64_t mpl0, uint64_t p0, |
| 109 | uint64_t rs, uint64_t rt) |
| 110 | { |
| 111 | uint64_t rd; |
| 112 | |
| 113 | asm volatile( |
| 114 | "move $8, %[mpl0]\n\t" |
| 115 | "move $9, $0\n\t" |
| 116 | ".word 0x71090008\n\t" /* mtm0 $8, $9 */ |
| 117 | "move $8, %[p0]\n\t" |
| 118 | "move $9, $0\n\t" |
| 119 | ".word 0x71090009\n\t" /* mtp0 $8, $9 */ |
| 120 | "move $8, %[rs]\n\t" |
| 121 | "move $9, %[rt]\n\t" |
| 122 | ".word 0x71095010\n\t" /* vmm0 $10, $8, $9 */ |
| 123 | "move %[rd], $10\n\t" |
| 124 | : [rd] "=r" (rd) |
| 125 | : [mpl0] "r" (mpl0), [p0] "r" (p0), |
| 126 | [rs] "r" (rs), [rt] "r" (rt) |
| 127 | : "$8", "$9", "$10"); |
| 128 | |
| 129 | return rd; |
| 130 | } |
| 131 | |
| 132 | static uint64_t octeon_qmac_lo(uint64_t rs, uint64_t rt, uint64_t lo) |
| 133 | { |
| 134 | uint64_t rd; |
| 135 | |
| 136 | asm volatile( |
| 137 | "move $8, %[rs]\n\t" |
| 138 | "move $9, %[rt]\n\t" |
| 139 | "mtlo %[lo]\n\t" |
| 140 | "mthi $0\n\t" |
| 141 | ".word 0x710904d2\n\t" /* qmac.03 $8, $9 */ |
| 142 | "mflo %[rd]\n\t" |
| 143 | : [rd] "=r" (rd) |
| 144 | : [rs] "r" (rs), [rt] "r" (rt), [lo] "r" (lo) |
| 145 | : "$8", "$9"); |
| 146 | |
| 147 | return rd; |
| 148 | } |
| 149 | |
| 150 | static uint64_t octeon_qmacs_state(uint64_t rs, uint64_t rt, uint64_t lo) |
| 151 | { |
| 152 | uint64_t hi, rd; |
| 153 | |
| 154 | asm volatile( |
| 155 | "move $8, %[rs]\n\t" |
| 156 | "move $9, %[rt]\n\t" |
| 157 | "mtlo %[lo]\n\t" |
| 158 | "mthi $0\n\t" |
| 159 | ".word 0x71090012\n\t" /* qmacs.00 $8, $9 */ |
| 160 | "mfhi %[hi]\n\t" |
| 161 | "mflo %[rd]\n\t" |
| 162 | : [hi] "=r" (hi), [rd] "=r" (rd) |
| 163 | : [rs] "r" (rs), [rt] "r" (rt), [lo] "r" (lo) |
| 164 | : "$8", "$9"); |
| 165 | |
| 166 | return ((hi & 1) << 32) | (rd & 0xffffffff); |
| 167 | } |
| 168 | |
| 169 | static uint64_t octeon_vmm0_zeroes_mpl1(void) |
| 170 | { |
| 171 | uint64_t rd; |
| 172 | |
| 173 | asm volatile( |
| 174 | "move $8, %[mpl0]\n\t" |
| 175 | "move $9, $0\n\t" |
| 176 | ".word 0x71090008\n\t" /* mtm0 $8, $9 */ |
| 177 | "move $8, %[mpl1]\n\t" |
| 178 | "move $9, $0\n\t" |
| 179 | ".word 0x7109000c\n\t" /* mtm1 $8, $9 */ |
| 180 | "move $8, %[vmm0_rs]\n\t" |
| 181 | "move $9, $0\n\t" |
| 182 | ".word 0x71095010\n\t" /* vmm0 $10, $8, $9 */ |
| 183 | "move $8, %[vmulu_rs]\n\t" |
| 184 | "move $9, $0\n\t" |
| 185 | ".word 0x7109500f\n\t" /* vmulu $10, $8, $9 */ |
| 186 | "move $8, $0\n\t" |
| 187 | "move $9, $0\n\t" |
| 188 | ".word 0x7109500f\n\t" /* vmulu $10, $8, $9 */ |
| 189 | "move %[rd], $10\n\t" |
| 190 | : [rd] "=r" (rd) |
| 191 | : [mpl0] "r" (1ULL), [mpl1] "r" (1ULL), |
| 192 | [vmm0_rs] "r" (2ULL), [vmulu_rs] "r" (1ULL) |
| 193 | : "$8", "$9", "$10"); |
| 194 | |
| 195 | return rd; |
| 196 | } |
| 197 | |
| 198 | static uint64_t octeon_mtp0_zeroes_p1(void) |
| 199 | { |
| 200 | uint64_t rd; |
| 201 | |
| 202 | asm volatile( |
| 203 | "move $8, %[mpl0]\n\t" |
| 204 | "move $9, $0\n\t" |
| 205 | ".word 0x71090008\n\t" /* mtm0 $8, $9 */ |
| 206 | "move $8, %[p1]\n\t" |
| 207 | "move $9, $0\n\t" |
| 208 | ".word 0x7109000a\n\t" /* mtp1 $8, $9 */ |
| 209 | "move $8, $0\n\t" |
| 210 | "move $9, $0\n\t" |
| 211 | ".word 0x71090009\n\t" /* mtp0 $8, $9 */ |
| 212 | "move $8, $0\n\t" |
| 213 | "move $9, $0\n\t" |
| 214 | ".word 0x7109500f\n\t" /* vmulu $10, $8, $9 */ |
| 215 | "move $8, $0\n\t" |
| 216 | "move $9, $0\n\t" |
| 217 | ".word 0x7109500f\n\t" /* vmulu $10, $8, $9 */ |
| 218 | "move %[rd], $10\n\t" |
| 219 | : [rd] "=r" (rd) |
| 220 | : [mpl0] "r" (0ULL), [p1] "r" (1ULL) |
| 221 | : "$8", "$9", "$10"); |
| 222 | |
| 223 | return rd; |
| 224 | } |
| 225 | |
| 226 | static uint64_t octeon_cop2_key0_readback(uint64_t value) |
| 227 | { |
| 228 | uint64_t rd; |
| 229 | |
| 230 | asm volatile( |
| 231 | "move $8, %[value]\n\t" |
| 232 | ".word 0x48a80104\n\t" /* dmtc2 $8, AES_KEY0 selector */ |
| 233 | ".word 0x482a0104\n\t" /* dmfc2 $10, AES_KEY0 selector */ |
| 234 | "move %[rd], $10\n\t" |
| 235 | : [rd] "=r" (rd) |
| 236 | : [value] "r" (value) |
| 237 | : "$8", "$10"); |
| 238 | |
| 239 | return rd; |
| 240 | } |
| 241 | |
| 242 | static uint64_t octeon_cop2_key2_readback(uint64_t value) |
| 243 | { |
| 244 | uint64_t rd; |
| 245 | |
| 246 | asm volatile( |
| 247 | "move $8, %[value]\n\t" |
| 248 | ".word 0x48a80106\n\t" /* dmtc2 $8, AES_KEY2 selector */ |
| 249 | ".word 0x482a0106\n\t" /* dmfc2 $10, AES_KEY2 selector */ |
| 250 | "move %[rd], $10\n\t" |
| 251 | : [rd] "=r" (rd) |
| 252 | : [value] "r" (value) |
| 253 | : "$8", "$10"); |
| 254 | |
| 255 | return rd; |
| 256 | } |
| 257 | |
| 258 | static uint64_t octeon_cop2_key3_readback(uint64_t value) |
| 259 | { |
| 260 | uint64_t rd; |
| 261 | |
| 262 | asm volatile( |
| 263 | "move $8, %[value]\n\t" |
| 264 | ".word 0x48a80107\n\t" /* dmtc2 $8, AES_KEY3 selector */ |
| 265 | ".word 0x482a0107\n\t" /* dmfc2 $10, AES_KEY3 selector */ |
| 266 | "move %[rd], $10\n\t" |
| 267 | : [rd] "=r" (rd) |
| 268 | : [value] "r" (value) |
| 269 | : "$8", "$10"); |
| 270 | |
| 271 | return rd; |
| 272 | } |
| 273 | |
| 274 | static uint64_t octeon_cop2_keylength_readback(uint64_t value) |
| 275 | { |
| 276 | uint64_t rd; |
| 277 | |
| 278 | asm volatile( |
| 279 | "move $8, %[value]\n\t" |
| 280 | ".word 0x48a80110\n\t" /* dmtc2 $8, AES_KEYLENGTH selector */ |
| 281 | ".word 0x482a0110\n\t" /* dmfc2 $10, AES_KEYLENGTH selector */ |
| 282 | "move %[rd], $10\n\t" |
| 283 | : [rd] "=r" (rd) |
| 284 | : [value] "r" (value) |
| 285 | : "$8", "$10"); |
| 286 | |
| 287 | return rd; |
| 288 | } |
| 289 | |
| 290 | static uint64_t octeon_cop2_hsh_dat0_readback(uint64_t value) |
| 291 | { |
| 292 | uint64_t rd; |
| 293 | |
| 294 | asm volatile( |
| 295 | "move $8, %[value]\n\t" |
| 296 | ".word 0x48a80040\n\t" /* dmtc2 $8, HSH_DAT0 selector */ |
| 297 | ".word 0x482a0040\n\t" /* dmfc2 $10, HSH_DAT0 selector */ |
| 298 | "move %[rd], $10\n\t" |
| 299 | : [rd] "=r" (rd) |
| 300 | : [value] "r" (value) |
| 301 | : "$8", "$10"); |
| 302 | |
| 303 | return rd; |
| 304 | } |
| 305 | |
| 306 | static uint64_t octeon_cop2_crc_len_readback(uint64_t value) |
| 307 | { |
| 308 | uint64_t rd; |
| 309 | |
| 310 | asm volatile( |
| 311 | "move $8, %[value]\n\t" |
| 312 | ".word 0x48a81202\n\t" /* dmtc2 $8, CRC_LEN selector */ |
| 313 | ".word 0x482a0202\n\t" /* dmfc2 $10, CRC_LEN selector */ |
| 314 | "move %[rd], $10\n\t" |
| 315 | : [rd] "=r" (rd) |
| 316 | : [value] "r" (value) |
| 317 | : "$8", "$10"); |
| 318 | |
| 319 | return rd; |
| 320 | } |
| 321 | |
| 322 | static uint64_t octeon_cop2_crc_poly_reflect_readback(uint64_t value) |
| 323 | { |
| 324 | uint64_t rd; |
| 325 | |
| 326 | asm volatile( |
| 327 | "move $8, %[value]\n\t" |
| 328 | ".word 0x48a84210\n\t" /* dmtc2 $8, CRC_POLYNOMIAL_REFLECT selector */ |
| 329 | ".word 0x482a0200\n\t" /* dmfc2 $10, CRC_POLYNOMIAL selector */ |
| 330 | "move %[rd], $10\n\t" |
| 331 | : [rd] "=r" (rd) |
| 332 | : [value] "r" (value) |
| 333 | : "$8", "$10"); |
| 334 | |
| 335 | return rd; |
| 336 | } |
| 337 | |
| 338 | static uint64_t octeon_cop2_gfm_mul_reflect_write_readback(uint64_t value) |
| 339 | { |
| 340 | uint64_t rd; |
| 341 | |
| 342 | asm volatile( |
| 343 | "move $8, %[value]\n\t" |
| 344 | ".word 0x48a80058\n\t" /* dmtc2 $8, GFM_MUL_REFLECT0 selector */ |
| 345 | ".word 0x482a0258\n\t" /* dmfc2 $10, GFM_MUL0 selector */ |
| 346 | "move %[rd], $10\n\t" |
| 347 | : [rd] "=r" (rd) |
| 348 | : [value] "r" (value) |
| 349 | : "$8", "$10"); |
| 350 | |
| 351 | return rd; |
| 352 | } |
| 353 | |
| 354 | static uint64_t octeon_cop2_gfm_mul_reflect_readback(uint64_t value) |
| 355 | { |
| 356 | uint64_t rd; |
| 357 | |
| 358 | asm volatile( |
| 359 | "move $8, %[value]\n\t" |
| 360 | ".word 0x48a80258\n\t" /* dmtc2 $8, GFM_MUL0 selector */ |
| 361 | ".word 0x482a0058\n\t" /* dmfc2 $10, GFM_MUL_REFLECT0 selector */ |
| 362 | "move %[rd], $10\n\t" |
| 363 | : [rd] "=r" (rd) |
| 364 | : [value] "r" (value) |
| 365 | : "$8", "$10"); |
| 366 | |
| 367 | return rd; |
| 368 | } |
| 369 | |
| 370 | static uint64_t octeon_rdhwr31_non_decreasing(void) |
| 371 | { |
| 372 | uint64_t first, second; |
| 373 | |
| 374 | asm volatile( |
| 375 | ".word 0x7c08f83b\n\t" /* rdhwr $8, $31 */ |
| 376 | ".word 0x7c09f83b\n\t" /* rdhwr $9, $31 */ |
| 377 | "move %[first], $8\n\t" |
| 378 | "move %[second], $9\n\t" |
| 379 | : [first] "=r" (first), [second] "=r" (second) |
| 380 | : |
| 381 | : "$8", "$9"); |
| 382 | |
| 383 | return second >= first; |
| 384 | } |
| 385 | |
| 386 | int main(void) |
| 387 | { |
| 388 | assert(octeon_baddu(0x123, 0x0f0) == 0x13); |
| 389 | assert(octeon_dmul(0x12345678, 0x10) == 0x123456780); |
| 390 | assert(octeon_dpop(0xf0f0f0f0f0f0f0f0ULL) == 32); |
| 391 | assert(octeon_seq(0xabc, 0xabc) == 1); |
| 392 | assert(octeon_seq(0xabc, 0xdef) == 0); |
| 393 | assert(octeon_sne(0xabc, 0xabc) == 0); |
| 394 | assert(octeon_sne(0xabc, 0xdef) == 1); |
| 395 | assert(octeon_qmac_lo(0x0003000000000000ULL, 2, 1) == 13); |
| 396 | assert(octeon_qmacs_state(1, 1, 0x7ffffffe) == 0x17fffffffULL); |
| 397 | assert(octeon_qmacs_state(0x8000, 0x8000, 0) == 0x17fffffffULL); |
| 398 | assert(octeon_vmulu(5, 7, 11) == 46); |
| 399 | assert(octeon_vmm0(5, 13, 7, 11) == 59); |
| 400 | assert(octeon_vmm0_zeroes_mpl1() == 0); |
| 401 | assert(octeon_mtp0_zeroes_p1() == 0); |
| 402 | assert(octeon_cop2_key0_readback(0x1122334455667788ULL) == |
| 403 | 0x1122334455667788ULL); |
| 404 | assert(octeon_cop2_key2_readback(0x8877665544332211ULL) == |
| 405 | 0x8877665544332211ULL); |
| 406 | assert(octeon_cop2_key3_readback(0x0102030405060708ULL) == |
| 407 | 0x0102030405060708ULL); |
| 408 | assert(octeon_cop2_keylength_readback(0xa5) == 1); |
| 409 | assert(octeon_cop2_hsh_dat0_readback(0x0102030405060708ULL) == |
| 410 | 0x0102030405060708ULL); |
| 411 | assert(octeon_cop2_crc_len_readback(0xb5) == 5); |
| 412 | assert(octeon_cop2_crc_poly_reflect_readback(0x12345678) == 0x482c6a1e); |
| 413 | assert(octeon_cop2_gfm_mul_reflect_write_readback( |
| 414 | 0x0123456789abcdefULL) == 0xf7b3d591e6a2c480ULL); |
| 415 | assert(octeon_cop2_gfm_mul_reflect_readback( |
| 416 | 0xfedcba9876543210ULL) == 0x084c2a6e195d3b7fULL); |
| 417 | assert(octeon_rdhwr31_non_decreasing()); |
| 418 | |
| 419 | return 0; |
| 420 | } |